ソースを参照

update

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek 1年前
コミット
e36b0e377a
8個のファイルの変更836行の追加343行の削除
  1. +1
    -5
      src/app/(main)/settings/skill/edit/page.tsx
  2. +5
    -2
      src/app/(main)/settings/staff/edit/page.tsx
  3. +37
    -1
      src/app/api/staff/index.ts
  4. +4
    -0
      src/app/utils/fetchUtil.ts
  5. +2
    -0
      src/components/CreateStaff/StaffInfo.tsx
  6. +226
    -331
      src/components/EditStaff/EditStaff.tsx
  7. +47
    -4
      src/components/EditStaff/EditStaffWrapper.tsx
  8. +514
    -0
      src/components/EditStaff/StaffInfo.tsx

+ 1
- 5
src/app/(main)/settings/skill/edit/page.tsx ファイルの表示

@@ -1,5 +1,4 @@
import { Edit } from "@mui/icons-material";
import { useSearchParams } from "next/navigation";
// import EditStaff from "@/components/EditStaff";
import { Suspense } from "react";
import { I18nProvider, getServerI18n } from "@/i18n";
@@ -8,10 +7,7 @@ import { Metadata } from "next";
import EditSkill from "@/components/EditSkill";
import { Typography } from "@mui/material";
import { fetchSkill } from "@/app/api/skill";

export interface searchParamsProps {
searchParams: { [key: string]: string | string[] | undefined };
}
import { searchParamsProps } from "@/app/utils/fetchUtil";

const EditSkillPage: React.FC<searchParamsProps> = async ({
searchParams,


+ 5
- 2
src/app/(main)/settings/staff/edit/page.tsx ファイルの表示

@@ -6,12 +6,15 @@ import { Suspense } from "react";
import { I18nProvider } from "@/i18n";
import EditStaffWrapper from "@/components/EditStaff/EditStaffWrapper";
import { Metadata } from "next";
import { searchParamsProps } from "@/app/utils/fetchUtil";

// export const metadata: Metadata = {
// title: "staff-edit",
// };

const EditStaffPage: React.FC = () => {
const EditStaffPage: React.FC<searchParamsProps> = async ({
searchParams,
}) => {
// const searchParams = useSearchParams();
// const userId = searchParams.get('param');
// console.log(userId); // Access the value of the "user_id" parameter
@@ -20,7 +23,7 @@ const EditStaffPage: React.FC = () => {
<>
<I18nProvider namespaces={["staff", "common"]}>
<Suspense fallback={<EditStaff.Loading />}>
<EditStaff />
<EditStaff id={parseInt(searchParams.id as string)}/>
</Suspense>
</I18nProvider>
{/* <EditStaff /> */}


+ 37
- 1
src/app/api/staff/index.ts ファイルの表示

@@ -26,6 +26,35 @@ export interface StaffTeamTable {
currentPosition: string;
}

export type IndivStaff = {
data: IndividualStaff
}

export type IndividualStaff = {
id: number
staffId: string
name: string
company: data
team: data
department: data
grade: data
skill: data
skillset: any
currentPosition: data
salary: data
employType: string
email: string
phone1: string
phone2?: string
emergContactName: string;
emergContactPhone: string;
joinDate: string;
joinPosition: data;
departDate?: string;
departReason?: string;
remark?: string;
}

export interface StaffResult {
action: any;
id: number;
@@ -35,10 +64,11 @@ export interface StaffResult {
grade: string;
joinPosition: string;
currentPosition: string;
data: data;
teamId: number;
staffName: string;
userId: number;
companyId: number;
data: data;
}
export interface searchInput {
staffId: string;
@@ -68,6 +98,12 @@ export const fetchStaff = cache(async () => {
});
});

export const fetchIndivStaff = cache(async (id: number) => {
return serverFetchJson<IndivStaff>(`${BASE_API_URL}/staffs/${id}`, {
next: { tags: ["staffs"] },
});
});

export const fetchStaffWithoutTeam = cache(async () => {
return serverFetchJson<StaffResult[]>(`${BASE_API_URL}/staffs/noteam`, {
next: { tags: ["staffs"] },


+ 4
- 0
src/app/utils/fetchUtil.ts ファイルの表示

@@ -3,6 +3,10 @@ import { getServerSession } from "next-auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";

export interface searchParamsProps {
searchParams: { [key: string]: string | string[] | undefined };
}

export class ServerFetchError extends Error {
public readonly response: Response | undefined;
constructor(message?: string, response?: Response) {


+ 2
- 0
src/components/CreateStaff/StaffInfo.tsx ファイルの表示

@@ -55,6 +55,7 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
(acc, skill) => ({ ...acc, [skill.id]: skill.label }),
{}
);
console.log(skillIdNameMap)

const resetStaff = useCallback(() => {
console.log(defaultValues);
@@ -235,6 +236,7 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
>
<Checkbox
checked={field.value!.indexOf(skill.id) > -1}
// checked={true}
/>
<ListItemText primary={skill.label} />
</MenuItem>


+ 226
- 331
src/components/EditStaff/EditStaff.tsx ファイルの表示

@@ -1,11 +1,18 @@
"use client";
import EditStaffForm from "../EditStaffForm";
import { useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
import { BASE_API_URL } from "@/config/api";
import { fetchStaffEdit } from "@/app/api/staff/actions";
import { getServerI18n } from "@/i18n";
import { useCallback, useEffect, useState } from "react";
import CustomInputForm from "../CustomInputForm";
import { useRouter, useSearchParams } from "next/navigation";
import { useTranslation } from "react-i18next";
import {
FieldErrors,
FormProvider,
SubmitErrorHandler,
SubmitHandler,
useForm,
} from "react-hook-form";
import { CreateStaffInputs, saveStaff, testing } from "@/app/api/staff/actions";
import { Button, Stack, Typography } from "@mui/material";
// import CreateStaffForm from "../CreateStaffForm";
import { comboProp, fetchCompanyCombo } from "@/app/api/companys/actions";
import { fetchTeamCombo } from "@/app/api/team/actions";
import { fetchDepartmentCombo } from "@/app/api/departments/actions";
@@ -13,346 +20,234 @@ import { fetchPositionCombo } from "@/app/api/positions/actions";
import { fetchGradeCombo } from "@/app/api/grades/actions";
import { fetchSkillCombo } from "@/app/api/skill/actions";
import { fetchSalaryCombo } from "@/app/api/salarys/actions";
// import { Field } from "react-hook-form";
// import StaffInfo from "./StaffInfo";
import { Check, Close } from "@mui/icons-material";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import StaffInfo from "./StaffInfo";
import { IndividualStaff } from "@/app/api/staff";
import dayjs from "dayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { List, differenceBy } from "lodash";


interface skill {
id: number;
name: string;
code: string;
}
interface skillObj {
id: number;
skill: skill;
export interface comboItem {
company: comboProp[];
team: comboProp[];
department: comboProp[];
position: comboProp[];
grade: comboProp[];
skill: comboProp[];
salary: comboProp[];
}

interface Options {
id: any;
label: string;
[key: string]: any;
interface formProps {
Staff: IndividualStaff
combos: comboItem;
}
// interface Field {
// id: string;
// label: string;
// type: string;
// value: any;
// required?: boolean;
// options?: comboProp[] | undefined | null;
// readOnly?: boolean;
// }

export interface Field {
// subtitle: string;
id: string;
label: string;
type: string;
value?: any;
required?: boolean;
pattern?: string;
message?: string;
options?: Options[] | null;
readOnly?: boolean;
size?: number;
setValue?: any[];
}

const EditStaff: React.FC = async () => {
const searchParams = useSearchParams();
const EditStaff: React.FC<formProps> = ({ Staff, combos }) => {
const defaultSkillset = Staff.skillset.map((s: any) => s.skill.id)
const { t } = useTranslation();
const idString = searchParams.get("id");
const [fieldLists, setFieldLists] = useState<Field[][]>();
const [companyCombo, setCompanyCombo] = useState<comboProp[]>();
const [teamCombo, setTeamCombo] = useState<comboProp[]>();
const [departmentCombo, setDepartmentCombo] = useState<comboProp[]>();
const [positionCombo, setPositionCombo] = useState<comboProp[]>();
const [gradeCombo, setGradeCombo] = useState<comboProp[]>();
const [skillCombo, setSkillCombo] = useState<comboProp[]>();
const [salaryCombo, setSalaryCombo] = useState<comboProp[]>();
// const employTypeCombo = [{id: "FT", label: t("FT")}, {id: "PT", label: t("PT")}];
const title = ["", t('Additional Info')]
const employTypeCombo = [
{ id: "FT", label: t("FT") },
{ id: "PT", label: t("PT") },
];
const keyOrder1 = [
"staffId",
"name",
"company",
"team",
"department",
"grade",
"skill",
"currentPosition",
"salary",
"hourlyRate",
"employType",
"email",
"phone1",
"phone2",
];
const searchParams = useSearchParams()
const id = parseInt(searchParams.get("id") || "0");
const formProps = useForm<CreateStaffInputs>({
defaultValues: {
staffId: Staff.staffId,
name: Staff.name,
companyId: Staff.company.id,
teamId: Staff.team?.id,
departmentId: Staff.department.id,
gradeId: Staff.department.id,
skillSetId: defaultSkillset,
// removeSkillSetId: [],
currentPositionId: Staff.currentPosition.id,
salaryId: Staff.salary.id,
employType: Staff.employType,
email: Staff.email,
phone1: Staff.phone1,
phone2: Staff.phone2,
emergContactName: Staff.emergContactName,
emergContactPhone: Staff.emergContactPhone,
joinDate: dayjs(Staff.joinDate).toString() || "",
joinPositionId: Staff.joinPosition.id,
departDate: dayjs(Staff.departDate).toString() || "",
departReason: Staff.departReason,
remark: Staff.remark,
}});
const [serverError, setServerError] = useState("");
const router = useRouter();
// const [tabIndex, setTabIndex] = useState(0);

const keyOrder2 = [
"emergContactName",
"emergContactPhone",
"joinDate",
"joinPosition",
"departDate",
"departPosition",
"departReason",
"remark",
];
const errors = formProps.formState.errors;

//fetch all combo
useEffect(() => {
fetchCompanyCombo().then((data) => {
if (data) setCompanyCombo(data.records);
});
fetchTeamCombo().then((data) => {
if (data) setTeamCombo(data.records);
});
fetchDepartmentCombo().then((data) => {
if (data) setDepartmentCombo(data.records);
});
fetchPositionCombo().then((data) => {
if (data) setPositionCombo(data.records);
});
fetchGradeCombo().then((data) => {
if (data) setGradeCombo(data.records);
});
fetchSkillCombo().then((data) => {
if (data) {
}setSkillCombo(data.records);
console.log(data.records)
});
fetchSalaryCombo().then((data) => {
if (data) setSalaryCombo(data.records);
});
}, [searchParams]);
const checkDuplicates = (str1: string, str2: string, str3: string) => {
return str1 === str2 || str1 === str3 || str2 === str3;
}

const onSubmit = useCallback<SubmitHandler<CreateStaffInputs>>(
async (data) => {
try {
console.log(data);
let haveError = false;
let regex_email = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
let regex_phone = /^\d{8}$/
// let removeSkillSetId: List<number> = []

// if (data.skillSetId && defaultSkillset.length > data.skillSetId) {
// removeSkillSetId = differenceBy(defaultSkillset, data.skillSetId)
// }
console.log(data.skillSetId)
console.log(defaultSkillset)
console.log(differenceBy(data.skillSetId, defaultSkillset))

if (!regex_email.test(data.email)) {
haveError = true
formProps.setError("email", { message: t("Please Enter Correct Email."), type: "required" })
}
if(!regex_phone.test(data.phone1)) {
haveError = true
formProps.setError("phone1", { message: t("Please Enter Correct Phone No.."), type: "required" })
}
if(!regex_phone.test(data.emergContactPhone)) {
haveError = true
formProps.setError("emergContactPhone", { message: t("Please Enter Correct Phone No.."), type: "required" })
}
if (data.phone2 && data.phone2?.length > 0) {
if(!regex_phone.test(data.phone2)) {
haveError = true
formProps.setError("phone2", { message: t("Please Enter Correct Phone No.."), type: "required" })
}
}
if (data.phone1 === data.phone2 || data.phone1 === data.emergContactPhone || data.phone2 === data.emergContactPhone) {
haveError = true
formProps.setError("phone1", { message: t("Please Enter Different Phone No.."), type: "required" })
if (data.phone2!.length > 0) {
formProps.setError("phone2", { message: t("Please Enter Different Phone No.."), type: "required" })
}
formProps.setError("emergContactPhone", { message: t("Please Enter Different Phone No.."), type: "required" })
}
if (!regex_email.test(data.email)) {
haveError = true
formProps.setError("email", { message: t("Please Enter Correct Email."), type: "required" })
}
if (!data.companyId) {
haveError = true
formProps.setError("companyId", { message: t("Please Enter Company."), type: "required" })
}
if (!data.employType) {
haveError = true
formProps.setError("employType", { message: t("Please Enter Employ Type."), type: "required" })
}
if (!data.departmentId) {
haveError = true
formProps.setError("departmentId", { message: t("Please Enter Department."), type: "required" })
}
if (!data.salaryId) {
haveError = true
formProps.setError("salaryId", { message: t("Please Enter Salary."), type: "required" })
}
if (!data.joinDate) {
haveError = true
formProps.setError("joinDate", { message: t("Please Enter Join Date."), type: "required" })
}
if (data.departDate && new Date(data.departDate) <= new Date(data.joinDate)) {
haveError = true
formProps.setError("departDate", { message: t("Depart Date cannot be earlier than Join Date."), type: "required" })
}
if (haveError) {
return
}
console.log("passed")
const postData = {
id: id,
...data,
// removeSkillSetId: removeSkillSetId
}
await saveStaff(postData)
router.replace("/settings/staff")
} catch (e: any) {
console.log(e);
formProps.setError("staffId", { message: t("Please Enter Employ Type."), type: "required" })
let msg = ""
if (e.message === "Duplicated StaffId Found") {
msg = t("Duplicated StaffId Found")
}
setServerError(`${t("An error has occurred. Please try again later.")} ${msg} `);
}
},
[router]
);
const handleCancel = () => {
router.back();
};

const resetStaff = useCallback(() => {
formProps.reset({
staffId: Staff.staffId,
name: Staff.name,
companyId: Staff.company.id,
teamId: Staff.team?.id,
departmentId: Staff.department.id,
gradeId: Staff.department.id,
skillSetId: defaultSkillset,
// removeSkillSetId: [],
currentPositionId: Staff.currentPosition.id,
salaryId: Staff.salary.id,
employType: Staff.employType,
email: Staff.email,
phone1: Staff.phone1,
phone2: Staff.phone2,
emergContactName: Staff.emergContactName,
emergContactPhone: Staff.emergContactPhone,
joinDate: dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT) || "",
joinPositionId: Staff.joinPosition.id,
departDate: !Staff.departDate ? "" : dayjs(Staff.departDate).format(INPUT_DATE_FORMAT),
departReason: Staff.departReason,
remark: Staff.remark,
});
}, []);
useEffect(() => {
let id = 0;
if (idString) {
id = parseInt(idString);
console.log(id)
fetchStaffEdit(id).then((staff) => {
console.log(staff.data);
const skillset = staff.data.skillset
console.log(skillset);
const skillIds = skillset.map((item: skillObj) => item.skill.id);
console.log(skillIds)
const data = staff.data;
///////////////////// list 1 /////////////////////
const list1 = keyOrder1
.map((key) => {
switch (key) {
case "staffId":
return {
id: `${key}`,
label: t(`Staff ID`),
type: "text",
value: data[key] ?? "",
required: true,
};
case "name":
return {
id: `${key}`,
label: t(`Staff Name`),
type: "text",
value: data[key] ?? "",
required: true,
};
case "company":
return {
id: `${key}Id`,
label: t(`Company`),
type: "combo-Obj",
options: companyCombo,
value: data[key].id ?? "",
required: true,
};
case "team":
return {
id: `${key}Id`,
label: t(`Team`),
type: "combo-Obj",
options: teamCombo,
value: data[key]?.id ?? "",
};
case "department":
return {
id: `${key}Id`,
label: t(`Department`),
type: "combo-Obj",
options: departmentCombo,
value: data[key]?.id ?? "",
required: true,
// later check
};
case "grade":
return {
id: `${key}Id`,
label: t(`Grade`),
type: "combo-Obj",
options: gradeCombo,
value: data[key]?.id ?? "",
};
case "skill":
console.log(skillIds)
return {
id: `${key}SetId`,
label: t(`Skillset`),
type: "multiSelect-Obj",
options: skillCombo,
value: skillIds ?? [],
//array problem
};
case "currentPosition":
return {
id: `${key}Id`,
label: t(`Current Position`),
type: "combo-Obj",
options: positionCombo,
value: data[key].id ?? "",
required: true,
};
case "salary":
// console.log("salary", data[key])
return {
id: `salaryId`,
label: t(`Salary Point`),
type: "combo-Obj",
options: salaryCombo,
value: data[key]?.salaryPoint ?? "",
required: true,
};
// case "hourlyRate":
// return {
// id: `${key}`,
// label: t(`hourlyRate`),
// type: "text",
// value: "",
// // value: data[key],
// readOnly: true,
// };
case "employType":
return {
id: `${key}`,
label: t(`Employ Type`),
type: "combo-Obj",
options: employTypeCombo,
value: data[key] ?? "",
required: true,
};
case "email":
return {
id: `${key}`,
label: t(`Email`),
type: "text",
value: data[key] ?? "",
pattern: "^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$",
message: t("input matching format"),
required: true,
};
case "phone1":
return {
id: `${key}`,
label: t(`Phone1`),
type: "text",
// pattern: "^\\d{8}$",
message: t("input correct phone no."),
value: data[key] ?? "",
required: true,
};
case "phone2":
return {
id: `${key}`,
label: t(`Phone2`),
type: "text",
// pattern: "^\\d{8}$",
message: t("input correct phone no."),
value: data[key] ?? "",
} as Field;
default:
return null;
}
}).filter((item): item is Field => item !== null);
///////////////////// list 2 /////////////////////
const list2 = keyOrder2
.map((key) => {
switch (key) {
case "emergContactName":
return {
id: `${key}`,
label: t(`Emergency Contact Name`),
type: "text",
value: data[key] ?? "",
required: true,
} as Field;
case "emergContactPhone":
return {
id: `${key}`,
label: t(`Emergency Contact Phone`),
type: "text",
// pattern: "^\\d{8}$",
message: t("input correct phone no."),
value: data[key] ?? "",
required: true,
} as Field;
case "joinDate":
return {
id: `${key}`,
label: t(`Join Date`),
type: "multiDate",
value: data[key] ?? "",
required: true,
} as Field;
case "joinPosition":
return {
id: `${key}Id`,
label: t(`Join Position`),
type: "combo-Obj",
options: positionCombo,
value: data[key]?.id ?? "",
required: true,
} as Field;
case "departDate":
return {
id: `${key}`,
label: t(`Depart Date`),
type: "multiDate",
value: data[key] ?? "",
} as Field;
case "departReason":
return {
id: `${key}`,
label: t(`Depart Reason`),
type: "text",
value: data[key] ?? "",
} as Field;
case "remark":
return {
id: `remark`,
label: t(`Remark`),
type: "remarks",
value: data[key] ?? "",
} as Field;
default:
return null;
}
}).filter((item): item is Field => item !== null);
console.log(list2);
console.log([list1]);
setFieldLists([list1,list2]);
});
}
}, [companyCombo, teamCombo, departmentCombo, positionCombo, gradeCombo, skillCombo, salaryCombo, idString]);
console.log(Staff)
resetStaff()
}, [Staff, combos]);

return (
<>
<EditStaffForm Title={title} fieldLists={fieldLists as Field[][] || [[]]} />
<FormProvider {...formProps}>
<Stack
spacing={2}
component="form"
onSubmit={formProps.handleSubmit(onSubmit)}
>
{serverError && (
<Typography variant="body2" color="error" alignSelf="flex-end">
{serverError}
</Typography>
)}
{Staff && <StaffInfo combos={combos}/>}
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
variant="outlined"
startIcon={<Close />}
onClick={handleCancel}
>
{t("Cancel")}
</Button>
<Button
variant="contained"
startIcon={<Check />}
type="submit"
// disabled={Boolean(formProps.watch("isGridEditing"))}
>
{t("Confirm")}
</Button>
</Stack>
</Stack>
</FormProvider>
</>
);
};

export default EditStaff;
export default EditStaff;

+ 47
- 4
src/components/EditStaff/EditStaffWrapper.tsx ファイルの表示

@@ -1,17 +1,60 @@
import React from "react";
import EditStaff from "./EditStaff";
import EditStaff, { comboItem } from "./EditStaff";
import EditStaffLoading from "./EditStaffLoading";
import { fetchStaff, fetchTeamLeads } from "@/app/api/staff";
import { StaffResult, fetchIndivStaff, fetchStaff, fetchTeamLeads, preloadStaff } from "@/app/api/staff";
import { useSearchParams } from "next/navigation";
import { fetchTeamCombo } from "@/app/api/team/actions";
import { fetchDepartmentCombo } from "@/app/api/departments/actions";
import { fetchPositionCombo } from "@/app/api/positions/actions";
import { fetchGradeCombo } from "@/app/api/grades/actions";
import { fetchSkillCombo } from "@/app/api/skill/actions";
import { fetchSalaryCombo } from "@/app/api/salarys/actions";
import { fetchCompanyCombo } from "@/app/api/companys/actions";

interface SubComponents {
Loading: typeof EditStaffLoading;
}

const EditStaffWrapper: React.FC & SubComponents = async () => {
interface Props {
id: number
}

const EditStaffWrapper: React.FC<Props> & SubComponents = async ({
id
}) => {
preloadStaff()
const [
Staff,
CompanyCombo,
TeamCombo,
DepartmentCombo,
PositionCombo,
GradeCombo,
SkillCombo,
SalaryCombo,
] = await Promise.all([
fetchIndivStaff(id),
fetchCompanyCombo(),
fetchTeamCombo(),
fetchDepartmentCombo(),
fetchPositionCombo(),
fetchGradeCombo(),
fetchSkillCombo(),
fetchSalaryCombo(),
]);
const combos: comboItem = {
company: CompanyCombo.records,
team: TeamCombo.records,
department: DepartmentCombo.records,
position: PositionCombo.records,
grade: GradeCombo.records,
skill: SkillCombo.records,
salary: SalaryCombo.records,
}

return <EditStaff/>;
console.log(Staff.data)

return <EditStaff Staff={Staff.data} combos={combos}/>;
};

EditStaffWrapper.Loading = EditStaffLoading;


+ 514
- 0
src/components/EditStaff/StaffInfo.tsx ファイルの表示

@@ -0,0 +1,514 @@
"use client";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Grid from "@mui/material/Grid";
import TextField from "@mui/material/TextField";
import Typography from "@mui/material/Typography";
import { CreateGroupInputs } from "@/app/api/group/actions";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useCallback, useEffect } from "react";
import { CreateStaffInputs } from "@/app/api/staff/actions";
import {
Checkbox,
FormControl,
InputLabel,
ListItemText,
MenuItem,
Select,
} from "@mui/material";
import { comboItem } from "./EditStaff";
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { DemoItem } from "@mui/x-date-pickers/internals/demo";
import dayjs from "dayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";

interface Props {
combos: comboItem;
}

const StaffInfo: React.FC<Props> = ({ combos }) => {
const {
t,
i18n: { language },
} = useTranslation();
const {
register,
formState: { errors, defaultValues },
control,
reset,
resetField,
setValue,
getValues,
clearErrors,
} = useFormContext<CreateStaffInputs>();

const employType = [
{ id: 1, label: "FT" },
{ id: 2, label: "PT" },
];

const skillIdNameMap = combos.skill.reduce<{ [id: number]: string }>(
(acc, skill) => ({ ...acc, [skill.id]: skill.label }),
{}
);

const resetStaff = useCallback(() => {
console.log(defaultValues);
if (defaultValues !== undefined) {
// resetField("description");
}
}, [defaultValues]);

const joinDate = getValues("joinDate");
const departDate = getValues("departDate");

useEffect(() => {
if (joinDate) clearErrors("joinDate");
if (departDate) clearErrors("departDate");
}, [joinDate, departDate]);

return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
<Box>
<Typography variant="overline" display="block" marginBlockEnd={1}>
{t("Staff")}
</Typography>
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
<Grid item xs={6}>
<TextField
label={t("Staff ID")}
fullWidth
required
{...register("staffId", {
required: "Staff Id required!",
})}
error={Boolean(errors.name)}
helperText={
Boolean(errors.name) &&
(errors.name?.message
? t(errors.name.message)
: t("Please input correct staffId"))
}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Staff Name")}
fullWidth
required
{...register("name", {
required: "Staff Name required!",
})}
error={Boolean(errors.name)}
helperText={
Boolean(errors.name) &&
(errors.name?.message
? t(errors.name.message)
: t("Please input correct name"))
}
/>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Company")}</InputLabel>
<Controller
control={control}
name="companyId"
render={({ field }) => (
<Select
label={t("Company")}
{...field}
error={Boolean(errors.companyId)}
>
{combos.company.map((company, index) => (
<MenuItem
key={`${company.id}-${index}`}
value={company.id}
>
{t(company.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel>{t("Team")}</InputLabel>
<Controller
control={control}
name="teamId"
render={({ field }) => (
<Select
label={t("Team")}
{...field}
// error={Boolean(errors.teamId)}
>
{combos.team.map((team, index) => (
<MenuItem key={`${team.id}-${index}`} value={team.id}>
{t(team.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Department")}</InputLabel>
<Controller
control={control}
name="departmentId"
render={({ field }) => (
<Select
label={t("Department")}
{...field}
error={Boolean(errors.departmentId)}
>
{combos.department.map((department, index) => (
<MenuItem
key={`${department.id}-${index}`}
value={department.id}
>
{t(department.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel>{t("Grade")}</InputLabel>
<Controller
control={control}
name="gradeId"
render={({ field }) => (
<Select
label={t("Grade")}
{...field}
error={Boolean(errors.gradeId)}
>
{combos.grade.map((grade, index) => (
<MenuItem key={`${grade.id}-${index}`} value={grade.id}>
{t(grade.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel>{t("Skillset")}</InputLabel>
<Controller
defaultValue={[]}
control={control}
name="skillSetId"
render={({ field }) => (
<Select
// error={Boolean(errors.skillSetId)}
renderValue={(types) =>
types.map((type) => skillIdNameMap[type]).join(", ")
}
multiple
label={t("Skillset")}
{...field}
>
{combos.skill.map((skill, index) => {
// console.log(field)
return (
<MenuItem
key={`${skill.id}-${index}`}
value={skill.id}
>
<Checkbox
checked={field.value!.indexOf(skill.id) > -1}
/>
<ListItemText primary={skill.label} />
</MenuItem>
);
})}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Current Position")}</InputLabel>
<Controller
control={control}
name="currentPositionId"
render={({ field }) => (
<Select
label={t("Current Position")}
{...field}
error={Boolean(errors.currentPositionId)}
>
{combos.position.map((position, index) => (
<MenuItem
key={`${position.id}-${index}`}
value={position.id}
>
{t(position.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Salary Point")}</InputLabel>
<Controller
control={control}
name="salaryId"
render={({ field }) => (
<Select
label={t("Salary Point")}
{...field}
error={Boolean(errors.salaryId)}
>
{combos.salary.map((salary, index) => (
<MenuItem
key={`${salary.id}-${index}`}
value={salary.id}
>
{t(salary.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Employ Type")}</InputLabel>
<Controller
control={control}
name="employType"
render={({ field }) => (
<Select
label={t("Employ Type")}
{...field}
error={Boolean(errors.employType)}
>
{employType.map((type, index) => (
<MenuItem
key={`${type.id}-${index}`}
value={type.label}
>
{t(type.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Email")}
fullWidth
required
{...register("email", {
required: "Email required!",
})}
error={Boolean(errors.email)}
helperText={
Boolean(errors.email) &&
(errors.email?.message
? t(errors.email.message)
: t("Please input correct email"))
}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Phone1")}
fullWidth
required
{...register("phone1", {
required: "phone1 required!",
})}
error={Boolean(errors.phone1)}
helperText={
Boolean(errors.phone1) &&
(errors.phone1?.message
? t(errors.phone1.message)
: t("Please input correct phone1"))
}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Phone2")}
fullWidth
{...register("phone2")}
error={Boolean(errors.phone2)}
helperText={
Boolean(errors.phone2) &&
(errors.phone2?.message
? t(errors.phone2.message)
: t("Please input correct phone2"))
}
/>
</Grid>
</Grid>
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }} marginTop={3}>
<Grid item xs={6}>
<TextField
label={t("Emergency Contact Name")}
fullWidth
required
{...register("emergContactName", {
required: "Emergency Contact Name required!",
})}
error={Boolean(errors.emergContactName)}
helperText={
Boolean(errors.emergContactName) &&
(errors.emergContactName?.message
? t(errors.emergContactName.message)
: t("Please input correct Emergency Contact Name"))
}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Emergency Contact Phone")}
fullWidth
required
{...register("emergContactPhone", {
required: "Emergency Contact Phone required!",
})}
error={Boolean(errors.emergContactPhone)}
helperText={
Boolean(errors.emergContactPhone) &&
(errors.emergContactPhone?.message
? t(errors.emergContactPhone.message)
: t("Please input correct Emergency Contact Phone"))
}
/>
</Grid>
<Grid item xs={6}>
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<DatePicker
sx={{ width: "100%" }}
label={t("Join Date")}
value={joinDate ? dayjs(joinDate) : null}
onChange={(date) => {
if (!date) return;
setValue("joinDate", date.format(INPUT_DATE_FORMAT));
}}
slotProps={{
textField: {
required: true,
error:
joinDate === "Invalid Date" || Boolean(errors.joinDate),
// value: errors.joinDate?.message,
},
}}
/>
</LocalizationProvider>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
<InputLabel required>{t("Join Position")}</InputLabel>
<Controller
control={control}
name="joinPositionId"
render={({ field }) => (
<Select
label={t("Join Position")}
{...field}
error={Boolean(errors.joinPositionId)}
>
{combos.position.map((position, index) => (
<MenuItem
key={`${position.id}-${index}`}
value={position.id}
>
{t(position.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<DatePicker
sx={{ width: "100%" }}
label={t("Depart Date")}
value={departDate ? dayjs(departDate) : null}
onChange={(date) => {
if (!date) return;
setValue("departDate", date.format(INPUT_DATE_FORMAT));
}}
slotProps={{
textField: {
error: departDate
? new Date(joinDate) > new Date(departDate)
: false,
},
}}
/>
</LocalizationProvider>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Depart Reason")}
fullWidth
{...register("departReason")}
error={Boolean(errors.departReason)}
helperText={
Boolean(errors.departReason) &&
(errors.departReason?.message
? t(errors.departReason.message)
: t("Please input correct departReason"))
}
/>
</Grid>
<Grid item xs={12}>
<TextField
label={t("Remark")}
fullWidth
multiline
rows={4}
{...register("remark")}
error={Boolean(errors.remark)}
helperText={
Boolean(errors.remark) &&
(errors.remark?.message
? t(errors.remark.message)
: t("Please input correct remark"))
}
/>
</Grid>
</Grid>
</Box>
</CardContent>
</Card>
);
};

export default StaffInfo;

読み込み中…
キャンセル
保存