update ui and other frontend updates

This commit is contained in:
JCEEE
2026-07-29 09:41:52 +01:00
parent 04b83925e0
commit 57ef30d3a7
79 changed files with 7323 additions and 429 deletions
@@ -0,0 +1,24 @@
import { fail, redirect } from '@sveltejs/kit';
import { joinMember, setDeviceTokenCookie } from '$lib/server/auth';
export const actions = {
default: async (event) => {
const code = event.params.code;
const fd = await event.request.formData();
const name = fd.get('name') as string;
if (!name) {
return fail(400, { error: 'Name is required' });
}
const deviceToken = crypto.randomUUID();
try {
const result = await joinMember(code, name, deviceToken);
setDeviceTokenCookie(event, deviceToken);
throw redirect(303, `/${result.famSlug}/${result.name}`);
} catch (e) {
return fail(400, { error: e instanceof Error ? e.message : 'Invalid invite code' });
}
},
};
@@ -0,0 +1,29 @@
<script lang="ts">
let { form } = $props();
let name = $state('');
</script>
<h1>Join family</h1>
<p>Enter your name to join. It must match a member slot created by your admin.</p>
<form method="POST">
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<label>
Your name
<input name="name" bind:value={name} required placeholder="Enter your exact name" />
</label>
<button type="submit">Join</button>
</form>
<style>
form { display: flex; flex-direction: column; gap: 1rem; max-width: 400px; margin: 2rem auto; }
label { display: flex; flex-direction: column; gap: 0.25rem; }
input { padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 0.75rem; background: #6366f1; color: white; border: none; border-radius: 4px; cursor: pointer; }
.error { color: #dc2626; padding: 0.5rem; background: #fef2f2; border-radius: 4px; }
</style>
@@ -0,0 +1,24 @@
import { fail, redirect } from '@sveltejs/kit';
import { setDeviceTokenCookie } from '$lib/server/auth';
import { SERVER_IP, PROXY_PORT } from '../../../../../../config.ts';
const HONO_URL = `http://${SERVER_IP}:${PROXY_PORT}`;
export const actions = {
default: async (event) => {
const code = event.params.code;
const name = event.params.member;
const res = await fetch(`${HONO_URL}/api/members/direct-join`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inviteCode: code, name }),
});
const data = await res.json();
if (!res.ok) return fail(400, { error: data.error || 'Join failed' });
setDeviceTokenCookie(event, data.deviceToken);
throw redirect(303, `/${data.famSlug}/${data.name}`);
},
};
@@ -0,0 +1,24 @@
<script lang="ts">
import { page } from '$app/state';
import { enhance } from '$app/forms';
let { form } = $props();
let memberName = $derived(page.params.member);
</script>
<h1>Join family</h1>
{#if form?.error}
<p class="error">{form.error}</p>
{:else}
<p>Click below to join as <strong>{memberName}</strong></p>
{/if}
<form method="POST" use:enhance>
<button type="submit">Join</button>
</form>
<style>
.error { color: #dc2626; padding: 0.5rem; background: #fef2f2; border-radius: 4px; }
button { padding: 0.75rem 1.5rem; background: #6366f1; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 1rem; }
</style>