MVP frontend+backend
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { ParentalLeaveBreakdown } from './ParentalLeaveBreakdown'
|
||||
import type { ParentalLeaveFetch } from '@/types'
|
||||
|
||||
describe('ParentalLeaveBreakdown', () => {
|
||||
const mockData: ParentalLeaveFetch = {
|
||||
id: 'pf1',
|
||||
personalDataUuid: 'pd1',
|
||||
workspaceId: 'ws1',
|
||||
childId: 'c1',
|
||||
source: 'scraped',
|
||||
fetchedAt: '2026-06-13T10:00:00Z',
|
||||
totalDays: 300,
|
||||
daysUsed: 50,
|
||||
daysLeft: 250,
|
||||
reservedDaysTotal: 90,
|
||||
reservedDaysLeft: 80,
|
||||
transferableDaysLeft: 50,
|
||||
dubbeldagarLeft: 60,
|
||||
tierData: {
|
||||
sjukpenningTotal: 100,
|
||||
sjukpenningUsed: 20,
|
||||
sjukpenningLeft: 80,
|
||||
lagstaNivaTotal: 200,
|
||||
lagstaNivaUsed: 30,
|
||||
lagstaNivaLeft: 170,
|
||||
},
|
||||
createdAt: '2026-06-13T10:00:00Z',
|
||||
updatedAt: '2026-06-13T10:00:00Z',
|
||||
}
|
||||
|
||||
it('renders empty state when data is null', () => {
|
||||
render(<ParentalLeaveBreakdown data={null} />)
|
||||
expect(screen.getByText(/Ingen data hämtad ännu/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders breakdown table with data', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
expect(screen.getByTestId('parental-leave-breakdown')).toBeInTheDocument()
|
||||
expect(screen.getByText(/Reserverade dagar/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('displays reserved days', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
const row = screen.getByTestId('breakdown-reserved')
|
||||
expect(row).toHaveTextContent('80')
|
||||
expect(row).toHaveTextContent('90')
|
||||
})
|
||||
|
||||
it('displays transferable days', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
const row = screen.getByTestId('breakdown-transferable')
|
||||
expect(row).toHaveTextContent('50')
|
||||
})
|
||||
|
||||
it('displays dubbeldagar left', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
const row = screen.getByTestId('breakdown-dubbeldagar')
|
||||
expect(row).toHaveTextContent('60')
|
||||
})
|
||||
|
||||
it('displays tier data', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
const sjukRow = screen.getByTestId('breakdown-sjukpenning')
|
||||
expect(sjukRow).toHaveTextContent('80')
|
||||
expect(sjukRow).toHaveTextContent('100')
|
||||
|
||||
const lagstaRow = screen.getByTestId('breakdown-lagsta-niva')
|
||||
expect(lagstaRow).toHaveTextContent('170')
|
||||
expect(lagstaRow).toHaveTextContent('200')
|
||||
})
|
||||
|
||||
it('displays scraped source label', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
expect(screen.getByText(/Hämtad från Försäkringskassan/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('displays manual source label', () => {
|
||||
const manualData = { ...mockData, source: 'manual' as const }
|
||||
render(<ParentalLeaveBreakdown data={manualData} />)
|
||||
expect(screen.getByText(/Manuellt angiven/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('displays formatted date', () => {
|
||||
render(<ParentalLeaveBreakdown data={mockData} />)
|
||||
expect(screen.getByText(/2026-06-13/)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
import { ReactNode } from 'react'
|
||||
import type { ParentalLeaveFetch } from '@/types'
|
||||
|
||||
export interface ParentalLeaveBreakdownProps {
|
||||
data: ParentalLeaveFetch | null
|
||||
}
|
||||
|
||||
export function ParentalLeaveBreakdown({ data }: ParentalLeaveBreakdownProps): ReactNode {
|
||||
if (!data) {
|
||||
return (
|
||||
<div data-testid="parental-leave-breakdown" className="parental-leave-breakdown">
|
||||
<p className="parental-leave-breakdown__empty">
|
||||
Ingen data hämtad ännu — tryck på Hämta från Försäkringskassan.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('sv-SE')
|
||||
}
|
||||
|
||||
const sourceLabel = data.source === 'scraped' ? 'Hämtad från Försäkringskassan' : 'Manuellt angiven'
|
||||
|
||||
return (
|
||||
<div data-testid="parental-leave-breakdown" className="parental-leave-breakdown">
|
||||
<div className="parental-leave-breakdown__section">
|
||||
<table className="parental-leave-breakdown__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Typ</th>
|
||||
<th>Återstående</th>
|
||||
<th>Totalt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-testid="breakdown-reserved">
|
||||
<td>Reserverade dagar</td>
|
||||
<td>{data.reservedDaysLeft}</td>
|
||||
<td>{data.reservedDaysTotal}</td>
|
||||
</tr>
|
||||
<tr data-testid="breakdown-transferable">
|
||||
<td>Övergripbara dagar</td>
|
||||
<td>{data.transferableDaysLeft}</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
<tr data-testid="breakdown-dubbeldagar">
|
||||
<td>Dubbeldagar kvar</td>
|
||||
<td>{data.dubbeldagarLeft}</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
{data.tierData && (
|
||||
<>
|
||||
<tr data-testid="breakdown-sjukpenning">
|
||||
<td>Sjukpenning</td>
|
||||
<td>{data.tierData.sjukpenningLeft}</td>
|
||||
<td>{data.tierData.sjukpenningTotal}</td>
|
||||
</tr>
|
||||
<tr data-testid="breakdown-lagsta-niva">
|
||||
<td>Lägsta nivå</td>
|
||||
<td>{data.tierData.lagstaNivaLeft}</td>
|
||||
<td>{data.tierData.lagstaNivaTotal}</td>
|
||||
</tr>
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="parental-leave-breakdown__provenance">
|
||||
<small>
|
||||
{sourceLabel} {formatDate(data.fetchedAt)}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user