Ver a proveniência

Add project import function

tags/Baseline_30082024_FRONTEND_UAT
cyril.tsui há 1 ano
ascendente
cometimento
b7878256a0
8 ficheiros alterados com 150 adições e 8 eliminações
  1. +34
    -0
      src/app/(main)/settings/import/page.tsx
  2. +14
    -0
      src/app/api/projects/actions.ts
  3. +2
    -1
      src/components/AppBar/AppBar.tsx
  4. +6
    -4
      src/components/AppBar/NavigationToggle.tsx
  5. +75
    -0
      src/components/ExcelFileImport/ExcelFileImport.tsx
  6. +12
    -0
      src/components/ExcelFileImport/ExcelFileImportWrapper.tsx
  7. +1
    -0
      src/components/ExcelFileImport/index.ts
  8. +6
    -3
      src/components/NavigationContent/NavigationContent.tsx

+ 34
- 0
src/app/(main)/settings/import/page.tsx Ver ficheiro

@@ -0,0 +1,34 @@
import { Metadata } from "next";
import { getServerI18n } from "@/i18n";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { Suspense } from "react";
import ExcelFileImport from "@/components/ExcelFileImport";

export const metadata: Metadata = {
title: "Excel File Import",
};

const Import: React.FC = async () => {
const { t } = await getServerI18n("holiday");

return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Typography variant="h4" marginInlineEnd={2}>
{t("Excel File Import")}
</Typography>
</Stack>
<Suspense>
<ExcelFileImport />
</Suspense>
</>
)
};

export default Import;

+ 14
- 0
src/app/api/projects/actions.ts Ver ficheiro

@@ -2,6 +2,7 @@

import {
serverFetchJson,
serverFetchString,
serverFetchWithNoContent,
} from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
@@ -83,6 +84,7 @@ export interface CreateProjectResponse {
team: string;
client: string;
}

export const saveProject = async (data: CreateProjectInputs) => {
const newProject = await serverFetchJson<CreateProjectResponse>(
`${BASE_API_URL}/projects/new`,
@@ -110,3 +112,15 @@ export const deleteProject = async (id: number) => {
revalidatePath("/(main)/home");
return project;
};

export const importProjects = async (data: FormData) => {
const importProjects = await serverFetchString<String>(
`${BASE_API_URL}/projects/import`,
{
method: "POST",
body: data,
},
);

return importProjects;
};

+ 2
- 1
src/components/AppBar/AppBar.tsx Ver ficheiro

@@ -16,12 +16,13 @@ export interface AppBarProps {
const AppBar: React.FC<AppBarProps> = async ({ avatarImageSrc, profileName }) => {
const session = await getServerSession(authOptions) as any;
const abilities: string[] = session.abilities
const username: string = session.user.name
// console.log(abilities)
return (
<I18nProvider namespaces={["common"]}>
<MUIAppBar position="sticky" color="default" elevation={4}>
<Toolbar>
<NavigationToggle abilities={abilities}/>
<NavigationToggle abilities={abilities} username={username}/>
<Box
sx={{ flexGrow: 1, display: "flex", justifyContent: "flex-end" }}
>


+ 6
- 4
src/components/AppBar/NavigationToggle.tsx Ver ficheiro

@@ -8,14 +8,16 @@ import { Session } from "inspector";
import { authOptions } from "@/config/authConfig";
import { getServerSession } from "next-auth";
export interface SessionWithAbilities extends Session {
abilities?: string[]
abilities?: string[],
username?: string
}

interface Props {
abilities?: string[]
abilities?: string[],
username?: string
}

const NavigationToggle: React.FC<Props> = ({ abilities }) => {
const NavigationToggle: React.FC<Props> = ({ abilities, username }) => {
const [isOpened, setIsOpened] = React.useState(false);

const openNavigation = () => {
@@ -28,7 +30,7 @@ const NavigationToggle: React.FC<Props> = ({ abilities }) => {
return (
<>
<Drawer variant="permanent" sx={{ display: { xs: "none", xl: "block" } }}>
<NavigationContent abilities={abilities}/>
<NavigationContent abilities={abilities} username={username}/>
</Drawer>
<Drawer
sx={{ display: { xl: "none" } }}


+ 75
- 0
src/components/ExcelFileImport/ExcelFileImport.tsx Ver ficheiro

@@ -0,0 +1,75 @@
"use client";

import { importProjects } from "@/app/api/projects/actions";
import { FileUpload } from "@mui/icons-material";
import { Button, Stack } from "@mui/material";
import React, { ChangeEvent, useCallback } from "react";
import { useTranslation } from "react-i18next";
import { errorDialogWithContent, successDialog } from "../Swal/CustomAlerts";

interface Props {
}

const ExcelFileImport: React.FC<Props> = async ({ }) => {

const { t } = useTranslation("projects");

const handleProjectImportClick = useCallback(async (event: ChangeEvent<HTMLInputElement>) => {

try {
console.log(event.target.files)
if (event.target.files !== null) {
const file = event.target.files[0]
const formData = new FormData();
formData.append('multipartFileList', file);

if (file.name.endsWith(".xlsx") || file.name.endsWith(".csv")) {
const response = await importProjects(formData)

if (response === "Import Excel success") {
successDialog(t("Import Success"), t)
} else {
errorDialogWithContent(t("Import Fail"), t(`${response}`), t)
}
}
}

} catch (err) {
console.log(err)
return false
}

return
}, [])

return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Button
variant="contained"
color="info"
startIcon={<FileUpload />}
component="label"
>
<input
id='importExcel'
type='file'
accept='.xlsx, .csv'
hidden
onChange={(event) => {
handleProjectImportClick(event)
}}
/>
{t("Import Project")}
</Button>
</Stack>
</>
);
};

export default ExcelFileImport;

+ 12
- 0
src/components/ExcelFileImport/ExcelFileImportWrapper.tsx Ver ficheiro

@@ -0,0 +1,12 @@
import React from "react";
import { fetchProjects } from "@/app/api/projects";
import ExcelFileImport from "./ExcelFileImport";
import { getUserStaff } from "@/app/utils/commonUtil";

const ExcelFileImportWrapper: React.FC = async () => {

return <ExcelFileImport/>;
};


export default ExcelFileImportWrapper;

+ 1
- 0
src/components/ExcelFileImport/index.ts Ver ficheiro

@@ -0,0 +1 @@
export { default } from './ExcelFileImportWrapper'

+ 6
- 3
src/components/NavigationContent/NavigationContent.tsx Ver ficheiro

@@ -34,6 +34,7 @@ import BusinessIcon from "@mui/icons-material/Business";
import ViewWeekIcon from "@mui/icons-material/ViewWeek";
import ManageAccountsIcon from "@mui/icons-material/ManageAccounts";
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
import FileUploadIcon from '@mui/icons-material/FileUpload';
import {
GENERATE_REPORTS,
IMPORT_INVOICE,
@@ -63,9 +64,10 @@ interface NavigationItem {

interface Props {
abilities?: string[];
username?: string;
}

const NavigationContent: React.FC<Props> = ({ abilities }) => {
const NavigationContent: React.FC<Props> = ({ abilities, username }) => {
const navigationItems: NavigationItem[] = [
{
icon: <WorkHistory />,
@@ -242,7 +244,8 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
label: "User Group",
path: "/settings/group",
},
{ icon: <Holiday />, label: "Holiday", path: "/settings/holiday" },
{ icon: <Holiday />, label: "Holiday", path: "/settings/holiday"},
{ icon: <FileUploadIcon />, label: "Import Excel File", path: "/settings/import", isHidden: username !== "2fi"},
],
},
];
@@ -279,7 +282,7 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
</ListItemButton>
{item.children && isOpen && (
<List sx={{ pl: 2 }}>
{item.children.map((child) => renderNavigationItem(child))}
{item.children.map((child) => (!child.isHidden && renderNavigationItem(child)))}
</List>
)}
</Box>


Carregando…
Cancelar
Guardar