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