2. fallback search resulr from column sorting feature updates 3. Add selected project display in Project cash flow pagedevelop
| @@ -95,10 +95,10 @@ const MailSetting: React.FC<Props> = ({ | |||||
| try { | try { | ||||
| // msg = "testEveryone" | // msg = "testEveryone" | ||||
| // await testEveryone() | // await testEveryone() | ||||
| msg = "test7th" | |||||
| await test7th() | |||||
| // msg = "test15th" | |||||
| // await test15th() | |||||
| // msg = "test7th" | |||||
| // await test7th() | |||||
| msg = "test15th" | |||||
| await test15th() | |||||
| } catch (error) { | } catch (error) { | ||||
| console.log(error) | console.log(error) | ||||
| console.log(msg) | console.log(msg) | ||||
| @@ -5,7 +5,7 @@ import { useState, useEffect, useMemo } from "react"; | |||||
| import Paper from "@mui/material/Paper"; | import Paper from "@mui/material/Paper"; | ||||
| import { TFunction } from "i18next"; | import { TFunction } from "i18next"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { Card, CardHeader } from "@mui/material"; | |||||
| import { Card, CardContent, CardHeader } from "@mui/material"; | |||||
| import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; | ||||
| import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; | ||||
| import ReactApexChart from "react-apexcharts"; | import ReactApexChart from "react-apexcharts"; | ||||
| @@ -26,6 +26,7 @@ import dayjs from 'dayjs'; | |||||
| import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee"; | import ProjectTotalFee from "../CreateInvoice_forGen/ProjectTotalFee"; | ||||
| import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||
| import { useSearchParams } from 'next/navigation'; | import { useSearchParams } from 'next/navigation'; | ||||
| import { ResetTvOutlined } from "@mui/icons-material"; | |||||
| interface Props { | interface Props { | ||||
| projects: CashFlow[]; | projects: CashFlow[]; | ||||
| @@ -64,6 +65,7 @@ const ProjectCashFlow: React.FC = () => { | |||||
| const [monthlyAnticipateExpenditureList, setMonthlyAnticipateExpenditureList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]); | const [monthlyAnticipateExpenditureList, setMonthlyAnticipateExpenditureList]: any[] = React.useState([0,0,0,0,0,0,0,0,0,0,0,0]); | ||||
| const [ledgerData, setLedgerData]: any[] = React.useState([]); | const [ledgerData, setLedgerData]: any[] = React.useState([]); | ||||
| const [isInitializing, setIsInitializing] = useState(true); | const [isInitializing, setIsInitializing] = useState(true); | ||||
| const [projectInfo, setProjectInfo]: any[] = useState([]) | |||||
| const [cashFlowYear, setCashFlowYear]: any[] = React.useState( | const [cashFlowYear, setCashFlowYear]: any[] = React.useState( | ||||
| todayDate.getFullYear(), | todayDate.getFullYear(), | ||||
| ); | ); | ||||
| @@ -86,6 +88,11 @@ const ProjectCashFlow: React.FC = () => { | |||||
| ); | ); | ||||
| const projectIdList = selectedRowsData.map((row: any) => row.id); | const projectIdList = selectedRowsData.map((row: any) => row.id); | ||||
| setSelectedProjectIdList(projectIdList); | setSelectedProjectIdList(projectIdList); | ||||
| console.log(projectData) | |||||
| setProjectInfo(projectData.filter((result:any)=> { | |||||
| // console.log("Checking ID:", result.id, "against list:", projectIdList); | |||||
| return projectIdList.includes(result.id) | |||||
| })) | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -240,7 +247,6 @@ const ProjectCashFlow: React.FC = () => { | |||||
| fetchReceivableAndExpenditureData(); | fetchReceivableAndExpenditureData(); | ||||
| fetchAnticipateData(); | fetchAnticipateData(); | ||||
| fetchProjectCashFlowLedger(); | fetchProjectCashFlowLedger(); | ||||
| }, [cashFlowYear,selectedProjectIdList]); | }, [cashFlowYear,selectedProjectIdList]); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| @@ -829,6 +835,15 @@ const ProjectCashFlow: React.FC = () => { | |||||
| onRowSelectionModelChange={handleSelectionChange} | onRowSelectionModelChange={handleSelectionChange} | ||||
| rowSelectionModel={selectionModel} | rowSelectionModel={selectionModel} | ||||
| /> | /> | ||||
| <Grid container> | |||||
| <Grid item xs={12} md={12} lg={12}> | |||||
| <Card> | |||||
| <CardContent> | |||||
| { projectInfo[0]?.projectCode && `${projectInfo[0]?.projectCode} - ${projectInfo[0]?.projectName}`} | |||||
| </CardContent> | |||||
| </Card> | |||||
| </Grid> | |||||
| </Grid> | |||||
| <Grid item sm> | <Grid item sm> | ||||
| <div style={{ display: "inline-block", width: "50%" }}> | <div style={{ display: "inline-block", width: "50%" }}> | ||||
| <Grid item xs={12} md={12} lg={12}> | <Grid item xs={12} md={12} lg={12}> | ||||
| @@ -28,7 +28,10 @@ const ProjectSearchWrapper: React.FC & SubComponents = async () => { | |||||
| let filteredProjects = projects; | let filteredProjects = projects; | ||||
| if (!isViewAllProjectRight) { | if (!isViewAllProjectRight) { | ||||
| filteredProjects = projects.filter((project) => project.teamId === teamId || project.team === "ST"); | |||||
| filteredProjects = projects.filter((project) => project.teamId === teamId ); | |||||
| if (teamId == 1){ | |||||
| filteredProjects = projects.filter((project) => project.teamId === teamId || project.team === "ST"); | |||||
| } | |||||
| } | } | ||||
| return ( | return ( | ||||
| @@ -158,50 +158,50 @@ function SearchResults<T extends ResultWithId>({ | |||||
| return column.underline ?? "always"; | return column.underline ?? "always"; | ||||
| }; | }; | ||||
| type OrderProps = Record<keyof T, Boolean> | |||||
| const [sortedItems, setSortedItems] = useState(items) | |||||
| const [orderProps, setOrderProps] = useState<OrderProps>(() => { | |||||
| if (items.length === 0) { | |||||
| return {} as OrderProps | |||||
| } | |||||
| return Object.keys(sortedItems[0]).reduce((acc, key) => { | |||||
| if (key === "deleted" || key === "id") return acc | |||||
| acc[key as keyof T] = false; | |||||
| return acc; | |||||
| }, {} as OrderProps); | |||||
| }); | |||||
| const changeOrder = useCallback((key: keyof T) => { | |||||
| // preserve all column sorting | |||||
| // setOrderProps( | |||||
| // (prev) => ({ | |||||
| // [...prev]: false, | |||||
| // [key]: !prev[key] | |||||
| // }) | |||||
| // ) | |||||
| // only sort 1 column | |||||
| setOrderProps( | |||||
| (prev) => { | |||||
| const newOrderProps = Object.keys(prev).reduce((acc, currKey) => { | |||||
| acc[currKey as keyof T] = currKey === key ? !prev[currKey as keyof T] : false; | |||||
| return acc; | |||||
| }, {} as OrderProps); | |||||
| return newOrderProps; | |||||
| } | |||||
| ) | |||||
| }, []) | |||||
| const sortingItems = useCallback( | |||||
| (key: keyof T) => { | |||||
| // true === asc | |||||
| // false === desc | |||||
| console.log(orderProps) | |||||
| if (orderProps[key]) { | |||||
| return orderBy(sortedItems, key, 'asc') | |||||
| } else { | |||||
| return orderBy(sortedItems, key, 'desc') | |||||
| } | |||||
| } | |||||
| , [sortedItems, orderProps] | |||||
| ) | |||||
| // type OrderProps = Record<keyof T, Boolean> | |||||
| // const [sortedItems, setSortedItems] = useState(items) | |||||
| // const [orderProps, setOrderProps] = useState<OrderProps>(() => { | |||||
| // if (items.length === 0) { | |||||
| // return {} as OrderProps | |||||
| // } | |||||
| // return Object.keys(sortedItems[0]).reduce((acc, key) => { | |||||
| // if (key === "deleted" || key === "id") return acc | |||||
| // acc[key as keyof T] = false; | |||||
| // return acc; | |||||
| // }, {} as OrderProps); | |||||
| // }); | |||||
| // const changeOrder = useCallback((key: keyof T) => { | |||||
| // // preserve all column sorting | |||||
| // // setOrderProps( | |||||
| // // (prev) => ({ | |||||
| // // [...prev]: false, | |||||
| // // [key]: !prev[key] | |||||
| // // }) | |||||
| // // ) | |||||
| // // only sort 1 column | |||||
| // setOrderProps( | |||||
| // (prev) => { | |||||
| // const newOrderProps = Object.keys(prev).reduce((acc, currKey) => { | |||||
| // acc[currKey as keyof T] = currKey === key ? !prev[currKey as keyof T] : false; | |||||
| // return acc; | |||||
| // }, {} as OrderProps); | |||||
| // return newOrderProps; | |||||
| // } | |||||
| // ) | |||||
| // }, []) | |||||
| // const sortingItems = useCallback( | |||||
| // (key: keyof T) => { | |||||
| // // true === asc | |||||
| // // false === desc | |||||
| // console.log(orderProps) | |||||
| // if (orderProps[key]) { | |||||
| // return orderBy(sortedItems, key, 'asc') | |||||
| // } else { | |||||
| // return orderBy(sortedItems, key, 'desc') | |||||
| // } | |||||
| // } | |||||
| // , [sortedItems, orderProps] | |||||
| // ) | |||||
| const table = ( | const table = ( | ||||
| <> | <> | ||||
| <TableContainer sx={{ maxHeight: 440 }}> | <TableContainer sx={{ maxHeight: 440 }}> | ||||
| @@ -209,25 +209,15 @@ function SearchResults<T extends ResultWithId>({ | |||||
| <TableHead> | <TableHead> | ||||
| <TableRow> | <TableRow> | ||||
| {columns.filter(item => item.isHidden !== true).map((column, idx) => ( | {columns.filter(item => item.isHidden !== true).map((column, idx) => ( | ||||
| <TableCell | |||||
| key={`${column.name.toString()}${idx}`} | |||||
| onClick={() => { | |||||
| changeOrder(column.name) | |||||
| setSortedItems(sortingItems(column.name)) | |||||
| }} | |||||
| > | |||||
| <TableCell key={`${column.name.toString()}${idx}`}> | |||||
| {column?.type === "money" ? <div style={{display: "flex", justifyContent: "flex-end"}}>{column.label}</div> : column.label} | {column?.type === "money" ? <div style={{display: "flex", justifyContent: "flex-end"}}>{column.label}</div> : column.label} | ||||
| {(() => { | |||||
| const isAscending = orderProps[column.name]; | |||||
| if (isAscending === undefined) return undefined; | |||||
| return isAscending ? <ArrowUp /> : <ArrowDown />; | |||||
| })()} | |||||
| </TableCell> | </TableCell> | ||||
| ))} | ))} | ||||
| </TableRow> | </TableRow> | ||||
| </TableHead> | </TableHead> | ||||
| <TableBody> | <TableBody> | ||||
| {sortedItems | |||||
| {items | |||||
| .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) | .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) | ||||
| .map((item) => { | .map((item) => { | ||||
| return ( | return ( | ||||
| @@ -280,7 +270,7 @@ function SearchResults<T extends ResultWithId>({ | |||||
| <TablePagination | <TablePagination | ||||
| rowsPerPageOptions={[10, 25, 100]} | rowsPerPageOptions={[10, 25, 100]} | ||||
| component="div" | component="div" | ||||
| count={sortedItems.length} | |||||
| count={items.length} | |||||
| rowsPerPage={rowsPerPage} | rowsPerPage={rowsPerPage} | ||||
| page={page} | page={page} | ||||
| onPageChange={handleChangePage} | onPageChange={handleChangePage} | ||||
| @@ -25,6 +25,7 @@ interface CommonProps { | |||||
| referenceDay: Dayjs; | referenceDay: Dayjs; | ||||
| includeLeaves?: boolean; | includeLeaves?: boolean; | ||||
| leaveTypes?: LeaveType[]; | leaveTypes?: LeaveType[]; | ||||
| isTimesheetAdmendment?: boolean; | |||||
| } | } | ||||
| interface SingleAutocompleteProps extends CommonProps { | interface SingleAutocompleteProps extends CommonProps { | ||||
| @@ -44,7 +45,8 @@ interface MultiAutocompleteProps extends CommonProps { | |||||
| includeLeaves: false; | includeLeaves: false; | ||||
| } | } | ||||
| type Props = SingleAutocompleteProps | MultiAutocompleteProps; | |||||
| type Props = SingleAutocompleteProps | MultiAutocompleteProps ; | |||||
| const getGroupName = (t: TFunction, groupName: string): string => { | const getGroupName = (t: TFunction, groupName: string): string => { | ||||
| switch (groupName) { | switch (groupName) { | ||||
| @@ -73,6 +75,7 @@ const AutocompleteProjectSelect: React.FC<Props> = ({ | |||||
| multiple, | multiple, | ||||
| leaveTypes, | leaveTypes, | ||||
| includeLeaves, | includeLeaves, | ||||
| isTimesheetAdmendment | |||||
| }) => { | }) => { | ||||
| const { t } = useTranslation("home"); | const { t } = useTranslation("home"); | ||||
| const allFilteredProjects = useMemo(() => { | const allFilteredProjects = useMemo(() => { | ||||
| @@ -97,18 +100,20 @@ console.log(assignedProjects) | |||||
| label: `${p.code} - ${p.name}`, | label: `${p.code} - ${p.name}`, | ||||
| group: "assigned", | group: "assigned", | ||||
| })), | })), | ||||
| // ...(includeLeaves && leaveTypes | |||||
| // ? leaveTypes.map((l) => ({ | |||||
| // value: `leave-${l.id}`, | |||||
| // label: t(l.name), | |||||
| // group: "leaves", | |||||
| // })) | |||||
| // : []), | |||||
| // ...nonAssignedProjects.map((p) => ({ | |||||
| // value: p.id, | |||||
| // label: `${p.code} - ${p.name}`, | |||||
| // group: assignedProjects.length === 0 ? "all-projects" : "non-assigned", | |||||
| // })), | |||||
| ...(includeLeaves && leaveTypes | |||||
| ? leaveTypes.map((l) => ({ | |||||
| value: `leave-${l.id}`, | |||||
| label: t(l.name), | |||||
| group: "leaves", | |||||
| })) | |||||
| : []), | |||||
| ...(isTimesheetAdmendment | |||||
| ? nonAssignedProjects.map((p) => ({ | |||||
| value: p.id, | |||||
| label: `${p.code} - ${p.name}`, | |||||
| group: assignedProjects.length === 0 ? "all-projects" : "non-assigned", | |||||
| })) | |||||
| : []), | |||||
| ]; | ]; | ||||
| }, [assignedProjects, includeLeaves, leaveTypes, nonAssignedProjects, t]); | }, [assignedProjects, includeLeaves, leaveTypes, nonAssignedProjects, t]); | ||||
| @@ -177,6 +177,7 @@ const TimesheetEditModal: React.FC<Props> = ({ | |||||
| setValue("taskGroupId", firstTaskGroup?.value); | setValue("taskGroupId", firstTaskGroup?.value); | ||||
| setValue("taskId", undefined); | setValue("taskId", undefined); | ||||
| }} | }} | ||||
| isTimesheetAdmendment={true} | |||||
| /> | /> | ||||
| )} | )} | ||||
| rules={{ deps: ["taskGroupId", "taskId"] }} | rules={{ deps: ["taskGroupId", "taskId"] }} | ||||