From b502357373fbba5262029b88dc3df9c3c158a770 Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Wed, 3 Apr 2024 13:54:29 +0800 Subject: [PATCH] update customer --- src/app/(main)/staff/create/page.tsx | 79 +++++++++++-------- src/app/(main)/staff/page.tsx | 16 ++-- src/app/api/staff/actions.ts | 7 +- src/app/api/staff/index.ts | 1 + .../CreateStaff/CreateStaffForm.tsx | 24 ++++-- .../CustomInputForm/CustomInputForm.tsx | 58 +++++++++----- src/components/StaffSearch/StaffSearch.tsx | 14 ++-- src/i18n/zh/staff.json | 27 +++++++ 8 files changed, 150 insertions(+), 76 deletions(-) create mode 100644 src/i18n/zh/staff.json diff --git a/src/app/(main)/staff/create/page.tsx b/src/app/(main)/staff/create/page.tsx index f097298..4e98717 100644 --- a/src/app/(main)/staff/create/page.tsx +++ b/src/app/(main)/staff/create/page.tsx @@ -28,18 +28,6 @@ import { ProjectCategory } from "@/app/api/projects"; import { Grid, Typography } from "@mui/material"; import CreateStaffForm from "@/components/CreateStaff/CreateStaffForm"; -// import { Metadata } from "next"; - -// export const metadata: Metadata = { -// title: "staffCreate", -// }; - -// export interface Props { -// allTasks: Task[]; -// projectCategories: ProjectCategory[]; -// taskTemplates: TaskTemplate[]; -// teamLeads: Staff[]; -// } interface CreateCustomInputs { projectCode: string; projectName: string; @@ -52,65 +40,84 @@ const createCustomInputs: CreateCustomInputs = { // const Title = ["title1", "title2"]; const CreateStaff: React.FC = async () => { - const { t } = await getServerI18n("createStaff"); - - const title = ['', 'Additional Info'] + const { t } = await getServerI18n("staff"); + const title = ['', t('Additional Info')] + // const regex = new RegExp("^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$") + // console.log(regex) const fieldLists = [ [ { - id: "name", - label: t("Staff Id"), + id: "staffId", + label: t("Staff ID"), type: "text", - value: "asdasd", - // required: "asdasd", - // option: "asdasd", + value: "", + pattern: "^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$", + message: t("input matching format"), + required: true, }, { id: "name", label: t("Staff Name"), type: "text", value: "asdasd", - // required: "asdasd", - // option: "asdasd", + required: true, }, { id: "companyId", label: t("Company"), type: "combo-Obj", - // value: "asdasd", - // required: "asdasd", options: [{id: 1, key: 1, value: 1, label: "Company A"}, {id: 2, key: 2, value: 2, label: "Company B"}], + required: true, }, { id: "teamId", label: t("Team"), type: "combo-Obj", options: [{id: 1, key: 1, value: 1, label: "A"}, {id: 2, key: 2, value: 2, label: "B"}], + required: true, + }, + { + id: "departmentId", + label: t("Department"), + type: "combo-Obj", + options: [{id: 1, key: 1, value: 1, label: "Department A"}, {id: 2, key: 2, value: 2, label: "Department B"}], + required: true, }, { id: "gradeId", label: t("Grade"), type: "combo-Obj", options: [{id: 1, key: 1, value: 1, label: "A"}, {id: 2, key: 2, value: 2, label: "B"}], + required: true, + }, + { + id: "skillSetId", + label: t("Skillset"), + type: "combo-Obj", + options: [{id: 1, key: 1, value: 1, label: "excel"}, {id: 2, key: 2, value: 2, label: "word"}], + required: true, }, { - id: "currentPosition", + id: "currentPositionId", label: t("Current Position"), type: "combo-Obj", options: [{id: 1, key: 1, value: 1, label: "pos1"}, {id: 2, key: 2, value: 2, label: "pos2"}], + required: true, }, { id: "salaryEffId", - label: t("Salary point ID with effective date"), + label: t("Salary Point"), type: "combo-Obj", - options: [{id: 1, key: 1, value: 1, label: t("first")}, {id: 2, key: 2, value: 2, label: t("second")}], + options: [{id: 1, key: 1, value: 1, label: t("15")}, {id: 2, key: 2, value: 2, label: t("20")}], + required: true, }, { id: "hourlyRate", label: t("Hourly Rate"), type: "numeric", value: "", + required: true, }, { id: "employType", @@ -118,25 +125,29 @@ const CreateStaff: React.FC = async () => { type: "combo-Obj", options: [{id: 1, key: "FT", value: "FT", label: t("FT")}, {id: 2, key: "PT", value: "PT", label: t("PT")}], value: "", + required: true, }, { id: "email", label: t("Email"), - type: "text", + type: "email", value: "", + required: true, }, { id: "phone1", label: t("Phone1"), type: "numeric", value: "", + required: true, }, { id: "phone2", label: t("Phone2"), type: "numeric", value: "", - }, + required: true, + }, ], [ { @@ -144,24 +155,28 @@ const CreateStaff: React.FC = async () => { label: t("Emergency Contact Name"), type: "text", value: "", + required: true, }, { id: "emergContactPhone", label: t("Emergency Contact Phone"), type: "numeric", value: "", + required: true, }, { id: "joinDate", label: t("Join Date"), type: "multiDate", value: "", + required: true, }, { - id: "joinPosition", + id: "joinPositionId", label: t("Join Position"), type: "combo-Obj", options: [{id: 1, key: 1, value: 1, label: "pos1"}, {id: 2, key: 2, value: 2, label: "pos2"}], + required: true, }, { id: "departDate", @@ -171,7 +186,7 @@ const CreateStaff: React.FC = async () => { }, { id: "departReason", - label: t("Reason"), + label: t("Depart Reason"), type: "text", value: "", }, @@ -187,7 +202,7 @@ const CreateStaff: React.FC = async () => { return ( <> {t("Create Staff")} - + { - const { t } = await getServerI18n("projects"); - preloadTeamLeads() - preloadStaff() + const { t } = await getServerI18n("staff"); + preloadTeamLeads(); + preloadStaff(); return ( <> { {t("Create Staff")} - }> - - + + }> + + + ); }; diff --git a/src/app/api/staff/actions.ts b/src/app/api/staff/actions.ts index 4913e01..7d11a1f 100644 --- a/src/app/api/staff/actions.ts +++ b/src/app/api/staff/actions.ts @@ -25,12 +25,13 @@ export interface CreateStaffInputs { emergContactName: string; emergContactPhone: string; employType: string; - departDate: string; - departReason: string; - remark: string; + departDate: string | null; + departReason: string | null; + remark: string | null; } export const saveStaff = async (data: CreateStaffInputs) => { + console.log(`${BASE_API_URL}/staffs/new`) return serverFetchJson(`${BASE_API_URL}/staffs/new`, { method: "POST", body: JSON.stringify(data), diff --git a/src/app/api/staff/index.ts b/src/app/api/staff/index.ts index 013f7e4..83d76e5 100644 --- a/src/app/api/staff/index.ts +++ b/src/app/api/staff/index.ts @@ -4,6 +4,7 @@ import { cache } from "react"; import "server-only"; export interface StaffResult { + action: any; id: number; name: string; team: string; diff --git a/src/components/CreateStaff/CreateStaffForm.tsx b/src/components/CreateStaff/CreateStaffForm.tsx index 47b65a8..361a462 100644 --- a/src/components/CreateStaff/CreateStaffForm.tsx +++ b/src/components/CreateStaff/CreateStaffForm.tsx @@ -37,16 +37,10 @@ const CreateStaffForm: React.FC = ({ Title, fieldLists }) => { - // const [formData, setFormData] = useState(null); const router = useRouter(); const { t } = useTranslation(); const [serverError, setServerError] = useState(""); - // const handleSubmit = (data: any) => { - // console.log(data); - // // Handle the form submission logic here - // // setFormData(data); - // }; const handleCancel = () => { router.back(); }; @@ -54,8 +48,16 @@ const CreateStaffForm: React.FC = ({ async (data) => { try { console.log(data); + const postData = { + ...data, + emergContactPhone: data.emergContactPhone.toString(), + phone1: data.phone1.toString(), + phone2: data.phone2.toString(), + } + console.log(postData); setServerError(""); - await saveStaff(data); + await saveStaff(postData); + router.replace("/staff"); } catch (e) { setServerError(t("An error has occurred. Please try again later.")); } @@ -63,6 +65,13 @@ const CreateStaffForm: React.FC = ({ [router, t] ); + const onSubmitError = useCallback>( + (errors) => { + console.log(errors) + }, + [], +); + return ( <> {serverError && ( @@ -75,6 +84,7 @@ const CreateStaffForm: React.FC = ({ fieldLists={fieldLists} isActive={true} onSubmit={onSubmit} + onSubmitError={onSubmitError} onCancel={handleCancel} /> diff --git a/src/components/CustomInputForm/CustomInputForm.tsx b/src/components/CustomInputForm/CustomInputForm.tsx index 1e67f60..41c10e1 100644 --- a/src/components/CustomInputForm/CustomInputForm.tsx +++ b/src/components/CustomInputForm/CustomInputForm.tsx @@ -27,7 +27,7 @@ import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { DemoItem } from "@mui/x-date-pickers/internals/demo"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import dayjs from "dayjs"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Check, Close } from "@mui/icons-material"; // interface Option { @@ -45,6 +45,8 @@ interface Field { type: string; value?: any; required?: boolean; + pattern?: string; + message?: string; options?: any[]; readOnly?: boolean; size?: number; @@ -53,6 +55,7 @@ interface Field { interface CustomInputFormProps { onSubmit: (data: any) => void; + onSubmitError?: (data: any) => void; onCancel: () => void; // resetForm: () => void; Title?: string[]; @@ -60,20 +63,24 @@ interface CustomInputFormProps { fieldLists: Field[][]; } +// interface SubComponents { +// Loading: typeof CustomerSearchLoading; +// } + const CustomInputForm: React.FC = ({ Title, isActive, fieldLists, onSubmit, + onSubmitError, onCancel, // resetForm, }) => { const { t } = useTranslation(); - const { reset, register, handleSubmit, control } = useForm(); + const { reset, register, handleSubmit, control, formState: { errors } } = useForm(); const [dateObj, setDateObj] = useState(null); const [value, setValue] = useState({}); const [checkboxValue, setCheckboxValue] = useState({}); - // const [dateObj, setDateObj] = useState({}); interface DateObj { [key: string]: string; @@ -98,10 +105,7 @@ const CustomInputForm: React.FC = ({ if (checkboxValue !== null) { data = { ...data, ...checkboxValue }; } - - // if (value !== null) { - // data.dropdownCombo = value; - // } + const finalData = { ...value, ...data, @@ -172,14 +176,8 @@ const CustomInputForm: React.FC = ({ }); }); - // useEffect(() => { - // if (dateObj) { - // console.log(dateObj); - // } - // }, [dateObj]); - return ( -
+ <> @@ -200,17 +198,35 @@ const CustomInputForm: React.FC = ({ return ( + + ); + } else if (field.type === "email") { + return ( + + ); - } else if (field.type === "multiDate") { + }else if (field.type === "multiDate") { return ( @@ -408,4 +424,6 @@ const CustomInputForm: React.FC = ({ ); }; +// CustomInputForm.Loading = CustomerSearchLoading; + export default CustomInputForm; diff --git a/src/components/StaffSearch/StaffSearch.tsx b/src/components/StaffSearch/StaffSearch.tsx index f750bb7..ae3c26e 100644 --- a/src/components/StaffSearch/StaffSearch.tsx +++ b/src/components/StaffSearch/StaffSearch.tsx @@ -15,7 +15,7 @@ type SearchQuery = Partial>; type SearchParamNames = keyof SearchQuery; const StaffSearch: React.FC = ({ staff }) => { - const { t } = useTranslation("staff"); + const { t } = useTranslation(); // If claim searching is done on the server-side, then no need for this. const [filteredStaff, setFilteredStaff] = useState(staff); @@ -61,12 +61,12 @@ const StaffSearch: React.FC = ({ staff }) => { const columns = useMemo[]>( () => [ - // { - // name: "action", - // label: t("Actions"), - // onClick: onClaimClick, - // buttonIcon: , - // }, + { + name: "action", + label: t("Actions"), + onClick: onStaffClick, + buttonIcon: , + }, { name: "team", label: t("Team") }, { name: "name", label: t("Staff Name") }, { name: "staffId", label: t("Staff ID") }, diff --git a/src/i18n/zh/staff.json b/src/i18n/zh/staff.json new file mode 100644 index 0000000..75853f0 --- /dev/null +++ b/src/i18n/zh/staff.json @@ -0,0 +1,27 @@ +{ + "Staff": "員工", + "Team": "隊伍", + "Staff Name": "員工姓名", + "Staff ID": "員工編號", + "Grade": "級別", + "Current Position": "現職", + "Actions": "編輯", + "Create Staff": "新增員工", + "Company": "公司", + "Department": "部門", + "Skillset": "技能", + "Salary Point": "薪金點", + "Employ Type": "職位類別", + "Hourly Rate": "時薪", + "Email": "時薪", + "Phone1": "聯絡電話", + "Phone2": "次要聯絡電話", + "Additional Info": "更多資料", + "Emergency Contact Name": "緊急聯絡人", + "Emergency Contact Phone": "緊急聯絡人電話", + "Join Date": "入職日期", + "Join Position": "入職職位", + "Depart Date": "離職日期", + "Depart Reason": "離職原因", + "Remark": "備註" +} \ No newline at end of file