From 4dbed752e51c232ae49014f17a58b6b1e225f8f9 Mon Sep 17 00:00:00 2001 From: leoho2fi Date: Fri, 26 Apr 2024 18:38:59 +0800 Subject: [PATCH] add project claims report --- public/temp/AR07_Project Claims Report.xlsx | Bin 0 -> 12968 bytes .../analytics/ProjectClaimsReport/page.tsx | 24 + src/app/api/report7/index.ts | 42 ++ .../ProjectClaimsReport.tsx | 17 + .../Report/ProjectClaimsReport/index.ts | 2 + .../ProjectClaimsReportGen.tsx | 44 ++ .../ProjectClaimsReportGenLoading.tsx | 41 ++ .../ProjectClaimsReportGenWrapper.tsx | 19 + .../Report/ProjectClaimsReportGen/index.ts | 2 + .../Report/ReportSearchBox7/SearchBox7.tsx | 465 ++++++++++++++++++ .../Report/ReportSearchBox7/index.ts | 3 + 11 files changed, 659 insertions(+) create mode 100644 public/temp/AR07_Project Claims Report.xlsx create mode 100644 src/app/(main)/analytics/ProjectClaimsReport/page.tsx create mode 100644 src/app/api/report7/index.ts create mode 100644 src/components/Report/ProjectClaimsReport/ProjectClaimsReport.tsx create mode 100644 src/components/Report/ProjectClaimsReport/index.ts create mode 100644 src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGen.tsx create mode 100644 src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenLoading.tsx create mode 100644 src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenWrapper.tsx create mode 100644 src/components/Report/ProjectClaimsReportGen/index.ts create mode 100644 src/components/Report/ReportSearchBox7/SearchBox7.tsx create mode 100644 src/components/Report/ReportSearchBox7/index.ts diff --git a/public/temp/AR07_Project Claims Report.xlsx b/public/temp/AR07_Project Claims Report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..95b2c13bd92b90721a7b0d3e7d88e4ce2afa88e4 GIT binary patch literal 12968 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 LjctE%TY&!uw1_ud literal 0 HcmV?d00001 diff --git a/src/app/(main)/analytics/ProjectClaimsReport/page.tsx b/src/app/(main)/analytics/ProjectClaimsReport/page.tsx new file mode 100644 index 0000000..9f97f39 --- /dev/null +++ b/src/app/(main)/analytics/ProjectClaimsReport/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 ProjectClaimsReportComponent from "@/components/Report/ProjectClaimsReport"; + +export const metadata: Metadata = { + title: "Project Claims Report", +}; + +const ProjectClaimsReport: React.FC = () => { + return ( + + + Project Claims Report + + {/* }> + + */} + + + ); +}; +export default ProjectClaimsReport; diff --git a/src/app/api/report7/index.ts b/src/app/api/report7/index.ts new file mode 100644 index 0000000..c31a754 --- /dev/null +++ b/src/app/api/report7/index.ts @@ -0,0 +1,42 @@ +//src\app\api\report\index.ts +import { cache } from "react"; + +export interface ProjectClaims { + id: number; + projectCode: string; + projectName: string; + team: string; + teamLeader: string; + startDate: string; + startDateFrom: string; + startDateTo: string; + targetEndDate: string; + client: string; + subsidiary: string; + staffName: string; +} + +export const preloadProjects = () => { + fetchProjectsProjectClaims(); +}; + +export const fetchProjectsProjectClaims = cache(async () => { + return mockProjects; +}); + +const mockProjects: ProjectClaims[] = [ + { + id: 1, + projectCode: "CUST-001", + projectName: "Client A", + team: "N/A", + teamLeader: "N/A", + startDate: "1/2/2024", + startDateFrom: "1/2/2024", + startDateTo: "1/2/2024", + targetEndDate: "30/3/2024", + client: "ss", + subsidiary: "sus", + staffName: "Leo", + }, +]; diff --git a/src/components/Report/ProjectClaimsReport/ProjectClaimsReport.tsx b/src/components/Report/ProjectClaimsReport/ProjectClaimsReport.tsx new file mode 100644 index 0000000..ca230e1 --- /dev/null +++ b/src/components/Report/ProjectClaimsReport/ProjectClaimsReport.tsx @@ -0,0 +1,17 @@ +//src\components\LateStartReport\LateStartReport.tsx +"use client"; +import * as React from "react"; +import "../../../app/global.css"; +import { Suspense } from "react"; +import ProjectClaimsReportGen from "@/components/Report/ProjectClaimsReportGen"; + +const ProjectClaimsReport: React.FC = () => { + + return ( + }> + + + ); +}; + +export default ProjectClaimsReport; \ No newline at end of file diff --git a/src/components/Report/ProjectClaimsReport/index.ts b/src/components/Report/ProjectClaimsReport/index.ts new file mode 100644 index 0000000..fc83eb4 --- /dev/null +++ b/src/components/Report/ProjectClaimsReport/index.ts @@ -0,0 +1,2 @@ +//src\components\LateStartReport\index.ts +export { default } from "./ProjectClaimsReport"; diff --git a/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGen.tsx b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGen.tsx new file mode 100644 index 0000000..204b847 --- /dev/null +++ b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGen.tsx @@ -0,0 +1,44 @@ +//src\components\LateStartReportGen\LateStartReportGen.tsx +"use client"; +import React, { useMemo, useState } from "react"; +import SearchBox, { Criterion } from "../ReportSearchBox7"; +import { useTranslation } from "react-i18next"; +import { ProjectClaims } from "@/app/api/report7"; +//import { DownloadReportButton } from './DownloadReportButton'; +interface Props { + projects: ProjectClaims[]; +} +type SearchQuery = Partial>; +type SearchParamNames = keyof SearchQuery; + +const ProgressByClientSearch: React.FC = ({ projects }) => { + const { t } = useTranslation("projects"); + + const searchCriteria: Criterion[] = useMemo( + () => [ + { + label: "Report Period From", + label2: "Report Period To", + paramName: "targetEndDate", + type: "dateRange", + }, + { label: "Project Code", paramName: "projectCode", type: "select", options: ["M1963", "M1235", "M1476"] }, + { label: "Staff Name", paramName: "staffName", type: "select", options: ["Kennith", "Tom", "Cyril"] }, + ], + [t], + ); + + return ( + <> + { + console.log(query); + }} + /> + {/* */} + + ); +}; + +export default ProgressByClientSearch; diff --git a/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenLoading.tsx b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenLoading.tsx new file mode 100644 index 0000000..ab04aa4 --- /dev/null +++ b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenLoading.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 ProjectClaimsReportGenLoading: React.FC = () => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default ProjectClaimsReportGenLoading; diff --git a/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenWrapper.tsx b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenWrapper.tsx new file mode 100644 index 0000000..c5da0ec --- /dev/null +++ b/src/components/Report/ProjectClaimsReportGen/ProjectClaimsReportGenWrapper.tsx @@ -0,0 +1,19 @@ +//src\components\LateStartReportGen\LateStartReportGenWrapper.tsx +import { fetchProjectsProjectClaims } from "@/app/api/report7"; +import React from "react"; +import ProjectClaimsReportGen from "./ProjectClaimsReportGen"; +import ProjectClaimsReportGenLoading from "./ProjectClaimsReportGenLoading"; + +interface SubComponents { + Loading: typeof ProjectClaimsReportGenLoading; +} + +const ProjectClaimsReportGenWrapper: React.FC & SubComponents = async () => { + const clentprojects = await fetchProjectsProjectClaims(); + + return ; +}; + +ProjectClaimsReportGenWrapper.Loading = ProjectClaimsReportGenLoading; + +export default ProjectClaimsReportGenWrapper; \ No newline at end of file diff --git a/src/components/Report/ProjectClaimsReportGen/index.ts b/src/components/Report/ProjectClaimsReportGen/index.ts new file mode 100644 index 0000000..dab06a1 --- /dev/null +++ b/src/components/Report/ProjectClaimsReportGen/index.ts @@ -0,0 +1,2 @@ +//src\components\LateStartReportGen\index.ts +export { default } from "./ProjectClaimsReportGenWrapper"; diff --git a/src/components/Report/ReportSearchBox7/SearchBox7.tsx b/src/components/Report/ReportSearchBox7/SearchBox7.tsx new file mode 100644 index 0000000..5ad1d83 --- /dev/null +++ b/src/components/Report/ReportSearchBox7/SearchBox7.tsx @@ -0,0 +1,465 @@ +//src\components\ReportSearchBox\SearchBox.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"), + })); + }; + }, []); + + const handleReset = () => { + setInputs(defaultInputs); + onReset?.(); + }; + + const handleSearch = () => { + onSearch(inputs); + + }; + + const handleDownload = async () => { + //setIsLoading(true); + + try { + const response = await fetch('/temp/AR07_Project Claims 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 }); + + // Style for cell A1: Font size 16 and bold + if (worksheet['A1']) { + worksheet['A1'].s = { + font: {bold: true,sz: 16, // Font size 16 + //name: 'Times New Roman' // Specify font + } + }; + } + + // Apply styles from A2 to A4 (bold) + ['A2', 'A3', 'A4'].forEach(cell => { + if (worksheet[cell]) { + worksheet[cell].s = { font: { bold: true } }; + } + }); + + // Formatting from A6 to G6 + // Apply styles from A5 to G5 (bold, bottom border, center alignment) + for (let col = 0; col < 7; col++) { // Columns A to G + const cellRef = XLSX.utils.encode_col(col) + '6'; + if (worksheet[cellRef]) { + worksheet[cellRef].s = { + font: { bold: true }, + alignment: { horizontal: 'center' }, + border: { + bottom: { style: 'thin', color: { auto: 1 } } + } + }; + } + } + + const firstTableData = [ + ['Column1', 'Column2', 'Column3'], // Row 1 + ['Data1', 'Data2', 'Data3'], // Row 2 + // ... more rows as needed + ]; + const secondTableData = [ + ['Column1', 'Column2', 'Column3'], // Row 1 of second table + ['Data1', 'Data2', 'Data3'], // Row 2 of second table + // ... more rows as needed + ]; + + // Find the last row of the first table + let lastRowOfFirstTable = 6; // 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 } }); + // Update lastRowOfFirstTable to account for the new data + lastRowOfFirstTable += firstTableData.length; + // Now insert the text that goes between the two tables + + // Insert the additional text with one row of spacing after the first table + const textRow = lastRowOfFirstTable + 1; // Adjust the 1 based on how many lines of spacing you want + XLSX.utils.sheet_add_aoa(worksheet, [['AR07 - Project Claims Report (Staff)']], { origin: { c: 0, r: textRow } }); + XLSX.utils.sheet_add_aoa(worksheet, [['Report Generation Date:']], { origin: { c: 0, r: (textRow+1) } }); + XLSX.utils.sheet_add_aoa(worksheet, [[formattedDate]], { origin: { c: 2, r: (textRow+1) } }); + XLSX.utils.sheet_add_aoa(worksheet, [['Report Period:']], { origin: { c: 0, r: (textRow+2) } }); + //XLSX.utils.sheet_add_aoa(worksheet, [[]], { origin: { c: 2, r: (textRow+2) } }); + XLSX.utils.sheet_add_aoa(worksheet, [['Total Claim Amount (HKD):']], { origin: { c: 0, r: (textRow+3) } }); + XLSX.utils.sheet_add_aoa(worksheet, [[]], { origin: { c: 2, r: (textRow+3) } }); + // Row 6 is the template row we want to copy + const templateRow = 6; + // This is the new row where we want to copy the template row's content and style + const newRow = textRow + 6; + // Copy content and style from each cell in row 6 to newRow + for (let col = 0; col < 7; col++) { // Adjust the 7 if there are more columns + const sourceCellRef = XLSX.utils.encode_cell({ c: col, r: templateRow - 1 }); + const targetCellRef = XLSX.utils.encode_cell({ c: col, r: newRow - 1 }); + // If the source cell exists, copy its content and style + if (worksheet[sourceCellRef]) { + // Copy cell content + worksheet[targetCellRef] = { ...worksheet[sourceCellRef] }; + // If there is a style, we need to deep clone it to avoid references to the same style object + if (worksheet[sourceCellRef].s) { + worksheet[targetCellRef].s = JSON.parse(JSON.stringify(worksheet[sourceCellRef].s)); + } + } + } + + let secondTableStartRow = textRow + 6; + // Insert the second data form into the worksheet at the new starting row + XLSX.utils.sheet_add_aoa(worksheet, secondTableData, { origin: { c: 0, r: secondTableStartRow } }); + + // Source cell coordinates + const sourceCellCoord = { c: 2, r: 2 }; // C3 (columns and rows are 0-indexed in this library) + // Target cell coordinates + const targetCellCoord = { c: 2, r: textRow + 2 }; + // Create references for source and target cells + const sourceCellRef = XLSX.utils.encode_cell(sourceCellCoord); + const targetCellRef = XLSX.utils.encode_cell(targetCellCoord); + // Copy the cell content from C3 to the target cell + if (worksheet[sourceCellRef]) { + worksheet[targetCellRef] = { ...worksheet[sourceCellRef] }; + // If the source cell has a style, deep clone it for the target cell + if (worksheet[sourceCellRef].s) { + worksheet[targetCellRef].s = JSON.parse(JSON.stringify(worksheet[sourceCellRef].s)); + } + } + // Define the range of cells to merge + const mergeRangeA1 = { + s: { c: 0, r: textRow}, // Start cell + e: { c: 3, r: textRow} // End cell + }; + // Add the range to the 'merges' array in the worksheet if it doesn't exist + if (!worksheet['!merges']) worksheet['!merges'] = []; + worksheet['!merges'].push(mergeRangeA1); + // Apply center alignment to the merged cell + const mergedCellRefA1 = XLSX.utils.encode_cell({ c: 0, r: textRow}); + if (!worksheet[mergedCellRefA1]) { + worksheet[mergedCellRefA1] = {}; // Create the cell if it doesn't exist + } + worksheet[mergedCellRefA1].s = { + alignment: {horizontal: "left",vertical: "center",wrapText: true} + }; + + // Define the range of cells to merge { c: 0, r: (textRow+1) } to { c: 1, r: (textRow+1) } + const mergeRangeA2 = { + s: { c: 0, r: textRow + 1 }, // Start cell + e: { c: 1, r: textRow + 1 } // End cell + }; + // Add the range to the 'merges' array in the worksheet if it doesn't exist + if (!worksheet['!merges']) worksheet['!merges'] = []; + worksheet['!merges'].push(mergeRangeA2); + // Apply center alignment to the merged cell + const mergedCellRefA2 = XLSX.utils.encode_cell({ c: 0, r: textRow + 1 }); + if (!worksheet[mergedCellRefA2]) { + worksheet[mergedCellRefA2] = {}; // Create the cell if it doesn't exist + } + worksheet[mergedCellRefA2].s = { + alignment: {horizontal: "left",vertical: "center",wrapText: true} + }; + + // Define the range of cells to merge + const mergeRangeA3 = { + s: { c: 0, r: textRow + 2 }, // Start cell + e: { c: 1, r: textRow + 2 } // End cell + }; + // Add the range to the 'merges' array in the worksheet if it doesn't exist + if (!worksheet['!merges']) worksheet['!merges'] = []; + worksheet['!merges'].push(mergeRangeA3); + // Apply center alignment to the merged cell + const mergedCellRefA3 = XLSX.utils.encode_cell({ c: 0, r: textRow + 2 }); + if (!worksheet[mergedCellRefA3]) { + worksheet[mergedCellRefA3] = {}; // Create the cell if it doesn't exist + } + worksheet[mergedCellRefA3].s = { + alignment: {horizontal: "left",vertical: "center",wrapText: true} + }; + + // Define the range of cells to merge + const mergeRangeA4 = { + s: { c: 0, r: textRow + 3 }, // Start cell + e: { c: 1, r: textRow + 3 } // End cell + }; + // Add the range to the 'merges' array in the worksheet if it doesn't exist + if (!worksheet['!merges']) worksheet['!merges'] = []; + worksheet['!merges'].push(mergeRangeA4); + // Apply center alignment to the merged cell + const mergedCellRefA4 = XLSX.utils.encode_cell({ c: 0, r: textRow + 3 }); + if (!worksheet[mergedCellRefA4]) { + worksheet[mergedCellRefA4] = {}; // Create the cell if it doesn't exist + } + worksheet[mergedCellRefA4].s = { + alignment: {horizontal: "left",vertical: "center",wrapText: true} + }; + + // Style for the cell at { c: 0, r: textRow } + const tStyle = { + font: { bold: true, sz: 16, color: { rgb: "000000" } }, // Example: Black, bold, 12pt font + alignment: { horizontal: "left", vertical: "center" }, + // Add any additional styling properties here + }; + + // Apply the unique style to the cell at { c: 0, r: textRow } + const cellRefUnique = XLSX.utils.encode_cell({ c: 0, r: textRow }); + worksheet[cellRefUnique].s = tStyle; + + // Style for the other cells + const stStyle = { + font: { bold: true, sz: 11, color: { rgb: "000000" } }, + alignment: { horizontal: "left", vertical: "center" }, + // Add any additional styling properties here + }; + + // Apply the same style to the cells at { c: 0, r: textRow+1 }, { c: 0, r: textRow+2 }, { c: 0, r: textRow+3 } + for (let i = 1; i <= 3; i++) { + const cellRefOther = XLSX.utils.encode_cell({ c: 0, r: textRow + i }); + if (!worksheet[cellRefOther]) { + worksheet[cellRefOther] = {}; // Create the cell if it doesn't exist + } + worksheet[cellRefOther].s = stStyle; + } + + // Calculate the maximum length of content in each column and set column width + const colWidths: number[] = []; + + const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: "", blankrows: true }) as (string | number)[][]; + jsonData.forEach((row: (string | number)[]) => { + row.forEach((cell: string | number, index: number) => { + const valueLength = cell.toString().length; + colWidths[index] = Math.max(colWidths[index] || 0, valueLength); + }); + }); + + // Apply calculated widths to each column, skipping column A + worksheet['!cols'] = colWidths.map((width, index) => { + if (index === 0) { + return { wch: 8 }; // Set default or specific width for column A if needed + } + return { wch: width + 2 }; // Add padding to width + }); + + // 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 = `AR07_Project_Claims_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/ReportSearchBox7/index.ts b/src/components/Report/ReportSearchBox7/index.ts new file mode 100644 index 0000000..b3a9815 --- /dev/null +++ b/src/components/Report/ReportSearchBox7/index.ts @@ -0,0 +1,3 @@ +//src\components\SearchBox\index.ts +export { default } from "./SearchBox7"; +export type { Criterion } from "./SearchBox7";