| @@ -67,6 +67,12 @@ export const fetchStaff = cache(async () => { | |||||
| }); | }); | ||||
| }); | }); | ||||
| export const fetchStaffWithoutTeam = cache(async () => { | |||||
| return serverFetchJson<StaffResult[]>(`${BASE_API_URL}/staffs/noteam`, { | |||||
| next: { tags: ["staffs"] }, | |||||
| }); | |||||
| }); | |||||
| // export const fetchStaffCombo = cache(async () => { | // export const fetchStaffCombo = cache(async () => { | ||||
| // return serverFetchJson<Staff4TransferList>(`${BASE_API_URL}/staffs/combo`, { | // return serverFetchJson<Staff4TransferList>(`${BASE_API_URL}/staffs/combo`, { | ||||
| // next: { tags: ["staffs"] }, | // next: { tags: ["staffs"] }, | ||||
| @@ -51,3 +51,12 @@ export const saveTeam = async (data: CreateTeamInputs) => { | |||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | }; | ||||
| export const deleteTeam = async (data: TeamResult) => { | |||||
| return serverFetchJson(`${BASE_API_URL}/team/delete/${data.id}`, { | |||||
| method: "DELETE", | |||||
| // body: JSON.stringify(data), | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| @@ -47,7 +47,7 @@ const CreateStaffForm: React.FC<formProps> = ({ Title, fieldLists }) => { | |||||
| return haveError; | return haveError; | ||||
| } | } | ||||
| //check if joinDate > departDate | //check if joinDate > departDate | ||||
| if (data.departDate != null && data.departDate != "Invalid Date") { | |||||
| if (data.departDate != null && data.departDate != "Invalid Date" && data.departDate.length != 0) { | |||||
| if (data.joinDate != null) { | if (data.joinDate != null) { | ||||
| const joinDate = new Date(data.joinDate); | const joinDate = new Date(data.joinDate); | ||||
| const departDate = new Date(data.departDate); | const departDate = new Date(data.departDate); | ||||
| @@ -56,6 +56,10 @@ const CreateStaffForm: React.FC<formProps> = ({ Title, fieldLists }) => { | |||||
| return haveError; | return haveError; | ||||
| } | } | ||||
| } | } | ||||
| if (data.departReason == null || data.departReason.length == 0) { | |||||
| haveError = true; | |||||
| return haveError; | |||||
| } | |||||
| } | } | ||||
| if (haveError) { | if (haveError) { | ||||
| @@ -68,6 +72,13 @@ const CreateStaffForm: React.FC<formProps> = ({ Title, fieldLists }) => { | |||||
| phone2: data.phone2.toString(), | phone2: data.phone2.toString(), | ||||
| hourlyRate: typeof data.hourlyRate === 'string' ? parseInt(data.hourlyRate.replace("$", "").replace(",", "")) : 0 | hourlyRate: typeof data.hourlyRate === 'string' ? parseInt(data.hourlyRate.replace("$", "").replace(",", "")) : 0 | ||||
| }; | }; | ||||
| if (postData.departDate?.length === 0 && postData.departReason?.length === 0) { | |||||
| delete postData.departDate; | |||||
| delete postData.departReason; | |||||
| } | |||||
| if (postData.remark?.length === 0) { | |||||
| delete postData.remark; | |||||
| } | |||||
| console.log(postData); | console.log(postData); | ||||
| setServerError(""); | setServerError(""); | ||||
| await saveStaff(postData); | await saveStaff(postData); | ||||
| @@ -3,7 +3,7 @@ import CreateTeam from "./CreateTeam"; | |||||
| import CreateTeamLoading from "./CreateTeamLoading"; | import CreateTeamLoading from "./CreateTeamLoading"; | ||||
| // import { fetchTeam, fetchTeamLeads } from "@/app/api/team"; | // import { fetchTeam, fetchTeamLeads } from "@/app/api/team"; | ||||
| import { useSearchParams } from "next/navigation"; | import { useSearchParams } from "next/navigation"; | ||||
| import { fetchStaff } from "@/app/api/staff"; | |||||
| import { fetchStaff, fetchStaffWithoutTeam } from "@/app/api/staff"; | |||||
| interface SubComponents { | interface SubComponents { | ||||
| Loading: typeof CreateTeamLoading; | Loading: typeof CreateTeamLoading; | ||||
| @@ -14,7 +14,7 @@ const CreateTeamWrapper: React.FC & SubComponents = async () => { | |||||
| const [ | const [ | ||||
| staff, | staff, | ||||
| ] = await Promise.all([ | ] = await Promise.all([ | ||||
| fetchStaff(), | |||||
| fetchStaffWithoutTeam(), | |||||
| ]); | ]); | ||||
| return <CreateTeam allstaff={staff}/>; | return <CreateTeam allstaff={staff}/>; | ||||
| @@ -67,8 +67,8 @@ const Allocation: React.FC<Props> = ({ allStaffs: staff }) => { | |||||
| const removeStaff = useCallback((staff: StaffResult) => { | const removeStaff = useCallback((staff: StaffResult) => { | ||||
| setSelectedStaff((s) => s.filter((s) => s.id !== staff.id)); | setSelectedStaff((s) => s.filter((s) => s.id !== staff.id)); | ||||
| setDeletedStaffIds((s) => s) | |||||
| // setValue("deleteStaffIds", [...staff.id]) | |||||
| // setDeletedStaffIds((s) => s) | |||||
| setDeletedStaffIds((prevIds) => [...prevIds, staff.id]); | |||||
| }, []); | }, []); | ||||
| const setTeamLead = useCallback( | const setTeamLead = useCallback( | ||||
| @@ -118,7 +118,7 @@ const Allocation: React.FC<Props> = ({ allStaffs: staff }) => { | |||||
| useEffect(() => { | useEffect(() => { | ||||
| setValue("deleteStaffIds", deletedStaffIds) | setValue("deleteStaffIds", deletedStaffIds) | ||||
| console.log(deletedStaffIds) | console.log(deletedStaffIds) | ||||
| }, [deletedStaffIds, setValue]); | |||||
| }, [deletedStaffIds]); | |||||
| const StaffPoolColumns = useMemo<Column<StaffResult>[]>( | const StaffPoolColumns = useMemo<Column<StaffResult>[]>( | ||||
| () => [ | () => [ | ||||
| @@ -70,7 +70,7 @@ const EditTeam: React.FC<Props> = async ({ staff, desc }) => { | |||||
| const tempDesc = desc.filter( | const tempDesc = desc.filter( | ||||
| (item) => item.id === parseInt(idString) | (item) => item.id === parseInt(idString) | ||||
| ) | ) | ||||
| // console.log(filteredTeam); | |||||
| if (filteredTeam.length > 0) { | if (filteredTeam.length > 0) { | ||||
| const filteredIds: number[] = filteredTeam.map((i) => ( | const filteredIds: number[] = filteredTeam.map((i) => ( | ||||
| i.id | i.id | ||||
| @@ -82,21 +82,7 @@ const EditTeam: React.FC<Props> = async ({ staff, desc }) => { | |||||
| formProps.reset({description: tempDesc[0].description, addStaffIds: idList}) | formProps.reset({description: tempDesc[0].description, addStaffIds: idList}) | ||||
| setFilteredDesc(tempDesc[0].description) | setFilteredDesc(tempDesc[0].description) | ||||
| } | } | ||||
| // console.log(staff); | |||||
| // const desc = staff[0]?.description | |||||
| // setDesc(desc) | |||||
| // const staff = staff.map((item) => { | |||||
| // return { | |||||
| // id: item.id, | |||||
| // name: item.name, | |||||
| // staffId: item.staffId, | |||||
| // teamId: item.teamId, | |||||
| // staffName: item.staffName, | |||||
| // currentPosition: item.currentPosition | |||||
| // } as StaffResult | |||||
| // }) | |||||
| console.log(staff) | |||||
| setAllStaffs(staff) | setAllStaffs(staff) | ||||
| }, [searchParams]); | }, [searchParams]); | ||||
| @@ -124,11 +110,12 @@ const EditTeam: React.FC<Props> = async ({ staff, desc }) => { | |||||
| const tempData = { | const tempData = { | ||||
| description: data.description, | description: data.description, | ||||
| addStaffIds: data.addStaffIds, | addStaffIds: data.addStaffIds, | ||||
| deleteStaffIds: data.deleteStaffIds, | |||||
| id: parseInt(idString!!) | id: parseInt(idString!!) | ||||
| } | } | ||||
| console.log(tempData) | console.log(tempData) | ||||
| // await saveTeam(tempData); | |||||
| // router.replace("/settings/staff"); | |||||
| await saveTeam(tempData); | |||||
| router.replace("/settings/team"); | |||||
| } catch (e) { | } catch (e) { | ||||
| console.log(e); | console.log(e); | ||||
| setServerError(t("An error has occurred. Please try again later.")); | setServerError(t("An error has occurred. Please try again later.")); | ||||
| @@ -0,0 +1,105 @@ | |||||
| "use client"; | |||||
| import React, { useCallback, useMemo, useState } from "react"; | |||||
| import Button from "@mui/material/Button"; | |||||
| import { Card, Modal, Stack, Typography } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { Add } from "@mui/icons-material"; | |||||
| import Check from "@mui/icons-material/Check"; | |||||
| import Close from "@mui/icons-material/Close"; | |||||
| import { TSMS_BUTTON_THEME } from "@/theme/colorConst"; | |||||
| import { ThemeProvider } from "@emotion/react"; | |||||
| interface Props { | |||||
| isOpen: boolean; | |||||
| onConfirm: (data: any) => void; | |||||
| onCancel: (data: any | null) => void; | |||||
| } | |||||
| const ConfirmModal: React.FC<Props> = ({ ...props }) => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <> | |||||
| <Modal open={props.isOpen} onClose={props.onCancel}> | |||||
| <Card | |||||
| style={{ | |||||
| flex: 10, | |||||
| marginBottom: "20px", | |||||
| width: "auto", | |||||
| minWidth: "400px", | |||||
| minHeight: "200px", | |||||
| position: "fixed", | |||||
| top: "50%", | |||||
| left: "50%", | |||||
| transform: "translate(-50%, -50%)", | |||||
| }} | |||||
| > | |||||
| <> | |||||
| <Typography | |||||
| variant="h5" | |||||
| id="modal-title" | |||||
| sx={{ | |||||
| flex: 1, | |||||
| ml: 4, | |||||
| mt: 2, | |||||
| }} | |||||
| > | |||||
| {t("Confirm")} | |||||
| </Typography> | |||||
| <> | |||||
| <Typography | |||||
| variant="h6" | |||||
| id="modal-title" | |||||
| sx={{ | |||||
| flex: 1, | |||||
| mt: 4, | |||||
| justifyContent: "center", | |||||
| textAlign: "center", | |||||
| }} | |||||
| > | |||||
| {t("Are You Sure")} | |||||
| </Typography> | |||||
| </> | |||||
| {/* <ThemeProvider theme={TSMS_BUTTON_THEME}> */} | |||||
| <Stack direction="row"> | |||||
| <Button | |||||
| variant="contained" | |||||
| endIcon={<Check />} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| ml: 5, | |||||
| mr: 2, | |||||
| mt: 4, | |||||
| justifyContent: "space-between", | |||||
| }} | |||||
| onClick={props.onConfirm} | |||||
| // LinkComponent={Link} | |||||
| // href="/settings/department/new" | |||||
| > | |||||
| Proceed | |||||
| </Button> | |||||
| <Button | |||||
| variant="contained" | |||||
| startIcon={<Close />} | |||||
| sx={{ | |||||
| flex: 1, | |||||
| mr: 5, | |||||
| mt: 4, | |||||
| justifyContent: "space-between", | |||||
| }} | |||||
| color="warning" | |||||
| onClick={props.onCancel} | |||||
| // LinkComponent={Link} | |||||
| // href="/settings/department/new" | |||||
| > | |||||
| Cancel | |||||
| </Button> | |||||
| </Stack> | |||||
| {/* </ThemeProvider> */} | |||||
| </> | |||||
| </Card> | |||||
| </Modal> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default ConfirmModal; | |||||
| @@ -9,6 +9,9 @@ import EditNote from "@mui/icons-material/EditNote"; | |||||
| import DeleteIcon from '@mui/icons-material/Delete'; | import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import { deleteStaff } from "@/app/api/staff/actions"; | import { deleteStaff } from "@/app/api/staff/actions"; | ||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||
| import ConfirmModal from "./ConfirmDeleteModal"; | |||||
| import { deleteTeam } from "@/app/api/team/actions"; | |||||
| interface Props { | interface Props { | ||||
| team: TeamResult[]; | team: TeamResult[]; | ||||
| @@ -50,23 +53,47 @@ const TeamSearch: React.FC<Props> = ({ team }) => { | |||||
| router.push(`/settings/team/edit?id=${id}`); | router.push(`/settings/team/edit?id=${id}`); | ||||
| }, [router, t]); | }, [router, t]); | ||||
| // const onDeleteClick = useCallback((team: TeamResult) => { | |||||
| // console.log(team); | |||||
| // deleteTeam | |||||
| // }, [router, t]); | |||||
| const onDeleteClick = (team: TeamResult) => { | |||||
| console.log(team); | |||||
| setData(team) | |||||
| setIsOpen(!isOpen) | |||||
| }; | |||||
| const onConfirm = useCallback(async (team: TeamResult) => { | |||||
| console.log(team); | |||||
| if (data) | |||||
| await deleteTeam(data) | |||||
| setIsOpen(false) | |||||
| window.location.reload; | |||||
| }, [deleteTeam, data]); | |||||
| const onCancel = useCallback(() => { | |||||
| setIsOpen(false) | |||||
| }, []); | |||||
| const columns = useMemo<Column<TeamResult>[]>( | const columns = useMemo<Column<TeamResult>[]>( | ||||
| () => [ | () => [ | ||||
| { | { | ||||
| name: "action", | name: "action", | ||||
| label: t("Actions"), | |||||
| label: t("Edit"), | |||||
| onClick: onTeamClick, | onClick: onTeamClick, | ||||
| buttonIcon: <EditNote />, | buttonIcon: <EditNote />, | ||||
| }, | }, | ||||
| { name: "name", label: t("Name") }, | { name: "name", label: t("Name") }, | ||||
| { name: "code", label: t("Code") }, | { name: "code", label: t("Code") }, | ||||
| { name: "description", label: t("description") }, | { name: "description", label: t("description") }, | ||||
| // { | |||||
| // name: "action", | |||||
| // label: t("Actions"), | |||||
| // onClick: deleteClick, | |||||
| // buttonIcon: <DeleteIcon />, | |||||
| // }, | |||||
| { | |||||
| name: "action", | |||||
| label: t("Delete"), | |||||
| onClick: onDeleteClick, | |||||
| buttonIcon: <DeleteIcon />, | |||||
| }, | |||||
| ], | ], | ||||
| [t], | [t], | ||||
| ); | ); | ||||
| @@ -89,6 +116,11 @@ const TeamSearch: React.FC<Props> = ({ team }) => { | |||||
| }} | }} | ||||
| /> | /> | ||||
| <SearchResults<TeamResult> items={filteredTeam} columns={columns} /> | <SearchResults<TeamResult> items={filteredTeam} columns={columns} /> | ||||
| <ConfirmModal | |||||
| isOpen={isOpen} | |||||
| onConfirm={onConfirm} | |||||
| onCancel={onCancel} | |||||
| /> | |||||
| </> | </> | ||||
| ); | ); | ||||