From 6c16db51f5322352e68460a6f5eff1ea496a335f Mon Sep 17 00:00:00 2001 From: leoho2fi Date: Tue, 30 Apr 2024 18:14:49 +0800 Subject: [PATCH] add report ex01 --- public/temp/EX01_Financial Status Report.xlsx | Bin 0 -> 13143 bytes .../analytics/FinancialStatusReport/page.tsx | 24 + src/app/api/reporte1/index.ts | 42 ++ .../NavigationContent/NavigationContent.tsx | 1 + .../FinancialStatusReport.tsx | 17 + .../Report/FinancialStatusReport/index.ts | 2 + .../FinancialStatusReportGen.tsx | 43 ++ .../FinancialStatusReportGenLoading.tsx | 41 ++ .../FinancialStatusReportGenWrapper.tsx | 19 + .../Report/FinancialStatusReportGen/index.ts | 2 + .../Report/ReportSearchBoxe1/SearchBoxe1.tsx | 482 ++++++++++++++++++ .../Report/ReportSearchBoxe1/index.ts | 3 + 12 files changed, 676 insertions(+) create mode 100644 public/temp/EX01_Financial Status Report.xlsx create mode 100644 src/app/(main)/analytics/FinancialStatusReport/page.tsx create mode 100644 src/app/api/reporte1/index.ts create mode 100644 src/components/Report/FinancialStatusReport/FinancialStatusReport.tsx create mode 100644 src/components/Report/FinancialStatusReport/index.ts create mode 100644 src/components/Report/FinancialStatusReportGen/FinancialStatusReportGen.tsx create mode 100644 src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenLoading.tsx create mode 100644 src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenWrapper.tsx create mode 100644 src/components/Report/FinancialStatusReportGen/index.ts create mode 100644 src/components/Report/ReportSearchBoxe1/SearchBoxe1.tsx create mode 100644 src/components/Report/ReportSearchBoxe1/index.ts diff --git a/public/temp/EX01_Financial Status Report.xlsx b/public/temp/EX01_Financial Status Report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bd1b55dbd8348ebf9a7381c5a951080b0776f6ec GIT binary patch literal 13143 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 V9Mr20f`K8v?!R0=0n4wu{|9^8l?VU; literal 0 HcmV?d00001 diff --git a/src/app/(main)/analytics/FinancialStatusReport/page.tsx b/src/app/(main)/analytics/FinancialStatusReport/page.tsx new file mode 100644 index 0000000..0a3865d --- /dev/null +++ b/src/app/(main)/analytics/FinancialStatusReport/page.tsx @@ -0,0 +1,24 @@ +//src\app\(main)\analytics\DelayReport\page.tsx +import { Metadata } from "next"; +import { I18nProvider } from "@/i18n"; +import Typography from "@mui/material/Typography"; +import FinancialStatusReportComponent from "@/components/Report/FinancialStatusReport"; + +export const metadata: Metadata = { + title: "Financial Status Report", +}; + +const ProjectFinancialStatusReport: React.FC = () => { + return ( + + + Financial Status Report + + {/* }> + + */} + + + ); +}; +export default ProjectFinancialStatusReport; diff --git a/src/app/api/reporte1/index.ts b/src/app/api/reporte1/index.ts new file mode 100644 index 0000000..5e27648 --- /dev/null +++ b/src/app/api/reporte1/index.ts @@ -0,0 +1,42 @@ +//src\app\api\report\index.ts +import { cache } from "react"; + +export interface FinancialStatus { + id: number; + projectCode: string; + projectName: string; + team: string; + teamLeader: string; + startDate: string; + startDateFrom: string; + startDateTo: string; + targetEndDate: string; + client: string; + subsidiary: string; + status: string; +} + +export const preloadProjects = () => { + fetchProjectsFinancialStatus(); +}; + +export const fetchProjectsFinancialStatus = cache(async () => { + return mockProjects; +}); + +const mockProjects: FinancialStatus[] = [ + { + id: 1, + projectCode: "CUST-001", + projectName: "Client A", + team: "N/A", + teamLeader: "N/A", + startDate: "5", + startDateFrom: "5", + startDateTo: "5", + targetEndDate: "s", + client: "ss", + subsidiary: "ss", + status: "1", + }, +]; diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx index ad68823..45bfda9 100644 --- a/src/components/NavigationContent/NavigationContent.tsx +++ b/src/components/NavigationContent/NavigationContent.tsx @@ -108,6 +108,7 @@ const navigationItems: NavigationItem[] = [ {icon: , label:"Completion Report with Outstanding Un-billed Hours Report", path: "/analytics/ProjectCompletionReportWO"}, {icon: , label:"Project Claims Report", path: "/analytics/ProjectClaimsReport"}, {icon: , label:"Project P&L Report", path: "/analytics/ProjectPLReport"}, + {icon: , label:"Financial Status Report", path: "/analytics/FinancialStatusReport"}, ], }, { diff --git a/src/components/Report/FinancialStatusReport/FinancialStatusReport.tsx b/src/components/Report/FinancialStatusReport/FinancialStatusReport.tsx new file mode 100644 index 0000000..893b0ba --- /dev/null +++ b/src/components/Report/FinancialStatusReport/FinancialStatusReport.tsx @@ -0,0 +1,17 @@ +//src\components\DelayReport\DelayReport.tsx +"use client"; +import * as React from "react"; +import "../../../app/global.css"; +import { Suspense } from "react"; +import FinancialStatusReportGen from "@/components/Report/FinancialStatusReportGen"; + +const FinancialStatusReport: React.FC = () => { + + return ( + }> + + + ); +}; + +export default FinancialStatusReport; \ No newline at end of file diff --git a/src/components/Report/FinancialStatusReport/index.ts b/src/components/Report/FinancialStatusReport/index.ts new file mode 100644 index 0000000..4500704 --- /dev/null +++ b/src/components/Report/FinancialStatusReport/index.ts @@ -0,0 +1,2 @@ +//src\components\LateStartReport\index.ts +export { default } from "./FinancialStatusReport"; diff --git a/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGen.tsx b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGen.tsx new file mode 100644 index 0000000..bf4a7cd --- /dev/null +++ b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGen.tsx @@ -0,0 +1,43 @@ +//src\components\LateStartReportGen\LateStartReportGen.tsx +"use client"; +import React, { useMemo, useState } from "react"; +import SearchBox, { Criterion } from "../ReportSearchBoxe1"; +import { useTranslation } from "react-i18next"; +import { FinancialStatus } from "@/app/api/reporte1"; +//import { DownloadReportButton } from './DownloadReportButton'; +interface Props { + projects: FinancialStatus[]; +} +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const ProgressByClientSearch: React.FC = ({ projects }) => { + const { t } = useTranslation("projects"); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { label: "{Project Code}", paramName: "projectCode", type: "select", options: ["M1234", "M1268", "M1352", "M1393"] }, + // { + // label: "Status", + // label2: "Remained Date To", + // paramName: "targetEndDate", + // type: "dateRange", + // }, + ], + [t], + ); + + return ( + <> + { + console.log(query); + }} + /> + {/* */} + + ); +}; + +export default ProgressByClientSearch; diff --git a/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenLoading.tsx b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenLoading.tsx new file mode 100644 index 0000000..6d992f9 --- /dev/null +++ b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenLoading.tsx @@ -0,0 +1,41 @@ +//src\components\LateStartReportGen\LateStartReportGenLoading.tsx +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 FinancialStatusReportGenLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default FinancialStatusReportGenLoading; diff --git a/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenWrapper.tsx b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenWrapper.tsx new file mode 100644 index 0000000..e82ea4b --- /dev/null +++ b/src/components/Report/FinancialStatusReportGen/FinancialStatusReportGenWrapper.tsx @@ -0,0 +1,19 @@ +//src\components\LateStartReportGen\LateStartReportGenWrapper.tsx +import { fetchProjectsFinancialStatus } from "@/app/api/reporte1"; +import React from "react"; +import FinancialStatusReportGen from "./FinancialStatusReportGen"; +import FinancialStatusReportGenLoading from "./FinancialStatusReportGenLoading"; + +interface SubComponents { + Loading: typeof FinancialStatusReportGenLoading; +} + +const FinancialStatusReportGenWrapper: React.FC & SubComponents = async () => { + const clentprojects = await fetchProjectsFinancialStatus(); + + return ; +}; + +FinancialStatusReportGenWrapper.Loading = FinancialStatusReportGenLoading; + +export default FinancialStatusReportGenWrapper; \ No newline at end of file diff --git a/src/components/Report/FinancialStatusReportGen/index.ts b/src/components/Report/FinancialStatusReportGen/index.ts new file mode 100644 index 0000000..d53d85b --- /dev/null +++ b/src/components/Report/FinancialStatusReportGen/index.ts @@ -0,0 +1,2 @@ +//src\components\DelayReportGen\index.ts +export { default } from "./FinancialStatusReportGenWrapper"; diff --git a/src/components/Report/ReportSearchBoxe1/SearchBoxe1.tsx b/src/components/Report/ReportSearchBoxe1/SearchBoxe1.tsx new file mode 100644 index 0000000..ea7afb6 --- /dev/null +++ b/src/components/Report/ReportSearchBoxe1/SearchBoxe1.tsx @@ -0,0 +1,482 @@ +//src\components\ReportSearchBox\SearchBox2.tsx +"use client"; + +import Grid from "@mui/material/Grid"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Typography from "@mui/material/Typography"; +import React, { useCallback, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import TextField from "@mui/material/TextField"; +import FormControl from "@mui/material/FormControl"; +import InputLabel from "@mui/material/InputLabel"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; +import MenuItem from "@mui/material/MenuItem"; +import CardActions from "@mui/material/CardActions"; +import Button from "@mui/material/Button"; +import RestartAlt from "@mui/icons-material/RestartAlt"; +import Search from "@mui/icons-material/Search"; +import dayjs from "dayjs"; +import "dayjs/locale/zh-hk"; +import { DatePicker } from "@mui/x-date-pickers/DatePicker"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import { Box } from "@mui/material"; +import * as XLSX from 'xlsx-js-style'; +//import { DownloadReportButton } from '../LateStartReportGen/DownloadReportButton'; + +interface BaseCriterion { + label: string; + label2?: string; + paramName: T; + paramName2?: T; +} + +interface TextCriterion extends BaseCriterion { + type: "text"; +} + +interface SelectCriterion extends BaseCriterion { + type: "select"; + options: string[]; +} + +interface DateRangeCriterion extends BaseCriterion { + type: "dateRange"; +} + +export type Criterion = + | TextCriterion + | SelectCriterion + | DateRangeCriterion; + +interface Props { + criteria: Criterion[]; + onSearch: (inputs: Record) => void; + onReset?: () => void; +} + +function SearchBox({ + criteria, + onSearch, + onReset, +}: Props) { + const { t } = useTranslation("common"); + const defaultInputs = useMemo( + () => + criteria.reduce>( + (acc, c) => { + return { ...acc, [c.paramName]: c.type === "select" ? "All" : "" }; + }, + {} as Record, + ), + [criteria], + ); + const [inputs, setInputs] = useState(defaultInputs); + + const makeInputChangeHandler = useCallback( + (paramName: T): React.ChangeEventHandler => { + return (e) => { + setInputs((i) => ({ ...i, [paramName]: e.target.value })); + }; + }, + [], + ); + + const makeSelectChangeHandler = useCallback((paramName: T) => { + return (e: SelectChangeEvent) => { + setInputs((i) => ({ ...i, [paramName]: e.target.value })); + }; + }, []); + + const makeDateChangeHandler = useCallback((paramName: T) => { + return (e: any) => { + setInputs((i) => ({ ...i, [paramName]: dayjs(e).format("YYYY-MM-DD") })); + }; + }, []); + + const makeDateToChangeHandler = useCallback((paramName: T) => { + return (e: any) => { + setInputs((i) => ({ + ...i, + [paramName + "To"]: dayjs(e).format("YYYY-MM-DD"), + })); + }; + }, []); + + interface CellValue { + v: number | string; // Value of the cell + t: 'n' | 's'; // Type of the cell value: 'n' for number, 's' for string + s?: XLSX.CellStyle; // Optional style for the cell + } + + const handleReset = () => { + setInputs(defaultInputs); + onReset?.(); + }; + + const handleSearch = () => { + onSearch(inputs); + + }; + + // Function to merge cells from A2:B2 to A14:B14 +function mergeCells(worksheet: XLSX.WorkSheet) { + // Ensure the 'merges' array exists in the worksheet + if (!worksheet['!merges']) worksheet['!merges'] = []; + + // Loop through rows 2 to 14 (0-indexed + 1) + for (let row = 1; row <= 13; row++) { + // Define the range for current row to merge A and B columns + const mergeRange = { + s: { c: 0, r: row }, // Start cell (Column A) + e: { c: 1, r: row } // End cell (Column B) + }; + // Add the range to the 'merges' array in the worksheet + worksheet['!merges'].push(mergeRange); + // Apply center alignment to the merged cell + const mergedCellRef = XLSX.utils.encode_cell({ c: 0, r: row }); + if (!worksheet[mergedCellRef]) { + worksheet[mergedCellRef] = {}; // Create the cell if it doesn't exist + } + worksheet[mergedCellRef].s = { + alignment: { horizontal: "left", wrapText: true } + }; + } +} + +// Processing and inserting table data with calculations +function processDataAndInsert(worksheet: XLSX.WorkSheet, startRow:number, data:(string|number)[][]) { + data.forEach((row, rowIndex) => { + const r = startRow + rowIndex; + + // Direct assignments for columns A-F as strings + const stringCols = ['A', 'B', 'C', 'D', 'E', 'F']; + stringCols.forEach((col, index) => { + const cellRef = col + r; + worksheet[cellRef] = { v: row[index], t: 's' }; // Force type as string + }); + + // Assignments for columns G-O as numbers + const numberCols = ['G', 'H', 'I', 'K', 'N']; + const colIndices = [6, 7, 8, 9, 10]; // Indices in the data array corresponding to G, H, I, K, N + numberCols.forEach((col, index) => { + const cellRef = col + r; + worksheet[cellRef] = { v: row[colIndices[index]], t: 'n' }; // Force type as number + }); + + // Calculations for columns J, L, M, O + const h = row[6] as number; + const i = row[7] as number; + const k = row[9] as number; + const n = row[10] as number; + + // Column J: H - I + worksheet['J' + r] = { v: h - i, t: 'n' }; + + // Column L: IF(H { + const cellRefs = data.map((_, index) => col + (startRow + index)); + const formula = `=SUM(${cellRefs.join(',')})`; + worksheet[col + sumRow] = { f: formula, t: 'n', s: { + border: { + top: {style: 'thin', color: {auto: 1}}, + bottom: {style: 'double', color: {auto: 1}} + } + }}; + }); + XLSX.utils.sheet_add_aoa(worksheet, [['Sub-total']], { origin: { c: 0, r: (sumRow-1) } }); + +// const mergedCellRefA1 = XLSX.utils.encode_cell({ c: 0, r: sumRow-1}); +// if (!worksheet[mergedCellRefA1]) { +// worksheet[mergedCellRefA1] = {}; // Create the cell if it doesn't exist +// } +// // Apply right alignment, center vertical alignment, wrap text, and border styles to the 'Sub-total' cell +// worksheet[mergedCellRefA1].s = { +// alignment: {horizontal: "right", vertical: "center", wrapText: true}, +// border: { +// top: {style: 'thin', color: {auto: 1}}, +// bottom: {style: 'double', color: {auto: 1}} +// } +// }; +// Define the range of cells to merge for 'Sub-total' +const mergeRangeSubTotal = { + s: { c: 0, r: sumRow-1}, // Start at column A + e: { c: 5, r: sumRow-1} // End at column F +}; +// // Add the range to the 'merges' array in the worksheet if it doesn't exist +// if (!worksheet['!merges']) worksheet['!merges'] = []; +// worksheet['!merges'].push(mergeRangeSubTotal); + +// Update styles for the merged cell range where 'Sub-total' is located +const mergedCellRefSubTotal = XLSX.utils.encode_cell({ c: 0, r: sumRow-1 }); +if (!worksheet[mergedCellRefSubTotal]) { + worksheet[mergedCellRefSubTotal] = {}; // Create the cell if it doesn't exist +} +worksheet[mergedCellRefSubTotal].s = { + alignment: {horizontal: "right", vertical: "center", wrapText: true}, + border: { + top: {style: 'thin', color: {auto: 1}}, + bottom: {style: 'double', color: {auto: 1}}} +}; +// Add the range to the 'merges' array in the worksheet if it doesn't exist +if (!worksheet['!merges']) worksheet['!merges'] = []; +worksheet['!merges'].push(mergeRangeSubTotal) + + +const mergedCellRefM1 = XLSX.utils.encode_cell({ c: 12, r: sumRow}); +if (!worksheet[mergedCellRefM1]) { + worksheet[mergedCellRefM1] = {}; // Create the cell if it doesn't exist +} +worksheet[mergedCellRefM1].s = { + alignment: {horizontal: "right", vertical: "center", wrapText: true}, + border: { + top: {style: 'thin', color: {auto: 1}}, + bottom: {style: 'double', color: {auto: 1}} + } +}; + +} +const firstTableData = [ + ['Code1', 'PJName1', 'Client1','Team1','2011/01/01','2011/02/01','625','500','350','350','171'], // Row 1 + ['Code2', 'PJName2', 'Client2','Team2','2011/03/01','2011/04/01','1000','800','565','565','565'],// Row 2 + ['Code2', 'PJName2', 'Client2','Team2','2011/03/01','2011/04/01','1000','800','565','565','565'],// Row 3 + // ... more rows as needed +]; + + const handleDownload = async () => { + //setIsLoading(true); + + try { + const response = await fetch('/temp/EX01_Financial Status Report.xlsx', { + headers: { + 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + }, + }); + if (!response.ok) throw new Error('Network response was not ok.'); + + const data = await response.blob(); + const reader = new FileReader(); + reader.onload = (e) => { + if (e.target && e.target.result) { + const ab = e.target.result as ArrayBuffer; + const workbook = XLSX.read(ab, { type: 'array' }); + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + + // Add the current date to cell C2 + const cellAddress = 'C2'; + const date = new Date().toISOString().split('T')[0]; // Format YYYY-MM-DD + const formattedDate = date.replace(/-/g, '/'); // Change format to YYYY/MM/DD + XLSX.utils.sheet_add_aoa(worksheet, [[formattedDate]], { origin: cellAddress }); + + mergeCells(worksheet); + + // Style for cell A1: Font size 16 and bold + if (worksheet['A1']) { + worksheet['A1'].s = { + font: {bold: true,sz: 16,},alignment: { horizontal: 'center' } // Font size 16 //name: 'Times New Roman' // Specify font + }; + } + + // Apply styles from A2 A3 A5 (bold) + ['A2', 'A3', 'A5','A14'].forEach(cell => { + if (worksheet[cell]) { + worksheet[cell].s = { font: { bold: true },alignment: { horizontal: 'left' } }; + } + }); + + // Apply styles from A2 A3 A5 (bold) + ['A6', 'A7', 'A8','A9','A10','A11','A12'].forEach(cell => { + if (worksheet[cell]) { + worksheet[cell].s = { font: { bold: false },alignment: { horizontal: 'left' } }; + } + }); + + // Formatting from A15 to O15 + // Apply styles from A6 to K6 (bold, bottom border, center alignment) + for (let col = 0; col < 15; col++) { // Columns A to O + const cellRef = XLSX.utils.encode_col(col) + '15'; + if (worksheet[cellRef]) { + worksheet[cellRef].s = { + font: { bold: true }, + alignment: { horizontal: 'center' }, + border: { + bottom: { style: 'thin', color: { auto: 1 } } + } + }; + } + } + + // Find the last row of the first table + let lastRowOfFirstTable = 16; // Starting row for data in the first table + while (worksheet[XLSX.utils.encode_cell({ c: 0, r: lastRowOfFirstTable })]) { + lastRowOfFirstTable++; + } + // Insert the first data form into the worksheet at the desired location + //XLSX.utils.sheet_add_aoa(worksheet, firstTableData, { origin: { c: 0, r: lastRowOfFirstTable } }); + // Assuming worksheet is already defined, and we start inserting from row 16 +processDataAndInsert(worksheet, 16, firstTableData); + // Update lastRowOfFirstTable to account for the new data + lastRowOfFirstTable += firstTableData.length; + // Now insert the text that goes between the two tables + + // Calculate the maximum length of content in each column and set column width + const colWidths: number[] = []; + + // Start with a base width for each column (optional, but can help with columns that have no data) + // Check if worksheet['!ref'] is defined to prevent errors + const maxCol = worksheet['!ref'] ? worksheet['!ref'].split(':')[1].charCodeAt(0) - 'A'.charCodeAt(0) + 1 : 0; + for (let col = 0; col < maxCol; col++) { + colWidths[col] = 10; // Default base width + } + + const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: "", blankrows: true }) as (string | number)[][]; + + // Skip the first row in the jsonData + for (let row = 1; row < jsonData.length; row++) { + jsonData[row].forEach((cell, index) => { + // Only process if the cell is not null/undefined + if (cell) { + const valueLength = cell.toString().length; + colWidths[index] = Math.max(colWidths[index] || 0, valueLength); + } + }); + } + + // Check if worksheet exists before setting '!cols' + if (worksheet) { + worksheet['!cols'] = colWidths.map((width) => ({ wch: width + 2 })); // +2 for a little extra padding + } + + // Format filename with date + const today = new Date().toISOString().split('T')[0].replace(/-/g, '_'); // Get current date and format as YYYY_MM_DD + const filename = `EX01_Financial_Status_Report_${today}.xlsx`; // Append formatted date to the filename + + // Convert workbook back to XLSX file + XLSX.writeFile(workbook, filename); + } else { + throw new Error('Failed to load file'); + } + }; + reader.readAsArrayBuffer(data); + } catch (error) { + console.error('Error downloading the file: ', error); + } + + //setIsLoading(false); + }; + return ( + + + {t("Search Criteria")} + + {criteria.map((c) => { + return ( + + {c.type === "text" && ( + + )} + {c.type === "select" && ( + + {c.label} + + + )} + {c.type === "dateRange" && ( + + + + + + + {"-"} + + + + + + + )} + + ); + })} + + + + + + + + ); +} + +export default SearchBox; diff --git a/src/components/Report/ReportSearchBoxe1/index.ts b/src/components/Report/ReportSearchBoxe1/index.ts new file mode 100644 index 0000000..8f4d421 --- /dev/null +++ b/src/components/Report/ReportSearchBoxe1/index.ts @@ -0,0 +1,3 @@ +//src\components\SearchBox\index.ts +export { default } from "./SearchBoxe1"; +export type { Criterion } from "./SearchBoxe1";