From 466ea471217dedbb7dbd09bb3ace20375a6b3854 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Thu, 18 Dec 2025 16:08:15 +0700 Subject: [PATCH] feat(FE-364): create DailyMarketingReportContent component --- .../report/DailyMarketingReportContent.tsx | 413 ++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 src/components/pages/report/DailyMarketingReportContent.tsx diff --git a/src/components/pages/report/DailyMarketingReportContent.tsx b/src/components/pages/report/DailyMarketingReportContent.tsx new file mode 100644 index 00000000..1eba4ea3 --- /dev/null +++ b/src/components/pages/report/DailyMarketingReportContent.tsx @@ -0,0 +1,413 @@ +'use client'; + +import { ChangeEventHandler, useState } from 'react'; +import { pdf } from '@react-pdf/renderer'; +import toast from 'react-hot-toast'; + +import { Icon } from '@iconify/react'; +import Button from '@/components/Button'; +import Dropdown from '@/components/dropdown/Dropdown'; +import DateInput from '@/components/input/DateInput'; +import SelectInput, { + OptionType, + useSelect, +} from '@/components/input/SelectInput'; +import Menu from '@/components/menu/Menu'; +import MenuItem from '@/components/menu/MenuItem'; +import DailyMarketingsTable from '@/components/pages/report/DailyMarketingsTable'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import DailyMarketingReportPDF from '@/components/pages/report/DailyMarketingReportPDF'; + +import { Area } from '@/types/api/master-data/area'; +import { + AreaApi, + CustomerApi, + LocationApi, + WarehouseApi, +} from '@/services/api/master-data'; +import { Warehouse } from '@/types/api/master-data/warehouse'; +import { Customer } from '@/types/api/master-data/customer'; +import { MarketingReportApi } from '@/services/api/report/marketing-report'; +import { MARKETING_TYPE_OPTIONS } from '@/config/constant'; +import { httpClient } from '@/services/http/client'; +import { BaseApiResponse } from '@/types/api/api-general'; +import { DailyMarketingReport } from '@/types/api/report/marketing'; +import { isResponseError } from '@/lib/api-helper'; + +const DailyMarketingReportContent = () => { + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + reset: resetFilter, + } = useTableFilter({ + initial: { + search: '', + area_id: '', + location_id: '', + warehouse_id: '', + customer_id: '', + start_date: '', + end_date: '', + marketing_type: '', + filter_by: '', + sort_by: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + area_id: 'area_id', + location_id: 'location_id', + warehouse_id: 'warehouse_id', + customer_id: 'customer_id', + start_date: 'start_date', + end_date: 'end_date', + marketing_type: 'marketing_type', + filter_by: 'filter_by', + sort_by: 'sort_by', + }, + }); + + const dailyMarketingsReportUrl = `${MarketingReportApi.basePath}${getTableFilterQueryString()}`; + + const [isLoadingExportingToExcel, setIsLoadingExportingToExcel] = + useState(false); + const [isLoadingExportingToPdf, setIsLoadingExportingToPdf] = useState(false); + + const [selectedArea, setSelectedArea] = useState(null); + const { + setInputValue: setAreaInputValue, + options: areaOptions, + isLoadingOptions: isLoadingAreaOptions, + } = useSelect(AreaApi.basePath, 'id', 'name'); + + const areaChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedArea(val as OptionType); + updateFilter('area_id', val ? ((val as OptionType).value as string) : ''); + }; + + const [selectedLocation, setSelectedLocation] = useState( + null + ); + const { + setInputValue: setLocationInputValue, + options: locationOptions, + isLoadingOptions: isLoadingLocationOptions, + } = useSelect(LocationApi.basePath, 'id', 'name'); + + const locationChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedLocation(val as OptionType); + updateFilter( + 'location_id', + val ? ((val as OptionType).value as string) : '' + ); + }; + + const [selectedWarehouse, setSelectedWarehouse] = useState( + null + ); + const { + setInputValue: setWarehouseInputValue, + options: warehouseOptions, + isLoadingOptions: isLoadingWarehouseOptions, + } = useSelect(WarehouseApi.basePath, 'id', 'name'); + + const warehouseChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedWarehouse(val as OptionType); + updateFilter( + 'warehouse_id', + val ? ((val as OptionType).value as string) : '' + ); + }; + + const [selectedCustomer, setSelectedCustomer] = useState( + null + ); + const { + setInputValue: setCustomerInputValue, + options: customerOptions, + isLoadingOptions: isLoadingCustomerOptions, + } = useSelect(CustomerApi.basePath, 'id', 'name'); + + const customerChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedCustomer(val as OptionType); + updateFilter( + 'customer_id', + val ? ((val as OptionType).value as string) : '' + ); + }; + + const startDateChangeHandler = (e: React.ChangeEvent) => { + updateFilter('start_date', e.target.value ? e.target.value : ''); + }; + + const endDateChangeHandler = (e: React.ChangeEvent) => { + updateFilter('end_date', e.target.value ? e.target.value : ''); + }; + + const [selectedMarketingType, setSelectedMarketingType] = + useState(null); + const marketingTypeChangeHandler = ( + val: OptionType | OptionType[] | null + ) => { + setSelectedMarketingType(val as OptionType); + updateFilter( + 'marketing_type', + val ? ((val as OptionType).value as string) : '' + ); + }; + + const searchChangeHandler: ChangeEventHandler = (e) => { + updateFilter('search', e.target.value); + }; + + const filterByChangeHandler = (filterBy: string) => { + updateFilter('filter_by', filterBy); + }; + + const sortByChangeHandler = (sort: 'asc' | 'desc' | '') => { + updateFilter('sort_by', sort); + }; + + const exportToExcelHandler = async () => { + setIsLoadingExportingToExcel(true); + + await MarketingReportApi.exportDailyMarketingToExcel( + getTableFilterQueryString() + ); + + setIsLoadingExportingToExcel(false); + }; + + const exportToPdfHandler = async () => { + setIsLoadingExportingToPdf(true); + + const params = new URLSearchParams(getTableFilterQueryString()); + + params.set('limit', '9999999'); + + const queryString = `?${params.toString()}`; + + try { + const dailyMarketingsReport = await httpClient< + BaseApiResponse + >(`${MarketingReportApi.basePath}${queryString}`); + + if (isResponseError(dailyMarketingsReport)) { + toast.error('Gagal melakukan export penjualan harian! Coba lagi.'); + return; + } + + const openPdf = async () => { + const dailyMarketingReportPdfBlob = await pdf( + + ).toBlob(); + + const dailyMarketingReportPdfUrl = URL.createObjectURL( + dailyMarketingReportPdfBlob + ); + window.open(dailyMarketingReportPdfUrl, '_blank'); + }; + + const downloadPdf = async () => { + const blob = await pdf( + + ).toBlob(); + const url = URL.createObjectURL(blob); + + const link = document.createElement('a'); + link.href = url; + link.download = 'laporan-penjualan-harian.pdf'; + link.click(); + + URL.revokeObjectURL(url); + }; + + await openPdf(); + } catch (error) { + toast.error('Gagal melakukan export penjualan harian! Coba lagi.'); + } + + setIsLoadingExportingToPdf(false); + }; + + const handleReset = () => { + setSelectedArea(null); + setSelectedLocation(null); + setSelectedWarehouse(null); + setSelectedCustomer(null); + setSelectedMarketingType(null); + resetFilter(); + }; + + return ( +
+
+

Penjualan Harian

+
+ + {/* Filters */} +
+
+ + + + + + + + + + + +
+ +
+ + +
+ + + + + + Export{' '} + + + } + > + + + + + +
+
+
+ + +
+ ); +}; + +export default DailyMarketingReportContent;