Add import, profileCompletion state, compute function, showSetup logic, and avatar upload input
cgen-3b3b902612494d3c9be67f460b3932e8
This commit is contained in:
parent
c359fb80df
commit
0946bc3744
1 changed files with 33 additions and 1 deletions
|
|
@ -4,6 +4,7 @@ import Layout from "@/components/Layout";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { useAuth } from "@/contexts/AuthContext";
|
||||
import { aethexToast } from "@/lib/aethex-toast";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import {
|
||||
aethexProjectService,
|
||||
aethexAchievementService,
|
||||
|
|
@ -60,6 +61,7 @@ export default function Dashboard() {
|
|||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [achievements, setAchievements] = useState([]);
|
||||
const [profileCompletion, setProfileCompletion] = useState(0);
|
||||
const [stats, setStats] = useState({
|
||||
activeProjects: 0,
|
||||
completedTasks: 0,
|
||||
|
|
@ -126,6 +128,18 @@ export default function Dashboard() {
|
|||
}
|
||||
};
|
||||
|
||||
const computeProfileCompletion = (p: any) => {
|
||||
const checks = [
|
||||
!!p?.full_name,
|
||||
!!p?.bio,
|
||||
!!p?.location,
|
||||
!!p?.avatar_url,
|
||||
!!(p?.website_url || p?.github_url || p?.linkedin_url || p?.twitter_url),
|
||||
];
|
||||
const pct = Math.round((checks.filter(Boolean).length / checks.length) * 100);
|
||||
setProfileCompletion(pct);
|
||||
};
|
||||
|
||||
const loadDashboardData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
|
@ -226,7 +240,7 @@ export default function Dashboard() {
|
|||
}
|
||||
|
||||
// Show profile setup if no profile exists, but allow dashboard to continue
|
||||
const showProfileSetup = !profile;
|
||||
const showProfileSetup = !profile || profileCompletion < 80;
|
||||
|
||||
const statsDisplay = [
|
||||
{
|
||||
|
|
@ -543,6 +557,24 @@ export default function Dashboard() {
|
|||
<Label htmlFor="location">Location</Label>
|
||||
<Input id="location" value={locationInput} onChange={(e) => setLocationInput(e.target.value)} />
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<Label htmlFor="avatar">Profile Image</Label>
|
||||
<Input id="avatar" type="file" accept="image/*" onChange={async (e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file || !user) return;
|
||||
try {
|
||||
const path = `${user.id}/avatar-${Date.now()}-${file.name}`;
|
||||
const { error } = await supabase.storage.from("avatars").upload(path, file, { upsert: true });
|
||||
if (error) throw error;
|
||||
const { data } = supabase.storage.from("avatars").getPublicUrl(path);
|
||||
await updateProfile({ avatar_url: data.publicUrl } as any);
|
||||
computeProfileCompletion({ ...(profile as any), avatar_url: data.publicUrl });
|
||||
aethexToast.success({ title: "Avatar updated" });
|
||||
} catch (err: any) {
|
||||
aethexToast.error({ title: "Upload failed", description: err?.message || "Unable to upload image" });
|
||||
}
|
||||
}} />
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<Label htmlFor="bio">Bio</Label>
|
||||
<Textarea id="bio" value={bio} onChange={(e) => setBio(e.target.value)} />
|
||||
|
|
|
|||
Loading…
Reference in a new issue