UI laid out and started

This commit is contained in:
D. Scott Boggs 2023-06-14 11:39:00 -04:00
parent 1438ab6d24
commit 441d3c28ec
7 changed files with 241 additions and 3 deletions

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import Table from "./components/Table.vue";
</script>
<template>
<button class="button is-info">Test, hello!</button>
<Table></Table>
</template>
<style scoped>
</style>
<style scoped></style>

View file

@ -0,0 +1,40 @@
<template>
<table class="table">
<thead>
<th>Date</th>
<th v-for="track in tracks" :key="track.id">{{ track.icon }}</th>
</thead>
<tbody>
<tr v-for="date in dates" :key="date.valueOf()">
<th>{{ dateString(date) }}</th>
<td v-for="track in tracks" :key="track.id">
<TickComponent :isSet="track.isSetOn(date)" />
</td>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Track } from '../track'
import TickComponent from "./TickComponent.vue";
const tracks = ref(new Array<Track>())
const today = new Date()
const ONE_DAY_MS = 86_400_000
// A list of the past 60 days
const dates = [...Array(60).keys()]
.map(n => new Date(today.valueOf() - (n * ONE_DAY_MS)))
console.log(dates)
// The date as a string like 2023-06-11
function dateString(date: Date) {
return date.toISOString().substring(0, 10)
}
Track.fetchAll().then(result => tracks.value = result)
</script>

View file

@ -0,0 +1,18 @@
<template>
<tr>
<td>{{dateString()}}</td>
<td v-for="tick in ticks" :key="tick.id">{{tick.name}}</td>
</tr>
</template>
<script setup lang="ts">
const props = defineProps<{date: Date}>();
const ticks = [{id: 1, name: 'test'}]
// The date as a string like 2023-06-11
function dateString() {
return props.date.toISOString().substring(0, 10)
}
</script>

View file

@ -0,0 +1,9 @@
<template>
<button :class="className()">{{ props.isSet ? "x" : "\u{A0}" }}</button>
</template>
<script setup lang="ts">
const props = defineProps<{ isSet: boolean }>()
const className = () => props.isSet ? "is-rounded is-info" : "is-rounded"
</script>

6
client/src/error.ts Normal file
View file

@ -0,0 +1,6 @@
export const error = console.error
export function handleError(message: string): any {
return (...args: any) => error(message, ...args)
}

65
client/src/ticks.ts Normal file
View file

@ -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)
}
}

100
client/src/track.ts Normal file
View file

@ -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<Tick>
}
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<Tick>
constructor(
id: number,
name: String,
description: String,
icon: String,
enabled: number,
multiple_entries_per_day?: number,
color?: number,
order?: number,
ticks?: Array<ITick>
) {
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<Track> {
const response = await fetch(`/api/v1/tracks/${this.id}/ticks`)
if (response.ok) {
this.ticks = await response.json()
} else {
throw new Error(`error fetching ticks: ${response.statusText} (${response.status})`)
}
return this
}
static async fetchAll(): Promise<Array<Track>> {
const result = await fetch('/api/v1/tracks')
if (result.ok) {
try {
const body = await result.text();
try {
const tracks = Array.prototype.map.call(JSON.parse(body), Track.fromJSON) as Array<Track>
return Promise.all(tracks.map((track: Track) => track.fetchTicks()))
} catch (e) {
console.error('error parsing body from JSON')
console.error(e)
console.debug(body)
}
} catch (err) {
console.error(err)
result.text()
.then(console.debug)
.catch(console.error)
}
} else {
error(`error fetching tracks: ${result.statusText} (${result.status})`)
}
return []
}
}