Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
441952d
refactor: Move seed data outside of main seed file
ZeroWave022 Aug 1, 2025
49142de
feat: Add events table and seed data
ZeroWave022 Aug 1, 2025
830861a
fix: Add locale to eventLocalizations
ZeroWave022 Aug 1, 2025
481a758
feat: Fetch events from db
ZeroWave022 Aug 1, 2025
978f8bb
fix: Fetch internal events only for members
ZeroWave022 Aug 1, 2025
b6884c8
refactor: Move event fetching to tRPC
ZeroWave022 Aug 1, 2025
9d900b2
feat: Add pagination to events page
ZeroWave022 Aug 1, 2025
c2ebba9
fix: Only show image on EventCard if there is one available
ZeroWave022 Aug 1, 2025
b4134a7
refactor: Use next-intl formatter wherever possible
ZeroWave022 Aug 1, 2025
533026a
refactor: Simplify ref prop typing
ZeroWave022 Aug 2, 2025
3506764
feat: Add DateTimePicker
ZeroWave022 Aug 2, 2025
a51918b
fix: Connect events to skills in db schema
ZeroWave022 Aug 2, 2025
7e3f52a
feat: Add event editing form
ZeroWave022 Aug 2, 2025
d396969
refactor: Rename storage procedure to protected edit procedure
ZeroWave022 Aug 3, 2025
1e60c50
refactor: Remove skillIdentifiers, replace with db
ZeroWave022 Aug 3, 2025
7199606
feat: Add default icon if skill identifier doesn't have a custom icon
ZeroWave022 Aug 3, 2025
ed2c340
feat: Event creation
ZeroWave022 Aug 3, 2025
bd7369f
fix: Make summary, description and location required
ZeroWave022 Aug 3, 2025
0436574
feat: Add edit button and back to events button
ZeroWave022 Aug 3, 2025
e52082b
fix: Set initial value in DateTimePicker if provided
ZeroWave022 Aug 3, 2025
4b385ce
feat: Add event editing and deletion
ZeroWave022 Aug 3, 2025
989e3fa
feat: Event image deletion
ZeroWave022 Aug 3, 2025
b940a5f
refactor: Remove skill names from messages, they're stored in db now
ZeroWave022 Aug 3, 2025
02a003d
feat: Add sign-up for events
ZeroWave022 Aug 3, 2025
3da2368
refactor: Rename many-to-many relation SQL tables for consistency
ZeroWave022 Aug 3, 2025
6566985
fix: Disable sign up button when not logged in
ZeroWave022 Aug 3, 2025
f98b070
refactor: Move member avatar to own component
ZeroWave022 Aug 3, 2025
e82b607
feat: Setting member attendance for events
ZeroWave022 Aug 3, 2025
4f82233
feat: Add event deadlines
ZeroWave022 Aug 5, 2025
ef49bdd
fix: Adjust size of MemberAvatar on MemberInfoCard
ZeroWave022 Aug 5, 2025
99f274a
feat: Give participants skills after finished event
ZeroWave022 Aug 5, 2025
63cba55
feat: Use non-relative imports for all VS Code users
ZeroWave022 Aug 5, 2025
2af3ca8
Merge branch 'dev' into feat/events
ZeroWave022 Aug 5, 2025
12b023f
feat: Add loading to new event and edit event pages
ZeroWave022 Aug 5, 2025
181ae9f
Merge branch 'dev' into feat/events
ZeroWave022 Aug 6, 2025
d0f72da
feat: Custom tooltip if event is finished
ZeroWave022 Aug 27, 2025
6820cbe
fix: Adjust the back buttons on event edit pages
ZeroWave022 Aug 27, 2025
37fd6e0
fix: Set initial event start date to next day
ZeroWave022 Aug 27, 2025
241b0a1
refactor: Avoid event localization arrays of length 1
ZeroWave022 Aug 27, 2025
79e062e
refactor: Move API exports
ZeroWave022 Aug 27, 2025
4db409b
fix: Limit name and location lengths on client
ZeroWave022 Aug 27, 2025
8625303
feat: Optimistic UI for event attendance checkbox
ZeroWave022 Aug 27, 2025
06fc6a0
feat: Show skill that can be achieved by participating at event
ZeroWave022 Aug 27, 2025
2ae53a2
Merge branch 'dev' into feat/events
ZeroWave022 Aug 27, 2025
5ab4d0e
Merge branch 'dev' into feat/events
ZeroWave022 Sep 3, 2025
03a4366
fix: Increase max length of event name
ZeroWave022 Sep 3, 2025
24f5557
refactor: Simplify check for user having skill already
ZeroWave022 Sep 3, 2025
1209f39
fix: Don't use div inside HTML paragraph
ZeroWave022 Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"prettier.enable": false,
"eslint.enable": false,
"typescript.preferences.importModuleSpecifier": "non-relative",
"files.associations": {
"*.css": "tailwindcss"
},
Expand Down
161 changes: 149 additions & 12 deletions messages/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"category": "category",
"sort": "sort",
"photoOf": "Photo of {name}",
"skills": "Skills",
"today": "Today",
"selected": "Selected",
"week": "Week",
Expand Down Expand Up @@ -516,24 +517,160 @@
"startedAt": "Started at",
"endsAt": "Ends at",
"endedAt": "Ended at",
"backToEvents": "Back to Events"
"backToEvents": "Back to Events",
"new": {
"title": "New Event",
"unauthorized": "Unauthorized to create events",
"success": "Event created successfully! Redirecting to event..."
},
"edit": {
"title": "Edit Event",
"unauthorized": "Unauthorized to edit events",
"delete": "Delete event",
"deleteImage": "Delete event image",
"deleteConfirmTitle": "Are you sure you want to delete this event?",
"deleteConfirmDescription": "All registrations for this event will also be deleted. This action cannot be undone.",
"deleteImageConfirmTitle": "Are you sure you want to delete the event image?",
"deleteImageConfirmDescription": "This action cannot be undone.",
"successEdit": "Event updated successfully! Redirecting to event...",
"successDelete": "Event deleted successfully! Redirecting to events...",
"successDeleteImage": "Event image deleted successfully!"
},
"form": {
"nameNorwegian": {
"label": "Event name (Norwegian)",
"placeholder": "Arrangementsnavn",
"required": "Event name is required"
},
"nameEnglish": {
"label": "Event name (English)",
"placeholder": "Event name",
"required": "Event name is required"
},
"summaryNorwegian": {
"label": "Summary (Norwegian)",
"placeholder": "Kort beskrivelse av arrangementet",
"required": "Event summary is required"
},
"summaryEnglish": {
"label": "Summary (English)",
"placeholder": "Short description of the event",
"required": "Event summary is required"
},
"descriptionNorwegian": {
"label": "Description (Norwegian)",
"placeholder": "Beskrivelse av arrangementet",
"required": "Event description is required"
},
"descriptionEnglish": {
"label": "Description (English)",
"placeholder": "Description of the event",
"required": "Event description is required"
},
"locationNorwegian": {
"label": "Location (Norwegian)",
"placeholder": "Sted for arrangementet",
"required": "Event location is required"
},
"locationEnglish": {
"label": "Location (English)",
"placeholder": "Location of the event",
"required": "Event location is required"
},
"startTime": {
"label": "Start time",
"required": "Start time is required",
"timeInPast": "The start time must be in the future"
},
"setSignUpDeadline": {
"label": "Set sign-up deadline",
"description": "Optionally, you can set a sign-up deadline. After this time, no new sign-ups will be accepted"
},
"signUpDeadline": {
"label": "Sign-up deadline",
"timeInPast": "The sign-up deadline must be in the future",
"beforeStartTime": "The sign-up deadline must be before the event start time"
},
"endTime": {
"label": "End time",
"required": "End time is required",
"dateBeforeStart": "The end time must be after the start time"
},
"locationMapLink": {
"label": "Location map link",
"placeholder": "https://use.mazemap.com/...",
"description": "Link to a map showing the event location",
"invalid": "Invalid map link format. Must be a URL"
},
"internal": {
"label": "Internal event",
"description": "If checked, the event will only be visible to Hackerspace members"
},
"skill": {
"label": "Select skill",
"description": "Select the skill that can be acquired by attending this event",
"placeholder": "Select a skill"
},
"image": {
"label": "Event image",
"upload": "Upload an image...",
"sizeLimitError": "Event image must be less than {size} MB",
"wrongFileTypeError": "Event image must be a PNG or JPG",
"fileNotImageError": "The file is not an image"
},
"createSubmit": "Create event",
"editSubmit": "Update event"
},
"attendance": {
"signUp": "Sign up",
"cancelSignUp": "Cancel sign-up",
"signUpSuccess": "Successfully signed up for the event!",
"cancelSignUpSuccess": "Successfully canceled sign-up for the event!",
"mustBeLoggedIn": "You must be logged in to sign up",
"signUpClosed": "Sign-up for this event is closed",
"pastSignUpDeadline": "The sign-up deadline has passed",
"eventStartedAlready": "The event has already started",
"signUpDeadline": "Sign-up deadline: {date}",
"attendance": "Attendance",
"attendanceDescription": "Check the attendance of members who signed up for this event. If a skill can be achieved by attending this event, you may give it to a participant after confirming their attendance.",
"attendeesList": "Attendees list",
"member": "Member",
"actions": "Actions",
"present": "Present",
"absent": "Absent",
"give": "Give",
"skillAttained": "Skill attained!",
"noParticipants": "No members signed up for this event",
"notStartedYet": "Cannot change attendance: The event has not started yet",
"updating": "Updating attendance for {name}...",
"success": "Attendance updated for {name}!",
"error": "Failed to update attendance for {name}",
"givingSkill": "Giving skill {skill} to {name}...",
"successSkill": "Skill {skill} given to {name}!",
"errorSkill": "Failed to give skill {skill} to {name}"
},
"api": {
"invalidId": "Invalid event ID",
"invalidUserId": "Invalid user ID",
"invalidSkillId": "Invalid skill ID",
"fetchEventFailed": "Failed to fetch event",
"unauthorized": "Unauthorized to view this event",
"invalidOffset": "Invalid offset",
"invalidLimit": "Invalid limit",
"insertFailed": "Failed to create event",
"notFound": "Event not found",
"skillNotFound": "Skill not found",
"userNotFound": "User not found",
"alreadyHasSkill": "User {user} already has the skill {skill}",
"participantNotFound": "Participant not found",
"noImage": "There is no image for this event"
}
},
"rules": {
"title": "Rules",
"forEveryone": "For everyone",
"internal": "Internal rules"
},
"skills": {
"skills": "Skills",
"printing": "3D Printing",
"soldering": "Soldering",
"raspberry": "Raspberry Pi",
"unix": "Unix/Linux",
"laser": "Laser Cutting",
"workshop": "Workshop Tools",
"microcontroller": "Microcontroller Programming",
"webdevelopment": "Web Development"
},
"api": {
"tooManyRequests": "Too many requests, please try again later",
"notAuthenticated": "Not authenticated",
Expand Down
169 changes: 153 additions & 16 deletions messages/nb-NO.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"category": "kategori",
"sort": "sortering",
"photoOf": "Bilde av {name}",
"skills": "Ferdigheter",
"today": "I dag",
"selected": "Valgt",
"week": "Uke",
Expand Down Expand Up @@ -512,28 +513,164 @@
"upcomingEvents": "Kommende arrangementer",
"pastEvents": "Tidligere arrangementer",
"detailsAboutEvent": "Les mer om {eventName}",
"startsAt": "Starter kl.",
"startedAt": "Startet kl.",
"endsAt": "Slutter kl.",
"endedAt": "Sluttet kl.",
"backToEvents": "Tilbake til arrangementer"
"startsAt": "Starter",
"startedAt": "Startet",
"endsAt": "Slutter",
"endedAt": "Sluttet",
"backToEvents": "Tilbake til arrangementer",
"new": {
"title": "Nytt arrangement",
"unauthorized": "Du har ikke rettigheter til å opprette arrangementer",
"success": "Arrangementet ble opprettet! Videresender deg til arrangementet..."
},
"edit": {
"title": "Rediger arrangement",
"unauthorized": "Du har ikke rettigheter til å redigere arrangementer",
"delete": "Slett arrangement",
"deleteImage": "Slett arrangementsbilde",
"deleteConfirmTitle": "Er du sikker på at du vil slette dette arrangementet?",
"deleteConfirmDescription": "Alle påmeldinger for dette arrangementet vil også bli slettet. Denne handlingen kan ikke angres.",
"deleteImageConfirmTitle": "Er du sikker på at du vil slette arrangementsbildet?",
"deleteImageConfirmDescription": "Denne handlingen kan ikke angres.",
"successEdit": "Arrangementet ble oppdatert! Videresender deg til arrangementet...",
"successDelete": "Arrangementet ble slettet! Videresender deg til arrangementer...",
"successDeleteImage": "Arrangementsbildet ble slettet!"
},
"form": {
"nameNorwegian": {
"label": "Navn (norsk)",
"placeholder": "Navn",
"required": "Navn er påkrevd"
},
"nameEnglish": {
"label": "Navn (engelsk)",
"placeholder": "Event name",
"required": "Navn er påkrevd"
},
"summaryNorwegian": {
"label": "Sammendrag (norsk)",
"placeholder": "Kort beskrivelse av arrangementet",
"required": "Sammendrag er påkrevd"
},
"summaryEnglish": {
"label": "Sammendrag (engelsk)",
"placeholder": "Short description of the event",
"required": "Sammendrag er påkrevd"
},
"descriptionNorwegian": {
"label": "Beskrivelse (norsk)",
"placeholder": "Beskrivelse av arrangementet",
"required": "Beskrivelse er påkrevd"
},
"descriptionEnglish": {
"label": "Beskrivelse (engelsk)",
"placeholder": "Description of the event",
"required": "Beskrivelse er påkrevd"
},
"locationNorwegian": {
"label": "Sted (norsk)",
"placeholder": "Sted for arrangementet",
"required": "Sted er påkrevd"
},
"locationEnglish": {
"label": "Sted (engelsk)",
"placeholder": "Location of the event",
"required": "Location is required"
},
"startTime": {
"label": "Starttidspunkt",
"required": "Starttidspunkt er påkrevd",
"timeInPast": "Starttidspunktet må være i fremtiden"
},
"setSignUpDeadline": {
"label": "Sett påmeldingsfrist",
"description": "Du kan du sette en påmeldingsfrist. Etter dette tidspunktet vil ingen nye påmeldinger bli akseptert"
},
"signUpDeadline": {
"label": "Påmeldingsfrist",
"timeInPast": "Påmeldingsfristen må være i fremtiden",
"beforeStartTime": "Påmeldingsfristen må være før arrangementets starttidspunkt"
},
"endTime": {
"label": "Sluttidspunkt",
"required": "Sluttidspunkt er påkrevd",
"dateBeforeStart": "Sluttidspunktet må være etter starttidspunktet"
},
"locationMapLink": {
"label": "Lenke til kart",
"placeholder": "https://use.mazemap.com/...",
"description": "Lenke til et kart som viser arrangementsstedet",
"invalid": "Ugyldig kartlenke. Må være en URL"
},
"internal": {
"label": "Internt arrangement",
"description": "Hvis avkrysset, vil arrangementet kun være synlig for Hackerspace-medlemmer"
},
"skill": {
"label": "Velg ferdighet",
"description": "Velg ferdigheten som kan tilegnes ved å delta på dette arrangementet",
"placeholder": "Velg en ferdighet"
},
"image": {
"label": "Arrangementsbilde",
"upload": "Last opp et bilde...",
"sizeLimitError": "Arrangementsbilde må være mindre enn {size} MB",
"wrongFileTypeError": "Arrangementsbilde må være en PNG eller JPG",
"fileNotImageError": "Filen er ikke et bilde"
},
"createSubmit": "Opprett arrangement",
"editSubmit": "Oppdater arrangement"
},
"attendance": {
"signUp": "Meld meg på",
"cancelSignUp": "Meld meg av",
"signUpSuccess": "Du har blitt meldt på arrangementet!",
"cancelSignUpSuccess": "Du har meldt deg av arrangementet!",
"mustBeLoggedIn": "Du må være logget inn for å melde deg på",
"signUpClosed": "Påmeldingen for dette arrangementet er stengt",
"pastSignUpDeadline": "Påmeldingsfristen har gått ut",
"eventStartedAlready": "Arrangementet har allerede startet",
"signUpDeadline": "Påmeldingsfrist: {date}",
"attendance": "Oppmøte",
"attendanceDescription": "Sjekk oppmøtet til medlemmene som har meldt seg på. Hvis en ferdighet kan bli oppnådd ved å delta på dette arrangementet, kan du gi den til deltakeren etter å ha bekreftet oppmøtet deres.",
"attendeesList": "Deltakerliste",
"member": "Medlem",
"actions": "Handlinger",
"present": "Til stede",
"absent": "Fraværende",
"give": "Gi",
"skillAttained": "Ferdighet oppnådd!",
"noParticipants": "Ingen medlemmer har meldt seg på dette arrangementet",
"notStartedYet": "Kan ikke endre oppmøte: Arrangementet har ikke startet enda",
"updating": "Oppdaterer oppmøte for {name}...",
"success": "Oppmøte oppdatert for {name}!",
"error": "Kunne ikke oppdatere oppmøte for {name}",
"givingSkill": "Gir ferdighet {skill} til {name}...",
"successSkill": "Ferdighet {skill} gitt til {name}!",
"errorSkill": "Kunne ikke gi ferdighet {skill} til {name}"
},
"api": {
"invalidId": "Ugyldig arrangement-ID",
"invalidUserId": "Ugyldig bruker-ID",
"invalidSkillId": "Ugyldig ferdighet-ID",
"fetchEventFailed": "Kunne ikke hente arrangement",
"unauthorized": "Du har ikke rettigheter til å se dette arrangementet",
"invalidOffset": "Ugyldig offset",
"invalidLimit": "Ugyldig limit",
"insertFailed": "Kunne ikke opprette arrangement",
"notFound": "Kunne ikke finne arrangementet",
"skillNotFound": "Kunne ikke finne ferdigheten",
"userNotFound": "Kunne ikke finne brukeren",
"alreadyHasSkill": "Brukeren {user} har allerede ferdigheten {skill}",
"participantNotFound": "Kunne ikke finne deltakeren",
"noImage": "Det finnes ikke noe bilde for dette arrangementet"
}
},
"rules": {
"title": "Regler",
"forEveryone": "For alle",
"internal": "Interne regler"
},
"skills": {
"skills": "Ferdigheter",
"printing": "3D-printing",
"soldering": "Lodding",
"raspberry": "Raspberry Pi",
"unix": "Unix/Linux",
"laser": "Laserkutting",
"workshop": "Verkstedsverktøy",
"microcontroller": "Mikrokontroller-programmering",
"webdevelopment": "Webutvikling"
},
"api": {
"tooManyRequests": "For mange forespørsler. Vennligst vent noen minutter og prøv igjen",
"notAuthenticated": "Ikke autentisert",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"db:migrate": "bunx drizzle-kit migrate",
"db:push": "bunx drizzle-kit push",
"db:studio": "bunx drizzle-kit studio",
"db:seed": "bun run src/server/db/seed.ts",
"db:seed": "bun run src/server/db/seed",
"s3:squash": "bun -e \"require('fs').rmSync('src/server/db/migrations/*', { recursive: true, force: true })\" && bun run db:generate",
"s3:start": "docker compose -f compose.local.yml up s3 -d",
"s3:stop": "docker compose -f compose.local.yml down s3",
Expand Down
Loading
Loading