Implement food creation, such as it is

This commit is contained in:
2024-06-12 00:56:52 +02:00
parent c1c821d703
commit 5ee56a98d0
8 changed files with 201 additions and 50 deletions

View File

@@ -64,8 +64,8 @@
"windows": [ "windows": [
{ {
"title": "Svelte-Tauri", "title": "Svelte-Tauri",
"width": 900, "width": 1920,
"height": 600, "height": 1080,
"fullscreen": false, "fullscreen": false,
"transparent": true, "transparent": true,
"decorations": false "decorations": false

View File

@@ -1,29 +1,16 @@
<script lang="ts"> <script lang="ts">
import { mode, ModeWatcher } from 'mode-watcher' import { mode, ModeWatcher } from 'mode-watcher'
import { Toaster } from 'svelte-sonner' import { Toaster } from 'svelte-sonner'
import Header from '$components/Header.svelte'
import { onMount } from 'svelte' import Router from '$router/Router.svelte'
import { type Food, FoodService } from '$lib/database/food'
let food: Food[] = []
onMount(async () => {
food = await FoodService.GetAll()
})
</script> </script>
<ModeWatcher defaultMode="dark" /> <ModeWatcher defaultMode="dark" />
<Toaster theme={$mode} /> <Toaster theme={$mode} />
<div class="relative flex flex-col h-screen" data-vaul-drawer-wrapper id="page"> <template>
<div> <Header />
<pre> <main class="flex-1">
{#each food as f} <Router />
{f.amount} </main>
{/each} </template>
</pre>
</div>
<!-- <Header />-->
<!-- <main class="flex-1">-->
<!-- <Router />-->
<!-- </main>-->
</div>

View File

@@ -0,0 +1,61 @@
<script lang="ts">
import { type Food, FoodService } from '$lib/database/food'
import { toast } from 'svelte-sonner'
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
let item: Food = {
food: '',
amount: 0,
description: ''
}
let name: string = ''
let amount: string = ''
let description: string = ''
async function update(event: KeyboardEvent & { currentTarget: (EventTarget & HTMLTableCellElement) }) {
if (event.key == 'Enter') {
item.food = name.trim()
item.amount = parseInt(amount.trim())
item.description = description.trim()
const [food, err] = await FoodService.Create(item)
name = ''
amount = ''
description = ''
if (err) {
toast.error(err)
return
}
dispatch('created', food)
}
}
</script>
<template>
<tr class="border-b border-gray-200 dark:border-gray-700">
<th class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800"
scope="row">
</th>
<td class="px-6 py-4"
bind:innerText={name}
contenteditable="true"
on:keyup={update}>
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800"
bind:innerText={description}
contenteditable="true"
on:keyup={update}>
</td>
<td class="px-6 py-4"
bind:innerText={amount}
contenteditable="true"
on:keyup={update}>
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
</td>
<td class="px-6 py-4">
</td>
</tr>
</template>

View File

@@ -0,0 +1,31 @@
<script lang="ts">
import type { Food } from '$lib/database/food'
export let item: Food
console.log(item)
</script>
<template>
<tr class="border-b border-gray-200 dark:border-gray-700">
<th scope="row"
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap bg-gray-50 dark:text-white dark:bg-gray-800">
{item.date}
</th>
<td class="px-6 py-4">
{item.food}
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
{item.description}
</td>
<td class="px-6 py-4">
{item.amount}
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
{item.per100}
</td>
<td class="px-6 py-4">
{item.energy}
</td>
</tr>
</template>

View File

@@ -1,18 +1,44 @@
import { db } from '$lib/database' import { db } from '$lib/database'
import type { Err } from '$lib/types'
export type Food = { export type Food = {
rowid: number, rowid?: number,
date?: Date,
food: string, food: string,
description?: string,
amount: number, amount: number,
per100: number, per100?: number,
energy: number, energy?: number,
} }
const columns = ['rowid', 'date', 'food', 'description', 'amount', 'per100', 'energy']
const FoodService = { const FoodService = {
async GetAll() { async GetAll() {
return await db.select<Food[]>('SELECT rowid, food, amount, per100, energy FROM food ORDER BY date DESC') return await db.select<Food[]>(`
select ${columns.join(', ')}
from food
order by date desc
`)
}, },
async SetAll(data: Food[]) { async GetAllForDate(date: Date) {
return await db.select<Food[]>(`
select ${columns.join(', ')}
from food
where strftime('%Y-%m-%d', date) = strftime('%Y-%m-%d', '2024-06-12')
or strftime('%Y-%m-%d', date) = strftime('%Y-%m-%d', date('2024-06-12', '-1 day'))
order by date DESC;
`, [date])
},
// TODO: Rework this to use Err in Go style
async Create(food: Food): Promise<[Food, Err]> {
if (!food.food) return [food, 'food.food is required']
if (!food.amount) throw [food, 'food.amount is required']
const res = await db.execute(`insert into food (food, description, amount) values ($1, $2, $3)`, [food.food, food.description, food.amount])
const row = await db.select<Food>(`select ${columns.join(', ')} from food where rowid = $1`, [res.lastInsertId])
return [row, null]
} }
} }

View File

@@ -8,20 +8,22 @@ declare global {
} }
// Function avoids 'window not defined' in SSR // Function avoids 'window not defined' in SSR
const invoke = () => window.__TAURI_INVOKE__ const invoke = () => window.__TAURI_INVOKE__;
export function helloTauri() { export function helloTauri() {
return invoke()<string>('hello_tauri') return invoke()<string>("hello_tauri")
} }
export function hash256sum(hashInput: string) { export function hash256sum(hashInput: string) {
return invoke()<string>('hash256sum', { hashInput }) return invoke()<string>("hash256sum", { hashInput })
} }
export function storeSetKey(key: string, value: string) { export function storeSetKey(key: string, value: string) {
return invoke()<null>('store_set_key', { key, value }) return invoke()<null>("store_set_key", { key,value })
} }
export function storeReadKey(key: string) { export function storeReadKey(key: string) {
return invoke()<string | null>('store_read_key', { key }) return invoke()<string | null>("store_read_key", { key })
} }

View File

@@ -1,14 +1,56 @@
<section class="h-full flex-col flex items-center justify-center gap-y-8"> <script lang="ts">
<h1 class="text-6xl">Welcome</h1> import { onMount } from 'svelte'
<h2 class="flex items-center text-3xl [&_img]:h-12"> import { type Food, FoodService } from '$lib/database/food'
This is a &#160 import FoodComp from '$components/FoodComp.svelte'
<span> import EmptyFoodComp from '$components/EmptyFoodComp.svelte'
<img alt="svelte logo" src="/svelte_logo.svg" />
</span> let food: Food[] = []
&#160-&#160 onMount(async () => {
<span> food = await FoodService.GetAllForDate(new Date());
<img alt="svelte logo" src="/tauri_logo.svg" /> })
</span>
&#160 Template function newFood(event: CustomEvent<Food>) {
</h2> console.log(event)
</section> food.push(event.detail)
food = food
}
</script>
<template>
<div class="relative flex flex-col h-screen" data-vaul-drawer-wrapper id="page">
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
Date
</th>
<th scope="col" class="px-6 py-3">
Food
</th>
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
Description
</th>
<th scope="col" class="px-6 py-3">
Amount
</th>
<th scope="col" class="px-6 py-3 bg-gray-50 dark:bg-gray-800">
Cal Per 100
</th>
<th scope="col" class="px-6 py-3">
Energy
</th>
</tr>
</thead>
<tbody>
<EmptyFoodComp on:created={newFood}/>
{#each food as f}
<FoodComp item="{f}" />
{/each}
</tbody>
</table>
</div>
<div>
</div>
</div>
</template>

View File

@@ -1,2 +1,4 @@
export const themes = ['dark', 'light'] as const export const themes = ['dark', 'light'] as const
export type Theme = (typeof themes)[number] export type Theme = (typeof themes)[number]
export type Err = string | null