From 9d39ff5bc2831619fe9247a501ad966463d79fc2 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Wed, 6 Mar 2024 09:41:36 +0100 Subject: [PATCH 1/4] Re-implemented demo button --- backend/cmd/main.go | 4 ++++ backend/internal/handlers/global_state.go | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/backend/cmd/main.go b/backend/cmd/main.go index 5762bab..b0cee26 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -36,6 +36,10 @@ func main() { // Register our handlers server.Post("/api/register", gs.Register) + // Register handlers for example button count + server.Get("/api/button", gs.GetButtonCount) + server.Post("/api/button", gs.IncrementButtonCount) + // Announce the port we are listening on and start the server err = server.Listen(fmt.Sprintf(":%d", conf.Port)) if err != nil { diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 4dae3d8..6c8a9dc 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -10,16 +10,19 @@ import ( // The actual interface that we will use type GlobalState interface { Register(c *fiber.Ctx) error + GetButtonCount(c *fiber.Ctx) error + IncrementButtonCount(c *fiber.Ctx) error } // "Constructor" func NewGlobalState(db database.Database) GlobalState { - return &GState{Db: db} + return &GState{Db: db, ButtonCount: 0} } // The global state, which implements all the handlers type GState struct { - Db database.Database + Db database.Database + ButtonCount int } func (gs *GState) Register(c *fiber.Ctx) error { @@ -34,3 +37,12 @@ func (gs *GState) Register(c *fiber.Ctx) error { return c.Status(200).SendString("User added") } + +func (gs *GState) GetButtonCount(c *fiber.Ctx) error { + return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount}) +} + +func (gs *GState) IncrementButtonCount(c *fiber.Ctx) error { + gs.ButtonCount++ + return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount}) +} From 4878ce1c398d0b6dc23119f7c295943cea5ecd37 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Wed, 6 Mar 2024 09:51:26 +0100 Subject: [PATCH 2/4] Useless fix for the vite default template with tailwind --- frontend/src/App.css | 4 ++++ frontend/src/App.tsx | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index b9d355d..bb6c55a 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -5,6 +5,10 @@ text-align: center; } +a { + display:inline-block; +} + .logo { height: 6em; padding: 1.5em; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 20e5f1f..2722ed9 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -8,16 +8,16 @@ function App(): JSX.Element { <>
- Vite logo + Vite logo - React logo + React logo

Vite + React

-

+

Edit src/App.tsx and save to test HMR

From 56693350bea3b716a5a66b97f0739cf2607706ce Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Wed, 6 Mar 2024 10:09:59 +0100 Subject: [PATCH 3/4] Pulling in and configuring react-router-dom --- frontend/package-lock.json | 100 ++++++++++++++++++++++++++++++++++++- frontend/package.json | 6 ++- frontend/src/main.tsx | 10 +++- 3 files changed, 113 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5131784..eecde70 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,8 +8,12 @@ "name": "tmp", "version": "0.0.0", "dependencies": { + "localforage": "^1.10.0", + "match-sorter": "^6.3.4", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.22.2", + "sort-by": "^0.0.2" }, "devDependencies": { "@swc/core": "^1.4.2", @@ -670,6 +674,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", @@ -1782,6 +1797,14 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@remix-run/router": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz", + "integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.10.0.tgz", @@ -4644,6 +4667,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -5898,6 +5926,14 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -5913,6 +5949,14 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/localforage": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", + "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "dependencies": { + "lie": "3.1.1" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5981,6 +6025,15 @@ "tmpl": "1.0.5" } }, + "node_modules/match-sorter": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.4.tgz", + "integrity": "sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==", + "dependencies": { + "@babel/runtime": "^7.23.8", + "remove-accents": "0.5.0" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6849,6 +6902,36 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/react-router": { + "version": "6.22.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz", + "integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==", + "dependencies": { + "@remix-run/router": "1.15.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz", + "integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==", + "dependencies": { + "@remix-run/router": "1.15.2", + "react-router": "6.22.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -6924,6 +7007,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -6942,6 +7030,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7242,6 +7335,11 @@ "node": ">=8" } }, + "node_modules/sort-by": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/sort-by/-/sort-by-0.0.2.tgz", + "integrity": "sha512-iOX5oHA4a0eqTMFiWrHYqv924UeRKFBLhym7iwSVG37Egg2wApgZKAjyzM9WZjMwKv6+8Zi+nIaJ7FYsO9EkoA==" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 9dce126..e8d78c1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,8 +12,12 @@ "test": "jest" }, "dependencies": { + "localforage": "^1.10.0", + "match-sorter": "^6.3.4", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.22.2", + "sort-by": "^0.0.2" }, "devDependencies": { "@swc/core": "^1.4.2", diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 05dff10..b980985 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -2,11 +2,19 @@ import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.tsx"; import "./index.css"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + }, +]); const root = document.getElementById("root") ?? document.createElement("div"); ReactDOM.createRoot(root).render( - + , ); From 70ae3598567beedc3e6351cb73bc977e30c6fe07 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Wed, 6 Mar 2024 10:14:54 +0100 Subject: [PATCH 4/4] Example of how to extend the API --- backend/cmd/main.go | 1 + backend/internal/handlers/global_state.go | 40 +++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/backend/cmd/main.go b/backend/cmd/main.go index b0cee26..2593019 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -35,6 +35,7 @@ func main() { // Register our handlers server.Post("/api/register", gs.Register) + server.Delete("/api/userdelete", gs.UserDelete) // Perhaps just use POST to avoid headaches // Register handlers for example button count server.Get("/api/button", gs.GetButtonCount) diff --git a/backend/internal/handlers/global_state.go b/backend/internal/handlers/global_state.go index 6c8a9dc..2d3e9f6 100644 --- a/backend/internal/handlers/global_state.go +++ b/backend/internal/handlers/global_state.go @@ -9,9 +9,28 @@ import ( // The actual interface that we will use type GlobalState interface { - Register(c *fiber.Ctx) error - GetButtonCount(c *fiber.Ctx) error - IncrementButtonCount(c *fiber.Ctx) error + Register(c *fiber.Ctx) error // To register a new user + UserDelete(c *fiber.Ctx) error // To delete a user + // LoginPost(c *fiber.Ctx) error // To get the token + // LoginUpdate(c *fiber.Ctx) error // To renew the token + // CreateProject(c *fiber.Ctx) error // To create a new project + // GetProjects(c *fiber.Ctx) error // To get all projects + // GetProject(c *fiber.Ctx) error // To get a specific project + // UpdateProject(c *fiber.Ctx) error // To update a project + // DeleteProject(c *fiber.Ctx) error // To delete a project + // CreateTask(c *fiber.Ctx) error // To create a new task + // GetTasks(c *fiber.Ctx) error // To get all tasks + // GetTask(c *fiber.Ctx) error // To get a specific task + // UpdateTask(c *fiber.Ctx) error // To update a task + // DeleteTask(c *fiber.Ctx) error // To delete a task + // CreateCollection(c *fiber.Ctx) error // To create a new collection + // GetCollections(c *fiber.Ctx) error // To get all collections + // GetCollection(c *fiber.Ctx) error // To get a specific collection + // UpdateCollection(c *fiber.Ctx) error // To update a collection + // DeleteCollection(c *fiber.Ctx) error // To delete a collection + // SignCollection(c *fiber.Ctx) error // To sign a collection + GetButtonCount(c *fiber.Ctx) error // For demonstration purposes + IncrementButtonCount(c *fiber.Ctx) error // For demonstration purposes } // "Constructor" @@ -38,6 +57,21 @@ func (gs *GState) Register(c *fiber.Ctx) error { return c.Status(200).SendString("User added") } +// This path should obviously be protected in the future +// UserDelete deletes a user from the database +func (gs *GState) UserDelete(c *fiber.Ctx) error { + u := new(types.User) + if err := c.BodyParser(u); err != nil { + return c.Status(400).SendString(err.Error()) + } + + if err := gs.Db.RemoveUser(u.Username); err != nil { + return c.Status(500).SendString(err.Error()) + } + + return c.Status(200).SendString("User deleted") +} + func (gs *GState) GetButtonCount(c *fiber.Ctx) error { return c.Status(200).JSON(fiber.Map{"pressCount": gs.ButtonCount}) }