From 3fb4ec8b7b8c3d60751c08fbd5da6070218cb6b5 Mon Sep 17 00:00:00 2001 From: Dominic Zimmer Date: Sat, 3 May 2025 13:16:13 +0200 Subject: [PATCH] Finish prototype --- public/index.html | 2 +- server/file.json | 19 ++++--- server/server.js | 3 +- src/App.css | 81 ++++++++++++++++++---------- src/App.tsx | 131 +++++++++++++++++++++++++++++++++------------- src/api.ts | 14 +++-- 6 files changed, 172 insertions(+), 78 deletions(-) diff --git a/public/index.html b/public/index.html index aa069f2..5e1d247 100644 --- a/public/index.html +++ b/public/index.html @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + Shouldnthave diff --git a/server/file.json b/server/file.json index 7c9ad6b..1e242e5 100644 --- a/server/file.json +++ b/server/file.json @@ -12,16 +12,6 @@ "date": "Sat May 03 2025 12:08:00 GMT+0200 (Central European Summer Time)", "item": "nothing" }, - { - "variant": "eats", - "date": "Sat May 03 2025 12:09:03 GMT+0200 (Central European Summer Time)", - "item": "nuttin" - }, - { - "variant": "eats", - "date": "Sat May 03 2025 12:09:56 GMT+0200 (Central European Summer Time)", - "item": "foo" - }, { "variant": "eats", "date": "Sat May 03 2025 12:12:57 GMT+0200 (Central European Summer Time)", @@ -40,6 +30,15 @@ "variant": "eats", "date": "Sat May 03 2025 12:16:13 GMT+0200 (Central European Summer Time)", "item": "Mushrooms" + }, + { + "variant": "eats", + "date": "Sat May 03 2025 12:29:55 GMT+0200 (Central European Summer Time)", + "item": "something" + }, + { + "variant": "allergy", + "date": "Sat May 03 2025 13:03:52 GMT+0200 (Central European Summer Time)" } ] } diff --git a/server/server.js b/server/server.js index b36ab6a..580c505 100644 --- a/server/server.js +++ b/server/server.js @@ -9,7 +9,8 @@ const key = "c3dpZ2dpdHlzd29vdHkK"; const reStoreWrite = new RegExp(`/write/${key}/?`) const reStoreRead = new RegExp(`/read/${key}/?`) -const hostname = '127.0.0.1'; +let hostname = '127.0.0.1'; +hostname = "0.0.0.0"; const port = 4444; const server = createServer((req, res) => { diff --git a/src/App.css b/src/App.css index 74b5e05..151f128 100644 --- a/src/App.css +++ b/src/App.css @@ -1,38 +1,63 @@ +body { + width: 100%; + height: 100vh +} +#root { + width: 100%; + height: 100%; +} .App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; + width: 100%; + height: 100%; display: flex; flex-direction: column; align-items: center; + background-color: #A0C878; +} +.toprow { + display: flex; + flex-direction: row; justify-content: center; - font-size: calc(10px + 2vmin); - color: white; + gap: 15px; + width: 100%; +} +.toprow > div { + width: 45%; +} +h1,h2,h3 { + user-select: none; } -.App-link { - color: #61dafb; +.eats form div { + display: flex; + flex-direction: column; + gap: 10px; +} +.entry-table .reacts { + background-color: #DDEB9D; +} +.entry-table .eats:nth-child(2n+1) { + background-color: #FFFDF6; +} +.entry-table .eats:nth-child(2n) { + background-color: #FAF6E9; +} +.entry-table .delete { + background-color: #F16767; +} +.entry-table table td { + text-align: center; +} +.toprow .reacts { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } +.entry-table { + width: 80%; +} +.entry-table table { + border-spacing: 12px 2px; } diff --git a/src/App.tsx b/src/App.tsx index 7d5d446..8687e25 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,6 @@ import React, { JSX, useEffect, useState } from 'react'; -import logo from './logo.svg'; import './App.css'; -import { addEntry, ensureToday, getAPI, getToday } from './api'; +import { addEntry, APIEndPoint, ensureToday, getAPI, getToday, removeEntry } from './api'; import { ItemType, Store, StoreEntry } from './types'; import dayjs from 'dayjs'; @@ -11,7 +10,8 @@ const defaultStore: Store = { entries: {}, }; -const key="c3dpZ2dpdHlzd29vdHkK" +//const key="c3dpZ2dpdHlzd29vdHkK" +const key = localStorage.getItem("apikey") ?? ""; export const App : React.FC = () => { const [API, setAPI] = useState(() => getAPI(key)); @@ -24,42 +24,58 @@ export const App : React.FC = () => { f(); }, [API]); + const [showAPIField, setShowAPIField] = useState(false); + + const [input, setInput] = useState(""); return (
-
-

I ate ...

-
- setInput(e.target.value)} value={input} /> - -
-
-
-

I have allergy

- +

SHULNEFF

+
+
+

{e.preventDefault(); setShowAPIField(!showAPIField);}}>I ate ...

+ {showAPIField? + { + localStorage.setItem("apikey", e.target.value); + }}/> + :null} +
+
+ setInput(e.target.value)} value={input} /> + +
+
+
+
+ +
+
{store ? - +
+ +
:null} +
Raw Store
@@ -72,21 +88,66 @@ export const App : React.FC = () => {
 
 const DATEFORMAT = "YYYY MM DD HH:mm";
 
-export const RenderTable : React.FC<{store: Store}> = ({store}) => {
+export const RenderTable : React.FC<{API: APIEndPoint, store: Store, setStore: (store: Store) => void}> = ({store, API, setStore}) => {
+
+  const [selectedItem, setSelected] = useState(null);
   const listEntries = Object
     .values(store.entries)
     .flatMap((entry) => entry.items)
     .sort((a,b) => b.date.localeCompare(a.date));
+
   const itemToRow = (item: ItemType, index: number): JSX.Element => {
     const datestring = dayjs(new Date(item.date)).format(DATEFORMAT) 
+    const isSelected = (selectedItem !== null) && JSON.stringify(item) === JSON.stringify(selectedItem);
     if (item.variant === "eats") {
-      return {datestring}ate {item.item};
+      return  {
+          e.preventDefault();
+          if (isSelected) setSelected(null);
+          else setSelected(item);
+        }}
+        onClick={async (e) => {
+          if (isSelected) {
+            const newst = removeEntry(store, item );
+            console.log("newstore is", newst);
+            await API.write(JSON.stringify(store))
+            const fromserver = await API.read();
+            setStore({...fromserver} );
+          }
+        }}
+      key={index} className="eats">{datestring}ate
+      {isSelected ? 
+        X
+        :  {item.item}
+      }
+
+      ;
     } else if (item.variant === "allergy") {
-      return {datestring}Reaction!;
+      return  {
+          e.preventDefault();
+          if (isSelected) setSelected(null);
+          else setSelected(item);
+        }}
+        onClick={async (e) => {
+          if (isSelected) {
+            const newst = removeEntry(store, item );
+            console.log("newstore is", newst);
+            await API.write(JSON.stringify(store))
+            const fromserver = await API.read();
+            setStore({...fromserver} );
+          }
+        }}
+      key={index} className="reacts">{datestring}
+      {isSelected ? 
+        X
+        : Reaction!
+      }
+      ;
     }
     return <>;
   }
-  return 
+  return 
diff --git a/src/api.ts b/src/api.ts index 34c8f79..4b67b0b 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,11 +1,11 @@ import { ItemType, Store, StoreEntry } from "./types" -const defaultEndpoint = "http://localhost:4444/" +const defaultEndpoint = "http://slateport:4444" -type APIEndPoint = { +export type APIEndPoint = { write: (json: string) => Promise, - read: () => Promise, + read: () => Promise, }; const makeEndpoint = (key: string, method: string, endPointOverride?: string): string => { @@ -65,6 +65,14 @@ type APIEndPoint = { return store; } + export const removeEntry = (store: Store, entry: ItemType): Store => { + const [storeIndex, dateString] = getToday(ensureToday(store))!; + const today = store.entries[storeIndex]; + today.items = today.items.filter((item) => JSON.stringify(item) !== JSON.stringify(entry)); + store.entries[storeIndex] = today; + return store; + } + export const getToday = (store: Store) => { if (!store) return; const today : Date = new Date();
TimeEvent