diff --git a/.gitignore b/.gitignore index 0e677d2..f05c7d5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ yarn-error.log* # typescript *.tsbuildinfo -/data \ No newline at end of file +/data +/dev/data \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fecff9d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,69 @@ +# Contributing + +Vad kul att du vill hjälpa till och utveckla nollk.it! Alla förbättringar leder +till en bättre upplevelse för både Nollan och NollKIT, så tack! + +## Information om projektet + +Projektet använder teknologierna i listan nedanför. Du behöver inte vara bekant +med alla för att göra ändringar men det gör det självklart lättare desto mer du +kan! Det skadar aldrig att försöka och du kan alltid fråga om hjälp. + +- [Next.js](https://nextjs.org/) +- [TypeScript](https://www.typescriptlang.org/) +- [Node.js](https://nodejs.org/) +- [Tailwind](https://tailwindcss.com/) +- [Prisma](https://www.prisma.io/) +- [Docker](https://www.docker.com/) ([Docker Compose](https://docs.docker.com/compose/)) +- [MongoDB](https://www.mongodb.com/) + +## För att utveckla + +Installera [Docker Compose](https://docs.docker.com/compose/install) och +[Node.js](https://nodejs.org/en/download) om du inte redan har det. + +### Starta databasen + +```console +docker compose --file dev/docker-compose.yml up -d +``` + +> [!WARNING] +> Om du får ett felmeddelande, [kontrollera att Docker körs](https://docs.docker.com/engine/daemon/troubleshoot/). + +### Förbered webbsidan + +1. Skapa filen `.env` med följande innehåll: + + ```env + DATABASE_URL=mongodb://localhost:27017/db + PASSWORD=123 + ``` + +2. Kör dessa kommandon: + + ```console + npm install -D + npx prisma generate + node data.js + ``` + + > [!NOTE] + > `npm install -D` installerar alla Node dependencies, inklusive dependencies för utveckling. + > `npx prisma generate` genererar koden för Prisma klienten. + > `node data.js` skapar startdata i databasen. + +### Starta webbsidan + +```console +npm run dev +``` + +> [!TIP] +> Sidan uppdateras automatiskt när du ändrar källkoden. + +### Stäng av databasen + +```compose +docker compose --file dev/docker-compose.yml down +``` diff --git a/README.md b/README.md index b2d5e3e..50fc629 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,3 @@ Döp filerna till `år.pdf` eller `år.ttf`. För att starta projektet bygg docker nånting nånting Prisma generate? Gör det lätt att förstå helt enkelt. - - - -## För att utveckla -Först kör npm i, sen npx prisma generate om prisma skulle gnälla. - -Hur gör man med databasen? -Docker? - diff --git a/components/Countdown.tsx b/components/Countdown.tsx index b702990..b1774b8 100644 --- a/components/Countdown.tsx +++ b/components/Countdown.tsx @@ -10,12 +10,14 @@ export default function Countdown({ criticalDates }: { criticalDates: string[] } seconds: number, } - const [timeLeft, setTimeLeft] = useState({ + const defaultTimeLeft: TimeLeft = { days: 100, hours: 0, minutes: 0, seconds: 0, - }) + } + + const [timeLeft, setTimeLeft] = useState(defaultTimeLeft) const ctx = useContext(YearContext) @@ -26,7 +28,10 @@ export default function Countdown({ criticalDates }: { criticalDates: string[] } function getTimeLeft(year: string): TimeLeft { const todaysDate = new Date() - const msDelta = new Date(findCriticalDate(criticalDates, year)).getTime() - todaysDate.getTime() + const criticalDate = findCriticalDate(criticalDates, year) + if (criticalDate === "") + return defaultTimeLeft + const msDelta = new Date(criticalDate).getTime() - todaysDate.getTime() const daysLeft = Math.floor(msDelta / (86_400_000)) const hoursLeft = Math.floor((msDelta % 86_400_000) / 3_600_000) diff --git a/components/ImageWithFallback.tsx b/components/ImageWithFallback.tsx index 77fa9a7..02aee31 100644 --- a/components/ImageWithFallback.tsx +++ b/components/ImageWithFallback.tsx @@ -21,12 +21,16 @@ export default function ImageWithFallback(props: ImageWithFallbackProps) { return useFallback ? // If fallbacksrc is not set, don't render anything - props.fallbacksrc ? ( - + ( + props.fallbacksrc && + typeof props.fallbacksrc === 'string' && + props.fallbacksrc.trim() !== '' + ) ? ( + ) : ( null ) : ( - setUseFallback(true)}/> + setUseFallback(true)}/> ) } \ No newline at end of file diff --git a/components/ManagementDisplays/CommitteeManagementDisplay.tsx b/components/ManagementDisplays/CommitteeManagementDisplay.tsx index 3984062..83f776e 100644 --- a/components/ManagementDisplays/CommitteeManagementDisplay.tsx +++ b/components/ManagementDisplays/CommitteeManagementDisplay.tsx @@ -6,10 +6,13 @@ import TextInput from "../admin/TextInput" import Accordion from "../admin/Accordion" interface CommitteeManagementDisplayProps { - committee: CommitteeWithMembers + committee?: CommitteeWithMembers } export default function CommitteeManagementDisplay({ committee }: CommitteeManagementDisplayProps) { + if (!committee) { + return

Skapa en kommittée för att komma igång.

+ } const [members, setMembers] = useState(committee.members) let newMembers = [...members] @@ -155,7 +158,7 @@ export default function CommitteeManagementDisplay({ committee }: CommitteeManag "Content-Type": "application/json", }, body: JSON.stringify({ year: committee.year }), - }).then(() => { + }).then(() => fetch("/api/admin/committee/add", { method: "POST", headers: { @@ -163,7 +166,13 @@ export default function CommitteeManagementDisplay({ committee }: CommitteeManag }, body: JSON.stringify(committeeWithMembers), }) - }).then(() => alert("Sparat " + committee.year + " till databasen!")) + ).then(res => { + if (res.status === 200) { + alert("Sparat " + committee.year + " till databasen!") + } else { + alert("Något gick fel") + } + }) }}> Spara till databasen diff --git a/components/ManagementDisplays/TimelineManagementDisplay.tsx b/components/ManagementDisplays/TimelineManagementDisplay.tsx index ed0e55b..424abb7 100644 --- a/components/ManagementDisplays/TimelineManagementDisplay.tsx +++ b/components/ManagementDisplays/TimelineManagementDisplay.tsx @@ -11,12 +11,16 @@ interface TimelineManagementDisplayProps { export default function TextManagementDisplay(props: TimelineManagementDisplayProps) { - const [selectedYear, setSelectedYear] = useState(props.committees.sort((a, b) => b.year - a.year)[0].year) + const [selectedYear, setSelectedYear] = useState(props.committees.sort((a, b) => b.year - a.year)[0]?.year ?? new Date().getFullYear()) const [shownEvents, setShownEvents] = useState(props.timelineEvents.filter(event => event.year === selectedYear.toString()).sort((a, b) => a.date > b.date ? 1 : -1)) - const getCategoryColor = (categoryId: string) => { - return props.categories.find(category => category.title === categoryId)?.color ?? props.categories[0].color + const [shownCategories, setShownCategories] = useState(props.categories) + + const [newCategory, setNewCategory] = useState({ title: "", color: "", }) + + const getCategoryColor = (categoryId: string): string | undefined => { + return shownCategories.find(category => category.title === categoryId)?.color ?? shownCategories[0]?.color } return <> @@ -32,7 +36,10 @@ export default function TextManagementDisplay(props: TimelineManagementDisplayPr } -
+
+

Tidslinje

+ +
{ shownEvents.map((event, index) => { return ( @@ -85,49 +92,140 @@ export default function TextManagementDisplay(props: TimelineManagementDisplayPr ) }) } +
-
- - - +
+ +
+ +
+ + } +
+ +
+

Kategorier

+
+ { + shownCategories.map((category, index) => { + return ( +
+ +
+
{category.title}
+ +
+ + { + const newShownCategories = [...shownCategories] + newShownCategories[index].color = inputValue + setShownCategories(newShownCategories) + } + }> + {category.color} + +
+ ) + }) } - }> - Lägg till -
-
- + + { + const changedCategory = { ...newCategory, title: inputValue } + setNewCategory(changedCategory) + }} + > + {newCategory.title} + + + + + +
-
- -
- +
} \ No newline at end of file diff --git a/temp.js b/data.js similarity index 100% rename from temp.js rename to data.js diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml new file mode 100644 index 0000000..f9ea8f8 --- /dev/null +++ b/dev/docker-compose.yml @@ -0,0 +1,18 @@ +services: + mongo: + image: mongo:7.0 + command: ["--replSet", "rs0", "--bind_ip_all"] + ports: + - 27017:27017 + expose: + - 27017 + healthcheck: + test: echo 'db.runCommand("ping").ok' | mongosh --port 27017 --quiet + interval: 5s + timeout: 30s + start_period: 0s + retries: 30 + volumes: + - "./data/originalData:/data/db" + - "./data/originalData_config:/data/configdb" + - "./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh" diff --git a/dev/init-mongo.sh b/dev/init-mongo.sh new file mode 100644 index 0000000..36ac11a --- /dev/null +++ b/dev/init-mongo.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# Initiate single-node replica set if not already running +mongosh --quiet --eval ' + try { + rs.status() + } catch (e) { + rs.initiate({_id:"rs0", members:[{_id:0, host:"localhost:27017"}]}) + } +' diff --git a/pages/admin/index.tsx b/pages/admin/index.tsx index 4fdf633..a963429 100644 --- a/pages/admin/index.tsx +++ b/pages/admin/index.tsx @@ -103,7 +103,9 @@ const Admin: NextPage = (props: AdminProps) => {
- {faqItems.map((faqItem, index) => ( + {faqItems?.map((faqItem, index) => (
diff --git a/pages/nollkit.tsx b/pages/nollkit.tsx index b58b7a9..2cdd47a 100644 --- a/pages/nollkit.tsx +++ b/pages/nollkit.tsx @@ -25,8 +25,8 @@ export const getServerSideProps = async () => { } interface NollkitProps { - allMembers: Member[] - text: PageText + allMembers?: Member[] + text?: PageText } const Nollkit: NextPage = ({ allMembers, text }) => { @@ -43,7 +43,7 @@ const Nollkit: NextPage = ({ allMembers, text }) => { - {text.content} + {text?.content} @@ -54,7 +54,7 @@ const Nollkit: NextPage = ({ allMembers, text }) => {
{ - allMembers.filter(member => member.year.toString() === ctx.year).sort( (a, b) => a.orderInImage - b.orderInImage).map((member, index) => { + allMembers?.filter(member => member.year.toString() === ctx.year).sort( (a, b) => a.orderInImage - b.orderInImage).map((member, index) => { return (
diff --git a/pages/pateter.tsx b/pages/pateter.tsx index 9946460..2952d91 100644 --- a/pages/pateter.tsx +++ b/pages/pateter.tsx @@ -33,8 +33,8 @@ export const getServerSideProps = async () => { }; interface PateterProps { - text: PageText; - allCommittees: CommitteeWithMembers[]; + text?: PageText; + allCommittees?: CommitteeWithMembers[]; } const Pateter: NextPage = ({ text, allCommittees }) => { @@ -71,7 +71,7 @@ const Pateter: NextPage = ({ text, allCommittees }) => { onScroll={() => handleScroll()} >
- {text.content} + {text?.content}
= ({ text, allCommittees }) => {
{/* used to to know whether user has scrolled far enough */}
{" "} - {allCommittees.map((committee) => ( + {allCommittees?.map((committee) => (