Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 31x 31x 23x 23x 1x 31x 2x 2x 2x 2x 31x 1x 30x 180x | import { Link } from "@tanstack/react-router";
import { Check, ChevronDown, ChevronUp, Circle } from "lucide-react";
import { useState } from "react";
import type { Pro } from "../../lib/api";
import { getProfileCompleteness } from "../../lib/profile-completeness";
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
interface ProfileCompletenessCardProps {
pro: Pro;
projectCount: number;
}
export function ProfileCompletenessCard({
pro,
projectCount,
}: ProfileCompletenessCardProps) {
const { sections, percentage } = getProfileCompleteness(pro, projectCount);
const [collapsed, setCollapsed] = useState(() => {
try {
return localStorage.getItem("profile-card-collapsed") === "true";
} catch {
return false;
}
});
const toggleCollapsed = () => {
const next = !collapsed;
setCollapsed(next);
try {
localStorage.setItem("profile-card-collapsed", String(next));
} catch {}
};
// Only show if profile is incomplete
if (percentage >= 100) {
return null;
}
return (
<Card className="border-primary-200 bg-primary-50">
<CardHeader className="pb-4">
<div className="flex items-center justify-between">
<CardTitle className="text-foreground-default">
Complete Your Profile
</CardTitle>
<div className="flex items-center gap-2">
<span className="text-2xl font-bold text-primary-600">
{percentage}%
</span>
<button
type="button"
onClick={toggleCollapsed}
className="p-1 text-foreground-muted hover:text-foreground-default sm:hidden"
aria-label={collapsed ? "Expand profile checklist" : "Collapse profile checklist"}
>
{collapsed ? <ChevronDown className="h-5 w-5" /> : <ChevronUp className="h-5 w-5" />}
</button>
</div>
</div>
{/* Progress bar */}
<div className="mt-3 h-2 w-full bg-background-muted rounded-full overflow-hidden">
<div
className="h-full bg-primary-500 transition-all duration-500"
style={{ width: `${percentage}%` }}
/>
</div>
</CardHeader>
<CardContent>
<div className={collapsed ? "hidden sm:block" : ""}>
<p className="text-sm text-foreground-muted mb-4">
A complete profile helps customers find and trust your business.
Complete these sections to boost your visibility.
</p>
<div className="space-y-3">
{sections.map((section) => (
<div
key={section.name}
className="flex items-center justify-between"
>
<div className="flex items-center gap-2">
{section.completed ? (
<div className="flex items-center justify-center w-5 h-5 rounded-full bg-success">
<Check className="h-3 w-3 text-foreground-inverse" />
</div>
) : (
<Circle className="h-5 w-5 text-foreground-subtle" />
)}
<span
className={
section.completed
? "text-foreground-muted line-through"
: "text-foreground-default"
}
>
{section.name}
</span>
</div>
{!section.completed && (
<Link
to={section.href}
search={section.tab ? { tab: section.tab } : {}}
className="text-sm text-primary-600 hover:text-primary-700 font-medium"
>
Add details
</Link>
)}
</div>
))}
</div>
</div>
</CardContent>
</Card>
);
}
|