User-style public ID, tutor quota on plan cards, switch and delete account

- profile shows "User482917" under the name, no copy button
- plan cards start with "N questions a day from Pi (free: M)" taken from the plan itself
- "ورود با حسابِ دیگر" signs out cleanly instead of keeping several accounts on one device
- "حذفِ حساب": SMS code for phone users, typing "حذف" for guests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 06:10:17 +03:30
parent de7cd0bfa8
commit 44871894e0
4 changed files with 156 additions and 34 deletions

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Check, Crown, Heart, Ticket } from 'lucide-react';
import { Check, Crown, Heart, Sparkles, Ticket } from 'lucide-react';
import { api, type Plan } from '@/api';
import { useAsync } from '@/lib/useAsync';
import { Sheet } from '@/components/Sheet';
@@ -40,17 +40,19 @@ export function SubscriptionScreen() {
<div className="flex items-center gap-3 rounded-3xl border border-line bg-white p-4">
<Heart size={22} className="flex-shrink-0 text-coral" fill="#ED6956" />
<p className="text-sm leading-7 text-body">با اشتراک، قلب‌هات هیچ‌وقت تموم نمی‌شن و هر چقدر بخوای تمرین می‌کنی.</p>
<p className="text-sm leading-7 text-body">
با اشتراک هر روز سوالِ بیشتری از دستیار می‌پرسی و قلب‌هات هیچ‌وقت تموم نمی‌شن.
</p>
</div>
{plans.loading ? (
<LoadingState text="دارم پلن‌ها رو میارم…" />
) : plans.error ? (
<ErrorState error={plans.error} onRetry={plans.reload} />
) : !plans.data?.length ? (
) : !plans.data?.plans.length ? (
<EmptyState text="فعلاً پلنی برای خرید تعریف نشده" />
) : (
plans.data.map((plan) => {
plans.data.plans.map((plan) => {
const featured = plan.popular;
const isCurrent = plan.id === activePlanId;
return (
@@ -75,16 +77,27 @@ export function SubscriptionScreen() {
)}
</div>
</div>
{plan.features.length > 0 && (
<ul className="mb-4 flex flex-col gap-2">
{plan.features.map((f) => (
<ul className="mb-4 flex flex-col gap-2">
{/* سقفِ دستیار از خودِ پلن ساخته می‌شود (Plan.ai_daily_quota)، نه از متنِ ویژگی‌ها،
تا عوض کردنِ عدد در ادمین کارت را هم درست عوض کند. */}
{plan.aiDailyQuota > 0 && (
<li className="flex items-center gap-2 text-sm font-bold">
<Sparkles size={14} strokeWidth={3} className={featured ? 'text-white' : 'text-coral'} />
<span>
{toFa(plan.aiDailyQuota)} سوال در روز از دستیارِ «پی»
<span className={`font-medium ${featured ? 'text-white/75' : 'text-muted'}`}>
{' '}(رایگان: {toFa(plans.data!.freeAiDailyQuota)})
</span>
</span>
</li>
)}
{plan.features.map((f) => (
<li key={f} className="flex items-center gap-2 text-sm">
<Check size={14} strokeWidth={3} className={featured ? 'text-white' : 'text-coral'} />
<span className={featured ? 'text-white/90' : 'text-body'}>{f}</span>
</li>
))}
</ul>
)}
</ul>
<button
type="button"
disabled={plan.price === 0 || isCurrent}