From 7a36dce16012d7089a8c5c68ad9e14fbbfd7ba8c Mon Sep 17 00:00:00 2001 From: Kai Vogelgesang Date: Wed, 15 Feb 2023 00:43:33 +0100 Subject: [PATCH] Add text / skeleton --- package-lock.json | 77 +++++++++++++++++++++++++++ package.json | 3 ++ src/PartyPage.css | 83 +++++++++++++++++++---------- src/PartyPage.tsx | 117 ++++++++++++++++++++++++++++++++++------- src/logo.svg | 1 - src/reportWebVitals.ts | 15 ------ src/setupTests.ts | 5 -- 7 files changed, 232 insertions(+), 69 deletions(-) delete mode 100644 src/logo.svg delete mode 100644 src/reportWebVitals.ts delete mode 100644 src/setupTests.ts diff --git a/package-lock.json b/package-lock.json index a860353..ac78d6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "party-template", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -2203,6 +2206,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.10.7", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", @@ -17990,6 +18038,35 @@ } } }, + "@fortawesome/fontawesome-common-types": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.3.0" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.3.0" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "requires": { + "prop-types": "^15.8.1" + } + }, "@humanwhocodes/config-array": { "version": "0.10.7", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", diff --git a/package.json b/package.json index e9f6b3b..e47726b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", diff --git a/src/PartyPage.css b/src/PartyPage.css index 07b1f68..24a0a0f 100644 --- a/src/PartyPage.css +++ b/src/PartyPage.css @@ -5,40 +5,67 @@ } .App { + font-size: calc(10px + 2vmin); +} + +.page { 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; + height: 100vh; + width: 100vw; display: flex; flex-direction: column; align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; } -.App-link { - color: #61dafb; +.page-content { + flex-grow: 1; + max-width: 1224px; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } +.info-button { + display: flex; + flex-direction: column; + padding-bottom: 2em; + cursor: pointer; } + +.feedback { + line-height: 3em; + text-align: center; +} + +input[type="radio"] { + display: none; +} + +input[type="radio"]+label { + font-size: larger; + cursor: pointer; + display: inline-block; + width: 5em; +} + +input[type="radio"]+label:hover { + text-shadow: 0 0 1em; +} + +input[type="radio"]+label:last-of-type { + border-right: none; +} + +input[type="radio"]:checked+label { + color: var(--selected-color); + text-decoration: underline; +} + +#coming-yes+label { + --selected-color: #16a34a; +} + +#coming-maybe+label { + --selected-color: #ca8a04; +} + +#coming-no+label { + --selected-color: #dc2626; +} \ No newline at end of file diff --git a/src/PartyPage.tsx b/src/PartyPage.tsx index 8ca2536..5dbb376 100644 --- a/src/PartyPage.tsx +++ b/src/PartyPage.tsx @@ -1,27 +1,104 @@ -import React, { useContext } from 'react'; -import logo from './logo.svg'; +import React, { ChangeEvent, useContext, useRef, useState } from 'react'; import './PartyPage.css'; -import { PartyContext } from './PartyContext'; +import { APIEndPoint, PartyContext } from './PartyContext'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faAngleDown, faCalendarDays, faLocationDot } from '@fortawesome/free-solid-svg-icons'; +import { modifySelfRequest, parseURI } from './partyApi'; export const PartyPage: React.FC = () => { const partyContext = useContext(PartyContext); - - return
-
- logo -

- Edit src/PartyPage.tsx and save to reload. -

- - Learn React - - Hello {partyContext.self.name} -
+ const dear = { + "m": "lieber", + "f": "liebe", + "d": "liebes", + }[partyContext.self.grammatical_gender]; + const name = partyContext.self.name; + + const [comingState, setComingState] = useState(partyContext.self.coming); + + // SAFETY: If this is undefined, the contextProvider already fails + const endpoint = parseURI(window.location.href) as APIEndPoint; + + const handleSelect = async (e: ChangeEvent) => { + const value = (e.target as HTMLInputElement).value; + if (value !== "yes" && value !== "no" && value !== "maybe") { + throw new Error("received invalid value?"); + } + const status = await modifySelfRequest(endpoint, { coming: value }); + setComingState(status.coming); + } + + const party = partyContext.party; + + let coming: string; + if (party.maybe_coming === 0) { + // exact number + if (party.definitely_coming === 0) { + coming = "Bisher hat noch niemand zugesagt." + } else if (party.definitely_coming === 1) { + coming = "Bisher hat ein Gast zugesagt." + } else { + coming = `Es haben schon ${party.definitely_coming} Gäste zugesagt.` + } + } else { + // inexact + if (party.definitely_coming === 0 && party.maybe_coming === 1) { + coming = "Bisher hat ein Gast vorläufig zugesagt." + } else if (party.definitely_coming === 0) { + coming = `Bisher haben ${party.maybe_coming} Gäste vorläufig zugesagt.` + } else { + coming = `Nach den bisherigen Zusagen kommen ${party.definitely_coming} bis ${party.definitely_coming + party.maybe_coming} Gäste.` + } + } + + const infoRef = useRef(null); + const executeScroll = () => { + infoRef.current!.scrollIntoView({ behavior: 'smooth' }); + } + + return
+
+

Hallo {dear} {name},

+
+

+ wir (Kai, Dominic, Jenny) leiden aktuell unter dem zuckerfreien Februar. + Um das Ende dieser selbstauferlegten Folter gebührend zu feiern, möchten wir + dich gerne dazu einladen, dir gemeinsam mit uns ordentlich den Bauch + mit zuckersüßem Dessert vollzuschlagen. +

+

Klingt gut?

+
+ + + + + + +
+

{coming} Wir würden uns sehr freuen wenn auch du, {dear} {name}, kommen könntest! +

+
+
+ Mehr Infos + +
+
+
+
+

Wann und Wo?

+

+ 2. März, 20:00 +

+

+ Mainzer Str. 28, 66111 Saarbrücken +

+

Was für Süßkram?

+

+ Wir sorgen für selbstgebackene Brownies und Kekse, eventuell (wenn Ofen und Bäcker das durchhalten) auch Zimtschnecken. + Bring gerne noch selbstgebackene, selbstgekaufte oder anderwertig organisierte Desserts (oder Snacks) mit! +

+
+
}; \ No newline at end of file diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c0..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts deleted file mode 100644 index 49a2a16..0000000 --- a/src/reportWebVitals.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ReportHandler } from 'web-vitals'; - -const reportWebVitals = (onPerfEntry?: ReportHandler) => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/setupTests.ts b/src/setupTests.ts deleted file mode 100644 index 8f2609b..0000000 --- a/src/setupTests.ts +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom';