mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-337): init slicing UI and define data types
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
const FinanceAddInitialBalance = () => {
|
||||||
|
return <div>Initial Balance</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceAddInitialBalance;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const FinanceAdd = () => {
|
||||||
|
return <div>Finance Add</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceAdd;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const FinanceAdjust = () => {
|
||||||
|
return <div>Finance Adjust</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceAdjust;
|
||||||
@@ -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,41 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import FinanceDetail from '@/components/pages/finance/FinanceDetail';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
|
import { FinanceApi } from '@/services/api/finance';
|
||||||
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
|
||||||
|
const FinanceDetailPage = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
const financeId = useSearchParams().get('financeId');
|
||||||
|
|
||||||
|
const { data: finance } = useSWR(financeId, () =>
|
||||||
|
FinanceApi.getSingleFetcher(financeId as string)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!financeId) {
|
||||||
|
router.back();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-full flex flex-row justify-center items-center p-4'>
|
||||||
|
<span className='loading loading-spinner loading-xl' />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(finance);
|
||||||
|
|
||||||
|
// if (!finance || isResponseError(finance)) {
|
||||||
|
// router.replace('/404');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isResponseSuccess(finance) && <FinanceDetail finance={finance.data} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceDetailPage;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import FinanceTable from '@/components/pages/finance/FinanceTable';
|
||||||
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import { FinanceApi } from '@/services/api/finance';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
|
const Finance = () => {
|
||||||
|
const { data: finances, isLoading: isLoadingFinances } = useSWR(
|
||||||
|
`${FinanceApi.basePath}`,
|
||||||
|
() => FinanceApi.getAllFetcher()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoadingFinances) {
|
||||||
|
return (
|
||||||
|
<div className='w-full flex flex-row justify-center items-center p-4'>
|
||||||
|
<span className='loading loading-spinner loading-xl' />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className='size-full p-4'>
|
||||||
|
<h1>Finance</h1>
|
||||||
|
<FinanceTable
|
||||||
|
finances={isResponseSuccess(finances) ? finances.data : []}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Finance;
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
import Card from '@/components/Card';
|
||||||
|
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import { formatCurrency } from '@/lib/helper';
|
||||||
|
import { Finance, FinanceReferences } from '@/types/api/finance/finance';
|
||||||
|
|
||||||
|
const FinanceDetail = ({ finance }: { finance: Finance }) => {
|
||||||
|
const informasiUmum = [
|
||||||
|
{
|
||||||
|
label: 'ID',
|
||||||
|
value: finance.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Jenis Transaksi',
|
||||||
|
value: finance.transaction_type,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Pihak',
|
||||||
|
value: finance.transaction_owner.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Tanggal',
|
||||||
|
value: finance.transaction_date,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Metode Pembayaran',
|
||||||
|
value: finance.payment_method,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const informasiTransfer = [
|
||||||
|
{
|
||||||
|
label: 'No. Referensi',
|
||||||
|
value: finance.references_number,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Nomor Rekening',
|
||||||
|
value: `${finance.bank_account.alias} - ${finance.bank_account.account_number} - ${finance.bank_account.owner}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rekening Customer',
|
||||||
|
value: finance.transaction_account_number,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Nominal',
|
||||||
|
value: formatCurrency(finance.transaction_amount),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Sisa',
|
||||||
|
value: formatCurrency(finance.balance_amount),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col gap-4'>
|
||||||
|
<Card
|
||||||
|
title='Detail Keuangan'
|
||||||
|
className={{
|
||||||
|
wrapper: 'w-full',
|
||||||
|
}}
|
||||||
|
variant='bordered'
|
||||||
|
>
|
||||||
|
<div className='grid grid-cols-2 gap-4 mb-6'>
|
||||||
|
<Table
|
||||||
|
data={informasiUmum}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
header: '',
|
||||||
|
id: 'label',
|
||||||
|
accessorKey: 'label',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: '',
|
||||||
|
id: 'value',
|
||||||
|
accessorKey: 'value',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
className={{
|
||||||
|
headerRowClassName: 'hidden',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
containerClassName: 'mb-0',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table
|
||||||
|
data={informasiTransfer}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
header: '',
|
||||||
|
id: 'label',
|
||||||
|
accessorKey: 'label',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: '',
|
||||||
|
id: 'value',
|
||||||
|
accessorKey: 'value',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
className={{
|
||||||
|
headerRowClassName: 'hidden',
|
||||||
|
paginationClassName: 'hidden',
|
||||||
|
containerClassName: 'mb-0',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col gap-4'>
|
||||||
|
<div className='flex flex-row gap-4'>
|
||||||
|
<DebouncedTextInput
|
||||||
|
className={{
|
||||||
|
wrapper: 'max-w-1/4 ml-auto',
|
||||||
|
}}
|
||||||
|
name='cari'
|
||||||
|
placeholder='Cari'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Table<FinanceReferences>
|
||||||
|
data={finance.references}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
header: 'No.',
|
||||||
|
id: 'index',
|
||||||
|
accessorFn: (row, index) => index + 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'No. Referensi',
|
||||||
|
id: 'references_number',
|
||||||
|
accessorKey: 'references_number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Nominal',
|
||||||
|
id: 'nominal',
|
||||||
|
accessorFn: (row) =>
|
||||||
|
formatCurrency(Number(row.total_allocation)),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
className={{
|
||||||
|
containerClassName: 'mb-6',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceDetail;
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import Button from '@/components/Button';
|
||||||
|
import Dropdown from '@/components/dropdown/Dropdown';
|
||||||
|
import Menu from '@/components/menu/Menu';
|
||||||
|
import MenuItem from '@/components/menu/MenuItem';
|
||||||
|
import Table from '@/components/Table';
|
||||||
|
import Tooltip from '@/components/Tooltip';
|
||||||
|
import { formatCurrency, formatDate } from '@/lib/helper';
|
||||||
|
import { Finance } from '@/types/api/finance/finance';
|
||||||
|
import { Row } from '@tanstack/react-table';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
const FinanceTable = ({ finances }: { finances: Finance[] }) => {
|
||||||
|
const columns = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
header: 'ID',
|
||||||
|
accessorKey: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Alokasi',
|
||||||
|
accessorFn: (finance: Finance) => finance.references.length,
|
||||||
|
cell: ({ row }: { row: Row<Finance> }) => (
|
||||||
|
<Tooltip
|
||||||
|
content={row.original.references
|
||||||
|
.map((ref) => ref.references_number)
|
||||||
|
.join(', ')}
|
||||||
|
>
|
||||||
|
<span className='text-primary'>
|
||||||
|
{row.original.references.length}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'References Number',
|
||||||
|
accessorKey: 'references_number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Jenis Transaksi',
|
||||||
|
accessorKey: 'transaction_type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Pihak',
|
||||||
|
accessorFn: (finance: Finance) => finance.transaction_owner.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Tanggal',
|
||||||
|
accessorFn: (finance: Finance) =>
|
||||||
|
formatDate(finance.transaction_date, 'DD MMM YYYY'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Metode Pembayaran',
|
||||||
|
accessorKey: 'payment_method',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Bank',
|
||||||
|
accessorFn: (finance: Finance) =>
|
||||||
|
`${finance.bank_account.alias} - ${finance.bank_account.account_number} - ${finance.bank_account.owner}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Pengeluaran (Rp)',
|
||||||
|
accessorFn: (finance: Finance) =>
|
||||||
|
formatCurrency(finance.balance_amount),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Pemasukan (Rp)',
|
||||||
|
accessorFn: (finance: Finance) =>
|
||||||
|
formatCurrency(finance.transaction_amount),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: 'Aksi',
|
||||||
|
cell: ({ row }: { row: Row<Finance> }) => (
|
||||||
|
<Dropdown
|
||||||
|
trigger={<Button variant='ghost'>...</Button>}
|
||||||
|
direction='bottom'
|
||||||
|
align='end'
|
||||||
|
>
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
title='Detail'
|
||||||
|
href={`/finance/detail?financeId=${row.original.id}`}
|
||||||
|
className='hover:bg-primary hover:text-primary-content'
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
</Dropdown>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<section className='size-full p-4'>
|
||||||
|
<Table<Finance> data={finances} columns={columns} />
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceTable;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const FinanceAdjust = () => {
|
||||||
|
return <div>Finance Adjust</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FinanceAdjust;
|
||||||
@@ -35,6 +35,11 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [
|
|||||||
link: '/marketing',
|
link: '/marketing',
|
||||||
icon: 'heroicons-outline:currency-dollar',
|
icon: 'heroicons-outline:currency-dollar',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Keuangan',
|
||||||
|
link: '/finance',
|
||||||
|
icon: 'heroicons-outline:banknotes',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: 'Biaya Operasional',
|
text: 'Biaya Operasional',
|
||||||
link: '/expense',
|
link: '/expense',
|
||||||
@@ -60,7 +65,6 @@ export const MAIN_DRAWER_LINKS: SidebarMenuItem[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
text: 'Persediaan',
|
text: 'Persediaan',
|
||||||
link: '/inventory',
|
link: '/inventory',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Dummy data for Finance[]
|
||||||
|
* Generated from: finance.json
|
||||||
|
*
|
||||||
|
* This file is auto-generated. Do not edit manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
FinanceBankAccount,
|
||||||
|
FinanceTransactionOwner,
|
||||||
|
FinanceReferences,
|
||||||
|
Finance,
|
||||||
|
} from '../../types/api/finance/finance';
|
||||||
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
import dummyData from './finance.dummy.json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get dummy Finance[] data
|
||||||
|
* @returns Promise with BaseApiResponse containing Finance[]
|
||||||
|
*/
|
||||||
|
export async function getAllDummyFinance(): Promise<
|
||||||
|
BaseApiResponse<Finance[]>
|
||||||
|
> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
code: 200,
|
||||||
|
status: 'success',
|
||||||
|
message: 'Data retrieved successfully',
|
||||||
|
data: dummyData as unknown as Finance[],
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSingleDummyFinance(
|
||||||
|
id: string
|
||||||
|
): Promise<BaseApiResponse<Finance>> {
|
||||||
|
console.log(dummyData as unknown as Finance[]);
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
code: 200,
|
||||||
|
status: 'success',
|
||||||
|
message: 'Data retrieved successfully',
|
||||||
|
data: (dummyData as unknown as Finance[]).find(
|
||||||
|
(finance) => finance.id === id
|
||||||
|
) as Finance,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { BaseApiService } from '@/services/api/base';
|
||||||
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
import { httpClient } from '@/services/http/client';
|
||||||
|
import { Finance } from '@/types/api/finance/finance';
|
||||||
|
// DUMMY_START
|
||||||
|
import {
|
||||||
|
getAllDummyFinance,
|
||||||
|
getSingleDummyFinance,
|
||||||
|
} from '@/dummy/finance/finance.dummy';
|
||||||
|
// DUMMY_END
|
||||||
|
|
||||||
|
export class FinanceApiService extends BaseApiService<
|
||||||
|
Finance,
|
||||||
|
unknown,
|
||||||
|
unknown
|
||||||
|
> {
|
||||||
|
constructor(basePath: string) {
|
||||||
|
super(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllFetcher(): Promise<BaseApiResponse<Finance[]>> {
|
||||||
|
// DUMMY_START
|
||||||
|
return await getAllDummyFinance();
|
||||||
|
// DUMMY_END
|
||||||
|
|
||||||
|
// LIVE_START
|
||||||
|
// try {
|
||||||
|
// const path = `${this.basePath}/`;
|
||||||
|
// return await httpClient<BaseApiResponse<Finance[]>>(path);
|
||||||
|
// } catch (error) {
|
||||||
|
// if (axios.isAxiosError<BaseApiResponse<Finance[]>>(error)) {
|
||||||
|
// return error.response?.data;
|
||||||
|
// }
|
||||||
|
// return undefined;
|
||||||
|
// }
|
||||||
|
// LIVE_END
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSingleFetcher(id: string): Promise<BaseApiResponse<Finance>> {
|
||||||
|
// DUMMY_START
|
||||||
|
console.log(id);
|
||||||
|
return await getSingleDummyFinance(id);
|
||||||
|
// DUMMY_END
|
||||||
|
|
||||||
|
// LIVE_START
|
||||||
|
// try {
|
||||||
|
// const path = `${this.basePath}/`;
|
||||||
|
// return await httpClient<BaseApiResponse<Finance[]>>(path);
|
||||||
|
// } catch (error) {
|
||||||
|
// if (axios.isAxiosError<BaseApiResponse<Finance[]>>(error)) {
|
||||||
|
// return error.response?.data;
|
||||||
|
// }
|
||||||
|
// return undefined;
|
||||||
|
// }
|
||||||
|
// LIVE_END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FinanceApi = new FinanceApiService('/finances');
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
export interface Finance {
|
||||||
|
id: string;
|
||||||
|
references_number: string;
|
||||||
|
bank_account: FinanceBankAccount;
|
||||||
|
transaction_type: string;
|
||||||
|
transaction_owner: FinanceTransactionOwner;
|
||||||
|
transaction_account_number: string;
|
||||||
|
transaction_date: string;
|
||||||
|
payment_method: string;
|
||||||
|
transaction_amount: number;
|
||||||
|
balance_amount: number;
|
||||||
|
notes: string;
|
||||||
|
references: FinanceReferences[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FinanceReferences {
|
||||||
|
references_number: string;
|
||||||
|
total_allocation: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FinanceTransactionOwner {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FinanceBankAccount {
|
||||||
|
alias: string;
|
||||||
|
name: string;
|
||||||
|
account_number: string;
|
||||||
|
owner: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user