@@ -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} | |||||
/> | |||||
</> | </> | ||||
); | ); | ||||