From 9e2eecf9dfcdac19e0ba0a84eaae193ce66b1ac7 Mon Sep 17 00:00:00 2001 From: Kenneth Obsequio Date: Sun, 28 Jun 2026 11:31:37 +0800 Subject: [PATCH] push pushy Signed-off-by: Kenneth Obsequio --- src/modules/admin/pages/tiers/PlanPolicy.jsx | 298 ------------------- src/modules/admin/pages/tiers/ViewPlan.jsx | 11 +- 2 files changed, 1 insertion(+), 308 deletions(-) delete mode 100644 src/modules/admin/pages/tiers/PlanPolicy.jsx diff --git a/src/modules/admin/pages/tiers/PlanPolicy.jsx b/src/modules/admin/pages/tiers/PlanPolicy.jsx deleted file mode 100644 index 03afe7b..0000000 --- a/src/modules/admin/pages/tiers/PlanPolicy.jsx +++ /dev/null @@ -1,298 +0,0 @@ -import { useEffect, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { ArrowLeft, House, ShieldCheck, Plus, Trash2 } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Badge } from "@/components/ui/badge"; -import { Separator } from "@/components/ui/separator"; -import { Skeleton } from "@/components/ui/skeleton"; -import { - Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from "@/components/ui/select"; -import AppBreadcrumb from "@/components/generic/Breadcrumb/AppBreadcrumb"; -import { PageMeta } from "@/contexts/MetadataContext"; -import { AdminTierPoliciesProvider, useAdminTierPolicies } from "@/contexts/AdminTierPoliciesContext"; -import { useTiers } from "@/contexts/AdminTiersContext"; -import api from "@/utils/api.util"; - -// ─── Rule type definitions ──────────────────────────────────────────────────── - -const RULE_DEFS = { - course_subscription_access: { - label: "Course Subscription Access", - description: "Which course subscription levels this plan can unlock.", - default: { type: "course_subscription_access", levels: ["free"] }, - }, - required_active_tier: { - label: "Required Active Tier", - description: "User's tier must be at least this rank to access content.", - default: { type: "required_active_tier", tier: "" }, - }, - group_restriction: { - label: "Group Restriction", - description: "Only users in selected groups can access content.", - default: { type: "group_restriction", group_ids: [] }, - }, -}; - -// ─── Rule Editors ───────────────────────────────────────────────────────────── - -function CourseAccessEditor({ rule, onChange }) { - const [availableLevels, setAvailableLevels] = useState(["free"]); - - useEffect(() => { - api.get("/admin/tiers/categories") - .then(({ data }) => { - setAvailableLevels((data.data ?? []).filter((c) => c.is_active).map((c) => c.slug)); - }) - .catch(() => {}); - }, []); - - const toggle = (level) => { - const levels = rule.levels ?? []; - onChange({ ...rule, levels: levels.includes(level) ? levels.filter((l) => l !== level) : [...levels, level] }); - }; - - return ( -
- {availableLevels.map((lvl) => ( - - ))} -
- ); -} - -function RequiredTierEditor({ rule, onChange }) { - const [categories, setCategories] = useState([]); - - useEffect(() => { - api.get("/admin/tiers/categories") - .then(({ data }) => setCategories((data.data ?? []).filter((c) => c.is_active && !c.is_default))) - .catch(() => {}); - }, []); - - return ( - - ); -} - -function GroupRestrictionEditor({ rule, onChange }) { - const [groups, setGroups] = useState([]); - - useEffect(() => { - api.get("/admin/groups").then(({ data }) => setGroups(data.data?.data ?? [])).catch(() => {}); - }, []); - - const toggleGroup = (gid) => { - const ids = rule.group_ids ?? []; - onChange({ ...rule, group_ids: ids.includes(gid) ? ids.filter((id) => id !== gid) : [...ids, gid] }); - }; - - return ( -
- {groups.length === 0 &&

No groups found.

} - {groups.map((g) => { - const selected = (rule.group_ids ?? []).includes(Number(g.group_id)); - return ( - - ); - })} -
- ); -} - -function RuleCard({ rule, index, onChange, onRemove }) { - const def = RULE_DEFS[rule.type]; - return ( -
-
-
-

{def?.label ?? rule.type}

-

{def?.description}

-
- -
- {rule.type === "course_subscription_access" && onChange(index, r)} />} - {rule.type === "required_active_tier" && onChange(index, r)} />} - {rule.type === "group_restriction" && onChange(index, r)} />} -
- ); -} - -function SectionCard({ icon: Icon, title, children }) { - return ( -
-
- {Icon && } -

{title}

-
- - {children} -
- ); -} - -// ─── Inner page ─────────────────────────────────────────────────────────────── - -function PlanPolicyInner() { - const navigate = useNavigate(); - const { planId } = useParams(); - const { fetchPlan, plan, loading: planLoading } = useTiers(); - const { fetchPlanPolicy, savePlanPolicy, policy, loading } = useAdminTierPolicies(); - - const [rules, setRules] = useState([]); - - useEffect(() => { - fetchPlan(planId); - fetchPlanPolicy(planId); - }, [planId]); - - useEffect(() => { - if (policy) setRules(policy.access_rules ?? []); - }, [policy]); - - const handleRuleChange = (index, updated) => - setRules((prev) => prev.map((r, i) => (i === index ? updated : r))); - - const removeRule = (index) => - setRules((prev) => prev.filter((_, i) => i !== index)); - - const addRule = (type) => { - const def = RULE_DEFS[type]; - if (!def) return; - setRules((prev) => [...prev, { ...def.default }]); - }; - - const usedTypes = new Set(rules.map((r) => r.type)); - - const handleSave = async () => { - await savePlanPolicy(planId, { access_rules: rules }); - }; - - return ( -
- -
-
- -
- , to: "/admin" }, - { label: "Plans", to: "/admin/tiers/plans" }, - { label: plan?.label ?? `Plan #${planId}`, to: `/admin/tiers/plans/${planId}/view` }, - { label: "Policy" }, - ]} /> -
- -
-
- -
-

Access Policy

-

- {planLoading ? : (plan?.label ?? `Plan #${planId}`)} -

-
-
- -
- -
- - - {rules.length === 0 && ( -

- No rules defined. Content access falls back to tier rank comparison. -

- )} - -
- {rules.map((rule, i) => ( - removeRule(i)} - /> - ))} -
- -
-

Add Rule

-
- {Object.entries(RULE_DEFS).map(([type, def]) => ( - - ))} -
-
-
- - {plan && ( -
- {plan.tier} - {plan.label} - · - {plan.duration_days} days -
- )} - -
-
-
-
- ); -} - -export default function PlanPolicy() { - return ( - - - - ); -} diff --git a/src/modules/admin/pages/tiers/ViewPlan.jsx b/src/modules/admin/pages/tiers/ViewPlan.jsx index 5af2e7b..e443349 100644 --- a/src/modules/admin/pages/tiers/ViewPlan.jsx +++ b/src/modules/admin/pages/tiers/ViewPlan.jsx @@ -1,6 +1,6 @@ import { useEffect, useState, useMemo } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { ArrowLeft, House, Pencil, Tag, BadgeCheck, ShieldCheck } from "lucide-react"; +import { ArrowLeft, House, Pencil, Tag, BadgeCheck } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Skeleton } from "@/components/ui/skeleton"; @@ -86,15 +86,6 @@ export default function ViewPlan() {
-