Add user profiles and account setup page

This commit is contained in:
NeilClack
2026-02-03 10:11:00 -06:00
parent 2df81d20e3
commit c34e10159d
19 changed files with 3542 additions and 153 deletions
@@ -0,0 +1,23 @@
import type { PageServerLoad } from './$types';
import { prisma } from '$lib/db';
import { error, redirect } from '@sveltejs/kit';
export const load: PageServerLoad = async ({ locals }) => {
const user = await prisma.user.findUnique({
where: {
id: locals.user?.id
},
include: {
profile: true
}
});
if (user) {
if (!user?.profile) {
throw redirect(403, '/account/setup');
}
return { user };
} else {
throw error(403, 'not authorized');
}
};
@@ -0,0 +1,5 @@
<script lang="ts">
import type {PageProps} from "./$types";
let {data}: PageProps = $props();
$inspect(data);
</script>
+35 -1
View File
@@ -1,6 +1,7 @@
import type { PageServerLoad } from './$types';
import { error } from '@sveltejs/kit';
import { error, fail, isRedirect, redirect, type Actions } from '@sveltejs/kit';
import { prisma } from '$lib/db';
import { serverFormatPhoneNumber } from '$lib/utils';
// Tell the page what to do when it loads
export const load: PageServerLoad = async ({ locals }) => {
@@ -15,3 +16,36 @@ export const load: PageServerLoad = async ({ locals }) => {
return { user };
};
export const actions: Actions = {
default: async ({ request }) => {
const data = await request.formData();
const userID = data.get('userId') as string;
const firstName = data.get('firstName') as string;
const lastName = data.get('lastName') as string;
const phoneNumber = serverFormatPhoneNumber(data.get('phoneNumber') as string);
try {
const profile = await prisma.profile.create({
data: {
userId: userID,
firstName: firstName,
lastName: lastName,
phoneNumber: phoneNumber
}
});
if (profile) {
console.log(`created profile: ${JSON.stringify(profile)}`);
throw redirect(303, '/account');
} else {
return fail(400);
}
} catch (err) {
if (!isRedirect(err)) {
console.log(err);
throw error(400, 'bad request');
}
}
}
};
+51 -9
View File
@@ -1,12 +1,54 @@
<script lang="ts">
import type { PageProps } from "./$types";
let { data }: PageProps = $props();
$inspect(data);
<!--
There should be a form in the middle
rounded corners
floats above the screen slightly
Profile picture in the center at the top, about 1/3-1/2 the width of the form
Their email address, not editable, instead is a regular sized black text (or white in dark mode)
Input field for their Phone Number
Two inputs, side by side, a little margin between them. First and Last name
A submit button
Save the form then redirect them to their dashboard
-->
<script lang="ts">
import Window from '$lib/components/containers/Window.svelte';
import { clientFormatPhoneNumber } from '$lib/utils';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
$inspect(data);
let phoneNumber = $state('');
function handlePhoneInput(event: Event) {
const input = event.target as HTMLInputElement;
phoneNumber = clientFormatPhoneNumber(input.value);
}
</script>
<div>
<h1>
Account Setup
</h1>
</div>
<Window>
<form method="POST" class="border shadow-lg p-6 rounded-xl">
<p class="mx-auto text-center my-4 italic">Please finish setting up your profile</p>
{#if data.user?.image}
<img src={data.user?.image} class="rounded-full w-[8rem] mx-auto" alt="Profile" />
{:else}
<div class="mx-auto aspect-square w-[8rem] rounded-full bg-slate-900"></div>
{/if}
<p class="mx-auto text-center my-4">{data.user?.email}</p>
<div class="flex flex-col">
<input type="text" name="userId" value={data.user?.id} class="hidden"/>
<input type="text" name="firstName" placeholder="First Name" class="my-2" />
<input type="text" name="lastName" placeholder="Last Name" class="my-2" />
<input
type="tel"
name="phoneNumber"
placeholder="Phone Number"
class="my-2"
bind:value={phoneNumber}
oninput={handlePhoneInput}
/>
</div>
<button type="submit" class="p-2 px-4 bg-blue-300 rounded-xl">Submit</button>
</form>
</Window>