Procházet zdrojové kódy

Add SalaryEffectiveModel for salary adjustment

tags/Baseline_30082024_FRONTEND_UAT
MSI\2Fi před 1 rokem
rodič
revize
4e0c7ac6af
7 změnil soubory, kde provedl 160 přidání a 30 odebrání
  1. +6
    -0
      src/app/api/staff/actions.ts
  2. +6
    -0
      src/app/api/staff/index.ts
  3. +7
    -4
      src/components/EditStaff/EditStaff.tsx
  4. +1
    -1
      src/components/EditStaff/EditStaffWrapper.tsx
  5. +85
    -0
      src/components/EditStaff/SalaryEffectiveModel.tsx
  6. +53
    -24
      src/components/EditStaff/StaffInfo.tsx
  7. +2
    -1
      src/i18n/zh/staff.json

+ 6
- 0
src/app/api/staff/actions.ts Zobrazit soubor

@@ -43,6 +43,12 @@ export interface CreateStaffInputs {
// team: Team[];
}

export interface salaryEffectiveInfo {
id: number;
date: string;
salaryPoint: number;
}

export const saveStaff = async (data: CreateStaffInputs) => {
// try {
const newStaffList = await serverFetchJson(`${BASE_API_URL}/staffs/save`, {


+ 6
- 0
src/app/api/staff/index.ts Zobrazit soubor

@@ -78,6 +78,12 @@ export interface searchInput {
currentPosition: string;
}

export interface SalaryEffectiveInfo {
id: number;
date: string;
salaryPoint: number;
}

export const preloadTeamLeads = () => {
fetchTeamLeads();
};


+ 7
- 4
src/components/EditStaff/EditStaff.tsx Zobrazit soubor

@@ -24,7 +24,7 @@ import { fetchSalaryCombo } from "@/app/api/salarys/actions";
import { Check, Close, RestartAlt } from "@mui/icons-material";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import StaffInfo from "./StaffInfo";
import { IndividualStaff } from "@/app/api/staff";
import { IndividualStaff, SalaryEffectiveInfo } from "@/app/api/staff";
import dayjs from "dayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { List, differenceBy } from "lodash";
@@ -42,15 +42,16 @@ export interface comboItem {
interface formProps {
Staff: IndividualStaff
combos: comboItem;
SalaryEffectiveInfo: SalaryEffectiveInfo[];
}


const EditStaff: React.FC<formProps> = ({ Staff, combos }) => {
const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo }) => {
const defaultSkillset = Staff.skillset.map((s: any) => s.skill.id)
const { t } = useTranslation();
const searchParams = useSearchParams()
const id = parseInt(searchParams.get("id") || "0");
const formProps = useForm<CreateStaffInputs>({
const formProps = useForm<CreateStaffInputs & { salaryEffectiveInfo: SalaryEffectiveInfo[] }>({
defaultValues: {
staffId: Staff.staffId,
name: Staff.name,
@@ -73,6 +74,7 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos }) => {
departDate: dayjs(Staff.departDate).toString() || "",
departReason: Staff.departReason,
remark: Staff.remark,
salaryEffectiveInfo: SalaryEffectiveInfo
}});
const [serverError, setServerError] = useState("");
const router = useRouter();
@@ -84,7 +86,7 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos }) => {
return str1 === str2 || str1 === str3 || str2 === str3;
}

const onSubmit = useCallback<SubmitHandler<CreateStaffInputs>>(
const onSubmit = useCallback<SubmitHandler<CreateStaffInputs & { salaryEffectiveInfo: SalaryEffectiveInfo[] } >>(
async (data) => {
try {
console.log(data);
@@ -190,6 +192,7 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos }) => {
departDate: !Staff.departDate ? "" : dayjs(Staff.departDate).format(INPUT_DATE_FORMAT),
departReason: Staff.departReason,
remark: Staff.remark,
salaryEffectiveInfo: SalaryEffectiveInfo
});
}, [Staff,formProps]);


+ 1
- 1
src/components/EditStaff/EditStaffWrapper.tsx Zobrazit soubor

@@ -54,7 +54,7 @@ const EditStaffWrapper: React.FC<Props> & SubComponents = async ({

console.log(Staff.data)

return <EditStaff Staff={Staff.data} combos={combos}/>;
return <EditStaff Staff={Staff.data} combos={combos} SalaryEffectiveInfo={[{id:0, salaryPoint: 1, date:"2021-05-05"}]}/>;
};

EditStaffWrapper.Loading = EditStaffLoading;


+ 85
- 0
src/components/EditStaff/SalaryEffectiveModel.tsx Zobrazit soubor

@@ -0,0 +1,85 @@

import React, { useEffect } from 'react';
import { Modal, Box, Typography, Button, TextField, FormControl, InputLabel, Select, MenuItem, Paper, SxProps } from '@mui/material';
import { useForm, Controller } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT } from '@/app/utils/formatUtil';
import dayjs from 'dayjs';
import { DatePicker } from '@mui/x-date-pickers';

interface SalaryEffectiveModelProps {
open: boolean;
onClose: () => void;
modalSx?: SxProps;
onSave: () => void;
}

const modalSx: SxProps = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "90%",
maxWidth: "sm",
maxHeight: "90%",
padding: 3,
display: "flex",
flexDirection: "column",
gap: 2,
};

const SalaryEffectiveModel: React.FC<SalaryEffectiveModelProps> = ({ open, onClose, modalSx: mSx, onSave }) => {
const { t } = useTranslation();
const { control, register, formState, trigger, watch, setValue } = useForm({});

const formValues = watch(); // This line of code is using the watch function from react-hook-form to get the current values of the form fields.

const handleClose = () => {
onClose();
};

const handleSave = async () => {
const isValid = await trigger();
if (isValid) {
onSave();
onClose();
}
};

useEffect(() => {
console.log(formValues)
}, [open])

return (
<Modal open={open} onClose={handleClose}>
<Paper sx={{ ...modalSx, ...mSx }}>
<Typography variant="h6" component="h2">
{t('Salary Effective Date Change')}
</Typography>
<FormControl>
<TextField
label={t('Salary')}
type="number"
fullWidth
{...register('salary', {
valueAsNumber: true,
required: t('Salary is required'),
})}
error={Boolean(formState.errors.salary)}
// helperText={formState.errors.salary?.message}
/>
<Box display="flex" justifyContent="flex-end" gap={2}>
<Button variant="text" onClick={handleClose}>
{t('Cancel')}
</Button>
<Button variant="contained" onClick={handleSave}>
{t("Save")}
</Button>
</Box>
</FormControl>
</Paper>
</Modal>
);
};

export default SalaryEffectiveModel;

+ 53
- 24
src/components/EditStaff/StaffInfo.tsx Zobrazit soubor

@@ -9,9 +9,10 @@ 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 { useCallback, useEffect, useState } from "react";
import { CreateStaffInputs } from "@/app/api/staff/actions";
import {
Button,
Checkbox,
FormControl,
InputLabel,
@@ -25,6 +26,8 @@ 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";
import SalaryEffectiveModel from "./SalaryEffectiveModel";
import { SalaryEffectiveInfo } from "@/app/api/staff";

interface Props {
combos: comboItem;
@@ -45,7 +48,7 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
getValues,
watch,
clearErrors,
} = useFormContext<CreateStaffInputs>();
} = useFormContext<CreateStaffInputs & { salaryEffectiveInfo: SalaryEffectiveInfo[] }>();

const employType = [
{ id: 1, label: "FT" },
@@ -57,6 +60,21 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
{}
);

// Salary Effiective History edit modal related
const [salaryEffectiveModelOpen, setSalaaryEffectiveModelOpen] = useState(false);
const closeSalaryEffectiveModel = useCallback(() => {
setSalaaryEffectiveModelOpen(false);
}, []);
const openSalaryEffectiveModel = useCallback(() => {
setSalaaryEffectiveModelOpen(true);
}, []);
const onSalaryEffectiveSave = useCallback(async () => {
console.log(getValues())
setSalaaryEffectiveModelOpen(false);
}, []);



const resetStaff = useCallback(() => {
console.log(defaultValues);
if (defaultValues !== undefined) {
@@ -275,29 +293,35 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
</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}
<FormControl fullWidth>
<InputLabel required>{t("Salary Point")}</InputLabel>
<Controller
control={control}
name="salaryId"
render={({ field }) => (
<Box display="flex" justifyContent="space-between" alignItems="center">
<Select
label={t("Salary Point")}
{...field}
error={Boolean(errors.salaryId)}
style={{ flex: 1, marginRight: '8px' }}
>
{t(salary.label)}
</MenuItem>
))}
</Select>
)}
/>
</FormControl>
{combos.salary.map((salary, index) => (
<MenuItem
key={`${salary.id}-${index}`}
value={salary.id}
>
{t(salary.label)}
</MenuItem>
))}
</Select>
<Button variant="contained" size="small" onClick={openSalaryEffectiveModel}>
{t("Edit")}
</Button>
</Box>
)}
/>
</FormControl>
</Grid>
<Grid item xs={6}>
<FormControl fullWidth>
@@ -516,6 +540,11 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
</Grid>
</Box>
</CardContent>
<SalaryEffectiveModel
open={salaryEffectiveModelOpen}
onClose={closeSalaryEffectiveModel}
onSave={onSalaryEffectiveSave}
/>
</Card>
);
};


+ 2
- 1
src/i18n/zh/staff.json Zobrazit soubor

@@ -27,5 +27,6 @@
"Remark": "備註",
"Reset": "重設",
"Confirm": "確認",
"Cancel": "取消"
"Cancel": "取消",
"Save": "儲存"
}

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