efril #6

Merged
aefril merged 43 commits from efril into main 2025-09-11 18:58:35 +00:00
18 changed files with 1938 additions and 2 deletions
Showing only changes of commit dfa6b4be75 - Show all commits

View File

@ -0,0 +1,7 @@
import VendorView from '@/views/apps/vendor/detail'
const VendorViewPage = async () => {
return <VendorView />
}
export default VendorViewPage

View File

@ -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
}
]

View File

@ -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
}

20
src/views/apps/vendor/detail/index.tsx vendored Normal file
View File

@ -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 (
<Grid container spacing={6}>
<Grid size={{ xs: 12, lg: 4, md: 5 }}>
<VendorOverview />
</Grid>
<Grid size={{ xs: 12, lg: 8, md: 7 }}>
<VendorContent />
</Grid>
</Grid>
)
}
export default VendorView

View File

@ -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 (
<Card className='mt-5'>
<CardHeader title='Keluar Masuk Uang' action={<OptionMenu options={['View More', 'Delete']} />} />
<CardContent>
<AppReactApexCharts
id='keluar-masuk-uang'
type='bar'
height={360}
width='100%'
series={series}
options={options}
/>
</CardContent>
</Card>
)
}
export default VendorMoneyInOutChart

View File

@ -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 (
<Card className='mt-5'>
<CardHeader title='Penjualan' action={<OptionMenu options={['View More', 'Delete']} />} />
<CardContent>
<AppReactApexCharts id='penjualan' type='bar' height={360} width='100%' series={series} options={options} />
</CardContent>
</Card>
)
}
export default VendorSalesChart

View File

@ -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 && (
<Grid container spacing={6}>
{data.map((item, index) => (
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={index}>
<CardStatsHorizontalWithAvatar {...item} avatarSkin='light' />
</Grid>
))}
</Grid>
)
)
}
export default VendorStatistic

View File

@ -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 (
<>
<VendorStatistic />
<VendorMoneyInOutChart />
<VendorSalesChart />
<VendorReceivablesPayment />
<VendorDebsPayed />
<VendorTransaction />
</>
)
}
export default VendorContent

View File

@ -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;
}

View File

@ -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<unknown>
}
interface FilterMeta {
itemRank: RankingInfo
}
}
type VendorDebsPayedTypeWithAction = VendorDebsPayedType & {
action?: string
}
// Styled Components
const Icon = styled('i')({})
const fuzzyFilter: FilterFn<any> = (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<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)} />
}
// Column Definitions
const columnHelper = createColumnHelper<VendorDebsPayedTypeWithAction>()
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<ColumnDef<VendorDebsPayedTypeWithAction, any>[]>(
() => [
{
id: 'select',
header: ({ table }) => (
<Checkbox
{...{
checked: table.getIsAllRowsSelected(),
indeterminate: table.getIsSomeRowsSelected(),
onChange: table.getToggleAllRowsSelectedHandler()
}}
/>
),
cell: ({ row }) => (
<Checkbox
{...{
checked: row.getIsSelected(),
disabled: !row.getCanSelect(),
indeterminate: row.getIsSomeSelected(),
onChange: row.getToggleSelectedHandler()
}}
/>
)
},
columnHelper.accessor('date', {
header: 'Tanggal',
cell: ({ row }) => <Typography color='text.primary'>{row.original.date}</Typography>
}),
columnHelper.accessor('transaction', {
header: 'Keterangan Transaksi',
cell: ({ row }) => (
<div className='flex flex-col max-w-xs'>
<Typography color='text.primary' className='font-medium'>
{row.original.transaction}
</Typography>
</div>
)
}),
columnHelper.accessor('reference', {
header: 'Referensi',
cell: ({ row }) => <Chip label={row.original.reference} color='primary' variant='outlined' size='small' />
}),
columnHelper.accessor('total', {
header: () => <div className='text-right'>Jumlah Hutang</div>,
cell: ({ row }) => (
<div className='text-right'>
<Typography color='error' className='font-medium'>
{formatCurrency(row.original.total)}
</Typography>
</div>
)
})
],
// 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 (
<>
<Card>
<CardHeader title='Hutang yang Perlu Anda Bayar' className='pbe-4' />
<div className='flex justify-between flex-col items-start md:flex-row md:items-center p-6 border-bs gap-4'>
<CustomTextField
select
value={table.getState().pagination.pageSize}
onChange={e => table.setPageSize(Number(e.target.value))}
className='max-sm:is-full sm:is-[70px]'
>
<MenuItem value='10'>10</MenuItem>
<MenuItem value='25'>25</MenuItem>
<MenuItem value='50'>50</MenuItem>
</CustomTextField>
<div className='flex flex-col sm:flex-row max-sm:is-full items-start sm:items-center gap-4'>
<DebouncedInput
value={globalFilter ?? ''}
onChange={value => setGlobalFilter(String(value))}
placeholder='Cari Hutang'
className='max-sm:is-full'
/>
<Button
color='secondary'
variant='tonal'
startIcon={<i className='tabler-upload' />}
className='max-sm:is-full'
>
Ekspor
</Button>
</div>
</div>
<div className='overflow-x-auto'>
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
<div className='flex flex-col items-center gap-2 py-8'>
<Icon className='tabler-database-off text-4xl text-gray-400' />
<Typography variant='h6' color='text.secondary'>
Tidak ada hutang ditemukan
</Typography>
<Typography variant='body2' color='text.disabled'>
Cobalah mengubah filter pencarian
</Typography>
</div>
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
</div>
<TablePaginationComponent
pageIndex={table.getState().pagination.pageIndex}
pageSize={table.getState().pagination.pageSize}
totalCount={table.getFilteredRowModel().rows.length}
onPageChange={(_, page) => {
table.setPageIndex(page)
}}
/>
</Card>
</>
)
}
export default VendorDebsPayedTable

View File

@ -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 (
<Grid container spacing={6} className='mt-5'>
<Grid size={{ xs: 12 }}>
<VendorDebsPayedTable tableData={vendorDebsPayedData} />
</Grid>
</Grid>
)
}
export default VendorDebsPayed

View File

@ -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<unknown>
}
interface FilterMeta {
itemRank: RankingInfo
}
}
type VendorDebsPayedTypeWithAction = VendorDebsPayedType & {
action?: string
}
// Styled Components
const Icon = styled('i')({})
const fuzzyFilter: FilterFn<any> = (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<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)} />
}
// Column Definitions
const columnHelper = createColumnHelper<VendorDebsPayedTypeWithAction>()
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<ColumnDef<VendorDebsPayedTypeWithAction, any>[]>(
() => [
{
id: 'select',
header: ({ table }) => (
<Checkbox
{...{
checked: table.getIsAllRowsSelected(),
indeterminate: table.getIsSomeRowsSelected(),
onChange: table.getToggleAllRowsSelectedHandler()
}}
/>
),
cell: ({ row }) => (
<Checkbox
{...{
checked: row.getIsSelected(),
disabled: !row.getCanSelect(),
indeterminate: row.getIsSomeSelected(),
onChange: row.getToggleSelectedHandler()
}}
/>
)
},
columnHelper.accessor('date', {
header: 'Tanggal',
cell: ({ row }) => <Typography color='text.primary'>{row.original.date}</Typography>
}),
columnHelper.accessor('transaction', {
header: 'Keterangan Transaksi',
cell: ({ row }) => (
<div className='flex flex-col max-w-xs'>
<Typography color='text.primary' className='font-medium'>
{row.original.transaction}
</Typography>
</div>
)
}),
columnHelper.accessor('reference', {
header: 'Referensi',
cell: ({ row }) => <Chip label={row.original.reference} color='primary' variant='outlined' size='small' />
}),
columnHelper.accessor('total', {
header: () => <div className='text-right'>Jumlah Hutang</div>,
cell: ({ row }) => (
<div className='text-right'>
<Typography color='error' className='font-medium'>
{formatCurrency(row.original.total)}
</Typography>
</div>
)
})
],
// 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 (
<>
<Card>
<CardHeader title='Piutang menunggu pembayaran' className='pbe-4' />
<div className='flex justify-between flex-col items-start md:flex-row md:items-center p-6 border-bs gap-4'>
<CustomTextField
select
value={table.getState().pagination.pageSize}
onChange={e => table.setPageSize(Number(e.target.value))}
className='max-sm:is-full sm:is-[70px]'
>
<MenuItem value='10'>10</MenuItem>
<MenuItem value='25'>25</MenuItem>
<MenuItem value='50'>50</MenuItem>
</CustomTextField>
<div className='flex flex-col sm:flex-row max-sm:is-full items-start sm:items-center gap-4'>
<DebouncedInput
value={globalFilter ?? ''}
onChange={value => setGlobalFilter(String(value))}
placeholder='Cari'
className='max-sm:is-full'
/>
<Button
color='secondary'
variant='tonal'
startIcon={<i className='tabler-upload' />}
className='max-sm:is-full'
>
Ekspor
</Button>
</div>
</div>
<div className='overflow-x-auto'>
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
<div className='flex flex-col items-center gap-2 py-8'>
<Icon className='tabler-database-off text-4xl text-gray-400' />
<Typography variant='h6' color='text.secondary'>
Tidak ada hutang ditemukan
</Typography>
<Typography variant='body2' color='text.disabled'>
Cobalah mengubah filter pencarian
</Typography>
</div>
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
</div>
<TablePaginationComponent
pageIndex={table.getState().pagination.pageIndex}
pageSize={table.getState().pagination.pageSize}
totalCount={table.getFilteredRowModel().rows.length}
onPageChange={(_, page) => {
table.setPageIndex(page)
}}
/>
</Card>
</>
)
}
export default VendorReceivablesPaymentTable

View File

@ -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 (
<Grid container spacing={6} className='mt-5'>
<Grid size={{ xs: 12 }}>
<VendorReceivablesPaymentTable tableData={vendorReceivablesData} />
</Grid>
</Grid>
)
}
export default VendorReceivablesPayment

View File

@ -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<unknown>
}
interface FilterMeta {
itemRank: RankingInfo
}
}
type VendorTransactionTypeWithAction = VendorTransactionType & {
action?: string
}
// Styled Components
const Icon = styled('i')({})
const fuzzyFilter: FilterFn<any> = (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<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)} />
}
// 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<VendorTransactionTypeWithAction>()
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<ColumnDef<VendorTransactionTypeWithAction, any>[]>(
() => [
{
id: 'select',
header: ({ table }) => (
<Checkbox
{...{
checked: table.getIsAllRowsSelected(),
indeterminate: table.getIsSomeRowsSelected(),
onChange: table.getToggleAllRowsSelectedHandler()
}}
/>
),
cell: ({ row }) => (
<Checkbox
{...{
checked: row.getIsSelected(),
disabled: !row.getCanSelect(),
indeterminate: row.getIsSomeSelected(),
onChange: row.getToggleSelectedHandler()
}}
/>
)
},
columnHelper.accessor('date', {
header: 'Tanggal',
cell: ({ row }) => <Typography color='text.primary'>{row.original.date}</Typography>
}),
columnHelper.accessor('transaction', {
header: 'Keterangan Transaksi',
cell: ({ row }) => (
<div className='flex flex-col max-w-xs'>
<Typography color='text.primary' className='font-medium'>
{row.original.transaction}
</Typography>
</div>
)
}),
columnHelper.accessor('none', {
header: 'Referensi',
cell: ({ row }) => <Chip label={row.original.none} color='primary' variant='outlined' size='small' />
}),
columnHelper.accessor('total', {
header: () => <div className='text-right'>Jumlah</div>,
cell: ({ row }) => (
<div className='text-right'>
<Typography color='text.primary' className='font-medium'>
{formatCurrency(row.original.total)}
</Typography>
</div>
)
})
],
// 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 (
<>
<Card>
<CardHeader
title='Riwayat Transaksi Vendor'
className='pbe-4'
action={
<Chip
label={`Total: ${formatCurrency(totalAmount)}`}
color='primary'
variant='filled'
size='medium'
className='font-semibold'
/>
}
/>
<div className='flex justify-between flex-col items-start md:flex-row md:items-center p-6 border-bs gap-4'>
<CustomTextField
select
value={table.getState().pagination.pageSize}
onChange={e => table.setPageSize(Number(e.target.value))}
className='max-sm:is-full sm:is-[70px]'
>
<MenuItem value='10'>10</MenuItem>
<MenuItem value='25'>25</MenuItem>
<MenuItem value='50'>50</MenuItem>
</CustomTextField>
<div className='flex flex-col sm:flex-row max-sm:is-full items-start sm:items-center gap-4'>
<DebouncedInput
value={globalFilter ?? ''}
onChange={value => setGlobalFilter(String(value))}
placeholder='Cari Transaksi'
className='max-sm:is-full'
/>
<Button
color='secondary'
variant='tonal'
startIcon={<i className='tabler-upload' />}
className='max-sm:is-full'
>
Ekspor
</Button>
</div>
</div>
<div className='overflow-x-auto'>
<table className={tableStyles.table}>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : (
<>
<div
className={classnames({
'flex items-center': header.column.getIsSorted(),
'cursor-pointer select-none': header.column.getCanSort()
})}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{
asc: <i className='tabler-chevron-up text-xl' />,
desc: <i className='tabler-chevron-down text-xl' />
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
</div>
</>
)}
</th>
))}
</tr>
))}
</thead>
{table.getFilteredRowModel().rows.length === 0 ? (
<tbody>
<tr>
<td colSpan={table.getVisibleFlatColumns().length} className='text-center'>
<div className='flex flex-col items-center gap-2 py-8'>
<Icon className='tabler-database-off text-4xl text-gray-400' />
<Typography variant='h6' color='text.secondary'>
Tidak ada transaksi ditemukan
</Typography>
<Typography variant='body2' color='text.disabled'>
Cobalah mengubah filter pencarian
</Typography>
</div>
</td>
</tr>
</tbody>
) : (
<tbody>
{table
.getRowModel()
.rows.slice(0, table.getState().pagination.pageSize)
.map(row => {
return (
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
))}
</tr>
)
})}
</tbody>
)}
</table>
</div>
<TablePaginationComponent
pageIndex={table.getState().pagination.pageIndex}
pageSize={table.getState().pagination.pageSize}
totalCount={table.getFilteredRowModel().rows.length}
onPageChange={(_, page) => {
table.setPageIndex(page)
}}
/>
</Card>
</>
)
}
export default VendorTransactionTable

View File

@ -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 (
<Grid container spacing={6} className='mt-5'>
<Grid size={{ xs: 12 }}>
<VendorTransactionTable tableData={vendorTransactionData} />
</Grid>
</Grid>
)
}
export default VendorTransaction

View File

@ -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 (
<>
<Card>
<CardContent className='flex flex-col pbs-12 gap-6'>
<div className='flex flex-col gap-6'>
<div className='flex items-center justify-center flex-col gap-4'>
<div className='flex flex-col items-center gap-4'>
<CustomAvatar alt='user-profile' src='/images/avatars/1.png' variant='rounded' size={120} />
<Typography variant='h5'>{`${userData.firstName} ${userData.lastName}`}</Typography>
</div>
<Chip label='Vendor' color='primary' size='small' variant='tonal' />
</div>
</div>
{/* Detail Kontak Section */}
<div>
<Typography variant='h5'>Detail Kontak</Typography>
<Divider className='mlb-4' />
<div className='flex flex-col gap-2'>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Nama:
</Typography>
<Typography>{`${userData.firstName} ${userData.lastName}`}</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Perusahaan:
</Typography>
<Typography>{userData.perusahaan}</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Email:
</Typography>
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
{userData.email}
</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Telepon:
</Typography>
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
{userData.telepon}
</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Alamat Penagihan:
</Typography>
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
{userData.alamatPenagihan}
</Typography>
</div>
</div>
</div>
{/* Pemetaan Akun Section */}
<div>
<Typography variant='h5'>Pemetaan Akun</Typography>
<Divider className='mlb-4' />
<div className='flex flex-col gap-2'>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Akun Hutang:
</Typography>
<Typography color='primary' sx={{ textDecoration: 'none', cursor: 'pointer' }}>
{userData.akunHutang}
</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Akun Piutang:
</Typography>
<Typography color='text.secondary'>{userData.akunPiutang || '-'}</Typography>
</div>
<div className='flex items-center flex-wrap gap-x-1.5'>
<Typography className='font-medium' color='text.primary'>
Kena Pajak:
</Typography>
<Typography color='text.primary'>{userData.kenaPajak}</Typography>
</div>
</div>
</div>
</CardContent>
</Card>
</>
)
}
export default VendorDetails

View File

@ -0,0 +1,17 @@
// MUI Imports
import Grid from '@mui/material/Grid2'
// Component Imports
import VendorDetails from './VendorDetails'
const VendorOverview = () => {
return (
<Grid container spacing={6}>
<Grid size={{ xs: 12 }}>
<VendorDetails />
</Grid>
</Grid>
)
}
export default VendorOverview

View File

@ -161,7 +161,7 @@ const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => {
<div className='flex items-center gap-4'>
{getAvatar({ photo: row.original.photo, name: row.original.name })}
<div className='flex flex-col'>
<Link href={getLocalizedUrl(`/apps/vendor/view/${row.original.id}`, locale as Locale)}>
<Link href={getLocalizedUrl(`/apps/vendor/detail`, locale as Locale)}>
<Typography color='primary' className='font-medium cursor-pointer hover:underline'>
{row.original.name}
</Typography>