diff --git a/app/profile/page.tsx b/app/profile/page.tsx new file mode 100644 index 0000000..9e3836e --- /dev/null +++ b/app/profile/page.tsx @@ -0,0 +1,89 @@ +// app/profile/page.tsx +"use client"; + +import { useState, useEffect } from "react"; +import Navbar from "@/components/Navbar"; +import ProfileCard from "@/components/ProfileCard"; +import EditProfileModal from "@/components/EditProfileModal"; +import { supabase } from "@/lib/supabase"; +import { ProfileDTO } from "@/lib/dto/profiles"; +import { User } from "@supabase/supabase-js"; + +const EMPTY_PROFILE: ProfileDTO = { + name: "", + grad_year: "", + linkedin: "", + github: "", + experiences: [], +}; + +export default function ProfilePage() { + const [user, setUser] = useState(null); + const [profile, setProfile] = useState(EMPTY_PROFILE); + const [modalOpen, setModalOpen] = useState(false); + + useEffect(() => { + supabase.auth.getSession().then(({ data }) => { + setUser(data.session?.user ?? null); + }); + + const { data: { subscription } } = supabase.auth.onAuthStateChange((_e, session) => { + setUser(session?.user ?? null); + }); + + return () => subscription.unsubscribe(); + }, []); + + function handleSave(data: ProfileDTO) { + setProfile(data); + // TODO: supabase upsert + } + + const hasProfile = !!profile.name; + + return ( +
+ + +
+ {!user ? ( +
+

+ Sign in to create your profile +

+
+ ) : ( +
+
+

Your Card

+ {!hasProfile && ( + + )} +
+ +
+ setModalOpen(true)} + /> +
+
+ )} +
+ + {modalOpen && ( + setModalOpen(false)} + /> + )} +
+ ); +} \ No newline at end of file diff --git a/components/ProfileCard.tsx b/components/ProfileCard.tsx index 6fa67b6..5d3bcbf 100644 --- a/components/ProfileCard.tsx +++ b/components/ProfileCard.tsx @@ -1,7 +1,7 @@ // Thank Peter for his pre-made components import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Github, Linkedin, Pencil } from "lucide-react"; -import type { ProfileDTO } from "@/lib/dto/profiles"; +import type { ProfileDTO, Contact, Experience } from "@/lib/dto/profile"; interface ProfileCardProps { profile: ProfileDTO | null; @@ -9,6 +9,27 @@ interface ProfileCardProps { onEdit?: () => void; } +// Helper methods for clean formatting +function formatTerm(term: [string, number] | null | undefined, fallback: string): string { + if (!term) return fallback; + return `${term[0]} '${String(term[1]).slice(2)}`; +} + +function formatTermRange(profile: ProfileDTO): string { + const start = formatTerm(profile.startTerm, "?"); + const end = profile.endTerm ? formatTerm(profile.endTerm, "Present") : "Present"; + return `${start} — ${end}`; +} + +function getContact(contacts: Contact[], type: "LinkedIn" | "GitHub"): string | null { + const match = contacts.find(([t]) => t === type); + return match ? match[1] : null; +} + +function formatExperience(exp: Experience): { company: string; role: string } { + return { company: exp[2], role: exp[1] }; +} + // Destructure the prop, ignore all types for now unless we want to add an interface later on // Thank Peter for his pre-made components @@ -17,6 +38,9 @@ export default function ProfileCard({ profile, editable = false, onEdit }: Profi if (!profile) return null; const isProfileEmpty = !profile.name; + const linkedin = getContact(profile.contact ?? [], "LinkedIn"); + const github = getContact(profile.contact ?? [], "GitHub"); + const termRange = formatTermRange(profile); return ( @@ -31,15 +55,15 @@ export default function ProfileCard({ profile, editable = false, onEdit }: Profi
- {profile?.linkedin ? ( - + {linkedin ? ( + ) : ( )} - {profile?.github ? ( - + {github ? ( + ) : ( @@ -49,8 +73,8 @@ export default function ProfileCard({ profile, editable = false, onEdit }: Profi
- - {profile?.grad_year ?? "----"} + + {isProfileEmpty ? "---" : termRange} {editable && ( @@ -66,14 +90,17 @@ export default function ProfileCard({ profile, editable = false, onEdit }: Profi - {(profile.experiences ?? []).map((exp, i: number) => ( -
-

{exp.company}

-

{exp.role}

-
- ))} + {(profile.experience ?? []).map((exp, i) => { + const { company, role } = formatExperience(exp); + return ( +
+

{company}

+

{role}

+
+ ); + })} - {(!profile.experiences || profile.experiences.length === 0) && ( + {(!profile.experience || profile.experience.length === 0) && (

No history available

)}
diff --git a/lib/dto/profiles.ts b/lib/dto/profiles.ts deleted file mode 100644 index 51b5ec6..0000000 --- a/lib/dto/profiles.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface ExperienceDTO { - company: string; - role: string; -} - -export interface ProfileDTO { - id?: string; - name?: string; - start_term?: string; - grad_year?: string; - linkedin?: string; - github?: string; - experiences?: ExperienceDTO[]; -}