Skip to content

Commit 229ec10

Browse files
committed
feat: update navigation styles and add registration page
1 parent 87d4a56 commit 229ec10

File tree

5 files changed

+170
-3
lines changed

5 files changed

+170
-3
lines changed

backend/pb_migrations/1749115403_seed_database.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ migrate(
2020
categoryIds[name] = record.id;
2121
}
2222

23-
// Add Dogs
2423
let pets = app.findCollectionByNameOrId("pets");
24+
25+
// Add Dogs
2526
for (let dogName of DOG_NAMES) {
2627
let record = new Record(pets, {
2728
name: dogName,

frontend/src/lib/components/navigation.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<div class="bg-blue-400 px-4 py-2"><a href="/auth/logout">Logout</a></div>
2222
{/if}
2323
{#if authStore.isValid}
24-
<div class="bg-blue-300 px-4 py-2"><a href="/orders">My Orders</a></div>
24+
<div class="bg-blue-400 px-4 py-2"><a href="/orders">My Orders</a></div>
2525
{/if}
2626
<div class="bg-blue-400 px-4 py-2">
2727
<a href="/order/cart">Cart ({cartStore.cart.length})</a>

frontend/src/routes/auth/login/+page.svelte

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
});
1616
1717
const form = superForm(defaults(zod(loginSchema)), {
18-
id: 'pet-create-form',
18+
id: 'login-form',
1919
SPA: true,
2020
validators: zodClient(loginSchema),
2121
onUpdate: async ({ form }) => {
@@ -106,5 +106,11 @@
106106
>
107107
Login
108108
</button>
109+
<a
110+
href="/auth/register"
111+
class="inline-block cursor-pointer bg-blue-400 px-4 py-2 disabled:bg-gray-400"
112+
>
113+
Register
114+
</a>
109115
</div>
110116
</form>
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
<script lang="ts">
2+
import { goto } from '$app/navigation';
3+
import { getPocketBase } from '$lib/services/pocketbase';
4+
import { getAuthStore } from '$lib/stores/auth.store.svelte';
5+
import { Control, Description, Field, FieldErrors, Label } from 'formsnap';
6+
import { ClientResponseError } from 'pocketbase';
7+
import { defaults, setError, superForm } from 'sveltekit-superforms';
8+
import { zod, zodClient } from 'sveltekit-superforms/adapters';
9+
import { z } from 'zod';
10+
11+
const authStore = getAuthStore();
12+
13+
const registerSchema = z.object({
14+
name: z.string(),
15+
email: z.string().email(),
16+
password: z.string().min(4),
17+
admin: z.boolean().default(false)
18+
});
19+
20+
const form = superForm(defaults(zod(registerSchema)), {
21+
id: 'register-form',
22+
SPA: true,
23+
validators: zodClient(registerSchema),
24+
onUpdate: async ({ form }) => {
25+
if (!form.valid) return;
26+
27+
const { name, email, password, admin } = form.data;
28+
29+
try {
30+
await getPocketBase().collection('users').create({
31+
name,
32+
email,
33+
password,
34+
passwordConfirm: password,
35+
admin
36+
});
37+
await authStore.authWithPassword(email, password);
38+
await goto('/');
39+
} catch (error) {
40+
if (error instanceof ClientResponseError) {
41+
setError(form, error.message);
42+
} else {
43+
setError(
44+
form,
45+
`An unexpected error occurred. Please try again later. (${JSON.stringify(error)})`
46+
);
47+
}
48+
}
49+
}
50+
});
51+
52+
const { form: formData, constraints, enhance, submitting, delayed, allErrors } = form;
53+
54+
let formErrors = $derived(
55+
$allErrors.filter((error) => error.path === '_errors').flatMap((error) => error.messages)
56+
);
57+
</script>
58+
59+
<div class="mb-4 flex items-center justify-between gap-4 bg-gray-100">
60+
<h1 class="px-4 py-2 text-xl">Register</h1>
61+
</div>
62+
{#if formErrors.length > 0}
63+
<div class="bg-red-400 px-4 py-2">
64+
<p>There were errors with your submission:</p>
65+
<ul class="list-disc px-8">
66+
{#each formErrors as error}
67+
<li>{error}</li>
68+
{/each}
69+
</ul>
70+
</div>
71+
{/if}
72+
<form method="POST" use:enhance class="flex flex-col gap-4">
73+
<div class="flex flex-col gap-2">
74+
<Field {form} name="name">
75+
<Control>
76+
{#snippet children({ props })}
77+
<Label>Name</Label>
78+
<input
79+
{...props}
80+
{...$constraints.name}
81+
type="text"
82+
autocomplete="name"
83+
bind:value={$formData.name}
84+
/>
85+
{/snippet}
86+
</Control>
87+
<Description>Enter your name.</Description>
88+
<FieldErrors class="text-red-400" />
89+
</Field>
90+
</div>
91+
92+
<div class="flex flex-col gap-2">
93+
<Field {form} name="email">
94+
<Control>
95+
{#snippet children({ props })}
96+
<Label>Email</Label>
97+
<input
98+
{...props}
99+
{...$constraints.email}
100+
type="text"
101+
autocomplete="email"
102+
bind:value={$formData.email}
103+
/>
104+
{/snippet}
105+
</Control>
106+
<Description>Enter your email address.</Description>
107+
<FieldErrors class="text-red-400" />
108+
</Field>
109+
</div>
110+
111+
<div class="flex flex-col gap-2">
112+
<Field {form} name="password">
113+
<Control>
114+
{#snippet children({ props })}
115+
<Label>Password</Label>
116+
<input
117+
{...props}
118+
{...$constraints.password}
119+
type="password"
120+
autocomplete="current-password"
121+
bind:value={$formData.password}
122+
/>
123+
{/snippet}
124+
</Control>
125+
<Description>Enter your password.</Description>
126+
<FieldErrors class="text-red-400" />
127+
</Field>
128+
</div>
129+
130+
<div class="flex flex-col gap-2">
131+
<Field {form} name="admin">
132+
<Control>
133+
{#snippet children({ props })}
134+
<div class="flex items-center gap-2 border px-4 py-2">
135+
<input
136+
{...props}
137+
{...$constraints.admin}
138+
type="checkbox"
139+
bind:checked={$formData.admin}
140+
/>
141+
<Label for={props.id}>Admin</Label>
142+
</div>
143+
{/snippet}
144+
</Control>
145+
<Description>Wanna be an admin?</Description>
146+
<FieldErrors class="text-red-400" />
147+
</Field>
148+
</div>
149+
150+
<div class="col-span-2">
151+
<button
152+
type="submit"
153+
disabled={$submitting}
154+
class="cursor-pointer bg-blue-400 px-4 py-2 disabled:bg-gray-400"
155+
>
156+
Register
157+
</button>
158+
</div>
159+
</form>

frontend/src/routes/pets/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
</div>
6969
{/each}
7070
</div>
71+
<p class="text-right">Showing a total of {pets.length} pets</p>
7172
{:catch error}
7273
<p class="bg-red-400">Error loading pets: {error}</p>
7374
{/await}

0 commit comments

Comments
 (0)