From f9f7af69d5eb6888b91007a498f788b7a89b3598 Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Fri, 2 Feb 2024 13:10:46 +0800 Subject: [PATCH] update staff reimbursement update create claim minor update on timesheet input --- .../ClaimApproval}/page.tsx | 0 .../staffReimbursement/ClaimSummary/page.tsx | 11 + .../(main)/staffReimbursement/create/page.tsx | 21 + src/app/(main)/staffReimbursement/page.tsx | 47 ++ src/app/api/claims/index.ts | 50 +++ src/components/ClaimSearch/ClaimSearch.tsx | 91 ++++ .../ClaimSearch/ClaimSearchLoading.tsx | 40 ++ .../ClaimSearch/ClaimSearchWrapper.tsx | 18 + src/components/ClaimSearch/index.ts | 1 + src/components/CreateClaim/ClaimDetails.tsx | 79 ++++ src/components/CreateClaim/ClaimInputGrid.tsx | 406 ++++++++++++++++++ src/components/CreateClaim/CreateClaim.tsx | 48 +++ src/components/CreateClaim/index.ts | 1 + .../EnterTimesheet/EnterTimesheetModal.tsx | 10 +- src/components/EnterTimesheet/ProjectGrid.tsx | 62 --- .../EnterTimesheet/TimesheetInputGrid.tsx | 104 ++--- .../NavigationContent/NavigationContent.tsx | 5 +- .../UserWorkspacePage/ProjectGrid.tsx | 2 +- src/theme/colorConst.js | 12 + 19 files changed, 891 insertions(+), 117 deletions(-) rename src/app/(main)/{claim => staffReimbursement/ClaimApproval}/page.tsx (100%) create mode 100644 src/app/(main)/staffReimbursement/ClaimSummary/page.tsx create mode 100644 src/app/(main)/staffReimbursement/create/page.tsx create mode 100644 src/app/(main)/staffReimbursement/page.tsx create mode 100644 src/app/api/claims/index.ts create mode 100644 src/components/ClaimSearch/ClaimSearch.tsx create mode 100644 src/components/ClaimSearch/ClaimSearchLoading.tsx create mode 100644 src/components/ClaimSearch/ClaimSearchWrapper.tsx create mode 100644 src/components/ClaimSearch/index.ts create mode 100644 src/components/CreateClaim/ClaimDetails.tsx create mode 100644 src/components/CreateClaim/ClaimInputGrid.tsx create mode 100644 src/components/CreateClaim/CreateClaim.tsx create mode 100644 src/components/CreateClaim/index.ts delete mode 100644 src/components/EnterTimesheet/ProjectGrid.tsx diff --git a/src/app/(main)/claim/page.tsx b/src/app/(main)/staffReimbursement/ClaimApproval/page.tsx similarity index 100% rename from src/app/(main)/claim/page.tsx rename to src/app/(main)/staffReimbursement/ClaimApproval/page.tsx diff --git a/src/app/(main)/staffReimbursement/ClaimSummary/page.tsx b/src/app/(main)/staffReimbursement/ClaimSummary/page.tsx new file mode 100644 index 0000000..9388d1a --- /dev/null +++ b/src/app/(main)/staffReimbursement/ClaimSummary/page.tsx @@ -0,0 +1,11 @@ +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Claim", +}; + +const Claim: React.FC = async () => { + return "Claim"; +}; + +export default Claim; diff --git a/src/app/(main)/staffReimbursement/create/page.tsx b/src/app/(main)/staffReimbursement/create/page.tsx new file mode 100644 index 0000000..eafce4f --- /dev/null +++ b/src/app/(main)/staffReimbursement/create/page.tsx @@ -0,0 +1,21 @@ +import CreateClaim from "@/components/CreateClaim"; +import { getServerI18n } from "@/i18n"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Create Claim", +}; + +const CreateClaims: React.FC = async () => { + const { t } = await getServerI18n("claims"); + + return ( + <> + {t("Create Claim")} + + + ); +}; + +export default CreateClaims; diff --git a/src/app/(main)/staffReimbursement/page.tsx b/src/app/(main)/staffReimbursement/page.tsx new file mode 100644 index 0000000..1a1afcf --- /dev/null +++ b/src/app/(main)/staffReimbursement/page.tsx @@ -0,0 +1,47 @@ +import { preloadClaims } from "@/app/api/claims"; +import ClaimSearch from "@/components/ClaimSearch"; +import { getServerI18n } from "@/i18n"; +import Add from "@mui/icons-material/Add"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import { Metadata } from "next"; +import Link from "next/link"; +import { Suspense } from "react"; + +export const metadata: Metadata = { + title: "Claims", +}; + +const StaffReimbursement: React.FC = async () => { + const { t } = await getServerI18n("claims"); + preloadClaims(); + + return ( + <> + + + {t("Staff Reimbursement")} + + + + }> + + + + ); +}; + +export default StaffReimbursement; diff --git a/src/app/api/claims/index.ts b/src/app/api/claims/index.ts new file mode 100644 index 0000000..cfb2554 --- /dev/null +++ b/src/app/api/claims/index.ts @@ -0,0 +1,50 @@ +import { cache } from "react"; +import "server-only"; + +export interface ClaimResult { + id: number; + created: string; + name: string; + cost: number; + type: "Expense" | "Petty Cash"; + status: "Not Submitted" | "Waiting for Approval" | "Approved" | "Rejected"; + remarks: string; +} + +export const preloadClaims = () => { + fetchClaims(); +}; + +export const fetchClaims = cache(async () => { + return mockClaims; +}); + +const mockClaims: ClaimResult[] = [ + { + id: 1, + created: "2023-11-22", + name: "Consultancy Project A", + cost: 121.00, + type: "Expense", + status: "Not Submitted", + remarks: "", + }, + { + id: 2, + created: "2023-11-30", + name: "Consultancy Project A", + cost: 4300.00, + type: "Expense", + status: "Waiting for Approval", + remarks: "", + }, + { + id: 3, + created: "2023-12-12", + name: "Construction Project C", + cost: 3675.00, + type: "Petty Cash", + status: "Rejected", + remarks: "Duplicate Claim Form", + }, +]; diff --git a/src/components/ClaimSearch/ClaimSearch.tsx b/src/components/ClaimSearch/ClaimSearch.tsx new file mode 100644 index 0000000..d8cfe6e --- /dev/null +++ b/src/components/ClaimSearch/ClaimSearch.tsx @@ -0,0 +1,91 @@ +"use client"; + +import { ClaimResult } from "@/app/api/claims"; +import React, { useCallback, useMemo, useState } from "react"; +import SearchBox, { Criterion } from "../SearchBox/index"; +import { useTranslation } from "react-i18next"; +import SearchResults, { Column } from "../SearchResults/index"; +import EditNote from "@mui/icons-material/EditNote"; + +interface Props { + claims: ClaimResult[]; +} + +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const ClaimSearch: React.FC = ({ claims }) => { + const { t } = useTranslation("claims"); + + // If claim searching is done on the server-side, then no need for this. + const [filteredClaims, setFilteredClaims] = useState(claims); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { label: t("Creation Date"), paramName: "created", type: "dateRange" }, + { label: t("Related Project Name"), paramName: "name", type: "text" }, + { + label: t("Cost (HKD)"), + paramName: "cost", + type: "text", + }, + { + label: t("Expense Type"), + paramName: "type", + type: "select", + options: ["Expense", "Petty Cash"], + }, + { + label: t("Status"), + paramName: "status", + type: "select", + options: ["Not Submitted", "Waiting for Approval", "Approved", "Rejected"] + }, + { + label: t("Remarks"), + paramName: "remarks", + type: "text", + }, + ], + [t], + ); + + const onClaimClick = useCallback((claim: ClaimResult) => { + console.log(claim); + }, []); + + const columns = useMemo[]>( + () => [ + { + name: "action", + label: t("Actions"), + onClick: onClaimClick, + buttonIcon: , + }, + { name: "created", label: t("Creation Date") }, + { name: "name", label: t("Related Project Name") }, + { name: "cost", label: t("Cost (HKD)") }, + { name: "type", label: t("Expense Type") }, + { name: "status", label: t("Status") }, + { name: "remarks", label: t("Remarks") }, + ], + [t, onClaimClick], + ); + + return ( + <> + { + console.log(query); + }} + /> + + items={filteredClaims} + columns={columns} + /> + + ); +}; + +export default ClaimSearch; diff --git a/src/components/ClaimSearch/ClaimSearchLoading.tsx b/src/components/ClaimSearch/ClaimSearchLoading.tsx new file mode 100644 index 0000000..604aa7a --- /dev/null +++ b/src/components/ClaimSearch/ClaimSearchLoading.tsx @@ -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 ClaimSearchLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default ClaimSearchLoading; diff --git a/src/components/ClaimSearch/ClaimSearchWrapper.tsx b/src/components/ClaimSearch/ClaimSearchWrapper.tsx new file mode 100644 index 0000000..c8a7f55 --- /dev/null +++ b/src/components/ClaimSearch/ClaimSearchWrapper.tsx @@ -0,0 +1,18 @@ +import { fetchClaims } from "@/app/api/claims"; +import React from "react"; +import ClaimSearch from "./ClaimSearch"; +import ClaimSearchLoading from "./ClaimSearchLoading"; + +interface SubComponents { + Loading: typeof ClaimSearchLoading; +} + +const ClaimSearchWrapper: React.FC & SubComponents = async () => { + const claims = await fetchClaims(); + + return ; +}; + +ClaimSearchWrapper.Loading = ClaimSearchLoading; + +export default ClaimSearchWrapper; diff --git a/src/components/ClaimSearch/index.ts b/src/components/ClaimSearch/index.ts new file mode 100644 index 0000000..865400d --- /dev/null +++ b/src/components/ClaimSearch/index.ts @@ -0,0 +1 @@ +export { default } from "./ClaimSearchWrapper"; diff --git a/src/components/CreateClaim/ClaimDetails.tsx b/src/components/CreateClaim/ClaimDetails.tsx new file mode 100644 index 0000000..a5b6215 --- /dev/null +++ b/src/components/CreateClaim/ClaimDetails.tsx @@ -0,0 +1,79 @@ +"use client"; + +import Stack from "@mui/material/Stack"; +import Box from "@mui/material/Box"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import FormControl from "@mui/material/FormControl"; +import Grid from "@mui/material/Grid"; +import InputLabel from "@mui/material/InputLabel"; +import MenuItem from "@mui/material/MenuItem"; +import Select from "@mui/material/Select"; +import TextField from "@mui/material/TextField"; +import Typography from "@mui/material/Typography"; +import { useTranslation } from "react-i18next"; +import CardActions from "@mui/material/CardActions"; +import RestartAlt from "@mui/icons-material/RestartAlt"; +import Button from "@mui/material/Button"; +import ClaimInputGrid from "./ClaimInputGrid"; + +const ClaimDetails: React.FC = () => { + const { t } = useTranslation(); + + return ( + + + + {/* + {t("Related Project")} + */} + + + + {t("Related Project")} + + + + + + {t("Expense Type")} + + + + + + + + + + + {/* + + */} + + + ); +}; + +export default ClaimDetails; diff --git a/src/components/CreateClaim/ClaimInputGrid.tsx b/src/components/CreateClaim/ClaimInputGrid.tsx new file mode 100644 index 0000000..ab8fbc9 --- /dev/null +++ b/src/components/CreateClaim/ClaimInputGrid.tsx @@ -0,0 +1,406 @@ +"use client"; +import Grid from "@mui/material/Grid"; +import Paper from "@mui/material/Paper"; +import { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import PageTitle from "../PageTitle/PageTitle"; +import { Suspense } from "react"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Link from "next/link"; +import { t } from 'i18next'; +import { Box, Container, Modal, Select, SelectChangeEvent, Typography } from "@mui/material"; +import { Close } from '@mui/icons-material'; +import AddIcon from '@mui/icons-material/Add'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/DeleteOutlined'; +import SaveIcon from '@mui/icons-material/Save'; +import CancelIcon from '@mui/icons-material/Close'; +import AddPhotoAlternateOutlinedIcon from '@mui/icons-material/AddPhotoAlternateOutlined'; +import ImageNotSupportedOutlinedIcon from '@mui/icons-material/ImageNotSupportedOutlined'; +import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import Swal from "sweetalert2"; +import { msg } from "../Swal/CustomAlerts"; +import React from "react"; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; +import { + GridRowsProp, + GridRowModesModel, + GridRowModes, + DataGrid, + GridColDef, + GridToolbarContainer, + GridFooterContainer, + GridActionsCellItem, + GridEventListener, + GridRowId, + GridRowModel, + GridRowEditStopReasons, + GridEditInputCell, + GridValueSetterParams, +} from '@mui/x-data-grid'; +import { LocalizationProvider } from "@mui/x-date-pickers"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import dayjs from "dayjs"; +import { Props } from "react-intl/src/components/relative"; +import palette from "@/theme/devias-material-kit/palette"; + +const weekdays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']; + +interface BottomBarProps { + getCostTotal: () => number; + setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void; + setRowModesModel: ( + newModel: (oldModel: GridRowModesModel) => GridRowModesModel, + ) => void; +} + +interface EditToolbarProps { + // setDay: (newDay : dayjs.Dayjs) => void; + setDay: (newDay: (oldDay: dayjs.Dayjs) => dayjs.Dayjs) => void; + setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void; + setRowModesModel: ( + newModel: (oldModel: GridRowModesModel) => GridRowModesModel, + ) => void; +} + +interface EditFooterProps { + setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void; + setRowModesModel: ( + newModel: (oldModel: GridRowModesModel) => GridRowModesModel, + ) => void; +} + +const BottomBar = (props: BottomBarProps) => { + const { setRows, setRowModesModel, getCostTotal } = props; + // const getCostTotal = props.getCostTotal; + const [newId, setNewId] = useState(-1); + const [invalidDays, setInvalidDays] = useState(0); + + const handleAddClick = () => { + const id = newId; + setNewId(newId - 1); + setRows((oldRows) => [...oldRows, { id, projectCode: '', task: '', isNew: true }]); + setRowModesModel((oldModel) => ({ + ...oldModel, + [id]: { mode: GridRowModes.Edit, fieldToFocus: 'projectCode' }, + })); + }; + + const totalColDef = { + flex:1, + // style: {color:getCostTotal('mon')>24?"red":"black"} + }; + + const TotalCell = ({value}: Props) => { + const [invalid, setInvalid] = useState(false); + + useEffect(()=> { + const newInvalid = (value ?? 0) < 0; + setInvalid(newInvalid); + }, [value]); + + return ( + + $ {value} + + ); + } + + return ( +
+
+ + Total: + + +
+ +
+ ); +} + +const EditFooter = (props: EditFooterProps) => { + return ( +
+ + Total: + + test +
+ ); +} + +interface ClaimInputGridProps { + onClose?: () => void; +} + +const initialRows: GridRowsProp = [ + { + id: 1, + date: new Date(), + description: "Taxi to client office", + cost: 169.5, + document: 'taxi_receipt.jpg', + }, + { + id: 2, + date: dayjs().add(-14, 'days').toDate(), + description: "MTR fee to Kowloon Bay Office", + cost: 15.5, + document: 'octopus_invoice.jpg', + }, + { + id: 3, + date: dayjs().add(-44, 'days').toDate(), + description: "Starbucks", + cost: 504, + }, +]; + +const ClaimInputGrid: React.FC = ({ ...props }) => { + + const [rows, setRows] = useState(initialRows); + const [day, setDay] = useState(dayjs()); + const [rowModesModel, setRowModesModel] = React.useState({}); + + const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => { + if (params.reason === GridRowEditStopReasons.rowFocusOut) { + event.defaultMuiPrevented = true; + } + }; + + const handleEditClick = (id: GridRowId) => () => { + setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.Edit } }); + }; + + const handleSaveClick = (id: GridRowId) => () => { + + setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } }); + }; + + const handleDeleteClick = (id: GridRowId) => () => { + setRows(rows.filter((row) => row.id !== id)); + }; + + const handleCancelClick = (id: GridRowId) => () => { + setRowModesModel({ + ...rowModesModel, + [id]: { mode: GridRowModes.View, ignoreModifications: true }, + }); + + const editedRow = rows.find((row) => row.id === id); + if (editedRow!.isNew) { + setRows(rows.filter((row) => row.id !== id)); + } + }; + + const processRowUpdate = (newRow: GridRowModel) => { + const updatedRow = { ...newRow, isNew: false }; + setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row))); + return updatedRow; + }; + + const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => { + setRowModesModel(newRowModesModel); + }; + + const getCostTotal = () => { + let sum = 0; + rows.forEach((row) => { + sum += row['cost']??0; + }); + return sum; + }; + + const commonGridColConfig : any = { + type: 'number', + // sortable: false, + //width: 100, + flex: 1, + align: 'left', + headerAlign: 'left', + // headerClassName: 'header', + editable: true, + renderEditCell: (value : any) => ( + + ), + }; + + const columns: GridColDef[] = [ + { + field: 'actions', + type: 'actions', + headerName: 'Actions', + width: 100, + cellClassName: 'actions', + getActions: ({ id }) => { + const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit; + + if (isInEditMode) { + return [ + } + title="Save" + label="Save" + sx={{ + color: 'primary.main', + }} + onClick={handleSaveClick(id)} + />, + } + title="Cancel" + label="Cancel" + className="textPrimary" + onClick={handleCancelClick(id)} + color="inherit" + />, + ]; + } + + return [ + } + title="Edit" + label="Edit" + className="textPrimary" + onClick={handleEditClick(id)} + color="inherit" + />, + } + onClick={handleDeleteClick(id)} + sx={{color:"red"}} + />, + ]; + }, + }, + { + field: 'date', + headerName: 'Invoice Date', + // width: 220, + flex: 1, + editable: true, + type: 'date', + }, + { + field: 'description', + headerName: 'Description', + // width: 220, + flex: 2, + editable: true, + type: 'string', + }, + { + field: 'cost', + headerName: 'Cost (HKD)', + editable: true, + type: 'number', + valueFormatter: (params) => { + return `$ ${params.value??0}`; + }, + }, + { + field: 'document', + headerName: 'Supporting Document', + type: 'string', + editable: true, + flex: 2, + renderCell: (params) => { + return params.value? + ( + + + {params.value} + + + ) : + (No Documents) + }, + renderEditCell: (params) => { + return params.value? + ( + + + {params.value} + + + + + ) : ( + + ) + }, + }, + ]; + + return ( + + + + + + ); +} + +export default ClaimInputGrid; diff --git a/src/components/CreateClaim/CreateClaim.tsx b/src/components/CreateClaim/CreateClaim.tsx new file mode 100644 index 0000000..c5c7594 --- /dev/null +++ b/src/components/CreateClaim/CreateClaim.tsx @@ -0,0 +1,48 @@ +"use client"; + +import Check from "@mui/icons-material/Check"; +import Close from "@mui/icons-material/Close"; +import Button from "@mui/material/Button"; +import Stack from "@mui/material/Stack"; +import Tab from "@mui/material/Tab"; +import Tabs, { TabsProps } from "@mui/material/Tabs"; +import { useRouter } from "next/navigation"; +import React, { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; +import ClaimProjectDetails from "./ClaimDetails"; +import TaskSetup from "./TaskSetup"; +import StaffAllocation from "./StaffAllocation"; +import ResourceMilestone from "./ResourceMilestone"; + +const CreateProject: React.FC = () => { + const [tabIndex, setTabIndex] = useState(0); + const { t } = useTranslation(); + const router = useRouter(); + + const handleCancel = () => { + router.back(); + }; + + const handleTabChange = useCallback>( + (_e, newValue) => { + setTabIndex(newValue); + }, + [], + ); + + return ( + <> + + + + + + + ); +}; + +export default CreateProject; diff --git a/src/components/CreateClaim/index.ts b/src/components/CreateClaim/index.ts new file mode 100644 index 0000000..a0bd052 --- /dev/null +++ b/src/components/CreateClaim/index.ts @@ -0,0 +1 @@ +export { default } from "./CreateClaim"; diff --git a/src/components/EnterTimesheet/EnterTimesheetModal.tsx b/src/components/EnterTimesheet/EnterTimesheetModal.tsx index 4aa8023..73665bf 100644 --- a/src/components/EnterTimesheet/EnterTimesheetModal.tsx +++ b/src/components/EnterTimesheet/EnterTimesheetModal.tsx @@ -11,7 +11,7 @@ import Stack from "@mui/material/Stack"; import { Add } from '@mui/icons-material'; import Link from "next/link"; import { t } from 'i18next'; -import { Modal, Typography } from "@mui/material"; +import { Card, Modal, Typography } from "@mui/material"; import CustomModal from "../CustomModal/CustomModal"; import { PROJECT_MODAL_STYLE } from "@/theme/colorConst"; import CustomDatagrid from "../CustomDatagrid/CustomDatagrid"; @@ -51,15 +51,15 @@ const EnterTimesheetModal: React.FC = ({ ...props }) = return (
- + {/*
Timesheet Input
-
+
*/} -
+ -
+
= (props) => { - const [items, setItems] = React.useState([]) - - useEffect(() => { - if (props.tab == 0) { - setItems(cards) - } - else { - const filteredItems = cards;//cards.filter(item => (item.track == props.tab)); - setItems(filteredItems); - } - }, [props.tab]); - - const cards = [ - {code: 'M1001 (C)', name: 'Consultancy Project A', hr_spent: 12.75, hr_spent_normal: 0.00, hr_alloc: 150.00, hr_alloc_normal: 30.00}, - {code: 'M1301 (C)', name: 'Consultancy Project AAA', hr_spent: 4.25, hr_spent_normal: 0.25, hr_alloc: 30.00, hr_alloc_normal: 0.00}, - {code: 'M1354 (C)', name: 'Consultancy Project BBB', hr_spent: 57.00, hr_spent_normal: 6.50, hr_alloc: 100.00, hr_alloc_normal: 20.00}, - {code: 'M1973 (C)', name: 'Construction Project CCC', hr_spent: 12.75, hr_spent_normal: 0.00, hr_alloc: 150.00, hr_alloc_normal: 30.00}, - {code: 'M2014 (T)', name: 'Consultancy Project DDD', hr_spent: 1.00, hr_spent_normal: 0.00, hr_alloc: 10.00, hr_alloc_normal: 0.00}, - ]; - - const cardLayout = (item: Record) => { - return ( - - - -

Hours Spent: {item.hr_spent}

-

Normal (Others): {item.hr_spent_normal}

-

Hours Allocated: {item.hr_alloc}

-

Normal (Others): {item.hr_alloc_normal}

-
-
- ); - } - // Apply the preset style to the cards in child, if not specified // - return ( - - {/* */} - {/* item count = {items?.length??"idk"} , track/tab = {props.tab} */} - - {/* */} - - ); -}; - -export default ProjectGrid; diff --git a/src/components/EnterTimesheet/TimesheetInputGrid.tsx b/src/components/EnterTimesheet/TimesheetInputGrid.tsx index 1ad4c0b..7ebc57d 100644 --- a/src/components/EnterTimesheet/TimesheetInputGrid.tsx +++ b/src/components/EnterTimesheet/TimesheetInputGrid.tsx @@ -7,7 +7,6 @@ import PageTitle from "../PageTitle/PageTitle"; import { Suspense } from "react"; import Button from "@mui/material/Button"; import Stack from "@mui/material/Stack"; -import { Add, SettingsEthernet } from '@mui/icons-material'; import Link from "next/link"; import { t } from 'i18next'; import { Box, Container, Modal, Select, SelectChangeEvent, Typography } from "@mui/material"; @@ -21,7 +20,6 @@ import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import Swal from "sweetalert2"; import { msg } from "../Swal/CustomAlerts"; -import ComboEditor from "../ComboEditor/ComboEditor"; import React from "react"; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { @@ -72,6 +70,53 @@ interface EditFooterProps { ) => void; } +const EditToolbar = (props: EditToolbarProps) => { + const { setDay } = props; + const [selectedDate, setSelectedDate] = useState(dayjs()); + + const handleClickLeft = () => { + if (selectedDate) { + const newDate = selectedDate.add(-7, 'day'); + setSelectedDate(newDate); + } + }; + const handleClickRight = () => { + if (selectedDate) { + const newDate = selectedDate.add(7, 'day') > dayjs()? dayjs(): selectedDate.add(7, 'day'); + setSelectedDate(newDate); + } + }; + + const handleDateChange = (date: dayjs.Dayjs | Date | null) => { + const newDate = dayjs(date); + setSelectedDate(newDate); + }; + + useEffect(() => { + setDay((oldDay) => selectedDate); + }, [selectedDate]); + + return ( + +
+ + Timesheet Input + + + + +
+
+ ); +} + const BottomBar = (props: BottomBarProps) => { const { setRows, setRowModesModel, getHoursTotal, setLockConfirm } = props; // const getHoursTotal = props.getHoursTotal; @@ -136,49 +181,6 @@ const BottomBar = (props: BottomBarProps) => { ); } -const EditToolbar = (props: EditToolbarProps) => { - const { setDay } = props; - const [selectedDate, setSelectedDate] = useState(dayjs()); - - const handleClickLeft = () => { - if (selectedDate) { - const newDate = selectedDate.add(-7, 'day'); - setSelectedDate(newDate); - } - }; - const handleClickRight = () => { - if (selectedDate) { - const newDate = selectedDate.add(7, 'day') > dayjs()? dayjs(): selectedDate.add(7, 'day'); - setSelectedDate(newDate); - } - }; - - const handleDateChange = (date: dayjs.Dayjs | Date | null) => { - const newDate = dayjs(date); - setSelectedDate(newDate); - }; - - useEffect(() => { - setDay((oldDay) => selectedDate); - }, [selectedDate]); - - return ( - -
- - - -
-
- ); -} const EditFooter = (props: EditFooterProps) => { return ( @@ -307,7 +309,7 @@ const TimesheetInputGrid: React.FC = ({ ...props }) => { field: 'actions', type: 'actions', - headerName: '', + headerName: 'Actions', width: 100, cellClassName: 'actions', getActions: ({ id }) => { @@ -455,7 +457,11 @@ const TimesheetInputGrid: React.FC = ({ ...props }) => = ({ ...props }) => initialState={{ pagination: { paginationModel: { pageSize: 100 } }, }} + sx={{flex:1}} /> - + ); } diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx index 8df7a44..ab48616 100644 --- a/src/components/NavigationContent/NavigationContent.tsx +++ b/src/components/NavigationContent/NavigationContent.tsx @@ -35,7 +35,10 @@ const navigationItems: NavigationItem[] = [ { icon: , label: "Project Cash Flow", path: "/dashboard/ProjectCashFlow" }, { icon: , label: "Project Status by Client", path: "/dashboard/ProjectStatusByClient" }, ]}, - { icon: , label: "Expense Claim", path: "/claim" }, + { icon: , label: "Staff Reimbursement", path: "/staffReimbursement", children: [ + { icon: , label: "ClaimApproval", path: "/staffReimbursement/ClaimApproval"}, + { icon: , label: "ClaimSummary", path: "/staffReimbursement/ClaimSummary"} + ] }, { icon: , label: "Project Management", path: "/projects" }, { icon: , label: "Task Template", path: "/tasks" }, { icon: , label: "Invoice", path: "/invoice" }, diff --git a/src/components/UserWorkspacePage/ProjectGrid.tsx b/src/components/UserWorkspacePage/ProjectGrid.tsx index 53cc264..c0b140f 100644 --- a/src/components/UserWorkspacePage/ProjectGrid.tsx +++ b/src/components/UserWorkspacePage/ProjectGrid.tsx @@ -38,7 +38,7 @@ const ProjectGrid: React.FC = (props) => { const cardLayout = (item: Record) => { return ( - +

Hours Spent: {item.hr_spent}

Normal (Others): {item.hr_spent_normal}

diff --git a/src/theme/colorConst.js b/src/theme/colorConst.js index 2d3c0a8..58802a0 100644 --- a/src/theme/colorConst.js +++ b/src/theme/colorConst.js @@ -78,6 +78,18 @@ export const PROJECT_MODAL_STYLE = { flexDirection: 'column', }; +export const DATAGRID_STYLE = { + boxShadow: 2, + border: 2, + borderColor: 'primary.light', + '& .MuiDataGrid-cell:hover': { + color: 'primary.main' + }, + '& .MuiDataGrid-root': { + overflow: 'auto', + } +}; + export const TAB_THEME = { components: { MuiTab: {