forked from Tadrisino/MathApp_frontend
parents screen: tell the child and the parent apart
A linked child (demo user Ali) was told "you are linked to Ali" and the screen asked for the parent-only weekly report, which 404s. GET /family/link does not say which side the caller is on, so the role now comes from the weekly report: it answers only for the parent. The child sees a line saying their parent follows their progress and no invite/accept forms. Found on the live site with the demo accounts. deploy.sh now prints the full API URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,6 @@ step "جابهجایی"
|
||||
rm -rf dist.prev
|
||||
[ -d dist ] && mv dist dist.prev
|
||||
mv dist.next dist
|
||||
API="$(grep -o 'https\?://[a-zA-Z0-9.-]*/api' dist/assets/*.js | head -1 | cut -d: -f2-)"
|
||||
API="$(grep -oh 'https\?://[a-zA-Z0-9.-]*/api' dist/assets/*.js | head -1)"
|
||||
printf ' منتشر شد. آدرسِ API در build: %s\n' "${API:-(همدامنه /api یا config.js)}"
|
||||
printf ' کشِ آروان را برای index.html و config.js پاک کنید اگر تغییری دیده نشد.\n'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { BookOpen, Flame, Link2, Star, Trophy, UserPlus } from 'lucide-react';
|
||||
import { api, ApiError, type FamilyLink } from '@/api';
|
||||
import { api, ApiError, type FamilyLink, type FamilyWeeklyReport } from '@/api';
|
||||
import { useAsync } from '@/lib/useAsync';
|
||||
import { useToast } from '@/components/Toast';
|
||||
import { InlineError, LoadingState, PrimaryButton, Screen, ScreenBody, ScreenHeader } from '@/components/ui';
|
||||
import { ErrorState, InlineError, LoadingState, PrimaryButton, Screen, ScreenBody, ScreenHeader } from '@/components/ui';
|
||||
import { friendlyError } from '@/lib/errors';
|
||||
import { digitsOnly, formatJalaliDate, toFa } from '@/lib/format';
|
||||
|
||||
@@ -13,26 +13,37 @@ import { digitsOnly, formatJalaliDate, toFa } from '@/lib/format';
|
||||
* گزارشِ هفتگی را میبیند.
|
||||
*/
|
||||
export function FamilyScreen() {
|
||||
const link = useAsync(
|
||||
() => api.family.link().catch((err) => {
|
||||
// GET /family/link نمیگوید کاربر در این اتصال والد است یا فرزند؛ گزارشِ
|
||||
// هفتگی فقط برای والد جواب میدهد و برای فرزند ۴۰۴ است، پس نقش از همان درمیآید.
|
||||
const state = useAsync(async () => {
|
||||
const link = await api.family.link().catch((err) => {
|
||||
if (err instanceof ApiError && err.status === 404) return null;
|
||||
throw err;
|
||||
}),
|
||||
[],
|
||||
);
|
||||
});
|
||||
if (!link || link.status !== 'accepted') return { link, role: null, report: null };
|
||||
try {
|
||||
return { link, role: 'parent' as const, report: await api.family.weeklyReport() };
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && (err.status === 404 || err.status === 403)) return { link, role: 'child' as const, report: null };
|
||||
throw err;
|
||||
}
|
||||
}, []);
|
||||
const data = state.data;
|
||||
|
||||
return (
|
||||
<Screen>
|
||||
<ScreenHeader title="بخشِ والدین" subtitle="پیشرفتِ فرزندت رو هر هفته ببین" color="#FF7A3D" back mascot={{ char: 'sigma', mood: 'happy', size: 56 }} />
|
||||
<ScreenBody className="flex flex-col gap-4">
|
||||
{link.loading ? (
|
||||
{state.loading ? (
|
||||
<LoadingState />
|
||||
) : state.error ? (
|
||||
<ErrorState error={state.error} onRetry={state.reload} />
|
||||
) : (
|
||||
<>
|
||||
{link.data && <LinkStatus link={link.data} />}
|
||||
{link.data?.status === 'accepted' && <WeeklyReport />}
|
||||
<InviteChild onDone={link.reload} />
|
||||
<AcceptInvite onDone={link.reload} />
|
||||
{data?.link && <LinkStatus link={data.link} role={data.role} />}
|
||||
{data?.report && <WeeklyReport report={data.report} />}
|
||||
{data?.role !== 'child' && <InviteChild onDone={state.reload} />}
|
||||
{!data?.role && <AcceptInvite onDone={state.reload} />}
|
||||
</>
|
||||
)}
|
||||
</ScreenBody>
|
||||
@@ -40,23 +51,23 @@ export function FamilyScreen() {
|
||||
);
|
||||
}
|
||||
|
||||
function LinkStatus({ link }: { link: FamilyLink }) {
|
||||
function LinkStatus({ link, role }: { link: FamilyLink; role: 'parent' | 'child' | null }) {
|
||||
const accepted = link.status === 'accepted';
|
||||
return (
|
||||
<div className={`flex items-center gap-3 rounded-3xl p-4 ${accepted ? 'bg-[#EAF8F0]' : 'bg-[#FFF8E1]'}`}>
|
||||
<Link2 size={20} className={accepted ? 'text-mint' : 'text-gold'} />
|
||||
<p className="text-sm leading-7 text-ink">
|
||||
{accepted ? <>به <b>{link.childName || 'فرزندت'}</b> وصلی.</> : 'دعوت فرستاده شده و منتظرِ تأییدِ فرزندته.'}
|
||||
{!accepted
|
||||
? 'دعوت فرستاده شده و منتظرِ تأییدِ فرزندته.'
|
||||
: role === 'child'
|
||||
? 'حسابت به پدر یا مادرت وصله؛ اونها هر هفته پیشرفتت رو میبینن.'
|
||||
: <>به <b>{link.childName || 'فرزندت'}</b> وصلی.</>}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function WeeklyReport() {
|
||||
const report = useAsync(() => api.family.weeklyReport(), []);
|
||||
if (report.loading) return <div className="h-32 animate-pulse rounded-3xl bg-soft" />;
|
||||
if (!report.data) return null;
|
||||
const r = report.data;
|
||||
function WeeklyReport({ report: r }: { report: FamilyWeeklyReport }) {
|
||||
return (
|
||||
<section className="rounded-3xl border border-line bg-white p-4">
|
||||
<h2 className="mb-3 text-sm font-black text-ink">گزارشِ این هفته <span className="text-xs font-medium text-muted">(از {formatJalaliDate(r.weekStart)})</span></h2>
|
||||
|
||||
Reference in New Issue
Block a user