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 { Button } from "@/components/ui/button";
|
||||||
import { useAuth } from "@/contexts/AuthContext";
|
import { useAuth } from "@/contexts/AuthContext";
|
||||||
import { aethexToast } from "@/lib/aethex-toast";
|
import { aethexToast } from "@/lib/aethex-toast";
|
||||||
|
import { supabase } from "@/lib/supabase";
|
||||||
import {
|
import {
|
||||||
aethexProjectService,
|
aethexProjectService,
|
||||||
aethexAchievementService,
|
aethexAchievementService,
|
||||||
|
|
@ -60,6 +61,7 @@ export default function Dashboard() {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [projects, setProjects] = useState([]);
|
const [projects, setProjects] = useState([]);
|
||||||
const [achievements, setAchievements] = useState([]);
|
const [achievements, setAchievements] = useState([]);
|
||||||
|
const [profileCompletion, setProfileCompletion] = useState(0);
|
||||||
const [stats, setStats] = useState({
|
const [stats, setStats] = useState({
|
||||||
activeProjects: 0,
|
activeProjects: 0,
|
||||||
completedTasks: 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 () => {
|
const loadDashboardData = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
@ -226,7 +240,7 @@ export default function Dashboard() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show profile setup if no profile exists, but allow dashboard to continue
|
// Show profile setup if no profile exists, but allow dashboard to continue
|
||||||
const showProfileSetup = !profile;
|
const showProfileSetup = !profile || profileCompletion < 80;
|
||||||
|
|
||||||
const statsDisplay = [
|
const statsDisplay = [
|
||||||
{
|
{
|
||||||
|
|
@ -543,6 +557,24 @@ export default function Dashboard() {
|
||||||
<Label htmlFor="location">Location</Label>
|
<Label htmlFor="location">Location</Label>
|
||||||
<Input id="location" value={locationInput} onChange={(e) => setLocationInput(e.target.value)} />
|
<Input id="location" value={locationInput} onChange={(e) => setLocationInput(e.target.value)} />
|
||||||
</div>
|
</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">
|
<div className="md:col-span-2">
|
||||||
<Label htmlFor="bio">Bio</Label>
|
<Label htmlFor="bio">Bio</Label>
|
||||||
<Textarea id="bio" value={bio} onChange={(e) => setBio(e.target.value)} />
|
<Textarea id="bio" value={bio} onChange={(e) => setBio(e.target.value)} />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue