瀏覽代碼

update staff project history

tags/Baseline_30082024_FRONTEND_UAT
MSI\derek 1 年之前
父節點
當前提交
4a1c28954d
共有 6 個檔案被更改,包括 149 行新增13 行删除
  1. +17
    -0
      src/app/api/staff/index.ts
  2. +33
    -5
      src/components/EditStaff/EditStaff.tsx
  3. +6
    -3
      src/components/EditStaff/EditStaffWrapper.tsx
  4. +53
    -0
      src/components/EditStaff/ProjectHistory.tsx
  5. +38
    -3
      src/components/EditStaff/StaffInfo.tsx
  6. +2
    -2
      src/components/MailSetting/TimesheetMailDetails.tsx

+ 17
- 0
src/app/api/staff/index.ts 查看文件

@@ -30,6 +30,17 @@ export type IndivStaff = {
data: IndividualStaff data: IndividualStaff
} }


export type projects = {
id: number,
code: string,
name: string,
status: string
}

// export type InvolvedProject = {
// records: projects[]
// }

export type IndividualStaff = { export type IndividualStaff = {
id: number id: number
staffId: string staffId: string
@@ -110,6 +121,12 @@ export const fetchIndivStaff = cache(async (id: number) => {
}); });
}); });


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

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


+ 33
- 5
src/components/EditStaff/EditStaff.tsx 查看文件

@@ -11,14 +11,15 @@ import {
useForm, useForm,
} from "react-hook-form"; } from "react-hook-form";
import { CreateStaffInputs, saveStaff } from "@/app/api/staff/actions"; import { CreateStaffInputs, saveStaff } from "@/app/api/staff/actions";
import { Button, Stack, Typography } from "@mui/material";
import { Button, Stack, Tab, Tabs, TabsProps, Typography } from "@mui/material";
// import CreateStaffForm from "../CreateStaffForm"; // import CreateStaffForm from "../CreateStaffForm";
import { comboProp } from "@/app/api/companys/actions"; import { comboProp } from "@/app/api/companys/actions";
// import StaffInfo from "./StaffInfo"; // import StaffInfo from "./StaffInfo";
import { Check, Close, RestartAlt } from "@mui/icons-material"; import { Check, Close, RestartAlt } from "@mui/icons-material";
import StaffInfo from "./StaffInfo"; import StaffInfo from "./StaffInfo";
import { IndividualStaff, SalaryEffectiveInfo } from "@/app/api/staff";
import { IndividualStaff, projects, SalaryEffectiveInfo } from "@/app/api/staff";
import dayjs from "dayjs"; import dayjs from "dayjs";
import ProjectHistory from "./ProjectHistory";
// import { useGridApiContext } from '@mui/x-data-grid'; // import { useGridApiContext } from '@mui/x-data-grid';


export interface comboItem { export interface comboItem {
@@ -35,14 +36,16 @@ interface formProps {
Staff: IndividualStaff Staff: IndividualStaff
combos: comboItem; combos: comboItem;
SalaryEffectiveInfo: SalaryEffectiveInfo[]; SalaryEffectiveInfo: SalaryEffectiveInfo[];
InvolvedProject?: projects[]
} }




const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo }) => {
// console.log(Staff.joinDate)
const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo, InvolvedProject }) => {
console.log(InvolvedProject)
const defaultSkillset = Staff.skillset.map((s: any) => s.skill.id) const defaultSkillset = Staff.skillset.map((s: any) => s.skill.id)
const { t } = useTranslation(); const { t } = useTranslation();
const searchParams = useSearchParams() const searchParams = useSearchParams()
const [tabIndex, setTabIndex] = useState(0);
const id = parseInt(searchParams.get("id") || "0"); const id = parseInt(searchParams.get("id") || "0");
const formProps = useForm<CreateStaffInputs & { salaryEffectiveInfo: SalaryEffectiveInfo[] } & { delSalaryEffectiveInfo: number[] }>({ const formProps = useForm<CreateStaffInputs & { salaryEffectiveInfo: SalaryEffectiveInfo[] } & { delSalaryEffectiveInfo: number[] }>({
defaultValues: { defaultValues: {
@@ -190,6 +193,13 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo })
return null; return null;
} }


const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
(_e, newValue) => {
setTabIndex(newValue);
},
[]
);

// const resetStaff = useCallback(() => { // const resetStaff = useCallback(() => {
// window.location.reload() // window.location.reload()
// console.log(dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT)) // console.log(dayjs(Staff.joinDate).format(INPUT_DATE_FORMAT))
@@ -258,7 +268,24 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo })
{serverError} {serverError}
</Typography> </Typography>
)} )}
{Staff && <StaffInfo combos={combos}/>}
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
<Tabs
value={tabIndex}
onChange={handleTabChange}
variant="scrollable"
>
<Tab label={t("Info")}/>
<Tab label={t("Involved Project History")} />
</Tabs>
</Stack>
{tabIndex == 0 && Staff && <StaffInfo combos={combos} />}
{tabIndex == 1 && <ProjectHistory InvolvedProject={InvolvedProject}/>}
{tabIndex == 0 &&
<Stack direction="row" justifyContent="flex-end" gap={1}> <Stack direction="row" justifyContent="flex-end" gap={1}>
<Button <Button
variant="text" variant="text"
@@ -283,6 +310,7 @@ const EditStaff: React.FC<formProps> = ({ Staff, combos, SalaryEffectiveInfo })
{t("Confirm")} {t("Confirm")}
</Button> </Button>
</Stack> </Stack>
}
</Stack> </Stack>
</FormProvider> </FormProvider>
</> </>


+ 6
- 3
src/components/EditStaff/EditStaffWrapper.tsx 查看文件

@@ -1,8 +1,7 @@
import React from "react"; import React from "react";
import EditStaff, { comboItem } from "./EditStaff"; import EditStaff, { comboItem } from "./EditStaff";
import EditStaffLoading from "./EditStaffLoading"; import EditStaffLoading from "./EditStaffLoading";
import { StaffResult, fetchIndivStaff, fetchStaff, fetchStaffSalaryEffectiveInfo, fetchTeamLeads, preloadStaff } from "@/app/api/staff";
import { useSearchParams } from "next/navigation";
import { fetchIndivStaff, fetchStaffInvolvedProjects, fetchStaffSalaryEffectiveInfo, preloadStaff } from "@/app/api/staff";
import { fetchTeamCombo } from "@/app/api/team/actions"; import { fetchTeamCombo } from "@/app/api/team/actions";
import { fetchDepartmentCombo } from "@/app/api/departments/actions"; import { fetchDepartmentCombo } from "@/app/api/departments/actions";
import { fetchPositionCombo } from "@/app/api/positions/actions"; import { fetchPositionCombo } from "@/app/api/positions/actions";
@@ -23,6 +22,7 @@ const EditStaffWrapper: React.FC<Props> & SubComponents = async ({
id id
}) => { }) => {
preloadStaff() preloadStaff()
const [ const [
Staff, Staff,
CompanyCombo, CompanyCombo,
@@ -33,6 +33,7 @@ const EditStaffWrapper: React.FC<Props> & SubComponents = async ({
SkillCombo, SkillCombo,
SalaryCombo, SalaryCombo,
SalaryEffectiveInfo, SalaryEffectiveInfo,
InvolvedProject
] = await Promise.all([ ] = await Promise.all([
fetchIndivStaff(id), fetchIndivStaff(id),
fetchCompanyCombo(), fetchCompanyCombo(),
@@ -43,8 +44,10 @@ const EditStaffWrapper: React.FC<Props> & SubComponents = async ({
fetchSkillCombo(), fetchSkillCombo(),
fetchSalaryCombo(), fetchSalaryCombo(),
fetchStaffSalaryEffectiveInfo(id), fetchStaffSalaryEffectiveInfo(id),
fetchStaffInvolvedProjects(id)
]); ]);


console.log(InvolvedProject)
console.log(SalaryCombo.records) console.log(SalaryCombo.records)
const combos: comboItem = { const combos: comboItem = {
company: CompanyCombo.records, company: CompanyCombo.records,
@@ -61,7 +64,7 @@ Staff.data.departDate = Staff.data.departDate && dateArrayToString(Staff.data.de
// [{id:0, salaryPoint: 1, date:"2021-05-05"}, {id:1, salaryPoint: 43, date:"2024-05-05"}] // [{id:0, salaryPoint: 1, date:"2021-05-05"}, {id:1, salaryPoint: 43, date:"2024-05-05"}]
console.log(Staff.data) console.log(Staff.data)


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


EditStaffWrapper.Loading = EditStaffLoading; EditStaffWrapper.Loading = EditStaffLoading;


+ 53
- 0
src/components/EditStaff/ProjectHistory.tsx 查看文件

@@ -0,0 +1,53 @@
import { projects } from "@/app/api/staff";
import { Box, Card, CardContent, Grid, Stack } from "@mui/material";
import StyledDataGrid from "../StyledDataGrid";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";


interface Props {
InvolvedProject?: projects[]
}


const ProjectHistory: React.FC<Props> = async ({ InvolvedProject }) => {
const { t } = useTranslation();
const projectCols = useMemo(
() => [
{
field: 'code',
headerName: t("Code"),
flex: .4,
},
{
field: 'name',
headerName: t("Name"),
flex: 1,
},
], [InvolvedProject])

return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
<Box>
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
<Grid item xs={6}>
<StyledDataGrid
rows={InvolvedProject?.filter(item => item.status === "On-going") ?? []}
columns={projectCols}
/>
</Grid>
<Grid item xs={6}>
<StyledDataGrid
rows={InvolvedProject?.filter(item => item.status === "Completed") ?? []}
columns={projectCols}
/>
</Grid>
</Grid>
</Box>
</CardContent>
</Card>
)

}
export default ProjectHistory;

+ 38
- 3
src/components/EditStaff/StaffInfo.tsx 查看文件

@@ -16,6 +16,8 @@ import {
Checkbox, Checkbox,
FormControl, FormControl,
InputLabel, InputLabel,
List,
ListItem,
ListItemText, ListItemText,
MenuItem, MenuItem,
Select, Select,
@@ -27,10 +29,11 @@ import { DemoItem } from "@mui/x-date-pickers/internals/demo";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import SalaryEffectiveModel from "./SalaryEffectiveModel"; import SalaryEffectiveModel from "./SalaryEffectiveModel";
import { SalaryEffectiveInfo } from "@/app/api/staff";
import { SalaryEffectiveInfo, projects } from "@/app/api/staff";


interface Props { interface Props {
combos: comboItem; combos: comboItem;
// InvolvedProject?: projects[]
} }


const StaffInfo: React.FC<Props> = ({ combos }) => { const StaffInfo: React.FC<Props> = ({ combos }) => {
@@ -411,8 +414,40 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
/> />
</Grid> </Grid>
</Grid> </Grid>
{/* <Grid container spacing={2} columns={{ xs: 6, sm: 12 }} marginTop={3}> */}
{/* <Grid item xs={6} md={3}>
<Typography sx={{ ml: 1 }} variant="h6" component="div">
{t("on-going")}
</Typography>
<List>
{InvolvedProject.filter((item: projects) => item.status === "On-going")
.map((item: projects) => (
<ListItem key={item.code}>
<ListItemText
primary={item.name}
secondary={item.code}
/>
</ListItem>
))
}
</List>
</Grid>
<Grid item xs={6} md={3}>
<Typography sx={{ ml: 1 }} variant="h6" component="div">
{t("completed")}
</Typography>
<List>
<ListItem>
<ListItemText
primary="Single-line item"
secondary={'Secondary text'}
/>
</ListItem>
</List>
</Grid>
</Grid> */}
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }} marginTop={3}> <Grid container spacing={2} columns={{ xs: 6, sm: 12 }} marginTop={3}>
<Grid item xs={6}>
{/* <Grid item xs={6}>
<TextField <TextField
label={t("Emergency Contact Name")} label={t("Emergency Contact Name")}
fullWidth fullWidth
@@ -447,7 +482,7 @@ const StaffInfo: React.FC<Props> = ({ combos }) => {
: t("Please input correct Emergency Contact Phone")) : t("Please input correct Emergency Contact Phone"))
} }
/> />
</Grid>
</Grid> */}
<Grid item xs={6}> <Grid item xs={6}>
<LocalizationProvider <LocalizationProvider
dateAdapter={AdapterDayjs} dateAdapter={AdapterDayjs}


+ 2
- 2
src/components/MailSetting/TimesheetMailDetails.tsx 查看文件

@@ -65,8 +65,8 @@ const TimesheetMailDetails: React.FC<Props> = ({ isActive }) => {
label={t("Required Params")} label={t("Required Params")}
fullWidth fullWidth
value={"${date}"} value={"${date}"}
disabled
error={Boolean(errors.template?.template)}
// disabled
// error={Boolean(errors.template?.template)}
/> />
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>


Loading…
取消
儲存