No diacritics or written ezafe ی in the UI; map without the speech banner, companions cheering along the path; familiar payment sheet with gateway logos and per-channel methods; account deletion moved under «حساب کاربری»
- Text: kasra/fatha/damma/shadda/sukun/hamza-above and «هی» ezafe removed from every user-visible string (comments untouched); tanwin kept. Stale copy fixed (question packs are no longer sold), awkward onboarding sentences rewritten, سؤال → سوال. plainPersian() in MathText cleans the live tutor stream. - Home: the mascot + speech bubble header is gone; the selected companion hops beside the current island and sits at every third bend (CSS transform animations only). - Checkout: order summary, payment-method rows with Zarinpal/Bazaar icons and radio, amount on the pay button, lock trust line, darker overlay. paymentMethods in config.js per channel (web: zarinpal, app: zarinpal+bazaar by default). - Profile: «ورود با حساب دیگر» removed (it was logout); new «حساب کاربری» sheet shows phone/ID and holds «حذف حساب کاربری»; logout is a red row. Delete sheet tells Bazaar subscribers to cancel renewal in Bazaar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -257,7 +257,7 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
|
||||
<p className="text-sm text-muted">دارم نتیجهت رو ثبت میکنم…</p>
|
||||
) : (
|
||||
<>
|
||||
<InlineError>نتیجهی این تمرین ثبت نشد: {friendlyError(phase.error)}</InlineError>
|
||||
<InlineError>نتیجه این تمرین ثبت نشد: {friendlyError(phase.error)}</InlineError>
|
||||
<PrimaryButton color={color} onClick={() => void finish()}>دوباره ثبت کن</PrimaryButton>
|
||||
<SecondaryButton onClick={nav.back}>بیخیال، برگرد</SecondaryButton>
|
||||
</>
|
||||
@@ -281,9 +281,9 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
|
||||
|
||||
const mood: SeyarMood = !answer ? 'idle' : answer.correct ? 'excited' : outOfHearts ? 'depressed' : 'sad';
|
||||
const bubble = !answer
|
||||
? selected === null ? 'جوابِ درست رو انتخاب کن!' : 'مطمئنی؟ «بررسی» رو بزن.'
|
||||
? selected === null ? 'جواب درست رو انتخاب کن!' : 'مطمئنی؟ «بررسی» رو بزن.'
|
||||
: answer.correct
|
||||
? combo >= 2 ? `${toFa(combo)} تا پشتِ هم درست! داری عالی پیش میری` : PRAISE[index % PRAISE.length]
|
||||
? combo >= 2 ? `${toFa(combo)} تا پشت هم درست! داری عالی پیش میری` : PRAISE[index % PRAISE.length]
|
||||
: outOfHearts
|
||||
? 'قلبهات تموم شد؛ یه کم استراحت کنیم.'
|
||||
: NUDGE[index % NUDGE.length];
|
||||
@@ -343,7 +343,7 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
|
||||
|
||||
<div className="rounded-3xl border border-line bg-white p-5 shadow-sm">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<span className="text-xs font-medium text-muted">سوالِ {toFa(index + 1)}</span>
|
||||
<span className="text-xs font-medium text-muted">سوال {toFa(index + 1)}</span>
|
||||
</div>
|
||||
<h2 className="whitespace-pre-line text-base font-bold leading-8 text-ink"><MathText text={question.prompt} /></h2>
|
||||
{question.figure ? <div className="mt-3"><Diagram spec={question.figure} /></div> : null}
|
||||
@@ -389,7 +389,7 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
|
||||
</button>
|
||||
)}
|
||||
<PrimaryButton color={answer.correct ? '#5FBF8F' : color} onClick={() => void next()}>
|
||||
{isLast ? 'پایانِ تمرین' : 'ادامه'} <ChevronLeft size={18} />
|
||||
{isLast ? 'پایان تمرین' : 'ادامه'} <ChevronLeft size={18} />
|
||||
</PrimaryButton>
|
||||
</>
|
||||
) : (
|
||||
@@ -417,7 +417,7 @@ function HeartsRow({ hearts }: { hearts: Hearts | null }) {
|
||||
if (hearts?.isUnlimited) {
|
||||
return (
|
||||
<div className="mt-3 flex items-center justify-center gap-1.5 text-xs font-bold text-coral">
|
||||
<Heart size={18} fill="#ED6956" /> <InfinityIcon size={18} /> قلبِ نامحدود
|
||||
<Heart size={18} fill="#ED6956" /> <InfinityIcon size={18} /> قلب نامحدود
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -495,7 +495,7 @@ function Result({
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-ink">{result.stars === 3 ? 'عالی بود!' : result.stars === 2 ? 'آفرین!' : 'تموم شد!'}</h2>
|
||||
{nodeMode && <p className="mt-1 text-sm font-bold" style={{ color }}>این جزیره رو تموم کردی</p>}
|
||||
<p className="mt-1 text-sm text-muted">{toFa(correct)} جوابِ درست از {toFa(total)} سوال</p>
|
||||
<p className="mt-1 text-sm text-muted">{toFa(correct)} جواب درست از {toFa(total)} سوال</p>
|
||||
{/* نمرهی کم: تلاش و راه را ستایش کن، نه «باهوشی» را (پژوهشهای ذهنیتِ رشد)؛ و راهِ بعدی را نشان بده. */}
|
||||
{result.stars <= 1 && (
|
||||
<p className="mt-2 text-xs leading-6 text-body">
|
||||
@@ -517,7 +517,7 @@ function Result({
|
||||
</div>
|
||||
</div>}
|
||||
<PrimaryButton color={color} loading={loadingNext} onClick={() => then(() => void goNext())}>
|
||||
{nodeMode && nextNode ? 'بریم جزیرهی بعدی' : 'ادامه'} <ChevronLeft size={18} />
|
||||
{nodeMode && nextNode ? 'بریم جزیره بعدی' : 'ادامه'} <ChevronLeft size={18} />
|
||||
</PrimaryButton>
|
||||
{nodeMode && nextNode && (
|
||||
<button type="button" onClick={() => then(nav.back)} className="-mt-2 py-2 text-sm font-bold text-muted">
|
||||
@@ -534,13 +534,13 @@ function Result({
|
||||
* تلاش و راه ستایش میشود و قدمِ بعدی گفته میشود، نه اینکه «اشکالی نداره» تنها بماند.
|
||||
*/
|
||||
const PRAISE = ['آفرین! درست بود', 'دقیقاً همینه!', 'عالی! خوب فکر کردی', 'درسته! داری راه میفتی'];
|
||||
const NUDGE = ['نزدیک بودی! جوابِ درست رو ببین.', 'اشکالی نداره؛ از همین اشتباه یاد میگیریم.', 'این یکی سخت بود؛ جوابِ درست سبز شده.'];
|
||||
const NUDGE = ['نزدیک بودی! جواب درست رو ببین.', 'اشکالی نداره؛ از همین اشتباه یاد میگیریم.', 'این یکی سخت بود؛ جواب درست سبز شده.'];
|
||||
|
||||
/** «راهنمای مهربون»ِ پی: نکتهی عمومیِ کوتاه بعد از جوابِ غلط؛ نه جوابِ سوال، فقط عادتِ خوبِ حل کردن. */
|
||||
const PI_TIPS = [
|
||||
'صورتِ سوال رو یه بار دیگه آروم بخون؛ کلمهی «نیست» یا «بیشترین» زیاد جا میمونه.',
|
||||
'علامتِ منفیها رو یه بار دیگه چک کن.',
|
||||
'اول داخلِ پرانتز، بعد ضرب و تقسیم، آخرش جمع و تفریق.',
|
||||
'صورت سوال رو یه بار دیگه آروم بخون؛ کلمه «نیست» یا «بیشترین» زیاد جا میمونه.',
|
||||
'علامت منفیها رو یه بار دیگه چک کن.',
|
||||
'اول داخل پرانتز، بعد ضرب و تقسیم، آخرش جمع و تفریق.',
|
||||
'جوابت رو بذار توی سوال؛ اگه درست درنیومد یه جا اشتباه شده.',
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user