|
- //src\components\ReportSearchBox3\SearchBox3.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<T extends string> {
- label: string;
- label2?: string;
- paramName: T;
- paramName2?: T;
- }
-
- interface TextCriterion<T extends string> extends BaseCriterion<T> {
- type: "text";
- }
-
- interface SelectCriterion<T extends string> extends BaseCriterion<T> {
- type: "select";
- options: string[];
- }
-
- interface DateRangeCriterion<T extends string> extends BaseCriterion<T> {
- type: "dateRange";
- }
-
- export type Criterion<T extends string> =
- | TextCriterion<T>
- | SelectCriterion<T>
- | DateRangeCriterion<T>;
-
- interface Props<T extends string> {
- criteria: Criterion<T>[];
- onSearch: (inputs: Record<T, string>) => void;
- onReset?: () => void;
- }
-
- function SearchBox<T extends string>({
- criteria,
- onSearch,
- onReset,
- }: Props<T>) {
- const { t } = useTranslation("common");
- const defaultInputs = useMemo(
- () =>
- criteria.reduce<Record<T, string>>(
- (acc, c) => {
- return { ...acc, [c.paramName]: c.type === "select" ? "All" : "" };
- },
- {} as Record<T, string>,
- ),
- [criteria],
- );
- const [inputs, setInputs] = useState(defaultInputs);
-
- const makeInputChangeHandler = useCallback(
- (paramName: T): React.ChangeEventHandler<HTMLInputElement> => {
- 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/AR03_Resource Overconsumption.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 L6
- // Apply styles from A6 to L6 (bold, bottom border, center alignment)
- for (let col = 0; col < 12; col++) { // Columns A to K
- 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
- ];
- // 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++;
- }
-
- // 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 = `AR03_Resource_Overconsumption_${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 (
- <Card>
- <CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
- <Typography variant="overline">{t("Search Criteria")}</Typography>
- <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}>
- {criteria.map((c) => {
- return (
- <Grid key={c.paramName} item xs={6}>
- {c.type === "text" && (
- <TextField
- label={c.label}
- fullWidth
- onChange={makeInputChangeHandler(c.paramName)}
- value={inputs[c.paramName]}
- />
- )}
- {c.type === "select" && (
- <FormControl fullWidth>
- <InputLabel>{c.label}</InputLabel>
- <Select
- label={c.label}
- onChange={makeSelectChangeHandler(c.paramName)}
- value={inputs[c.paramName]}
- >
- <MenuItem value={"All"}>{t("All")}</MenuItem>
- {c.options.map((option, index) => (
- <MenuItem key={`${option}-${index}`} value={option}>
- {option}
- </MenuItem>
- ))}
- </Select>
- </FormControl>
- )}
- {c.type === "dateRange" && (
- <LocalizationProvider
- dateAdapter={AdapterDayjs}
- // TODO: Should maybe use a custom adapterLocale here to support YYYY-MM-DD
- adapterLocale="zh-hk"
- >
- <Box display="flex">
- <FormControl fullWidth>
- <DatePicker
- label={c.label}
- onChange={makeDateChangeHandler(c.paramName)}
- value={inputs[c.paramName] ? dayjs(inputs[c.paramName]) : null}
- />
- </FormControl>
- <Box
- display="flex"
- alignItems="center"
- justifyContent="center"
- marginInline={2}
- >
- {"-"}
- </Box>
- <FormControl fullWidth>
- <DatePicker
- label={c.label2}
- onChange={makeDateToChangeHandler(c.paramName)}
- value={inputs[c.paramName.concat("To") as T] ? dayjs(inputs[c.paramName.concat("To") as T]) : null}
- />
- </FormControl>
- </Box>
- </LocalizationProvider>
- )}
- </Grid>
- );
- })}
- </Grid>
- <CardActions sx={{ justifyContent: "flex-end" }}>
- <Button
- variant="text"
- startIcon={<RestartAlt />}
- onClick={handleReset}
- >
- {t("Reset")}
- </Button>
- <Button
- variant="outlined"
- startIcon={<Search />}
- onClick={handleDownload}
- >
- {t("Download")}
- </Button>
- </CardActions>
- </CardContent>
- </Card>
- );
- }
-
- export default SearchBox;
|