Give a new account a first run, and drop to three tabs
Registering used to land you on a bare form asking for a child, with no hint what came next. A short wizard now walks through the child, whether you are planning alone or together, and where the day balances come from: fetched from Försäkringskassan, entered by hand, or skipped — and if skipped, the figures carry a badge saying they are estimates until real ones arrive. Fetching is the first option rather than a hidden one, so the scraper is on by default and the script that used to force it on no longer needs to. Planning and Tips lose their tabs. Authoring moved to the calendar and the figures moved to the overview, so both pages were only a second way to reach what is already on screen; their routes now redirect rather than dead-end. The dead translations went with them. Dates also follow the chosen language now instead of always formatting as Swedish.
This commit is contained in:
@@ -23,10 +23,10 @@ import { Age4Bars } from '@/components/dashboard/Age4Bars'
|
||||
import { YearTimeline } from '@/components/dashboard/YearTimeline'
|
||||
import { PlanFold } from '@/components/dashboard/PlanFold'
|
||||
import { ParentalLeaveBreakdown } from '@/components/dashboard/ParentalLeaveBreakdown'
|
||||
import { ChildBirthdayInput } from '@/components/inputs/ChildBirthdayInput'
|
||||
import { TipCard } from '@/components/inputs/TipCard'
|
||||
import { QRCodeModal } from '@/components/modals/QRCodeModal'
|
||||
import { ManualFetchModal } from '@/components/modals/ManualFetchModal'
|
||||
import { Onboarding } from '@/pages/Onboarding'
|
||||
|
||||
/** Fallback horizon end when the analytics projection isn't available yet
|
||||
* (e.g. mid-load) — plain date arithmetic, not a business rule, so deriving
|
||||
@@ -40,7 +40,7 @@ function computeFourthBirthday(birthDateIso: string): string {
|
||||
export function Dashboard(): ReactNode {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
const { workspace, isLoading: wsLoading, selectedChildId, children, personalDataUuid, refreshContext } = useWorkspace()
|
||||
const { workspace, isLoading: wsLoading, selectedChildId, children, personalDataUuid } = useWorkspace()
|
||||
const { data: analytics, isLoading: analyticsLoading, error: analyticsError, refresh: refreshAnalytics } = useAnalytics(
|
||||
workspace?.id ?? null,
|
||||
selectedChildId ?? ''
|
||||
@@ -51,10 +51,6 @@ export function Dashboard(): ReactNode {
|
||||
const { data: tips, dismiss: dismissTip } = useOptimizationTips(workspace?.id ?? null)
|
||||
const scraper = useScraperFetch()
|
||||
|
||||
const [childName, setChildName] = useState('')
|
||||
const [childBirthDate, setChildBirthDate] = useState('')
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [showManualFetchModal, setShowManualFetchModal] = useState(false)
|
||||
const [isManualFetchSaving, setIsManualFetchSaving] = useState(false)
|
||||
@@ -66,30 +62,6 @@ export function Dashboard(): ReactNode {
|
||||
return <LoadingSpinner message={t('dashboard.loading')} />
|
||||
}
|
||||
|
||||
const handleAddChild = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setSubmitError(null)
|
||||
if (!workspace || !childName || !childBirthDate) {
|
||||
setSubmitError(t('dashboard.fillAllFields'))
|
||||
return
|
||||
}
|
||||
setIsSubmitting(true)
|
||||
try {
|
||||
await api.createChild({
|
||||
workspace_id: workspace.id,
|
||||
name: childName,
|
||||
birth_date: childBirthDate,
|
||||
})
|
||||
setChildName('')
|
||||
setChildBirthDate('')
|
||||
await refreshContext()
|
||||
} catch (err: unknown) {
|
||||
setSubmitError(err instanceof Error ? err.message : t('dashboard.createChildError'))
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleFetchFK = async () => {
|
||||
setShowModal(true)
|
||||
await scraper.start(selectedChildId ?? undefined)
|
||||
@@ -188,46 +160,13 @@ export function Dashboard(): ReactNode {
|
||||
]
|
||||
: []
|
||||
|
||||
// A new account has no child yet — hand off to the onboarding wizard
|
||||
// (add child, solo/couple, balances ladder) instead of rendering the
|
||||
// dashboard itself. `Onboarding` only calls `refreshContext()` once the
|
||||
// whole wizard is done, at which point `children` here becomes non-empty
|
||||
// and this component naturally re-renders past this branch.
|
||||
if (children.length === 0) {
|
||||
return (
|
||||
<Layout>
|
||||
<div data-testid="dashboard" className="dashboard">
|
||||
<section className="dashboard__section">
|
||||
<h2>{t('dashboard.addChildTitle')}</h2>
|
||||
<p>{t('dashboard.addChildIntro')}</p>
|
||||
<form onSubmit={(e) => void handleAddChild(e)}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="child-name">{t('dashboard.childNameLabel')}</label>
|
||||
<input
|
||||
id="child-name"
|
||||
type="text"
|
||||
placeholder={t('dashboard.namePlaceholder')}
|
||||
value={childName}
|
||||
onChange={(e) => setChildName(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<ChildBirthdayInput
|
||||
birthDate={childBirthDate}
|
||||
onBirthDateChange={setChildBirthDate}
|
||||
label={t('dashboard.birthdayLabel')}
|
||||
/>
|
||||
</div>
|
||||
{submitError && (
|
||||
<div role="alert" className="error-message">
|
||||
{submitError}
|
||||
</div>
|
||||
)}
|
||||
<button type="submit" disabled={isSubmitting}>
|
||||
{isSubmitting ? t('dashboard.addingChild') : t('dashboard.addChildButton')}
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
return <Onboarding />
|
||||
}
|
||||
|
||||
const selectedChild = children.find((c) => c.id === selectedChildId)
|
||||
@@ -261,6 +200,16 @@ export function Dashboard(): ReactNode {
|
||||
/>
|
||||
)}
|
||||
|
||||
{!parentalLeave && (
|
||||
<p
|
||||
className="dashboard__estimate-badge"
|
||||
data-testid="dashboard-estimate-badge"
|
||||
title={t('dashboard.estimatedBadgeCaption')}
|
||||
>
|
||||
{t('dashboard.estimatedBadge')}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{age4Bars.length > 0 && <Age4Bars bars={age4Bars} />}
|
||||
|
||||
<section className="dashboard__section">
|
||||
|
||||
Reference in New Issue
Block a user