Add NewTrackView
This commit is contained in:
parent
c7cfa86be1
commit
678e95bba0
|
@ -1,7 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import NavBar from './components/NavBar.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterView />
|
||||
<div >
|
||||
<NavBar />
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
|
28
client/src/components/NavBar.vue
Normal file
28
client/src/components/NavBar.vue
Normal file
|
@ -0,0 +1,28 @@
|
|||
<script setup lang="ts">
|
||||
import { RouterLink } from 'vue-router';
|
||||
</script>
|
||||
<template>
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<h1 class="title navbar-item">Kalkutago</h1>
|
||||
</div>
|
||||
<div class="navbar-menu"></div>
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<div class="buttons">
|
||||
<RouterLink to="/" v-if="$route.path === '/new-track'">
|
||||
<button class="button is-info">
|
||||
Go Back
|
||||
</button>
|
||||
</RouterLink>
|
||||
|
||||
<RouterLink to="/new-track" v-else>
|
||||
<button class="button is-primary">
|
||||
Add Track
|
||||
</button>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
|
@ -2,7 +2,9 @@
|
|||
<table class="table">
|
||||
<thead>
|
||||
<th>Date</th>
|
||||
<th v-for="track in state.tracks" :key="track.id">{{ track.icon }}</th>
|
||||
<th v-for="track in state.tracks" :key="track.id">
|
||||
<TrackIcon :icon="track.icon" :id="track.id" />
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="date in dates" :key="date.valueOf()">
|
||||
|
@ -18,6 +20,7 @@
|
|||
<script setup lang="ts">
|
||||
import TickComponent from "./TickComponent.vue";
|
||||
import { state } from "../state";
|
||||
import TrackIcon from "./TrackIcon.vue";
|
||||
|
||||
const today = new Date()
|
||||
const ONE_DAY_MS = 86_400_000
|
||||
|
|
16
client/src/components/TrackIcon.vue
Normal file
16
client/src/components/TrackIcon.vue
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { state } from '../state';
|
||||
|
||||
const props = defineProps<{icon: String, id: number|undefined}>()
|
||||
|
||||
const del = () => {
|
||||
if(props.id)
|
||||
if(confirm("are you sure you want to delete this track?"))
|
||||
state.removeTrack(props.id)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div @click=del>
|
||||
{{props.icon}}
|
||||
</div>
|
||||
</template>
|
|
@ -1,10 +1,12 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import TableView from './views/TableView.vue'
|
||||
import NewTrackView from './views/NewTrackView.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{ path: '/', component: TableView }
|
||||
{ path: '/', component: TableView },
|
||||
{ path: '/new-track', component: NewTrackView }
|
||||
// for other pages:
|
||||
// {path: '/', component: import('./views/TableView.vue')}
|
||||
]
|
||||
|
|
|
@ -85,5 +85,18 @@ export const state = reactive({
|
|||
const { ok, status, statusText } = await fetch(`/api/v1/tracks/${track.id}/all-ticks?${query.toString()}`, { method: 'DELETE' })
|
||||
if (!ok)
|
||||
error(`error deleting ticks for ${track.id}: ${statusText} (${status})`)
|
||||
},
|
||||
async addTrack(track: Track) {
|
||||
const response = await fetch('/api/v1/tracks', {
|
||||
method: "POST",
|
||||
body: JSON.stringify(track),
|
||||
headers: { "Content-Type": "application/json" }
|
||||
})
|
||||
if (!response.ok)
|
||||
error(`error submitting track: ${track}: ${response.statusText} (${response.status})`)
|
||||
},
|
||||
async removeTrack(trackID: number) {
|
||||
const response = await fetch(`/api/v1/tracks/${trackID}`, { method: "DELETE" })
|
||||
if (!response.ok) error(`error deleting track with ID ${trackID}: ${response.statusText} (${response.status})`)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { error } from "./error"
|
||||
|
||||
export interface ITrack {
|
||||
id: number
|
||||
id?: number
|
||||
name: String
|
||||
description: String
|
||||
icon: String
|
||||
|
@ -13,7 +13,7 @@ export interface ITrack {
|
|||
}
|
||||
|
||||
export class Track implements ITrack {
|
||||
id: number
|
||||
id?: number
|
||||
name: String
|
||||
description: String
|
||||
icon: String
|
||||
|
@ -24,7 +24,7 @@ export class Track implements ITrack {
|
|||
ticks?: Array<Tick>
|
||||
|
||||
constructor(
|
||||
id: number,
|
||||
id: number | undefined,
|
||||
name: String,
|
||||
description: String,
|
||||
icon: String,
|
||||
|
|
88
client/src/views/NewTrackView.vue
Normal file
88
client/src/views/NewTrackView.vue
Normal file
|
@ -0,0 +1,88 @@
|
|||
<script setup lang="ts">
|
||||
import { RouterLink, useRouter } from 'vue-router';
|
||||
import { Track } from '../track';
|
||||
import { computed, ref } from 'vue';
|
||||
import { state } from '../state';
|
||||
|
||||
const props = defineProps<{initialState?: Track}>()
|
||||
const router = useRouter()
|
||||
|
||||
const name = ref(props.initialState?.name ?? "")
|
||||
const description = ref(props.initialState?.description?.toString() ?? "")
|
||||
const icon = ref(props.initialState?.icon ?? "")
|
||||
const enabled = ref(props.initialState?.enabled ?? true)
|
||||
const multipleEntriesPerDay = ref(props.initialState?.multiple_entries_per_day ?? false)
|
||||
const color = ref(props.initialState?.color ?? null)
|
||||
const order = ref(props.initialState?.order ?? null)
|
||||
|
||||
const submittingNow = ref(false)
|
||||
const submitButtonClass = computed(() => 'button is-primary' + (submittingNow.value ? ' is-loading' : ''))
|
||||
|
||||
const submit = async () => {
|
||||
submittingNow.value = true
|
||||
const track = new Track(undefined, name.value, description.value,
|
||||
icon.value, Number(enabled.value), Number(multipleEntriesPerDay.value),
|
||||
color.value, order.value)
|
||||
await state.addTrack(track)
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="section">
|
||||
<div class="field">
|
||||
<label for="name" class="label">Name</label>
|
||||
<div class="control">
|
||||
<input type="text" name="name" class="input" v-model="name"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="description" class="label">Description</label>
|
||||
<div class="control">
|
||||
<textarea name="description" cols="30" rows="5" v-model="description"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="icon" class="label">Icon</label>
|
||||
<div class="control">
|
||||
<input type="text" name="icon" class="input" v-model="icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<label for="enabled" class="label">
|
||||
<input type="checkbox" name="enabled" class="checkbox" v-model="enabled" />
|
||||
Enabled?
|
||||
</label>
|
||||
</div>
|
||||
<div class="control">
|
||||
<label for="multiple-entries" class="label">
|
||||
<input type="checkbox" name="multiple-entries" class="checkbox" v-model="multipleEntriesPerDay"/>
|
||||
Multiple Entries per Day?
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
TODO color choice
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label for="order" class="label">
|
||||
<input type="number" name="order" class="input" v-model="order"/>
|
||||
Order
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<RouterLink to="/">
|
||||
<button class="button is-danger">
|
||||
Cancel
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button :class="submitButtonClass" @click="submit">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
Loading…
Reference in a new issue