feat(ui): page édition d'une carte pré-remplie (P3-5, F-06)
Page /cards/:id/edit : charge la carte via cardsApi, pré-remplit CardForm en mode edit et enregistre via cardsApi.update. Ajoute un test F-06 au form (pré-remplissage + update + navigation). Coche P3-5 dans TODO.
This commit is contained in:
1 parent
2e131dddcb
commit
03a6b7b455
2 files changed
+67
No files matched your search
@@ -0,0 +1,45 @@
|
|||||||
|
import type { Metadata } from 'next'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { notFound } from 'next/navigation'
|
||||||
|
import { CardForm } from '@/components/card-form'
|
||||||
|
import type { Card, CardInput } from '@/domain/card'
|
||||||
|
import { ApiClientError, cardsApi } from '@/lib/api-client'
|
||||||
|
|
||||||
|
export const metadata: Metadata = { title: 'Modifier la carte' }
|
||||||
|
|
||||||
|
export default async function EditCardPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ id: string }>
|
||||||
|
}) {
|
||||||
|
const { id } = await params
|
||||||
|
let card: Card | null = null
|
||||||
|
try {
|
||||||
|
card = await cardsApi.get(id)
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof ApiClientError && e.status === 404) notFound()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
const initial: CardInput = {
|
||||||
|
question: card.question,
|
||||||
|
response: card.response,
|
||||||
|
theme: card.theme,
|
||||||
|
tags: card.tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="mx-auto max-w-3xl px-4 py-8">
|
||||||
|
<div className="mb-6">
|
||||||
|
<Link
|
||||||
|
href={`/cards/${id}`}
|
||||||
|
className="text-sm font-medium text-slate-600 underline-offset-4 hover:underline"
|
||||||
|
>
|
||||||
|
← Retour au détail
|
||||||
|
</Link>
|
||||||
|
<h1 className="mt-2 text-2xl font-bold text-slate-900">{card.question}</h1>
|
||||||
|
</div>
|
||||||
|
<CardForm mode="edit" cardId={card.id} initial={initial} />
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -36,3 +36,25 @@ it('crée une carte puis navigue vers son détail (F-05)', async () => {
|
|||||||
})
|
})
|
||||||
await screen.findByText('Enregistrement…')
|
await screen.findByText('Enregistrement…')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('pré-remplit le formulaire et enregistre une modification (F-06 édition)', async () => {
|
||||||
|
vi.mocked(cardsApi.update).mockResolvedValue({ id: 'c1' } as never)
|
||||||
|
render(
|
||||||
|
<CardForm
|
||||||
|
mode="edit"
|
||||||
|
cardId="c1"
|
||||||
|
initial={{ question: 'Ancienne question', response: 'Ancienne réponse', theme: 'git' }}
|
||||||
|
/>,
|
||||||
|
)
|
||||||
|
const question = screen.getByLabelText('Question')
|
||||||
|
expect(question).toHaveValue('Ancienne question')
|
||||||
|
await userEvent.clear(question)
|
||||||
|
await userEvent.type(question, 'Nouvelle question')
|
||||||
|
await userEvent.click(screen.getByRole('button', { name: 'Enregistrer' }))
|
||||||
|
expect(vi.mocked(cardsApi.update)).toHaveBeenCalledWith('c1', {
|
||||||
|
question: 'Nouvelle question',
|
||||||
|
response: 'Ancienne réponse',
|
||||||
|
theme: 'git',
|
||||||
|
})
|
||||||
|
expect(routerMock.push).toHaveBeenCalledWith('/cards/c1')
|
||||||
|
})
|
||||||
Reference in new issue
Block a user