refactor(FE): Refactor marketing report components and add HPP filter

This commit is contained in:
rstubryan
2026-02-12 11:16:26 +07:00
parent 6d2855d117
commit 43d26b4833
5 changed files with 658 additions and 403 deletions
+1 -5
View File
@@ -1,11 +1,7 @@
import MarketingReportContent from '@/components/pages/report/marketing/MarketingReportContent';
const MarketingReportPage = () => {
return (
<section className='w-full p-4'>
<MarketingReportContent />
</section>
);
return <MarketingReportContent />;
};
export default MarketingReportPage;
@@ -1,47 +1,42 @@
'use client';
import { JSX, useState } from 'react';
import { useState } from 'react';
import Tabs from '@/components/Tabs';
import DailyMarketingReportContent from '@/components/pages/report/marketing/tab/DailyMarketingReportContent';
import HppPerKandangTab from '@/components/pages/report/marketing/tab/HppPerKandangTab';
import { useMarketingTabStore } from '@/stores/marketing-tab/marketing-tab.store';
type MarketingReportTabType =
| 'daily'
| 'transaction'
| 'hpp-comparison'
| 'daily-hpp';
const MarketingReportContent = () => {
const [activeTabId, setActiveTabId] = useState<string>('1');
const tabActions = useMarketingTabStore((state) => state.tabActions);
const marketingReportTabs: {
id: MarketingReportTabType;
label: string;
content: JSX.Element;
}[] = [
const tabs = [
{
id: 'daily',
id: '1',
label: 'Penjualan Harian',
content: <DailyMarketingReportContent />,
},
{
id: 'daily-hpp',
id: '2',
label: 'HPP Harian Kandang',
content: <HppPerKandangTab />,
content: <HppPerKandangTab tabId={'2'} />,
},
];
const MarketingReportContent = () => {
const [activeTab, setActiveTab] = useState<string>('daily');
];
return (
<section className='w-full max-w-full pb-16'>
<section className='w-full'>
<Tabs
activeTabId={activeTab}
onTabChange={setActiveTab}
tabs={marketingReportTabs}
variant='lifted'
tabs={tabs}
variant='boxed'
activeTabId={activeTabId}
onTabChange={setActiveTabId}
className={{
content: '-m-px pl-px',
tabHeaderWrapper:
'justify-between items-center p-3 border-b border-base-content/10',
tab: 'w-fit',
content: 'p-0 m-0',
}}
sideContent={tabActions[activeTabId] || null}
/>
</section>
);
@@ -0,0 +1,40 @@
import * as yup from 'yup';
export type HppPerKandangFilterType = {
area_id: string | null;
location_id: string | null;
kandang_id: string | null;
weight_min: string | null;
weight_max: string | null;
period: string | null;
sort_by: string | null;
show_unrecorded: boolean | null;
};
export const HppPerKandangFilterSchema = yup.object({
area_id: yup.string().nullable(),
location_id: yup.string().nullable(),
kandang_id: yup.string().nullable(),
weight_min: yup.string().nullable(),
weight_max: yup
.string()
.nullable()
.test(
'is-greater-than-min',
'Rentang bobot max tidak boleh lebih kecil dari min',
function (value) {
const { weight_min } = this.parent;
if (!weight_min || !value) return true;
const weightMinNum = parseFloat(weight_min) || 0;
const weightMaxNum = parseFloat(value) || 0;
return weightMaxNum >= weightMinNum;
}
),
period: yup.string().required('Periode wajib diisi'),
sort_by: yup.string().nullable(),
show_unrecorded: yup.boolean().nullable(),
});
export type HppPerKandangFilterValues = yup.InferType<
typeof HppPerKandangFilterSchema
>;
@@ -0,0 +1,37 @@
import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton';
import Table from '@/components/Table';
import { HppPerKandangReport } from '@/types/api/report/hpp-per-kandang';
import { ColumnDef } from '@tanstack/react-table';
const HppPerKandangSkeleton = ({
columns,
icon,
title,
subtitle,
}: {
columns: ColumnDef<HppPerKandangReport['rows'][0]>[];
icon: React.ReactNode;
title: string;
subtitle: string;
}) => {
return (
<div className='relative size-full'>
<Table
data={[]}
columns={columns}
isLoading={true}
className={{
skeletonCellClassName: 'animate-none w-full h-5 bg-base-content/4',
headerColumnClassName: 'whitespace-nowrap',
containerClassName: 'mb-0 overflow-hidden',
tableWrapperClassName: 'overflow-hidden',
}}
/>
<div className='absolute inset-0 flex items-center justify-center'>
<DataStateSkeleton icon={icon} title={title} description={subtitle} />
</div>
</div>
);
};
export default HppPerKandangSkeleton;
File diff suppressed because it is too large Load Diff