Redesign the setup flow and consolidate the CSS into one primitives layer
Onboarding asks explicitly for one or two parents and shows one card per parent for balances; the balance form is per parent with inline validation; the partner can be filled from the FK deduction or added from it. Settings and Dashboard reuse the same form. CSS: bare buttons carry no colour any more; buttons, cards, choice cards, fields, alerts, badges, eyebrow and modal chrome are defined once in primitives.css. Media queries live only in responsive.css. A style guard test blocks hex, !important and stray media queries. Bilingual fixes: calendar selects size by content, header no longer wraps. Vitest is capped at four workers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { isSelf, orderSelfFirst } from './members'
|
||||
import { makePersonalData } from '../../tests/fixtures'
|
||||
|
||||
describe('isSelf', () => {
|
||||
it('is true when the member uuid matches personalDataUuid', () => {
|
||||
const member = makePersonalData({ uuid: 'pd-1' })
|
||||
expect(isSelf(member, 'pd-1')).toBe(true)
|
||||
})
|
||||
|
||||
it('is false when the member uuid does not match personalDataUuid', () => {
|
||||
const member = makePersonalData({ uuid: 'pd-1' })
|
||||
expect(isSelf(member, 'pd-2')).toBe(false)
|
||||
})
|
||||
|
||||
it('is false when personalDataUuid is null', () => {
|
||||
const member = makePersonalData({ uuid: 'pd-1' })
|
||||
expect(isSelf(member, null)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('orderSelfFirst', () => {
|
||||
it('moves the signed-in user to the front, keeping others in order', () => {
|
||||
const a = makePersonalData({ uuid: 'pd-a', name: 'Alex' })
|
||||
const b = makePersonalData({ uuid: 'pd-b', name: 'Sam' })
|
||||
const c = makePersonalData({ uuid: 'pd-c', name: 'Kim' })
|
||||
|
||||
const ordered = orderSelfFirst([a, b, c], 'pd-b')
|
||||
|
||||
expect(ordered.map((m) => m.uuid)).toEqual(['pd-b', 'pd-a', 'pd-c'])
|
||||
})
|
||||
|
||||
it('is a no-op when the signed-in user is already first', () => {
|
||||
const a = makePersonalData({ uuid: 'pd-a' })
|
||||
const b = makePersonalData({ uuid: 'pd-b' })
|
||||
|
||||
expect(orderSelfFirst([a, b], 'pd-a').map((m) => m.uuid)).toEqual(['pd-a', 'pd-b'])
|
||||
})
|
||||
|
||||
it('leaves the order unchanged when personalDataUuid is null', () => {
|
||||
const a = makePersonalData({ uuid: 'pd-a' })
|
||||
const b = makePersonalData({ uuid: 'pd-b' })
|
||||
|
||||
expect(orderSelfFirst([a, b], null).map((m) => m.uuid)).toEqual(['pd-a', 'pd-b'])
|
||||
})
|
||||
|
||||
it('leaves the order unchanged when the signed-in user is not among the members', () => {
|
||||
const a = makePersonalData({ uuid: 'pd-a' })
|
||||
const b = makePersonalData({ uuid: 'pd-b' })
|
||||
|
||||
expect(orderSelfFirst([a, b], 'pd-unknown').map((m) => m.uuid)).toEqual(['pd-a', 'pd-b'])
|
||||
})
|
||||
|
||||
it('returns an empty array for an empty members list', () => {
|
||||
expect(orderSelfFirst([], 'pd-a')).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { PersonalData } from '@/types'
|
||||
|
||||
/** True when `member` is the signed-in user identified by `personalDataUuid`. */
|
||||
export function isSelf(member: PersonalData, personalDataUuid: string | null): boolean {
|
||||
return personalDataUuid !== null && member.uuid === personalDataUuid
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable-sorts `members` so the signed-in user (if present among them) comes
|
||||
* first, leaving every other member in their original relative order.
|
||||
*
|
||||
* Used to put "your" `ParentBalanceForm` ahead of a partner's in any UI that
|
||||
* lists both — see `ParentBalanceForm.tsx`.
|
||||
*/
|
||||
export function orderSelfFirst(
|
||||
members: PersonalData[],
|
||||
personalDataUuid: string | null,
|
||||
): PersonalData[] {
|
||||
const self = members.filter((m) => isSelf(m, personalDataUuid))
|
||||
const others = members.filter((m) => !isSelf(m, personalDataUuid))
|
||||
return [...self, ...others]
|
||||
}
|
||||
Reference in New Issue
Block a user