diff --git a/package-lock.json b/package-lock.json index 2a69adb..debab88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,9 @@ "react-dom": "^18", "react-hook-form": "^7.49.2", "react-i18next": "^13.5.0", - "react-intl": "^6.5.5" + "react-intl": "^6.5.5", + "react-select": "^5.8.0", + "reactstrap": "^9.2.2" }, "devDependencies": { "@types/lodash": "^4.14.202", @@ -2194,6 +2196,11 @@ "node": ">= 6" } }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -4433,6 +4440,11 @@ "node": ">=10" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5455,6 +5467,11 @@ "react": "^18.2.0" } }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "node_modules/react-hook-form": { "version": "7.49.2", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.49.2.tgz", @@ -5523,6 +5540,40 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -5538,6 +5589,23 @@ "react-dom": ">=16.6.0" } }, + "node_modules/reactstrap": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.2.2.tgz", + "integrity": "sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.6.0", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^2.2.4", + "react-transition-group": "^4.4.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -6561,6 +6629,19 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6583,6 +6664,14 @@ "node": ">=0.10.0" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index ff98a0e..182e58d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "react-dom": "^18", "react-hook-form": "^7.49.2", "react-i18next": "^13.5.0", - "react-intl": "^6.5.5" + "react-intl": "^6.5.5", + "react-select": "^5.8.0", + "reactstrap": "^9.2.2" }, "devDependencies": { "@types/lodash": "^4.14.202", diff --git a/src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx b/src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx new file mode 100644 index 0000000..df5365e --- /dev/null +++ b/src/app/(main)/dashboard/CompanyTeamCashFlow/page.tsx @@ -0,0 +1,28 @@ +import { Metadata } from "next"; +import { I18nProvider } from "@/i18n"; +import DashboardPage from "@/components/DashboardPage/DashboardPage"; +import DashboardPageButton from "@/components/DashboardPage/DashboardTabButton"; +import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; +import { Suspense} from "react"; +import Tabs, { TabsProps } from "@mui/material/Tabs"; +import Tab from "@mui/material/Tab"; +import Typography from "@mui/material/Typography"; +import CompanyTeamCashFlowComponent from '@/components/CompanyTeamCashFlow' + +export const metadata: Metadata = { + title: "Project Status by Client", +}; + + +const CompanyTeamCashFlow: React.FC = () => { + + return ( + + + Company / Team Cash Flow + + + + ); +}; +export default CompanyTeamCashFlow; diff --git a/src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx b/src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx new file mode 100644 index 0000000..fb935df --- /dev/null +++ b/src/components/CompanyTeamCashFlow/CompanyTeamCashFlow.tsx @@ -0,0 +1,285 @@ +"use client"; +import * as React from "react"; +import Grid from "@mui/material/Grid"; +import { useState,useEffect, useMemo } from 'react' +import Paper from "@mui/material/Paper"; +import { TFunction } from "i18next"; +import { useTranslation } from "react-i18next"; +import {Card,CardHeader} from '@mui/material'; +import CustomSearchForm from "../CustomSearchForm/CustomSearchForm"; +import CustomDatagrid from '../CustomDatagrid/CustomDatagrid'; +import ReactApexChart from 'react-apexcharts'; +import { ApexOptions } from 'apexcharts'; +import { GridColDef, GridRowSelectionModel} from '@mui/x-data-grid'; +import ReportProblemIcon from '@mui/icons-material/ReportProblem'; +import dynamic from 'next/dynamic'; +import '../../app/global.css'; +import { AnyARecord, AnyCnameRecord } from "dns"; +import SearchBox, { Criterion } from "../SearchBox"; +import ProgressByClientSearch from "@/components/ProgressByClientSearch"; +import { Suspense } from "react"; +import ProgressCashFlowSearch from "@/components/ProgressCashFlowSearch"; +import {Input,Label} from "reactstrap"; +import Select, {components} from 'react-select' + +const CompanyTeamCashFlow: React.FC = () => { + const todayDate = new Date; + const [selectionModel, setSelectionModel] : any[] = React.useState([]); + const [cashFlowYear, setCashFlowYear] : any[] = React.useState(todayDate.getFullYear()); + + const teamOptions = [ + { value: 1, label: 'XXX Team' }, + { value: 2, label: 'YYY Team' }, + { value: 3, label: 'ZZZ Team' } + ] + + const columns = [ + { + id: 'projectCode', + field: 'projectCode', + headerName: "Project Code", + flex: 1, + }, + { + id: 'projectName', + field: 'projectName', + headerName: "Project Name", + flex: 1, + }, + { + id: 'team', + field: 'team', + headerName: "Team", + flex: 1, + }, + { + id: 'teamLeader', + field: 'teamLeader', + headerName: "Team Leader", + flex: 1, + }, + { + id: 'startDate', + field: 'startDate', + headerName: "Start Date", + flex: 1, + }, + { + id: 'targetEndDate', + field: 'targetEndDate', + headerName: "Target End Date", + flex: 1, + }, + { + id: 'client', + field: 'client', + headerName: "Client", + flex: 1, + }, + { + id: 'subsidiary', + field: 'subsidiary', + headerName: "Subsidiary", + flex: 1, + }, + ]; + + const ledgerColumns = [ + { + id: 'date', + field: 'date', + headerName: "Date", + flex: 0.5, + }, + { + id: 'expenditure', + field: 'expenditure', + headerName: "Expenditure (HKD)", + flex: 0.6, + }, + { + id: 'income', + field: 'income', + headerName: "Income (HKD)", + flex: 0.6, + }, + { + id: 'cashFlowBalance', + field: 'cashFlowBalance', + headerName: "Cash Flow Balance (HKD)", + flex: 0.6, + }, + { + id: 'remarks', + field: 'remarks', + headerName: "Remarks", + flex: 1, + }, + ]; + + const options: ApexOptions = { + chart: { + height: 350, + type: 'line', + }, + stroke: { + width: [0, 0, 2, 2] + }, + plotOptions: { + bar: { + horizontal: false, + distributed: false, + }, + }, + dataLabels: { + enabled: false + }, + xaxis: { + categories: [ + 'Q1', + 'Q2', + 'Q3', + 'Q4', + 'Q5', + 'Q6', + 'Q7', + 'Q8', + 'Q9', + 'Q10', + 'Q11', + 'Q12', + ], + }, + yaxis: [ + + { + title: { + text: 'Monthly Income and Expenditure(HKD)' + }, + min: 0, + max: 3700000, + tickAmount: 5 + }, + { + show:false, + seriesName: 'Monthly_Expenditure', + title: { + text: 'Monthly Expenditure (HKD)' + }, + min: 0, + max: 3700000, + tickAmount: 5 + }, + { + seriesName: 'Cumulative_Income', + opposite: true, + title: { + text: 'Cumulative Income and Expenditure(HKD)' + }, + min: 0, + max: 21000000, + tickAmount: 5 + }, + { + show:false, + seriesName: 'Cumulative_Expenditure', + opposite: true, + title: { + text: 'Cumulative Expenditure (HKD)' + }, + min: 0, + max: 21000000, + tickAmount: 5 + } + ], + grid: { + borderColor: '#f1f1f1', + }, + annotations: { + }, + series:[ + { + name:"Monthly_Income", + type:"column", + color: "#ffde91", + data:[1280000,170000,3600000,2400000,1000000,1800000,1800000,1200000,1250000,1200000,600000,2400000], + }, + { + name:"Monthly_Expenditure", + type:"column", + color: "#82b59a", + data:[1200000,1400000,2000000,1400000,1450000,1800000,1200000,1400000,1200000,1600000,2000000,1600000] + }, + { + name:"Cumulative_Income", + type:"line", + color: "#EE6D7A", + data:[500000,3000000,7000000,9000000,10000000,13000000,14000000,16000000,17000000,17500000,18000000,20000000] + }, + { + name:"Cumulative_Expenditure", + type:"line", + color: "#7cd3f2", + data:[400000,2800000,4000000,5200000,7100000,8000000,10000000,11000000,12100000,14000000,15400000,17200000] + } + ] + }; + + return ( + <> + +
+ + + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + +
Total A. Receivable
+
1,000,000.00

+
Amount Received
+
800,000.00

+
Remaining Balance
+
200,000.00
+
+
+
+
+
+ + + + + +
Budgeted Expenditure
+
800,000.00

+
Actual Expenditure
+
760,000.00

+
Remaining Balance
+
40,000.00
+
+
+
+
+
+ + + +
+ +
+
+
+
);