mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE): refactor UI detail from page into drawer
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function ProjectFlockLayout({
|
||||
closeOnBackdropClick={isDetail ? true : false}
|
||||
onBackdropClick={handleBackdropClick}
|
||||
variant='right'
|
||||
sidebarContent={isOpen && <div className='p-4'>{children}</div>}
|
||||
sidebarContent={isOpen && <div className=''>{children}</div>}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
import Badge from '@/components/Badge';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import {
|
||||
formatCurrency,
|
||||
formatDate,
|
||||
formatNumber,
|
||||
formatTitleCase,
|
||||
} from '@/lib/helper';
|
||||
import { ProjectFlock } from '@/types/api/production/project-flock';
|
||||
import { Icon } from '@iconify/react';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
|
||||
const ProjectFlockDetail = ({
|
||||
projectFlock,
|
||||
}: {
|
||||
projectFlock: ProjectFlock;
|
||||
}) => {
|
||||
const [openBudgets, setOpenBudget] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='h-full w-full flex flex-col gap-4'>
|
||||
{/* Header */}
|
||||
<div className='flex flex-row justify-between items-center px-4 pt-4'>
|
||||
<div className='flex flex-row h-full gap-2'>
|
||||
<Link
|
||||
href={`/production/project-flock`}
|
||||
className='hover:text-gray-400'
|
||||
>
|
||||
<Icon icon='mdi:close' width={24} height={24} />
|
||||
</Link>
|
||||
<div className='divider divider-horizontal p-0 m-0'></div>
|
||||
<div className='text-sm text-secondary'>
|
||||
Created On {formatDate(projectFlock.created_at, 'MMM DD, YYYY')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row gap-3 justify-end'>
|
||||
<Link
|
||||
href={`/production/project-flock/detail/edit?projectFlockId=${projectFlock.id}`}
|
||||
>
|
||||
<Icon icon='mdi:square-edit-outline' width={20} height={20} />
|
||||
</Link>
|
||||
<Button variant='link' className='p-0 text-error'>
|
||||
<Icon icon='mdi:trash-can-outline' width={20} height={20} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Informasi Umum */}
|
||||
<div className='border-t-1 border-gray-300'>
|
||||
<div className='p-4 flex flex-col gap-4'>
|
||||
<h2 className='text-2xl font-semibold'>Informasi Umum</h2>
|
||||
{/* Badge Row */}
|
||||
<div className='flex flex-row gap-2'>
|
||||
<Badge
|
||||
variant='soft'
|
||||
color={
|
||||
projectFlock.approval.step_number == 1
|
||||
? 'secondary'
|
||||
: projectFlock.approval.step_number == 2
|
||||
? 'success'
|
||||
: projectFlock.approval.step_number >= 3
|
||||
? 'error'
|
||||
: undefined
|
||||
}
|
||||
className={{
|
||||
badge: 'rounded-lg px-2',
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:circle'
|
||||
width={12}
|
||||
height={12}
|
||||
color={
|
||||
projectFlock.approval.step_number == 1
|
||||
? 'secondary'
|
||||
: projectFlock.approval.step_number == 2
|
||||
? 'success'
|
||||
: projectFlock.approval.step_number >= 3
|
||||
? 'error'
|
||||
: undefined
|
||||
}
|
||||
/>{' '}
|
||||
{projectFlock.approval.step_name}
|
||||
</Badge>
|
||||
<div className='divider divider-horizontal p-0 m-0'></div>
|
||||
<Badge
|
||||
color='secondary'
|
||||
variant='soft'
|
||||
className={{ badge: 'rounded-lg px-2' }}
|
||||
>
|
||||
<Icon icon='mdi:bookmark' width={12} height={12} />
|
||||
{` ${formatTitleCase(projectFlock.category)}`}
|
||||
</Badge>
|
||||
</div>
|
||||
{/* Information Grid */}
|
||||
<div className='grid grid-cols-3 gap-4'>
|
||||
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
|
||||
<Icon width={14} height={14} icon='mdi:account' /> Submitted
|
||||
</div>
|
||||
<div className='col-span-2'>
|
||||
<Badge
|
||||
variant='soft'
|
||||
color='secondary'
|
||||
className={{
|
||||
badge: 'rounded-lg px-2',
|
||||
}}
|
||||
>
|
||||
<Icon icon='mdi:account-circle' width={14} height={14} />{' '}
|
||||
{projectFlock.created_user.name}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
|
||||
<Icon width={14} height={14} icon={'mdi:clock'} /> History
|
||||
</div>
|
||||
<div className='col-span-2'>
|
||||
<Button variant='outline' className='py-1 text-sm'>
|
||||
See History{' '}
|
||||
<Icon
|
||||
icon='mdi:arrow-top-right-thin'
|
||||
width={11}
|
||||
height={11}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* BARIS 1 */}
|
||||
<div
|
||||
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
|
||||
relative
|
||||
before:content-[""] before:absolute before:left-[5px] before:top-[90%] before:bottom-[-100%] before:w-[1px] before:border-1 before:border-dashed before:border-gray-400'
|
||||
>
|
||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Area
|
||||
</div>
|
||||
<div className='col-span-2'>{projectFlock.area.name}</div>
|
||||
|
||||
{/* BARIS 2 */}
|
||||
<div
|
||||
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
|
||||
relative
|
||||
before:content-[""] before:absolute before:left-[5px] before:top-[90%] before:bottom-[-100%] before:w-[1px] before:border-1 before:border-dashed before:border-gray-400'
|
||||
>
|
||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> Lokasi
|
||||
</div>
|
||||
<div className='col-span-2'>{projectFlock.location.name}</div>
|
||||
|
||||
<div
|
||||
className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2
|
||||
relative
|
||||
before:content-[""] before:absolute before:left-[5px] before:top-[90%] before:bottom-[-100%] before:w-[1px] before:border-1 before:border-dashed before:border-gray-400'
|
||||
>
|
||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' /> FCR
|
||||
</div>
|
||||
<div className='col-span-2'>{projectFlock.fcr.name}</div>
|
||||
|
||||
{/* BARIS 3 (Terakhir - TIDAK PERLU garis di bawahnya) */}
|
||||
<div className='col-span-1 flex flex-row items-center text-gray-400 font-semibold gap-2'>
|
||||
<Icon width={14} height={14} icon='mdi:circle-slice-8' />{' '}
|
||||
Kategori
|
||||
</div>
|
||||
<div className='col-span-2'>
|
||||
{formatTitleCase(projectFlock.category)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Kandang Aktif */}
|
||||
<div className='border-t-1 border-gray-300'>
|
||||
<div className='p-4 flex flex-col gap-4'>
|
||||
<h2 className='text-2xl font-semibold'>Kandang Aktif</h2>
|
||||
{/* Badge Row */}
|
||||
<div className='flex flex-row gap-2'>
|
||||
<Badge
|
||||
variant='soft'
|
||||
color={'success'}
|
||||
className={{
|
||||
badge: 'rounded-lg px-2',
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
icon='mdi:circle'
|
||||
width={12}
|
||||
height={12}
|
||||
color={'success'}
|
||||
/>{' '}
|
||||
Kandang Aktif ({projectFlock.kandangs.length})
|
||||
</Badge>
|
||||
<div className='divider divider-horizontal p-0 m-0'></div>
|
||||
<Badge
|
||||
color='secondary'
|
||||
variant='soft'
|
||||
className={{ badge: 'rounded-lg px-2 cursor-pointer' }}
|
||||
onClick={() => {
|
||||
setOpenBudget(!openBudgets);
|
||||
}}
|
||||
>
|
||||
{` ${formatCurrency(
|
||||
projectFlock.project_budgets.reduce(
|
||||
(acc, curr) => acc + curr.price * curr.qty,
|
||||
0
|
||||
)
|
||||
)}`}
|
||||
<Icon
|
||||
icon={`mdi:${openBudgets ? 'eye' : 'eye-off'}`}
|
||||
width={12}
|
||||
height={12}
|
||||
/>
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Card List Project Budgets */}
|
||||
{openBudgets &&
|
||||
projectFlock.project_budgets.map((budget) => (
|
||||
<Card
|
||||
key={budget.id}
|
||||
variant='bordered'
|
||||
className={{
|
||||
wrapper: 'w-full',
|
||||
body: 'p-3',
|
||||
}}
|
||||
>
|
||||
<div className='flex flex-col gap-6'>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<div className='flex flex-row gap-2 items-center text-gray-400'>
|
||||
<Icon icon={'mdi:tag'} width={14} height={14} />{' '}
|
||||
<span>Jenis Produk</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-500'>
|
||||
{budget.nonstock?.name}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<div className='flex flex-row gap-2 items-center text-gray-400'>
|
||||
<Icon icon={'mdi:tag'} width={14} height={14} />{' '}
|
||||
<span>Nama Satuan</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-500'>
|
||||
{budget.nonstock?.uom.name}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<div className='flex flex-row gap-2 items-center text-gray-400'>
|
||||
<Icon
|
||||
icon={'mdi:file-multiple'}
|
||||
width={14}
|
||||
height={14}
|
||||
/>{' '}
|
||||
<span>Jumlah Pembelian</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-500'>
|
||||
{formatNumber(budget.qty)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<div className='flex flex-row gap-2 items-center text-gray-400'>
|
||||
<Icon icon={'mdi:file'} width={14} height={14} />{' '}
|
||||
<span>Harga Satuan</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-500'>
|
||||
{formatCurrency(budget.price)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-row justify-between items-center'>
|
||||
<div className='flex flex-row gap-2 items-center text-gray-400'>
|
||||
<Icon icon={'mdi:calculator'} width={14} height={14} />{' '}
|
||||
<span>Total Harga</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-500'>
|
||||
{formatCurrency(budget.price * budget.qty)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
{/* Card Kandangs */}
|
||||
<Card
|
||||
variant='bordered'
|
||||
className={{
|
||||
wrapper: 'w-full',
|
||||
body: 'p-3',
|
||||
}}
|
||||
>
|
||||
<div className='flex flex-col gap-6'>
|
||||
{projectFlock.kandangs.map((kandang) => (
|
||||
<div
|
||||
key={kandang.id}
|
||||
className='flex flex-row justify-between items-center'
|
||||
>
|
||||
<div className='flex flex-row gap-2 items-center cursor-pointer text-gray-400'>
|
||||
<Icon icon={'mdi:drag'} width={21} height={21} />{' '}
|
||||
<span className='font-semibold'>{kandang.name}</span>
|
||||
</div>
|
||||
<div className='text-end text-gray-400'>
|
||||
Created On{' '}
|
||||
{formatDate(projectFlock.created_at, 'MMM DD, YYYY')}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectFlockDetail;
|
||||
@@ -29,6 +29,14 @@ export const formatNumber = (
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
export const formatTitleCase = (value: string) => {
|
||||
return value
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
export function formatVechicleNumber(value: string): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < (value?.length ?? 0); i++) {
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ export type BaseProjectFlock = {
|
||||
kandangs: (Kandang & {
|
||||
project_flock_kandang_id: number;
|
||||
})[];
|
||||
project_budgets: ProjectFlockBudget[];
|
||||
approval: BaseApproval;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user