diff --git a/src/app/[lang]/(dashboard)/(private)/apps/expense/[id]/detail/page.tsx b/src/app/[lang]/(dashboard)/(private)/apps/expense/[id]/detail/page.tsx
new file mode 100644
index 0000000..68c6855
--- /dev/null
+++ b/src/app/[lang]/(dashboard)/(private)/apps/expense/[id]/detail/page.tsx
@@ -0,0 +1,18 @@
+import ExpenseDetailContent from '@/views/apps/expense/detail/ExpenseDetailContent'
+import ExpenseDetailHeader from '@/views/apps/expense/detail/ExpenseDetailHeader'
+import Grid from '@mui/material/Grid2'
+
+const ExpenseDetailPage = () => {
+ return (
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ExpenseDetailPage
diff --git a/src/views/apps/expense/detail/ExpenseDetailContent.tsx b/src/views/apps/expense/detail/ExpenseDetailContent.tsx
new file mode 100644
index 0000000..accf703
--- /dev/null
+++ b/src/views/apps/expense/detail/ExpenseDetailContent.tsx
@@ -0,0 +1,22 @@
+import Grid from '@mui/material/Grid2'
+import ExpenseDetailInformation from './ExpenseDetailInformation'
+import ExpenseDetailSendPayment from './ExpenseDetailSendPayment'
+import ExpenseDetailLog from './ExpenseDetailLog'
+
+const ExpenseDetailContent = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ExpenseDetailContent
diff --git a/src/views/apps/expense/detail/ExpenseDetailHeader.tsx b/src/views/apps/expense/detail/ExpenseDetailHeader.tsx
new file mode 100644
index 0000000..f0b5681
--- /dev/null
+++ b/src/views/apps/expense/detail/ExpenseDetailHeader.tsx
@@ -0,0 +1,15 @@
+import { Typography } from '@mui/material'
+
+const ExpenseDetailHeader = () => {
+ return (
+
+ )
+}
+
+export default ExpenseDetailHeader
diff --git a/src/views/apps/expense/detail/ExpenseDetailInformation.tsx b/src/views/apps/expense/detail/ExpenseDetailInformation.tsx
new file mode 100644
index 0000000..fe58ae7
--- /dev/null
+++ b/src/views/apps/expense/detail/ExpenseDetailInformation.tsx
@@ -0,0 +1,265 @@
+import React from 'react'
+import { Card, CardHeader, CardContent, Typography, Box, Button, IconButton } from '@mui/material'
+import Grid from '@mui/material/Grid2'
+
+interface Product {
+ produk: string
+ deskripsi: string
+ kuantitas: number
+ satuan: string
+ discount: string
+ harga: number
+ pajak: string
+ jumlah: number
+}
+
+interface PurchaseData {
+ vendor: string
+ nomor: string
+ tglTransaksi: string
+ tglJatuhTempo: string
+ gudang: string
+ status: string
+}
+
+const ExpenseDetailInformation: React.FC = () => {
+ const purchaseData: PurchaseData = {
+ vendor: 'Bagas Rizki Sihotang S.Farm Widodo',
+ nomor: 'PI/00053',
+ tglTransaksi: '08/09/2025',
+ tglJatuhTempo: '06/10/2025',
+ gudang: 'Unassigned',
+ status: 'Belum Dibayar'
+ }
+
+ const products: Product[] = [
+ {
+ produk: 'Komisi penjualan tim IT',
+ deskripsi: '6-60002 - Komisi & Fee (PPN)',
+ kuantitas: 1,
+ satuan: 'Pcs',
+ discount: '0%',
+ harga: 810000,
+ pajak: 'PPN',
+ jumlah: 810000
+ },
+ {
+ produk: 'Hotel Ibis 3 Malam, Surabaya',
+ deskripsi: '6-60004 - Perjalanan Dinas - Penjualan (PPN)',
+ kuantitas: 1,
+ satuan: 'Pcs',
+ discount: '0%',
+ harga: 400000,
+ pajak: 'PPN',
+ jumlah: 400000
+ },
+ {
+ produk: 'Biaya telp fixed',
+ deskripsi: '6-60005 - Komunikasi - Penjualan',
+ kuantitas: 1,
+ satuan: 'Pcs',
+ discount: '0%',
+ harga: 950000,
+ pajak: 'PPN',
+ jumlah: 950000
+ }
+ ]
+
+ const subTotal: number = products.reduce((sum, product) => sum + product.jumlah, 0)
+ const ppn: number = Math.round(subTotal * 0.11)
+ const total: number = subTotal + ppn
+ const sisaTagihan: number = total
+
+ const formatCurrency = (amount: number): string => {
+ return new Intl.NumberFormat('id-ID').format(amount)
+ }
+
+ return (
+
+
+
+ Belum Dibayar
+
+
+ } variant='outlined' size='small' sx={{ mr: 1 }}>
+ Bagikan
+
+ } variant='outlined' size='small' sx={{ mr: 1 }}>
+ Print
+
+
+
+
+
+
+ }
+ />
+
+
+ {/* Purchase Information */}
+
+
+
+
+ Penerima
+
+
+ {purchaseData.vendor}
+
+
+
+
+
+ Tgl. Transaksi
+
+ {purchaseData.tglTransaksi}
+
+
+
+
+
+
+ Nomor
+
+ {purchaseData.nomor}
+
+
+
+
+ Tgl. Jatuh Tempo
+
+ {purchaseData.tglJatuhTempo}
+
+
+
+
+ {/* Products List */}
+
+ {products.map((product, index) => (
+
+
+
+ {product.produk}
+
+
+ {product.deskripsi}
+
+
+
+
+ {formatCurrency(product.jumlah)}
+
+
+
+ ))}
+
+
+ {/* Summary Section */}
+
+
+ {/* Empty space for left side */}
+
+
+
+
+ Sub Total
+
+
+ {formatCurrency(subTotal)}
+
+
+
+
+
+ PPN
+
+
+ {formatCurrency(ppn)}
+
+
+
+
+
+ Total
+
+
+ {formatCurrency(total)}
+
+
+
+
+
+ Sisa Tagihan
+
+
+ {formatCurrency(sisaTagihan)}
+
+
+
+
+
+
+
+
+ )
+}
+
+export default ExpenseDetailInformation
diff --git a/src/views/apps/expense/detail/ExpenseDetailLog.tsx b/src/views/apps/expense/detail/ExpenseDetailLog.tsx
new file mode 100644
index 0000000..0ee010a
--- /dev/null
+++ b/src/views/apps/expense/detail/ExpenseDetailLog.tsx
@@ -0,0 +1,59 @@
+'use client'
+
+import React from 'react'
+import { Card, CardContent, CardHeader, Typography, Box, Link } from '@mui/material'
+
+interface LogEntry {
+ id: string
+ action: string
+ timestamp: string
+ user: string
+}
+
+const ExpenseDetailLog: React.FC = () => {
+ const logEntries: LogEntry[] = [
+ {
+ id: '1',
+ action: 'Terakhir diubah oleh',
+ timestamp: '08 Sep 2025 18:26',
+ user: 'pada'
+ }
+ ]
+
+ return (
+
+
+ Pantau log perubahan data
+
+ }
+ sx={{ pb: 1 }}
+ />
+
+ {logEntries.map(entry => (
+
+
+
+
+ {entry.action} {entry.user} {entry.timestamp}
+
+
+
+ ))}
+
+
+ )
+}
+
+export default ExpenseDetailLog
diff --git a/src/views/apps/expense/detail/ExpenseDetailSendPayment.tsx b/src/views/apps/expense/detail/ExpenseDetailSendPayment.tsx
new file mode 100644
index 0000000..8f2ac20
--- /dev/null
+++ b/src/views/apps/expense/detail/ExpenseDetailSendPayment.tsx
@@ -0,0 +1,417 @@
+'use client'
+
+import React, { useState } from 'react'
+import {
+ Card,
+ CardContent,
+ Typography,
+ Button,
+ Box,
+ Accordion,
+ AccordionSummary,
+ AccordionDetails,
+ Tooltip,
+ IconButton,
+ CardHeader
+} from '@mui/material'
+import Grid from '@mui/material/Grid2'
+import CustomTextField from '@/@core/components/mui/TextField'
+import CustomAutocomplete from '@/@core/components/mui/Autocomplete'
+
+interface PaymentFormData {
+ totalDibayar: string
+ tglTransaksi: string
+ referensi: string
+ nomor: string
+ dibayarDari: string
+}
+
+interface PemotonganItem {
+ id: string
+ dipotong: string
+ persentase: string
+ nominal: string
+ tipe: 'persen' | 'rupiah'
+}
+
+const ExpenseDetailSendPayment: React.FC = () => {
+ const [formData, setFormData] = useState({
+ totalDibayar: '849.000',
+ tglTransaksi: '10/09/2025',
+ referensi: '',
+ nomor: 'PP/00025',
+ dibayarDari: '1-10001 Kas'
+ })
+
+ const [expanded, setExpanded] = useState(false)
+ const [pemotonganItems, setPemotonganItems] = useState([])
+
+ const dibayarDariOptions = [
+ { label: '1-10001 Kas', value: '1-10001 Kas' },
+ { label: '1-10002 Bank BCA', value: '1-10002 Bank BCA' },
+ { label: '1-10003 Bank Mandiri', value: '1-10003 Bank Mandiri' },
+ { label: '1-10004 Petty Cash', value: '1-10004 Petty Cash' }
+ ]
+
+ const pemotonganOptions = [
+ { label: 'PPN 11%', value: 'ppn' },
+ { label: 'PPh 21', value: 'pph21' },
+ { label: 'PPh 23', value: 'pph23' },
+ { label: 'Biaya Admin', value: 'admin' }
+ ]
+
+ const handleChange =
+ (field: keyof PaymentFormData) => (event: React.ChangeEvent | any) => {
+ setFormData(prev => ({
+ ...prev,
+ [field]: event.target.value
+ }))
+ }
+
+ const handleDibayarDariChange = (value: { label: string; value: string } | null) => {
+ setFormData(prev => ({
+ ...prev,
+ dibayarDari: value?.value || ''
+ }))
+ }
+
+ const addPemotongan = () => {
+ const newItem: PemotonganItem = {
+ id: Date.now().toString(),
+ dipotong: '',
+ persentase: '0',
+ nominal: '',
+ tipe: 'persen'
+ }
+ setPemotonganItems(prev => [...prev, newItem])
+ }
+
+ const removePemotongan = (id: string) => {
+ setPemotonganItems(prev => prev.filter(item => item.id !== id))
+ }
+
+ const updatePemotongan = (id: string, field: keyof PemotonganItem, value: string) => {
+ setPemotonganItems(prev => prev.map(item => (item.id === id ? { ...item, [field]: value } : item)))
+ }
+
+ const handleAccordionChange = () => {
+ setExpanded(!expanded)
+ }
+
+ const calculatePemotongan = (item: PemotonganItem): number => {
+ const totalDibayar = parseInt(formData.totalDibayar.replace(/\D/g, '')) || 0
+ const nilai = parseFloat(item.persentase) || 0
+
+ if (item.tipe === 'persen') {
+ return (totalDibayar * nilai) / 100
+ } else {
+ return nilai
+ }
+ }
+
+ const formatCurrency = (amount: string | number): string => {
+ const numAmount = typeof amount === 'string' ? parseInt(amount.replace(/\D/g, '')) : amount
+ return new Intl.NumberFormat('id-ID').format(numAmount)
+ }
+
+ return (
+
+
+
+ Kirim Pembayaran
+
+
+ }
+ />
+
+
+ {/* Left Column */}
+
+ {/* Total Dibayar */}
+
+
+ * Total Dibayar
+
+ }
+ value={formData.totalDibayar}
+ onChange={handleChange('totalDibayar')}
+ sx={{
+ '& .MuiInputBase-root': {
+ textAlign: 'right'
+ }
+ }}
+ />
+
+
+ {/* Tgl. Transaksi */}
+
+
+ * Tgl. Transaksi
+
+ }
+ type='date'
+ value={formData.tglTransaksi.split('/').reverse().join('-')}
+ onChange={handleChange('tglTransaksi')}
+ slotProps={{
+ input: {
+ endAdornment:
+ }
+ }}
+ />
+
+
+ {/* Referensi */}
+
+
+
+ Referensi
+
+
+
+
+
+
+
+
+
+
+ {/* Attachment Accordion */}
+
+
+ }
+ sx={{
+ backgroundColor: '#f8f9fa',
+ borderRadius: '8px',
+ minHeight: '48px',
+ '& .MuiAccordionSummary-content': {
+ margin: '12px 0'
+ }
+ }}
+ >
+
+ Attachment
+
+
+
+
+ Drag and drop files here or click to upload
+
+
+
+
+
+ {/* Right Column */}
+
+ {/* Nomor */}
+
+
+
+ Nomor
+
+
+
+
+
+
+
+
+
+
+ {/* Dibayar Dari */}
+
+
+ * Dibayar Dari
+
+ option.label || ''}
+ value={dibayarDariOptions.find(option => option.value === formData.dibayarDari) || null}
+ onChange={(_, value: { label: string; value: string } | null) => handleDibayarDariChange(value)}
+ renderInput={(params: any) => }
+ noOptionsText='Tidak ada pilihan'
+ />
+
+
+ {/* Empty space to match Referensi height */}
+ {/* Empty space */}
+
+ {/* Pemotongan Button - aligned with Attachment */}
+
+ }
+ variant='text'
+ color='primary'
+ sx={{ textTransform: 'none' }}
+ onClick={addPemotongan}
+ >
+ Pemotongan
+
+
+
+
+
+ {/* Pemotongan Items */}
+ {pemotonganItems.length > 0 && (
+
+ {pemotonganItems.map((item, index) => (
+
+
+
+ removePemotongan(item.id)}
+ sx={{
+ backgroundColor: '#fff',
+ border: '1px solid #f44336',
+ '&:hover': { backgroundColor: '#ffebee' }
+ }}
+ >
+
+
+
+
+
+ option.label || ''}
+ value={pemotonganOptions.find(option => option.value === item.dipotong) || null}
+ onChange={(_, value: { label: string; value: string } | null) =>
+ updatePemotongan(item.id, 'dipotong', value?.value || '')
+ }
+ renderInput={(params: any) => }
+ noOptionsText='Tidak ada pilihan'
+ />
+
+
+
+ updatePemotongan(item.id, 'persentase', e.target.value)}
+ placeholder='0'
+ sx={{
+ '& .MuiInputBase-root': {
+ textAlign: 'center'
+ }
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+ {formatCurrency(calculatePemotongan(item))}
+
+
+
+
+
+ ))}
+
+ )}
+
+ {/* Bottom Section */}
+
+
+ {/* Empty space */}
+
+
+
+ Total
+
+
+ {formatCurrency(formData.totalDibayar)}
+
+
+
+ }
+ fullWidth
+ sx={{
+ py: 1.5,
+ textTransform: 'none',
+ fontWeight: 'medium'
+ }}
+ >
+ Tambah Pembayaran
+
+
+
+
+
+
+ )
+}
+
+export default ExpenseDetailSendPayment
diff --git a/src/views/apps/expense/list/ExpenseListTable.tsx b/src/views/apps/expense/list/ExpenseListTable.tsx
index 83d527f..16a87e4 100644
--- a/src/views/apps/expense/list/ExpenseListTable.tsx
+++ b/src/views/apps/expense/list/ExpenseListTable.tsx
@@ -244,7 +244,8 @@ const ExpenseListTable = () => {
variant='text'
color='primary'
className='p-0 min-w-0 font-medium normal-case justify-start'
- onClick={() => handleExpenseClick(row.original.id.toString())}
+ component={Link}
+ href={getLocalizedUrl(`/apps/expense/${row.original.id}/detail`, locale as Locale)}
sx={{
textTransform: 'none',
fontWeight: 500,