From 69ea776fa696b1f1107c116f06e7329b06618353 Mon Sep 17 00:00:00 2001 From: Jared Schoeny Date: Fri, 10 Oct 2025 23:42:00 -1000 Subject: [PATCH] Add initial account setup form --- src/app/account/page.tsx | 26 ++- src/app/globals.css | 8 + src/components/Account/AccountForm.tsx | 87 +++---- src/components/Account/AccountSetupForm.tsx | 238 ++++++++++++++++++++ 4 files changed, 293 insertions(+), 66 deletions(-) create mode 100644 src/components/Account/AccountSetupForm.tsx diff --git a/src/app/account/page.tsx b/src/app/account/page.tsx index d8a3b56..5a4c86f 100644 --- a/src/app/account/page.tsx +++ b/src/app/account/page.tsx @@ -1,4 +1,5 @@ import AccountForm from "@/components/Account/AccountForm"; +import AccountSetupForm from "../../components/Account/AccountSetupForm"; import { createClient } from "@/utils/supabase/server"; import { redirect } from "next/navigation"; @@ -10,12 +11,27 @@ export default async function AccountPage() { redirect('/login') } + // Fetch profile server-side to decide which form to render and pass to client + const { data: profile } = await supabase + .from('profiles') + .select('full_name, username, website, avatar_url') + .eq('id', user.id) + .maybeSingle() + + const needsInitialSetup = !profile || profile.username == null + return ( -
-

Your account

-

Manage profile details and avatar.

-
- +
+

{needsInitialSetup ? 'Finish setting up your account' : 'Your account'}

+

+ {needsInitialSetup ? 'Choose a unique username to get started. You can update other details later.' : 'Manage profile details and avatar.'} +

+
+ {needsInitialSetup ? ( + + ) : ( + + )}
); diff --git a/src/app/globals.css b/src/app/globals.css index 7c1a7e4..4021c1e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -185,3 +185,11 @@ body { --tw-prose-hr: var(--border); --tw-prose-captions: color-mix(in oklab, var(--foreground) 70%, transparent); } + +.scrollbar-thin { + scrollbar-width: thin; +} + +.scrollbar-color-muted { + scrollbar-color: var(--muted) transparent; +} diff --git a/src/components/Account/AccountForm.tsx b/src/components/Account/AccountForm.tsx index d16fb9c..14043fa 100644 --- a/src/components/Account/AccountForm.tsx +++ b/src/components/Account/AccountForm.tsx @@ -1,69 +1,36 @@ 'use client' -import { useCallback, useEffect, useState } from 'react' +import { useState } from 'react' import { createClient } from '@/utils/supabase/client' import { type User } from '@supabase/supabase-js' import Avatar from './Avatar' -export default function AccountForm({ user }: { user: User | null }) { +type Profile = { + full_name: string | null + username: string | null + website: string | null + avatar_url: string | null +} + +export default function AccountForm({ user, profile }: { user: User | null, profile: Profile | null }) { const supabase = createClient() - const [loading, setLoading] = useState(true) - const [fullname, setFullname] = useState(null) - const [username, setUsername] = useState(null) - const [website, setWebsite] = useState(null) - const [avatar_url, setAvatarUrl] = useState(null) - const [initialProfile, setInitialProfile] = useState<{ - fullname: string | null - username: string | null - website: string | null - avatar_url: string | null - }>({ fullname: null, username: null, website: null, avatar_url: null }) - - const getProfile = useCallback(async () => { - try { - setLoading(true) - - const { data, error, status } = await supabase - .from('profiles') - .select(`full_name, username, website, avatar_url`) - .eq('id', user?.id) - .single() - - if (error && status !== 406) { - console.log(error) - throw error - } - - if (data) { - setFullname(data.full_name) - setUsername(data.username) - setWebsite(data.website) - setAvatarUrl(data.avatar_url) - setInitialProfile({ - fullname: data.full_name, - username: data.username, - website: data.website, - avatar_url: data.avatar_url, - }) - } - } catch (error) { - alert('Error loading user data!') - } finally { - setLoading(false) - } - }, [user, supabase]) - - useEffect(() => { - getProfile() - }, [user, getProfile]) + const [loading, setLoading] = useState(false) + const [fullname, setFullname] = useState(profile?.full_name ?? null) + const [username] = useState(profile?.username ?? null) + const [website, setWebsite] = useState(profile?.website ?? null) + const [avatar_url, setAvatarUrl] = useState(profile?.avatar_url ?? null) + const [initialProfile, setInitialProfile] = useState({ + full_name: profile?.full_name ?? null, + username: profile?.username ?? null, + website: profile?.website ?? null, + avatar_url: profile?.avatar_url ?? null, + }) async function updateProfile({ - username, website, avatar_url, fullname, }: { - username: string | null fullname: string | null website: string | null avatar_url: string | null @@ -74,13 +41,12 @@ export default function AccountForm({ user }: { user: User | null }) { const { error } = await supabase.from('profiles').upsert({ id: user?.id as string, full_name: fullname, - username, website, avatar_url, updated_at: new Date().toISOString(), }) if (error) throw error - setInitialProfile({ fullname, username, website, avatar_url }) + setInitialProfile({ full_name: fullname, username, website, avatar_url }) alert('Profile updated!') } catch (error) { alert('Error updating the data!') @@ -91,8 +57,7 @@ export default function AccountForm({ user }: { user: User | null }) { const normalize = (v: string | null | undefined) => v ?? '' const hasChanges = - normalize(fullname) !== normalize(initialProfile.fullname) || - normalize(username) !== normalize(initialProfile.username) || + normalize(fullname) !== normalize(initialProfile.full_name) || normalize(website) !== normalize(initialProfile.website) || normalize(avatar_url) !== normalize(initialProfile.avatar_url) @@ -105,7 +70,7 @@ export default function AccountForm({ user }: { user: User | null }) { size={120} onUpload={(url) => { setAvatarUrl(url) - updateProfile({ fullname, username, website, avatar_url: url }) + updateProfile({ fullname, website, avatar_url: url }) }} />
@@ -138,8 +103,8 @@ export default function AccountForm({ user }: { user: User | null }) { id="username" type="text" value={username || ''} - onChange={(e) => setUsername(e.target.value)} - className="h-11 rounded-md bg-[var(--surface-2)] px-3 text-sm ring-1 ring-inset ring-[var(--border)] focus:outline-none focus:ring-2 focus:ring-[var(--ring)]" + disabled + className="h-11 rounded-md bg-[var(--surface-2)] px-3 text-sm text-foreground/70 ring-1 ring-inset ring-[var(--border)]" />
@@ -157,7 +122,7 @@ export default function AccountForm({ user }: { user: User | null }) {
+
+
+
+ + +
+ +
+ +
+
+ + ) +} + +