Spaces:
Sleeping
Sleeping
File size: 7,303 Bytes
cd99321 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | // Shared types for the TREK travel planner.
//
// Domain entity/response types are now sourced from @trek/shared — the single
// source of truth shared with the server. The Zod schemas there are built to
// match the REAL server response shapes (see shared/src/<domain>/*.schema.ts,
// each documented against the producing service). Re-exported here so the rest
// of the client keeps importing from '../types' unchanged.
import type {
Trip,
TripMember,
Day,
DayNote,
Place,
AssignmentPlace,
PlaceCategory,
Assignment,
AssignmentParticipant,
PackingItem,
PackingBag,
PackingBagMember,
BudgetItem,
BudgetItemMember,
Reservation,
ReservationEndpoint,
Accommodation,
Tag,
Category,
} from '@trek/shared'
export type {
Trip,
TripMember,
Day,
DayNote,
Place,
AssignmentPlace,
PlaceCategory,
Assignment,
AssignmentParticipant,
PackingItem,
PackingBag,
PackingBagMember,
BudgetItem,
BudgetItemMember,
Reservation,
ReservationEndpoint,
Accommodation,
Tag,
Category,
}
export interface User {
id: number
username: string
email: string
role: 'admin' | 'user'
avatar_url: string | null
maps_api_key: string | null
created_at: string
/** Present after load; true when TOTP MFA is enabled for password login */
mfa_enabled?: boolean
/** True when a password change is required before the user can continue */
must_change_password?: boolean
}
export interface TodoItem {
id: number
trip_id: number
name: string
category: string | null
checked: number
sort_order: number
due_date: string | null
description: string | null
assigned_user_id: number | null
priority: number
}
export interface TripFile {
id: number
trip_id: number
place_id?: number | null
reservation_id?: number | null
note_id?: number | null
uploaded_by?: number | null
uploaded_by_name?: string | null
uploaded_by_avatar?: string | null
filename: string
original_name: string
file_size?: number | null
mime_type: string
description?: string | null
starred?: number
deleted_at?: string | null
created_at: string
reservation_title?: string
linked_reservation_ids?: (number | null)[]
linked_place_ids?: (number | null)[]
/** Served download path — always present on list/create/update responses (formatFile). */
url: string
}
export interface Settings {
map_tile_url: string
default_lat: number
default_lng: number
default_zoom: number
dark_mode: boolean | string
default_currency: string
language: string
temperature_unit: string
time_format: string
show_place_description: boolean
blur_booking_codes?: boolean
map_booking_labels?: boolean
map_poi_pill_enabled?: boolean
optimize_from_accommodation?: boolean
map_provider?: 'leaflet' | 'mapbox-gl'
mapbox_access_token?: string
mapbox_style?: string
mapbox_3d_enabled?: boolean
mapbox_quality_mode?: boolean
}
export interface AssignmentsMap {
[dayId: string]: Assignment[]
}
export interface DayNotesMap {
[dayId: string]: DayNote[]
}
export interface RouteSegment {
mid: [number, number]
from: [number, number]
to: [number, number]
distance: number
duration: number
walkingText: string
drivingText: string
distanceText: string
durationText?: string
}
export interface RouteWithLegs {
coordinates: [number, number][]
distance: number
duration: number
legs: RouteSegment[]
}
export interface RouteResult {
coordinates: [number, number][]
distance: number
duration: number
distanceText: string
durationText: string
walkingText: string
drivingText: string
}
export interface Waypoint {
lat: number
lng: number
}
// Optional fixed start/end points for route optimization (e.g. the day's accommodation).
export interface RouteAnchors {
start?: Waypoint
end?: Waypoint
}
// User with optional OIDC fields
export interface UserWithOidc extends User {
oidc_issuer?: string | null
}
// Atlas place detail
export interface AtlasPlace {
id: number
name: string
lat: number | null
lng: number | null
}
// GeoJSON types (simplified for atlas map)
export interface GeoJsonFeature {
type: 'Feature'
properties: Record<string, string | number | null | undefined>
geometry: {
type: string
coordinates: unknown
}
id?: string
}
export interface GeoJsonFeatureCollection {
type: 'FeatureCollection'
features: GeoJsonFeature[]
}
// App config from /auth/app-config
export interface AppConfig {
has_users: boolean
allow_registration: boolean
demo_mode: boolean
oidc_configured: boolean
oidc_display_name?: string
oidc_only_mode?: boolean
has_maps_key?: boolean
allowed_file_types?: string
timezone?: string
/** When true, users without MFA cannot use the app until they enable it */
require_mfa?: boolean
// Granular auth toggles
password_login?: boolean
password_registration?: boolean
oidc_login?: boolean
oidc_registration?: boolean
env_override_oidc_only?: boolean
}
// Translation function type
export type TranslationFn = (key: string, params?: Record<string, string | number | null>) => string
// WebSocket event type
export interface WebSocketEvent {
type: string
[key: string]: unknown
}
// Vacay types
export interface VacayHolidayCalendar {
id: number
plan_id: number
region: string
label: string | null
color: string
sort_order: number
}
export interface VacayPlan {
id: number
holidays_enabled: boolean
holidays_region: string | null
holiday_calendars: VacayHolidayCalendar[]
block_weekends: boolean
carry_over_enabled: boolean
company_holidays_enabled: boolean
// Comma-separated weekday indices (e.g. '0,6'); stored as TEXT on vacay_plans.
weekend_days?: string
week_start?: number
name?: string
year?: number
owner_id?: number
created_at?: string
updated_at?: string
}
export interface VacayUser {
id: number
username: string
color: string | null
}
export interface VacayEntry {
date: string
user_id: number
plan_id?: number
person_color?: string
person_name?: string
}
// Vacay per-user stats row as returned by getStats
// (server/src/services/vacayService.ts -> getStats).
export interface VacayStat {
user_id: number
person_name: string
person_color: string
year: number
vacation_days: number
carried_over: number
total_available: number
used: number
remaining: number
}
export interface HolidayInfo {
name: string
localName: string
color: string
label: string | null
}
export interface HolidaysMap {
[date: string]: HolidayInfo
}
// API error shape from axios
export interface ApiError {
response?: {
data?: {
error?: string
}
status?: number
}
message: string
}
/** Safely extract an error message from an unknown catch value */
export function getApiErrorMessage(err: unknown, fallback: string): string {
if (typeof err === 'object' && err !== null && 'response' in err) {
const apiErr = err as ApiError
if (apiErr.response?.data?.error) return apiErr.response.data.error
}
if (err instanceof Error) return err.message
return fallback
}
// MergedItem used in day notes hook
export interface MergedItem {
type: 'assignment' | 'note' | 'place' | 'transport'
sortKey: number
data: Assignment | DayNote | Reservation
}
|