From 4e5fa5d42ed4198d3f922cd7b29af536bb7be0ab Mon Sep 17 00:00:00 2001 From: Ned Halksworth Date: Wed, 27 May 2026 19:10:57 +0100 Subject: [PATCH] fix: fix fact the app stopped working for goodness sake --- src/App.tsx | 355 +++++++++---------------------- src/components/LegalFootnote.tsx | 35 +++ src/index.css | 135 ++++++++++-- src/lib/appwrite.ts | 1 + src/types.ts | 20 ++ 5 files changed, 280 insertions(+), 266 deletions(-) create mode 100644 src/components/LegalFootnote.tsx diff --git a/src/App.tsx b/src/App.tsx index 7024628..6ca5d6b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,13 +2,11 @@ import type { Models } from "appwrite"; import { Activity, AlertTriangle, - Brain, CalendarDays, Camera, ChevronRight, Cloud, Command, - Database, Edit3, FileJson, FileSpreadsheet, @@ -16,19 +14,15 @@ import { Home, LineChart, Loader2, - Lock, LogIn, LogOut, Plus, PoundSterling, RefreshCcw, RotateCcw, - Send, Search, Settings2, - ShieldCheck, Sparkles, - Square, TimerReset, Trash2, Upload, @@ -86,6 +80,7 @@ import { } from "./lib/appwriteEntries"; import { BarcodeScannerModal } from "./components/BarcodeScannerModal"; import { DailyLimitsCard } from "./components/DailyLimitsCard"; +import { LegalFootnote } from "./components/LegalFootnote"; import { LimitsSettingsForm } from "./components/LimitsSettingsForm"; import { OnboardingScreen } from "./components/OnboardingScreen"; import { buildDynamicGreeting } from "./lib/greeting"; @@ -123,16 +118,21 @@ import { wholeNumber, } from "./lib/metrics"; import { exportPayload, parseImport } from "./lib/storage"; -import type { CoachChat, CoachMessage, DateFilter, EntryDraft, Filters, Flavour, ImportPreview, RedBullEntry } from "./types"; +import type { + DateFilter, + EntryDraft, + Filters, + Flavour, + ImportPreview, + LimitCheckResult, + RedBullEntry, + UserLimits, +} from "./types"; type AppView = "overview" | "logbook" | "trends" | "settings"; type AuthMode = "login" | "signup"; type AuthUser = Models.User; type SetupStatus = { state: "checking" | "ok" | "error"; message: string }; -type OllamaStreamChunk = { error?: string; message?: { content?: string; thinking?: string } }; -const OLLAMA_MODEL = "deepseek-v4-pro:cloud"; -const OLLAMA_PROXY_URL = import.meta.env.VITE_OLLAMA_PROXY_URL?.trim() || "/api/ollama-chat"; - type ForecastPoint = { label: string; current: number; @@ -140,6 +140,21 @@ type ForecastPoint = { limit?: number; }; +type PendingLimitAction = { + kind: "save" | "quick"; + draft: EntryDraft; + editingId?: string; + quickLabel?: string; +}; + +const MATERIAL_ACCENTS = { + primary: "var(--chart-primary)", + secondary: "var(--chart-secondary)", + tertiary: "var(--chart-tertiary)", + error: "var(--chart-error)", + custom: "#b85d84", +}; + const DEFAULT_FILTERS: Filters = { flavour: "all", dateRange: "all", @@ -379,7 +394,7 @@ function App() { setIsEntryModalOpen(true); } - async function saveEntry(draft: EntryDraft) { + async function saveUserLimits(next: UserLimits) { if (!user) return; setBusyAction("save-limits"); setSyncError(""); @@ -433,9 +448,9 @@ function App() { ? await updateEntry(user.$id, editing.id, { ...action.draft, source: editing.source }) : await createEntry(user.$id, { ...action.draft, source: action.draft.source ?? "manual" }); setEntries((current) => - sortEntries(editingEntry ? current.map((entry) => (entry.id === saved.id ? saved : entry)) : [saved, ...current]), + sortEntries(editing ? current.map((entry) => (entry.id === saved.id ? saved : entry)) : [saved, ...current]), ); - setNotice(editingEntry ? "Entry updated in Appwrite." : "Entry saved to Appwrite."); + setNotice(editing ? "Entry updated in Appwrite." : "Entry saved to Appwrite."); setEditingEntry(null); setEntryInitialDraft(null); setIsEntryModalOpen(false); @@ -481,16 +496,12 @@ function App() { source: "quick-add", }; - setActionLoading(`quick-${item.label}`); - setDataError(""); - try { - const saved = await createEntry(user.$id, draft); - setEntries((current) => sortEntries([saved, ...current])); - setNotice(`${item.label} saved to Appwrite.`); - } catch (error) { - setDataError(appwriteErrorMessage(error)); - } finally { - setActionLoading(null); + const check = evaluateLimits(userLimits, entries, { draft }); + if (check.violations.length) { + setPendingLimitAction({ kind: "quick", draft, quickLabel: item.label }); + setLimitConfirmMessage(limitStatusMessage(check.violations, check, userLimits)); + setLimitConfirmOpen(true); + return; } void saveDraft({ kind: "quick", draft, quickLabel: item.label }); @@ -664,7 +675,7 @@ function App() { -
+
setActiveView("settings")} /> -
- - +
{activeView === "overview" && ( setActiveView("logbook")} + onOpenSettings={() => setActiveView("settings")} /> )} @@ -744,7 +753,9 @@ function App() { entries={entriesInView} filters={filters} flavours={allFlavours} + userLimits={userLimits} onFilterChange={setFilters} + onSaveLimits={(next) => void saveUserLimits(next)} /> )} @@ -777,14 +788,14 @@ function App() {
+ + { setIsEntryModalOpen(false); setEditingEntry(null); @@ -957,6 +968,7 @@ function AuthView({ +
@@ -1028,7 +1040,7 @@ function Sidebar({ onOpenSettings: () => void; }) { return ( -