create-household flow via useAuth and Welcome page

This commit is contained in:
jableader 2025-11-01 14:05:15 +11:00
parent ff8e665374
commit 44072a2363
4 changed files with 61 additions and 5 deletions

View file

@ -81,11 +81,11 @@ This plan is adapted to the existing codebase, focusing on refactoring rather th
- Ensures `activeHousehold` is set when navigating within a household. - Ensures `activeHousehold` is set when navigating within a household.
- **Nest existing routes**: Implemented behind feature flag. - **Nest existing routes**: Implemented behind feature flag.
3. **[ ] Implement Onboarding and Invitation Flows**: 3. **[~] Implement Onboarding and Invitation Flows**:
- Build the `Welcome.vue` view for creating the first household. - Build the `Welcome.vue` view for creating the first household.
- Build the `CreateAccount.vue` view. - Build the `CreateAccount.vue` view.
- Build the "Accept Invitation" page (`/invitations/accept?token=...`). It should take the token from the URL, call the API, and redirect on success. - Build the "Accept Invitation" page (`/invitations/accept?token=...`). It should take the token from the URL, call the API, and redirect on success.
- Status: Placeholder views created for all three; logic pending. Household creation endpoint available. - Status: Welcome page now implements create-household flow using `POST /api/v1/households` and redirects to `/:slug/mealplan`. Create Account and Invitation Accept remain TODO.
4. **[~] Integrate Household Context into the App**: 4. **[~] Integrate Household Context into the App**:
- **Create `src/composables/useHousehold.ts`**: Implemented. Extracts `householdSlug` from route and binds provider to API client. - **Create `src/composables/useHousehold.ts`**: Implemented. Extracts `householdSlug` from route and binds provider to API client.

View file

@ -60,5 +60,15 @@ export function useAuth() {
return hs return hs
} }
return { user, households, activeHousehold, loadUser, login, loginWithPassword, logout, setHouseholds, setActiveHousehold, fetchHouseholds } async function createHousehold(name: string): Promise<Household> {
const res = await api.POST('/api/v1/households', { body: { name } })
if (!res.response.ok || !res.data) throw new Error('Failed to create household')
const h: Household = { id: res.data.id, name: res.data.name, slug: res.data.slug }
// Update local state: append and set active
setHouseholds([...households.value, h])
setActiveHousehold(h)
return h
}
return { user, households, activeHousehold, loadUser, login, loginWithPassword, logout, setHouseholds, setActiveHousehold, fetchHouseholds, createHousehold }
} }

View file

@ -1,10 +1,35 @@
<template> <template>
<div> <div>
<h1>Welcome</h1> <h1>Welcome</h1>
<p>Choose to create a new household or join via invitation link.</p> <section>
<h2>Create a new household</h2>
<form @submit.prevent="onCreate">
<label for="name">Household Name</label>
<input id="name" v-model="name" required />
<button type="submit">Create</button>
</form>
</section>
<section>
<h2>Join an existing household</h2>
<p>To join a household, ask an existing member to send an invitation to your email address.</p>
</section>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// TODO: Implement onboarding flow per spec import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuth } from '@/composables/useAuth'
const name = ref('')
const router = useRouter()
const { createHousehold } = useAuth()
async function onCreate() {
const h = await createHousehold(name.value.trim())
if (h?.slug) {
router.push({ name: 'mealplan', params: { householdSlug: h.slug } })
}
}
</script> </script>

View file

@ -0,0 +1,21 @@
import { describe, it, expect } from 'vitest'
import { server, http, HttpResponse } from './test-setup'
import { useAuth } from '@/composables/useAuth'
describe('useAuth createHousehold', () => {
it('creates a new household and sets activeHousehold', async () => {
server.use(
http.post('*/api/v1/households', async ({ request }) => {
const body = await request.json()
expect(body).toEqual({ name: 'The Smiths' })
return HttpResponse.json({ id: 10, name: 'The Smiths', slug: 'the-smiths' })
})
)
const { households, activeHousehold, createHousehold } = useAuth()
expect(households.value).toEqual([])
const h = await createHousehold('The Smiths')
expect(h.slug).toBe('the-smiths')
expect(activeHousehold.value?.slug).toBe('the-smiths')
expect(households.value.find((x) => x.slug === 'the-smiths')).toBeTruthy()
})
})