Files
calorie-counter/frontend/src/lib/components/Energy/EmptyFoodComp.svelte

175 lines
4.6 KiB
Svelte

<script lang="ts">
import { toast } from "svelte-sonner";
import { main } from "$wails/models";
import { CreateFood, GetLastPer100 } from "$wails/main/App";
import { foodStore } from "$lib/store/Energy/foodStore";
import FoodSearchEntry from "./FoodSearchEntry.svelte";
let item: main.Food = {
food: "",
amount: 0,
description: "",
rowid: 0,
date: "",
per100: 0,
energy: 0,
};
let name: string = "";
let amount: string = "";
let description: string = "";
let per100: string = "";
let per100Edited: boolean = false;
let per100Element: HTMLTableCellElement;
let nameElement: HTMLTableCellElement;
let autocompleteList: HTMLUListElement;
let foodSearch: main.Food[] = [];
// Maybe it would be a good idea to use $ instead of update down there...
// Maybe it's a topic for another day
$: {
name = name.trim();
if (!name) {
foodSearch = [];
} else {
updateAutocomplete();
}
}
function updateAutocomplete() {
if (!per100Edited)
GetLastPer100(name.trim()).then((res) => {
// Prevent search when there's nothing to search
// Sometimes we get search results after deleting name
if (res.success && res.data && name) {
foodSearch = res.data;
} else {
foodSearch = [];
}
});
}
async function update(event: KeyboardEvent & { currentTarget: EventTarget & HTMLTableCellElement }) {
name = name.trim();
amount = amount.trim();
description = description.trim();
per100 = per100.trim();
if (!name) {
foodSearch = [];
return;
}
if (!per100Edited && event.currentTarget == per100Element) per100Edited = true;
if (event.key == "Enter") {
event.preventDefault();
item.food = name;
item.description = description;
item.amount = parseInt(amount);
item.per100 = parseInt(per100);
const res = await CreateFood(item);
name = "";
amount = "";
// description = ''
per100 = "";
per100Edited = false;
if (!res.success) {
toast.error(`failed to create item with error ${res.error}`);
return;
}
foodStore.update((value) => [res.data, ...value]);
nameElement.focus();
foodSearch = [];
}
}
let hiLiteIndex: number | null = null;
// function navigateList(e: KeyboardEvent) {
// console.log(foodSearch, hiLiteIndex);
// // @ts-ignore shut the fuck up
// if (e.key == "ArrowDown" && hiLiteIndex <= foodSearch.length - 2) {
// hiLiteIndex == null ? (hiLiteIndex = 0) : (hiLiteIndex += 1);
// } else if (e.key == "ArrowUp" && hiLiteIndex !== null) {
// hiLiteIndex == 0 ? 0 : (hiLiteIndex -= 1);
// } else if (e.key == "Enter") {
// // @ts-ignore ITS NOT NULL YOU ASSHAT
// // WE CHECKED
// // ITS NOT
// setInputVal(foodSearch[hiLiteIndex]);
// } else {
// return;
// }
// }
function setInputVal(food: main.Food) {
name = food.food;
per100 = String(food.per100);
hiLiteIndex = null;
foodSearch = [];
}
$: {
if (nameElement && autocompleteList) {
const { top, left, height } = nameElement.getBoundingClientRect();
autocompleteList.style.top = `${top + height}px`;
autocompleteList.style.left = `${left}px`;
}
}
</script>
<!-- <svelte:window on:keydown={navigateList} /> -->
<template>
<tr class="border-b border-gray-200 dark:border-gray-700 text-lg font-bold relative">
<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>
<!-- svelte-ignore a11y-autofocus -->
<td
bind:innerText={name}
class:border-[3px]={!name}
class:border-red-600={!name}
class="px-6 py-4 overflow-hidden"
contenteditable="true"
autofocus
on:keydown={update}
on:focusin={updateAutocomplete}
on:focusout={() => foodSearch = []}
bind:this={nameElement}
/>
<td
bind:innerText={description}
class="px-6 py-4 bg-gray-50 dark:bg-gray-800 overflow-hidden"
contenteditable="true"
on:keydown={update}
/>
<td
bind:innerText={amount}
class:border-[3px]={!amount}
class:border-red-600={!amount}
class="px-6 py-4 overflow-hidden"
contenteditable="true"
on:keydown={update}
/>
<td
bind:this={per100Element}
bind:innerText={per100}
class="px-6 py-4 bg-gray-50 dark:bg-gray-800 overflow-hidden"
class:border-[3px]={!per100}
class:border-orange-600={!per100}
contenteditable="true"
on:keydown={update}
/>
</tr>
{#if foodSearch.length > 0}
<ul bind:this={autocompleteList} class="z-50 fixed top-0 left-0 w-3/12 border border-x-gray-800">
{#each foodSearch as f, i}
<FoodSearchEntry itemLabel={f.food} highlighted={i == hiLiteIndex} on:click={() => setInputVal(f)} />
{/each}
</ul>
{/if}
</template>