diff --git a/src/app/[lang]/(dashboard)/(private)/apps/cash-bank/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/cash-bank/page.tsx
new file mode 100644
index 0000000..b63c066
--- /dev/null
+++ b/src/app/[lang]/(dashboard)/(private)/apps/cash-bank/page.tsx
@@ -0,0 +1,7 @@
+import CashBankList from '@/views/apps/cash-bank/CashBankList'
+
+const CashBankPage = () => {
+ return
+}
+
+export default CashBankPage
diff --git a/src/components/layout/vertical/VerticalMenu.tsx b/src/components/layout/vertical/VerticalMenu.tsx
index 007da5d..e963920 100644
--- a/src/components/layout/vertical/VerticalMenu.tsx
+++ b/src/components/layout/vertical/VerticalMenu.tsx
@@ -116,6 +116,14 @@ const VerticalMenu = ({ dictionary, scrollMenu }: Props) => {
}>
+ }
+ exactMatch={false}
+ activeUrl='/apps/cash-bank'
+ >
+ {dictionary['navigation'].cash_and_bank}
+
}>
diff --git a/src/data/dictionaries/en.json b/src/data/dictionaries/en.json
index c9ab714..df083d2 100644
--- a/src/data/dictionaries/en.json
+++ b/src/data/dictionaries/en.json
@@ -123,6 +123,7 @@
"deliveries": "Deliveries",
"sales_orders": "Orders",
"quotes": "Quotes",
- "expenses": "Expenses"
+ "expenses": "Expenses",
+ "cash_and_bank": "Cash & Bank"
}
}
diff --git a/src/data/dictionaries/id.json b/src/data/dictionaries/id.json
index 5c4742b..53ddf6d 100644
--- a/src/data/dictionaries/id.json
+++ b/src/data/dictionaries/id.json
@@ -123,6 +123,7 @@
"deliveries": "Pengiriman",
"sales_orders": "Pemesanan",
"quotes": "Penawaran",
- "expenses": "Biaya"
+ "expenses": "Biaya",
+ "cash_and_bank": "Kas & Bank"
}
}
diff --git a/src/views/apps/cash-bank/CashBankCard.tsx b/src/views/apps/cash-bank/CashBankCard.tsx
new file mode 100644
index 0000000..94f1b10
--- /dev/null
+++ b/src/views/apps/cash-bank/CashBankCard.tsx
@@ -0,0 +1,263 @@
+'use client'
+
+// Next Imports
+import dynamic from 'next/dynamic'
+
+// MUI Imports
+import Card from '@mui/material/Card'
+import CardHeader from '@mui/material/CardHeader'
+import CardContent from '@mui/material/CardContent'
+import Typography from '@mui/material/Typography'
+import Box from '@mui/material/Box'
+import Button from '@mui/material/Button'
+
+// Third-party Imports
+import type { ApexOptions } from 'apexcharts'
+
+// Styled Component Imports
+const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts'))
+
+// Types
+interface Balance {
+ amount: string | number
+ label: string
+}
+
+interface ChartData {
+ name: string
+ data: number[]
+}
+
+interface CashBankCardProps {
+ title: string
+ accountNumber: string
+ balances: Balance[]
+ chartData: ChartData[]
+ categories: string[]
+ buttonText?: string
+ buttonIcon?: string
+ onButtonClick?: () => void
+ chartColor?: string
+ height?: number
+ currency?: 'IDR' | 'USD' | 'EUR'
+ showButton?: boolean
+ maxValue?: number
+ enableHover?: boolean
+}
+
+const CashBankCard = ({
+ title,
+ accountNumber,
+ balances,
+ chartData,
+ categories,
+ onButtonClick,
+ chartColor = '#ff6b9d',
+ height = 300,
+ currency = 'IDR',
+ showButton = true,
+ maxValue,
+ enableHover = true
+}: CashBankCardProps) => {
+ // Vars
+ const divider = 'var(--mui-palette-divider)'
+ const disabledText = 'var(--mui-palette-text-disabled)'
+ const primaryText = 'var(--mui-palette-text-primary)'
+
+ // Auto calculate maxValue if not provided
+ const calculatedMaxValue = maxValue || Math.max(...chartData.flatMap(series => series.data)) * 1.2
+
+ // Currency formatter
+ const formatCurrency = (value: number) => {
+ const formatters = {
+ IDR: new Intl.NumberFormat('id-ID', {
+ style: 'currency',
+ currency: 'IDR',
+ minimumFractionDigits: 0
+ }),
+ USD: new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ minimumFractionDigits: 0
+ }),
+ EUR: new Intl.NumberFormat('de-DE', {
+ style: 'currency',
+ currency: 'EUR',
+ minimumFractionDigits: 0
+ })
+ }
+ return formatters[currency].format(value)
+ }
+
+ // Format balance display
+ const formatBalance = (amount: string | number) => {
+ if (typeof amount === 'string') return amount
+ return new Intl.NumberFormat('id-ID').format(amount)
+ }
+
+ // Y-axis label formatter based on currency
+ const formatYAxisLabel = (val: number) => {
+ if (currency === 'IDR') {
+ return (val / 1000000).toFixed(0) + '.000.000'
+ }
+ return (val / 1000).toFixed(0) + 'K'
+ }
+
+ const options: ApexOptions = {
+ chart: {
+ height: height,
+ type: 'area',
+ parentHeightOffset: 0,
+ zoom: { enabled: false },
+ toolbar: { show: false }
+ },
+ colors: [chartColor],
+ fill: {
+ type: 'gradient',
+ gradient: {
+ shade: 'light',
+ type: 'vertical',
+ shadeIntensity: 0.4,
+ gradientToColors: [chartColor],
+ inverseColors: false,
+ opacityFrom: 0.8,
+ opacityTo: 0.1,
+ stops: [0, 100]
+ }
+ },
+ stroke: {
+ curve: 'smooth',
+ width: 3
+ },
+ dataLabels: { enabled: false },
+ grid: {
+ show: true,
+ borderColor: divider,
+ strokeDashArray: 3,
+ padding: {
+ top: -10,
+ bottom: -10,
+ left: 20,
+ right: 20
+ },
+ xaxis: {
+ lines: { show: true }
+ },
+ yaxis: {
+ lines: { show: true }
+ }
+ },
+ tooltip: {
+ enabled: true,
+ y: {
+ formatter: function (val: number) {
+ return formatCurrency(val)
+ }
+ }
+ },
+ yaxis: {
+ min: 0,
+ max: calculatedMaxValue,
+ tickAmount: 7,
+ labels: {
+ style: {
+ colors: disabledText,
+ fontSize: '12px',
+ fontWeight: '400'
+ },
+ formatter: function (val: number) {
+ return formatYAxisLabel(val)
+ }
+ }
+ },
+ xaxis: {
+ axisBorder: { show: false },
+ axisTicks: { show: false },
+ crosshairs: {
+ stroke: { color: divider }
+ },
+ labels: {
+ style: {
+ colors: disabledText,
+ fontSize: '12px',
+ fontWeight: '400'
+ }
+ },
+ categories: categories
+ },
+ legend: {
+ show: false
+ }
+ }
+
+ return (
+
+
+
+
+
+ {title}
+
+
+ {accountNumber}
+
+
+ {showButton && (
+
+ )}
+
+
+
+ {balances.map((balance, index) => (
+
+
+ {formatBalance(balance.amount)}
+
+
+ {balance.label}
+
+
+ ))}
+
+
+ }
+ sx={{
+ pb: 0,
+ '& .MuiCardHeader-content': {
+ width: '100%'
+ }
+ }}
+ />
+
+
+
+
+ )
+}
+
+export default CashBankCard
diff --git a/src/views/apps/cash-bank/CashBankList.tsx b/src/views/apps/cash-bank/CashBankList.tsx
new file mode 100644
index 0000000..740fe03
--- /dev/null
+++ b/src/views/apps/cash-bank/CashBankList.tsx
@@ -0,0 +1,326 @@
+'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'
+
+// 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) => {
+ // 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 setValue(e.target.value)} />
+}
+const CashBankList = () => {
+ const [searchQuery, setSearchQuery] = useState('')
+
+ // Handle button clicks
+ const handleAccountAction = (accountId: string, action: string) => {
+ console.log(`Action: ${action} for account: ${accountId}`)
+ // Implement your action logic here
+ }
+
+ // 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 (
+
+ {/* Search and Filters */}
+
+
+
+ setSearchQuery(value as string)}
+ placeholder='Cari '
+ className='max-sm:is-full'
+ />
+
+
+
+
+ {/* Account Cards */}
+
+ {filteredAccounts.length > 0 ? (
+ filteredAccounts.map(account => (
+
+ handleAccountAction(account.id, account.accountType || 'default')}
+ />
+
+ ))
+ ) : (
+
+
+
+ Tidak ada akun yang ditemukan
+
+
+ Coba ubah kata kunci pencarian atau filter yang digunakan
+
+
+
+ )}
+
+
+ )
+}
+
+export default CashBankList