Merge branch 'development' of gitlab.com:mbugroup/lti-web-client into feat/FE/US-339/TASK-361-362-363-slicing-purchase-and-integrate-purchase-report-page

This commit is contained in:
rstubryan
2025-12-10 14:12:25 +07:00
88 changed files with 5977 additions and 1404 deletions
+11
View File
@@ -0,0 +1,11 @@
import SuspenseHelper from '@/components/helper/SuspenseHelper';
const Layout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
return <SuspenseHelper>{children}</SuspenseHelper>;
};
export default Layout;
+59
View File
@@ -0,0 +1,59 @@
'use client';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
import ClosingDetail from '@/components/pages/closing/ClosingDetail';
import SalesReportTable from '@/components/pages/closing/sale/SalesReportTable';
import { ClosingApi } from '@/services/api/closing';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
const ClosingDetailPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
const closingId = searchParams.get('closingId');
const { data: closing, isLoading: isLoadingClosing } = useSWR(
closingId,
(id: number) => ClosingApi.getGeneralInfo(id)
);
const { data: salesReport, isLoading: isLoadingSalesReport } = useSWR(
closingId,
(id: number) => ClosingApi.getPenjualan(id)
);
if (!closingId) {
router.back();
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
<span className='loading loading-spinner loading-xl' />
</div>
);
}
if (!isLoadingClosing && (!closing || isResponseError(closing))) {
router.replace('/404');
return;
}
return (
<div className='w-full p-4 flex flex-row justify-center'>
{isLoadingClosing && (
<span className='loading loading-spinner loading-xl' />
)}
{!isLoadingClosing && isResponseSuccess(closing) && (
<ClosingDetail id={Number(closingId)} initialValue={closing.data} />
)}
{!isLoadingSalesReport && isResponseSuccess(salesReport) && (
<SalesReportTable type='detail' initialValues={salesReport.data} />
)}
</div>
);
};
export default ClosingDetailPage;
+11
View File
@@ -0,0 +1,11 @@
import ClosingsTable from '@/components/pages/closing/ClosingsTable';
const Closing = () => {
return (
<section className='w-full p-4'>
<ClosingsTable />
</section>
);
};
export default Closing;
+39 -20
View File
@@ -7,26 +7,39 @@
default: false;
prefersdark: false;
color-scheme: 'light';
--color-base-100: oklch(98% 0.001 106.423);
--color-base-200: oklch(97% 0.001 106.424);
--color-base-300: oklch(92% 0.003 48.717);
--color-base-content: oklch(22.389% 0.031 278.072);
--color-primary: oklch(60% 0.126 221.723);
--color-primary-content: oklch(100% 0 0);
--color-secondary: oklch(52% 0.105 223.128);
--color-secondary-content: oklch(100% 0 0);
--color-accent: oklch(45% 0.085 224.283);
--color-accent-content: oklch(100% 0 0);
--color-neutral: oklch(39% 0.07 227.392);
--color-neutral-content: oklch(100% 0 0);
--color-info: oklch(58% 0.158 241.966);
--color-info-content: oklch(100% 0 0);
--color-success: oklch(62% 0.194 149.214);
--color-success-content: oklch(100% 0 0);
--color-warning: oklch(85% 0.199 91.936);
--color-warning-content: oklch(0% 0 0);
--color-error: oklch(57% 0.245 27.325);
--color-error-content: oklch(100% 0 0);
/* Primary Colors */
--color-primary: oklch(39.4% 0.177 301.9);
--color-primary-content: oklch(87.5% 0.038 274.5);
/* Secondary Colors */
--color-secondary: oklch(60.1% 0.258 335.7);
--color-secondary-content: oklch(99.4% 0.007 337.8);
/* Accent Colors */
--color-accent: oklch(76.2% 0.155 170.8);
--color-accent-content: oklch(7.2% 0.007 167.6);
/* Neutral Colors */
--color-neutral: oklch(22.4% 0.032 258.8);
--color-neutral-content: oklch(87.7% 0.016 257);
/* Base Colors */
--color-base-100: oklch(100% 0 0); /* #ffffff */
--color-base-200: oklch(97.2% 0 0); /* #f2f2f2 */
--color-base-300: oklch(93.1% 0.002 249.7); /* #e5e6e6 */
--color-base-content: oklch(18.6% 0.024 257.7); /* #1f2937 */
/* Status/Utility Colors */
--color-info: oklch(67.4% 0.176 238.9);
--color-info-content: oklch(0% 0 0); /* #000000 */
--color-success: oklch(62.3% 0.147 149);
--color-success-content: oklch(100% 0 0); /* #ffffff */
--color-warning: oklch(82.2% 0.165 91.9);
--color-warning-content: oklch(0% 0 0); /* #000000 */
--color-error: oklch(61.8% 0.203 27.8);
--color-error-content: oklch(100% 0 0); /* #fffffff */
--radius-selector: 0rem;
--radius-field: 0.25rem;
--radius-box: 0.25rem;
@@ -43,6 +56,12 @@
@theme {
--font-inter: var(--font-inter);
--container-sm: 40rem;
--container-md: 48rem;
--container-lg: 64rem;
--container-xl: 80rem;
--container-2xl: 96rem;
}
html {
@@ -12,8 +12,6 @@ const DetailInventoryAdjustment = () => {
// Ambil data dari router state
useEffect(() => {
console.log('Router State');
console.log(window.history.state);
const state = window.history.state?.usr as
| { inventoryAdjustment?: InventoryAdjustment }
| undefined;
@@ -26,9 +24,6 @@ const DetailInventoryAdjustment = () => {
const finalData = inventoryAdjustment;
console.log('Final Data');
console.log(finalData);
if (!finalData) {
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
@@ -0,0 +1,11 @@
import SuspenseHelper from '@/components/helper/SuspenseHelper';
const Layout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
return <SuspenseHelper>{children}</SuspenseHelper>;
};
export default Layout;
+50
View File
@@ -0,0 +1,50 @@
'use client';
import InventoryProductDetail from '@/components/pages/inventory/product/detail/InventoryProductDetail';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { InventoryProductApi } from '@/services/api/inventory';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
const InventoryProductDetailPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
const inventoryProductId = searchParams.get('inventoryProductId');
const { data: inventoryProduct, isLoading: isLoadingInventoryProduct } =
useSWR(inventoryProductId, (id: number) =>
InventoryProductApi.getSingle(id)
);
if (!inventoryProductId) {
router.back();
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
<span className='loading loading-spinner loading-xl' />
</div>
);
}
if (
!isLoadingInventoryProduct &&
(!inventoryProduct || isResponseError(inventoryProduct))
) {
router.replace('/404');
return;
}
return (
<div className='size-full'>
{isLoadingInventoryProduct && (
<span className='loading loading-spinner loading-xl' />
)}
{!isLoadingInventoryProduct && isResponseSuccess(inventoryProduct) && (
<InventoryProductDetail inventoryProduct={inventoryProduct.data} />
)}
</div>
);
};
export default InventoryProductDetailPage;
+11
View File
@@ -0,0 +1,11 @@
import InventoryProductTable from '@/components/pages/inventory/product/InventoryProductTable';
const InventoryProductPage = () => {
return (
<div className='size-full'>
<InventoryProductTable />
</div>
);
};
export default InventoryProductPage;
@@ -1,10 +1,18 @@
'use client';
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
import React, { useImperativeHandle } from 'react';
import toast from 'react-hot-toast';
const AddProjectFlock = () => {
// useImperativeHandle(ref, () => ({
// validate() {
// toast.success('Validating');
// return false;
// },
// }));
return (
<section className='w-full p-4 flex flex-row justify-center'>
<section className='w-full flex flex-row justify-center'>
<ProjectFlockForm formType='add' />
</section>
);
@@ -44,7 +44,7 @@ export default function AddChickinKandang() {
return (
<>
<section className='w-full p-4'>
<section className='size-full'>
{isLoading && <span className='loading loading-spinner loading-xl' />}
{!isLoading &&
isResponseSuccess(projectFlockKandang) &&
@@ -10,7 +10,7 @@ const AddChickin = () => {
return (
<>
<section className='w-full p-4'>
<section className='w-full'>
<ProjectFlockChickinDetail projectFlockId={Number(projectFlockId)} />
</section>
</>
@@ -2,7 +2,7 @@ import ChickinTable from '@/components/pages/production/chickin/ChickinTable';
const Chickin = () => {
return (
<section className='w-full p-4'>
<section className='w-full'>
<ChickinTable />
</section>
);
@@ -0,0 +1,11 @@
import SuspenseHelper from '@/components/helper/SuspenseHelper';
const Layout = ({
children,
}: Readonly<{
children: React.ReactNode;
}>) => {
return <SuspenseHelper>{children}</SuspenseHelper>;
};
export default Layout;
@@ -0,0 +1,63 @@
'use client';
import ProjectFlockClosingForm from '@/components/pages/production/project-flock/closing/ProjectFlockClosingForm';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { ProjectFlockKandangApi } from '@/services/api/production';
import { ProjectFlockApi } from '@/services/api/production/project-flock';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
const ProjectFlockClosingPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
const projectFlockId = searchParams.get('projectFlockId');
const projectFlockKandangId = searchParams.get('projectFlockKandangId');
const { data: projectFlockKandang, isLoading: isLoadingProjectFlockKandang } =
useSWR(projectFlockKandangId, (id: number) =>
ProjectFlockKandangApi.getSingle(id)
);
const { data: projectFlock, isLoading: isLoadingProjectFlock } = useSWR(
projectFlockId,
(id: number) => ProjectFlockApi.getSingle(id)
);
if (!projectFlockId || !projectFlockKandangId) {
router.back();
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
<span className='loading loading-spinner loading-xl' />
</div>
);
}
if (
!isLoadingProjectFlock &&
(!projectFlock || isResponseError(projectFlock)) &&
!isLoadingProjectFlockKandang &&
(!projectFlockKandang || isResponseError(projectFlockKandang))
) {
router.replace('/404');
return;
}
return (
<div className='w-full h-full flex flex-col justify-center'>
{isLoadingProjectFlock ||
(isLoadingProjectFlockKandang && (
<span className='loading loading-spinner loading-xl' />
))}
{isResponseSuccess(projectFlock) &&
isResponseSuccess(projectFlockKandang) && (
<ProjectFlockClosingForm
projectFlock={projectFlock.data}
projectFlockKandang={projectFlockKandang.data}
/>
)}
</div>
);
};
export default ProjectFlockClosingPage;
@@ -37,7 +37,7 @@ const ProjectFlockEdit = () => {
}
return (
<div className='w-full p-4 flex flex-col justify-center'>
<div className='w-full flex flex-col justify-center'>
{isLoadingProjectFlock && (
<span className='loading loading-spinner loading-xl' />
)}
@@ -1,12 +1,13 @@
'use client';
import ProjectFlockDetail from '@/components/pages/production/project-flock/detail/ProjectFlockDetail';
import ProjectFlockForm from '@/components/pages/production/project-flock/form/ProjectFlockForm';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { ProjectFlockApi } from '@/services/api/production/project-flock';
import { useRouter, useSearchParams } from 'next/navigation';
import useSWR from 'swr';
const ProjectFlockDetail = () => {
const ProjectFlockDetailPage = () => {
const router = useRouter();
const searchParams = useSearchParams();
@@ -37,19 +38,17 @@ const ProjectFlockDetail = () => {
}
return (
<div className='w-full p-4 flex flex-col justify-center'>
<div className='w-full h-full flex flex-col justify-center'>
{isLoadingProjectFlock && (
<span className='loading loading-spinner loading-xl' />
)}
{isResponseSuccess(projectFlock) && (
<ProjectFlockForm
formType='detail'
initialValues={projectFlock.data}
refreshProjectFlocks={refreshProjectFlock}
/>
<ProjectFlockDetail projectFlock={projectFlock.data} />
)}
</div>
);
};
export default ProjectFlockDetail;
export default ProjectFlockDetailPage;
ProjectFlockDetail;
ProjectFlockDetail;
@@ -0,0 +1,60 @@
'use client';
import { usePathname, useRouter } from 'next/navigation';
import Drawer from '@/components/Drawer';
import React, { ReactNode } from 'react';
import ProjectFlockTable from '@/components/pages/production/project-flock/ProjectFlockTable';
import { useUiStore } from '@/stores/ui/ui.store';
export default function ProjectFlockLayout({
children,
}: {
children: ReactNode;
}) {
const pathname = usePathname();
const router = useRouter();
const toggleValidate = useUiStore((s) => s.toggleValidate);
const isAdd = pathname.endsWith('/add');
const isEdit = pathname.includes('/detail/edit');
const isDetail = pathname.includes('/detail');
const isChickin = pathname.includes('/chickin/add/kandang');
const isClosing = pathname.includes('/closing');
const isOpen = isAdd || isEdit || isDetail || isChickin || isClosing;
const handleBackdropClick = () => {
const unsub = useUiStore.getState().subscribeIsValid((isValid) => {
if (isValid) {
unsub(); // berhenti listen
router.push('/production/project-flock');
}
});
toggleValidate();
};
return (
<>
{/* List page always rendered */}
<div className='min-h-sceen w-full relative'>
<ProjectFlockTable
refresh={() => !isOpen && router.push('/production/project-flock')}
/>
</div>
{/* Render Drawer only on /add */}
<Drawer
open={isOpen}
setOpen={(v) => {
if (!v) router.push('/production/project-flock');
}}
closeOnBackdropClick={isDetail ? true : false}
onBackdropClick={handleBackdropClick}
variant='right'
zIndex='99999'
sidebarContent={isOpen && <div className=''>{children}</div>}
/>
</>
);
}
+1 -1
View File
@@ -2,7 +2,7 @@ import ProjectFlockTable from '@/components/pages/production/project-flock/Proje
const ProjectFlock = () => {
return (
<section className='w-full p-4'>
<section className='size-full p-4'>
<ProjectFlockTable />
</section>
);