feat: add permission checks for various actions across admin pages
- Integrated permission checks using `can` function in payroll period management to control visibility of adjustment, pay, and cancel actions. - Updated employee management to conditionally render edit, reset password, and delete actions based on permissions. - Enhanced leave request management with permission checks for approve, reject, edit, and delete actions. - Implemented permission checks in cutting management for edit and delete actions. - Added permission checks for purchase management actions including create, edit, and delete. - Integrated permission checks in restock management for create, edit, and delete actions. - Updated transaction management to conditionally render create, edit, and delete actions based on permissions. - Enhanced category management with permission checks for edit and delete actions. - Integrated permission checks in customer management for edit and delete actions. - Updated product management to conditionally render create, edit, and delete actions based on permissions. - Enhanced raw material management with permission checks for edit and delete actions. - Integrated permission checks in supplier management for edit and delete actions. - Updated role management to conditionally render edit and delete actions based on permissions.
This commit is contained in:
parent
fc1c84f420
commit
4ac83c8e78
@ -12,12 +12,13 @@ export type CashAccount = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (cashAccount: CashAccount) => void;
|
||||
handleDeleteClick: (cashAccount: CashAccount) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createCashAccountColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<CashAccount>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -54,6 +55,7 @@ export function createCashAccountColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('cash.update'),
|
||||
onClick: () => handleEdit(cashAccount),
|
||||
},
|
||||
{
|
||||
@ -61,6 +63,7 @@ export function createCashAccountColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('cash.delete'),
|
||||
onClick: () => handleDeleteClick(cashAccount),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import {
|
||||
@ -69,6 +70,7 @@ export default function CashAccountIndex({
|
||||
filters,
|
||||
filterOptions,
|
||||
}: Props) {
|
||||
const { can } = useCan();
|
||||
const [depositOpen, setDepositOpen] = useState(false);
|
||||
const [withdrawalOpen, setWithdrawalOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<CashTransaction | null>(null);
|
||||
@ -137,6 +139,7 @@ export default function CashAccountIndex({
|
||||
setEditReceiptKey(transaction.receipt_key ?? null);
|
||||
},
|
||||
handleDeleteClick: (transaction) => setDeleting(transaction),
|
||||
can,
|
||||
});
|
||||
|
||||
const filterToolbar = (
|
||||
@ -180,20 +183,24 @@ export default function CashAccountIndex({
|
||||
title="Kas Toko"
|
||||
actions={
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setDepositOpen(true)}
|
||||
>
|
||||
<ArrowDownToLine className="h-4 w-4" />
|
||||
Deposit
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setWithdrawalOpen(true)}
|
||||
>
|
||||
<ArrowUpFromLine className="h-4 w-4" />
|
||||
Withdrawal
|
||||
</Button>
|
||||
{can('cash.deposit') && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setDepositOpen(true)}
|
||||
>
|
||||
<ArrowDownToLine className="h-4 w-4" />
|
||||
Deposit
|
||||
</Button>
|
||||
)}
|
||||
{can('cash.withdraw') && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setWithdrawalOpen(true)}
|
||||
>
|
||||
<ArrowUpFromLine className="h-4 w-4" />
|
||||
Withdrawal
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
@ -50,12 +50,13 @@ function getReferenceLabel(type: string): string {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (transaction: CashTransaction) => void;
|
||||
handleDeleteClick: (transaction: CashTransaction) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createTransactionColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<CashTransaction>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -174,6 +175,7 @@ export function createTransactionColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('cash.update'),
|
||||
onClick: () => handleEdit(transaction),
|
||||
},
|
||||
{
|
||||
@ -181,6 +183,7 @@ export function createTransactionColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('cash.delete'),
|
||||
onClick: () => handleDeleteClick(transaction),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -62,12 +62,14 @@ type CreateColumnsParams = {
|
||||
handleDeleteClick: (employeeAdvance: EmployeeAdvance) => void;
|
||||
handleApprove: (employeeAdvance: EmployeeAdvance) => void;
|
||||
handlePay: (employeeAdvance: EmployeeAdvance) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createEmployeeAdvanceColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<EmployeeAdvance>[] {
|
||||
const { handleEdit, handleDeleteClick, handleApprove, handlePay } = params;
|
||||
const { handleEdit, handleDeleteClick, handleApprove, handlePay, can } =
|
||||
params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -142,7 +144,9 @@ export function createEmployeeAdvanceColumns(
|
||||
icon: (
|
||||
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||
),
|
||||
show: employeeAdvance.status === 'pending',
|
||||
show:
|
||||
can('employee_advances.verify') &&
|
||||
employeeAdvance.status === 'pending',
|
||||
onClick: () => handleApprove(employeeAdvance),
|
||||
},
|
||||
{
|
||||
@ -150,12 +154,15 @@ export function createEmployeeAdvanceColumns(
|
||||
icon: (
|
||||
<CircleDollarSign className="h-4 w-4 text-blue-600" />
|
||||
),
|
||||
show: employeeAdvance.status === 'approved',
|
||||
show:
|
||||
can('employee_advances.pay') &&
|
||||
employeeAdvance.status === 'approved',
|
||||
onClick: () => handlePay(employeeAdvance),
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('employee_advances.update'),
|
||||
onClick: () => handleEdit(employeeAdvance),
|
||||
},
|
||||
{
|
||||
@ -163,6 +170,7 @@ export function createEmployeeAdvanceColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('employee_advances.delete'),
|
||||
onClick: () =>
|
||||
handleDeleteClick(employeeAdvance),
|
||||
},
|
||||
|
||||
@ -12,6 +12,7 @@ import { RupiahInput } from '@/components/rupiah-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -35,6 +36,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<EmployeeAdvance | null>(null);
|
||||
const [deleting, setDeleting] = useState<EmployeeAdvance | null>(null);
|
||||
@ -113,6 +115,7 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) {
|
||||
handleDeleteClick: (employeeAdvance) => setDeleting(employeeAdvance),
|
||||
handleApprove: (employeeAdvance) => setApproving(employeeAdvance),
|
||||
handlePay: (employeeAdvance) => setPaying(employeeAdvance),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -123,15 +126,17 @@ export default function EmployeeAdvanceIndex({ employeeAdvances }: Props) {
|
||||
<PageHeader
|
||||
title="Kasbon"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('employee_advances.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -22,12 +22,13 @@ export type Expense = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (expense: Expense) => void;
|
||||
handleDeleteClick: (expense: Expense) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createExpenseColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<Expense>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -98,6 +99,7 @@ export function createExpenseColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('expenses.update'),
|
||||
onClick: () => handleEdit(expense),
|
||||
},
|
||||
{
|
||||
@ -105,6 +107,7 @@ export function createExpenseColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('expenses.delete'),
|
||||
onClick: () => handleDeleteClick(expense),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -12,6 +12,7 @@ import { RupiahInput } from '@/components/rupiah-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -33,6 +34,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function ExpenseIndex({ expenses }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<Expense | null>(null);
|
||||
const [deleting, setDeleting] = useState<Expense | null>(null);
|
||||
@ -84,6 +86,7 @@ export default function ExpenseIndex({ expenses }: Props) {
|
||||
setEditReceiptKey(expense.receipt_key ?? null);
|
||||
},
|
||||
handleDeleteClick: (expense) => setDeleting(expense),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -94,15 +97,17 @@ export default function ExpenseIndex({ expenses }: Props) {
|
||||
<PageHeader
|
||||
title="Pengeluaran"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('expenses.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -49,12 +49,13 @@ type CreateColumnsParams = {
|
||||
showUrl: (id: number) => string;
|
||||
handleClose: (period: PayrollPeriod) => void;
|
||||
handleReopen: (period: PayrollPeriod) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createPayrollPeriodColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<PayrollPeriod>[] {
|
||||
const { showUrl, handleClose, handleReopen } = params;
|
||||
const { showUrl, handleClose, handleReopen, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -191,7 +192,9 @@ export function createPayrollPeriodColumns(
|
||||
icon: (
|
||||
<Lock className="h-4 w-4 text-orange-600" />
|
||||
),
|
||||
show: period.status === 'open',
|
||||
show:
|
||||
can('payroll.adjust') &&
|
||||
period.status === 'open',
|
||||
onClick: () => handleClose(period),
|
||||
},
|
||||
{
|
||||
@ -199,7 +202,9 @@ export function createPayrollPeriodColumns(
|
||||
icon: (
|
||||
<Unlock className="h-4 w-4 text-blue-600" />
|
||||
),
|
||||
show: period.status === 'closed',
|
||||
show:
|
||||
can('payroll.adjust') &&
|
||||
period.status === 'closed',
|
||||
onClick: () => handleReopen(period),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -4,6 +4,7 @@ import type { PaginationState } from '@/components/data-table';
|
||||
import { DataTable } from '@/components/data-table';
|
||||
import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import { MONTH_NAMES } from '@/lib/constants';
|
||||
import {
|
||||
@ -26,6 +27,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function PayrollPeriodIndex({ payrollPeriods }: Props) {
|
||||
const { can } = useCan();
|
||||
const [closing, setClosing] = useState<PayrollPeriod | null>(null);
|
||||
const [reopening, setReopening] = useState<PayrollPeriod | null>(null);
|
||||
|
||||
@ -78,6 +80,7 @@ export default function PayrollPeriodIndex({ payrollPeriods }: Props) {
|
||||
showUrl: (id) => payrollPeriodShow(id).url,
|
||||
handleClose: (period) => setClosing(period),
|
||||
handleReopen: (period) => setReopening(period),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@ -67,6 +67,7 @@ type CreateColumnsParams = {
|
||||
adjustment: PayrollAdjustment,
|
||||
payrollId: number,
|
||||
) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createPayrollColumns(
|
||||
@ -77,6 +78,7 @@ export function createPayrollColumns(
|
||||
handleCancel,
|
||||
handleAddAdjustment,
|
||||
handleDeleteAdjustment,
|
||||
can,
|
||||
} = params;
|
||||
|
||||
return [
|
||||
@ -218,7 +220,9 @@ export function createPayrollColumns(
|
||||
{
|
||||
label: 'Tambah Adjustment',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: payroll.status === 'unpaid',
|
||||
show:
|
||||
can('payroll.adjust') &&
|
||||
payroll.status === 'unpaid',
|
||||
onClick: () => handleAddAdjustment(payroll),
|
||||
},
|
||||
{
|
||||
@ -226,7 +230,9 @@ export function createPayrollColumns(
|
||||
icon: (
|
||||
<CircleDollarSign className="h-4 w-4 text-green-600" />
|
||||
),
|
||||
show: payroll.status === 'unpaid',
|
||||
show:
|
||||
can('payroll.pay') &&
|
||||
payroll.status === 'unpaid',
|
||||
onClick: () => handlePay(payroll),
|
||||
},
|
||||
{
|
||||
@ -234,7 +240,9 @@ export function createPayrollColumns(
|
||||
icon: (
|
||||
<XCircle className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: payroll.status === 'unpaid',
|
||||
show:
|
||||
can('payroll.cancel') &&
|
||||
payroll.status === 'unpaid',
|
||||
onClick: () => handleCancel(payroll),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { MONTH_NAMES } from '@/lib/constants';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import { destroy as adjustmentDestroy } from '@/routes/admin/finance/payroll-adjustments';
|
||||
@ -39,6 +40,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function PayrollPeriodShow({ payrollPeriod }: Props) {
|
||||
const { can } = useCan();
|
||||
const [paying, setPaying] = useState<Payroll | null>(null);
|
||||
const [cancelling, setCancelling] = useState<Payroll | null>(null);
|
||||
const [addingAdjustment, setAddingAdjustment] = useState<Payroll | null>(
|
||||
@ -98,6 +100,7 @@ export default function PayrollPeriodShow({ payrollPeriod }: Props) {
|
||||
handleDeleteAdjustment: (adjustment, payrollId) => {
|
||||
setDeletingAdjustment({ adjustment, payrollId });
|
||||
},
|
||||
can,
|
||||
});
|
||||
|
||||
const totalBaseSalary = payrollPeriod.payrolls.reduce(
|
||||
|
||||
@ -38,6 +38,7 @@ type CreateColumnsParams = {
|
||||
handleDeleteClick: (employee: Employee) => void;
|
||||
handleResetPassword: (employee: Employee) => void;
|
||||
toggleActiveUrl: (id: number) => string;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createEmployeeColumns(
|
||||
@ -48,6 +49,7 @@ export function createEmployeeColumns(
|
||||
handleDeleteClick,
|
||||
handleResetPassword,
|
||||
toggleActiveUrl,
|
||||
can,
|
||||
} = params;
|
||||
|
||||
return [
|
||||
@ -161,6 +163,7 @@ export function createEmployeeColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('employees.update'),
|
||||
onClick: () => handleEdit(employee),
|
||||
},
|
||||
{
|
||||
@ -168,6 +171,7 @@ export function createEmployeeColumns(
|
||||
icon: (
|
||||
<KeyRound className="h-4 w-4 text-muted-foreground" />
|
||||
),
|
||||
show: can('employees.reset_password'),
|
||||
onClick: () => handleResetPassword(employee),
|
||||
},
|
||||
{
|
||||
@ -175,6 +179,7 @@ export function createEmployeeColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('employees.delete'),
|
||||
onClick: () => handleDeleteClick(employee),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -42,6 +43,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function EmployeeIndex({ employees, filters }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Employee | null>(null);
|
||||
const [resetPasswordTarget, setResetPasswordTarget] =
|
||||
useState<Employee | null>(null);
|
||||
@ -99,6 +101,7 @@ export default function EmployeeIndex({ employees, filters }: Props) {
|
||||
handleDeleteClick: (employee) => setDeleting(employee),
|
||||
handleResetPassword: (employee) => setResetPasswordTarget(employee),
|
||||
toggleActiveUrl: (id) => toggleActive.url(id),
|
||||
can,
|
||||
});
|
||||
|
||||
const filterToolbar = (
|
||||
@ -183,12 +186,14 @@ export default function EmployeeIndex({ employees, filters }: Props) {
|
||||
<PageHeader
|
||||
title="Pegawai"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={employeeCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('employees.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={employeeCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -55,12 +55,13 @@ type CreateColumnsParams = {
|
||||
handleDeleteClick: (leaveRequest: LeaveRequest) => void;
|
||||
handleApprove: (leaveRequest: LeaveRequest) => void;
|
||||
handleReject: (leaveRequest: LeaveRequest) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createLeaveRequestColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<LeaveRequest>[] {
|
||||
const { handleEdit, handleDeleteClick, handleApprove, handleReject } =
|
||||
const { handleEdit, handleDeleteClick, handleApprove, handleReject, can } =
|
||||
params;
|
||||
|
||||
return [
|
||||
@ -129,7 +130,9 @@ export function createLeaveRequestColumns(
|
||||
icon: (
|
||||
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||
),
|
||||
show: leaveRequest.status === 'pending',
|
||||
show:
|
||||
can('leave_requests.verify') &&
|
||||
leaveRequest.status === 'pending',
|
||||
onClick: () => handleApprove(leaveRequest),
|
||||
},
|
||||
{
|
||||
@ -137,12 +140,15 @@ export function createLeaveRequestColumns(
|
||||
icon: (
|
||||
<XCircle className="h-4 w-4 text-red-600" />
|
||||
),
|
||||
show: leaveRequest.status === 'pending',
|
||||
show:
|
||||
can('leave_requests.verify') &&
|
||||
leaveRequest.status === 'pending',
|
||||
onClick: () => handleReject(leaveRequest),
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('leave_requests.update'),
|
||||
onClick: () => handleEdit(leaveRequest),
|
||||
},
|
||||
{
|
||||
@ -150,6 +156,7 @@ export function createLeaveRequestColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('leave_requests.delete'),
|
||||
onClick: () => handleDeleteClick(leaveRequest),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
approve,
|
||||
@ -52,6 +53,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function LeaveRequestIndex({ leaveRequests, filters, filterOptions }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<LeaveRequest | null>(null);
|
||||
const [deleting, setDeleting] = useState<LeaveRequest | null>(null);
|
||||
@ -141,6 +143,7 @@ export default function LeaveRequestIndex({ leaveRequests, filters, filterOption
|
||||
handleDeleteClick: (leaveRequest) => setDeleting(leaveRequest),
|
||||
handleApprove: (leaveRequest) => setApproving(leaveRequest),
|
||||
handleReject: (leaveRequest) => setRejecting(leaveRequest),
|
||||
can,
|
||||
});
|
||||
|
||||
const filterToolbar = (
|
||||
@ -181,15 +184,17 @@ export default function LeaveRequestIndex({ leaveRequests, filters, filterOption
|
||||
<PageHeader
|
||||
title="Cuti"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('leave_requests.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { ImagePreviewButton } from '@/components/image-preview-button';
|
||||
import { RowActions } from '@/components/row-actions';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatDateTime, formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import type { Cutting } from './columns';
|
||||
@ -24,6 +25,7 @@ export function CuttingCardRow({
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: CuttingCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const items = cutting.cutting_materials ?? [];
|
||||
const result = cutting.cutting_results?.[0];
|
||||
const materialCount = items.length;
|
||||
@ -126,6 +128,7 @@ export function CuttingCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('cuttings.update'),
|
||||
onClick: () => onEdit(cutting),
|
||||
},
|
||||
{
|
||||
@ -133,6 +136,7 @@ export function CuttingCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('cuttings.delete'),
|
||||
onClick: () => onDelete(cutting),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -6,6 +6,7 @@ import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
|
||||
import { useCardTableExpand } from '@/components/hooks/use-card-table-expand';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -28,6 +29,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function CuttingIndex({ cuttings }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Cutting | null>(null);
|
||||
const expand = useCardTableExpand(true);
|
||||
|
||||
@ -66,12 +68,14 @@ export default function CuttingIndex({ cuttings }: Props) {
|
||||
<PageHeader
|
||||
title="Cutting"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={cuttingCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('cuttings.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={cuttingCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
|
||||
import { useCardTableExpand } from '@/components/hooks/use-card-table-expand';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -28,6 +29,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function PurchaseIndex({ purchases }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Purchase | null>(null);
|
||||
const expand = useCardTableExpand(true);
|
||||
|
||||
@ -66,12 +68,14 @@ export default function PurchaseIndex({ purchases }: Props) {
|
||||
<PageHeader
|
||||
title="Belanja"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={purchaseCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('purchases.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={purchaseCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { ImagePreviewButton } from '@/components/image-preview-button';
|
||||
import { RowActions } from '@/components/row-actions';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatDateTime, formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import type { Purchase } from './columns';
|
||||
@ -24,6 +25,7 @@ export function PurchaseCardRow({
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: PurchaseCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const items = purchase.purchase_items ?? [];
|
||||
const variantCount = items.length;
|
||||
const rawMaterialName =
|
||||
@ -129,6 +131,7 @@ export function PurchaseCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('purchases.update'),
|
||||
onClick: () => onEdit(purchase),
|
||||
},
|
||||
{
|
||||
@ -136,6 +139,7 @@ export function PurchaseCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('purchases.delete'),
|
||||
onClick: () => onDelete(purchase),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -6,6 +6,7 @@ import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
|
||||
import { useCardTableExpand } from '@/components/hooks/use-card-table-expand';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -28,6 +29,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function RestockIndex({ restocks }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Restock | null>(null);
|
||||
const expand = useCardTableExpand(true);
|
||||
|
||||
@ -66,12 +68,14 @@ export default function RestockIndex({ restocks }: Props) {
|
||||
<PageHeader
|
||||
title="Restock"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={restockCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('restocks.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={restockCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { RowActions } from '@/components/row-actions';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatDateTime, formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import type { Restock, RestockStockType } from './columns';
|
||||
@ -38,6 +39,7 @@ export function RestockCardRow({
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: RestockCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const items = restock.restock_items ?? [];
|
||||
const variantCount = items.length;
|
||||
const productNames = [
|
||||
@ -138,6 +140,7 @@ export function RestockCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('restocks.update'),
|
||||
onClick: () => onEdit(restock),
|
||||
},
|
||||
{
|
||||
@ -145,6 +148,7 @@ export function RestockCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('restocks.delete'),
|
||||
onClick: () => onDelete(restock),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -73,6 +74,7 @@ export default function TransactionIndex({
|
||||
filters,
|
||||
filterOptions,
|
||||
}: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Transaction | null>(null);
|
||||
const expand = useCardTableExpand(true);
|
||||
|
||||
@ -320,12 +322,14 @@ export default function TransactionIndex({
|
||||
<PageHeader
|
||||
title="Transaksi"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={transactionCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('orders.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={transactionCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { RowActions } from '@/components/row-actions';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatDateTime, formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import type { Transaction } from './columns';
|
||||
@ -32,6 +33,7 @@ export function TransactionCardRow({
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: TransactionCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const items = transaction.order_items ?? [];
|
||||
const variantCount = items.length;
|
||||
const productNames = [
|
||||
@ -176,6 +178,7 @@ export function TransactionCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('orders.update'),
|
||||
onClick: () => onEdit(transaction),
|
||||
},
|
||||
{
|
||||
@ -183,6 +186,7 @@ export function TransactionCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('orders.delete'),
|
||||
onClick: () => onDelete(transaction),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -10,12 +10,13 @@ export type Category = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (category: Category) => void;
|
||||
handleDeleteClick: (category: Category) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createCategoryColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<Category>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -43,6 +44,7 @@ export function createCategoryColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('categories.update'),
|
||||
onClick: () => handleEdit(category),
|
||||
},
|
||||
{
|
||||
@ -50,6 +52,7 @@ export function createCategoryColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('categories.delete'),
|
||||
onClick: () => handleDeleteClick(category),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -10,6 +10,7 @@ import { PageHeader } from '@/components/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -32,6 +33,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function CategoryIndex({ categories, highlight }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<Category | null>(null);
|
||||
const [deleting, setDeleting] = useState<Category | null>(null);
|
||||
@ -66,6 +68,7 @@ export default function CategoryIndex({ categories, highlight }: Props) {
|
||||
const columns = createCategoryColumns({
|
||||
handleEdit: (category) => setEditing(category),
|
||||
handleDeleteClick: (category) => setDeleting(category),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -98,15 +101,17 @@ export default function CategoryIndex({ categories, highlight }: Props) {
|
||||
)
|
||||
}
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('categories.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -12,12 +12,13 @@ export type Customer = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (customer: Customer) => void;
|
||||
handleDeleteClick: (customer: Customer) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createCustomerColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<Customer>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -61,6 +62,7 @@ export function createCustomerColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('customers.update'),
|
||||
onClick: () => handleEdit(customer),
|
||||
},
|
||||
{
|
||||
@ -68,6 +70,7 @@ export function createCustomerColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('customers.delete'),
|
||||
onClick: () => handleDeleteClick(customer),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -11,6 +11,7 @@ import { PhoneNumberInput } from '@/components/phone-number-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -32,6 +33,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function CustomerIndex({ customers }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<Customer | null>(null);
|
||||
const [deleting, setDeleting] = useState<Customer | null>(null);
|
||||
@ -66,6 +68,7 @@ export default function CustomerIndex({ customers }: Props) {
|
||||
const columns = createCustomerColumns({
|
||||
handleEdit: (customer) => setEditing(customer),
|
||||
handleDeleteClick: (customer) => setDeleting(customer),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -76,15 +79,17 @@ export default function CustomerIndex({ customers }: Props) {
|
||||
<PageHeader
|
||||
title="Customer"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('customers.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -75,6 +75,7 @@ type CreateColumnsParams = {
|
||||
variant: ProductVariant,
|
||||
) => void;
|
||||
toggleStatusUrl: (id: number) => string;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createProductColumns(
|
||||
@ -86,6 +87,7 @@ export function createProductColumns(
|
||||
handleVariantEdit,
|
||||
handleVariantDeleteClick,
|
||||
toggleStatusUrl,
|
||||
can,
|
||||
} = params;
|
||||
|
||||
return [
|
||||
@ -352,6 +354,7 @@ export function createProductColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('products.update'),
|
||||
onClick: () => handleEdit(product),
|
||||
},
|
||||
{
|
||||
@ -359,6 +362,7 @@ export function createProductColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('products.delete'),
|
||||
onClick: () => handleDeleteClick(product),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -32,7 +33,7 @@ import {
|
||||
destroy as variantDestroy,
|
||||
edit as variantEdit,
|
||||
} from '@/routes/admin/master/products/variants';
|
||||
import { Head, router } from '@inertiajs/react';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { Link, Plus } from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { Product, ProductVariant } from './columns';
|
||||
@ -60,6 +61,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function ProductIndex({ products, categories, filters }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Product | null>(null);
|
||||
const [deletingVariant, setDeletingVariant] = useState<{
|
||||
product: Product;
|
||||
@ -249,12 +251,14 @@ export default function ProductIndex({ products, categories, filters }: Props) {
|
||||
<PageHeader
|
||||
title="Produk"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={productCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('products.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={productCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { RowActions } from '@/components/row-actions';
|
||||
import { ToggleStatus } from '@/components/toggle-status';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import type { Product } from './columns';
|
||||
|
||||
@ -45,6 +46,7 @@ export function ProductCardRow({
|
||||
onDelete,
|
||||
toggleStatusUrl,
|
||||
}: ProductCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const variants = product.product_variants ?? [];
|
||||
const totalStock = variants.reduce((sum, v) => sum + (v.stock ?? 0), 0);
|
||||
const totalReject = variants.reduce(
|
||||
@ -147,6 +149,7 @@ export function ProductCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('products.update'),
|
||||
onClick: () => onEdit(product),
|
||||
},
|
||||
{
|
||||
@ -154,6 +157,7 @@ export function ProductCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('products.delete'),
|
||||
onClick: () => onDelete(product),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import { stockMutations } from '@/routes/admin/master/products/variants';
|
||||
@ -26,6 +27,7 @@ export function VariantSubRow({
|
||||
onEditVariant: (product: Product, variant: ProductVariant) => void;
|
||||
onDeleteVariantClick: (product: Product, variant: ProductVariant) => void;
|
||||
}) {
|
||||
const { can } = useCan();
|
||||
const variants = product.product_variants ?? [];
|
||||
const [transferVariant, setTransferVariant] = useState<{
|
||||
product: Product;
|
||||
@ -122,6 +124,7 @@ export function VariantSubRow({
|
||||
icon: (
|
||||
<ArrowRightLeft className="h-4 w-4" />
|
||||
),
|
||||
show: can('stocks.view'),
|
||||
onClick: () =>
|
||||
setTransferVariant({
|
||||
product,
|
||||
@ -133,6 +136,7 @@ export function VariantSubRow({
|
||||
icon: (
|
||||
<ScrollText className="h-4 w-4" />
|
||||
),
|
||||
show: can('stocks.view'),
|
||||
onClick: () => {
|
||||
router.visit(
|
||||
stockMutations.url({
|
||||
@ -147,6 +151,7 @@ export function VariantSubRow({
|
||||
icon: (
|
||||
<Pencil className="h-4 w-4" />
|
||||
),
|
||||
show: can('products.update'),
|
||||
onClick: () =>
|
||||
onEditVariant(
|
||||
product,
|
||||
@ -158,6 +163,7 @@ export function VariantSubRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('products.delete'),
|
||||
onClick: () =>
|
||||
onDeleteVariantClick(
|
||||
product,
|
||||
|
||||
@ -28,6 +28,7 @@ import { useState } from 'react';
|
||||
import type { RawMaterial, RawMaterialVariant } from './columns';
|
||||
import { RawMaterialCardRow } from './raw-material-card';
|
||||
import { RawMaterialVariantSubRow } from './variant/sub-row';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
|
||||
type Props = {
|
||||
rawMaterials: {
|
||||
@ -44,6 +45,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function RawMaterialIndex({ rawMaterials, filters }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<RawMaterial | null>(null);
|
||||
const [deletingVariant, setDeletingVariant] = useState<{
|
||||
rawMaterial: RawMaterial;
|
||||
@ -154,12 +156,14 @@ export default function RawMaterialIndex({ rawMaterials, filters }: Props) {
|
||||
<PageHeader
|
||||
title="Bahan Baku"
|
||||
actions={
|
||||
<Link href={rawMaterialCreate.url()}>
|
||||
<Button>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Button>
|
||||
</Link>
|
||||
can('raw_materials.create') ? (
|
||||
<Link href={rawMaterialCreate.url()}>
|
||||
<Button>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Button>
|
||||
</Link>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { RowActions } from '@/components/row-actions';
|
||||
import { ToggleStatus } from '@/components/toggle-status';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import type { RawMaterial } from './columns';
|
||||
@ -26,6 +27,7 @@ export function RawMaterialCardRow({
|
||||
onDelete,
|
||||
toggleStatusUrl,
|
||||
}: RawMaterialCardRowParams) {
|
||||
const { can } = useCan();
|
||||
const variants = rawMaterial.raw_material_prices ?? [];
|
||||
const totalStock = variants.reduce(
|
||||
(sum, v) => sum + (Number(v.stock) || 0),
|
||||
@ -97,6 +99,7 @@ export function RawMaterialCardRow({
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('raw_materials.update'),
|
||||
onClick: () => onEdit(rawMaterial),
|
||||
},
|
||||
{
|
||||
@ -104,6 +107,7 @@ export function RawMaterialCardRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('raw_materials.delete'),
|
||||
onClick: () => onDelete(rawMaterial),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { formatNumber } from '@/lib/format';
|
||||
import { formatCurrency } from '@/lib/utils';
|
||||
import {
|
||||
@ -25,6 +26,7 @@ export function RawMaterialVariantSubRow({
|
||||
}: {
|
||||
rawMaterial: RawMaterial;
|
||||
}) {
|
||||
const { can } = useCan();
|
||||
const variants = rawMaterial.raw_material_prices ?? [];
|
||||
const [deletingVariant, setDeletingVariant] =
|
||||
useState<RawMaterialVariant | null>(null);
|
||||
@ -107,6 +109,7 @@ export function RawMaterialVariantSubRow({
|
||||
icon: (
|
||||
<Pencil className="h-4 w-4" />
|
||||
),
|
||||
show: can('raw_materials.update'),
|
||||
onClick: () => {
|
||||
router.visit(
|
||||
variantEdit.url({
|
||||
@ -122,6 +125,7 @@ export function RawMaterialVariantSubRow({
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('raw_materials.delete'),
|
||||
onClick: () =>
|
||||
setDeletingVariant(variant),
|
||||
},
|
||||
|
||||
@ -12,12 +12,13 @@ export type Supplier = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (supplier: Supplier) => void;
|
||||
handleDeleteClick: (supplier: Supplier) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createSupplierColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<Supplier>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -61,6 +62,7 @@ export function createSupplierColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('suppliers.update'),
|
||||
onClick: () => handleEdit(supplier),
|
||||
},
|
||||
{
|
||||
@ -68,6 +70,7 @@ export function createSupplierColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('suppliers.delete'),
|
||||
onClick: () => handleDeleteClick(supplier),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -11,6 +11,7 @@ import { PhoneNumberInput } from '@/components/phone-number-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
destroy,
|
||||
@ -32,6 +33,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function SupplierIndex({ suppliers }: Props) {
|
||||
const { can } = useCan();
|
||||
const [createOpen, setCreateOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<Supplier | null>(null);
|
||||
const [deleting, setDeleting] = useState<Supplier | null>(null);
|
||||
@ -66,6 +68,7 @@ export default function SupplierIndex({ suppliers }: Props) {
|
||||
const columns = createSupplierColumns({
|
||||
handleEdit: (supplier) => setEditing(supplier),
|
||||
handleDeleteClick: (supplier) => setDeleting(supplier),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -76,15 +79,17 @@ export default function SupplierIndex({ suppliers }: Props) {
|
||||
<PageHeader
|
||||
title="Supplier"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
can('suppliers.create') ? (
|
||||
<Button asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</button>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@ -11,12 +11,13 @@ export type Role = {
|
||||
type CreateColumnsParams = {
|
||||
handleEdit: (role: Role) => void;
|
||||
handleDeleteClick: (role: Role) => void;
|
||||
can: (permission: string) => boolean;
|
||||
};
|
||||
|
||||
export function createRoleColumns(
|
||||
params: CreateColumnsParams,
|
||||
): ColumnDef<Role>[] {
|
||||
const { handleEdit, handleDeleteClick } = params;
|
||||
const { handleEdit, handleDeleteClick, can } = params;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -59,6 +60,7 @@ export function createRoleColumns(
|
||||
{
|
||||
label: 'Edit',
|
||||
icon: <Pencil className="h-4 w-4" />,
|
||||
show: can('roles.update'),
|
||||
onClick: () => handleEdit(role),
|
||||
},
|
||||
{
|
||||
@ -66,6 +68,7 @@ export function createRoleColumns(
|
||||
icon: (
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
),
|
||||
show: can('roles.delete'),
|
||||
onClick: () => handleDeleteClick(role),
|
||||
},
|
||||
]}
|
||||
|
||||
@ -6,6 +6,7 @@ import { DataTable } from '@/components/data-table';
|
||||
import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
|
||||
import { PageHeader } from '@/components/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCan } from '@/hooks/use-can';
|
||||
import { useServerTable } from '@/hooks/use-server-table';
|
||||
import {
|
||||
index as rolesIndex,
|
||||
@ -27,6 +28,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export default function RoleIndex({ roles }: Props) {
|
||||
const { can } = useCan();
|
||||
const [deleting, setDeleting] = useState<Role | null>(null);
|
||||
|
||||
const pagination: PaginationState = {
|
||||
@ -61,6 +63,7 @@ export default function RoleIndex({ roles }: Props) {
|
||||
router.visit(roleEdit.url(role.id));
|
||||
},
|
||||
handleDeleteClick: (role) => setDeleting(role),
|
||||
can,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -71,12 +74,14 @@ export default function RoleIndex({ roles }: Props) {
|
||||
<PageHeader
|
||||
title="Role & Permission"
|
||||
actions={
|
||||
<Button asChild>
|
||||
<Link href={roleCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
can('roles.create') ? (
|
||||
<Button asChild>
|
||||
<Link href={roleCreate.url()}>
|
||||
<Plus className="h-4 w-4" />
|
||||
Tambah
|
||||
</Link>
|
||||
</Button>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user