Bugfixes in dashboard and calendar

This commit is contained in:
2026-06-14 19:02:20 +02:00
parent 566595984f
commit d556ce0f6f
6 changed files with 699 additions and 31 deletions
+27 -15
View File
@@ -1,6 +1,5 @@
"""HTTP routes for planned leave days (calendar planning)."""
from datetime import date
from uuid import UUID
from fastapi import APIRouter, HTTPException, Query, status
@@ -9,6 +8,7 @@ from app.dependencies import CurrentUserDep, PlanningServiceDep
from app.models.planned_leave import (
PlannedLeaveDayCreate,
PlannedLeaveDayResponse,
PlannedLeaveDayUpdate,
)
from app.utils.errors import NotFoundError, ValidationError
@@ -39,6 +39,16 @@ async def create_planned_day(
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, str(exc)) from exc
@router.get("", response_model=list[PlannedLeaveDayResponse])
async def list_planned_days(
service: PlanningServiceDep,
_current_user: CurrentUserDep,
child_id: UUID = Query(...),
) -> list[PlannedLeaveDayResponse]:
days = await service.list_by_child(child_id)
return [_to_response(d) for d in days]
@router.get("/{planned_leave_day_id}", response_model=PlannedLeaveDayResponse)
async def get_planned_day(
planned_leave_day_id: UUID,
@@ -62,20 +72,22 @@ async def list_planned_days_by_workspace(
return [_to_response(d) for d in days]
@router.get("/range", response_model=list[PlannedLeaveDayResponse])
async def list_planned_days_by_range(
workspace_id: UUID = Query(...),
child_id: UUID = Query(...),
start_date: date = Query(...),
end_date: date = Query(...),
service: PlanningServiceDep = None,
_current_user: CurrentUserDep = None,
) -> list[PlannedLeaveDayResponse]:
# Inject dependencies manually for query parameters
# Since we can't easily pass Query params with FastAPI dependencies,
# we'll need to inject them differently
pass
@router.put("/{planned_leave_day_id}", response_model=PlannedLeaveDayResponse)
async def update_planned_day(
planned_leave_day_id: UUID,
payload: PlannedLeaveDayUpdate,
service: PlanningServiceDep,
_current_user: CurrentUserDep,
) -> PlannedLeaveDayResponse:
try:
day = await service.update(
planned_leave_day_id,
day_type=payload.day_type,
is_dubbeldag=payload.is_dubbeldag,
)
return _to_response(day)
except NotFoundError as exc:
raise HTTPException(status.HTTP_404_NOT_FOUND, str(exc)) from exc
@router.delete("/{planned_leave_day_id}", status_code=status.HTTP_204_NO_CONTENT)
+22
View File
@@ -91,3 +91,25 @@ class PlanningService:
if entity is None:
raise NotFoundError(f"PlannedLeaveDay {planned_leave_day_id} not found")
return entity
async def list_by_child(self, child_id: UUID) -> list[PlannedLeaveDay]:
"""Get all planned days for a child across workspaces."""
return await self._repo.list(child_id=child_id)
async def update(
self,
planned_leave_day_id: UUID,
day_type: str | None = None,
is_dubbeldag: bool | None = None,
) -> PlannedLeaveDay:
"""Update a planned day (partial update)."""
entity = await self._repo.get_by_id(planned_leave_day_id)
if entity is None:
raise NotFoundError(f"PlannedLeaveDay {planned_leave_day_id} not found")
if day_type is not None:
entity.day_type = day_type
if is_dubbeldag is not None:
entity.is_dubbeldag = is_dubbeldag
return await self._repo.update(planned_leave_day_id, entity)
+113
View File
@@ -226,3 +226,116 @@ class TestPlanningService:
assert vacation.day_type == "vacation"
assert lagsta.day_type == "lagsta"
assert sjuk.day_type == "sjukpenning"
async def test_list_by_child(
self,
planning_service: PlanningService,
seeded_ids: SeededIds,
) -> None:
"""List all planned days for a child."""
child_id = seeded_ids.child_id
d1 = await planning_service.add_planned_day(
workspace_id=seeded_ids.workspace_id,
child_id=child_id,
parent_personal_data_uuid=seeded_ids.personal_data_uuid,
date=date(2026, 6, 15),
day_type="vacation",
)
d2 = await planning_service.add_planned_day(
workspace_id=seeded_ids.workspace_id,
child_id=child_id,
parent_personal_data_uuid=seeded_ids.personal_data_uuid,
date=date(2026, 6, 16),
day_type="lagsta",
)
result = await planning_service.list_by_child(child_id)
ids = {d.id for d in result}
assert d1.id in ids
assert d2.id in ids
async def test_list_by_child_empty(
self,
planning_service: PlanningService,
) -> None:
"""Listing a child with no planned days returns empty."""
result = await planning_service.list_by_child(uuid4())
assert result == []
async def test_update_planned_day_day_type(
self,
planning_service: PlanningService,
seeded_ids: SeededIds,
) -> None:
"""Update the day_type of a planned day."""
created = await planning_service.add_planned_day(
workspace_id=seeded_ids.workspace_id,
child_id=seeded_ids.child_id,
parent_personal_data_uuid=seeded_ids.personal_data_uuid,
date=date(2026, 6, 15),
day_type="vacation",
)
updated = await planning_service.update(
created.id,
day_type="lagsta",
)
assert updated.day_type == "lagsta"
assert updated.date == date(2026, 6, 15)
async def test_update_planned_day_is_dubbeldag(
self,
planning_service: PlanningService,
seeded_ids: SeededIds,
) -> None:
"""Update the is_dubbeldag flag of a planned day."""
created = await planning_service.add_planned_day(
workspace_id=seeded_ids.workspace_id,
child_id=seeded_ids.child_id,
parent_personal_data_uuid=seeded_ids.personal_data_uuid,
date=date(2026, 6, 15),
day_type="vacation",
is_dubbeldag=False,
)
updated = await planning_service.update(
created.id,
is_dubbeldag=True,
)
assert updated.is_dubbeldag is True
assert updated.day_type == "vacation"
async def test_update_planned_day_both_fields(
self,
planning_service: PlanningService,
seeded_ids: SeededIds,
) -> None:
"""Update both day_type and is_dubbeldag."""
created = await planning_service.add_planned_day(
workspace_id=seeded_ids.workspace_id,
child_id=seeded_ids.child_id,
parent_personal_data_uuid=seeded_ids.personal_data_uuid,
date=date(2026, 6, 15),
day_type="vacation",
is_dubbeldag=False,
)
updated = await planning_service.update(
created.id,
day_type="sjukpenning",
is_dubbeldag=True,
)
assert updated.day_type == "sjukpenning"
assert updated.is_dubbeldag is True
async def test_update_missing_raises(
self,
planning_service: PlanningService,
) -> None:
"""Updating a missing planned day raises NotFoundError."""
with pytest.raises(NotFoundError):
await planning_service.update(
uuid4(),
day_type="lagsta",
)
+299
View File
@@ -0,0 +1,299 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import * as api from './api'
import type { RawParentalLeaveFetch, RawWorkspaceOverview } from './api'
describe('API response mappers (snake_case → camelCase)', () => {
let fetchMock: ReturnType<typeof vi.fn>
beforeEach(() => {
fetchMock = vi.fn()
globalThis.fetch = fetchMock as any
})
afterEach(() => {
vi.clearAllMocks()
})
describe('getWorkspaceOverview', () => {
it('maps snake_case workspace overview to camelCase', async () => {
const rawResponse: RawWorkspaceOverview = {
workspace_id: 'ws1',
child_id: 'child1',
parent_projections: [
{
personal_data_uuid: 'pd1',
child_id: 'child1',
birth_date: '2024-01-01',
fourth_birthday: '2028-01-01',
total_days: 480,
days_used: 100,
planned_days_before_b4: 150,
projected_left_at_b4: 230,
savable_after_b4: 96,
expiring_at_b4: 134,
},
],
combined_days_used: 100,
combined_days_left: 380,
combined_expiring_at_b4: 134,
}
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getWorkspaceOverview('ws1', 'child1')
expect(result.workspaceId).toBe('ws1')
expect(result.childId).toBe('child1')
expect(result.combinedDaysUsed).toBe(100)
expect(result.combinedDaysLeft).toBe(380)
expect(result.combinedExpiringAtB4).toBe(134)
expect(result.parentProjections.length).toBe(1)
expect(result.parentProjections[0]!.personalDataUuid).toBe('pd1')
expect(result.parentProjections[0]!.fourthBirthday).toBe('2028-01-01')
expect(result.parentProjections[0]!.plannedDaysBeforeB4).toBe(150)
expect(result.parentProjections[0]!.projectedLeftAtB4).toBe(230)
expect(result.parentProjections[0]!.savableAfterB4).toBe(96)
expect(result.parentProjections[0]!.expiringAtB4).toBe(134)
})
})
describe('getParentalLeave', () => {
it('maps snake_case parental leave fetch to camelCase with nested tierData', async () => {
const rawResponse: RawParentalLeaveFetch = {
id: 'pf1',
personal_data_uuid: 'pd1',
workspace_id: 'ws1',
child_id: 'child1',
source: 'manual',
fetched_at: '2026-06-14T17:09:47',
total_days: 480,
days_used: 100,
days_left: 380,
reserved_days_total: 90,
reserved_days_left: 80,
transferable_days_left: 100,
dubbeldagar_left: 60,
tier_data: {
sjukpenning_total: 390,
sjukpenning_used: 50,
sjukpenning_left: 340,
lagsta_niva_total: 90,
lagsta_niva_used: 10,
lagsta_niva_left: 80,
},
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
}
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getParentalLeave('pd1', 'child1')
expect(result.personalDataUuid).toBe('pd1')
expect(result.workspaceId).toBe('ws1')
expect(result.childId).toBe('child1')
expect(result.fetchedAt).toBe('2026-06-14T17:09:47')
expect(result.totalDays).toBe(480)
expect(result.daysUsed).toBe(100)
expect(result.daysLeft).toBe(380)
expect(result.reservedDaysTotal).toBe(90)
expect(result.reservedDaysLeft).toBe(80)
expect(result.transferableDaysLeft).toBe(100)
expect(result.dubbeldagarLeft).toBe(60)
expect(result.createdAt).toBe('2026-06-14T17:09:47')
expect(result.updatedAt).toBe('2026-06-14T17:09:47')
expect(result.tierData!.sjukpenningTotal).toBe(390)
expect(result.tierData!.sjukpenningUsed).toBe(50)
expect(result.tierData!.sjukpenningLeft).toBe(340)
expect(result.tierData!.lagstaNivaTotal).toBe(90)
expect(result.tierData!.lagstaNivaUsed).toBe(10)
expect(result.tierData!.lagstaNivaLeft).toBe(80)
})
})
describe('getPlannedDays', () => {
it('maps snake_case planned days to camelCase', async () => {
const rawResponse = [
{
id: 'pd1',
workspace_id: 'ws1',
child_id: 'child1',
parent_personal_data_uuid: 'pp1',
date: '2026-06-15',
day_type: 'sjukpenning' as const,
is_dubbeldag: false,
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
},
{
id: 'pd2',
workspace_id: 'ws1',
child_id: 'child1',
parent_personal_data_uuid: 'pp1',
date: '2026-06-16',
day_type: 'vacation' as const,
is_dubbeldag: true,
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
},
]
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getPlannedDays('child1')
expect(result).toHaveLength(2)
expect(result[0]!.workspaceId).toBe('ws1')
expect(result[0]!.childId).toBe('child1')
expect(result[0]!.parentPersonalDataUuid).toBe('pp1')
expect(result[0]!.dayType).toBe('sjukpenning')
expect(result[0]!.isDubbeldag).toBe(false)
expect(result[1]!.dayType).toBe('vacation')
expect(result[1]!.isDubbeldag).toBe(true)
})
})
describe('getBreakPeriods', () => {
it('maps snake_case break periods to camelCase', async () => {
const rawResponse = [
{
id: 'bp1',
workspace_id: 'ws1',
name: 'Summer 2026',
start_date: '2026-06-15',
end_date: '2026-08-31',
target_weeks: 12,
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
},
]
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getBreakPeriods('ws1')
expect(result).toHaveLength(1)
expect(result[0]!.workspaceId).toBe('ws1')
expect(result[0]!.name).toBe('Summer 2026')
expect(result[0]!.startDate).toBe('2026-06-15')
expect(result[0]!.endDate).toBe('2026-08-31')
expect(result[0]!.targetWeeks).toBe(12)
})
})
describe('getVacationDaysByWorkspace', () => {
it('maps snake_case vacation days to camelCase', async () => {
const rawResponse = [
{
id: 'vd1',
personal_data_uuid: 'pd1',
workspace_id: 'ws1',
year: 2026,
total_days: 25,
saved_days_in: 5,
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
},
]
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getVacationDaysByWorkspace('ws1')
expect(result).toHaveLength(1)
expect(result[0]!.personalDataUuid).toBe('pd1')
expect(result[0]!.workspaceId).toBe('ws1')
expect(result[0]!.year).toBe(2026)
expect(result[0]!.totalDays).toBe(25)
expect(result[0]!.savedDaysIn).toBe(5)
})
})
describe('createBreakPeriod', () => {
it('sends camelCase request and maps snake_case response to camelCase', async () => {
const rawResponse = {
id: 'bp1',
workspace_id: 'ws1',
name: 'Summer 2026',
start_date: '2026-06-15',
end_date: '2026-08-31',
target_weeks: 12,
created_at: '2026-06-14T17:09:47',
updated_at: '2026-06-14T17:09:47',
}
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.createBreakPeriod('ws1', {
startDate: '2026-06-15',
endDate: '2026-08-31',
name: 'Summer 2026',
targetWeeks: 12,
})
const calls = (fetchMock.mock?.calls ?? []) as any[][]
if (calls.length === 0) throw new Error('No fetch calls made')
const [, options] = calls[0]!
const bodyStr = options.body
const body = JSON.parse(bodyStr)
expect(body.start_date).toBe('2026-06-15')
expect(body.end_date).toBe('2026-08-31')
expect(body.target_weeks).toBe(12)
expect(result.startDate).toBe('2026-06-15')
expect(result.endDate).toBe('2026-08-31')
expect(result.targetWeeks).toBe(12)
})
})
describe('getWorkspace', () => {
it('maps snake_case workspace to camelCase', async () => {
const rawResponse = {
id: 'ws1',
name: 'My Workspace',
planning_goal: 'max_time' as const,
created_at: '2026-06-14T17:09:47',
}
fetchMock.mockResolvedValue({
ok: true,
status: 200,
json: async () => rawResponse,
})
const result = await api.getWorkspace('ws1')
expect(result.id).toBe('ws1')
expect(result.name).toBe('My Workspace')
expect(result.planningGoal).toBe('max_time')
expect(result.createdAt).toBe('2026-06-14T17:09:47')
})
})
})
+234 -16
View File
@@ -20,10 +20,212 @@ import type {
WorkspaceUpdateRequest,
WorkspaceOverview,
} from '@/types'
import type { Workspace, BreakPeriod, Tip, PlannedLeaveDay } from '@/types'
import type { Workspace, BreakPeriod, Tip, PlannedLeaveDay, TierData, Age4Projection } from '@/types'
const BASE = '/api'
// ---------------------------------------------------------------------------
// Wire format converters (snake_case → camelCase)
// ---------------------------------------------------------------------------
export interface RawTierData {
sjukpenning_total: number
sjukpenning_used: number
sjukpenning_left: number
lagsta_niva_total: number
lagsta_niva_used: number
lagsta_niva_left: number
}
function toTierData(raw: RawTierData): TierData {
return {
sjukpenningTotal: raw.sjukpenning_total,
sjukpenningUsed: raw.sjukpenning_used,
sjukpenningLeft: raw.sjukpenning_left,
lagstaNivaTotal: raw.lagsta_niva_total,
lagstaNivaUsed: raw.lagsta_niva_used,
lagstaNivaLeft: raw.lagsta_niva_left,
}
}
export interface RawParentalLeaveFetch {
id: string
personal_data_uuid: string
workspace_id: string
child_id: string
source: 'scraped' | 'manual'
fetched_at: string
total_days: number
days_used: number
days_left: number
reserved_days_total: number
reserved_days_left: number
transferable_days_left: number
dubbeldagar_left: number
tier_data: RawTierData
created_at: string
updated_at: string
}
function toParentalLeaveFetch(raw: RawParentalLeaveFetch): ParentalLeaveFetch {
return {
id: raw.id,
personalDataUuid: raw.personal_data_uuid,
workspaceId: raw.workspace_id,
childId: raw.child_id,
source: raw.source,
fetchedAt: raw.fetched_at,
totalDays: raw.total_days,
daysUsed: raw.days_used,
daysLeft: raw.days_left,
reservedDaysTotal: raw.reserved_days_total,
reservedDaysLeft: raw.reserved_days_left,
transferableDaysLeft: raw.transferable_days_left,
dubbeldagarLeft: raw.dubbeldagar_left,
tierData: toTierData(raw.tier_data),
createdAt: raw.created_at,
updatedAt: raw.updated_at,
}
}
export interface RawAge4Projection {
personal_data_uuid: string
child_id: string
birth_date: string
fourth_birthday: string
total_days: number
days_used: number
planned_days_before_b4: number
projected_left_at_b4: number
savable_after_b4: number
expiring_at_b4: number
}
function toAge4Projection(raw: RawAge4Projection): Age4Projection {
return {
personalDataUuid: raw.personal_data_uuid,
childId: raw.child_id,
birthDate: raw.birth_date,
fourthBirthday: raw.fourth_birthday,
totalDays: raw.total_days,
daysUsed: raw.days_used,
plannedDaysBeforeB4: raw.planned_days_before_b4,
projectedLeftAtB4: raw.projected_left_at_b4,
savableAfterB4: raw.savable_after_b4,
expiringAtB4: raw.expiring_at_b4,
}
}
export interface RawWorkspaceOverview {
workspace_id: string
child_id: string
parent_projections: RawAge4Projection[]
combined_days_used: number
combined_days_left: number
combined_expiring_at_b4: number
}
function toWorkspaceOverview(raw: RawWorkspaceOverview): WorkspaceOverview {
return {
workspaceId: raw.workspace_id,
childId: raw.child_id,
parentProjections: raw.parent_projections.map(toAge4Projection),
combinedDaysUsed: raw.combined_days_used,
combinedDaysLeft: raw.combined_days_left,
combinedExpiringAtB4: raw.combined_expiring_at_b4,
}
}
interface RawVacationDays {
id: string
personal_data_uuid: string
workspace_id: string
year: number
total_days: number
saved_days_in: number
created_at: string | null
updated_at: string | null
}
function toVacationDays(raw: RawVacationDays): VacationDays {
return {
id: raw.id,
personalDataUuid: raw.personal_data_uuid,
workspaceId: raw.workspace_id,
year: raw.year,
totalDays: raw.total_days,
savedDaysIn: raw.saved_days_in,
createdAt: raw.created_at,
updatedAt: raw.updated_at,
}
}
interface RawPlannedLeaveDay {
id: string
workspace_id: string
child_id: string
parent_personal_data_uuid: string
date: string
day_type: 'sjukpenning' | 'lagsta' | 'vacation'
is_dubbeldag: boolean
created_at: string
updated_at: string
}
function toPlannedLeaveDay(raw: RawPlannedLeaveDay): PlannedLeaveDay {
return {
id: raw.id,
workspaceId: raw.workspace_id,
childId: raw.child_id,
parentPersonalDataUuid: raw.parent_personal_data_uuid,
date: raw.date,
dayType: raw.day_type,
isDubbeldag: raw.is_dubbeldag,
createdAt: raw.created_at,
updatedAt: raw.updated_at,
}
}
interface RawBreakPeriod {
id: string
workspace_id: string
name: string
start_date: string
end_date: string
target_weeks: number
created_at: string
updated_at: string
}
function toBreakPeriod(raw: RawBreakPeriod): BreakPeriod {
return {
id: raw.id,
workspaceId: raw.workspace_id,
name: raw.name,
startDate: raw.start_date,
endDate: raw.end_date,
targetWeeks: raw.target_weeks,
createdAt: raw.created_at,
updatedAt: raw.updated_at,
}
}
interface RawWorkspace {
id: string
name: string
planning_goal: 'max_time' | 'max_money' | 'balanced'
created_at: string
}
function toWorkspace(raw: RawWorkspace): Workspace {
return {
id: raw.id,
name: raw.name,
planningGoal: raw.planning_goal,
createdAt: raw.created_at,
}
}
let _accessToken: string | null = null
export function setAccessToken(token: string | null): void {
@@ -132,7 +334,8 @@ export async function createWorkspace(req: WorkspaceCreateRequest): Promise<Work
}
export async function getWorkspace(workspaceId: string): Promise<Workspace> {
return apiFetch(`/workspace/${workspaceId}`)
const raw = (await apiFetch(`/workspace/${workspaceId}`)) as RawWorkspace
return toWorkspace(raw)
}
export async function updateWorkspace(
@@ -176,7 +379,8 @@ export async function upsertVacationDays(req: VacationDaysCreateRequest): Promis
}
export async function getVacationDaysByWorkspace(workspaceId: string): Promise<VacationDays[]> {
return apiFetch(`/vacation-days/workspace/${workspaceId}`)
const raw = (await apiFetch(`/vacation-days/workspace/${workspaceId}`)) as RawVacationDays[]
return raw.map(toVacationDays)
}
// ---------------------------------------------------------------------------
@@ -184,7 +388,7 @@ export async function getVacationDaysByWorkspace(workspaceId: string): Promise<V
// ---------------------------------------------------------------------------
export async function saveManualFetch(req: ManualFetchRequest): Promise<ParentalLeaveFetch> {
return apiFetch('/parental-leave/manual', {
const raw = (await apiFetch('/parental-leave/manual', {
method: 'POST',
body: JSON.stringify({
personal_data_uuid: req.personalDataUuid,
@@ -201,7 +405,8 @@ export async function saveManualFetch(req: ManualFetchRequest): Promise<Parental
lagsta_niva_total: req.lagstaNivaTotal ?? 90,
lagsta_niva_used: req.lagstaNivaUsed,
}),
})
})) as RawParentalLeaveFetch
return toParentalLeaveFetch(raw)
}
// ---------------------------------------------------------------------------
@@ -212,7 +417,8 @@ export async function getWorkspaceOverview(
workspaceId: string,
childId: string,
): Promise<WorkspaceOverview> {
return apiFetch(`/analytics/${workspaceId}/overview?child_id=${childId}`)
const raw = (await apiFetch(`/analytics/${workspaceId}/overview?child_id=${childId}`)) as RawWorkspaceOverview
return toWorkspaceOverview(raw)
}
// ---------------------------------------------------------------------------
@@ -254,17 +460,25 @@ export async function updateChildSettings(
// ---------------------------------------------------------------------------
export async function getBreakPeriods(workspaceId: string): Promise<BreakPeriod[]> {
return apiFetch(`/break-periods/${workspaceId}`)
const raw = (await apiFetch(`/break-periods/${workspaceId}`)) as RawBreakPeriod[]
return raw.map(toBreakPeriod)
}
export async function createBreakPeriod(
workspaceId: string,
payload: { startDate: string; endDate: string; name: string; targetWeeks: number },
): Promise<BreakPeriod> {
return apiFetch(`/break-periods`, {
const raw = (await apiFetch(`/break-periods`, {
method: 'POST',
body: JSON.stringify({ ...payload, workspace_id: workspaceId }),
})
body: JSON.stringify({
workspace_id: workspaceId,
start_date: payload.startDate,
end_date: payload.endDate,
name: payload.name,
target_weeks: payload.targetWeeks,
}),
})) as RawBreakPeriod
return toBreakPeriod(raw)
}
export async function deleteBreakPeriod(id: string): Promise<void> {
@@ -287,7 +501,8 @@ export async function getParentalLeave(
personalDataUuid: string,
childId: string,
): Promise<ParentalLeaveFetch> {
return apiFetch(`/parental-leave/${personalDataUuid}/${childId}`)
const raw = (await apiFetch(`/parental-leave/${personalDataUuid}/${childId}`)) as RawParentalLeaveFetch
return toParentalLeaveFetch(raw)
}
// ---------------------------------------------------------------------------
@@ -296,7 +511,8 @@ export async function getParentalLeave(
export async function getPlannedDays(childId?: string): Promise<PlannedLeaveDay[]> {
const query = childId ? `?child_id=${childId}` : ''
return apiFetch(`/planned-days${query}`)
const raw = (await apiFetch(`/planned-days${query}`)) as RawPlannedLeaveDay[]
return raw.map(toPlannedLeaveDay)
}
export interface CreatePlannedDayPayload {
@@ -309,10 +525,11 @@ export interface CreatePlannedDayPayload {
}
export async function createPlannedDay(payload: CreatePlannedDayPayload): Promise<PlannedLeaveDay> {
return apiFetch(`/planned-days`, {
const raw = (await apiFetch(`/planned-days`, {
method: 'POST',
body: JSON.stringify(payload),
})
})) as RawPlannedLeaveDay
return toPlannedLeaveDay(raw)
}
export interface UpdatePlannedDayPayload {
@@ -321,10 +538,11 @@ export interface UpdatePlannedDayPayload {
}
export async function updatePlannedDay(id: string, payload: UpdatePlannedDayPayload): Promise<PlannedLeaveDay> {
return apiFetch(`/planned-days/${id}`, {
const raw = (await apiFetch(`/planned-days/${id}`, {
method: 'PUT',
body: JSON.stringify(payload),
})
})) as RawPlannedLeaveDay
return toPlannedLeaveDay(raw)
}
export async function deletePlannedDay(id: string): Promise<void> {
+4
View File
@@ -0,0 +1,4 @@
- "Vacation days" i settings behöver vara så att man tex första året när man troligtvis är hemma mera, att det då är färre dagar men resterande år så har man sit "fulla pott", så att vi vet vad vi har att leka med för tid
- "Workspace Settings" makes no sense just nu.
- Ger också ett error :P när man sparar som säger "planning_goal must be one of {'max_money', 'max_time', 'balanced'}" så kanske att det borde heta så i frontend också
- "Parent Profile" går inte att ställa in hur mkt pengar man får, men vet inte heller varför detta behövs?