efril #7
36
src/services/queries/account.ts
Normal file
36
src/services/queries/account.ts
Normal file
@ -0,0 +1,36 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -37,3 +37,28 @@ export interface ChartOfAccounts {
|
||||
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
|
||||
}
|
||||
|
||||
@ -41,6 +41,11 @@ import TablePaginationComponent from '@/components/TablePaginationComponent'
|
||||
import Loading from '@/components/layout/shared/Loading'
|
||||
import { getLocalizedUrl } from '@/utils/i18n'
|
||||
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
|
||||
export type AccountType = {
|
||||
@ -60,119 +65,10 @@ declare module '@tanstack/table-core' {
|
||||
}
|
||||
}
|
||||
|
||||
type AccountTypeWithAction = AccountType & {
|
||||
type AccountTypeWithAction = Account & {
|
||||
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
|
||||
const Icon = styled('i')({})
|
||||
|
||||
@ -242,16 +138,6 @@ 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
|
||||
const columnHelper = createColumnHelper<AccountTypeWithAction>()
|
||||
|
||||
@ -261,53 +147,25 @@ const AccountListTable = () => {
|
||||
// States
|
||||
const [addAccountOpen, setAddAccountOpen] = useState(false)
|
||||
const [rowSelection, setRowSelection] = useState({})
|
||||
const [currentPage, setCurrentPage] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(10)
|
||||
const [openConfirm, setOpenConfirm] = useState(false)
|
||||
const [accountId, setAccountId] = useState('')
|
||||
const [search, setSearch] = useState('')
|
||||
const [categoryFilter, setCategoryFilter] = useState<string>('Semua')
|
||||
const [filteredData, setFilteredData] = useState<AccountType[]>(accountsData)
|
||||
const [data, setData] = useState<AccountType[]>(accountsData)
|
||||
const [editingAccount, setEditingAccount] = useState<AccountType | null>(null)
|
||||
const [editingAccount, setEditingAccount] = useState<Account | null>(null)
|
||||
|
||||
const { data, isLoading } = useAccounts({
|
||||
page: currentPage,
|
||||
limit: pageSize,
|
||||
search
|
||||
})
|
||||
|
||||
// Hooks
|
||||
const { lang: locale } = useParams()
|
||||
|
||||
// Get unique categories for filter
|
||||
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 accounts = data?.data ?? []
|
||||
const totalCount = data?.total ?? 0
|
||||
|
||||
const handlePageChange = useCallback((event: unknown, newPage: number) => {
|
||||
setCurrentPage(newPage)
|
||||
@ -319,12 +177,8 @@ const AccountListTable = () => {
|
||||
setCurrentPage(0)
|
||||
}, [])
|
||||
|
||||
const handleDelete = () => {
|
||||
setOpenConfirm(false)
|
||||
}
|
||||
|
||||
// Handle row click for edit
|
||||
const handleRowClick = (account: AccountType, event: React.MouseEvent) => {
|
||||
const handleRowClick = (account: Account, event: React.MouseEvent) => {
|
||||
// Don't trigger row click if clicking on checkbox or link
|
||||
const target = event.target as HTMLElement
|
||||
if (target.closest('input[type="checkbox"]') || target.closest('a') || target.closest('button')) {
|
||||
@ -365,7 +219,7 @@ const AccountListTable = () => {
|
||||
/>
|
||||
)
|
||||
},
|
||||
columnHelper.accessor('code', {
|
||||
columnHelper.accessor('number', {
|
||||
header: 'Kode Akun',
|
||||
cell: ({ row }) => (
|
||||
<Button
|
||||
@ -381,7 +235,7 @@ const AccountListTable = () => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{row.original.code}
|
||||
{row.original.number}
|
||||
</Button>
|
||||
)
|
||||
}),
|
||||
@ -393,26 +247,21 @@ const AccountListTable = () => {
|
||||
</Typography>
|
||||
)
|
||||
}),
|
||||
columnHelper.accessor('category', {
|
||||
columnHelper.accessor('chart_of_account.name', {
|
||||
header: 'Kategori',
|
||||
cell: ({ row }) => (
|
||||
<Chip
|
||||
variant='tonal'
|
||||
label={row.original.category}
|
||||
size='small'
|
||||
color={getCategoryColor(row.original.category) as any}
|
||||
className='capitalize'
|
||||
/>
|
||||
<Typography color='text.primary' className='font-medium'>
|
||||
{row.original.chart_of_account.name}
|
||||
</Typography>
|
||||
)
|
||||
}),
|
||||
columnHelper.accessor('balance', {
|
||||
columnHelper.accessor('current_balance', {
|
||||
header: 'Saldo',
|
||||
cell: ({ row }) => {
|
||||
const balance = parseInt(row.original.balance)
|
||||
return (
|
||||
<Typography className='font-medium text-right text-primary'>
|
||||
{balance < 0 ? '-' : ''}
|
||||
{formatCurrency(row.original.balance)}
|
||||
{row.original.current_balance < 0 ? '-' : ''}
|
||||
{formatCurrency(row.original.current_balance)}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
@ -422,7 +271,7 @@ const AccountListTable = () => {
|
||||
)
|
||||
|
||||
const table = useReactTable({
|
||||
data: paginatedData as AccountType[],
|
||||
data: accounts as Account[],
|
||||
columns,
|
||||
filterFns: {
|
||||
fuzzy: fuzzyFilter
|
||||
@ -512,7 +361,7 @@ const AccountListTable = () => {
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
{filteredData.length === 0 ? (
|
||||
{accounts.length === 0 ? (
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
|
||||
@ -558,15 +407,16 @@ const AccountListTable = () => {
|
||||
onPageChange={handlePageChange}
|
||||
onRowsPerPageChange={handlePageSizeChange}
|
||||
rowsPerPageOptions={[10, 25, 50]}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</Card>
|
||||
<AccountFormDrawer
|
||||
{/* <AccountFormDrawer
|
||||
open={addAccountOpen}
|
||||
handleClose={handleCloseDrawer}
|
||||
accountData={data}
|
||||
setData={setData}
|
||||
editingAccount={editingAccount}
|
||||
/>
|
||||
/> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user