| @@ -32,11 +32,7 @@ interface CreateCustomInputs { | |||||
| projectCode: string; | projectCode: string; | ||||
| projectName: string; | projectName: string; | ||||
| } | } | ||||
| const createCustomInputs: CreateCustomInputs = { | |||||
| // Project details | |||||
| projectCode: "", | |||||
| projectName: "", | |||||
| } | |||||
| // const Title = ["title1", "title2"]; | // const Title = ["title1", "title2"]; | ||||
| const CreateStaff: React.FC = async () => { | const CreateStaff: React.FC = async () => { | ||||
| @@ -58,7 +54,7 @@ const CreateStaff: React.FC = async () => { | |||||
| id: "name", | id: "name", | ||||
| label: t("Staff Name"), | label: t("Staff Name"), | ||||
| type: "text", | type: "text", | ||||
| value: "asdasd", | |||||
| value: "", | |||||
| required: true, | required: true, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -1,10 +1,31 @@ | |||||
| const EditStaff: React.FC = async () => { | |||||
| // "use client"; | |||||
| import { Edit } from "@mui/icons-material"; | |||||
| import { useSearchParams } from "next/navigation"; | |||||
| import EditStaff from "@/components/EditStaff"; | |||||
| import { Suspense } from "react"; | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| import EditStaffWrapper from "@/components/EditStaff/EditStaffWrapper"; | |||||
| import { Metadata } from "next"; | |||||
| return ( | |||||
| <> | |||||
| sdsadasd | |||||
| </> | |||||
| ) | |||||
| } | |||||
| // export const metadata: Metadata = { | |||||
| // title: "staff-edit", | |||||
| // }; | |||||
| export default EditStaff; | |||||
| const EditStaffPage: React.FC = () => { | |||||
| // const searchParams = useSearchParams(); | |||||
| // const userId = searchParams.get('param'); | |||||
| // console.log(userId); // Access the value of the "user_id" parameter | |||||
| return ( | |||||
| <> | |||||
| <I18nProvider namespaces={["staff", "common"]}> | |||||
| <Suspense fallback={<EditStaff.Loading />}> | |||||
| <EditStaff /> | |||||
| </Suspense> | |||||
| </I18nProvider> | |||||
| {/* <EditStaff /> */} | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default EditStaffPage; | |||||
| @@ -1,4 +1,3 @@ | |||||
| // 'use client'; | |||||
| import { preloadClaims } from "@/app/api/claims"; | import { preloadClaims } from "@/app/api/claims"; | ||||
| import { preloadStaff, preloadTeamLeads } from "@/app/api/staff"; | import { preloadStaff, preloadTeamLeads } from "@/app/api/staff"; | ||||
| import StaffSearch from "@/components/StaffSearch"; | import StaffSearch from "@/components/StaffSearch"; | ||||
| @@ -0,0 +1,19 @@ | |||||
| "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 fetchCompanyCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/companys/combo`, { | |||||
| next: { tags: ["company"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -2,7 +2,17 @@ | |||||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | import { serverFetchJson } from "@/app/utils/fetchUtil"; | ||||
| import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
| import { cache } from "react"; | |||||
| export interface comboProp { | |||||
| id: any; | |||||
| label: string; | |||||
| } | |||||
| export interface combo { | |||||
| records: comboProp; | |||||
| } | |||||
| export interface CreateDepartmentInputs { | export interface CreateDepartmentInputs { | ||||
| departmentCode: string; | departmentCode: string; | ||||
| departmentName: string; | departmentName: string; | ||||
| @@ -15,4 +25,11 @@ export const saveDepartment = async (data: CreateDepartmentInputs) => { | |||||
| body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | |||||
| }; | |||||
| export const fetchDepartmentCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/departments/combo`, { | |||||
| next: { tags: ["department"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -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 fetchGradeCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/grades/combo`, { | |||||
| next: { tags: ["grades"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -2,6 +2,16 @@ | |||||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | import { serverFetchJson } from "@/app/utils/fetchUtil"; | ||||
| import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
| import { cache } from "react"; | |||||
| export interface comboProp { | |||||
| id: any; | |||||
| label: string; | |||||
| } | |||||
| export interface combo { | |||||
| records: comboProp; | |||||
| } | |||||
| export interface CreatePositionInputs { | export interface CreatePositionInputs { | ||||
| positionCode: string; | positionCode: string; | ||||
| @@ -15,4 +25,11 @@ export const savePosition = async (data: CreatePositionInputs) => { | |||||
| body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | |||||
| }; | |||||
| export const fetchPositionCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/positions/combo`, { | |||||
| next: { tags: ["positions"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,21 @@ | |||||
| "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 fetchSkillCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/skill/combo`, { | |||||
| next: { tags: ["skill"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -1,7 +1,8 @@ | |||||
| "use server"; | "use server"; | ||||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | import { serverFetchJson } from "@/app/utils/fetchUtil"; | ||||
| import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
| import { StaffResult } from "."; | |||||
| import { StaffResult, data } from "."; | |||||
| import { cache } from "react"; | |||||
| export interface CreateCustomInputs { | export interface CreateCustomInputs { | ||||
| // Project details | // Project details | ||||
| projectCode: string; | projectCode: string; | ||||
| @@ -33,17 +34,29 @@ export interface CreateStaffInputs { | |||||
| } | } | ||||
| export const saveStaff = async (data: CreateStaffInputs) => { | export const saveStaff = async (data: CreateStaffInputs) => { | ||||
| return serverFetchJson(`${BASE_API_URL}/staffs/new`, { | |||||
| return serverFetchJson(`${BASE_API_URL}/staffs/save`, { | |||||
| method: "POST", | method: "POST", | ||||
| body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | }; | ||||
| export const deleteStaff = async (id: number) => { | |||||
| return serverFetchJson(`${BASE_API_URL}/staffs/delete/${id}`, { | |||||
| export const deleteStaff = async (data: StaffResult) => { | |||||
| return serverFetchJson(`${BASE_API_URL}/staffs/delete/${data.id}`, { | |||||
| method: "DELETE", | method: "DELETE", | ||||
| // body: JSON.stringify(id), | |||||
| body: JSON.stringify(data), | |||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | |||||
| }; | |||||
| export const fetchStaffEdit = cache(async (id: number) => { | |||||
| return serverFetchJson<data>(`${BASE_API_URL}/staffs/${id}`, { | |||||
| next: { tags: ["staffs"] }, | |||||
| }); | |||||
| }); | |||||
| // export const preloadStaffEdit = (id: number) => { | |||||
| // fetchStaffEdit(id); | |||||
| // }; | |||||
| @@ -3,6 +3,9 @@ import { BASE_API_URL } from "@/config/api"; | |||||
| import { cache } from "react"; | import { cache } from "react"; | ||||
| import "server-only"; | import "server-only"; | ||||
| export interface data { | |||||
| [key: string]: any; | |||||
| } | |||||
| export interface StaffResult { | export interface StaffResult { | ||||
| action: any; | action: any; | ||||
| id: number; | id: number; | ||||
| @@ -12,6 +15,7 @@ export interface StaffResult { | |||||
| grade: string; | grade: string; | ||||
| joinPosition: string; | joinPosition: string; | ||||
| currentPosition: string; | currentPosition: string; | ||||
| data: data | |||||
| } | } | ||||
| export interface searchInput { | export interface searchInput { | ||||
| staffId: string; | staffId: string; | ||||
| @@ -41,3 +45,5 @@ export const fetchStaff = cache(async () => { | |||||
| }); | }); | ||||
| }); | }); | ||||
| @@ -0,0 +1,19 @@ | |||||
| "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 fetchTeamCombo = cache(async () => { | |||||
| return serverFetchJson<combo>(`${BASE_API_URL}/team/combo`, { | |||||
| next: { tags: ["team"] }, | |||||
| }); | |||||
| }); | |||||
| @@ -32,15 +32,13 @@ import { Check, Close } from "@mui/icons-material"; | |||||
| import { NumericFormat, NumericFormatProps } from "react-number-format"; | import { NumericFormat, NumericFormatProps } from "react-number-format"; | ||||
| import * as React from "react"; | import * as React from "react"; | ||||
| // interface Option { | |||||
| // // Define properties of each option object | |||||
| // // based on your specific requirements | |||||
| // id: any; | |||||
| // value: any; | |||||
| // label: string; | |||||
| // } | |||||
| interface Options { | |||||
| id: any; | |||||
| label: string; | |||||
| [key: string]: any; | |||||
| } | |||||
| interface Field { | |||||
| export interface Field { | |||||
| // subtitle: string; | // subtitle: string; | ||||
| id: string; | id: string; | ||||
| label: string; | label: string; | ||||
| @@ -49,7 +47,7 @@ interface Field { | |||||
| required?: boolean; | required?: boolean; | ||||
| pattern?: string; | pattern?: string; | ||||
| message?: string; | message?: string; | ||||
| options?: any[]; | |||||
| options?: Options[] | null; | |||||
| readOnly?: boolean; | readOnly?: boolean; | ||||
| size?: number; | size?: number; | ||||
| setValue?: any[]; | setValue?: any[]; | ||||
| @@ -249,7 +247,10 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({ | |||||
| ? new RegExp(field.pattern) | ? new RegExp(field.pattern) | ||||
| : /.*/, | : /.*/, | ||||
| })} | })} | ||||
| defaultValue={!field.value ? `${field.value}` : ""} | |||||
| defaultValue={field.value ? `${field.value}` : ""} | |||||
| inputProps={{ | |||||
| readOnly: field.readOnly, | |||||
| }} | |||||
| required={field.required ?? false} | required={field.required ?? false} | ||||
| error={Boolean(errors[field.id])} | error={Boolean(errors[field.id])} | ||||
| helperText={ | helperText={ | ||||
| @@ -347,9 +348,9 @@ const CustomInputForm: React.FC<CustomInputFormProps> = ({ | |||||
| : option | : option | ||||
| } | } | ||||
| > | > | ||||
| {option.id !== undefined | |||||
| {option.id | |||||
| ? option.label | ? option.label | ||||
| : option} | |||||
| : ""} | |||||
| </MenuItem> | </MenuItem> | ||||
| ))} | ))} | ||||
| </Select> | </Select> | ||||
| @@ -0,0 +1,244 @@ | |||||
| "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 { useTranslation } from "react-i18next"; | |||||
| import { comboProp, fetchCompanyCombo } from "@/app/api/companys/actions"; | |||||
| 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 { Field } from "react-hook-form"; | |||||
| interface dataType { | |||||
| [key: string]: any; | |||||
| } | |||||
| interface Options { | |||||
| id: any; | |||||
| label: string; | |||||
| [key: string]: any; | |||||
| } | |||||
| // 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 { t } = useTranslation(); | |||||
| const idString = searchParams.get("id"); | |||||
| const [id, setId] = useState(0); | |||||
| 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 employTypeCombo = [{id: "FT", label: t("FT")}, {id: "PT", label: t("PT")}]; | |||||
| const employTypeCombo = [{id: "FT", label: t("FT")}, {id: "PT", label: t("PT")}]; | |||||
| //fetch all combo | |||||
| useEffect(() => { | |||||
| fetchCompanyCombo().then((data) => { | |||||
| console.log(data.records); | |||||
| setCompanyCombo(data.records); | |||||
| }); | |||||
| fetchTeamCombo().then((data) => { | |||||
| setTeamCombo(data.records); | |||||
| }) | |||||
| fetchDepartmentCombo().then((data) => { | |||||
| setDepartmentCombo(data.records); | |||||
| }) | |||||
| fetchPositionCombo().then((data) => { | |||||
| setPositionCombo(data.records); | |||||
| }) | |||||
| fetchGradeCombo().then((data) => { | |||||
| setGradeCombo(data.records); | |||||
| }) | |||||
| fetchSkillCombo().then((data) => { | |||||
| setSkillCombo(data.records); | |||||
| }) | |||||
| }, [searchParams]); | |||||
| useEffect(() => { | |||||
| let id = 0; | |||||
| if (idString) { | |||||
| id = parseInt(idString); | |||||
| setId(id) | |||||
| } | |||||
| fetchStaffEdit(id).then((staff) => { | |||||
| console.log(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 | |||||
| .map((key) => { | |||||
| switch (key) { | |||||
| case "staffId": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| }; | |||||
| case "name": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| }; | |||||
| case "company": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: companyCombo, | |||||
| value: data[key].id, | |||||
| }; | |||||
| case "team": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: teamCombo, | |||||
| value: data[key].id, | |||||
| }; | |||||
| case "department": | |||||
| // console.log(data[key]) | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: departmentCombo, | |||||
| value: data[key]?.id ?? "", | |||||
| // later check | |||||
| }; | |||||
| case "grade": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: gradeCombo, | |||||
| value: data[key].id, | |||||
| }; | |||||
| case "skill": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: skillCombo, | |||||
| value: data[key].id, | |||||
| }; | |||||
| case "currentPosition": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: positionCombo, | |||||
| value: data[key].id, | |||||
| }; | |||||
| case "salaryEffective": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| }; | |||||
| case "hourlySalary": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| // value: data[key], | |||||
| readOnly: true | |||||
| }; | |||||
| case "employType": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "combo-Obj", | |||||
| options: employTypeCombo, | |||||
| value: data[key], | |||||
| }; | |||||
| case "email": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| }; | |||||
| case "phone1": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| }; | |||||
| case "phone2": | |||||
| return { | |||||
| id: `${key}`, | |||||
| label: t(`${key}`), | |||||
| type: "text", | |||||
| value: data[key], | |||||
| } as Field; | |||||
| // Add more cases for each property | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| }) | |||||
| .filter((item): item is Field => item !== null); | |||||
| console.log([list1]); | |||||
| setFieldLists([list1]); | |||||
| }); | |||||
| }, [companyCombo]); | |||||
| return ( | |||||
| <> | |||||
| <EditStaffForm id={id} fieldLists={fieldLists || [[]]} /> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default EditStaff; | |||||
| @@ -0,0 +1,40 @@ | |||||
| import Card from "@mui/material/Card"; | |||||
| import CardContent from "@mui/material/CardContent"; | |||||
| import Skeleton from "@mui/material/Skeleton"; | |||||
| import Stack from "@mui/material/Stack"; | |||||
| import React from "react"; | |||||
| // Can make this nicer | |||||
| export const EditStaffLoading: React.FC = () => { | |||||
| return ( | |||||
| <> | |||||
| <Card> | |||||
| <CardContent> | |||||
| <Stack spacing={2}> | |||||
| <Skeleton variant="rounded" height={60} /> | |||||
| <Skeleton variant="rounded" height={60} /> | |||||
| <Skeleton variant="rounded" height={60} /> | |||||
| <Skeleton | |||||
| variant="rounded" | |||||
| height={50} | |||||
| width={100} | |||||
| sx={{ alignSelf: "flex-end" }} | |||||
| /> | |||||
| </Stack> | |||||
| </CardContent> | |||||
| </Card> | |||||
| <Card>EditStaff | |||||
| <CardContent> | |||||
| <Stack spacing={2}> | |||||
| <Skeleton variant="rounded" height={40} /> | |||||
| <Skeleton variant="rounded" height={40} /> | |||||
| <Skeleton variant="rounded" height={40} /> | |||||
| <Skeleton variant="rounded" height={40} /> | |||||
| </Stack> | |||||
| </CardContent> | |||||
| </Card> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default EditStaffLoading; | |||||
| @@ -0,0 +1,19 @@ | |||||
| import React from "react"; | |||||
| import EditStaff from "./EditStaff"; | |||||
| import EditStaffLoading from "./EditStaffLoading"; | |||||
| import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | |||||
| import { useSearchParams } from "next/navigation"; | |||||
| interface SubComponents { | |||||
| Loading: typeof EditStaffLoading; | |||||
| } | |||||
| const EditStaffWrapper: React.FC & SubComponents = async () => { | |||||
| return <EditStaff/>; | |||||
| }; | |||||
| EditStaffWrapper.Loading = EditStaffLoading; | |||||
| export default EditStaffWrapper; | |||||
| @@ -0,0 +1 @@ | |||||
| export { default } from "./EditStaffWrapper"; | |||||
| @@ -0,0 +1,83 @@ | |||||
| // import { fetchStaffEdit } from "@/app/api/staff"; | |||||
| import { useRouter, useSearchParams } from "next/navigation"; | |||||
| import { useCallback, useEffect, useState } from "react"; | |||||
| import CustomInputForm from "../CustomInputForm"; | |||||
| import { SubmitErrorHandler, SubmitHandler } from "react-hook-form"; | |||||
| import { CreateStaffInputs, saveStaff } from "@/app/api/staff/actions"; | |||||
| import { Typography } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| interface Options { | |||||
| id: any; | |||||
| label: string; | |||||
| [key: string]: any; | |||||
| } | |||||
| interface Field { | |||||
| // subtitle: string; | |||||
| id: string; | |||||
| label: string; | |||||
| type: string; | |||||
| value?: any; | |||||
| required?: boolean; | |||||
| options?: any[] | null; | |||||
| readOnly?: boolean; | |||||
| } | |||||
| interface formProps { | |||||
| id: number; | |||||
| Title?: string[]; | |||||
| fieldLists: Field[][]; | |||||
| } | |||||
| const EditStaffForm: React.FC<formProps> = ({ id, Title, fieldLists }) => { | |||||
| const router = useRouter(); | |||||
| const { t } = useTranslation(); | |||||
| const [serverError, setServerError] = useState(""); | |||||
| // make new inputs | |||||
| const onSubmit = useCallback<SubmitHandler<CreateStaffInputs>>( | |||||
| async (data) => { | |||||
| try { | |||||
| console.log(data); | |||||
| const temp = { | |||||
| id: id, | |||||
| ...data | |||||
| } | |||||
| console.log(temp) | |||||
| setServerError(""); | |||||
| await saveStaff(temp); | |||||
| } catch (e) { | |||||
| setServerError(t("An error has occurred. Please try again later.")); | |||||
| } | |||||
| }, | |||||
| [router, t] | |||||
| ); | |||||
| const onSubmitError = useCallback<SubmitErrorHandler<CreateStaffInputs>>( | |||||
| (errors) => { | |||||
| console.log(errors); | |||||
| }, | |||||
| [] | |||||
| ); | |||||
| const handleCancel = () => { | |||||
| router.back(); | |||||
| }; | |||||
| return ( | |||||
| <> | |||||
| {serverError && ( | |||||
| <Typography variant="body2" color="error" alignSelf="flex-end"> | |||||
| {serverError} | |||||
| </Typography> | |||||
| )} | |||||
| <CustomInputForm | |||||
| Title={Title} | |||||
| fieldLists={fieldLists} | |||||
| isActive={true} | |||||
| onSubmit={onSubmit} | |||||
| onSubmitError={onSubmitError} | |||||
| onCancel={handleCancel} | |||||
| /> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default EditStaffForm; | |||||
| @@ -0,0 +1 @@ | |||||
| export { default } from "./EditStaffForm"; | |||||
| @@ -9,6 +9,7 @@ import EditNote from "@mui/icons-material/EditNote"; | |||||
| import DeleteIcon from '@mui/icons-material/Delete'; | import DeleteIcon from '@mui/icons-material/Delete'; | ||||
| import ConfirmModal from "./ConfirmDeleteModal"; | import ConfirmModal from "./ConfirmDeleteModal"; | ||||
| import { deleteStaff } from "@/app/api/staff/actions"; | import { deleteStaff } from "@/app/api/staff/actions"; | ||||
| import { useRouter } from "next/navigation"; | |||||
| interface Props { | interface Props { | ||||
| staff: StaffResult[]; | staff: StaffResult[]; | ||||
| @@ -20,8 +21,9 @@ type SearchParamNames = keyof SearchQuery; | |||||
| const StaffSearch: React.FC<Props> = ({ staff }) => { | const StaffSearch: React.FC<Props> = ({ staff }) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const [filteredStaff, setFilteredStaff] = useState(staff); | const [filteredStaff, setFilteredStaff] = useState(staff); | ||||
| const [id, setId] = useState(0); | |||||
| const [data, setData] = useState<StaffResult>(); | |||||
| const [isOpen, setIsOpen] = useState(false); | const [isOpen, setIsOpen] = useState(false); | ||||
| const router = useRouter(); | |||||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
| () => [ | () => [ | ||||
| @@ -59,31 +61,32 @@ const StaffSearch: React.FC<Props> = ({ staff }) => { | |||||
| const onStaffClick = useCallback((staff: StaffResult) => { | const onStaffClick = useCallback((staff: StaffResult) => { | ||||
| console.log(staff); | console.log(staff); | ||||
| }, []); | |||||
| const id = staff.id | |||||
| router.push(`/settings/staff/edit?id=${id}`); | |||||
| }, [router, t]); | |||||
| const deleteClick = (staff: StaffResult) => { | const deleteClick = (staff: StaffResult) => { | ||||
| console.log(staff.id); | |||||
| const temp = staff.id | |||||
| console.log(temp) | |||||
| setId(temp) | |||||
| console.log(staff); | |||||
| setData(staff) | |||||
| setIsOpen(!isOpen) | setIsOpen(!isOpen) | ||||
| }; | }; | ||||
| const onConfirm = (staff: StaffResult) => { | |||||
| const onConfirm = useCallback(async (staff: StaffResult) => { | |||||
| console.log(staff); | console.log(staff); | ||||
| console.log(id); | |||||
| deleteStaff(id) | |||||
| // setIsOpen(!isOpen) | |||||
| } | |||||
| // if (data) | |||||
| // await deleteStaff(data) | |||||
| window.location.reload; | |||||
| }, [deleteStaff, data]); | |||||
| const onCancel = useCallback((staff: StaffResult) => { | const onCancel = useCallback((staff: StaffResult) => { | ||||
| console.log(staff); | console.log(staff); | ||||
| // setId(0) | |||||
| setIsOpen(false) | setIsOpen(false) | ||||
| }, []); | }, []); | ||||
| useEffect(() => { | |||||
| console.log("id"); | |||||
| console.log(id); | |||||
| }, [id]); | |||||
| // useEffect(() => { | |||||
| // console.log("id"); | |||||
| // console.log(id); | |||||
| // }, [id]); | |||||
| const columns = useMemo<Column<StaffResult>[]>( | const columns = useMemo<Column<StaffResult>[]>( | ||||
| () => [ | () => [ | ||||
| @@ -1,3 +1,4 @@ | |||||
| import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | import { fetchStaff, fetchTeamLeads } from "@/app/api/staff"; | ||||
| import React from "react"; | import React from "react"; | ||||
| import StaffSearch from "./StaffSearch"; | import StaffSearch from "./StaffSearch"; | ||||
| @@ -10,9 +11,7 @@ interface SubComponents { | |||||
| const StaffSearchWrapper: React.FC & SubComponents = async () => { | const StaffSearchWrapper: React.FC & SubComponents = async () => { | ||||
| const staff = await fetchStaff(); | const staff = await fetchStaff(); | ||||
| // const try = ...staff | |||||
| console.log(staff) | |||||
| // const records = staff.records; | |||||
| // console.log(staff) | |||||
| return <StaffSearch staff={staff} />; | return <StaffSearch staff={staff} />; | ||||
| }; | }; | ||||
| @@ -12,8 +12,8 @@ | |||||
| "Skillset": "技能", | "Skillset": "技能", | ||||
| "Salary Point": "薪金點", | "Salary Point": "薪金點", | ||||
| "Employ Type": "職位類別", | "Employ Type": "職位類別", | ||||
| "Hourly Rate": "時薪", | |||||
| "Email": "時薪", | |||||
| "hourlyRate": "時薪", | |||||
| "Email": "電郵地址", | |||||
| "Phone1": "聯絡電話", | "Phone1": "聯絡電話", | ||||
| "Phone2": "次要聯絡電話", | "Phone2": "次要聯絡電話", | ||||
| "Additional Info": "更多資料", | "Additional Info": "更多資料", | ||||
| @@ -23,5 +23,7 @@ | |||||
| "Join Position": "入職職位", | "Join Position": "入職職位", | ||||
| "Depart Date": "離職日期", | "Depart Date": "離職日期", | ||||
| "Depart Reason": "離職原因", | "Depart Reason": "離職原因", | ||||
| "Remark": "備註" | |||||
| "Remark": "備註", | |||||
| "Confirm": "確認", | |||||
| "Cancel": "取消" | |||||
| } | } | ||||