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"] }} | ||||