Add routes for daily weekly and the rest

This commit is contained in:
2024-08-09 22:32:58 +02:00
parent 8119775084
commit fce5b8416e
19 changed files with 472 additions and 27 deletions

29
app.go
View File

@@ -51,6 +51,35 @@ func (a *App) GetLastPer100(name string) WailsPer100 {
return WailsPer100{Data: data, Success: true} return WailsPer100{Data: data, Success: true}
} }
func (a *App) GetDailyFood() WailsAggregateFood {
data, err := foodService.GetDaily()
if err != nil {
return WailsAggregateFood{Success: false, Error: err.Error()}
}
return WailsAggregateFood{Data: data, Success: true}
}
func (a *App) GetWeeklyFood() WailsAggregateFood {
data, err := foodService.GetWeekly()
if err != nil {
return WailsAggregateFood{Success: false, Error: err.Error()}
}
return WailsAggregateFood{Data: data, Success: true}
}
func (a *App) GetMonthlyFood() WailsAggregateFood {
data, err := foodService.GetMonthly()
if err != nil {
return WailsAggregateFood{Success: false, Error: err.Error()}
}
return WailsAggregateFood{Data: data, Success: true}
}
func (a *App) GetYearlyFood() WailsAggregateFood {
data, err := foodService.GetYearly()
if err != nil {
return WailsAggregateFood{Success: false, Error: err.Error()}
}
return WailsAggregateFood{Data: data, Success: true}
}
// region settings // region settings
func (a *App) GetSettings() settings { func (a *App) GetSettings() settings {
return Settings return Settings

View File

@@ -0,0 +1,23 @@
<script lang="ts">
import type { AggregatedFood } from '$lib/database/food'
export let item: AggregatedFood
</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">
{item.period}
</th>
<td class="px-6 py-4">
{item.amount}
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
{item.avgPer100}
</td>
<td class="px-6 py-4">
{item.energy}
</td>
</tr>
</template>

View File

@@ -0,0 +1,118 @@
<script lang="ts">
import { Line } from 'svelte-chartjs'
import type { AggregatedFood } from '$lib/database/food'
import AggregatedFoodComp from '$components/Energy/AggregatedFood/AggregatedFoodComp.svelte'
import type { ChartData, Point } from 'chart.js'
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip
} from 'chart.js'
ChartJS.register(
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale
)
export let items: AggregatedFood[] = []
export let energyTarget: number = 2000
export let energyLimit: number = 2500
let reversedItems = items.slice().reverse()
const defaultOptions = {
backgroundColor: 'rgba(225, 204,230, .3)',
borderColor: 'rgb(205, 130, 158)',
pointBorderColor: 'rgb(205, 130, 158)',
pointBackgroundColor: 'rgb(255, 255, 255)',
pointBorderWidth: 10,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgb(0, 157, 123)',
pointHoverBorderColor: 'rgba(220, 220, 220, 1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10
}
const data: ChartData<'line', (number | Point)[]> = {
labels: reversedItems.map(f => f.period),
datasets: [
{
...defaultOptions,
label: 'Amount',
data: reversedItems.map(f => f.amount),
borderColor: '#ff4dff',
pointBorderColor: '#ff4dff',
},
{
...defaultOptions,
label: 'AvgPer100',
data: reversedItems.map(f => f.avgPer100),
borderColor: '#ffb84d',
pointBorderColor: '#ffb84d',
},
{
...defaultOptions,
label: 'Energy',
data: reversedItems.map(f => f.energy),
borderColor: '#b8ff4d',
pointBorderColor: '#b8ff4d',
},
{
...defaultOptions,
label: 'Target',
data: reversedItems.map(f => energyTarget),
borderColor: '#00ff00',
pointBorderColor: '#00ff00',
},
{
...defaultOptions,
label: 'Limit',
data: reversedItems.map(f => energyLimit),
borderColor: '#ff0000',
pointBorderColor: '#ff0000',
}
]
}
</script>
<template>
<Line data="{data}" class="max-h-[50vh] h-[50vh]" />
<div class="relative flex flex-col h-[43vh]" 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 class="px-6 py-3 bg-gray-50 dark:bg-gray-800 w-2/12" scope="col">
Period
</th>
<th class="px-6 py-3" scope="col">
Amount
</th>
<th class="px-6 py-3 bg-gray-50 dark:bg-gray-800" scope="col">
AvgPer100
</th>
<th class="px-6 py-3" scope="col">
Energy
</th>
</tr>
</thead>
<tbody>
{#each items as f}
<AggregatedFoodComp item="{f}" />
{/each}
</tbody>
</table>
</div>
<div>
</div>
</div>
</template>

View File

@@ -2,7 +2,7 @@
import { toast } from "svelte-sonner"; import { toast } from "svelte-sonner";
import { main } from "$wails/models"; import { main } from "$wails/models";
import { CreateFood, GetLastPer100 } from "$wails/main/App"; import { CreateFood, GetLastPer100 } from "$wails/main/App";
import { foodStore } from "$lib/store/FoodStore"; import { foodStore } from "$lib/store/Energy/foodStore";
let item: main.Food = { let item: main.Food = {
food: "", food: "",

View File

@@ -1,9 +1,17 @@
<script lang="ts"> <script lang="ts">
import Router from 'svelte-spa-router' import Router from 'svelte-spa-router'
import Energy from '$lib/components/Energy/Energy.svelte' import Energy from './routes/Energy.svelte'
import Daily from './routes/Daily.svelte'
import Weekly from './routes/Weekly.svelte'
import Monthly from './routes/Monthly.svelte'
import Yearly from './routes/Yearly.svelte'
const routes = { const routes = {
'/': Energy, '/': Energy,
'/Energy/daily': Daily,
'/Energy/weekly': Weekly,
'/Energy/monthly': Monthly,
'/Energy/yearly': Yearly,
} }
</script> </script>

View File

@@ -0,0 +1,8 @@
<script lang="ts">
import AggregatedFoodTable from '$components/Energy/AggregatedFood/AggregatedFoodTable.svelte'
import { dailyFoodStore } from '$lib/store/Energy/dailyFoodStore'
</script>
<template>
<AggregatedFoodTable items="{$dailyFoodStore}" />
</template>

View File

@@ -1,24 +1,24 @@
<script lang="ts"> <script lang="ts">
import { foodStore } from "$lib/store/FoodStore"; import { foodStore } from "$lib/store/Energy/foodStore";
import FoodTable from "./Food/FoodTable.svelte"; import FoodTable from "$lib/components/Energy/Food/FoodTable.svelte";
// Fuck this hacky shit // Fuck this hacky shit
// Svelte won't re-render FoodTable when using the store directly // Svelte won't re-render FoodTable when using the store directly
// It won't do it when using a variable and subscribing to the store // It won't do it when using a variable and subscribing to the store
// It won't do it when reassigning the store // It won't do it when reassigning the store
// Not when pushing unshifting the store // Not when pushing unshifting the store
// This is the only thing that works // This is the only thing that works
// Hacky ass shit // Hacky ass shit
let forceUpdate = false; let forceUpdate = false;
foodStore.subscribe(() => { foodStore.subscribe(() => {
forceUpdate = !forceUpdate; forceUpdate = !forceUpdate;
}); });
</script> </script>
<template> <template>
{#if forceUpdate} {#if forceUpdate}
<FoodTable items={$foodStore} /> <FoodTable items={$foodStore} />
{:else} {:else}
<FoodTable items={$foodStore} /> <FoodTable items={$foodStore} />
{/if} {/if}
</template> </template>

View File

@@ -0,0 +1,8 @@
<script lang="ts">
import AggregatedFoodTable from '$components/Energy/AggregatedFood/AggregatedFoodTable.svelte'
import { monthlyFoodStore } from '$lib/store/Energy/monthlyFoodStore'
</script>
<template>
<AggregatedFoodTable items="{$monthlyFoodStore}" />
</template>

View File

@@ -0,0 +1,8 @@
<script lang="ts">
import AggregatedFoodTable from '$components/Energy/AggregatedFood/AggregatedFoodTable.svelte'
import { weeklyFoodStore } from '$lib/store/Energy/weeklyFoodStore'
</script>
<template>
<AggregatedFoodTable items="{$weeklyFoodStore}" />
</template>

View File

@@ -0,0 +1,8 @@
<script lang="ts">
import AggregatedFoodTable from '$components/Energy/AggregatedFood/AggregatedFoodTable.svelte'
import { yearlyFoodStore } from '$lib/store/Energy/yearlyFoodStore'
</script>
<template>
<AggregatedFoodTable items="{$yearlyFoodStore}" />
</template>

View File

@@ -0,0 +1,39 @@
import { type Writable, writable } from "svelte/store";
import { main } from "$wails/models";
import { GetDailyFood } from "$wails/main/App";
import { toast } from "svelte-sonner";
import { settingsStore } from "../SettingsStore";
async function createStore(): Promise<Writable<main.AggregatedFood[]>> {
let foods: main.AggregatedFood[] = [];
let res: main.WailsAggregateFood = await GetDailyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
} else {
foods = res.data;
}
const { subscribe, update, set } = writable(foods);
return {
subscribe,
update,
set,
// @ts-ignore
refresh: async () => {
const res = await GetDailyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
return;
}
set(res.data);
},
};
}
const dailyFoodStore = await createStore();
settingsStore.subscribe((settings) => {
// @ts-ignore
dailyFoodStore.refresh();
});
export { dailyFoodStore };

View File

@@ -2,7 +2,7 @@ import { type Writable, writable } from "svelte/store";
import { main } from "$wails/models"; import { main } from "$wails/models";
import { GetFood } from "$wails/main/App"; import { GetFood } from "$wails/main/App";
import { toast } from "svelte-sonner"; import { toast } from "svelte-sonner";
import { settingsStore } from "./SettingsStore"; import { settingsStore } from "../SettingsStore";
async function createStore(): Promise<Writable<main.Food[]>> { async function createStore(): Promise<Writable<main.Food[]>> {
let foods: main.Food[] = []; let foods: main.Food[] = [];

View File

@@ -0,0 +1,39 @@
import { type Writable, writable } from "svelte/store";
import { main } from "$wails/models";
import { GetMonthlyFood } from "$wails/main/App";
import { toast } from "svelte-sonner";
import { settingsStore } from "../SettingsStore";
async function createStore(): Promise<Writable<main.AggregatedFood[]>> {
let foods: main.AggregatedFood[] = [];
let res: main.WailsAggregateFood = await GetMonthlyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
} else {
foods = res.data;
}
const { subscribe, update, set } = writable(foods);
return {
subscribe,
update,
set,
// @ts-ignore
refresh: async () => {
const res = await GetMonthlyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
return;
}
set(res.data);
},
};
}
const monthlyFoodStore = await createStore();
settingsStore.subscribe((settings) => {
// @ts-ignore
monthlyFoodStore.refresh();
});
export { monthlyFoodStore };

View File

@@ -0,0 +1,39 @@
import { type Writable, writable } from "svelte/store";
import { main } from "$wails/models";
import { GetWeeklyFood } from "$wails/main/App";
import { toast } from "svelte-sonner";
import { settingsStore } from "../SettingsStore";
async function createStore(): Promise<Writable<main.AggregatedFood[]>> {
let foods: main.AggregatedFood[] = [];
let res: main.WailsAggregateFood = await GetWeeklyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
} else {
foods = res.data;
}
const { subscribe, update, set } = writable(foods);
return {
subscribe,
update,
set,
// @ts-ignore
refresh: async () => {
const res = await GetWeeklyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
return;
}
set(res.data);
},
};
}
const weeklyFoodStore = await createStore();
settingsStore.subscribe((settings) => {
// @ts-ignore
weeklyFoodStore.refresh();
});
export { weeklyFoodStore };

View File

@@ -0,0 +1,39 @@
import { type Writable, writable } from "svelte/store";
import { main } from "$wails/models";
import { GetYearlyFood } from "$wails/main/App";
import { toast } from "svelte-sonner";
import { settingsStore } from "../SettingsStore";
async function createStore(): Promise<Writable<main.AggregatedFood[]>> {
let foods: main.AggregatedFood[] = [];
let res: main.WailsAggregateFood = await GetYearlyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
} else {
foods = res.data;
}
const { subscribe, update, set } = writable(foods);
return {
subscribe,
update,
set,
// @ts-ignore
refresh: async () => {
const res = await GetYearlyFood();
if (!res.success) {
toast.error(`Failed to get foods with error: ${res.error}`);
return;
}
set(res.data);
},
};
}
const yearlyFoodStore = await createStore();
settingsStore.subscribe((settings) => {
// @ts-ignore
yearlyFoodStore.refresh();
});
export { yearlyFoodStore };

View File

@@ -4,12 +4,20 @@ import {main} from '../models';
export function CreateFood(arg1:main.Food):Promise<main.WailsFood1>; export function CreateFood(arg1:main.Food):Promise<main.WailsFood1>;
export function GetDailyFood():Promise<main.WailsAggregateFood>;
export function GetFood():Promise<main.WailsFood>; export function GetFood():Promise<main.WailsFood>;
export function GetLastPer100(arg1:string):Promise<main.WailsPer100>; export function GetLastPer100(arg1:string):Promise<main.WailsPer100>;
export function GetMonthlyFood():Promise<main.WailsAggregateFood>;
export function GetSettings():Promise<main.settings>; export function GetSettings():Promise<main.settings>;
export function GetWeeklyFood():Promise<main.WailsAggregateFood>;
export function GetYearlyFood():Promise<main.WailsAggregateFood>;
export function SetSetting(arg1:string,arg2:number):Promise<main.WailsGenericAck>; export function SetSetting(arg1:string,arg2:number):Promise<main.WailsGenericAck>;
export function UpdateFood(arg1:main.Food):Promise<main.WailsFood1>; export function UpdateFood(arg1:main.Food):Promise<main.WailsFood1>;

View File

@@ -6,6 +6,10 @@ export function CreateFood(arg1) {
return window['go']['main']['App']['CreateFood'](arg1); return window['go']['main']['App']['CreateFood'](arg1);
} }
export function GetDailyFood() {
return window['go']['main']['App']['GetDailyFood']();
}
export function GetFood() { export function GetFood() {
return window['go']['main']['App']['GetFood'](); return window['go']['main']['App']['GetFood']();
} }
@@ -14,10 +18,22 @@ export function GetLastPer100(arg1) {
return window['go']['main']['App']['GetLastPer100'](arg1); return window['go']['main']['App']['GetLastPer100'](arg1);
} }
export function GetMonthlyFood() {
return window['go']['main']['App']['GetMonthlyFood']();
}
export function GetSettings() { export function GetSettings() {
return window['go']['main']['App']['GetSettings'](); return window['go']['main']['App']['GetSettings']();
} }
export function GetWeeklyFood() {
return window['go']['main']['App']['GetWeeklyFood']();
}
export function GetYearlyFood() {
return window['go']['main']['App']['GetYearlyFood']();
}
export function SetSetting(arg1, arg2) { export function SetSetting(arg1, arg2) {
return window['go']['main']['App']['SetSetting'](arg1, arg2); return window['go']['main']['App']['SetSetting'](arg1, arg2);
} }

View File

@@ -1,5 +1,23 @@
export namespace main { export namespace main {
export class AggregatedFood {
period: string;
amount: number;
avgPer100: number;
energy: number;
static createFrom(source: any = {}) {
return new AggregatedFood(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.period = source["period"];
this.amount = source["amount"];
this.avgPer100 = source["avgPer100"];
this.energy = source["energy"];
}
}
export class Food { export class Food {
rowid: number; rowid: number;
date: string; date: string;
@@ -24,6 +42,40 @@ export namespace main {
this.energy = source["energy"]; this.energy = source["energy"];
} }
} }
export class WailsAggregateFood {
data: AggregatedFood[];
success: boolean;
error?: string;
static createFrom(source: any = {}) {
return new WailsAggregateFood(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.data = this.convertValues(source["data"], AggregatedFood);
this.success = source["success"];
this.error = source["error"];
}
convertValues(a: any, classs: any, asMap: boolean = false): any {
if (!a) {
return a;
}
if (a.slice && a.map) {
return (a as any[]).map(elem => this.convertValues(elem, classs));
} else if ("object" === typeof a) {
if (asMap) {
for (const key of Object.keys(a)) {
a[key] = new classs(a[key]);
}
return a;
}
return new classs(a);
}
return a;
}
}
export class WailsFood { export class WailsFood {
data: Food[]; data: Food[];
success: boolean; success: boolean;
@@ -136,6 +188,7 @@ export namespace main {
weightMonthlyLookback: number; weightMonthlyLookback: number;
weightYearlyLookback: number; weightYearlyLookback: number;
target: number; target: number;
limit: number;
static createFrom(source: any = {}) { static createFrom(source: any = {}) {
return new settings(source); return new settings(source);
@@ -156,6 +209,7 @@ export namespace main {
this.weightMonthlyLookback = source["weightMonthlyLookback"]; this.weightMonthlyLookback = source["weightMonthlyLookback"];
this.weightYearlyLookback = source["weightYearlyLookback"]; this.weightYearlyLookback = source["weightYearlyLookback"];
this.target = source["target"]; this.target = source["target"];
this.limit = source["limit"];
} }
} }

View File

@@ -29,6 +29,7 @@ type settings struct {
WeightYearlyLookback int `default:"2" json:"weightYearlyLookback"` WeightYearlyLookback int `default:"2" json:"weightYearlyLookback"`
Target int `default:"2000" json:"target"` Target int `default:"2000" json:"target"`
Limit int `default:"2500" json:"limit"`
} }
var Settings settings var Settings settings