202 lines
5.1 KiB
TypeScript
202 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
import { BadgeIndianRupee, Plus } from 'lucide-react';
|
|
|
|
import { PageHeader } from '@/components/page-header';
|
|
import { Button } from '@/components/ui/button';
|
|
import { PERMISSIONS } from '@/constants/permissions';
|
|
import { PermissionGuard } from '@/guards';
|
|
import type { Plan } from '@/types';
|
|
|
|
import { usePlanColumns } from './components/PlanColumns';
|
|
import { PlanFilters } from './components/PlanFilters';
|
|
import { PlanSheet } from './components/PlanSheet';
|
|
import { PlanTable } from './components/PlanTable';
|
|
import { usePlanFilters } from './hooks/usePlanFilters';
|
|
import { usePlanForm } from './hooks/usePlanForm';
|
|
import { usePlanStatusMutation } from './hooks/usePlanMutations';
|
|
import {
|
|
useOrganizationPermissionTreeQuery,
|
|
usePlansQuery,
|
|
} from './hooks/usePlanQueries';
|
|
|
|
export default function PlansPage() {
|
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
const pendingPlanRef = useRef<Plan | null>(null);
|
|
const hasSyncedPermissionsRef = useRef(false);
|
|
const {
|
|
skip,
|
|
setSkip,
|
|
limit,
|
|
setLimit,
|
|
sorting,
|
|
setSorting,
|
|
searchTerm,
|
|
debouncedSearchTerm,
|
|
setSearchTerm,
|
|
statusFilter,
|
|
setStatusFilter,
|
|
} = usePlanFilters();
|
|
|
|
const plansQuery = usePlansQuery({
|
|
skip,
|
|
limit,
|
|
searchTerm: debouncedSearchTerm,
|
|
statusFilter,
|
|
sorting,
|
|
});
|
|
const permissionsQuery = useOrganizationPermissionTreeQuery(isSheetOpen);
|
|
|
|
const handleSheetOpenChange = useCallback((open: boolean) => {
|
|
if (!open) {
|
|
pendingPlanRef.current = null;
|
|
}
|
|
setIsSheetOpen(open);
|
|
}, []);
|
|
|
|
const planForm = usePlanForm({
|
|
permissionTree: permissionsQuery.permissionTree,
|
|
onSaved: () => handleSheetOpenChange(false),
|
|
});
|
|
const { openCreate: prepareCreatePlan, openEdit: prepareEditPlan } = planForm;
|
|
const {
|
|
register,
|
|
control,
|
|
onSubmit,
|
|
planId,
|
|
permissionIds,
|
|
setPermissionIds,
|
|
errors,
|
|
isSubmitted,
|
|
canSubmit,
|
|
isSaving,
|
|
} = planForm;
|
|
const statusMutation = usePlanStatusMutation();
|
|
|
|
const openCreate = useCallback(() => {
|
|
pendingPlanRef.current = null;
|
|
setIsSheetOpen(true);
|
|
prepareCreatePlan();
|
|
}, [prepareCreatePlan]);
|
|
|
|
const openEdit = useCallback(
|
|
(plan: Plan) => {
|
|
pendingPlanRef.current = plan;
|
|
setIsSheetOpen(true);
|
|
prepareEditPlan(plan);
|
|
},
|
|
[prepareEditPlan],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (!isSheetOpen) {
|
|
hasSyncedPermissionsRef.current = false;
|
|
return;
|
|
}
|
|
|
|
if (
|
|
hasSyncedPermissionsRef.current ||
|
|
permissionsQuery.isLoading ||
|
|
permissionsQuery.permissionTree.length === 0
|
|
) {
|
|
return;
|
|
}
|
|
|
|
hasSyncedPermissionsRef.current = true;
|
|
|
|
if (pendingPlanRef.current) {
|
|
prepareEditPlan(pendingPlanRef.current);
|
|
return;
|
|
}
|
|
|
|
if (!planId) {
|
|
prepareCreatePlan();
|
|
}
|
|
}, [
|
|
isSheetOpen,
|
|
permissionsQuery.isLoading,
|
|
permissionsQuery.permissionTree,
|
|
planId,
|
|
prepareCreatePlan,
|
|
prepareEditPlan,
|
|
]);
|
|
|
|
const toggleStatus = useCallback(
|
|
(plan: Plan) => {
|
|
statusMutation.mutate(plan);
|
|
},
|
|
[statusMutation],
|
|
);
|
|
|
|
const columns = usePlanColumns();
|
|
|
|
const plans = plansQuery.data?.items ?? [];
|
|
const total = plansQuery.data?.total ?? plansQuery.data?.totalItems ?? 0;
|
|
const toolbar = useMemo(
|
|
() => (
|
|
<PlanFilters
|
|
searchTerm={searchTerm}
|
|
statusFilter={statusFilter}
|
|
onSearchChange={setSearchTerm}
|
|
onStatusChange={setStatusFilter}
|
|
/>
|
|
),
|
|
[searchTerm, setSearchTerm, setStatusFilter, statusFilter],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<main className="relative z-10 space-y-5">
|
|
<PageHeader
|
|
title="Plan Management"
|
|
description="Manage subscription plans, limits, and permission access"
|
|
icon={BadgeIndianRupee}
|
|
actions={
|
|
<PermissionGuard permissions={PERMISSIONS.PLAN.CREATE}>
|
|
<Button onClick={openCreate}>
|
|
<Plus className="mr-2 size-4" />
|
|
Add Plan
|
|
</Button>
|
|
</PermissionGuard>
|
|
}
|
|
/>
|
|
|
|
<PlanTable
|
|
columns={columns}
|
|
plans={plans}
|
|
isLoading={plansQuery.isLoading}
|
|
toolbar={toolbar}
|
|
skip={skip}
|
|
limit={limit}
|
|
total={total}
|
|
sorting={sorting}
|
|
onPageChange={setSkip}
|
|
onLimitChange={setLimit}
|
|
onSortingChange={setSorting}
|
|
onEdit={openEdit}
|
|
onToggleStatus={toggleStatus}
|
|
pendingPlanId={statusMutation.variables?.id}
|
|
/>
|
|
</main>
|
|
|
|
<PlanSheet
|
|
open={isSheetOpen}
|
|
onOpenChange={handleSheetOpenChange}
|
|
planId={planId}
|
|
register={register}
|
|
control={control}
|
|
errors={errors}
|
|
isSubmitted={isSubmitted}
|
|
onSubmit={onSubmit}
|
|
canSubmit={canSubmit}
|
|
permissionTree={permissionsQuery.permissionTree}
|
|
permissionIds={permissionIds}
|
|
onPermissionIdsChange={setPermissionIds}
|
|
isPermissionsLoading={permissionsQuery.isLoading}
|
|
isSaving={isSaving}
|
|
/>
|
|
</>
|
|
);
|
|
}
|