@@ -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; |
@@ -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; | |||
}; |
@@ -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" }} | |||
> | |||
@@ -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" } }} | |||
@@ -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; |
@@ -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; |
@@ -0,0 +1 @@ | |||
export { default } from './ExcelFileImportWrapper' |
@@ -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> | |||