/opt/canhelp/apps/web/src/app/specialist-setup
NameSizeModeActions
page.tsx265080644editdlrm
Edit: /opt/canhelp/apps/web/src/app/specialist-setup/page.tsx (26508B)
'use client' import { useState, useEffect, useRef } from 'react' import { useRouter } from 'next/navigation' import { useSession } from '@/lib/auth' import { useLocale } from '@/context/locale' import * as api from '@/lib/api' import type { SpecialistCard } from '@/lib/api' import { CategoryIcon, isCategoryIconUrl } from '@/components/CategoryIcon' const TOTAL_STEPS = 5 // ─── Step indicator ──────────────────────────────────────────────────────── function StepIndicator({ current, total }: { current: number; total: number }) { return (
{Array.from({ length: total }, (_, i) => i + 1).map((n) => (
{n < current ? ( ) : ( n )}
{n < total && (
)}
))}
) } // ─── Step 1: Welcome ─────────────────────────────────────────────────────── function Step1Welcome({ t, onNext }: { t: (k: string, fb?: string) => string; onNext: () => void }) { return (

{t('specialist_setup.step1.title')}

{t('specialist_setup.step1.subtitle')}

{t('specialist_setup.step1.desc')}

{t('specialist_setup.step1.what_next')}

    {[ t('specialist_setup.step1.item1'), t('specialist_setup.step1.item2'), t('specialist_setup.step1.item3'), t('specialist_setup.step1.item4'), t('specialist_setup.step1.item5'), ].map((item, i) => (
  • {i + 1} {item}
  • ))}
) } // ─── Step 2: Basic profile ───────────────────────────────────────────────── function Step2Profile({ t, onNext, onBack, }: { t: (k: string, fb?: string) => string onNext: () => void onBack: () => void }) { const [bio, setBio] = useState('') const [phone, setPhone] = useState('') const [saving, setSaving] = useState(false) const [avatarUrl, setAvatarUrl] = useState(null) const [uploading, setUploading] = useState(false) const fileRef = useRef(null) useEffect(() => { api.request('/users/me', {}).then((u) => { setBio(u.bio ?? '') setPhone(u.phone ?? '') setAvatarUrl(u.image ?? null) }).catch(() => {}) }, []) async function handleAvatarChange(e: React.ChangeEvent) { const file = e.target.files?.[0] if (!file) return setUploading(true) try { const form = new FormData() form.append('file', file) const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}/api/uploads`, { method: 'POST', credentials: 'include', body: form }, ) if (!res.ok) throw new Error('Upload failed') const { url } = await res.json() const fullUrl = `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000'}${url}` await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ image: fullUrl }) }) setAvatarUrl(fullUrl) } catch {} finally { setUploading(false) if (fileRef.current) fileRef.current.value = '' } } async function handleSave() { setSaving(true) try { await api.request('/users/me', { method: 'PATCH', body: JSON.stringify({ bio: bio || undefined, phone: phone || undefined }), }) onNext() } catch {} finally { setSaving(false) } } return (

{t('specialist_setup.step2.title')}

{t('specialist_setup.step2.subtitle')}

{/* Avatar */}

{t('specialist_setup.step2.photo_label')}

{avatarUrl ? ( ) : ( )}

{t('specialist_setup.step2.photo_hint')}

{/* Bio */}