SkateSpots/src/components/LabProfileProgress.tsx
SkateSpots 3d52f07144 Lab forms: profile-completeness progress + scroll-to/inline validation
Progress (interpreted as a completeness indicator, not a wizard — the form
stays one scroll):
- LabProfileProgress shows photo/bio/skills/rate/location/contact as done/todo
  with a % bar; wired into CraftProfileForm, coach, and the 4 bespoke pages.

Validation (was toast-only):
- CraftProfileForm splits email/website/portfolio into per-field inline errors
  with a red field border, gives the first skill section + contact fields ids,
  and scrolls to the first problem on submit; required sections show an inline
  message after a submit attempt.
- Coach page likewise splits email/website, shows inline errors + red borders,
  and scrolls to the contact field or the skills grid.
2026-10-04 11:39:31 +07:00

55 lines
2.1 KiB
TypeScript

import { useTranslation } from '@/contexts/language';
import { cn } from '@/lib/utils';
interface LabProfileProgressProps {
hasPhoto: boolean;
hasBio: boolean;
hasSkills: boolean;
hasRate: boolean;
hasLocation: boolean;
hasContact: boolean;
}
/**
* Compact "profile completeness" bar for the long Lab offer forms. Not a wizard
* — the form stays in one scroll — but it shows what's still worth adding so an
* incomplete listing isn't published blind.
*/
export function LabProfileProgress(props: LabProfileProgressProps) {
const { t } = useTranslation();
const steps = [
{ label: t('labUi.progress.photo'), done: props.hasPhoto },
{ label: t('labUi.progress.bio'), done: props.hasBio },
{ label: t('labUi.progress.skills'), done: props.hasSkills },
{ label: t('labUi.progress.rate'), done: props.hasRate },
{ label: t('labUi.progress.location'), done: props.hasLocation },
{ label: t('labUi.progress.contact'), done: props.hasContact },
];
const done = steps.filter((s) => s.done).length;
const pct = Math.round((done / steps.length) * 100);
return (
<div className="mb-4 rounded-xl border border-white/10 bg-white/[0.03] p-3">
<div className="flex items-center justify-between">
<span className="text-[10px] font-black uppercase tracking-widest text-gray-500">{t('labUi.progress.title')}</span>
<span className="text-[11px] font-bold text-gray-400">{t('labUi.progress.count', { done, total: steps.length })}</span>
</div>
<div className="mt-2 h-1.5 overflow-hidden rounded-full bg-white/10">
<div className="h-full rounded-full bg-[#ccff00] transition-all" style={{ width: `${pct}%` }} />
</div>
<div className="mt-2 flex flex-wrap gap-1.5">
{steps.map((s) => (
<span
key={s.label}
className={cn(
'rounded-full border px-2 py-0.5 text-[11px] font-semibold',
s.done ? 'border-[#ccff00]/40 bg-[#ccff00]/10 text-[#ccff00]' : 'border-white/10 text-gray-500',
)}
>
{s.done ? '✓ ' : ''}{s.label}
</span>
))}
</div>
</div>
);
}