diff --git a/src/app/[lang]/(dashboard)/(private)/apps/vendor/detail/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/vendor/detail/page.tsx new file mode 100644 index 0000000..5069723 --- /dev/null +++ b/src/app/[lang]/(dashboard)/(private)/apps/vendor/detail/page.tsx @@ -0,0 +1,7 @@ +import VendorView from '@/views/apps/vendor/detail' + +const VendorViewPage = async () => { + return +} + +export default VendorViewPage diff --git a/src/data/dummy/vendor.ts b/src/data/dummy/vendor.ts index d95ddcd..a984a99 100644 --- a/src/data/dummy/vendor.ts +++ b/src/data/dummy/vendor.ts @@ -1,4 +1,4 @@ -import { VendorType } from '@/types/apps/vendorTypes' +import { VendorDebsPayedType, VendorTransactionType, VendorType } from '@/types/apps/vendorTypes' export const vendorDummyData: VendorType[] = [ { @@ -202,3 +202,283 @@ export const vendorDummyData: VendorType[] = [ theyPayable: 23600000 } ] + +// Dummy data untuk VendorDebsPayedType +export const vendorDebsPayedData: VendorDebsPayedType[] = [ + { + date: '2024-08-15', + transaction: 'Hutang ke PT Supplier Bahan Kimia', + reference: 'DEBT-001-2024', + total: 4500000 + }, + { + date: '2024-08-22', + transaction: 'Invoice Belum Dibayar #INV-2024-789', + reference: 'DEBT-002-2024', + total: 2750000 + }, + { + date: '2024-08-30', + transaction: 'Tagihan CV Mitra Sejahtera', + reference: 'DEBT-003-2024', + total: 1850000 + }, + { + date: '2024-09-05', + transaction: 'Hutang Pembelian Peralatan Kantor', + reference: 'DEBT-004-2024', + total: 3200000 + }, + { + date: '2024-09-08', + transaction: 'Tagihan Listrik & Utilities Bulan Lalu', + reference: 'DEBT-005-2024', + total: 950000 + }, + { + date: '2024-09-10', + transaction: 'Hutang ke PT Konstruksi Prima', + reference: 'DEBT-006-2024', + total: 12500000 + }, + { + date: '2024-09-12', + transaction: 'Invoice Jasa Konsultasi IT', + reference: 'DEBT-007-2024', + total: 6800000 + }, + { + date: '2024-09-15', + transaction: 'Tagihan Bahan Baku Produksi', + reference: 'DEBT-008-2024', + total: 8900000 + }, + { + date: '2024-09-18', + transaction: 'Hutang ke Supplier Packaging', + reference: 'DEBT-009-2024', + total: 2100000 + }, + { + date: '2024-09-20', + transaction: 'Invoice Maintenance Equipment', + reference: 'DEBT-010-2024', + total: 4300000 + }, + { + date: '2024-09-22', + transaction: 'Tagihan Jasa Logistik & Pengiriman', + reference: 'DEBT-011-2024', + total: 1650000 + }, + { + date: '2024-09-25', + transaction: 'Hutang Pembelian Software License', + reference: 'DEBT-012-2024', + total: 5400000 + }, + { + date: '2024-09-28', + transaction: 'Invoice Jasa Cleaning Service', + reference: 'DEBT-013-2024', + total: 750000 + }, + { + date: '2024-09-30', + transaction: 'Tagihan Sewa Gedung Bulan September', + reference: 'DEBT-014-2024', + total: 15000000 + }, + { + date: '2024-10-01', + transaction: 'Hutang ke CV Digital Marketing', + reference: 'DEBT-015-2024', + total: 3800000 + } +] + +export const vendorReceivablesData: VendorDebsPayedType[] = [ + { + date: '2024-08-20', + transaction: 'Piutang dari PT Mitra Sejahtera Abadi', + reference: 'RCV-001-2024', + total: 5500000 + }, + { + date: '2024-08-25', + transaction: 'Invoice Jual Produk #INV-2024-456', + reference: 'RCV-002-2024', + total: 3250000 + }, + { + date: '2024-09-02', + transaction: 'Tagihan ke CV Berkah Mandiri', + reference: 'RCV-003-2024', + total: 2800000 + }, + { + date: '2024-09-05', + transaction: 'Piutang Penjualan Barang Jadi', + reference: 'RCV-004-2024', + total: 4200000 + }, + { + date: '2024-09-08', + transaction: 'Invoice Jasa Konsultasi', + reference: 'RCV-005-2024', + total: 1750000 + }, + { + date: '2024-09-10', + transaction: 'Tagihan ke PT Digital Solutions', + reference: 'RCV-006-2024', + total: 8900000 + }, + { + date: '2024-09-12', + transaction: 'Piutang dari Toko Elektronik Prima', + reference: 'RCV-007-2024', + total: 2450000 + }, + { + date: '2024-09-15', + transaction: 'Invoice Penjualan Software License', + reference: 'RCV-008-2024', + total: 12500000 + }, + { + date: '2024-09-18', + transaction: 'Tagihan Jasa Maintenance Equipment', + reference: 'RCV-009-2024', + total: 3600000 + }, + { + date: '2024-09-20', + transaction: 'Piutang dari CV Kreatif Media', + reference: 'RCV-010-2024', + total: 1950000 + }, + { + date: '2024-09-22', + transaction: 'Invoice Jual Material Konstruksi', + reference: 'RCV-011-2024', + total: 7200000 + }, + { + date: '2024-09-25', + transaction: 'Tagihan Jasa Pelatihan IT', + reference: 'RCV-012-2024', + total: 4800000 + }, + { + date: '2024-09-28', + transaction: 'Piutang dari PT Logistik Nusantara', + reference: 'RCV-013-2024', + total: 5300000 + }, + { + date: '2024-09-30', + transaction: 'Invoice Penjualan Peralatan Kantor', + reference: 'RCV-014-2024', + total: 2100000 + }, + { + date: '2024-10-02', + transaction: 'Tagihan ke Supplier Packaging', + reference: 'RCV-015-2024', + total: 3850000 + } +] + +export const vendorTransactionData: VendorTransactionType[] = [ + { + date: '2024-08-15', + transaction: 'Pembelian Bahan Baku Produksi', + none: 'PO-001-2024', + total: 4500000 + }, + { + date: '2024-08-18', + transaction: 'Pembayaran Invoice Supplier', + none: 'PAY-001-2024', + total: 2750000 + }, + { + date: '2024-08-22', + transaction: 'Penjualan Produk ke Klien', + none: 'INV-001-2024', + total: 6200000 + }, + { + date: '2024-08-25', + transaction: 'Pembelian Peralatan Kantor', + none: 'PO-002-2024', + total: 1850000 + }, + { + date: '2024-08-28', + transaction: 'Pembayaran Jasa Konsultasi', + none: 'PAY-002-2024', + total: 3200000 + }, + { + date: '2024-09-02', + transaction: 'Penjualan Software License', + none: 'INV-002-2024', + total: 8900000 + }, + { + date: '2024-09-05', + transaction: 'Pembelian Material Konstruksi', + none: 'PO-003-2024', + total: 12500000 + }, + { + date: '2024-09-08', + transaction: 'Pembayaran Maintenance Equipment', + none: 'PAY-003-2024', + total: 2450000 + }, + { + date: '2024-09-12', + transaction: 'Penjualan Jasa Pelatihan', + none: 'INV-003-2024', + total: 4800000 + }, + { + date: '2024-09-15', + transaction: 'Pembelian Bahan Kimia', + none: 'PO-004-2024', + total: 3600000 + }, + { + date: '2024-09-18', + transaction: 'Pembayaran Sewa Gedung', + none: 'PAY-004-2024', + total: 15000000 + }, + { + date: '2024-09-22', + transaction: 'Penjualan Peralatan Elektronik', + none: 'INV-004-2024', + total: 7200000 + }, + { + date: '2024-09-25', + transaction: 'Pembelian Packaging Materials', + none: 'PO-005-2024', + total: 1950000 + }, + { + date: '2024-09-28', + transaction: 'Pembayaran Jasa Logistik', + none: 'PAY-005-2024', + total: 2100000 + }, + { + date: '2024-10-01', + transaction: 'Penjualan Produk Digital', + none: 'INV-005-2024', + total: 5300000 + } +] diff --git a/src/types/apps/vendorTypes.ts b/src/types/apps/vendorTypes.ts index 33de981..bc3b109 100644 --- a/src/types/apps/vendorTypes.ts +++ b/src/types/apps/vendorTypes.ts @@ -8,3 +8,16 @@ export type VendorType = { youPayable: number theyPayable: number } + +export type VendorDebsPayedType = { + date: string + transaction: string + reference: string + total: number +} +export type VendorTransactionType = { + date: string + transaction: string + none: string + total: number +} diff --git a/src/views/apps/vendor/detail/index.tsx b/src/views/apps/vendor/detail/index.tsx new file mode 100644 index 0000000..3869930 --- /dev/null +++ b/src/views/apps/vendor/detail/index.tsx @@ -0,0 +1,20 @@ +import VendorOverview from '@/views/apps/vendor/detail/vendor-overview' +import Grid from '@mui/material/Grid2' +import VendorContent from './vendor-content' + +const VendorView = async () => { + // Vars + + return ( + + + + + + + + + ) +} + +export default VendorView diff --git a/src/views/apps/vendor/detail/vendor-content/VendorMoneyInOutChart.tsx b/src/views/apps/vendor/detail/vendor-content/VendorMoneyInOutChart.tsx new file mode 100644 index 0000000..c521fd5 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/VendorMoneyInOutChart.tsx @@ -0,0 +1,157 @@ +'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' + +// Third Party Imports +import type { ApexOptions } from 'apexcharts' + +// Components Imports +import OptionMenu from '@core/components/option-menu' + +// Styled Component Imports +const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts')) + +// Styles Imports +import './styles.css' + +// Vars +const colors = { + uangMasuk: '#28C76F', + uangKeluar: '#EA5455' +} + +const labelColor = 'var(--mui-palette-text-disabled)' +const bodyColor = 'var(--mui-palette-text-secondary)' +const borderColor = 'var(--mui-palette-divider)' + +const series = [ + { + name: 'Uang Masuk', + type: 'column', + data: [850, 920, 780, 1150, 980, 1250, 1080, 950, 1300, 1100, 890, 1400] + }, + { + name: 'Uang Keluar', + type: 'column', + data: [650, 720, 580, 850, 780, 950, 880, 750, 1000, 900, 690, 1100] + } +] + +const VendorMoneyInOutChart = () => { + const options: ApexOptions = { + chart: { + parentHeightOffset: 0, + stacked: false, + toolbar: { + show: false + }, + zoom: { + enabled: false + } + }, + tooltip: { + enabled: true, + y: { + formatter: function (val) { + return 'Rp ' + val.toLocaleString('id-ID') + '.000' + } + } + }, + plotOptions: { + bar: { + horizontal: false, + columnWidth: '60%', + borderRadius: 4 + } + }, + dataLabels: { + enabled: false + }, + xaxis: { + categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'], + labels: { + style: { + colors: labelColor, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400 + } + }, + axisBorder: { + show: false + }, + axisTicks: { + show: false + } + }, + yaxis: { + tickAmount: 5, + max: 1500, + min: 0, + labels: { + style: { + colors: labelColor, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400 + }, + formatter(val: number) { + return 'Rp ' + val + 'rb' + } + } + }, + legend: { + markers: { + width: 8, + height: 8, + offsetX: -3, + radius: 12 + }, + height: 33, + offsetY: 10, + itemMargin: { + horizontal: 10, + vertical: 0 + }, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400, + labels: { + colors: bodyColor, + useSeriesColors: false + } + }, + grid: { + borderColor, + strokeDashArray: 6 + }, + colors: [colors.uangMasuk, colors.uangKeluar], + fill: { + opacity: 1 + } + } + + return ( + + } /> + + + + + ) +} + +export default VendorMoneyInOutChart diff --git a/src/views/apps/vendor/detail/vendor-content/VendorSalesChart.tsx b/src/views/apps/vendor/detail/vendor-content/VendorSalesChart.tsx new file mode 100644 index 0000000..6d8f3aa --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/VendorSalesChart.tsx @@ -0,0 +1,144 @@ +'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' + +// Third Party Imports +import type { ApexOptions } from 'apexcharts' + +// Components Imports +import OptionMenu from '@core/components/option-menu' + +// Styled Component Imports +const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts')) + +// Styles Imports +import './styles.css' + +// Vars +const colors = { + penjualan: '#7367F0' +} + +const labelColor = 'var(--mui-palette-text-disabled)' +const bodyColor = 'var(--mui-palette-text-secondary)' +const borderColor = 'var(--mui-palette-divider)' + +const series = [ + { + name: 'Penjualan', + type: 'column', + data: [1250, 1420, 980, 1650, 1380, 1750, 1580, 1350, 1900, 1600, 1290, 2100] + } +] + +const VendorSalesChart = () => { + const options: ApexOptions = { + chart: { + parentHeightOffset: 0, + stacked: false, + toolbar: { + show: false + }, + zoom: { + enabled: false + } + }, + tooltip: { + enabled: true, + y: { + formatter: function (val) { + return 'Rp ' + val.toLocaleString('id-ID') + '.000' + } + } + }, + plotOptions: { + bar: { + horizontal: false, + columnWidth: '50%', + borderRadius: 4 + } + }, + dataLabels: { + enabled: false + }, + xaxis: { + categories: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'], + labels: { + style: { + colors: labelColor, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400 + } + }, + axisBorder: { + show: false + }, + axisTicks: { + show: false + } + }, + yaxis: { + tickAmount: 5, + max: 2200, + min: 0, + labels: { + style: { + colors: labelColor, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400 + }, + formatter(val: number) { + return 'Rp ' + val + 'rb' + } + } + }, + legend: { + markers: { + width: 8, + height: 8, + offsetX: -3, + radius: 12 + }, + height: 33, + offsetY: 10, + itemMargin: { + horizontal: 10, + vertical: 0 + }, + fontSize: '13px', + fontFamily: 'Public Sans', + fontWeight: 400, + labels: { + colors: bodyColor, + useSeriesColors: false + } + }, + grid: { + borderColor, + strokeDashArray: 6 + }, + colors: [colors.penjualan], + fill: { + opacity: 1 + } + } + + return ( + + } /> + + + + + ) +} + +export default VendorSalesChart diff --git a/src/views/apps/vendor/detail/vendor-content/VendorStatistic.tsx b/src/views/apps/vendor/detail/vendor-content/VendorStatistic.tsx new file mode 100644 index 0000000..790430f --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/VendorStatistic.tsx @@ -0,0 +1,63 @@ +// MUI Imports +import Grid from '@mui/material/Grid2' + +// Types Imports +import type { CardStatsHorizontalWithAvatarProps } from '@/types/pages/widgetTypes' + +// Component Imports +import CardStatsHorizontalWithAvatar from '@components/card-statistics/HorizontalWithAvatar' + +const data: CardStatsHorizontalWithAvatarProps[] = [ + { + stats: 'Rp 542.340.000', + title: 'Hutang Anda', + avatarIcon: 'tabler-credit-card', + avatarColor: 'error' + }, + { + stats: 'Rp 387.250.000', + title: 'Piutang Anda', + avatarIcon: 'tabler-wallet', + avatarColor: 'success' + }, + { + stats: 'Rp 156.800.000', + title: 'Pembayaran Diterima', + avatarIcon: 'tabler-arrow-down-circle', + avatarColor: 'success' + }, + { + stats: 'Rp 89.450.000', + title: 'Pembayaran Dikirim', + avatarIcon: 'tabler-arrow-up-circle', + avatarColor: 'warning' + }, + { + stats: 'Rp 67.890.000', + title: 'Hutang Jatuh Tempo', + avatarIcon: 'tabler-clock-exclamation', + avatarColor: 'error' + }, + { + stats: 'Rp 134.560.000', + title: 'Piutang Tertunda', + avatarIcon: 'tabler-clock-dollar', + avatarColor: 'info' + } +] + +const VendorStatistic = () => { + return ( + data && ( + + {data.map((item, index) => ( + + + + ))} + + ) + ) +} + +export default VendorStatistic diff --git a/src/views/apps/vendor/detail/vendor-content/index.tsx b/src/views/apps/vendor/detail/vendor-content/index.tsx new file mode 100644 index 0000000..c57eeb7 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/index.tsx @@ -0,0 +1,21 @@ +import VendorDebsPayed from './vendor-debs-payed-table' +import VendorReceivablesPayment from './vendor-receivables-payment-table' +import VendorTransaction from './vendor-transaction-table' +import VendorMoneyInOutChart from './VendorMoneyInOutChart' +import VendorSalesChart from './VendorSalesChart' +import VendorStatistic from './VendorStatistic' + +const VendorContent = () => { + return ( + <> + + + + + + + + ) +} + +export default VendorContent diff --git a/src/views/apps/vendor/detail/vendor-content/styles.css b/src/views/apps/vendor/detail/vendor-content/styles.css new file mode 100644 index 0000000..6d24cd4 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/styles.css @@ -0,0 +1,7 @@ +#keluar-masuk-uang .apexcharts-legend .apexcharts-legend-series { + border: 1px solid var(--mui-palette-divider); + border-radius: var(--mui-shape-borderRadius); + block-size: 83%; + padding-block: 4px; + padding-inline: 16px; +} diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/VendorDebsPayedTable.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/VendorDebsPayedTable.tsx new file mode 100644 index 0000000..2bb0986 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/VendorDebsPayedTable.tsx @@ -0,0 +1,334 @@ +'use client' + +// React Imports +import { useEffect, useState, useMemo } from 'react' + +// Next Imports +import Link from 'next/link' +import { useParams } from 'next/navigation' + +// MUI Imports +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Chip from '@mui/material/Chip' +import Checkbox from '@mui/material/Checkbox' +import IconButton from '@mui/material/IconButton' +import { styled } from '@mui/material/styles' +import TablePagination from '@mui/material/TablePagination' +import type { TextFieldProps } from '@mui/material/TextField' +import MenuItem from '@mui/material/MenuItem' + +// Third-party Imports +import classnames from 'classnames' +import { rankItem } from '@tanstack/match-sorter-utils' +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, + getFilteredRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFacetedMinMaxValues, + getPaginationRowModel, + getSortedRowModel +} from '@tanstack/react-table' +import type { ColumnDef, FilterFn } from '@tanstack/react-table' +import type { RankingInfo } from '@tanstack/match-sorter-utils' + +// Type Imports +import type { ThemeColor } from '@core/types' +import type { Locale } from '@configs/i18n' + +// Component Imports +import OptionMenu from '@core/components/option-menu' +import TablePaginationComponent from '@components/TablePaginationComponent' +import CustomTextField from '@core/components/mui/TextField' + +// Util Imports +import { getLocalizedUrl } from '@/utils/i18n' + +// Style Imports +import tableStyles from '@core/styles/table.module.css' +import { formatCurrency } from '@/utils/transform' + +// Type Definition +export type VendorDebsPayedType = { + date: string + transaction: string + reference: string + total: number +} + +declare module '@tanstack/table-core' { + interface FilterFns { + fuzzy: FilterFn + } + interface FilterMeta { + itemRank: RankingInfo + } +} + +type VendorDebsPayedTypeWithAction = VendorDebsPayedType & { + action?: string +} + +// Styled Components +const Icon = styled('i')({}) + +const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + // Rank the item + const itemRank = rankItem(row.getValue(columnId), value) + + // Store the itemRank info + addMeta({ + itemRank + }) + + // Return if the item should be filtered in/out + return itemRank.passed +} + +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)} /> +} + +// Column Definitions +const columnHelper = createColumnHelper() + +const VendorDebsPayedTable = ({ tableData }: { tableData?: VendorDebsPayedType[] }) => { + // States + const [rowSelection, setRowSelection] = useState({}) + const [data, setData] = useState(...[tableData]) + const [filteredData, setFilteredData] = useState(data) + const [globalFilter, setGlobalFilter] = useState('') + + // Hooks + const { lang: locale } = useParams() + + const columns = useMemo[]>( + () => [ + { + id: 'select', + header: ({ table }) => ( + + ), + cell: ({ row }) => ( + + ) + }, + columnHelper.accessor('date', { + header: 'Tanggal', + cell: ({ row }) => {row.original.date} + }), + columnHelper.accessor('transaction', { + header: 'Keterangan Transaksi', + cell: ({ row }) => ( +
+ + {row.original.transaction} + +
+ ) + }), + columnHelper.accessor('reference', { + header: 'Referensi', + cell: ({ row }) => + }), + columnHelper.accessor('total', { + header: () =>
Jumlah Hutang
, + cell: ({ row }) => ( +
+ + {formatCurrency(row.original.total)} + +
+ ) + }) + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [data, filteredData] + ) + + const table = useReactTable({ + data: filteredData as VendorDebsPayedType[], + columns, + filterFns: { + fuzzy: fuzzyFilter + }, + state: { + rowSelection, + globalFilter + }, + initialState: { + pagination: { + pageSize: 10 + } + }, + enableRowSelection: true, + globalFilterFn: fuzzyFilter, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + onGlobalFilterChange: setGlobalFilter, + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + getFacetedMinMaxValues: getFacetedMinMaxValues() + }) + + // Calculate total debt + const totalDebt = useMemo(() => { + return filteredData?.reduce((sum, item) => sum + item.total, 0) || 0 + }, [filteredData]) + + return ( + <> + + +
+ table.setPageSize(Number(e.target.value))} + className='max-sm:is-full sm:is-[70px]' + > + 10 + 25 + 50 + +
+ setGlobalFilter(String(value))} + placeholder='Cari Hutang' + className='max-sm:is-full' + /> + +
+
+
+ + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => ( + + ))} + + ))} + + {table.getFilteredRowModel().rows.length === 0 ? ( + + + + + + ) : ( + + {table + .getRowModel() + .rows.slice(0, table.getState().pagination.pageSize) + .map(row => { + return ( + + {row.getVisibleCells().map(cell => ( + + ))} + + ) + })} + + )} +
+ {header.isPlaceholder ? null : ( + <> +
+ {flexRender(header.column.columnDef.header, header.getContext())} + {{ + asc: , + desc: + }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null} +
+ + )} +
+
+ + + Tidak ada hutang ditemukan + + + Cobalah mengubah filter pencarian + +
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ { + table.setPageIndex(page) + }} + /> +
+ + ) +} + +export default VendorDebsPayedTable diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/index.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/index.tsx new file mode 100644 index 0000000..35c3ce0 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-debs-payed-table/index.tsx @@ -0,0 +1,21 @@ +// MUI Imports +import Grid from '@mui/material/Grid2' + +// Type Imports +import type { VendorType } from '@/types/apps/vendorTypes' + +// Component Imports +import VendorDebsPayedTable from './VendorDebsPayedTable' +import { vendorDebsPayedData } from '@/data/dummy/vendor' + +const VendorDebsPayed = () => { + return ( + + + + + + ) +} + +export default VendorDebsPayed diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/VendorReceivablesPaymentTable.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/VendorReceivablesPaymentTable.tsx new file mode 100644 index 0000000..5ddc36a --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/VendorReceivablesPaymentTable.tsx @@ -0,0 +1,327 @@ +'use client' + +// React Imports +import { useEffect, useState, useMemo } from 'react' + +// Next Imports +import Link from 'next/link' +import { useParams } from 'next/navigation' + +// MUI Imports +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Chip from '@mui/material/Chip' +import Checkbox from '@mui/material/Checkbox' +import IconButton from '@mui/material/IconButton' +import { styled } from '@mui/material/styles' +import TablePagination from '@mui/material/TablePagination' +import type { TextFieldProps } from '@mui/material/TextField' +import MenuItem from '@mui/material/MenuItem' + +// Third-party Imports +import classnames from 'classnames' +import { rankItem } from '@tanstack/match-sorter-utils' +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, + getFilteredRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFacetedMinMaxValues, + getPaginationRowModel, + getSortedRowModel +} from '@tanstack/react-table' +import type { ColumnDef, FilterFn } from '@tanstack/react-table' +import type { RankingInfo } from '@tanstack/match-sorter-utils' + +// Type Imports +import type { ThemeColor } from '@core/types' +import type { Locale } from '@configs/i18n' + +// Component Imports +import OptionMenu from '@core/components/option-menu' +import TablePaginationComponent from '@components/TablePaginationComponent' +import CustomTextField from '@core/components/mui/TextField' + +// Util Imports +import { getLocalizedUrl } from '@/utils/i18n' + +// Style Imports +import tableStyles from '@core/styles/table.module.css' +import { formatCurrency } from '@/utils/transform' +import { VendorDebsPayedType } from '../vendor-debs-payed-table/VendorDebsPayedTable' + +declare module '@tanstack/table-core' { + interface FilterFns { + fuzzy: FilterFn + } + interface FilterMeta { + itemRank: RankingInfo + } +} + +type VendorDebsPayedTypeWithAction = VendorDebsPayedType & { + action?: string +} + +// Styled Components +const Icon = styled('i')({}) + +const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + // Rank the item + const itemRank = rankItem(row.getValue(columnId), value) + + // Store the itemRank info + addMeta({ + itemRank + }) + + // Return if the item should be filtered in/out + return itemRank.passed +} + +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)} /> +} + +// Column Definitions +const columnHelper = createColumnHelper() + +const VendorReceivablesPaymentTable = ({ tableData }: { tableData?: VendorDebsPayedType[] }) => { + // States + const [rowSelection, setRowSelection] = useState({}) + const [data, setData] = useState(...[tableData]) + const [filteredData, setFilteredData] = useState(data) + const [globalFilter, setGlobalFilter] = useState('') + + // Hooks + const { lang: locale } = useParams() + + const columns = useMemo[]>( + () => [ + { + id: 'select', + header: ({ table }) => ( + + ), + cell: ({ row }) => ( + + ) + }, + columnHelper.accessor('date', { + header: 'Tanggal', + cell: ({ row }) => {row.original.date} + }), + columnHelper.accessor('transaction', { + header: 'Keterangan Transaksi', + cell: ({ row }) => ( +
+ + {row.original.transaction} + +
+ ) + }), + columnHelper.accessor('reference', { + header: 'Referensi', + cell: ({ row }) => + }), + columnHelper.accessor('total', { + header: () =>
Jumlah Hutang
, + cell: ({ row }) => ( +
+ + {formatCurrency(row.original.total)} + +
+ ) + }) + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [data, filteredData] + ) + + const table = useReactTable({ + data: filteredData as VendorDebsPayedType[], + columns, + filterFns: { + fuzzy: fuzzyFilter + }, + state: { + rowSelection, + globalFilter + }, + initialState: { + pagination: { + pageSize: 10 + } + }, + enableRowSelection: true, + globalFilterFn: fuzzyFilter, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + onGlobalFilterChange: setGlobalFilter, + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + getFacetedMinMaxValues: getFacetedMinMaxValues() + }) + + // Calculate total debt + const totalDebt = useMemo(() => { + return filteredData?.reduce((sum, item) => sum + item.total, 0) || 0 + }, [filteredData]) + + return ( + <> + + +
+ table.setPageSize(Number(e.target.value))} + className='max-sm:is-full sm:is-[70px]' + > + 10 + 25 + 50 + +
+ setGlobalFilter(String(value))} + placeholder='Cari' + className='max-sm:is-full' + /> + +
+
+
+ + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => ( + + ))} + + ))} + + {table.getFilteredRowModel().rows.length === 0 ? ( + + + + + + ) : ( + + {table + .getRowModel() + .rows.slice(0, table.getState().pagination.pageSize) + .map(row => { + return ( + + {row.getVisibleCells().map(cell => ( + + ))} + + ) + })} + + )} +
+ {header.isPlaceholder ? null : ( + <> +
+ {flexRender(header.column.columnDef.header, header.getContext())} + {{ + asc: , + desc: + }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null} +
+ + )} +
+
+ + + Tidak ada hutang ditemukan + + + Cobalah mengubah filter pencarian + +
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ { + table.setPageIndex(page) + }} + /> +
+ + ) +} + +export default VendorReceivablesPaymentTable diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/index.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/index.tsx new file mode 100644 index 0000000..fbf21df --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-receivables-payment-table/index.tsx @@ -0,0 +1,18 @@ +// MUI Imports +import Grid from '@mui/material/Grid2' + +// Component Imports +import VendorReceivablesPaymentTable from './VendorReceivablesPaymentTable' +import { vendorReceivablesData } from '@/data/dummy/vendor' + +const VendorReceivablesPayment = () => { + return ( + + + + + + ) +} + +export default VendorReceivablesPayment diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/VendorTransactionTable.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/VendorTransactionTable.tsx new file mode 100644 index 0000000..e9895d1 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/VendorTransactionTable.tsx @@ -0,0 +1,355 @@ +'use client' + +// React Imports +import { useEffect, useState, useMemo } from 'react' + +// Next Imports +import Link from 'next/link' +import { useParams } from 'next/navigation' + +// MUI Imports +import Card from '@mui/material/Card' +import CardHeader from '@mui/material/CardHeader' +import Button from '@mui/material/Button' +import Typography from '@mui/material/Typography' +import Chip from '@mui/material/Chip' +import Checkbox from '@mui/material/Checkbox' +import IconButton from '@mui/material/IconButton' +import { styled } from '@mui/material/styles' +import TablePagination from '@mui/material/TablePagination' +import type { TextFieldProps } from '@mui/material/TextField' +import MenuItem from '@mui/material/MenuItem' + +// Third-party Imports +import classnames from 'classnames' +import { rankItem } from '@tanstack/match-sorter-utils' +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, + getFilteredRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFacetedMinMaxValues, + getPaginationRowModel, + getSortedRowModel +} from '@tanstack/react-table' +import type { ColumnDef, FilterFn } from '@tanstack/react-table' +import type { RankingInfo } from '@tanstack/match-sorter-utils' + +// Type Imports +import type { ThemeColor } from '@core/types' +import type { Locale } from '@configs/i18n' + +// Component Imports +import OptionMenu from '@core/components/option-menu' +import TablePaginationComponent from '@components/TablePaginationComponent' +import CustomTextField from '@core/components/mui/TextField' + +// Util Imports +import { getLocalizedUrl } from '@/utils/i18n' + +// Style Imports +import tableStyles from '@core/styles/table.module.css' +import { formatCurrency } from '@/utils/transform' + +// Type Definition +export type VendorTransactionType = { + date: string + transaction: string + none: string + total: number +} + +declare module '@tanstack/table-core' { + interface FilterFns { + fuzzy: FilterFn + } + interface FilterMeta { + itemRank: RankingInfo + } +} + +type VendorTransactionTypeWithAction = VendorTransactionType & { + action?: string +} + +// Styled Components +const Icon = styled('i')({}) + +const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + // Rank the item + const itemRank = rankItem(row.getValue(columnId), value) + + // Store the itemRank info + addMeta({ + itemRank + }) + + // Return if the item should be filtered in/out + return itemRank.passed +} + +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)} /> +} + +// Format date helper +const formatDate = (dateString: string): string => { + return new Date(dateString).toLocaleDateString('id-ID', { + year: 'numeric', + month: 'long', + day: 'numeric' + }) +} + +// Column Definitions +const columnHelper = createColumnHelper() + +const VendorTransactionTable = ({ tableData }: { tableData?: VendorTransactionType[] }) => { + // States + const [rowSelection, setRowSelection] = useState({}) + const [data, setData] = useState(...[tableData]) + const [filteredData, setFilteredData] = useState(data) + const [globalFilter, setGlobalFilter] = useState('') + + // Hooks + const { lang: locale } = useParams() + + const columns = useMemo[]>( + () => [ + { + id: 'select', + header: ({ table }) => ( + + ), + cell: ({ row }) => ( + + ) + }, + columnHelper.accessor('date', { + header: 'Tanggal', + cell: ({ row }) => {row.original.date} + }), + columnHelper.accessor('transaction', { + header: 'Keterangan Transaksi', + cell: ({ row }) => ( +
+ + {row.original.transaction} + +
+ ) + }), + columnHelper.accessor('none', { + header: 'Referensi', + cell: ({ row }) => + }), + columnHelper.accessor('total', { + header: () =>
Jumlah
, + cell: ({ row }) => ( +
+ + {formatCurrency(row.original.total)} + +
+ ) + }) + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [data, filteredData] + ) + + const table = useReactTable({ + data: filteredData as VendorTransactionType[], + columns, + filterFns: { + fuzzy: fuzzyFilter + }, + state: { + rowSelection, + globalFilter + }, + initialState: { + pagination: { + pageSize: 10 + } + }, + enableRowSelection: true, + globalFilterFn: fuzzyFilter, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + onGlobalFilterChange: setGlobalFilter, + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + getFacetedMinMaxValues: getFacetedMinMaxValues() + }) + + // Calculate total amount + const totalAmount = useMemo(() => { + return filteredData?.reduce((sum, item) => sum + item.total, 0) || 0 + }, [filteredData]) + + return ( + <> + + + } + /> +
+ table.setPageSize(Number(e.target.value))} + className='max-sm:is-full sm:is-[70px]' + > + 10 + 25 + 50 + +
+ setGlobalFilter(String(value))} + placeholder='Cari Transaksi' + className='max-sm:is-full' + /> + +
+
+
+ + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => ( + + ))} + + ))} + + {table.getFilteredRowModel().rows.length === 0 ? ( + + + + + + ) : ( + + {table + .getRowModel() + .rows.slice(0, table.getState().pagination.pageSize) + .map(row => { + return ( + + {row.getVisibleCells().map(cell => ( + + ))} + + ) + })} + + )} +
+ {header.isPlaceholder ? null : ( + <> +
+ {flexRender(header.column.columnDef.header, header.getContext())} + {{ + asc: , + desc: + }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null} +
+ + )} +
+
+ + + Tidak ada transaksi ditemukan + + + Cobalah mengubah filter pencarian + +
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ { + table.setPageIndex(page) + }} + /> +
+ + ) +} + +export default VendorTransactionTable diff --git a/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/index.tsx b/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/index.tsx new file mode 100644 index 0000000..e492e2a --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-content/vendor-transaction-table/index.tsx @@ -0,0 +1,18 @@ +// MUI Imports +import Grid from '@mui/material/Grid2' + +// Component Imports +import { vendorTransactionData } from '@/data/dummy/vendor' +import VendorTransactionTable from './VendorTransactionTable' + +const VendorTransaction = () => { + return ( + + + + + + ) +} + +export default VendorTransaction diff --git a/src/views/apps/vendor/detail/vendor-overview/VendorDetails.tsx b/src/views/apps/vendor/detail/vendor-overview/VendorDetails.tsx new file mode 100644 index 0000000..f0f4615 --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-overview/VendorDetails.tsx @@ -0,0 +1,134 @@ +// MUI Imports +import Card from '@mui/material/Card' +import CardContent from '@mui/material/CardContent' +import Typography from '@mui/material/Typography' +import Chip from '@mui/material/Chip' +import Divider from '@mui/material/Divider' +import Button from '@mui/material/Button' +import type { ButtonProps } from '@mui/material/Button' + +// Type Imports +import type { ThemeColor } from '@core/types' + +// Component Imports +import EditUserInfo from '@components/dialogs/edit-user-info' +import ConfirmationDialog from '@components/dialogs/confirmation-dialog' +import OpenDialogOnElementClick from '@components/dialogs/OpenDialogOnElementClick' +import CustomAvatar from '@core/components/mui/Avatar' + +// Vars +const userData = { + firstName: 'Wadi Adika Adrian', + lastName: 'Firgantoro', + userName: '@wadiAdika', + perusahaan: 'Yayasan Pertiwi Tb', + email: 'labuh87@napitupu', + status: 'active', + role: 'Vendor', + telepon: '622301190560', + alamatPenagihan: 'Gg. Sentot Alibasa 381, Cimahi 66726 Sulbar', + akunHutang: '2-20100 Hutang U', + akunPiutang: '', + kenaPajak: 'Kena Pajak' +} + +const VendorDetails = () => { + // Vars + const buttonProps = (children: string, color: ThemeColor, variant: ButtonProps['variant']): ButtonProps => ({ + children, + color, + variant + }) + + return ( + <> + + +
+
+
+ + {`${userData.firstName} ${userData.lastName}`} +
+ +
+
+ + {/* Detail Kontak Section */} +
+ Detail Kontak + +
+
+ + Nama: + + {`${userData.firstName} ${userData.lastName}`} +
+
+ + Perusahaan: + + {userData.perusahaan} +
+
+ + Email: + + + {userData.email} + +
+
+ + Telepon: + + + {userData.telepon} + +
+
+ + Alamat Penagihan: + + + {userData.alamatPenagihan} + +
+
+
+ + {/* Pemetaan Akun Section */} +
+ Pemetaan Akun + +
+
+ + Akun Hutang: + + + {userData.akunHutang} + +
+
+ + Akun Piutang: + + {userData.akunPiutang || '-'} +
+
+ + Kena Pajak: + + {userData.kenaPajak} +
+
+
+
+
+ + ) +} + +export default VendorDetails diff --git a/src/views/apps/vendor/detail/vendor-overview/index.tsx b/src/views/apps/vendor/detail/vendor-overview/index.tsx new file mode 100644 index 0000000..f59240e --- /dev/null +++ b/src/views/apps/vendor/detail/vendor-overview/index.tsx @@ -0,0 +1,17 @@ +// MUI Imports +import Grid from '@mui/material/Grid2' + +// Component Imports +import VendorDetails from './VendorDetails' + +const VendorOverview = () => { + return ( + + + + + + ) +} + +export default VendorOverview diff --git a/src/views/apps/vendor/list/VendorListTable.tsx b/src/views/apps/vendor/list/VendorListTable.tsx index 284b160..754d059 100644 --- a/src/views/apps/vendor/list/VendorListTable.tsx +++ b/src/views/apps/vendor/list/VendorListTable.tsx @@ -161,7 +161,7 @@ const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => {
{getAvatar({ photo: row.original.photo, name: row.original.name })}
- + {row.original.name}