+
+
+
\ No newline at end of file
diff --git a/client/src/components/TableRow.vue b/client/src/components/TableRow.vue
new file mode 100644
index 0000000..840f0d4
--- /dev/null
+++ b/client/src/components/TableRow.vue
@@ -0,0 +1,18 @@
+
+
+
{{dateString()}}
+
{{tick.name}}
+
+
+
+
diff --git a/client/src/components/TickComponent.vue b/client/src/components/TickComponent.vue
new file mode 100644
index 0000000..fee8be8
--- /dev/null
+++ b/client/src/components/TickComponent.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/client/src/error.ts b/client/src/error.ts
new file mode 100644
index 0000000..5f2ab1a
--- /dev/null
+++ b/client/src/error.ts
@@ -0,0 +1,6 @@
+
+export const error = console.error
+
+export function handleError(message: string): any {
+ return (...args: any) => error(message, ...args)
+}
\ No newline at end of file
diff --git a/client/src/ticks.ts b/client/src/ticks.ts
new file mode 100644
index 0000000..1cd3e34
--- /dev/null
+++ b/client/src/ticks.ts
@@ -0,0 +1,65 @@
+interface ITick {
+ id: number
+ track_id?: number
+ year?: number
+ month?: number
+ day?: number
+ hour?: number
+ minute?: number
+ second?: number
+ has_time_info?: number
+}
+
+class Tick implements ITick {
+ id: number
+ track_id?: number
+ year?: number
+ month?: number
+ day?: number
+ hour?: number
+ minute?: number
+ second?: number
+ has_time_info?: number
+
+ constructor(id: number,
+ track_id?: number,
+ year?: number,
+ month?: number,
+ day?: number,
+ hour?: number,
+ minute?: number,
+ second?: number,
+ has_time_info?: number,
+ ) {
+ this.id = id
+ this.track_id = track_id
+ this.year = year
+ this.month = month
+ this.day = day
+ this.hour = hour
+ this.minute = minute
+ this.second = second
+ this.has_time_info = has_time_info
+ }
+
+ static fromJSON(tick: ITick): Tick {
+ return new Tick(
+ tick.id,
+ tick.track_id,
+ tick.year,
+ tick.month,
+ tick.day,
+ tick.hour,
+ tick.minute,
+ tick.second,
+ tick.has_time_info,
+ )
+ }
+
+ date(): Date | null {
+ if (this.year && this.month && this.day && this.hour && this.minute && this.second) {
+ return null
+ }
+ return new Date(this.year!, this.month!, this.day, this.hour, this.minute, this.second)
+ }
+}
diff --git a/client/src/track.ts b/client/src/track.ts
new file mode 100644
index 0000000..4ce889d
--- /dev/null
+++ b/client/src/track.ts
@@ -0,0 +1,100 @@
+import { error } from "./error"
+
+export interface ITrack {
+ id: number
+ name: String
+ description: String
+ icon: String
+ enabled: number
+ multiple_entries_per_day?: number
+ color?: number
+ order?: number
+ ticks?: Array
+}
+
+export class Track implements ITrack {
+ id: number
+ name: String
+ description: String
+ icon: String
+ enabled: number
+ multiple_entries_per_day?: number
+ color?: number
+ order?: number
+ ticks?: Array
+
+ constructor(
+ id: number,
+ name: String,
+ description: String,
+ icon: String,
+ enabled: number,
+ multiple_entries_per_day?: number,
+ color?: number,
+ order?: number,
+ ticks?: Array
+ ) {
+ this.id = id
+ this.name = name
+ this.description = description
+ this.icon = icon
+ this.enabled = enabled
+ this.multiple_entries_per_day = multiple_entries_per_day
+ this.color = color
+ this.order = order
+ this.ticks = ticks?.map(tick => Tick.fromJSON(tick))
+ this.isSetOn = this.isSetOn.bind(this)
+ this.fetchTicks = this.fetchTicks.bind(this)
+ }
+
+ static fromJSON(track: ITrack): Track {
+ return new Track(track.id, track.name, track.description, track.icon, track.enabled, track.multiple_entries_per_day, track.color, track.order)
+ }
+
+ isSetOn(date: Date): boolean {
+ for (var tick of (this.ticks ?? [])) {
+ if (
+ date.getUTCFullYear() == tick.year &&
+ date.getUTCMonth() == tick.month &&
+ date.getDate() == tick.day
+ ) return true
+ }
+ return false
+ }
+
+ async fetchTicks(): Promise