feat(join): implement A4 join household page (/join/[token])
- schema.d.ts: add GET /v1/invites/{code}, InviteInfoResponse, AcceptInviteRequest; update acceptInvite operation
- hooks.server.ts: add /join to PUBLIC_ROUTES; redirect authenticated users on /join/* to /
- +page.server.ts: load validates token (invalid:true on 404); action creates account + joins + sets session cookie
- HouseholdIdentityPanel.svelte: logo, household name (Fraunces), inviter text, static permissions list
- JoinForm.svelte: name/email/password + show/hide toggle, "Haushalt beitreten" CTA, field errors, pre-fill
- +page.svelte: no-chrome layout, mobile (banner+form stacked) / desktop (400px panel + flex:1) split, invalid-token inline state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
73
frontend/src/lib/api/schema.d.ts
vendored
73
frontend/src/lib/api/schema.d.ts
vendored
@@ -148,6 +148,22 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/invites/{code}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get: operations["getInviteInfo"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/invites/{code}/accept": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -739,6 +755,20 @@ export interface components {
|
||||
data?: components["schemas"]["AcceptInviteResponse"];
|
||||
meta?: components["schemas"]["Meta"];
|
||||
};
|
||||
InviteInfoResponse: {
|
||||
householdName?: string;
|
||||
inviterName?: string;
|
||||
};
|
||||
ApiResponseInviteInfoResponse: {
|
||||
status?: string;
|
||||
data?: components["schemas"]["InviteInfoResponse"];
|
||||
meta?: components["schemas"]["Meta"];
|
||||
};
|
||||
AcceptInviteRequest: {
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
Meta: {
|
||||
pagination?: components["schemas"]["Pagination"];
|
||||
};
|
||||
@@ -1345,7 +1375,7 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
acceptInvite: {
|
||||
getInviteInfo: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
@@ -1355,6 +1385,37 @@ export interface operations {
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"*/*": components["schemas"]["ApiResponseInviteInfoResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Not found */
|
||||
404: {
|
||||
headers: { [name: string]: unknown };
|
||||
content: { "*/*": components["schemas"]["ApiError"] };
|
||||
};
|
||||
};
|
||||
};
|
||||
acceptInvite: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
code: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["AcceptInviteRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK */
|
||||
200: {
|
||||
@@ -1365,6 +1426,16 @@ export interface operations {
|
||||
"*/*": components["schemas"]["ApiResponseAcceptInviteResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Email already registered */
|
||||
409: {
|
||||
headers: { [name: string]: unknown };
|
||||
content: { "*/*": components["schemas"]["ApiError"] };
|
||||
};
|
||||
/** @description Invite not found or invalid */
|
||||
404: {
|
||||
headers: { [name: string]: unknown };
|
||||
content: { "*/*": components["schemas"]["ApiError"] };
|
||||
};
|
||||
};
|
||||
};
|
||||
listCategories: {
|
||||
|
||||
Reference in New Issue
Block a user