diff --git a/Makefile b/Makefile index e4f4e18..29da659 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,15 @@ +.PHONY: migrate migrate: go run -v ./scripts/migrate -.PHONY: api -api: +.PHONY: backend +backend: go build -v -o api -ldflags="-buildid= -X gitlab.com/1f320/pronouns/backend/server.Revision=`git rev-parse --short HEAD`" ./backend + +.PHONY: frontend +frontend: + yarn build + +.PHONY: dev +dev: + yarn dev diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 730d59a..f3c550a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,6 +2,7 @@ import { Routes, Route } from "react-router-dom"; import "./App.css"; import Container from "./lib/Container"; import Navigation from "./lib/Navigation"; +import EditMe from "./pages/EditMe"; import Home from "./pages/Home"; import Discord from "./pages/login/Discord"; import Login from "./pages/login/Login"; @@ -15,6 +16,7 @@ function App() { } /> } /> + } /> } /> } /> diff --git a/frontend/src/lib/Card.tsx b/frontend/src/lib/Card.tsx index 22d9c99..3ec5381 100644 --- a/frontend/src/lib/Card.tsx +++ b/frontend/src/lib/Card.tsx @@ -1,11 +1,15 @@ import React, { PropsWithChildren } from "react"; -export type Props = PropsWithChildren<{ title: string }>; +export type Props = PropsWithChildren<{ title: string; draggable?: boolean }>; -export default function Card({ title, children }: Props) { +export default function Card({ title, draggable, children }: Props) { return (
-

+

{title}

{children}
diff --git a/frontend/src/lib/FieldCard.tsx b/frontend/src/lib/FieldCard.tsx index 830c369..a5ac2d5 100644 --- a/frontend/src/lib/FieldCard.tsx +++ b/frontend/src/lib/FieldCard.tsx @@ -9,9 +9,15 @@ import { import Card from "./Card"; import type { Field } from "./types"; -export default function FieldCard({ field }: { field: Field }) { +export default function FieldCard({ + field, + draggable, +}: { + field: Field; + draggable?: boolean; +}) { return ( - + {field.favourite.map((entry) => (

{entry} diff --git a/frontend/src/pages/EditMe.tsx b/frontend/src/pages/EditMe.tsx new file mode 100644 index 0000000..8205877 --- /dev/null +++ b/frontend/src/pages/EditMe.tsx @@ -0,0 +1,53 @@ +import cloneDeep from "lodash/cloneDeep"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { ReactSortable } from "react-sortablejs"; +import { useRecoilValue } from "recoil"; + +import { userState } from "../lib/store"; +import { Field } from "../lib/types"; +import FieldCard from "../lib/FieldCard"; + +interface FieldWithID extends Field { + id: number; +} + +export default function EditMe() { + const navigate = useNavigate(); + + const meUser = useRecoilValue(userState); + if (!meUser) { + navigate("/"); + return <>Loading...; + } + + const [state, setState] = useState(cloneDeep(meUser)); + // add an ID to every field (not returned by the API normally, but Sortable needs it) + const originalOrder = state.fields.map((f, i) => { + const fID = f as FieldWithID; + fID.id = i; + return fID; + }); + + const [fields, setFields] = useState(cloneDeep(originalOrder)); + const fieldsUpdated = + fields.length !== state.fields.length || + !fields.every((_, i) => fields[i].id === originalOrder[i].id); + + return ( +

+
{`fieldsUpdated: ${fieldsUpdated}`}
+ {/* @ts-ignore: This component isn't updated to have a "children" prop yet, but it accepts it just fine. */} + + {fields.map((field, i) => ( + + ))} + +
+ ); +} diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx index 6d5bed1..aaa55d9 100644 --- a/frontend/src/pages/User.tsx +++ b/frontend/src/pages/User.tsx @@ -4,7 +4,6 @@ import { ArrowClockwise } from "react-bootstrap-icons"; import ReactMarkdown from "react-markdown"; import { Helmet } from "react-helmet"; -import NavItem from "../lib/NavItem"; import type { User } from "../lib/types"; import fetchAPI from "../lib/fetch"; import FieldCard from "../lib/FieldCard"; diff --git a/package.json b/package.json index be20c63..4367290 100644 --- a/package.json +++ b/package.json @@ -10,20 +10,26 @@ "dependencies": { "@sentry/react": "^6.19.7", "@sentry/tracing": "^6.19.7", - "@types/react-helmet": "^6.1.5", "axios": "^0.27.2", + "lodash": "^4.17.21", "react": "^18.0.0", "react-bootstrap-icons": "^1.8.2", "react-dom": "^18.0.0", "react-helmet": "^6.1.0", "react-markdown": "^8.0.3", "react-router-dom": "6", - "recoil": "^0.7.2" + "react-sortablejs": "^6.1.1", + "recoil": "^0.7.2", + "sortablejs": "^1.15.0" }, "devDependencies": { + "@tailwindcss/forms": "^0.5.1", "@tailwindcss/typography": "^0.5.2", + "@types/lodash": "^4.14.182", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", + "@types/react-helmet": "^6.1.5", + "@types/sortablejs": "^1.13.0", "@vitejs/plugin-react": "^1.3.0", "autoprefixer": "^10.4.7", "postcss": "^8.4.13", diff --git a/tailwind.config.js b/tailwind.config.js index 1d9cfcb..a772ad0 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -4,5 +4,5 @@ module.exports = { theme: { extend: {}, }, - plugins: [require("@tailwindcss/typography")], + plugins: [require("@tailwindcss/typography"), require("@tailwindcss/forms")], }; diff --git a/yarn.lock b/yarn.lock index 5d980e9..5f773eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -378,6 +378,13 @@ "@sentry/types" "6.19.7" tslib "^1.9.3" +"@tailwindcss/forms@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.1.tgz#7fe86b9b67e6d91cb902e2d3f4ebe561cc057a13" + integrity sha512-QSwsFORnC2BAP0lRzQkz1pw+EzIiiPdk4e27vGQjyXkwJPeC7iLIRVndJzf9CJVbcrrIcirb/TfxF3gRTyFEVA== + dependencies: + mini-svg-data-uri "^1.2.3" + "@tailwindcss/typography@^0.5.2": version "0.5.2" resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.2.tgz#24b069dab24d7a2467d01aca0dd432cb4b29f0ee" @@ -401,6 +408,11 @@ dependencies: "@types/unist" "*" +"@types/lodash@^4.14.182": + version "4.14.182" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + "@types/mdast@^3.0.0": version "3.0.10" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" @@ -451,6 +463,11 @@ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/sortablejs@^1.13.0": + version "1.13.0" + resolved "https://registry.yarnpkg.com/@types/sortablejs/-/sortablejs-1.13.0.tgz#870223438f8f2cd81157b128a4c0261adbcaa946" + integrity sha512-C3064MH72iEfeGCYEGCt7FCxXoAXaMPG0QPnstcxvPmbl54erpISu06d++FY37Smja64iWy5L8wOyHHBghWbJQ== + "@types/unist@*", "@types/unist@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -606,6 +623,11 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +classnames@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1056,6 +1078,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -1336,6 +1363,11 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mini-svg-data-uri@^1.2.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" + integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== + minimist@^1.1.1: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" @@ -1550,6 +1582,14 @@ react-side-effect@^2.1.0: resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== +react-sortablejs@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/react-sortablejs/-/react-sortablejs-6.1.1.tgz#1c90b6ae79a59490986c7918ebc9aa2eecf965cf" + integrity sha512-VXTCHiitk1QT1uxt+hFGSihG1phk/HAw/17a65diTT3NVm/5dui2O99X5L/tOFLgRT5ifxwZtnloTTDsT5EH2w== + dependencies: + classnames "2.3.1" + tiny-invariant "1.2.0" + react@^18.0.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890" @@ -1647,6 +1687,11 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +sortablejs@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a" + integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w== + source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -1703,6 +1748,11 @@ tailwindcss@^3.0.24: quick-lru "^5.1.1" resolve "^1.22.0" +tiny-invariant@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"