Replace the fake backend with actual API calls

This commit is contained in:
Moritz Ruth 2024-06-17 13:38:21 +02:00
parent dfb3d8eb5a
commit 95f8b7a8db
Signed by: moritzruth
GPG key ID: C9BBAB79405EE56D
5 changed files with 87 additions and 111 deletions

View file

@ -33,6 +33,7 @@
"chartjs-adapter-date-fns": "^3.0.0",
"color-alpha": "^2.0.0",
"date-fns": "^3.6.0",
"ky": "^1.3.0",
"lodash-es": "^4.17.21",
"nanoid": "^5.0.7",
"temporal-polyfill": "^0.2.4",

9
pnpm-lock.yaml generated
View file

@ -38,6 +38,9 @@ importers:
date-fns:
specifier: ^3.6.0
version: 3.6.0
ky:
specifier: ^1.3.0
version: 1.3.0
lodash-es:
specifier: ^4.17.21
version: 4.17.21
@ -965,6 +968,10 @@ packages:
kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
ky@1.3.0:
resolution: {integrity: sha512-QUViPXlgP6NKA57IAPff/aZSmRA6qs9wKxlEpayBorwRZG+x2LG7jD4kXh8lnH3q/gkUr64NyZ7kwErUEZJmlw==}
engines: {node: '>=18'}
local-pkg@0.5.0:
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
@ -2254,6 +2261,8 @@ snapshots:
kolorist@1.8.0: {}
ky@1.3.0: {}
local-pkg@0.5.0:
dependencies:
mlly: 1.7.0

View file

@ -1,14 +1,29 @@
import { Temporal } from "temporal-polyfill"
import { cloneDeep } from "lodash-es"
import { fakeServerState } from "@/fakeServerState"
import ky from "ky"
const api = ky.extend({
prefixUrl: "https://ias-tea-axum.shuttleapp.rs/",
mode: "cors"
})
export interface TypeOfTea {
id: string
name: string
notes: string
waterTemperatureInCelsius: number
steepingTime: Temporal.Duration
registrationTimestamp: Temporal.Instant
}
interface WireTypeOfTea {
id: number
tea_name: string
tea_notes: string
water_temp: number // Celsius
steeping_seconds: number
registration_timestamp: string
}
export interface SteepingTimeChange {
id: string
typeOfTeaId: string
@ -22,34 +37,74 @@ export interface BrewingEvent {
timestamp: Temporal.Instant
}
interface WireBrewingEvent {
change_id: string
tea_id: number
steeping_seconds: number
steeping_tested_time: string
}
export interface Configuration {
defaultSteepingTime: Temporal.Duration
feedbackTimeout: Temporal.Duration
}
interface WireConfiguration {
default_steeping_time: number // seconds
feedback_timeout: number // seconds
}
const delay = () => new Promise(resolve => setTimeout(resolve, 1000))
export async function fetchConfiguration(): Promise<Configuration> {
await delay()
return cloneDeep(fakeServerState.configuration)
const result = await api.get("configuration").json<WireConfiguration>()
return {
defaultSteepingTime: Temporal.Duration.from({ seconds: result.default_steeping_time }).round({ largestUnit: "minutes" }),
feedbackTimeout: Temporal.Duration.from({ seconds: result.feedback_timeout }).round({ largestUnit: "hour" }),
}
}
export async function updateConfiguration(value: Configuration) {
await delay()
fakeServerState.configuration = cloneDeep(value)
export async function updateConfiguration(data: Configuration) {
const wireData: WireConfiguration = {
default_steeping_time: data.defaultSteepingTime.total("seconds"),
feedback_timeout: data.feedbackTimeout.total("seconds")
}
await api.post("configuration", { json: wireData })
}
export async function fetchBrewingEvents(): Promise<BrewingEvent[]> {
await delay()
return cloneDeep(fakeServerState.brewingEvents)
const result = await api.get("brewing-events").json<WireBrewingEvent[]>()
return result.map(e => ({
id: e.change_id,
typeOfTeaId: e.tea_id.toString(),
timestamp: Temporal.PlainDateTime.from(e.steeping_tested_time).toZonedDateTime("UTC").toInstant()
}))
}
export async function fetchTypesOfTeaById(): Promise<Map<string, TypeOfTea>> {
await delay()
return new Map(fakeServerState.typesOfTea.map(t => [t.id, t]))
const result = await api.get("types-of-tea").json<WireTypeOfTea[]>()
result.sort((a, b) => a.id - b.id)
return new Map(result.map(t => [t.id.toString(), {
id: t.id.toString(),
name: t.tea_name,
notes: t.tea_notes,
waterTemperatureInCelsius: t.water_temp,
steepingTime: Temporal.Duration.from({ seconds: t.steeping_seconds }).round({ largestUnit: "minutes" }), // round for balancing
registrationTimestamp: Temporal.PlainDateTime.from(t.registration_timestamp).toZonedDateTime("UTC").toInstant()
}]))
}
export async function updateTypeOfTea(id: string, data: Pick<TypeOfTea, "name" | "steepingTime">) {
await delay()
Object.assign(fakeServerState.typesOfTea.find(t => t.id === id)!, data)
export async function updateTypeOfTea(id: string, data: Pick<TypeOfTea, "name" | "notes" | "waterTemperatureInCelsius" | "steepingTime">) {
const wireData: Pick<WireTypeOfTea, "tea_name" | "tea_notes" | "water_temp" | "steeping_seconds"> = {
tea_name: data.name,
tea_notes: data.notes,
water_temp: data.waterTemperatureInCelsius,
steeping_seconds: data.steepingTime.total("seconds")
}
await api.put(`types-of-tea/${id}`, { json: wireData })
}

View file

@ -1,97 +0,0 @@
import { Temporal } from "temporal-polyfill"
import type { BrewingEvent, Configuration, SteepingTimeChange, TypeOfTea } from "@/backend"
import { random } from "lodash-es"
import { nanoid } from "nanoid"
const localTimeZoneId = Temporal.Now.timeZoneId()
const configuration: Configuration = {
defaultSteepingTime: Temporal.Duration.from({ minutes: 4, seconds: 30 }),
feedbackTimeout: Temporal.Duration.from({ hours: 2 })
}
const typesOfTea: TypeOfTea[] = [
{
id: nanoid(),
name: "Pfefferminz",
steepingTime: Temporal.Duration.from({ minutes: 5, seconds: 20 }),
registrationTimestamp: Temporal.ZonedDateTime.from({ timeZone: localTimeZoneId, year: 2024, month: 2, day: 20, hour: 14, minute: 24 }).toInstant()
},
{
id: nanoid(),
name: "Türkischer Apfel",
steepingTime: Temporal.Duration.from({ minutes: 3, seconds: 50 }),
registrationTimestamp: Temporal.ZonedDateTime.from({ timeZone: localTimeZoneId, year: 2024, month: 3, day: 1, hour: 16, minute: 1 }).toInstant()
},
{
id: nanoid(),
name: "Fenchel-Anis-Kümmel",
steepingTime: Temporal.Duration.from({ minutes: 8 }),
registrationTimestamp: Temporal.ZonedDateTime.from({ timeZone: localTimeZoneId, year: 2024, month: 3, day: 9, hour: 9, minute: 55 }).toInstant()
},
{
id: nanoid(),
name: "Hagebutte",
steepingTime: Temporal.Duration.from({ minutes: 4, seconds: 30 }),
registrationTimestamp: Temporal.ZonedDateTime.from({ timeZone: localTimeZoneId, year: 2024, month: 3, day: 29, hour: 15, minute: 34 }).toInstant()
},
]
const steepingTimeChanges: SteepingTimeChange[] = []
const brewingEvents: BrewingEvent[] = []
for (const type of typesOfTea) {
const numberOfBrewingEvents = random(5, 10)
let nextTimestamp = type.registrationTimestamp
let lastTwoSteepingTimeSeconds: number[] = [type.steepingTime.total({ unit: "seconds" })]
for (let i = 0; i < numberOfBrewingEvents; i++) {
brewingEvents.push({
id: nanoid(),
typeOfTeaId: type.id,
timestamp: nextTimestamp,
})
if (random(0, 100) < 20) {
let newSteepingTimeSeconds: number
const direction = random(0, 1) === 1 ? "increase" : "decrease"
const currentSeconds = lastTwoSteepingTimeSeconds[0]
if (lastTwoSteepingTimeSeconds.length === 1) {
newSteepingTimeSeconds = direction === "increase" ? currentSeconds + 30 : currentSeconds - 30
} else {
const lastDelta = lastTwoSteepingTimeSeconds[1] - lastTwoSteepingTimeSeconds[0]
const lastDirection = lastDelta > 0 ? "increase" : "decrease"
if (direction === lastDirection) {
newSteepingTimeSeconds = direction === "increase" ? currentSeconds + 30 : currentSeconds - 30
} else {
newSteepingTimeSeconds = Math.round(Math.abs(lastTwoSteepingTimeSeconds[0] - lastTwoSteepingTimeSeconds[1]) / 2)
}
}
steepingTimeChanges.push({
id: nanoid(),
typeOfTeaId: type.id,
timestamp: nextTimestamp.add({ hours: random(0, 1), minutes: random(0, 30) }),
newValue: Temporal.Duration.from({ seconds: newSteepingTimeSeconds })
})
}
nextTimestamp = nextTimestamp.add(Temporal.Duration.from({ hours: random(0, 14 * 24), minutes: random(0, 60) }))
}
}
brewingEvents.sort((a, b) => Temporal.Instant.compare(a.timestamp, b.timestamp))
steepingTimeChanges.sort((a, b) => Temporal.Instant.compare(a.timestamp, b.timestamp))
export const fakeServerState: {
configuration: Configuration
typesOfTea: TypeOfTea[]
steepingTimeChanges: SteepingTimeChange[]
brewingEvents: BrewingEvent[]
} = {
configuration,
typesOfTea,
steepingTimeChanges,
brewingEvents
}

View file

@ -19,5 +19,13 @@ export default defineConfig({
alias: {
"@": resolve(__dirname, "./src")
}
},
server: {
proxy: {
"/api": {
target: "http://localhost:8000",
ws: true
}
}
}
})