Compare commits
No commits in common. "2d69a024c1f5738b56b2e76784ff8bc39204bfd6" and "76ee71e7fed8e1a0de51cbe3bbe14fb7f460aed5" have entirely different histories.
2d69a024c1
...
76ee71e7fe
@ -1,36 +0,0 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
|
||||||
import { api } from '../api'
|
|
||||||
import { Accounts } from '@/types/services/chartOfAccount'
|
|
||||||
|
|
||||||
interface AccountQueryParams {
|
|
||||||
page?: number
|
|
||||||
limit?: number
|
|
||||||
search?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAccounts(params: AccountQueryParams = {}) {
|
|
||||||
const { page = 1, limit = 10, search = '', ...filters } = params
|
|
||||||
|
|
||||||
return useQuery<Accounts>({
|
|
||||||
queryKey: ['accounts', { page, limit, search, ...filters }],
|
|
||||||
queryFn: async () => {
|
|
||||||
const queryParams = new URLSearchParams()
|
|
||||||
|
|
||||||
queryParams.append('page', page.toString())
|
|
||||||
queryParams.append('limit', limit.toString())
|
|
||||||
|
|
||||||
if (search) {
|
|
||||||
queryParams.append('search', search)
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.entries(filters).forEach(([key, value]) => {
|
|
||||||
if (value !== undefined && value !== null && value !== '') {
|
|
||||||
queryParams.append(key, value.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await api.get(`/accounts?${queryParams.toString()}`)
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
|
||||||
import { api } from '../api'
|
|
||||||
import { ChartOfAccounts } from '@/types/services/chartOfAccount'
|
|
||||||
|
|
||||||
interface ChartOfAccountQueryParams {
|
|
||||||
page?: number
|
|
||||||
limit?: number
|
|
||||||
search?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useChartOfAccount(params: ChartOfAccountQueryParams = {}) {
|
|
||||||
const { page = 1, limit = 10, search = '', ...filters } = params
|
|
||||||
|
|
||||||
return useQuery<ChartOfAccounts>({
|
|
||||||
queryKey: ['chart-of-accounts', { page, limit, search, ...filters }],
|
|
||||||
queryFn: async () => {
|
|
||||||
const queryParams = new URLSearchParams()
|
|
||||||
|
|
||||||
queryParams.append('page', page.toString())
|
|
||||||
queryParams.append('limit', limit.toString())
|
|
||||||
|
|
||||||
if (search) {
|
|
||||||
queryParams.append('search', search)
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.entries(filters).forEach(([key, value]) => {
|
|
||||||
if (value !== undefined && value !== null && value !== '') {
|
|
||||||
queryParams.append(key, value.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await api.get(`/chart-of-accounts?${queryParams.toString()}`)
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
import { ChartOfAccountTypes } from '@/types/services/chartOfAccount'
|
|
||||||
import { useQuery } from '@tanstack/react-query'
|
|
||||||
import { api } from '../api'
|
|
||||||
|
|
||||||
interface ChartOfAccountQueryParams {
|
|
||||||
page?: number
|
|
||||||
limit?: number
|
|
||||||
search?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useChartOfAccountTypes(params: ChartOfAccountQueryParams = {}) {
|
|
||||||
const { page = 1, limit = 10, search = '', ...filters } = params
|
|
||||||
|
|
||||||
return useQuery<ChartOfAccountTypes>({
|
|
||||||
queryKey: ['chart-of-account-types', { page, limit, search, ...filters }],
|
|
||||||
queryFn: async () => {
|
|
||||||
const queryParams = new URLSearchParams()
|
|
||||||
|
|
||||||
queryParams.append('page', page.toString())
|
|
||||||
queryParams.append('limit', limit.toString())
|
|
||||||
|
|
||||||
if (search) {
|
|
||||||
queryParams.append('search', search)
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.entries(filters).forEach(([key, value]) => {
|
|
||||||
if (value !== undefined && value !== null && value !== '') {
|
|
||||||
queryParams.append(key, value.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await api.get(`/chart-of-account-types?${queryParams.toString()}`)
|
|
||||||
return res.data.data
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
export interface ChartOfAccountType {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
code: string
|
|
||||||
description: string
|
|
||||||
is_active: boolean
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChartOfAccountTypes {
|
|
||||||
data: ChartOfAccountType[]
|
|
||||||
limit: number
|
|
||||||
page: number
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChartOfAccount {
|
|
||||||
id: string
|
|
||||||
organization_id: string
|
|
||||||
outlet_id: string
|
|
||||||
chart_of_account_type_id: string
|
|
||||||
parent_id: string
|
|
||||||
name: string
|
|
||||||
code: string
|
|
||||||
description: string
|
|
||||||
is_active: boolean
|
|
||||||
is_system: boolean
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
chart_of_account_type: ChartOfAccountType
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChartOfAccounts {
|
|
||||||
data: ChartOfAccount[]
|
|
||||||
limit: number
|
|
||||||
page: number
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Account {
|
|
||||||
id: string
|
|
||||||
organization_id: string
|
|
||||||
outlet_id: string
|
|
||||||
chart_of_account_id: string
|
|
||||||
name: string
|
|
||||||
number: string
|
|
||||||
account_type: string
|
|
||||||
opening_balance: number
|
|
||||||
current_balance: number
|
|
||||||
description: string
|
|
||||||
is_active: true
|
|
||||||
is_system: false
|
|
||||||
created_at: string
|
|
||||||
updated_at: string
|
|
||||||
chart_of_account: ChartOfAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Accounts {
|
|
||||||
data: Account[]
|
|
||||||
limit: number
|
|
||||||
page: number
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
@ -5,6 +5,7 @@ import { useState, useEffect } from 'react'
|
|||||||
import Button from '@mui/material/Button'
|
import Button from '@mui/material/Button'
|
||||||
import Drawer from '@mui/material/Drawer'
|
import Drawer from '@mui/material/Drawer'
|
||||||
import IconButton from '@mui/material/IconButton'
|
import IconButton from '@mui/material/IconButton'
|
||||||
|
import MenuItem from '@mui/material/MenuItem'
|
||||||
import Typography from '@mui/material/Typography'
|
import Typography from '@mui/material/Typography'
|
||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
|
|
||||||
@ -14,8 +15,6 @@ import { useForm, Controller } from 'react-hook-form'
|
|||||||
// Component Imports
|
// Component Imports
|
||||||
import CustomTextField from '@core/components/mui/TextField'
|
import CustomTextField from '@core/components/mui/TextField'
|
||||||
import CustomAutocomplete from '@/@core/components/mui/Autocomplete'
|
import CustomAutocomplete from '@/@core/components/mui/Autocomplete'
|
||||||
import { useChartOfAccountTypes } from '@/services/queries/chartOfAccountType'
|
|
||||||
import { useChartOfAccount } from '@/services/queries/chartOfAccount'
|
|
||||||
|
|
||||||
// Account Type
|
// Account Type
|
||||||
export type AccountType = {
|
export type AccountType = {
|
||||||
@ -41,6 +40,31 @@ type FormValidateType = {
|
|||||||
parentAccount?: string
|
parentAccount?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Categories available for accounts
|
||||||
|
const accountCategories = [
|
||||||
|
'Kas & Bank',
|
||||||
|
'Piutang',
|
||||||
|
'Persediaan',
|
||||||
|
'Aset Tetap',
|
||||||
|
'Hutang',
|
||||||
|
'Ekuitas',
|
||||||
|
'Pendapatan',
|
||||||
|
'Beban'
|
||||||
|
]
|
||||||
|
|
||||||
|
// Parent accounts (dummy data for dropdown)
|
||||||
|
const parentAccounts = [
|
||||||
|
{ id: 1, code: '1-10001', name: 'Kas' },
|
||||||
|
{ id: 2, code: '1-10002', name: 'Bank BCA' },
|
||||||
|
{ id: 3, code: '1-10003', name: 'Bank Mandiri' },
|
||||||
|
{ id: 4, code: '1-10101', name: 'Piutang Usaha' },
|
||||||
|
{ id: 5, code: '1-10201', name: 'Persediaan Barang' },
|
||||||
|
{ id: 6, code: '2-20001', name: 'Hutang Usaha' },
|
||||||
|
{ id: 7, code: '3-30001', name: 'Modal Pemilik' },
|
||||||
|
{ id: 8, code: '4-40001', name: 'Penjualan' },
|
||||||
|
{ id: 9, code: '5-50001', name: 'Beban Gaji' }
|
||||||
|
]
|
||||||
|
|
||||||
// Vars
|
// Vars
|
||||||
const initialData = {
|
const initialData = {
|
||||||
name: '',
|
name: '',
|
||||||
@ -56,38 +80,6 @@ const AccountFormDrawer = (props: Props) => {
|
|||||||
// Determine if we're editing
|
// Determine if we're editing
|
||||||
const isEdit = !!editingAccount
|
const isEdit = !!editingAccount
|
||||||
|
|
||||||
const { data: accountTypes, isLoading } = useChartOfAccountTypes()
|
|
||||||
|
|
||||||
const { data: accounts, isLoading: isLoadingAccounts } = useChartOfAccount({
|
|
||||||
page: 1,
|
|
||||||
limit: 100
|
|
||||||
})
|
|
||||||
|
|
||||||
// Process account types for the dropdown
|
|
||||||
const categoryOptions = accountTypes?.data.length
|
|
||||||
? accountTypes.data
|
|
||||||
.filter(type => type.is_active) // Only show active types
|
|
||||||
.map(type => ({
|
|
||||||
id: type.id,
|
|
||||||
name: type.name,
|
|
||||||
code: type.code,
|
|
||||||
description: type.description
|
|
||||||
}))
|
|
||||||
: []
|
|
||||||
|
|
||||||
// Process accounts for parent account dropdown
|
|
||||||
const parentAccountOptions = accounts?.data.length
|
|
||||||
? accounts.data
|
|
||||||
.filter(account => account.is_active) // Only show active accounts
|
|
||||||
.filter(account => (editingAccount ? account.id !== editingAccount.id.toString() : true)) // Exclude current account when editing
|
|
||||||
.map(account => ({
|
|
||||||
id: account.id,
|
|
||||||
code: account.code,
|
|
||||||
name: account.name,
|
|
||||||
description: account.description
|
|
||||||
}))
|
|
||||||
: []
|
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -245,29 +237,17 @@ const AccountFormDrawer = (props: Props) => {
|
|||||||
render={({ field: { onChange, value, ...field } }) => (
|
render={({ field: { onChange, value, ...field } }) => (
|
||||||
<CustomAutocomplete
|
<CustomAutocomplete
|
||||||
{...field}
|
{...field}
|
||||||
loading={isLoading}
|
options={accountCategories}
|
||||||
options={categoryOptions}
|
value={value || null}
|
||||||
value={categoryOptions.find(option => option.name === value) || null}
|
onChange={(_, newValue) => onChange(newValue || '')}
|
||||||
onChange={(_, newValue) => onChange(newValue?.name || '')}
|
|
||||||
getOptionLabel={option => option.name}
|
|
||||||
renderOption={(props, option) => (
|
|
||||||
<Box component='li' {...props}>
|
|
||||||
<div>
|
|
||||||
<Typography variant='body2'>
|
|
||||||
{option.code} - {option.name}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
renderInput={params => (
|
renderInput={params => (
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
{...params}
|
{...params}
|
||||||
placeholder={isLoading ? 'Loading categories...' : 'Pilih kategori'}
|
placeholder='Pilih kategori'
|
||||||
{...(errors.category && { error: true, helperText: 'Field ini wajib diisi.' })}
|
{...(errors.category && { error: true, helperText: 'Field ini wajib diisi.' })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
isOptionEqualToValue={(option, value) => option.name === value.name}
|
isOptionEqualToValue={(option, value) => option === value}
|
||||||
disabled={isLoading}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -284,36 +264,14 @@ const AccountFormDrawer = (props: Props) => {
|
|||||||
render={({ field: { onChange, value, ...field } }) => (
|
render={({ field: { onChange, value, ...field } }) => (
|
||||||
<CustomAutocomplete
|
<CustomAutocomplete
|
||||||
{...field}
|
{...field}
|
||||||
loading={isLoadingAccounts}
|
options={parentAccounts}
|
||||||
options={parentAccountOptions}
|
value={parentAccounts.find(account => `${account.code} ${account.name}` === value) || null}
|
||||||
value={parentAccountOptions.find(account => `${account.code} ${account.name}` === value) || null}
|
|
||||||
onChange={(_, newValue) => onChange(newValue ? `${newValue.code} ${newValue.name}` : '')}
|
onChange={(_, newValue) => onChange(newValue ? `${newValue.code} ${newValue.name}` : '')}
|
||||||
getOptionLabel={option => `${option.code} - ${option.name}`}
|
getOptionLabel={option => `${option.code} ${option.name}`}
|
||||||
renderOption={(props, option) => (
|
renderInput={params => <CustomTextField {...params} placeholder='Pilih akun' />}
|
||||||
<Box component='li' {...props}>
|
|
||||||
<div>
|
|
||||||
<Typography variant='body2'>
|
|
||||||
{option.code} - {option.name}
|
|
||||||
</Typography>
|
|
||||||
{option.description && (
|
|
||||||
<Typography variant='caption' color='textSecondary'>
|
|
||||||
{option.description}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
renderInput={params => (
|
|
||||||
<CustomTextField
|
|
||||||
{...params}
|
|
||||||
placeholder={isLoadingAccounts ? 'Loading accounts...' : 'Pilih akun parent'}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
isOptionEqualToValue={(option, value) =>
|
isOptionEqualToValue={(option, value) =>
|
||||||
`${option.code} ${option.name}` === `${value.code} ${value.name}`
|
`${option.code} ${option.name}` === `${value.code} ${value.name}`
|
||||||
}
|
}
|
||||||
disabled={isLoadingAccounts}
|
|
||||||
noOptionsText={isLoadingAccounts ? 'Loading...' : 'Tidak ada akun tersedia'}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -41,11 +41,6 @@ import TablePaginationComponent from '@/components/TablePaginationComponent'
|
|||||||
import Loading from '@/components/layout/shared/Loading'
|
import Loading from '@/components/layout/shared/Loading'
|
||||||
import { getLocalizedUrl } from '@/utils/i18n'
|
import { getLocalizedUrl } from '@/utils/i18n'
|
||||||
import AccountFormDrawer from './AccountFormDrawer'
|
import AccountFormDrawer from './AccountFormDrawer'
|
||||||
import { useChartOfAccount } from '@/services/queries/chartOfAccount'
|
|
||||||
import { Account, ChartOfAccount } from '@/types/services/chartOfAccount'
|
|
||||||
import { useAccounts } from '@/services/queries/account'
|
|
||||||
import { formatCurrency } from '@/utils/transform'
|
|
||||||
import { useChartOfAccountTypes } from '@/services/queries/chartOfAccountType'
|
|
||||||
|
|
||||||
// Account Type
|
// Account Type
|
||||||
export type AccountType = {
|
export type AccountType = {
|
||||||
@ -65,10 +60,119 @@ declare module '@tanstack/table-core' {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountTypeWithAction = Account & {
|
type AccountTypeWithAction = AccountType & {
|
||||||
actions?: string
|
actions?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dummy Account Data
|
||||||
|
export const accountsData: AccountType[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
code: '1-10001',
|
||||||
|
name: 'Kas',
|
||||||
|
category: 'Kas & Bank',
|
||||||
|
balance: '20000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
code: '1-10002',
|
||||||
|
name: 'Bank BCA',
|
||||||
|
category: 'Kas & Bank',
|
||||||
|
balance: '150000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
code: '1-10003',
|
||||||
|
name: 'Bank Mandiri',
|
||||||
|
category: 'Kas & Bank',
|
||||||
|
balance: '75000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
code: '1-10101',
|
||||||
|
name: 'Piutang Usaha',
|
||||||
|
category: 'Piutang',
|
||||||
|
balance: '50000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
code: '1-10102',
|
||||||
|
name: 'Piutang Karyawan',
|
||||||
|
category: 'Piutang',
|
||||||
|
balance: '5000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
code: '1-10201',
|
||||||
|
name: 'Persediaan Barang',
|
||||||
|
category: 'Persediaan',
|
||||||
|
balance: '100000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
code: '1-10301',
|
||||||
|
name: 'Peralatan Kantor',
|
||||||
|
category: 'Aset Tetap',
|
||||||
|
balance: '25000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
code: '1-10302',
|
||||||
|
name: 'Kendaraan',
|
||||||
|
category: 'Aset Tetap',
|
||||||
|
balance: '200000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
code: '2-20001',
|
||||||
|
name: 'Hutang Usaha',
|
||||||
|
category: 'Hutang',
|
||||||
|
balance: '-30000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
code: '2-20002',
|
||||||
|
name: 'Hutang Gaji',
|
||||||
|
category: 'Hutang',
|
||||||
|
balance: '-15000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
code: '3-30001',
|
||||||
|
name: 'Modal Pemilik',
|
||||||
|
category: 'Ekuitas',
|
||||||
|
balance: '500000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
code: '4-40001',
|
||||||
|
name: 'Penjualan',
|
||||||
|
category: 'Pendapatan',
|
||||||
|
balance: '250000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 13,
|
||||||
|
code: '5-50001',
|
||||||
|
name: 'Beban Gaji',
|
||||||
|
category: 'Beban',
|
||||||
|
balance: '-80000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
code: '5-50002',
|
||||||
|
name: 'Beban Listrik',
|
||||||
|
category: 'Beban',
|
||||||
|
balance: '-5000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 15,
|
||||||
|
code: '5-50003',
|
||||||
|
name: 'Beban Telepon',
|
||||||
|
category: 'Beban',
|
||||||
|
balance: '-2000000'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
// Styled Components
|
// Styled Components
|
||||||
const Icon = styled('i')({})
|
const Icon = styled('i')({})
|
||||||
|
|
||||||
@ -138,6 +242,16 @@ const getCategoryColor = (category: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format currency
|
||||||
|
const formatCurrency = (amount: string) => {
|
||||||
|
const numAmount = parseInt(amount)
|
||||||
|
return new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(Math.abs(numAmount))
|
||||||
|
}
|
||||||
|
|
||||||
// Column Definitions
|
// Column Definitions
|
||||||
const columnHelper = createColumnHelper<AccountTypeWithAction>()
|
const columnHelper = createColumnHelper<AccountTypeWithAction>()
|
||||||
|
|
||||||
@ -147,25 +261,53 @@ const AccountListTable = () => {
|
|||||||
// States
|
// States
|
||||||
const [addAccountOpen, setAddAccountOpen] = useState(false)
|
const [addAccountOpen, setAddAccountOpen] = useState(false)
|
||||||
const [rowSelection, setRowSelection] = useState({})
|
const [rowSelection, setRowSelection] = useState({})
|
||||||
const [currentPage, setCurrentPage] = useState(1)
|
const [currentPage, setCurrentPage] = useState(0)
|
||||||
const [pageSize, setPageSize] = useState(10)
|
const [pageSize, setPageSize] = useState(10)
|
||||||
const [openConfirm, setOpenConfirm] = useState(false)
|
const [openConfirm, setOpenConfirm] = useState(false)
|
||||||
const [accountId, setAccountId] = useState('')
|
const [accountId, setAccountId] = useState('')
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const [categoryFilter, setCategoryFilter] = useState<string>('Semua')
|
const [categoryFilter, setCategoryFilter] = useState<string>('Semua')
|
||||||
const [editingAccount, setEditingAccount] = useState<Account | null>(null)
|
const [filteredData, setFilteredData] = useState<AccountType[]>(accountsData)
|
||||||
|
const [data, setData] = useState<AccountType[]>(accountsData)
|
||||||
const { data, isLoading } = useAccounts({
|
const [editingAccount, setEditingAccount] = useState<AccountType | null>(null)
|
||||||
page: currentPage,
|
|
||||||
limit: pageSize,
|
|
||||||
search
|
|
||||||
})
|
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
const { lang: locale } = useParams()
|
const { lang: locale } = useParams()
|
||||||
|
|
||||||
const accounts = data?.data ?? []
|
// Get unique categories for filter
|
||||||
const totalCount = data?.total ?? 0
|
const categories = useMemo(() => {
|
||||||
|
const uniqueCategories = [...new Set(data.map(account => account.category))]
|
||||||
|
return ['Semua', ...uniqueCategories]
|
||||||
|
}, [data])
|
||||||
|
|
||||||
|
// Filter data based on search and category
|
||||||
|
useEffect(() => {
|
||||||
|
let filtered = data
|
||||||
|
|
||||||
|
// Filter by search
|
||||||
|
if (search) {
|
||||||
|
filtered = filtered.filter(
|
||||||
|
account =>
|
||||||
|
account.code.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
|
account.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
|
account.category.toLowerCase().includes(search.toLowerCase())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by category
|
||||||
|
if (categoryFilter !== 'Semua') {
|
||||||
|
filtered = filtered.filter(account => account.category === categoryFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilteredData(filtered)
|
||||||
|
setCurrentPage(0)
|
||||||
|
}, [search, categoryFilter, data])
|
||||||
|
|
||||||
|
const totalCount = filteredData.length
|
||||||
|
const paginatedData = useMemo(() => {
|
||||||
|
const startIndex = currentPage * pageSize
|
||||||
|
return filteredData.slice(startIndex, startIndex + pageSize)
|
||||||
|
}, [filteredData, currentPage, pageSize])
|
||||||
|
|
||||||
const handlePageChange = useCallback((event: unknown, newPage: number) => {
|
const handlePageChange = useCallback((event: unknown, newPage: number) => {
|
||||||
setCurrentPage(newPage)
|
setCurrentPage(newPage)
|
||||||
@ -177,8 +319,12 @@ const AccountListTable = () => {
|
|||||||
setCurrentPage(0)
|
setCurrentPage(0)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
setOpenConfirm(false)
|
||||||
|
}
|
||||||
|
|
||||||
// Handle row click for edit
|
// Handle row click for edit
|
||||||
const handleRowClick = (account: Account, event: React.MouseEvent) => {
|
const handleRowClick = (account: AccountType, event: React.MouseEvent) => {
|
||||||
// Don't trigger row click if clicking on checkbox or link
|
// Don't trigger row click if clicking on checkbox or link
|
||||||
const target = event.target as HTMLElement
|
const target = event.target as HTMLElement
|
||||||
if (target.closest('input[type="checkbox"]') || target.closest('a') || target.closest('button')) {
|
if (target.closest('input[type="checkbox"]') || target.closest('a') || target.closest('button')) {
|
||||||
@ -219,7 +365,7 @@ const AccountListTable = () => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
columnHelper.accessor('number', {
|
columnHelper.accessor('code', {
|
||||||
header: 'Kode Akun',
|
header: 'Kode Akun',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<Button
|
<Button
|
||||||
@ -235,7 +381,7 @@ const AccountListTable = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{row.original.number}
|
{row.original.code}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
@ -247,21 +393,26 @@ const AccountListTable = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('chart_of_account.name', {
|
columnHelper.accessor('category', {
|
||||||
header: 'Kategori',
|
header: 'Kategori',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<Typography color='text.primary' className='font-medium'>
|
<Chip
|
||||||
{row.original.chart_of_account.name}
|
variant='tonal'
|
||||||
</Typography>
|
label={row.original.category}
|
||||||
|
size='small'
|
||||||
|
color={getCategoryColor(row.original.category) as any}
|
||||||
|
className='capitalize'
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('current_balance', {
|
columnHelper.accessor('balance', {
|
||||||
header: 'Saldo',
|
header: 'Saldo',
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
|
const balance = parseInt(row.original.balance)
|
||||||
return (
|
return (
|
||||||
<Typography className='font-medium text-right text-primary'>
|
<Typography className='font-medium text-right text-primary'>
|
||||||
{row.original.current_balance < 0 ? '-' : ''}
|
{balance < 0 ? '-' : ''}
|
||||||
{formatCurrency(row.original.current_balance)}
|
{formatCurrency(row.original.balance)}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -271,7 +422,7 @@ const AccountListTable = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: accounts as Account[],
|
data: paginatedData as AccountType[],
|
||||||
columns,
|
columns,
|
||||||
filterFns: {
|
filterFns: {
|
||||||
fuzzy: fuzzyFilter
|
fuzzy: fuzzyFilter
|
||||||
@ -361,7 +512,7 @@ const AccountListTable = () => {
|
|||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</thead>
|
</thead>
|
||||||
{accounts.length === 0 ? (
|
{filteredData.length === 0 ? (
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
|
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
|
||||||
@ -407,16 +558,15 @@ const AccountListTable = () => {
|
|||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onRowsPerPageChange={handlePageSizeChange}
|
onRowsPerPageChange={handlePageSizeChange}
|
||||||
rowsPerPageOptions={[10, 25, 50]}
|
rowsPerPageOptions={[10, 25, 50]}
|
||||||
disabled={isLoading}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
{/* <AccountFormDrawer
|
<AccountFormDrawer
|
||||||
open={addAccountOpen}
|
open={addAccountOpen}
|
||||||
handleClose={handleCloseDrawer}
|
handleClose={handleCloseDrawer}
|
||||||
accountData={data}
|
accountData={data}
|
||||||
setData={setData}
|
setData={setData}
|
||||||
editingAccount={editingAccount}
|
editingAccount={editingAccount}
|
||||||
/> */}
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user