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
+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> {