tier plans missing

This commit is contained in:
rgrgogu
2026-08-01 23:02:46 +08:00
parent 510a883974
commit 1315796412
20 changed files with 616 additions and 79 deletions
@@ -6,7 +6,7 @@
// Shared by LessonsList and Dashboard.
import { useNavigate } from "react-router-dom";
import { LockIcon, BookOpen, ShoppingCart } from "lucide-react";
import { LockIcon, BookOpen, ShoppingCart, GraduationCap } from "lucide-react";
import ResponsiveModal from "@/components/generic/ResponsiveModal";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -18,7 +18,9 @@ export default function LessonUpsellModal({ open, onOpenChange, lesson, tierMap
const { fmtCurrency } = useDateFormat();
const courses = lesson?.courses ?? [];
const ownTier = lesson?.subscription ? resolveTierBadge(lesson.subscription, tierMap) : null;
const canBuy = lesson?.product?.is_active && !lesson?.has_purchased;
const purchasable = lesson?.product?.is_active && !lesson?.has_purchased;
const awaitingStarterSet = purchasable && lesson?.purchase_eligible === false;
const canBuy = purchasable && !awaitingStarterSet;
return (
<ResponsiveModal
@@ -57,6 +59,15 @@ export default function LessonUpsellModal({ open, onOpenChange, lesson, tierMap
</div>
)}
{awaitingStarterSet && (
<div className="flex items-center gap-2.5 p-4 rounded-xl border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/40">
<GraduationCap className="size-4 text-amber-700 dark:text-amber-400 shrink-0" />
<p className="text-sm text-amber-800 dark:text-amber-300">
Complete your plan's starter content to unlock individual purchases like this one.
</p>
</div>
)}
{courses.length === 0 && !ownTier ? (
<p className="text-sm text-muted-foreground">
Upgrade your plan to access this content.
@@ -10,7 +10,7 @@
// instead of only ever pointing at an attached course.
import { useNavigate } from "react-router-dom";
import { LockIcon, Zap, ShoppingCart } from "lucide-react";
import { LockIcon, Zap, ShoppingCart, GraduationCap } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useDateFormat } from "@/hooks/useDateFormat";
import { resolveTierBadge } from "@/utils/tierBadge.util";
@@ -20,7 +20,9 @@ export default function LockedContentPanel({ course, item, tierMap = {}, checkou
const { fmtCurrency } = useDateFormat();
const tier = course?.subscription ? tierMap[course.subscription] : null;
const ownTier = item?.subscription ? resolveTierBadge(item.subscription, tierMap) : null;
const canBuy = item?.product?.is_active && !item?.has_purchased && checkoutPath;
const purchasable = item?.product?.is_active && !item?.has_purchased && checkoutPath;
const awaitingStarterSet = purchasable && item?.purchase_eligible === false;
const canBuy = purchasable && !awaitingStarterSet;
return (
<div className="flex flex-col items-center gap-6 py-32 text-center px-4">
@@ -37,6 +39,14 @@ export default function LockedContentPanel({ course, item, tierMap = {}, checkou
: "Upgrade your plan to access this content."}
</p>
</div>
{awaitingStarterSet && (
<div className="flex items-center gap-2.5 p-3 rounded-xl border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/40 max-w-sm">
<GraduationCap className="size-4 text-amber-700 dark:text-amber-400 shrink-0" />
<p className="text-sm text-amber-800 dark:text-amber-300 text-left">
Complete your plan's starter content to unlock individual purchases like this one.
</p>
</div>
)}
<div className="flex flex-col items-center gap-2">
<div className="flex items-center gap-2">
{canBuy && (
@@ -6,7 +6,7 @@
// Shared by UnitsList, UnitDetails, and Dashboard.
import { useNavigate } from "react-router-dom";
import { LockIcon, BookOpen, ShoppingCart } from "lucide-react";
import { LockIcon, BookOpen, ShoppingCart, GraduationCap } from "lucide-react";
import ResponsiveModal from "@/components/generic/ResponsiveModal";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -18,7 +18,10 @@ export default function UnitUpsellModal({ open, onOpenChange, unit, tierMap = {}
const { fmtCurrency } = useDateFormat();
const courses = unit?.courses ?? [];
const ownTier = unit?.subscription ? resolveTierBadge(unit.subscription, tierMap) : null;
const canBuy = unit?.product?.is_active && !unit?.has_purchased;
const purchasable = unit?.product?.is_active && !unit?.has_purchased;
// purchase_eligible is undefined for callers that haven't fetched it yet — treat as eligible (no regression).
const awaitingStarterSet = purchasable && unit?.purchase_eligible === false;
const canBuy = purchasable && !awaitingStarterSet;
return (
<ResponsiveModal
@@ -57,6 +60,15 @@ export default function UnitUpsellModal({ open, onOpenChange, unit, tierMap = {}
</div>
)}
{awaitingStarterSet && (
<div className="flex items-center gap-2.5 p-4 rounded-xl border border-amber-300 bg-amber-50 dark:border-amber-700 dark:bg-amber-950/40">
<GraduationCap className="size-4 text-amber-700 dark:text-amber-400 shrink-0" />
<p className="text-sm text-amber-800 dark:text-amber-300">
Complete your plan's starter content to unlock individual purchases like this one.
</p>
</div>
)}
{courses.length === 0 && !ownTier ? (
<p className="text-sm text-muted-foreground">
Upgrade your plan to access this content.