Procházet zdrojové kódy

update

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek před 1 rokem
rodič
revize
168053150d
7 změnil soubory, kde provedl 244 přidání a 109 odebrání
  1. +20
    -0
      src/app/api/salarys/actions.ts
  2. +10
    -2
      src/app/api/staff/actions.ts
  3. +1
    -1
      src/components/CreateStaff/CreateStaffForm.tsx
  4. +12
    -9
      src/components/CustomInputForm/CustomInputForm.tsx
  5. +178
    -92
      src/components/EditStaff/EditStaff.tsx
  6. +20
    -3
      src/components/EditStaffForm/EditStaffForm.tsx
  7. +3
    -2
      src/components/StaffSearch/StaffSearch.tsx

+ 20
- 0
src/app/api/salarys/actions.ts Zobrazit soubor

@@ -0,0 +1,20 @@
"use server"

import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
import { cache } from "react";

export interface comboProp {
id: any;
label: string;
}

export interface combo {
records: comboProp;
}
export const fetchSalaryCombo = cache(async () => {
return serverFetchJson<combo>(`${BASE_API_URL}/salary/combo`, {
next: { tags: ["salary"] },
});
});

+ 10
- 2
src/app/api/staff/actions.ts Zobrazit soubor

@@ -34,7 +34,15 @@ export interface CreateStaffInputs {
} }
export const saveStaff = async (data: CreateStaffInputs) => { export const saveStaff = async (data: CreateStaffInputs) => {
return serverFetchJson(`${BASE_API_URL}/staffs/save`, {
return serverFetchJson(`${BASE_API_URL}/staffs/save`, {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
});
};
export const testing = async (data: CreateStaffInputs) => {
return serverFetchJson(`${BASE_API_URL}/staffs/testing`, {
method: "POST", method: "POST",
body: JSON.stringify(data), body: JSON.stringify(data),
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
@@ -44,7 +52,7 @@ export const saveStaff = async (data: CreateStaffInputs) => {
export const deleteStaff = async (data: StaffResult) => { export const deleteStaff = async (data: StaffResult) => {
return serverFetchJson(`${BASE_API_URL}/staffs/delete/${data.id}`, { return serverFetchJson(`${BASE_API_URL}/staffs/delete/${data.id}`, {
method: "DELETE", method: "DELETE",
body: JSON.stringify(data),
// body: JSON.stringify(data),
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
}; };


+ 1
- 1
src/components/CreateStaff/CreateStaffForm.tsx Zobrazit soubor

@@ -10,7 +10,7 @@ import {
SubmitHandler, SubmitHandler,
useForm, useForm,
} from "react-hook-form"; } from "react-hook-form";
import { CreateStaffInputs, saveStaff } from "@/app/api/staff/actions";
import { CreateStaffInputs, saveStaff, testing } from "@/app/api/staff/actions";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";


interface Field { interface Field {


+ 12
- 9
src/components/CustomInputForm/CustomInputForm.tsx Zobrazit soubor

@@ -121,6 +121,7 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({
...dateObj, ...dateObj,
}; };


console.log(data);
console.log(finalData); console.log(finalData);
onSubmit(finalData); onSubmit(finalData);
}; };
@@ -279,19 +280,23 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({
</Grid> </Grid>
); );
} else if (field.type === "multiDate") { } else if (field.type === "multiDate") {
console.log(dayjs(field.value))
return ( return (
<Grid item xs={field.size ?? 6} key={field.id}> <Grid item xs={field.size ?? 6} key={field.id}>
<LocalizationProvider dateAdapter={AdapterDayjs}> <LocalizationProvider dateAdapter={AdapterDayjs}>
<DemoItem> <DemoItem>
<DatePicker <DatePicker
{...register(field.id)}
key={field.id} key={field.id}
label={field.label} label={field.label}
value={
!dateObj
? null
: !dateObj[field.id]
defaultValue={
field.value
? dayjs(field.value)
: !dateObj
? null ? null
: dayjs(dateObj[field.id])
: !dateObj[field.id]
? null
: dayjs(dateObj[field.id])
} // Set initial value or use a default value from state } // Set initial value or use a default value from state
onChange={(newValue) => { onChange={(newValue) => {
handleDateChange(field.id, newValue); handleDateChange(field.id, newValue);
@@ -348,9 +353,7 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({
: option : option
} }
> >
{option.id
? option.label
: ""}
{option.id ? option.label : ""}
</MenuItem> </MenuItem>
))} ))}
</Select> </Select>
@@ -455,7 +458,7 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({
rows={4} rows={4}
variant="filled" variant="filled"
{...register(field.id)} {...register(field.id)}
defaultValue={!field.value ? `${field.value}` : ""}
defaultValue={field.value ? `${field.value}` : ""}
id={field.id} id={field.id}
label={field.label} label={field.label}
required={field.required} required={field.required}


+ 178
- 92
src/components/EditStaff/EditStaff.tsx Zobrazit soubor

@@ -12,18 +12,18 @@ import { fetchDepartmentCombo } from "@/app/api/departments/actions";
import { fetchPositionCombo } from "@/app/api/positions/actions"; import { fetchPositionCombo } from "@/app/api/positions/actions";
import { fetchGradeCombo } from "@/app/api/grades/actions"; import { fetchGradeCombo } from "@/app/api/grades/actions";
import { fetchSkillCombo } from "@/app/api/skill/actions"; import { fetchSkillCombo } from "@/app/api/skill/actions";
import { fetchSalaryCombo } from "@/app/api/salarys/actions";
// import { Field } from "react-hook-form"; // import { Field } from "react-hook-form";


interface dataType { interface dataType {
[key: string]: any; [key: string]: any;
} }



interface Options { interface Options {
id: any;
label: string;
[key: string]: any;
}
id: any;
label: string;
[key: string]: any;
}
// interface Field { // interface Field {
// id: string; // id: string;
// label: string; // label: string;
@@ -35,19 +35,19 @@ interface Options {
// } // }


export interface Field { 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[];
}
// 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 EditStaff: React.FC = async () => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
@@ -61,95 +61,113 @@ const EditStaff: React.FC = async () => {
const [positionCombo, setPositionCombo] = useState<comboProp>(); const [positionCombo, setPositionCombo] = useState<comboProp>();
const [gradeCombo, setGradeCombo] = useState<comboProp>(); const [gradeCombo, setGradeCombo] = useState<comboProp>();
const [skillCombo, setSkillCombo] = useState<comboProp>(); const [skillCombo, setSkillCombo] = useState<comboProp>();
// const employTypeCombo = [{id: "FT", label: t("FT")}, {id: "PT", label: t("PT")}];
const employTypeCombo = [{id: "FT", label: t("FT")}, {id: "PT", label: t("PT")}];
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",
"salaryEffective",
"hourlyRate",
"employType",
"email",
"phone1",
"phone2",
];

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


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


useEffect(() => { useEffect(() => {
let id = 0; let id = 0;
if (idString) { if (idString) {
id = parseInt(idString); id = parseInt(idString);
setId(id)
setId(id);
} }
fetchStaffEdit(id).then((staff) => { fetchStaffEdit(id).then((staff) => {
console.log(staff.data); console.log(staff.data);
const data = staff.data; const data = staff.data;
const keyOrder = [
"staffId",
"name",
"company",
"team",
"department",
"grade",
"skill",
"currentPosition",
"salaryEffective",
"hourlySalary",
"employType",
"email",
"phone1",
"phone2",
];
const list1 = keyOrder
///////////////////// list 1 /////////////////////
const list1 = keyOrder1
.map((key) => { .map((key) => {
switch (key) { switch (key) {
case "staffId": case "staffId":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Staff ID`),
type: "text", type: "text",
value: data[key],
value: data[key] ?? "",
}; };
case "name": case "name":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Staff Name`),
type: "text", type: "text",
value: data[key],
value: data[key] ?? "",
}; };
case "company": case "company":
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}Id`,
label: t(`Company`),
type: "combo-Obj", type: "combo-Obj",
options: companyCombo, options: companyCombo,
value: data[key].id,
value: data[key].id ?? "",
}; };
case "team": case "team":
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}Id`,
label: t(`Team`),
type: "combo-Obj", type: "combo-Obj",
options: teamCombo, options: teamCombo,
value: data[key].id,
value: data[key].id ?? "",
}; };
case "department": case "department":
// console.log(data[key])
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}Id`,
label: t(`Department`),
type: "combo-Obj", type: "combo-Obj",
options: departmentCombo, options: departmentCombo,
value: data[key]?.id ?? "", value: data[key]?.id ?? "",
@@ -157,86 +175,154 @@ const EditStaff: React.FC = async () => {
}; };
case "grade": case "grade":
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}Id`,
label: t(`Grade`),
type: "combo-Obj", type: "combo-Obj",
options: gradeCombo, options: gradeCombo,
value: data[key].id,
value: data[key].id ?? "",
}; };
case "skill": case "skill":
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}SetId`,
label: t(`Skillset`),
type: "combo-Obj", type: "combo-Obj",
options: skillCombo, options: skillCombo,
value: data[key].id,
value: data[key].id ?? "",
}; };
case "currentPosition": case "currentPosition":
return { return {
id: `${key}`,
label: t(`${key}`),
id: `${key}Id`,
label: t(`Current Position`),
type: "combo-Obj", type: "combo-Obj",
options: positionCombo, options: positionCombo,
value: data[key].id,
value: data[key].id ?? "",
}; };
case "salaryEffective": case "salaryEffective":
return { return {
id: `${key}`,
label: t(`${key}`),
type: "text",
value: data[key],
id: `salaryEffId`,
label: t(`Salary Point`),
type: "combo-Obj",
options: salaryCombo,
value: data[key].salary.id ?? "",
}; };
case "hourlySalary":
case "hourlyRate":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`hourlyRate`),
type: "text", type: "text",
value: "",
// value: data[key], // value: data[key],
readOnly: true
readOnly: true,
}; };
case "employType": case "employType":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Employ Type`),
type: "combo-Obj", type: "combo-Obj",
options: employTypeCombo, options: employTypeCombo,
value: data[key],
value: data[key] ?? "",
}; };
case "email": case "email":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Email`),
type: "text", type: "text",
value: data[key],
value: data[key] ?? "",
pattern: "^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$",
message: t("input matching format"),
}; };
case "phone1": case "phone1":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Phone1`),
type: "text", type: "text",
value: data[key],
pattern: "^\\d{8}$",
message: t("input correct phone no."),
value: data[key] ?? "",
}; };
case "phone2": case "phone2":
return { return {
id: `${key}`, id: `${key}`,
label: t(`${key}`),
label: t(`Phone2`),
type: "text", type: "text",
value: data[key],
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] ?? "",
} as Field;
case "emergContactPhone":
return {
id: `${key}`,
label: t(`Emergency Contact Phonee`),
type: "text",
pattern: "^\\d{8}$",
message: t("input correct phone no."),
value: data[key] ?? "",
} as Field;
case "joinDate":
return {
id: `${key}`,
label: t(`Join Date`),
type: "multiDate",
value: data[key] ?? "",
} as Field;
case "joinPosition":
return {
id: `${key}Id`,
label: t(`Join Position`),
type: "combo-Obj",
options: positionCombo,
value: data[key].id ?? "",
} 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; } as Field;
// Add more cases for each property
default: default:
return null; return null;
} }
})
.filter((item): item is Field => item !== null);
}).filter((item): item is Field => item !== null);
console.log(list2);
console.log([list1]); console.log([list1]);
setFieldLists([list1]);
setFieldLists([list1,list2]);
}); });
}, [companyCombo]); }, [companyCombo]);


return ( return (
<> <>
<EditStaffForm id={id} fieldLists={fieldLists || [[]]} />
{/* {console.log(fieldLists)} */}
<EditStaffForm Title={title} id={id} fieldLists={fieldLists as Field[][] || [[]]} />
</> </>
); );
}; };


+ 20
- 3
src/components/EditStaffForm/EditStaffForm.tsx Zobrazit soubor

@@ -3,9 +3,10 @@ import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import CustomInputForm from "../CustomInputForm"; import CustomInputForm from "../CustomInputForm";
import { SubmitErrorHandler, SubmitHandler } from "react-hook-form"; import { SubmitErrorHandler, SubmitHandler } from "react-hook-form";
import { CreateStaffInputs, saveStaff } from "@/app/api/staff/actions";
import { CreateStaffInputs, saveStaff, testing } from "@/app/api/staff/actions";
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import dayjs from "dayjs";


interface Options { interface Options {
id: any; id: any;
@@ -38,14 +39,30 @@ const EditStaffForm: React.FC<formProps> = ({ id, Title, fieldLists }) => {
const onSubmit = useCallback<SubmitHandler<CreateStaffInputs>>( const onSubmit = useCallback<SubmitHandler<CreateStaffInputs>>(
async (data) => { async (data) => {
try { try {
console.log(data);
let formatJoinDate = data.joinDate
let formatDepartDate = data.departDate
if (data.joinDate && /^\d{2}\/\d{2}\/\d{4}$/.test(data.joinDate)) {
const formattedDate = dayjs(data.joinDate, 'MM/DD/YYYY').format('YYYY-MM-DD');
formatJoinDate = formattedDate;
}
if (data.departDate && data.departDate.length > 0 && /^\d{2}\/\d{2}\/\d{4}$/.test(data.departDate)) {
const formattedDate = dayjs(data.departDate, 'MM/DD/YYYY').format('YYYY-MM-DD');
formatDepartDate = formattedDate;
}
// console.log(data);
const temp = { const temp = {
id: id, id: id,
...data
...data,
emergContactPhone: data.emergContactPhone.toString(),
phone1: data.phone1.toString(),
phone2: data.phone1.toString(),
joinDate: formatJoinDate,
departDate: formatDepartDate,
} }
console.log(temp) console.log(temp)
setServerError(""); setServerError("");
await saveStaff(temp); await saveStaff(temp);
router.replace("/settings/staff");
} catch (e) { } catch (e) {
setServerError(t("An error has occurred. Please try again later.")); setServerError(t("An error has occurred. Please try again later."));
} }


+ 3
- 2
src/components/StaffSearch/StaffSearch.tsx Zobrazit soubor

@@ -73,8 +73,9 @@ const StaffSearch: React.FC<Props> = ({ staff }) => {


const onConfirm = useCallback(async (staff: StaffResult) => { const onConfirm = useCallback(async (staff: StaffResult) => {
console.log(staff); console.log(staff);
// if (data)
// await deleteStaff(data)
if (data)
await deleteStaff(data)
setIsOpen(false)
window.location.reload; window.location.reload;
}, [deleteStaff, data]); }, [deleteStaff, data]);




Načítá se…
Zrušit
Uložit