356 lines
10 KiB
TypeScript
356 lines
10 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useMemo, useEffect } from 'react'
|
|
import Grid from '@mui/material/Grid2'
|
|
import TextField, { TextFieldProps } from '@mui/material/TextField'
|
|
import InputAdornment from '@mui/material/InputAdornment'
|
|
import Box from '@mui/material/Box'
|
|
import Typography from '@mui/material/Typography'
|
|
import Chip from '@mui/material/Chip'
|
|
import FormControl from '@mui/material/FormControl'
|
|
import InputLabel from '@mui/material/InputLabel'
|
|
import Select from '@mui/material/Select'
|
|
import MenuItem from '@mui/material/MenuItem'
|
|
import CashBankCard from './CashBankCard' // Adjust import path as needed
|
|
import CustomTextField from '@/@core/components/mui/TextField'
|
|
import { getLocalizedUrl } from '@/utils/i18n'
|
|
import { Locale } from '@/configs/i18n'
|
|
import { useParams } from 'next/navigation'
|
|
import AccountFormDrawer, { AccountType } from '../account/AccountFormDrawer'
|
|
import { accountsData } from '../account/AccountListTable'
|
|
import { Button } from '@mui/material'
|
|
|
|
// Types
|
|
interface BankAccount {
|
|
id: string
|
|
title: string
|
|
accountNumber: string
|
|
balances: Array<{
|
|
amount: string | number
|
|
label: string
|
|
}>
|
|
chartData: Array<{
|
|
name: string
|
|
data: number[]
|
|
}>
|
|
categories: string[]
|
|
chartColor?: string
|
|
currency: 'IDR' | 'USD' | 'EUR'
|
|
accountType: 'giro' | 'savings' | 'investment' | 'credit' | 'cash'
|
|
bank: string
|
|
status: 'active' | 'inactive' | 'blocked'
|
|
}
|
|
|
|
// Dummy Data
|
|
const dummyAccounts: BankAccount[] = [
|
|
{
|
|
id: '1',
|
|
title: 'Giro',
|
|
accountNumber: '1-10003',
|
|
balances: [
|
|
{ amount: '7.313.321', label: 'Saldo di bank' },
|
|
{ amount: '30.631.261', label: 'Saldo di kledo' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Saldo',
|
|
data: [
|
|
20000000, 21000000, 20500000, 20800000, 21500000, 22000000, 25000000, 26000000, 28000000, 29000000, 30000000,
|
|
31000000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des', 'Jan', 'Feb', 'Mar'],
|
|
chartColor: '#ff6b9d',
|
|
currency: 'IDR',
|
|
accountType: 'giro',
|
|
bank: 'Bank Mandiri',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '2',
|
|
title: 'Tabungan Premium',
|
|
accountNumber: 'SAV-001234',
|
|
balances: [
|
|
{ amount: 15420000, label: 'Saldo Tersedia' },
|
|
{ amount: 18750000, label: 'Total Saldo' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Balance',
|
|
data: [
|
|
12000000, 13500000, 14200000, 15000000, 15800000, 16200000, 17000000, 17500000, 18000000, 18200000, 18500000,
|
|
18750000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'],
|
|
chartColor: '#4285f4',
|
|
currency: 'IDR',
|
|
accountType: 'savings',
|
|
bank: 'Bank BCA',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '3',
|
|
title: 'Investment Portfolio',
|
|
accountNumber: 'INV-789012',
|
|
balances: [
|
|
{ amount: 125000, label: 'Portfolio Value' },
|
|
{ amount: 8750, label: 'Total Gains' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Portfolio Value',
|
|
data: [110000, 115000, 112000, 118000, 122000, 119000, 125000, 128000, 126000, 130000, 127000, 125000]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
currency: 'USD',
|
|
accountType: 'investment',
|
|
bank: 'Charles Schwab',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '4',
|
|
title: 'Kartu Kredit Platinum',
|
|
accountNumber: 'CC-456789',
|
|
balances: [
|
|
{ amount: 2500000, label: 'Saldo Saat Ini' },
|
|
{ amount: 47500000, label: 'Limit Tersedia' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Spending',
|
|
data: [
|
|
1200000, 1800000, 2200000, 1900000, 2100000, 2400000, 2800000, 2600000, 2300000, 2500000, 2700000, 2500000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'],
|
|
currency: 'IDR',
|
|
accountType: 'credit',
|
|
bank: 'Bank BNI',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '5',
|
|
title: 'Deposito Berjangka',
|
|
accountNumber: 'DEP-334455',
|
|
balances: [
|
|
{ amount: 50000000, label: 'Pokok Deposito' },
|
|
{ amount: 2500000, label: 'Bunga Terkumpul' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Deposito Growth',
|
|
data: [
|
|
50000000, 50200000, 50420000, 50650000, 50880000, 51120000, 51360000, 51610000, 51860000, 52120000, 52380000,
|
|
52500000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'],
|
|
currency: 'IDR',
|
|
accountType: 'savings',
|
|
bank: 'Bank BRI',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '6',
|
|
title: 'Cash Management',
|
|
accountNumber: 'CSH-111222',
|
|
balances: [{ amount: 5000, label: 'Available Cash' }],
|
|
chartData: [
|
|
{
|
|
name: 'Cash Flow',
|
|
data: [4000, 4500, 4200, 4800, 5200, 4900, 5000, 5300, 5100, 5400, 5200, 5000]
|
|
}
|
|
],
|
|
categories: ['Q1', 'Q2', 'Q3', 'Q4', 'Q1', 'Q2', 'Q3', 'Q4', 'Q1', 'Q2', 'Q3', 'Q4'],
|
|
chartColor: '#00bcd4',
|
|
currency: 'USD',
|
|
accountType: 'cash',
|
|
bank: 'Wells Fargo',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '7',
|
|
title: 'Rekening Bisnis',
|
|
accountNumber: 'BIZ-998877',
|
|
balances: [
|
|
{ amount: 85000000, label: 'Saldo Operasional' },
|
|
{ amount: 15000000, label: 'Dana Cadangan' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Business Account',
|
|
data: [
|
|
70000000, 75000000, 80000000, 82000000, 85000000, 88000000, 90000000, 87000000, 85000000, 89000000, 92000000,
|
|
100000000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'],
|
|
chartColor: '#ff9800',
|
|
currency: 'IDR',
|
|
accountType: 'giro',
|
|
bank: 'Bank Mandiri',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: '8',
|
|
title: 'Tabungan Pendidikan',
|
|
accountNumber: 'EDU-567890',
|
|
balances: [
|
|
{ amount: 25000000, label: 'Dana Pendidikan' },
|
|
{ amount: 3500000, label: 'Bunga Terkumpul' }
|
|
],
|
|
chartData: [
|
|
{
|
|
name: 'Education Savings',
|
|
data: [
|
|
20000000, 21000000, 22000000, 23000000, 24000000, 24500000, 25000000, 25500000, 26000000, 27000000, 28000000,
|
|
28500000
|
|
]
|
|
}
|
|
],
|
|
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'],
|
|
chartColor: '#3f51b5',
|
|
currency: 'IDR',
|
|
accountType: 'savings',
|
|
bank: 'Bank BCA',
|
|
status: 'inactive'
|
|
}
|
|
]
|
|
const DebouncedInput = ({
|
|
value: initialValue,
|
|
onChange,
|
|
debounce = 500,
|
|
...props
|
|
}: {
|
|
value: string | number
|
|
onChange: (value: string | number) => void
|
|
debounce?: number
|
|
} & Omit<TextFieldProps, 'onChange'>) => {
|
|
// States
|
|
const [value, setValue] = useState(initialValue)
|
|
|
|
useEffect(() => {
|
|
setValue(initialValue)
|
|
}, [initialValue])
|
|
|
|
useEffect(() => {
|
|
const timeout = setTimeout(() => {
|
|
onChange(value)
|
|
}, debounce)
|
|
|
|
return () => clearTimeout(timeout)
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [value])
|
|
|
|
return <CustomTextField {...props} value={value} onChange={e => setValue(e.target.value)} />
|
|
}
|
|
const CashBankList = () => {
|
|
const [searchQuery, setSearchQuery] = useState('')
|
|
const [editingAccount, setEditingAccount] = useState<AccountType | null>(null)
|
|
const [addAccountOpen, setAddAccountOpen] = useState(false)
|
|
const [data, setData] = useState<AccountType[]>(accountsData)
|
|
const { lang: locale } = useParams()
|
|
|
|
const handleCloseDrawer = () => {
|
|
setAddAccountOpen(false)
|
|
setEditingAccount(null)
|
|
}
|
|
|
|
// Filter and search logic
|
|
const filteredAccounts = useMemo(() => {
|
|
return dummyAccounts.filter(account => {
|
|
const matchesSearch =
|
|
account.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
account.accountNumber.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
account.bank.toLowerCase().includes(searchQuery.toLowerCase())
|
|
return matchesSearch
|
|
})
|
|
}, [searchQuery])
|
|
|
|
return (
|
|
<>
|
|
<Box sx={{ p: 3 }}>
|
|
{/* Search and Filters */}
|
|
<Box sx={{ mb: 4 }}>
|
|
<div className='flex justify-between items-center'>
|
|
<DebouncedInput
|
|
value={searchQuery}
|
|
onChange={value => setSearchQuery(value as string)}
|
|
placeholder='Cari '
|
|
className='max-sm:is-full'
|
|
/>
|
|
<Box>
|
|
<Button
|
|
variant='contained'
|
|
className='max-sm:is-full is-auto'
|
|
startIcon={<i className='tabler-plus' />}
|
|
onClick={() => {
|
|
setEditingAccount(null)
|
|
setAddAccountOpen(true)
|
|
}}
|
|
>
|
|
Tambah Akun
|
|
</Button>
|
|
</Box>
|
|
</div>
|
|
</Box>
|
|
|
|
{/* Account Cards */}
|
|
<Grid container spacing={3}>
|
|
{filteredAccounts.length > 0 ? (
|
|
filteredAccounts.map(account => (
|
|
<Grid key={account.id} size={{ xs: 12, lg: 6, xl: 4 }}>
|
|
<CashBankCard
|
|
title={account.title}
|
|
accountNumber={account.accountNumber}
|
|
balances={account.balances}
|
|
chartData={account.chartData}
|
|
categories={account.categories}
|
|
chartColor={account.chartColor}
|
|
currency={account.currency}
|
|
showButton={account.accountType !== 'cash'}
|
|
href={getLocalizedUrl(`/apps/cash-bank/${account.accountNumber}/detail`, locale as Locale)}
|
|
/>
|
|
</Grid>
|
|
))
|
|
) : (
|
|
<Grid size={{ xs: 12 }}>
|
|
<Box
|
|
sx={{
|
|
textAlign: 'center',
|
|
py: 8,
|
|
backgroundColor: 'grey.50',
|
|
borderRadius: 2
|
|
}}
|
|
>
|
|
<Typography variant='h6' color='text.secondary' gutterBottom>
|
|
Tidak ada akun yang ditemukan
|
|
</Typography>
|
|
<Typography variant='body2' color='text.secondary'>
|
|
Coba ubah kata kunci pencarian atau filter yang digunakan
|
|
</Typography>
|
|
</Box>
|
|
</Grid>
|
|
)}
|
|
</Grid>
|
|
</Box>
|
|
<AccountFormDrawer
|
|
open={addAccountOpen}
|
|
handleClose={handleCloseDrawer}
|
|
accountData={data}
|
|
setData={setData}
|
|
editingAccount={editingAccount}
|
|
/>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default CashBankList
|