refactor: replace hardcoded URL strings with dynamic route helpers across services and frontend components.
This commit is contained in:
parent
2f8ece4b0a
commit
dfd2c5560b
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\EmployeeStatus;
|
||||
use App\Models\Attendance;
|
||||
use App\Models\Employee;
|
||||
use App\Services\System\PushNotificationService;
|
||||
@ -31,8 +30,7 @@ public function handle(PushNotificationService $pushNotificationService): int
|
||||
$scheduledCheckIn = Carbon::createFromFormat('Y-m-d H:i', $now->format('Y-m-d').' '.$scheduledTime);
|
||||
|
||||
$employees = Employee::query()
|
||||
->where('status', EmployeeStatus::ACTIVE)
|
||||
->whereNotNull('user_id')
|
||||
->whereHas('user', fn ($query) => $query->active())
|
||||
->get();
|
||||
|
||||
$sentCount = 0;
|
||||
@ -51,7 +49,7 @@ public function handle(PushNotificationService $pushNotificationService): int
|
||||
'⏰ Pengingat Presensi',
|
||||
"Jangan lupa melakukan presensi masuk sebelum pukul {$scheduledTime}.",
|
||||
$employee->user_id,
|
||||
'/admin/hr/attendances',
|
||||
route('admin.hr.attendances.index'),
|
||||
);
|
||||
|
||||
$sentCount++;
|
||||
|
||||
@ -97,7 +97,7 @@ public function deposit(CashAccount $cashAccount, array $validated, User $user):
|
||||
'💰 Setoran Kas',
|
||||
"Setoran kas baru {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer', 'admin-toko'],
|
||||
'/admin/finance/cash',
|
||||
route('admin.finance.cash.index'),
|
||||
);
|
||||
|
||||
return $transaction;
|
||||
@ -141,7 +141,7 @@ public function withdraw(CashAccount $cashAccount, array $validated, User $user)
|
||||
'🏦 Tarik Kas',
|
||||
"Tarik kas {$transaction->amount_formatted} dengan keterangan: {$transaction->description} oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer', 'admin-toko'],
|
||||
'/admin/finance/cash',
|
||||
route('admin.finance.cash.index'),
|
||||
);
|
||||
|
||||
return $transaction;
|
||||
@ -250,7 +250,7 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
|
||||
'✏️ Transaksi Kas Diperbarui',
|
||||
"Transaksi kas dengan keterangan {$transaction->description} diperbarui menjadi senilai {$transaction->amount_formatted}.",
|
||||
['owner', 'developer', 'admin-toko'],
|
||||
'/admin/finance/cash',
|
||||
route('admin.finance.cash.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ public function deleteTransaction(CashTransaction $transaction): void
|
||||
'🗑️ Transaksi Kas Dihapus',
|
||||
"Transaksi kas senilai {$transaction->amount_formatted} dengan keterangan {$transaction->description} telah dihapus.",
|
||||
['owner', 'developer', 'admin-toko'],
|
||||
'/admin/finance/cash',
|
||||
route('admin.finance.cash.index'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ public function create(array $validated, User $user): void
|
||||
'💰 Pengajuan Kasbon Baru',
|
||||
"Karyawan {$user->profil?->full_name} mengajukan kasbon sebesar {$employeeAdvance->amount_formatted} dengan keterangan: {$employeeAdvance->description}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/employee-advances',
|
||||
route('admin.finance.employee-advances.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated, User
|
||||
'✏️ Kasbon Diperbarui',
|
||||
"Kasbon sebesar {$employeeAdvance->amount_formatted} telah diperbarui oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/employee-advances',
|
||||
route('admin.finance.employee-advances.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ public function delete(EmployeeAdvance $employeeAdvance, User $user): void
|
||||
'🗑️ Kasbon Dihapus',
|
||||
"Kasbon sebesar {$amount} dengan keterangan {$description} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/employee-advances',
|
||||
route('admin.finance.employee-advances.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ public function approve(EmployeeAdvance $employeeAdvance, User $user): void
|
||||
'💰 Kasbon Disetujui',
|
||||
"Pengajuan kasbon Anda sebesar {$employeeAdvance->amount_formatted} telah disetujui.",
|
||||
$employeeAdvance->employee->user_id,
|
||||
'/admin/finance/employee-advances',
|
||||
route('admin.finance.employee-advances.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -187,7 +187,7 @@ public function reject(EmployeeAdvance $employeeAdvance, string $reason, User $u
|
||||
'💰 Kasbon Ditolak',
|
||||
"Pengajuan kasbon Anda sebesar {$employeeAdvance->amount_formatted} ditolak dengan alasan: {$reason}.",
|
||||
$employeeAdvance->employee->user_id,
|
||||
'/admin/finance/employee-advances',
|
||||
route('admin.finance.employee-advances.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ public function create(array $validated, User $user): void
|
||||
'💸 Pengeluaran Baru',
|
||||
"Pengeluaran baru sebesar {$expense->amount_formatted} dengan keterangan {$expense->description} telah dicatat oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/expenses',
|
||||
route('admin.finance.expenses.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ public function update(Expense $expense, array $validated): void
|
||||
'✏️ Pengeluaran Diperbarui',
|
||||
"Pengeluaran dengan keterangan {$expense->description} diperbarui menjadi sebesar {$expense->amount_formatted}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/expenses',
|
||||
route('admin.finance.expenses.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ public function delete(Expense $expense): void
|
||||
'🗑️ Pengeluaran Dihapus',
|
||||
"Pengeluaran sebesar {$expense->amount_formatted} dengan keterangan {$expense->description} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/finance/expenses',
|
||||
route('admin.finance.expenses.index'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -224,7 +224,7 @@ public function addAdjustment(Payroll $payroll, array $validated, User $user): v
|
||||
"📊 Penyesuaian Gaji: {$typeLabel}",
|
||||
"Gaji periode {$payroll->payrollPeriod->period_label} disesuaikan: {$typeLabel} sebesar {$formattedAmount} ({$validated['description']}).",
|
||||
$payroll->employee->user_id,
|
||||
'/admin/finance/payrolls',
|
||||
route('admin.finance.payroll.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -252,7 +252,7 @@ public function updateAdjustment(PayrollAdjustment $adjustment, array $validated
|
||||
"📊 Penyesuaian Gaji Diperbarui: {$typeLabel}",
|
||||
"Penyesuaian gaji Anda untuk periode {$payroll->payrollPeriod->period_label} diperbarui: {$typeLabel} menjadi {$formattedAmount} ({$validated['description']}).",
|
||||
$payroll->employee->user_id,
|
||||
'/admin/finance/payrolls',
|
||||
route('admin.finance.payroll.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -275,7 +275,7 @@ public function deleteAdjustment(PayrollAdjustment $adjustment): void
|
||||
'📊 Penyesuaian Gaji Dihapus',
|
||||
"Penyesuaian gaji Anda untuk periode {$payroll->payrollPeriod->period_label} telah dihapus.",
|
||||
$payroll->employee->user_id,
|
||||
'/admin/finance/payrolls',
|
||||
route('admin.finance.payroll.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -325,7 +325,7 @@ public function pay(Payroll $payroll, User $user): void
|
||||
'💸 Gaji Dibayarkan',
|
||||
"Gaji Anda untuk periode {$payroll->payrollPeriod->period_label} senilai {$payroll->total_amount_formatted} telah dibayarkan.",
|
||||
$payroll->employee->user_id,
|
||||
'/admin/finance/payrolls',
|
||||
route('admin.finance.payroll.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ public function checkIn(array $validated, User $user): void
|
||||
'⏰ Presensi Masuk',
|
||||
"Karyawan {$user->profile?->full_name} melakukan presensi masuk.",
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/attendances',
|
||||
route('admin.hr.attendances.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ public function checkOut(array $validated, User $user): void
|
||||
'⏰ Presensi Pulang',
|
||||
"Karyawan {$user->profile?->full_name} melakukan presensi pulang (Durasi kerja: ".round($workDurationMinutes / 60, 1).' jam).',
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/attendances',
|
||||
route('admin.hr.attendances.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -172,7 +172,7 @@ public function delete(Attendance $attendance): void
|
||||
'🗑️ Presensi Dihapus',
|
||||
"Data presensi {$employeeName} tanggal {$date} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/attendances',
|
||||
route('admin.hr.attendances.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ public function create(array $validated, User $user): void
|
||||
'🏖️ Pengajuan Cuti Baru',
|
||||
"Karyawan {$user->profile?->full_name} mengajukan cuti selama {$leaveRequest->total_days} hari mulai dari tanggal {$leaveRequest->start_date_formatted}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/leave-requests',
|
||||
route('admin.hr.leave_requests.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public function update(LeaveRequest $leaveRequest, array $validated, User $user)
|
||||
'✏️ Pengajuan Cuti Diperbarui',
|
||||
"Pengajuan cuti oleh {$user->profile?->full_name} telah diperbarui.",
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/leave-requests',
|
||||
route('admin.hr.leave_requests.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ public function delete(LeaveRequest $leaveRequest): void
|
||||
'🗑️ Pengajuan Cuti Dihapus',
|
||||
"Pengajuan cuti {$totalDays} hari oleh {$employeeName} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/hr/leave-requests',
|
||||
route('admin.hr.leave_requests.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ public function approve(LeaveRequest $leaveRequest, User $user): void
|
||||
'🏖️ Pengajuan Cuti Disetujui',
|
||||
"Pengajuan cuti Anda selama {$leaveRequest->total_days} hari ({$leaveRequest->start_date_formatted} - {$leaveRequest->end_date_formatted}) telah disetujui.",
|
||||
$leaveRequest->employee->user_id,
|
||||
'/admin/hr/leave-requests',
|
||||
route('admin.hr.leave_requests.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ public function reject(LeaveRequest $leaveRequest, string $reason, User $user):
|
||||
'🏖️ Pengajuan Cuti Ditolak',
|
||||
"Pengajuan cuti Anda selama {$leaveRequest->total_days} hari ({$leaveRequest->start_date_formatted} - {$leaveRequest->end_date_formatted}) ditolak dengan alasan: '{$reason}'.",
|
||||
$leaveRequest->employee->user_id,
|
||||
'/admin/hr/leave-requests',
|
||||
route('admin.hr.leave_requests.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -476,7 +476,7 @@ public function create(array $validated, User $user): Cutting
|
||||
'✂️ Proses Cutting Baru',
|
||||
"Proses cutting dengan deskripsi ({$cutting->description}) telah dimulai oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/cuttings',
|
||||
route('admin.manage.cuttings.index'),
|
||||
);
|
||||
|
||||
return $cutting;
|
||||
@ -536,7 +536,7 @@ public function update(Cutting $cutting, array $validated): void
|
||||
'✏️ Proses Cutting Diperbarui',
|
||||
"Proses cutting dengan deskripsi '{$description}' telah diperbarui.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/cuttings',
|
||||
route('admin.manage.cuttings.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -568,7 +568,7 @@ public function delete(Cutting $cutting): void
|
||||
'🗑️ Proses Cutting Dihapus',
|
||||
"Proses cutting dengan deskripsi {$description} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/cuttings',
|
||||
route('admin.manage.cuttings.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -655,7 +655,7 @@ public function transitionStatus(
|
||||
$title,
|
||||
$message,
|
||||
$roles,
|
||||
'/admin/manage/cuttings',
|
||||
route('admin.manage.cuttings.index'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -483,7 +483,7 @@ public function create(array $validated, User $user): Order
|
||||
'📦 Pesanan Baru',
|
||||
"Pesanan baru {$order->order_number} senilai {$order->total_amount_formatted} telah dibuat oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/orders',
|
||||
route('admin.manage.orders.index'),
|
||||
);
|
||||
|
||||
return $order;
|
||||
@ -563,7 +563,7 @@ public function update(Order $order, array $validated): void
|
||||
'✏️ Pesanan Diperbarui',
|
||||
"Pesanan {$order->order_number} senilai {$order->total_amount_formatted} telah diperbarui.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/orders',
|
||||
route('admin.manage.orders.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ public function delete(Order $order): void
|
||||
'🗑️ Pesanan Dihapus',
|
||||
"Pesanan {$orderNumber} senilai {$order->total_amount_formatted} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/orders',
|
||||
route('admin.manage.orders.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -627,7 +627,7 @@ public function transitionStatus(Order $order, OrderStatus $status): void
|
||||
'📦 Status Pesanan Diubah',
|
||||
"Pesanan {$order->order_number} diubah statusnya menjadi {$status->label()}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/orders',
|
||||
route('admin.manage.orders.index'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -253,7 +253,7 @@ public function create(array $validated, User $user): Purchase
|
||||
'🛒 Belanja Baru',
|
||||
"Pembelian dari supplier {$purchase->supplier->name} senilai {$purchase->total_formatted} telah ditambahkan oleh {$user->profile?->full_name}.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/purchases',
|
||||
route('admin.manage.purchases.index'),
|
||||
);
|
||||
|
||||
return $purchase;
|
||||
@ -301,7 +301,7 @@ public function update(Purchase $purchase, array $validated): void
|
||||
'✏️ Belanja Diperbarui',
|
||||
"Pembelian dari supplier {$purchase->supplier->name} senilai {$purchase->total_formatted} telah diperbarui.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/purchases',
|
||||
route('admin.manage.purchases.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -325,7 +325,7 @@ public function delete(Purchase $purchase): void
|
||||
'🗑️ Belanja Dihapus',
|
||||
"Pembelian dari supplier {$supplierName} senilai {$purchase->total_formatted} telah dihapus.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/purchases',
|
||||
route('admin.manage.purchases.index'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ public function submitVerification(
|
||||
'📦 Verifikasi Stok Menunggu Persetujuan',
|
||||
"Cutting dengan deskripsi '{$description}' telah diajukan verifikasi dan menunggu persetujuan owner.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/owner-verifications',
|
||||
route('admin.manage.owner_verifications.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ public function approveVerification(
|
||||
'📦 Stok Cutting Diverifikasi',
|
||||
"Cutting dengan deskripsi '{$description}' telah disetujui owner dan stok produk telah ditambahkan ke toko.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/owner-verifications',
|
||||
route('admin.manage.owner_verifications.index'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ public function rejectVerification(
|
||||
'📦 Verifikasi Cutting Ditolak Owner',
|
||||
"Cutting dengan deskripsi '{$description}' ditolak oleh owner dengan alasan: '{$reason}'.",
|
||||
['owner', 'developer'],
|
||||
'/admin/manage/owner-verifications',
|
||||
route('admin.manage.owner_verifications.index'),
|
||||
);
|
||||
|
||||
if ($cutting->submitted_by_id) {
|
||||
@ -202,7 +202,7 @@ public function rejectVerification(
|
||||
'📦 Verifikasi Cutting Ditolak Owner',
|
||||
"Cutting dengan deskripsi '{$description}' yang Anda verifikasi ditolak oleh owner dengan alasan: '{$reason}'.",
|
||||
$cutting->submitted_by_id,
|
||||
'/admin/manage/owner-verifications',
|
||||
route('admin.manage.owner_verifications.index'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
SidebarRail,
|
||||
} from '@/components/ui/sidebar';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import admin from '@/routes/admin';
|
||||
|
||||
const page = usePage();
|
||||
const { can } = useCan();
|
||||
@ -36,52 +37,52 @@ const menuGroups: MenuGroup[] = [
|
||||
{
|
||||
label: 'Menu',
|
||||
items: [
|
||||
{ title: 'Dasbor', href: '/admin/dashboard', icon: LayoutDashboard },
|
||||
{ title: 'Dasbor', href: admin.dashboard.url(), icon: LayoutDashboard },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Master',
|
||||
items: [
|
||||
{ title: 'Kategori', href: '/admin/master/categories', icon: FolderTree, permission: 'categories.view' },
|
||||
{ title: 'Produk', href: '/admin/master/products', icon: Package, permission: 'products.view' },
|
||||
{ title: 'Bahan Baku', href: '/admin/master/raw-materials', icon: Layers, permission: 'raw_materials.view' },
|
||||
{ title: 'Supplier', href: '/admin/master/suppliers', icon: User, permission: 'suppliers.view' },
|
||||
{ title: 'Customer', href: '/admin/master/customers', icon: UserCheck, permission: 'customers.view' },
|
||||
{ title: 'Kategori', href: admin.master.categories.index.url(), icon: FolderTree, permission: 'categories.view' },
|
||||
{ title: 'Produk', href: admin.master.products.index.url(), icon: Package, permission: 'products.view' },
|
||||
{ title: 'Bahan Baku', href: admin.master.raw_materials.index.url(), icon: Layers, permission: 'raw_materials.view' },
|
||||
{ title: 'Supplier', href: admin.master.suppliers.index.url(), icon: User, permission: 'suppliers.view' },
|
||||
{ title: 'Customer', href: admin.master.customers.index.url(), icon: UserCheck, permission: 'customers.view' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Kelola',
|
||||
items: [
|
||||
{ title: 'Belanja', href: '/admin/manage/purchases', icon: ShoppingBag, permission: 'purchases.view' },
|
||||
{ title: 'Cutting', href: '/admin/manage/cuttings', icon: Scissors, permission: 'cuttings.view' },
|
||||
{ title: 'Stok', href: '/admin/manage/stocks', icon: Warehouse, permission: 'stocks.view', badgeKey: 'pendingCuttings' },
|
||||
{ title: 'Verifikasi Owner', href: '/admin/manage/owner-verifications', icon: CheckCircle, permission: 'owner_verifications.view', badgeKey: 'pendingOwnerVerifications' },
|
||||
{ title: 'Pesanan', href: '/admin/manage/orders', icon: ShoppingCart, permission: 'orders.view' },
|
||||
{ title: 'Belanja', href: admin.manage.purchases.index.url(), icon: ShoppingBag, permission: 'purchases.view' },
|
||||
{ title: 'Cutting', href: admin.manage.cuttings.index.url(), icon: Scissors, permission: 'cuttings.view' },
|
||||
{ title: 'Stok', href: admin.manage.stocks.index.url(), icon: Warehouse, permission: 'stocks.view', badgeKey: 'pendingCuttings' },
|
||||
{ title: 'Verifikasi Owner', href: admin.manage.owner_verifications.index.url(), icon: CheckCircle, permission: 'owner_verifications.view', badgeKey: 'pendingOwnerVerifications' },
|
||||
{ title: 'Pesanan', href: admin.manage.orders.index.url(), icon: ShoppingCart, permission: 'orders.view' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Keuangan',
|
||||
items: [
|
||||
{ title: 'Kas Toko', href: '/admin/finance/cash', icon: Wallet, permission: 'cash.view' },
|
||||
{ title: 'Pengeluaran', href: '/admin/finance/expenses', icon: Receipt, permission: 'expenses.view' },
|
||||
{ title: 'Kasbon', href: '/admin/finance/employee-advances', icon: Banknote, permission: 'employee_advances.view', badgeKey: 'pendingEmployeeAdvances' },
|
||||
{ title: 'Gaji', href: '/admin/finance/payroll', icon: WalletCards, permission: 'payroll.view' },
|
||||
{ title: 'Kas Toko', href: admin.finance.cash.index.url(), icon: Wallet, permission: 'cash.view' },
|
||||
{ title: 'Pengeluaran', href: admin.finance.expenses.index.url(), icon: Receipt, permission: 'expenses.view' },
|
||||
{ title: 'Kasbon', href: admin.finance.employee_advances.index.url(), icon: Banknote, permission: 'employee_advances.view', badgeKey: 'pendingEmployeeAdvances' },
|
||||
{ title: 'Gaji', href: admin.finance.payroll.index.url(), icon: WalletCards, permission: 'payroll.view' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'HR',
|
||||
items: [
|
||||
{ title: 'Pegawai', href: '/admin/hr/employees', icon: Users, permission: 'employees.view' },
|
||||
{ title: 'Presensi', href: '/admin/hr/attendances', icon: Clock, permission: 'attendances.view' },
|
||||
{ title: 'Cuti', href: '/admin/hr/leave-requests', icon: CalendarDays, permission: 'leave_requests.view', badgeKey: 'pendingLeaveRequests' },
|
||||
{ title: 'Pegawai', href: admin.hr.employees.index.url(), icon: Users, permission: 'employees.view' },
|
||||
{ title: 'Presensi', href: admin.hr.attendances.index.url(), icon: Clock, permission: 'attendances.view' },
|
||||
{ title: 'Cuti', href: admin.hr.leave_requests.index.url(), icon: CalendarDays, permission: 'leave_requests.view', badgeKey: 'pendingLeaveRequests' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Sistem',
|
||||
items: [
|
||||
{ title: 'Role & Permission', href: '/admin/system/roles', icon: Shield, permission: 'roles.view' },
|
||||
{ title: 'Pengaturan', href: '/admin/system/settings', icon: Settings2, permission: 'settings.view' },
|
||||
{ title: 'Log Aktivitas', href: '/admin/system/activity-logs', icon: History, permission: 'activity_logs.view' },
|
||||
{ title: 'Role & Permission', href: admin.system.roles.index.url(), icon: Shield, permission: 'roles.view' },
|
||||
{ title: 'Pengaturan', href: admin.system.settings.index.url(), icon: Settings2, permission: 'settings.view' },
|
||||
{ title: 'Log Aktivitas', href: admin.system.activity_logs.index.url(), icon: History, permission: 'activity_logs.view' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@ -93,7 +94,7 @@ const menuGroups: MenuGroup[] = [
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton size="lg" as-child>
|
||||
<Link href="/admin/dashboard">
|
||||
<Link :href="admin.dashboard.url()">
|
||||
<img
|
||||
v-if="page.props.logo_url"
|
||||
:src="page.props.logo_url"
|
||||
|
||||
@ -13,6 +13,8 @@ import {
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { usePushNotification } from '@/composables/usePushNotification';
|
||||
import Separator from './ui/separator/Separator.vue';
|
||||
import { logout as logoutRoute } from '@/routes';
|
||||
import { profile } from '@/routes/admin/account';
|
||||
|
||||
const page = usePage();
|
||||
|
||||
@ -27,7 +29,7 @@ const initials = computed(() => {
|
||||
const { isSupported, isSubscribed, isLoading, toggle } = usePushNotification();
|
||||
|
||||
function logout() {
|
||||
router.post('/auth/logout');
|
||||
router.post(logoutRoute.url());
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -69,7 +71,7 @@ function logout() {
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem @click="router.visit('/admin/account/profile')">
|
||||
<DropdownMenuItem @click="router.visit(profile.url())">
|
||||
<User />
|
||||
Profil
|
||||
</DropdownMenuItem>
|
||||
|
||||
@ -5,23 +5,25 @@ import { computed } from 'vue';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
import { profile, password, appearance } from '@/routes/admin/account';
|
||||
|
||||
const page = usePage();
|
||||
|
||||
const currentPath = computed(() => page.url.split('?')[0]);
|
||||
|
||||
const navItems = [
|
||||
{
|
||||
href: '/admin/account/profile',
|
||||
href: profile.url(),
|
||||
label: 'Profil',
|
||||
icon: User,
|
||||
},
|
||||
{
|
||||
href: '/admin/account/password',
|
||||
href: password.url(),
|
||||
label: 'Kata Sandi',
|
||||
icon: KeyRound,
|
||||
},
|
||||
{
|
||||
href: '/admin/account/appearance',
|
||||
href: appearance.url(),
|
||||
label: 'Tampilan',
|
||||
icon: Palette,
|
||||
},
|
||||
|
||||
@ -19,6 +19,8 @@ import { formErrors } from '@/lib/form';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { AppearanceFormData, AppearanceMode } from '@/types/account';
|
||||
|
||||
import { update } from '@/routes/admin/account/appearance';
|
||||
|
||||
const props = defineProps<{
|
||||
appearance: AppearanceMode;
|
||||
}>();
|
||||
@ -63,7 +65,7 @@ function onAppearanceChange(value: AcceptableValue) {
|
||||
}
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/account/appearance', {
|
||||
form.put(update.url(), {
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan tampilan.');
|
||||
},
|
||||
|
||||
@ -17,6 +17,8 @@ import AccountLayout from '@/layouts/AccountLayout.vue';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { PasswordFormData } from '@/types/account';
|
||||
|
||||
import { update } from '@/routes/admin/account/password';
|
||||
|
||||
const form = useForm<PasswordFormData>({
|
||||
current_password: '',
|
||||
password: '',
|
||||
@ -28,7 +30,7 @@ const showPassword = ref(false);
|
||||
const showPasswordConfirmation = ref(false);
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/account/password', {
|
||||
form.put(update.url(), {
|
||||
onSuccess: () => {
|
||||
form.reset();
|
||||
},
|
||||
|
||||
@ -25,6 +25,8 @@ import type {
|
||||
ProfileUser,
|
||||
} from '@/types/account';
|
||||
|
||||
import { update } from '@/routes/admin/account/profile';
|
||||
|
||||
const props = defineProps<{
|
||||
user: ProfileUser;
|
||||
genders: EnumOption[];
|
||||
@ -41,7 +43,7 @@ const form = useForm<ProfileFormData>({
|
||||
});
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/account/profile', {
|
||||
form.put(update.url(), {
|
||||
preserveScroll: true,
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan profil. Periksa kembali formulir.');
|
||||
|
||||
@ -14,6 +14,7 @@ import type { CashAccount, CashTransactionListItem, PaginatedCashTransactions }
|
||||
import type { DataTableFilterDef, DataTableSort } from '@/types/data-table';
|
||||
import CashTransactionFormModal from './form/CashTransactionFormModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/finance/cash';
|
||||
|
||||
const props = defineProps<{
|
||||
cashAccount: CashAccount;
|
||||
@ -33,7 +34,7 @@ const formModalMode = ref<'deposit' | 'withdrawal'>(CashTransactionType.DEPOSIT)
|
||||
const editingTransaction = ref<CashTransactionListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: '/admin/finance/cash',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['reference_type'],
|
||||
});
|
||||
|
||||
@ -29,6 +29,8 @@ import { parseRupiah } from '@/lib/rupiah';
|
||||
import type { CashTransactionListItem } from '@/types/cash';
|
||||
import { appendRootPhotosToFormData, createMediaUploadState } from '@/types/media';
|
||||
import type { MediaUploadState } from '@/types/media';
|
||||
import { withdraw, deposit } from '@/routes/admin/finance/cash';
|
||||
import { update } from '@/routes/admin/finance/cash/transactions';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -111,12 +113,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.transaction) {
|
||||
form.transform(() => payload).put(`/admin/finance/cash/transactions/${props.transaction.id}`, options);
|
||||
form.transform(() => payload).put(update.url(props.transaction.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const endpoint = isWithdrawal.value ? '/admin/finance/cash/withdraw' : '/admin/finance/cash/deposit';
|
||||
const endpoint = isWithdrawal.value ? withdraw.url() : deposit.url();
|
||||
|
||||
form.transform(() => payload).post(endpoint, options);
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { CashTransactionListItem } from '@/types/cash';
|
||||
import { destroy } from '@/routes/admin/finance/cash/transactions';
|
||||
|
||||
const props = defineProps<{
|
||||
transaction: CashTransactionListItem;
|
||||
@ -27,7 +28,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyTransaction() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/finance/cash/transactions/${props.transaction.id}`, {
|
||||
router.delete(destroy.url(props.transaction.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -21,6 +21,8 @@ import EmployeeAdvanceFormModal from './form/EmployeeAdvanceFormModal.vue';
|
||||
import RejectEmployeeAdvanceModal from './form/RejectEmployeeAdvanceModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
|
||||
import { index } from '@/routes/admin/finance/employee_advances';
|
||||
|
||||
const props = defineProps<EmployeeAdvancePageProps>();
|
||||
|
||||
const { can } = useCan();
|
||||
@ -32,7 +34,7 @@ const rejectingEmployeeAdvance = ref<EmployeeAdvanceListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/finance/employee-advances',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['status'],
|
||||
});
|
||||
|
||||
@ -26,6 +26,7 @@ import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import { parseRupiah } from '@/lib/rupiah';
|
||||
import type { EmployeeAdvanceFormData, EmployeeAdvanceListItem } from '@/types/employee-advance';
|
||||
import { store, update } from '@/routes/admin/finance/employee_advances';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -94,12 +95,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.employeeAdvance) {
|
||||
form.transform(() => payload).put(`/admin/finance/employee-advances/${props.employeeAdvance.id}`, options);
|
||||
form.transform(() => payload).put(update.url(props.employeeAdvance.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.transform(() => payload).post('/admin/finance/employee-advances', options);
|
||||
form.transform(() => payload).post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { EmployeeAdvanceListItem } from '@/types/employee-advance';
|
||||
import { reject } from '@/routes/admin/finance/employee_advances';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -49,7 +50,7 @@ function submit() {
|
||||
return;
|
||||
}
|
||||
|
||||
form.post(`/admin/finance/employee-advances/${props.employeeAdvance.id}/reject`, {
|
||||
form.post(reject.url(props.employeeAdvance.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
open.value = false;
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { EmployeeAdvanceListItem } from '@/types/employee-advance';
|
||||
import { destroy, approve, pay } from '@/routes/admin/finance/employee_advances';
|
||||
|
||||
const props = defineProps<{
|
||||
employeeAdvance: EmployeeAdvanceListItem;
|
||||
@ -50,7 +51,7 @@ const payProcessing = ref(false);
|
||||
function destroyEmployeeAdvance() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/finance/employee-advances/${props.employeeAdvance.id}`, {
|
||||
router.delete(destroy.url(props.employeeAdvance.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -67,7 +68,7 @@ function destroyEmployeeAdvance() {
|
||||
function approveEmployeeAdvance() {
|
||||
approveProcessing.value = true;
|
||||
|
||||
router.post(`/admin/finance/employee-advances/${props.employeeAdvance.id}/approve`, {}, {
|
||||
router.post(approve.url(props.employeeAdvance.id), {}, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
approveConfirmOpen.value = false;
|
||||
@ -84,7 +85,7 @@ function approveEmployeeAdvance() {
|
||||
function payEmployeeAdvance() {
|
||||
payProcessing.value = true;
|
||||
|
||||
router.post(`/admin/finance/employee-advances/${props.employeeAdvance.id}/pay`, {}, {
|
||||
router.post(pay.url(props.employeeAdvance.id), {}, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
payConfirmOpen.value = false;
|
||||
|
||||
@ -15,6 +15,8 @@ import { computed, ref, watch } from 'vue';
|
||||
import ExpenseFormModal from './form/ExpenseFormModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
|
||||
import { index } from '@/routes/admin/finance/expenses';
|
||||
|
||||
const props = defineProps<{
|
||||
expenses: PaginatedExpenses;
|
||||
filters: {
|
||||
@ -31,7 +33,7 @@ const editingExpense = ref<ExpenseListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/finance/expenses',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
|
||||
@ -29,6 +29,8 @@ import type { ExpenseListItem } from '@/types/expense';
|
||||
import { appendRootPhotosToFormData, createMediaUploadState } from '@/types/media';
|
||||
import type { MediaUploadState } from '@/types/media';
|
||||
|
||||
import { store, update } from '@/routes/admin/finance/expenses';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
const props = defineProps<{
|
||||
@ -99,12 +101,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.expense) {
|
||||
form.transform(() => payload).put(`/admin/finance/expenses/${props.expense.id}`, options);
|
||||
form.transform(() => payload).put(update.url(props.expense.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.transform(() => payload).post('/admin/finance/expenses', options);
|
||||
form.transform(() => payload).post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { ExpenseListItem } from '@/types/expense';
|
||||
|
||||
import { destroy } from '@/routes/admin/finance/expenses';
|
||||
|
||||
const props = defineProps<{
|
||||
expense: ExpenseListItem;
|
||||
}>();
|
||||
@ -25,7 +27,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyExpense() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/finance/expenses/${props.expense.id}`, {
|
||||
router.delete(destroy.url(props.expense.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -27,6 +27,8 @@ import type { PayrollListItem, PayrollPageProps } from '@/types/payroll';
|
||||
import PayrollAdjustmentModal from './form/PayrollAdjustmentModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
|
||||
import { index } from '@/routes/admin/finance/payroll';
|
||||
|
||||
const props = defineProps<PayrollPageProps>();
|
||||
|
||||
const { can } = useCan();
|
||||
@ -48,7 +50,7 @@ const currentAdjustingPayroll = computed(() => {
|
||||
|
||||
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/finance/payroll',
|
||||
url: index.url(),
|
||||
initial: {
|
||||
...props.filters,
|
||||
period_id: props.filters.period_id
|
||||
|
||||
@ -31,6 +31,7 @@ import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import { parseRupiah } from '@/lib/rupiah';
|
||||
import type { PayrollAdjustmentFormData, PayrollAdjustmentItem, PayrollListItem, SelectOption } from '@/types/payroll';
|
||||
import { store, update, destroy } from '@/routes/admin/finance/payroll/adjustments';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -76,7 +77,7 @@ function cancelEdit() {
|
||||
}
|
||||
|
||||
function deleteAdj(adjustment: PayrollAdjustmentItem) {
|
||||
router.delete(`/admin/finance/payroll/adjustments/${adjustment.id}`, {
|
||||
router.delete(destroy.url(adjustment.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
toast.success('Penyesuaian berhasil dihapus.');
|
||||
@ -98,7 +99,7 @@ function submit() {
|
||||
}));
|
||||
|
||||
if (editingAdjustment.value) {
|
||||
payload.put(`/admin/finance/payroll/adjustments/${editingAdjustment.value.id}`, {
|
||||
payload.put(update.url(editingAdjustment.value.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
cancelEdit();
|
||||
@ -108,7 +109,7 @@ function submit() {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
payload.post(`/admin/finance/payroll/${props.payroll.id}/adjustments`, {
|
||||
payload.post(store.url(props.payroll.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
resetForm();
|
||||
|
||||
@ -14,6 +14,7 @@ import { useForm } from '@inertiajs/vue3';
|
||||
import { Camera, Loader2 } from '@lucide/vue';
|
||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { check_in, check_out } from '@/routes/admin/hr/attendances';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -44,8 +45,8 @@ const submitLabel = computed(() =>
|
||||
);
|
||||
const submitUrl = computed(() =>
|
||||
props.mode === 'check-in'
|
||||
? '/admin/hr/attendances/check-in'
|
||||
: '/admin/hr/attendances/check-out',
|
||||
? check_in.url()
|
||||
: check_out.url(),
|
||||
);
|
||||
|
||||
async function initializeCamera() {
|
||||
|
||||
@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { DatePicker } from '@/components/ui/date-picker';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { AttendanceListItem, CalendarRange } from '@/types/attendance';
|
||||
import { index } from '@/routes/admin/hr/attendances';
|
||||
|
||||
const props = defineProps<{
|
||||
attendances: AttendanceListItem[];
|
||||
@ -180,7 +181,7 @@ function handleDatesSet(arg: DatesSetArg) {
|
||||
|
||||
isNavigating.value = true;
|
||||
|
||||
router.get('/admin/hr/attendances', { start, end }, {
|
||||
router.get(index.url(), { start, end }, {
|
||||
preserveState: true,
|
||||
preserveScroll: true,
|
||||
only: ['attendances', 'calendarRange'],
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
} from '@/components/ui/dialog';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { AttendanceListItem } from '@/types/attendance';
|
||||
import { destroy } from '@/routes/admin/hr/attendances';
|
||||
|
||||
const open = defineModel<boolean>('open', { required: true });
|
||||
|
||||
@ -35,7 +36,7 @@ function destroyAttendance() {
|
||||
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/hr/attendances/${props.attendance.id}`, {
|
||||
router.delete(destroy.url(props.attendance.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { AttendanceListItem } from '@/types/attendance';
|
||||
import { destroy } from '@/routes/admin/hr/attendances';
|
||||
|
||||
const props = defineProps<{
|
||||
attendance: AttendanceListItem;
|
||||
@ -21,7 +22,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyAttendance() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/hr/attendances/${props.attendance.id}`, {
|
||||
router.delete(destroy.url(props.attendance.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -4,6 +4,7 @@ import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { EnumOption } from '@/types/employee';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import EmployeeForm from './form/EmployeeForm.vue';
|
||||
import { index, store } from '@/routes/admin/hr/employees';
|
||||
|
||||
defineProps<{
|
||||
genders: EnumOption[];
|
||||
@ -25,11 +26,11 @@ defineProps<{
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/hr/employees" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<EmployeeForm
|
||||
submit-url="/admin/hr/employees"
|
||||
:submit-url="store.url()"
|
||||
:genders="genders"
|
||||
:employment-statuses="employmentStatuses"
|
||||
:roles="roles"
|
||||
|
||||
@ -5,6 +5,7 @@ import type { EmployeeListItem, EnumOption } from '@/types/employee';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import EmployeeForm from './form/EmployeeForm.vue';
|
||||
import { index, update } from '@/routes/admin/hr/employees';
|
||||
|
||||
const props = defineProps<{
|
||||
employee: EmployeeListItem;
|
||||
@ -42,11 +43,11 @@ const initialData = computed(() => ({
|
||||
<h2 class="text-2xl font-bold tracking-tight">Ubah Pegawai</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/hr/employees" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<EmployeeForm
|
||||
:submit-url="`/admin/hr/employees/${employee.id}`"
|
||||
:submit-url="update.url(employee.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
:initial-data="initialData"
|
||||
|
||||
@ -14,6 +14,7 @@ import type { EnumOption, PaginatedEmployees } from '@/types/employee';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { columns } from './table/columns';
|
||||
import { index, create } from '@/routes/admin/hr/employees';
|
||||
|
||||
const props = defineProps<{
|
||||
employees: PaginatedEmployees;
|
||||
@ -36,7 +37,7 @@ const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/hr/employees',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['role', 'gender', 'employment_status', 'is_active'],
|
||||
});
|
||||
@ -123,7 +124,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('employees.create')"
|
||||
href="/admin/hr/employees/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
AlertDialogTrigger,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { reset_password } from '@/routes/admin/hr/employees';
|
||||
|
||||
const props = defineProps<{
|
||||
employeeId: number;
|
||||
@ -29,7 +30,7 @@ const processing = ref(false);
|
||||
function resetPassword() {
|
||||
processing.value = true;
|
||||
|
||||
router.post(`/admin/hr/employees/${props.employeeId}/reset-password`, {}, {
|
||||
router.post(reset_password.url(props.employeeId), {}, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
open.value = false;
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { EmployeeListItem } from '@/types/employee';
|
||||
import { edit, destroy, reset_password } from '@/routes/admin/hr/employees';
|
||||
|
||||
const props = defineProps<{
|
||||
employee: EmployeeListItem;
|
||||
@ -25,7 +26,7 @@ const resetPasswordProcessing = ref(false);
|
||||
function destroyEmployee() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/hr/employees/${props.employee.id}`, {
|
||||
router.delete(destroy.url(props.employee.id), {
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
},
|
||||
@ -41,7 +42,7 @@ function destroyEmployee() {
|
||||
function resetPassword() {
|
||||
resetPasswordProcessing.value = true;
|
||||
|
||||
router.post(`/admin/hr/employees/${props.employee.id}/reset-password`, {}, {
|
||||
router.post(reset_password.url(props.employee.id), {}, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
resetPasswordConfirmOpen.value = false;
|
||||
@ -61,7 +62,7 @@ function resetPassword() {
|
||||
<Tooltip v-if="can('employees.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/hr/employees/${employee.id}/edit`">
|
||||
<Link :href="edit.url(employee.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { EmployeeListItem } from '@/types/employee';
|
||||
import { toggle_status } from '@/routes/admin/hr/employees';
|
||||
|
||||
const props = defineProps<{
|
||||
employee: EmployeeListItem;
|
||||
@ -32,7 +33,7 @@ function toggleStatus(checked: boolean) {
|
||||
isActive.value = checked;
|
||||
processing.value = true;
|
||||
|
||||
router.patch(`/admin/hr/employees/${props.employee.id}/toggle-status`, {
|
||||
router.patch(toggle_status.url(props.employee.id), {
|
||||
is_active: checked,
|
||||
}, {
|
||||
preserveScroll: true,
|
||||
|
||||
@ -18,6 +18,7 @@ import { computed, ref, watch } from 'vue';
|
||||
import LeaveRequestFormModal from './form/LeaveRequestFormModal.vue';
|
||||
import RejectLeaveRequestModal from './form/RejectLeaveRequestModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/hr/leave_requests';
|
||||
|
||||
const props = defineProps<LeaveRequestPageProps>();
|
||||
|
||||
@ -30,7 +31,7 @@ const rejectingLeaveRequest = ref<LeaveRequestListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/hr/leave-requests',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
import { useFormDialog } from '@/composables/useFormDialog';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { LeaveRequestFormData, LeaveRequestListItem } from '@/types/leave-request';
|
||||
import { store, update } from '@/routes/admin/hr/leave_requests';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -71,12 +72,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.leaveRequest) {
|
||||
form.put(`/admin/hr/leave-requests/${props.leaveRequest.id}`, options);
|
||||
form.put(update.url(props.leaveRequest.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.post('/admin/hr/leave-requests', options);
|
||||
form.post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { LeaveRequestListItem } from '@/types/leave-request';
|
||||
import { reject } from '@/routes/admin/hr/leave_requests';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -49,7 +50,7 @@ function submit() {
|
||||
return;
|
||||
}
|
||||
|
||||
form.post(`/admin/hr/leave-requests/${props.leaveRequest.id}/reject`, {
|
||||
form.post(reject.url(props.leaveRequest.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
open.value = false;
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { LeaveRequestListItem } from '@/types/leave-request';
|
||||
import { destroy, approve } from '@/routes/admin/hr/leave_requests';
|
||||
|
||||
const props = defineProps<{
|
||||
leaveRequest: LeaveRequestListItem;
|
||||
@ -48,7 +49,7 @@ const approveProcessing = ref(false);
|
||||
function destroyLeaveRequest() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/hr/leave-requests/${props.leaveRequest.id}`, {
|
||||
router.delete(destroy.url(props.leaveRequest.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -65,7 +66,7 @@ function destroyLeaveRequest() {
|
||||
function approveLeaveRequest() {
|
||||
approveProcessing.value = true;
|
||||
|
||||
router.post(`/admin/hr/leave-requests/${props.leaveRequest.id}/approve`, {}, {
|
||||
router.post(approve.url(props.leaveRequest.id), {}, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
approveConfirmOpen.value = false;
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
} from '@/types/cutting';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import CuttingPosForm from './form/CuttingPosForm.vue';
|
||||
import { index, store } from '@/routes/admin/manage/cuttings';
|
||||
|
||||
defineProps<{
|
||||
rawMaterialCatalog: CuttingRawMaterialCatalogItem[];
|
||||
@ -31,7 +32,7 @@ defineProps<{
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/cuttings" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<CuttingPosForm
|
||||
@ -39,7 +40,7 @@ defineProps<{
|
||||
:product-catalog="productCatalog"
|
||||
:draft-materials="draftMaterials"
|
||||
:draft-results="draftResults"
|
||||
submit-url="/admin/manage/cuttings"
|
||||
:submit-url="store.url()"
|
||||
method="post"
|
||||
submit-label="Simpan"
|
||||
/>
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import CuttingPosForm from './form/CuttingPosForm.vue';
|
||||
import { index, update } from '@/routes/admin/manage/cuttings';
|
||||
|
||||
const props = defineProps<{
|
||||
cutting: CuttingEditItem;
|
||||
@ -56,14 +57,14 @@ const initialData = computed(() => ({
|
||||
<h2 class="text-2xl font-bold tracking-tight">Ubah Cutting</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/cuttings" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<CuttingPosForm
|
||||
:raw-material-catalog="rawMaterialCatalog"
|
||||
:product-catalog="productCatalog"
|
||||
:initial-data="initialData"
|
||||
:submit-url="`/admin/manage/cuttings/${cutting.id}`"
|
||||
:submit-url="update.url(props.cutting.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
/>
|
||||
|
||||
@ -12,6 +12,7 @@ import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import CuttingGroupedTable from './table/CuttingGroupedTable.vue';
|
||||
import CuttingInProgressSection from './table/CuttingInProgressSection.vue';
|
||||
import { index, create } from '@/routes/admin/manage/cuttings';
|
||||
|
||||
const props = defineProps<{
|
||||
cuttings: PaginatedCuttings;
|
||||
@ -27,7 +28,7 @@ const { can, hasAnyRole } = useCan();
|
||||
const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { setSearch, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: '/admin/manage/cuttings',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
@ -71,7 +72,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('cuttings.create')"
|
||||
href="/admin/manage/cuttings/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ import type {
|
||||
} from '@/types/cutting';
|
||||
import PosCatalogCard from '../../shared/PosCatalogCard.vue';
|
||||
import PosCatalogVariantThumb from '../../shared/PosCatalogVariantThumb.vue';
|
||||
import draft_materials from '@/routes/admin/manage/cuttings/draft_materials';
|
||||
import draft_results from '@/routes/admin/manage/cuttings/draft_results';
|
||||
|
||||
const props = defineProps<{
|
||||
rawMaterialCatalog: CuttingRawMaterialCatalogItem[];
|
||||
@ -245,7 +247,7 @@ function upsertResultCartItem(item: CuttingResultCartItem) {
|
||||
}
|
||||
|
||||
async function syncDraftMaterial(rawMaterial: CuttingRawMaterialCatalogItem, price: CatalogPrice, materialUsage: string, remainingMaterial: string) {
|
||||
const { item } = await apiFetch<{ item: CuttingMaterialCartItem }>('/admin/manage/cuttings/draft-materials', {
|
||||
const { item } = await apiFetch<{ item: CuttingMaterialCartItem }>(draft_materials.store.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
raw_material_price_id: price.id,
|
||||
@ -258,7 +260,7 @@ async function syncDraftMaterial(rawMaterial: CuttingRawMaterialCatalogItem, pri
|
||||
}
|
||||
|
||||
async function syncDraftResult(product: CuttingProductCatalogItem, variant: CuttingProductCatalogItem['variants'][number], cuttingResult: string, warehouseStock: string, cuttingReject: string) {
|
||||
const { item } = await apiFetch<{ item: CuttingResultCartItem }>('/admin/manage/cuttings/draft-results', {
|
||||
const { item } = await apiFetch<{ item: CuttingResultCartItem }>(draft_results.store.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
product_variant_id: variant.id,
|
||||
@ -371,7 +373,7 @@ async function removeMaterial(index: number) {
|
||||
if (isCreateMode.value) {
|
||||
try {
|
||||
await apiFetch(
|
||||
`/admin/manage/cuttings/draft-materials/${item.raw_material_price_id}`,
|
||||
draft_materials.destroy.url(item.raw_material_price_id),
|
||||
{ method: 'DELETE' },
|
||||
);
|
||||
} catch (error) {
|
||||
@ -487,7 +489,7 @@ async function removeResult(index: number) {
|
||||
if (isCreateMode.value) {
|
||||
try {
|
||||
await apiFetch(
|
||||
`/admin/manage/cuttings/draft-results/${item.product_variant_id}`,
|
||||
draft_results.destroy.url(item.product_variant_id),
|
||||
{ method: 'DELETE' },
|
||||
);
|
||||
} catch (error) {
|
||||
@ -516,7 +518,7 @@ async function syncMaterialField(index: number) {
|
||||
const item = materialCart.value[index];
|
||||
|
||||
try {
|
||||
await apiFetch<{ item: CuttingMaterialCartItem }>('/admin/manage/cuttings/draft-materials', {
|
||||
await apiFetch<{ item: CuttingMaterialCartItem }>(draft_materials.store.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
raw_material_price_id: item.raw_material_price_id,
|
||||
@ -537,7 +539,7 @@ async function syncResultField(index: number) {
|
||||
const item = resultCart.value[index];
|
||||
|
||||
try {
|
||||
await apiFetch<{ item: CuttingResultCartItem }>('/admin/manage/cuttings/draft-results', {
|
||||
await apiFetch<{ item: CuttingResultCartItem }>(draft_results.store.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
product_variant_id: item.product_variant_id,
|
||||
|
||||
@ -38,6 +38,8 @@ import {
|
||||
PRICE_TYPE_LABELS,
|
||||
} from '@/types/product';
|
||||
import type { CuttingListItem, CuttingStatusAction } from '@/types/cutting';
|
||||
import { edit, destroy, transition_status } from '@/routes/admin/manage/cuttings';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
|
||||
const props = defineProps<{
|
||||
cutting: CuttingListItem;
|
||||
@ -152,7 +154,7 @@ const canEdit = computed(
|
||||
() => props.cutting.is_editable && can('cuttings.update'),
|
||||
);
|
||||
const canDelete = computed(
|
||||
() => can('cuttings.delete') && [CuttingStatus.IN_PROGRESS, CuttingStatus.REJECTED].includes(props.cutting.status),
|
||||
() => can('cuttings.delete') && (props.cutting.status === CuttingStatus.IN_PROGRESS || props.cutting.status === CuttingStatus.REJECTED),
|
||||
);
|
||||
|
||||
function canPerformAction(action: CuttingStatusAction): boolean {
|
||||
@ -206,7 +208,7 @@ function submitVerify() {
|
||||
})),
|
||||
result_prices: buildResultPricesPayload(),
|
||||
}))
|
||||
.post(`/admin/manage/cuttings/${props.cutting.id}/status`, {
|
||||
.post(transition_status.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
verifyDialogOpen.value = false;
|
||||
@ -231,7 +233,7 @@ function transitionStatus() {
|
||||
statusProcessing.value = true;
|
||||
|
||||
router.post(
|
||||
`/admin/manage/cuttings/${props.cutting.id}/status`,
|
||||
transition_status.url(props.cutting.id),
|
||||
{
|
||||
status: pendingAction.value.status,
|
||||
},
|
||||
@ -258,7 +260,7 @@ function transitionStatus() {
|
||||
}
|
||||
|
||||
function submitReject() {
|
||||
rejectForm.post(`/admin/manage/cuttings/${props.cutting.id}/status`, {
|
||||
rejectForm.post(transition_status.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
rejectDialogOpen.value = false;
|
||||
@ -285,7 +287,7 @@ watch(rejectDialogOpen, (isOpen) => {
|
||||
function destroyCutting() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/manage/cuttings/${props.cutting.id}`, {
|
||||
router.delete(destroy.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -348,7 +350,7 @@ function actionIcon(status: string) {
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/manage/cuttings/${cutting.id}/edit`">
|
||||
<Link :href="edit.url(cutting.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -10,6 +10,7 @@ import type {
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import OrderPosForm from './form/OrderPosForm.vue';
|
||||
import { index, store } from '@/routes/admin/manage/orders';
|
||||
|
||||
const props = defineProps<{
|
||||
customers: SelectOption[];
|
||||
@ -41,7 +42,7 @@ function onCustomerCreated(customer: { id: number; name: string }) {
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/orders" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<OrderPosForm
|
||||
@ -52,7 +53,7 @@ function onCustomerCreated(customer: { id: number; name: string }) {
|
||||
:store-price-types="storePriceTypes"
|
||||
:payment-types="paymentTypes"
|
||||
:draft-items="draftItems"
|
||||
submit-url="/admin/manage/orders"
|
||||
:submit-url="store.url()"
|
||||
method="post"
|
||||
submit-label="Simpan"
|
||||
@customer-created="onCustomerCreated"
|
||||
|
||||
@ -10,6 +10,7 @@ import type {
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref } from 'vue';
|
||||
import OrderPosForm from './form/OrderPosForm.vue';
|
||||
import { index, update } from '@/routes/admin/manage/orders';
|
||||
|
||||
const props = defineProps<{
|
||||
order: OrderEditItem;
|
||||
@ -69,7 +70,7 @@ function onCustomerCreated(customer: { id: number; name: string }) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/orders" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<OrderPosForm
|
||||
@ -80,7 +81,7 @@ function onCustomerCreated(customer: { id: number; name: string }) {
|
||||
:store-price-types="storePriceTypes"
|
||||
:payment-types="paymentTypes"
|
||||
:initial-data="initialData"
|
||||
:submit-url="`/admin/manage/orders/${order.id}`"
|
||||
:submit-url="update.url(props.order.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
@customer-created="onCustomerCreated"
|
||||
|
||||
@ -16,6 +16,7 @@ import type { PaginatedOrders } from '@/types/order';
|
||||
import { Head, usePage } from '@inertiajs/vue3';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { index, create } from '@/routes/admin/manage/orders';
|
||||
import ThermalPrinterConnectButton from './form/ThermalPrinterConnectButton.vue';
|
||||
import OrderGroupedTable from './table/OrderGroupedTable.vue';
|
||||
|
||||
@ -34,7 +35,7 @@ const { isConnected, printOrderReceipt, tryReconnect } = useThermalPrinter();
|
||||
const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { setSearch, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: '/admin/manage/orders',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
@ -125,7 +126,7 @@ onMounted(async () => {
|
||||
>
|
||||
<ThermalPrinterConnectButton />
|
||||
|
||||
<CreateButton href="/admin/manage/orders/create" />
|
||||
<CreateButton :href="create.url()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ import { OrderStatus } from '@/constants/order-status';
|
||||
import { StockQuality } from '@/constants/stock-quality';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { OrderDetail, OrderStatusAction } from '@/types/order';
|
||||
import { index, edit, destroy, transition_status } from '@/routes/admin/manage/orders';
|
||||
|
||||
const props = defineProps<{
|
||||
order: OrderDetail;
|
||||
@ -97,7 +98,7 @@ function transitionStatus() {
|
||||
|
||||
statusProcessing.value = true;
|
||||
|
||||
router.post(`/admin/manage/orders/${props.order.id}/status`, {
|
||||
router.post(transition_status.url(props.order.id), {
|
||||
status: pendingAction.value.status,
|
||||
}, {
|
||||
onSuccess: () => {
|
||||
@ -117,7 +118,7 @@ function transitionStatus() {
|
||||
function destroyOrder() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/manage/orders/${props.order.id}`, {
|
||||
router.delete(destroy.url(props.order.id), {
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
},
|
||||
@ -239,7 +240,7 @@ const feeEntries = computed(() => {
|
||||
</template>
|
||||
|
||||
<Button v-if="canEdit" variant="outline" size="sm" as-child>
|
||||
<Link :href="`/admin/manage/orders/${order.id}/edit`">
|
||||
<Link :href="edit.url(props.order.id)">
|
||||
<Pencil class="size-3.5" />
|
||||
Ubah
|
||||
</Link>
|
||||
@ -256,7 +257,7 @@ const feeEntries = computed(() => {
|
||||
Hapus
|
||||
</Button>
|
||||
|
||||
<BackButton href="/admin/manage/orders" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { Save } from '@lucide/vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { PhoneNumberInput } from '@/components/form/phone-number-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@ -22,6 +19,10 @@ import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { apiFetch } from '@/lib/api';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { Save } from '@lucide/vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { api } from '@/routes/admin/master/customers/store';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -50,21 +51,25 @@ async function submit() {
|
||||
processing.value = true;
|
||||
|
||||
try {
|
||||
const customer = await apiFetch<{ id: number; name: string }>('/admin/master/customers/api', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: form.name,
|
||||
phone_number: form.phone_number || null,
|
||||
address: form.address || null,
|
||||
}),
|
||||
});
|
||||
const customer = await apiFetch<{ id: number; name: string }>(
|
||||
api.url(),
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name: form.name,
|
||||
phone_number: form.phone_number || null,
|
||||
address: form.address || null,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
emit('created', customer);
|
||||
open.value = false;
|
||||
resetForm();
|
||||
toast.success('Pelanggan berhasil ditambahkan.');
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Gagal menyimpan data.';
|
||||
const message =
|
||||
error instanceof Error ? error.message : 'Gagal menyimpan data.';
|
||||
|
||||
if (message.includes('nama')) {
|
||||
errors.name = message;
|
||||
@ -88,26 +93,53 @@ async function submit() {
|
||||
<FieldGroup>
|
||||
<FieldSet class="grid gap-4">
|
||||
<Field>
|
||||
<FieldLabel for="quick-customer-name" required>Nama</FieldLabel>
|
||||
<Input id="quick-customer-name" v-model="form.name" type="text"
|
||||
placeholder="Contoh: Budi Santoso" autofocus :maxlength="FIELD_LIMITS.name" />
|
||||
<FieldError v-if="errors.name" :errors="[errors.name]" />
|
||||
<FieldLabel for="quick-customer-name" required
|
||||
>Nama</FieldLabel
|
||||
>
|
||||
<Input
|
||||
id="quick-customer-name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
placeholder="Contoh: Budi Santoso"
|
||||
autofocus
|
||||
:maxlength="FIELD_LIMITS.name"
|
||||
/>
|
||||
<FieldError
|
||||
v-if="errors.name"
|
||||
:errors="[errors.name]"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="quick-customer-phone">Nomor Telepon</FieldLabel>
|
||||
<PhoneNumberInput id="quick-customer-phone" v-model="form.phone_number"
|
||||
placeholder="Contoh: 08123456789" />
|
||||
<FieldLabel for="quick-customer-phone"
|
||||
>Nomor Telepon</FieldLabel
|
||||
>
|
||||
<PhoneNumberInput
|
||||
id="quick-customer-phone"
|
||||
v-model="form.phone_number"
|
||||
placeholder="Contoh: 08123456789"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="quick-customer-address">Alamat</FieldLabel>
|
||||
<Textarea id="quick-customer-address" v-model="form.address" rows="3"
|
||||
placeholder="Contoh: Jl. Mawar No. 12, Surabaya" />
|
||||
<FieldLabel for="quick-customer-address"
|
||||
>Alamat</FieldLabel
|
||||
>
|
||||
<Textarea
|
||||
id="quick-customer-address"
|
||||
v-model="form.address"
|
||||
rows="3"
|
||||
placeholder="Contoh: Jl. Mawar No. 12, Surabaya"
|
||||
/>
|
||||
</Field>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
|
||||
<DialogFooter class="mt-6">
|
||||
<Button type="button" variant="outline" :disabled="processing" @click="open = false">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
:disabled="processing"
|
||||
@click="open = false"
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button type="submit" :disabled="processing">
|
||||
|
||||
@ -55,6 +55,7 @@ import type { ProductPriceItem, ProductVariantItem } from '@/types/product';
|
||||
import PosCatalogCard from '../../shared/PosCatalogCard.vue';
|
||||
import PosCatalogVariantThumb from '../../shared/PosCatalogVariantThumb.vue';
|
||||
import CustomerQuickCreateModal from './CustomerQuickCreateModal.vue';
|
||||
import { store as syncDraftRoute, resync_prices as resyncPricesRoute, destroy as destroyDraftRoute } from '@/routes/admin/manage/orders/draft_items';
|
||||
|
||||
const props = defineProps<{
|
||||
customers: SelectOption[];
|
||||
@ -200,7 +201,7 @@ watch(
|
||||
|
||||
try {
|
||||
const { items } = await apiFetch<{ items: OrderCartItem[] }>(
|
||||
'/admin/manage/orders/draft-items/resync-prices',
|
||||
resyncPricesRoute.url(),
|
||||
{
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ price_type: priceType }),
|
||||
@ -286,7 +287,7 @@ function lineSubtotal(item: OrderCartItem): number {
|
||||
}
|
||||
|
||||
async function syncDraftItem(variantId: number, quantity: number, stockQuality = selectedStockQuality.value) {
|
||||
const { item } = await apiFetch<{ item: OrderCartItem }>('/admin/manage/orders/draft-items', {
|
||||
const { item } = await apiFetch<{ item: OrderCartItem }>(syncDraftRoute.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
product_variant_id: variantId,
|
||||
@ -364,7 +365,9 @@ async function removeFromCart(index: number) {
|
||||
if (isCreateMode.value) {
|
||||
try {
|
||||
await apiFetch(
|
||||
`/admin/manage/orders/draft-items/${item.product_variant_id}?stock_quality=${item.stock_quality}`,
|
||||
destroyDraftRoute.url(item.product_variant_id, {
|
||||
query: { stock_quality: item.stock_quality }
|
||||
}),
|
||||
{
|
||||
method: 'DELETE',
|
||||
},
|
||||
|
||||
@ -10,6 +10,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import { OrderStatus } from '@/constants/order-status';
|
||||
import type { OrderListItem, OrderStatusAction } from '@/types/order';
|
||||
import { show, edit, destroy, transition_status } from '@/routes/admin/manage/orders';
|
||||
|
||||
const props = defineProps<{
|
||||
order: OrderListItem;
|
||||
@ -56,7 +57,7 @@ function transitionStatus() {
|
||||
|
||||
statusProcessing.value = true;
|
||||
|
||||
router.post(`/admin/manage/orders/${props.order.id}/status`, {
|
||||
router.post(transition_status.url(props.order.id), {
|
||||
status: pendingAction.value.status,
|
||||
}, {
|
||||
preserveScroll: true,
|
||||
@ -78,7 +79,7 @@ function transitionStatus() {
|
||||
function destroyOrder() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/manage/orders/${props.order.id}`, {
|
||||
router.delete(destroy.url(props.order.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -141,7 +142,7 @@ function actionIcon(status: string) {
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/manage/orders/${order.id}`">
|
||||
<Link :href="show.url(props.order.id)">
|
||||
<Eye class="size-4" />
|
||||
<span class="sr-only">Detail</span>
|
||||
</Link>
|
||||
@ -153,7 +154,7 @@ function actionIcon(status: string) {
|
||||
<Tooltip v-if="canEdit">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/manage/orders/${order.id}/edit`">
|
||||
<Link :href="edit.url(props.order.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -24,6 +24,7 @@ import {
|
||||
} from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { CuttingListItem } from '@/types/cutting';
|
||||
import { approve, reject } from '@/routes/admin/manage/owner_verifications';
|
||||
|
||||
const props = defineProps<{
|
||||
cutting: CuttingListItem;
|
||||
@ -41,7 +42,7 @@ const rejectForm = useForm({
|
||||
|
||||
function submitApprove() {
|
||||
approveForm
|
||||
.post(`/admin/manage/owner-verifications/${props.cutting.id}/approve`, {
|
||||
.post(approve.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onError: (errors) => {
|
||||
const message = Object.values(errors)[0];
|
||||
@ -52,7 +53,7 @@ function submitApprove() {
|
||||
|
||||
function submitReject() {
|
||||
rejectForm
|
||||
.post(`/admin/manage/owner-verifications/${props.cutting.id}/reject`, {
|
||||
.post(reject.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
rejectDialogOpen.value = false;
|
||||
|
||||
@ -8,6 +8,7 @@ import type {
|
||||
} from '@/types/purchase';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import PurchasePosForm from './form/PurchasePosForm.vue';
|
||||
import { index, store } from '@/routes/admin/manage/purchases';
|
||||
|
||||
defineProps<{
|
||||
suppliers: SelectOption[];
|
||||
@ -29,14 +30,14 @@ defineProps<{
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/purchases" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<PurchasePosForm
|
||||
:suppliers="suppliers"
|
||||
:catalog="catalog"
|
||||
:draft-items="draftItems"
|
||||
submit-url="/admin/manage/purchases"
|
||||
:submit-url="store.url()"
|
||||
method="post"
|
||||
submit-label="Simpan"
|
||||
/>
|
||||
|
||||
@ -9,6 +9,7 @@ import type {
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import PurchasePosForm from './form/PurchasePosForm.vue';
|
||||
import { index, update } from '@/routes/admin/manage/purchases';
|
||||
|
||||
const props = defineProps<{
|
||||
purchase: PurchaseEditItem;
|
||||
@ -45,14 +46,14 @@ const initialData = computed(() => ({
|
||||
<h2 class="text-2xl font-bold tracking-tight">Ubah Belanja</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/manage/purchases" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<PurchasePosForm
|
||||
:suppliers="suppliers"
|
||||
:catalog="catalog"
|
||||
:initial-data="initialData"
|
||||
:submit-url="`/admin/manage/purchases/${purchase.id}`"
|
||||
:submit-url="update.url(props.purchase.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
/>
|
||||
|
||||
@ -10,6 +10,7 @@ import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { PaginatedPurchases } from '@/types/purchase';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { index, create } from '@/routes/admin/manage/purchases';
|
||||
import PurchaseGroupedTable from './table/PurchaseGroupedTable.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
@ -25,7 +26,7 @@ const { can } = useCan();
|
||||
const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { setSearch, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: '/admin/manage/purchases',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
@ -69,7 +70,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('purchases.create')"
|
||||
href="/admin/manage/purchases/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -49,6 +49,7 @@ import type { MediaItem, MediaUploadState } from '@/types/media';
|
||||
import type { PurchaseCartItem, PurchaseCatalogItem, SelectOption } from '@/types/purchase';
|
||||
import PosCatalogCard from '../../shared/PosCatalogCard.vue';
|
||||
import PosCatalogVariantThumb from '../../shared/PosCatalogVariantThumb.vue';
|
||||
import { store as syncDraftRoute, destroy as destroyDraftRoute } from '@/routes/admin/manage/purchases/draft_items';
|
||||
const props = defineProps<{
|
||||
suppliers: SelectOption[];
|
||||
catalog: PurchaseCatalogItem[];
|
||||
@ -175,7 +176,7 @@ function lineSubtotal(item: PurchaseCartItem): number {
|
||||
}
|
||||
|
||||
async function syncDraftItem(priceId: number, quantity: number) {
|
||||
const { item } = await apiFetch<{ item: PurchaseCartItem }>('/admin/manage/purchases/draft-items', {
|
||||
const { item } = await apiFetch<{ item: PurchaseCartItem }>(syncDraftRoute.url(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
raw_material_price_id: priceId,
|
||||
@ -224,7 +225,7 @@ async function removeFromCart(index: number) {
|
||||
|
||||
if (isCreateMode.value) {
|
||||
try {
|
||||
await apiFetch(`/admin/manage/purchases/draft-items/${item.raw_material_price_id}`, {
|
||||
await apiFetch(destroyDraftRoute.url(item.raw_material_price_id), {
|
||||
method: 'DELETE',
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { PurchaseListItem } from '@/types/purchase';
|
||||
import { edit, destroy } from '@/routes/admin/manage/purchases';
|
||||
|
||||
const props = defineProps<{
|
||||
purchase: PurchaseListItem;
|
||||
@ -21,7 +22,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyPurchase() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/manage/purchases/${props.purchase.id}`, {
|
||||
router.delete(destroy.url(props.purchase.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -41,7 +42,7 @@ function destroyPurchase() {
|
||||
<Tooltip v-if="can('purchases.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/manage/purchases/${purchase.id}/edit`">
|
||||
<Link :href="edit.url(props.purchase.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -34,6 +34,7 @@ import {
|
||||
PRICE_TYPE_LABELS,
|
||||
} from '@/types/product';
|
||||
import type { CuttingListItem } from '@/types/cutting';
|
||||
import { verify } from '@/routes/admin/manage/stocks';
|
||||
|
||||
const props = defineProps<{
|
||||
cutting: CuttingListItem;
|
||||
@ -145,7 +146,7 @@ function submitVerify() {
|
||||
})),
|
||||
result_prices: buildResultPricesPayload(),
|
||||
}))
|
||||
.post(`/admin/manage/stocks/${props.cutting.id}/verify`, {
|
||||
.post(verify.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
verifyDialogOpen.value = false;
|
||||
|
||||
@ -14,6 +14,7 @@ import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import CategoryFormModal from './form/CategoryFormModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/master/categories';
|
||||
|
||||
const props = defineProps<{
|
||||
categories: PaginatedCategories;
|
||||
@ -31,7 +32,7 @@ const editingCategory = ref<CategoryListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/master/categories',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ import { useFormDialog } from '@/composables/useFormDialog';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { CategoryFormData, CategoryListItem } from '@/types/category';
|
||||
import { store, update } from '@/routes/admin/master/categories';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -70,12 +71,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.category) {
|
||||
form.put(`/admin/master/categories/${props.category.id}`, options);
|
||||
form.put(update.url(props.category.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.post('/admin/master/categories', options);
|
||||
form.post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { CategoryListItem } from '@/types/category';
|
||||
import { destroy } from '@/routes/admin/master/categories';
|
||||
|
||||
const props = defineProps<{
|
||||
category: CategoryListItem;
|
||||
@ -25,7 +26,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyCategory() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/master/categories/${props.category.id}`, {
|
||||
router.delete(destroy.url(props.category.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -14,6 +14,7 @@ import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import CustomerFormModal from './form/CustomerFormModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/master/customers';
|
||||
|
||||
const props = defineProps<{
|
||||
customers: PaginatedCustomers;
|
||||
@ -31,7 +32,7 @@ const editingCustomer = ref<CustomerListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/master/customers',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ import { useFormDialog } from '@/composables/useFormDialog';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { CustomerFormData, CustomerListItem } from '@/types/customer';
|
||||
import { store, update } from '@/routes/admin/master/customers';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -76,12 +77,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.customer) {
|
||||
form.put(`/admin/master/customers/${props.customer.id}`, options);
|
||||
form.put(update.url(props.customer.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.post('/admin/master/customers', options);
|
||||
form.post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { CustomerListItem } from '@/types/customer';
|
||||
import { destroy } from '@/routes/admin/master/customers';
|
||||
|
||||
const props = defineProps<{
|
||||
customer: CustomerListItem;
|
||||
@ -25,7 +26,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyCustomer() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/master/customers/${props.customer.id}`, {
|
||||
router.delete(destroy.url(props.customer.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -4,6 +4,7 @@ import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { CategoryOption } from '@/types/product';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import ProductForm from './form/ProductForm.vue';
|
||||
import { index, store } from '@/routes/admin/master/products';
|
||||
|
||||
defineProps<{
|
||||
categories: CategoryOption[];
|
||||
@ -21,11 +22,11 @@ defineProps<{
|
||||
<h2 class="text-2xl font-bold tracking-tight">Tambah Produk</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/master/products" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<ProductForm
|
||||
submit-url="/admin/master/products"
|
||||
:submit-url="store.url()"
|
||||
method="post"
|
||||
submit-label="Simpan"
|
||||
:categories="categories"
|
||||
|
||||
@ -5,6 +5,7 @@ import type { CategoryOption, ProductListItem } from '@/types/product';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import ProductForm from './form/ProductForm.vue';
|
||||
import { index, update } from '@/routes/admin/master/products';
|
||||
|
||||
const props = defineProps<{
|
||||
product: ProductListItem & { description?: string | null };
|
||||
@ -36,11 +37,11 @@ const initialData = computed(() => ({
|
||||
<h2 class="text-2xl font-bold tracking-tight">Ubah Produk</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/master/products" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<ProductForm
|
||||
:submit-url="`/admin/master/products/${product.id}`"
|
||||
:submit-url="update.url(props.product.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
:initial-data="initialData"
|
||||
|
||||
@ -13,6 +13,7 @@ import type { DataTableFilterDef } from '@/types/data-table';
|
||||
import type { CategoryOption, PaginatedProducts } from '@/types/product';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { index, create } from '@/routes/admin/master/products';
|
||||
import ProductGroupedTable from './table/ProductGroupedTable.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
@ -33,7 +34,7 @@ const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { query, setSearch, setFilter, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/master/products',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['is_active', 'category_id', 'stock_status'],
|
||||
});
|
||||
@ -114,7 +115,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('products.create')"
|
||||
href="/admin/master/products/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { ProductListItem } from '@/types/product';
|
||||
import { edit, destroy } from '@/routes/admin/master/products';
|
||||
|
||||
const props = defineProps<{
|
||||
product: ProductListItem;
|
||||
@ -21,7 +22,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyProduct() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/master/products/${props.product.id}`, {
|
||||
router.delete(destroy.url(props.product.id), {
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
},
|
||||
@ -40,7 +41,7 @@ function destroyProduct() {
|
||||
<Tooltip v-if="can('products.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/master/products/${product.id}/edit`">
|
||||
<Link :href="edit.url(props.product.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { ProductListItem } from '@/types/product';
|
||||
import { toggle_status } from '@/routes/admin/master/products';
|
||||
|
||||
const props = defineProps<{
|
||||
product: ProductListItem;
|
||||
@ -32,7 +33,7 @@ function toggleStatus(checked: boolean) {
|
||||
isActive.value = checked;
|
||||
processing.value = true;
|
||||
|
||||
router.patch(`/admin/master/products/${props.product.id}/toggle-status`, {
|
||||
router.patch(toggle_status.url(props.product.id), {
|
||||
is_active: checked,
|
||||
}, {
|
||||
preserveScroll: true,
|
||||
|
||||
@ -4,6 +4,7 @@ import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { EnumOption } from '@/types/raw-material';
|
||||
import RawMaterialForm from './form/RawMaterialForm.vue';
|
||||
import BackButton from '@/components/button/BackButton.vue';
|
||||
import { index, store } from '@/routes/admin/master/raw_materials';
|
||||
|
||||
defineProps<{
|
||||
units: EnumOption[];
|
||||
@ -22,9 +23,9 @@ defineProps<{
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/master/raw-materials" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<RawMaterialForm submit-url="/admin/master/raw-materials" method="post" submit-label="Simpan" :units="units" />
|
||||
<RawMaterialForm :submit-url="store.url()" method="post" submit-label="Simpan" :units="units" />
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
@ -5,6 +5,7 @@ import type { EnumOption, RawMaterialListItem } from '@/types/raw-material';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import RawMaterialForm from './form/RawMaterialForm.vue';
|
||||
import { index, update } from '@/routes/admin/master/raw_materials';
|
||||
|
||||
const props = defineProps<{
|
||||
rawMaterial: RawMaterialListItem;
|
||||
@ -37,11 +38,11 @@ const initialData = computed(() => ({
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/master/raw-materials" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<RawMaterialForm
|
||||
:submit-url="`/admin/master/raw-materials/${rawMaterial.id}`"
|
||||
:submit-url="update.url(props.rawMaterial.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
:initial-data="initialData"
|
||||
|
||||
@ -13,6 +13,7 @@ import type { DataTableFilterDef } from '@/types/data-table';
|
||||
import type { PaginatedRawMaterials } from '@/types/raw-material';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { index, create } from '@/routes/admin/master/raw_materials';
|
||||
import RawMaterialGroupedTable from './table/RawMaterialGroupedTable.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
@ -31,7 +32,7 @@ const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { query, setSearch, setFilter, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/master/raw-materials',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['is_active', 'stock_status'],
|
||||
});
|
||||
@ -103,7 +104,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('raw_materials.create')"
|
||||
href="/admin/master/raw-materials/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { RawMaterialListItem } from '@/types/raw-material';
|
||||
import { edit, destroy } from '@/routes/admin/master/raw_materials';
|
||||
|
||||
const props = defineProps<{
|
||||
material: RawMaterialListItem;
|
||||
@ -21,7 +22,7 @@ const deleteProcessing = ref(false);
|
||||
function destroyRawMaterial() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/master/raw-materials/${props.material.id}`, {
|
||||
router.delete(destroy.url(props.material.id), {
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
},
|
||||
@ -40,7 +41,7 @@ function destroyRawMaterial() {
|
||||
<Tooltip v-if="can('raw_materials.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/master/raw-materials/${material.id}/edit`">
|
||||
<Link :href="edit.url(props.material.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { RawMaterialListItem } from '@/types/raw-material';
|
||||
import { toggle_status } from '@/routes/admin/master/raw_materials';
|
||||
|
||||
const props = defineProps<{
|
||||
material: RawMaterialListItem;
|
||||
@ -32,7 +33,7 @@ function toggleStatus(checked: boolean) {
|
||||
isActive.value = checked;
|
||||
processing.value = true;
|
||||
|
||||
router.patch(`/admin/master/raw-materials/${props.material.id}/toggle-status`, {
|
||||
router.patch(toggle_status.url(props.material.id), {
|
||||
is_active: checked,
|
||||
}, {
|
||||
preserveScroll: true,
|
||||
|
||||
@ -14,6 +14,7 @@ import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import SupplierFormModal from './form/SupplierFormModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/master/suppliers';
|
||||
|
||||
const props = defineProps<{
|
||||
suppliers: PaginatedSuppliers;
|
||||
@ -31,7 +32,7 @@ const editingSupplier = ref<SupplierListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/master/suppliers',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ import { useFormDialog } from '@/composables/useFormDialog';
|
||||
import { FIELD_LIMITS } from '@/lib/field-limits';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { SupplierFormData, SupplierListItem } from '@/types/supplier';
|
||||
import { store, update } from '@/routes/admin/master/suppliers';
|
||||
|
||||
const open = defineModel<boolean>('open', { default: false });
|
||||
|
||||
@ -76,12 +77,12 @@ function submit() {
|
||||
};
|
||||
|
||||
if (isEditing.value && props.supplier) {
|
||||
form.put(`/admin/master/suppliers/${props.supplier.id}`, options);
|
||||
form.put(update.url(props.supplier.id), options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
form.post('/admin/master/suppliers', options);
|
||||
form.post(store.url(), options);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { SupplierListItem } from '@/types/supplier';
|
||||
import { destroy } from '@/routes/admin/master/suppliers';
|
||||
|
||||
const props = defineProps<{
|
||||
supplier: SupplierListItem;
|
||||
@ -25,7 +26,7 @@ const deleteProcessing = ref(false);
|
||||
function destroySupplier() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/master/suppliers/${props.supplier.id}`, {
|
||||
router.delete(destroy.url(props.supplier.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
|
||||
@ -9,6 +9,7 @@ import type { ActivityLogListItem, PaginatedActivityLogs, SelectOption } from '@
|
||||
import type { DataTableSort } from '@/types/data-table';
|
||||
import ActivityLogDetailModal from './table/ActivityLogDetailModal.vue';
|
||||
import { createColumns } from './table/columns';
|
||||
import { index } from '@/routes/admin/system/activity_logs';
|
||||
|
||||
const props = defineProps<{
|
||||
activityLogs: PaginatedActivityLogs;
|
||||
@ -28,7 +29,7 @@ const detailModalOpen = ref(false);
|
||||
const selectedActivityLog = ref<ActivityLogListItem | null>(null);
|
||||
|
||||
const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } = useDataTableQuery({
|
||||
url: '/admin/system/activity-logs',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
filterKeys: ['event', 'subject_type'],
|
||||
});
|
||||
|
||||
@ -3,6 +3,7 @@ import { Head, Link } from '@inertiajs/vue3';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import RoleForm from './form/RoleForm.vue';
|
||||
import BackButton from '@/components/button/BackButton.vue';
|
||||
import { index, store } from '@/routes/admin/system/roles';
|
||||
|
||||
interface PermissionOption {
|
||||
value: string;
|
||||
@ -27,9 +28,9 @@ defineProps<{
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/system/roles" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<RoleForm submit-url="/admin/system/roles" method="post" submit-label="Simpan" :permissions="permissions" />
|
||||
<RoleForm :submit-url="store.url()" method="post" submit-label="Simpan" :permissions="permissions" />
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
@ -3,6 +3,7 @@ import BackButton from '@/components/button/BackButton.vue';
|
||||
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import RoleForm from './form/RoleForm.vue';
|
||||
import { index, update } from '@/routes/admin/system/roles';
|
||||
|
||||
interface PermissionOption {
|
||||
value: string;
|
||||
@ -33,11 +34,11 @@ defineProps<{
|
||||
<h2 class="text-2xl font-bold tracking-tight">Ubah Role</h2>
|
||||
</div>
|
||||
|
||||
<BackButton href="/admin/system/roles" />
|
||||
<BackButton :href="index.url()" />
|
||||
</div>
|
||||
|
||||
<RoleForm
|
||||
:submit-url="`/admin/system/roles/${role.id}`"
|
||||
:submit-url="update.url(role.id)"
|
||||
method="put"
|
||||
submit-label="Perbarui"
|
||||
:initial-data="role"
|
||||
|
||||
@ -11,6 +11,7 @@ import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||
import type { DataTableSort } from '@/types/data-table';
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { index, create } from '@/routes/admin/system/roles';
|
||||
import type { RoleListItem } from './table/columns';
|
||||
import { createColumns } from './table/columns';
|
||||
|
||||
@ -37,7 +38,7 @@ const search = ref(props.filters.search ?? '');
|
||||
|
||||
const { query, setSearch, setSort, resetFilters, syncFromServer } =
|
||||
useDataTableQuery({
|
||||
url: '/admin/system/roles',
|
||||
url: index.url(),
|
||||
initial: { ...props.filters },
|
||||
});
|
||||
|
||||
@ -90,7 +91,7 @@ watch(
|
||||
|
||||
<CreateButton
|
||||
v-if="can('roles.create')"
|
||||
href="/admin/system/roles/create"
|
||||
:href="create.url()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { Link, router } from '@inertiajs/vue3';
|
||||
import { Pencil, Trash2 } from '@lucide/vue';
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useCan } from '@/composables/useCan';
|
||||
import type { RoleListItem } from './columns';
|
||||
import { edit, destroy } from '@/routes/admin/system/roles';
|
||||
|
||||
const props = defineProps<{
|
||||
role: RoleListItem;
|
||||
@ -18,10 +19,14 @@ const { can } = useCan();
|
||||
const deleteConfirmOpen = ref(false);
|
||||
const deleteProcessing = ref(false);
|
||||
|
||||
const isSystemRole = computed(() => {
|
||||
return ['developer', 'owner', 'admin-toko', 'admin-bahan-baku', 'direktur', 'marketing', 'cashier', 'non-operator'].includes(props.role.name);
|
||||
});
|
||||
|
||||
function destroyRole() {
|
||||
deleteProcessing.value = true;
|
||||
|
||||
router.delete(`/admin/system/roles/${props.role.id}`, {
|
||||
router.delete(destroy.url(props.role.id), {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
deleteConfirmOpen.value = false;
|
||||
@ -41,7 +46,7 @@ function destroyRole() {
|
||||
<Tooltip v-if="can('roles.update')">
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="size-8" as-child>
|
||||
<Link :href="`/admin/system/roles/${role.id}/edit`">
|
||||
<Link :href="edit.url(props.role.id)">
|
||||
<Pencil class="size-4" />
|
||||
<span class="sr-only">Ubah</span>
|
||||
</Link>
|
||||
|
||||
@ -9,6 +9,7 @@ import { Card, CardContent } from '@/components/ui/card';
|
||||
import { createMediaUploadState } from '@/types/media';
|
||||
import type { MediaUploadState } from '@/types/media';
|
||||
import type { HomepageSettingsData } from '@/types/setting';
|
||||
import { update } from '@/routes/admin/system/settings/homepage';
|
||||
|
||||
const props = defineProps<{
|
||||
data: HomepageSettingsData;
|
||||
@ -42,7 +43,7 @@ function submit() {
|
||||
formData.append('gallery_images_remove[]', String(id));
|
||||
});
|
||||
|
||||
router.put('/admin/system/settings/homepage', formData, {
|
||||
router.put(update.url(), formData, {
|
||||
preserveScroll: true,
|
||||
onSuccess: () => {
|
||||
heroImage.value = createMediaUploadState();
|
||||
|
||||
@ -9,6 +9,7 @@ import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from '@/component
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { HrSettingsData } from '@/types/setting';
|
||||
import { update } from '@/routes/admin/system/settings/hr';
|
||||
|
||||
const props = defineProps<{
|
||||
data: HrSettingsData;
|
||||
@ -22,7 +23,7 @@ const form = useForm({
|
||||
});
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/system/settings/hr', {
|
||||
form.put(update.url(), {
|
||||
preserveScroll: true,
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan pengaturan HR.');
|
||||
|
||||
@ -20,6 +20,7 @@ import type {
|
||||
MarketplaceSettingsData,
|
||||
} from '@/types/setting';
|
||||
import MarketplaceFeeField from './MarketplaceFeeField.vue';
|
||||
import { update } from '@/routes/admin/system/settings/marketplace';
|
||||
|
||||
const props = defineProps<{
|
||||
data: MarketplaceSettingsData;
|
||||
@ -64,7 +65,7 @@ function feeErrors(key: string): string[] {
|
||||
}
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/system/settings/marketplace', {
|
||||
form.put(update.url(), {
|
||||
preserveScroll: true,
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan pengaturan marketplace.');
|
||||
|
||||
@ -8,6 +8,7 @@ import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from '@/component
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { formErrors } from '@/lib/form';
|
||||
import type { SocialMediaSettingsData } from '@/types/setting';
|
||||
import { update } from '@/routes/admin/system/settings/social_media';
|
||||
|
||||
const props = defineProps<{
|
||||
data: SocialMediaSettingsData;
|
||||
@ -20,7 +21,7 @@ const form = useForm({
|
||||
});
|
||||
|
||||
function submit() {
|
||||
form.put('/admin/system/settings/social-media', {
|
||||
form.put(update.url(), {
|
||||
preserveScroll: true,
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan pengaturan media sosial.');
|
||||
|
||||
@ -14,6 +14,7 @@ import { formErrors } from '@/lib/form';
|
||||
import { createMediaUploadState } from '@/types/media';
|
||||
import type { MediaUploadState } from '@/types/media';
|
||||
import type { SystemSettingsData } from '@/types/setting';
|
||||
import { update } from '@/routes/admin/system/settings/system';
|
||||
|
||||
const props = defineProps<{
|
||||
data: SystemSettingsData;
|
||||
@ -58,7 +59,7 @@ function buildFormData(): FormData {
|
||||
function submit() {
|
||||
const payload = buildFormData();
|
||||
|
||||
form.transform(() => payload).put('/admin/system/settings/system', {
|
||||
form.transform(() => payload).put(update.url(), {
|
||||
preserveScroll: true,
|
||||
onError: () => {
|
||||
toast.error('Gagal menyimpan pengaturan sistem.');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user