From 575a4994bdff31b45bb13a42cf1f6d67baf4f204 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 23 Sep 2025 20:59:19 +0200 Subject: [PATCH 01/48] Add darkmode to storybook --- .../Components/OpeningHours/OpeningHours.module.scss | 12 ++++++++++++ .../src/Components/OpeningHours/OpeningHours.tsx | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.module.scss b/frontend/src/Components/OpeningHours/OpeningHours.module.scss index ded5733fc..5a5822013 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.module.scss +++ b/frontend/src/Components/OpeningHours/OpeningHours.module.scss @@ -1,4 +1,5 @@ @use 'src/constants' as *; +@use 'src/mixins' as *; .container { background-color: $white; @@ -7,8 +8,19 @@ display: flex; flex-direction: column; align-items: center; + + & td { + border-left: 0; + border-right: 0; +} + + @include theme-dark { + background-color: $black-2; + color: $white; + } } + .openingHoursText { margin: 0 0.2em; } diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index ad2c24308..fd568954b 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -1,4 +1,6 @@ import { useTranslation } from 'react-i18next'; +import { Text } from '~/Components/Text/Text'; +import { Link } from '~/Components/Link/Link'; import { TimeDuration } from '~/Components'; import { KEY } from '~/i18n/constants'; import styles from './OpeningHours.module.scss'; @@ -18,14 +20,14 @@ export function OpeningHours({ venues }: OpeningHoursProps) { const { t } = useTranslation(); return (
-

{t(KEY.common_opening_hours)}

+ {t(KEY.common_opening_hours)} {venues.map((venue) => ( ))} diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 55431ead0..6bc1e2e25 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -139,6 +139,12 @@ export type VenueDto = { closing_sunday?: string; }; +export type OpenVenuesDto = { + name: string; + opening: string; + closing: string; +} + // ==================== // // Event // // ==================== // From a1d65d0f5d91d5d278fd4f599fe0788c03ed1ac0 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 25 Sep 2025 18:51:52 +0200 Subject: [PATCH 04/48] Change route naming --- backend/root/utils/routes.py | 2 +- frontend/src/api.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index ebe6d0f60..a2784cffe 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -486,7 +486,7 @@ samfundet__eventgroups_detail = 'samfundet:eventgroups-detail' samfundet__venues_list = 'samfundet:venues-list' samfundet__venues_detail = 'samfundet:venues-detail' -samfundet__venues_open_today = 'samfundet:venues_open_today' +samfundet__open_venues = 'samfundet:open_venues' samfundet__closedperiods_list = 'samfundet:closedperiods-list' samfundet__closedperiods_detail = 'samfundet:closedperiods-detail' samfundet__gangs_list = 'samfundet:gangs-list' diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 06c129a55..68558d80b 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -19,6 +19,7 @@ import type { MenuDto, MenuItemDto, OccupiedTimeslotDto, + OpenVenuesDto, OrganizationDto, PermissionDto, PositionsByTagResponse, @@ -186,6 +187,12 @@ export async function patchVenue(slug: string | number, venue: Partial return response.data; } +export async function getOpenVenues(): Promise { + const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__open_venues; + const response = await axios.patch(url, { withCredentials: true }); + return response.data; +} + export async function getPermissions(): Promise { const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__permissions_list; const response = await axios.get(url, { withCredentials: true }); From 9d3231fcdc0647cad1327bd963f9af928ebd6a4d Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 25 Sep 2025 18:53:07 +0200 Subject: [PATCH 05/48] Change request from patch to get --- frontend/src/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 68558d80b..c3c5cd56b 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -189,7 +189,7 @@ export async function patchVenue(slug: string | number, venue: Partial export async function getOpenVenues(): Promise { const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__open_venues; - const response = await axios.patch(url, { withCredentials: true }); + const response = await axios.get(url, { withCredentials: true }); return response.data; } From cb6307124899079e2e990126d6f348bceefc71a5 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 25 Sep 2025 19:23:53 +0200 Subject: [PATCH 06/48] Create open_venues function in VenueView --- backend/samfundet/view/general_views.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/backend/samfundet/view/general_views.py b/backend/samfundet/view/general_views.py index 31825dfc3..2e440a688 100644 --- a/backend/samfundet/view/general_views.py +++ b/backend/samfundet/view/general_views.py @@ -16,7 +16,7 @@ from rest_framework.permissions import AllowAny from django.utils import timezone -from django.db.models import QuerySet +from django.db.models import Q, QuerySet from django.shortcuts import get_object_or_404 from root.custom_classes.permission_classes import RoleProtectedOrAnonReadOnlyObjectPermissions @@ -113,6 +113,22 @@ class VenueView(ModelViewSet): queryset = Venue.objects.all() lookup_field = 'slug' + @action(detail=False, methods=['get']) + def open_venues(self, request: Request) -> Response: + now = timezone.now() + day_name = now.strftime('%A').lower() + + q = Q( + **{ + f'opening_{day_name}__lte': now.time(), + f'closing_{day_name}__gte': now.time(), + } + ) + + open_venues = Venue.objects.filter(q) + serializer = self.get_serializer(open_venues, many=True) + return Response(serializer.data) + class ClosedPeriodView(ModelViewSet): permission_classes = (RoleProtectedOrAnonReadOnlyObjectPermissions,) From 532c81bb682cf65b6e50c82734e88d51ca414c57 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 25 Sep 2025 19:24:06 +0200 Subject: [PATCH 07/48] Generate routes --- backend/root/utils/routes.py | 9 ++++++++- frontend/src/routes/backend.ts | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index a2784cffe..2172812bb 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -485,8 +485,8 @@ samfundet__eventgroups_list = 'samfundet:eventgroups-list' samfundet__eventgroups_detail = 'samfundet:eventgroups-detail' samfundet__venues_list = 'samfundet:venues-list' +samfundet__venues_open_venues = 'samfundet:venues-open-venues' samfundet__venues_detail = 'samfundet:venues-detail' -samfundet__open_venues = 'samfundet:open_venues' samfundet__closedperiods_list = 'samfundet:closedperiods-list' samfundet__closedperiods_detail = 'samfundet:closedperiods-detail' samfundet__gangs_list = 'samfundet:gangs-list' @@ -554,6 +554,13 @@ samfundet__recruitment_applications_for_position_detail = 'samfundet:recruitment_applications_for_position-detail' samfundet__interview_list = 'samfundet:interview-list' samfundet__interview_detail = 'samfundet:interview-detail' +samfundet__billig_event_list = 'samfundet:billig_event-list' +samfundet__billig_event_detail = 'samfundet:billig_event-detail' +samfundet__billig_price_group_list = 'samfundet:billig_price_group-list' +samfundet__billig_price_group_detail = 'samfundet:billig_price_group-detail' +samfundet__billig_ticket_group_list = 'samfundet:billig_ticket_group-list' +samfundet__billig_ticket_group_detail = 'samfundet:billig_ticket_group-detail' +samfundet__api_root = 'samfundet:api-root' samfundet__api_root = 'samfundet:api-root' samfundet__schema = 'samfundet:schema' samfundet__swagger_ui = 'samfundet:swagger_ui' diff --git a/frontend/src/routes/backend.ts b/frontend/src/routes/backend.ts index d0d027a2b..485fbfa7d 100644 --- a/frontend/src/routes/backend.ts +++ b/frontend/src/routes/backend.ts @@ -484,6 +484,7 @@ export const ROUTES_BACKEND = { samfundet__eventgroups_list: '/api/eventgroups/', samfundet__eventgroups_detail: '/api/eventgroups/:pk/', samfundet__venues_list: '/api/venues/', + samfundet__venues_open_venues: '/api/venues/open_venues/', samfundet__venues_detail: '/api/venues/:slug/', samfundet__closedperiods_list: '/api/closed/', samfundet__closedperiods_detail: '/api/closed/:pk/', @@ -552,7 +553,14 @@ export const ROUTES_BACKEND = { samfundet__recruitment_applications_for_position_detail: '/api/recruitment-applications-for-position/:pk/', samfundet__interview_list: '/api/interview/', samfundet__interview_detail: '/api/interview/:pk/', + samfundet__billig_event_list: '/api/billig-event/', + samfundet__billig_event_detail: '/api/billig-event/:pk/', + samfundet__billig_price_group_list: '/api/billig-price-group/', + samfundet__billig_price_group_detail: '/api/billig-price-group/:pk/', + samfundet__billig_ticket_group_list: '/api/billig-ticket-group/', + samfundet__billig_ticket_group_detail: '/api/billig-ticket-group/:pk/', samfundet__api_root: '/api/', + samfundet__api_root: '/api/:format', samfundet__schema: '/schema/', samfundet__swagger_ui: '/schema/swagger-ui/', samfundet__redoc: '/schema/redoc/', @@ -610,4 +618,4 @@ export const ROUTES_BACKEND = { samfundet__recruitment_all_applications: '/recruitment/all-applications/', static__path: '/static/:path', media__path: '/media/:path', -} as const; +} as const; \ No newline at end of file From 1bd43d8f9b008a23fb698e849a9a92643b897e53 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 30 Sep 2025 19:17:23 +0200 Subject: [PATCH 08/48] Remove irrelevant routes changes --- backend/root/utils/routes.py | 7 ------- frontend/src/routes/backend.ts | 9 +-------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index 2172812bb..83a4dd799 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -554,13 +554,6 @@ samfundet__recruitment_applications_for_position_detail = 'samfundet:recruitment_applications_for_position-detail' samfundet__interview_list = 'samfundet:interview-list' samfundet__interview_detail = 'samfundet:interview-detail' -samfundet__billig_event_list = 'samfundet:billig_event-list' -samfundet__billig_event_detail = 'samfundet:billig_event-detail' -samfundet__billig_price_group_list = 'samfundet:billig_price_group-list' -samfundet__billig_price_group_detail = 'samfundet:billig_price_group-detail' -samfundet__billig_ticket_group_list = 'samfundet:billig_ticket_group-list' -samfundet__billig_ticket_group_detail = 'samfundet:billig_ticket_group-detail' -samfundet__api_root = 'samfundet:api-root' samfundet__api_root = 'samfundet:api-root' samfundet__schema = 'samfundet:schema' samfundet__swagger_ui = 'samfundet:swagger_ui' diff --git a/frontend/src/routes/backend.ts b/frontend/src/routes/backend.ts index 485fbfa7d..af0dc8645 100644 --- a/frontend/src/routes/backend.ts +++ b/frontend/src/routes/backend.ts @@ -553,14 +553,7 @@ export const ROUTES_BACKEND = { samfundet__recruitment_applications_for_position_detail: '/api/recruitment-applications-for-position/:pk/', samfundet__interview_list: '/api/interview/', samfundet__interview_detail: '/api/interview/:pk/', - samfundet__billig_event_list: '/api/billig-event/', - samfundet__billig_event_detail: '/api/billig-event/:pk/', - samfundet__billig_price_group_list: '/api/billig-price-group/', - samfundet__billig_price_group_detail: '/api/billig-price-group/:pk/', - samfundet__billig_ticket_group_list: '/api/billig-ticket-group/', - samfundet__billig_ticket_group_detail: '/api/billig-ticket-group/:pk/', samfundet__api_root: '/api/', - samfundet__api_root: '/api/:format', samfundet__schema: '/schema/', samfundet__swagger_ui: '/schema/swagger-ui/', samfundet__redoc: '/schema/redoc/', @@ -618,4 +611,4 @@ export const ROUTES_BACKEND = { samfundet__recruitment_all_applications: '/recruitment/all-applications/', static__path: '/static/:path', media__path: '/media/:path', -} as const; \ No newline at end of file +} as const; From 97819384c6c64a477b85b063109d9c823e19ad83 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 30 Sep 2025 19:52:55 +0200 Subject: [PATCH 09/48] Refactor api call to deliver venue list instead of new datatype --- frontend/src/api.ts | 6 +++--- frontend/src/dto.ts | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index c3c5cd56b..8987d63c9 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -187,9 +187,9 @@ export async function patchVenue(slug: string | number, venue: Partial return response.data; } -export async function getOpenVenues(): Promise { - const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__open_venues; - const response = await axios.get(url, { withCredentials: true }); +export async function getOpenVenues(): Promise { + const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__venues_open_venues; + const response = await axios.get(url, { withCredentials: true }); return response.data; } diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 6bc1e2e25..9ba1c2def 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -139,11 +139,7 @@ export type VenueDto = { closing_sunday?: string; }; -export type OpenVenuesDto = { - name: string; - opening: string; - closing: string; -} +export type OpenVenuesDto = VenueDto[]; // ==================== // // Event // From 567abe2842c07747e68d2769e2f4675c071f81e1 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 30 Sep 2025 21:36:37 +0200 Subject: [PATCH 10/48] Create container component --- .../OpeningHours/OpeningHoursContainer.tsx | 38 +++++++++++++++++++ frontend/src/Pages/HomePage/HomePage.tsx | 2 + 2 files changed, 40 insertions(+) create mode 100644 frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx diff --git a/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx new file mode 100644 index 000000000..10a90ed62 --- /dev/null +++ b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx @@ -0,0 +1,38 @@ +import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'react-i18next'; +import { getOpenVenues } from '~/api'; +import { Text } from '~/Components/Text'; +import { VenueDto } from '~/dto'; +import { KEY } from '~/i18n/constants'; +import { OpeningHours } from './OpeningHours'; + +export function OpeningHoursContainer() { + const { t } = useTranslation(); + const { data: openVenues, isLoading, isError } = useQuery({ + queryKey: ['openVenues'], + queryFn: getOpenVenues, + }); + + if (isLoading) { + return {t(KEY.common_loading)}; + } + + if (isError || !openVenues) { + return {t(KEY.error_generic)}; + } + + const today = new Date().toISOString().split('T')[0]; + const day = new Date().toLocaleDateString('en-US', { weekday: 'long' }).toLowerCase(); + + const venues = openVenues.map((venue) => { + const openingTime = venue[`opening_${day}` as keyof VenueDto] as string; + const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; + return { + name: venue.name, + opening: `${today}T${openingTime}`, + closing: `${today}T${closingTime}`, + }; + }); + + return ; +} diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index cb675d67a..4e637006c 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; +import { OpeningHoursContainer } from '~/Components/OpeningHours/OpeningHoursContainer'; import { EventCarousel, LargeCard } from '~/Pages/HomePage/components'; import { getHomeData } from '~/api'; import type { HomePageDto, HomePageElementDto } from '~/dto'; @@ -52,6 +53,7 @@ export function HomePage() { <>
+ {/**/} {isLoading && skeleton} From e01573dde381065cea572a990410e2c5c763f165 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 30 Sep 2025 22:03:07 +0200 Subject: [PATCH 11/48] Refactor so all logic is in OpeningHours.tsx --- .../Components/OpeningHours/OpeningHours.tsx | 65 ++++++++++++------- .../OpeningHours/OpeningHoursContainer.tsx | 27 +------- 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index d93cf76b8..6fb1162b0 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -1,38 +1,57 @@ import { useTranslation } from 'react-i18next'; -import { Text } from '~/Components/Text/Text'; -import { Link } from '~/Components/Link/Link'; import { TimeDuration } from '~/Components'; +import { Link } from '~/Components/Link/Link'; +import { Text } from '~/Components/Text/Text'; +import { VenueDto } from '~/dto'; import { KEY } from '~/i18n/constants'; import styles from './OpeningHours.module.scss'; -type VenueOpeningProp = { - name: string; - opening: string; - closing: string; -}; - type OpeningHoursProps = { - venues: VenueOpeningProp[]; + venues: VenueDto[] | undefined; + isLoading: boolean; + isError: boolean; }; -export function OpeningHours({ venues }: OpeningHoursProps) { +export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) { const { t } = useTranslation(); + + if (isLoading) { + return {t(KEY.common_loading)}; + } + + if (isError || !venues) { + return {t(KEY.error_generic)}; + } + + const today = new Date().toISOString().split('T')[0]; + const day = new Date().toLocaleDateString('en-US', { weekday: 'long' }).toLowerCase(); + return (
- {t(KEY.common_opening_hours)} + + {t(KEY.common_opening_hours)} +
- +

{venue.name}

-
+
From fa443e50ac20c96d947639c928f2de1ee0535936 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 23 Sep 2025 21:15:28 +0200 Subject: [PATCH 02/48] Remove bg color --- frontend/src/Components/OpeningHours/OpeningHours.module.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.module.scss b/frontend/src/Components/OpeningHours/OpeningHours.module.scss index 5a5822013..a62f5a46d 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.module.scss +++ b/frontend/src/Components/OpeningHours/OpeningHours.module.scss @@ -2,7 +2,6 @@ @use 'src/mixins' as *; .container { - background-color: $white; text-align: center; margin-bottom: 20px; display: flex; From f14c2a2cc2195f032f3d537732851b1f39327331 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 23 Sep 2025 21:40:36 +0200 Subject: [PATCH 03/48] Revise Venue Opening Dto --- backend/root/utils/routes.py | 1 + .../OpeningHours/OpeningHours.stories.tsx | 11 +++++------ .../src/Components/OpeningHours/OpeningHours.tsx | 13 ++++++------- frontend/src/dto.ts | 6 ++++++ 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/backend/root/utils/routes.py b/backend/root/utils/routes.py index 880250448..ebe6d0f60 100644 --- a/backend/root/utils/routes.py +++ b/backend/root/utils/routes.py @@ -486,6 +486,7 @@ samfundet__eventgroups_detail = 'samfundet:eventgroups-detail' samfundet__venues_list = 'samfundet:venues-list' samfundet__venues_detail = 'samfundet:venues-detail' +samfundet__venues_open_today = 'samfundet:venues_open_today' samfundet__closedperiods_list = 'samfundet:closedperiods-list' samfundet__closedperiods_detail = 'samfundet:closedperiods-detail' samfundet__gangs_list = 'samfundet:gangs-list' diff --git a/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx b/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx index 71e1162a8..2bf56de89 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx @@ -16,13 +16,12 @@ export const Basic: Story = { venues: [ { name: 'Daglighallen', - url: 'www.google.com', - start: '2011-10-05T14:00:00.000Z', - end: '2011-10-05T17:00:00.000Z', + opening: '2011-10-05T14:00:00.000Z', + closing: '2011-10-05T17:00:00.000Z', }, - { name: 'Edgar', url: 'www.google.com', start: '2011-10-05T12:00:00.000Z', end: '2011-10-05T17:00:00.000Z' }, - { name: 'Klubben', url: 'www.google.com', start: '2011-10-05T16:00:00.000Z', end: '2011-10-05T18:00:00.000Z' }, - { name: 'Storsalen', url: 'www.google.com', start: '2011-10-05T14:00:00.000Z', end: '2011-10-05T22:00:00.000Z' }, + { name: 'Edgar', opening: '2011-10-05T12:00:00.000Z', closing: '2011-10-05T17:00:00.000Z' }, + { name: 'Klubben', opening: '2011-10-05T16:00:00.000Z', closing: '2011-10-05T18:00:00.000Z' }, + { name: 'Storsalen', opening: '2011-10-05T14:00:00.000Z', closing: '2011-10-05T22:00:00.000Z' }, ], }, }; diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index fd568954b..d93cf76b8 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -5,15 +5,14 @@ import { TimeDuration } from '~/Components'; import { KEY } from '~/i18n/constants'; import styles from './OpeningHours.module.scss'; -type FakeVenue = { +type VenueOpeningProp = { name: string; - url: string; - start: string; - end: string; + opening: string; + closing: string; }; type OpeningHoursProps = { - venues: FakeVenue[]; + venues: VenueOpeningProp[]; }; export function OpeningHours({ venues }: OpeningHoursProps) { @@ -25,12 +24,12 @@ export function OpeningHours({ venues }: OpeningHoursProps) { {venues.map((venue) => (
- +

{venue.name}

- +
- {venues.map((venue) => ( - - - - - ))} + {venues.map((venue) => { + const openingTime = venue[`opening_${day}` as keyof VenueDto] as string; + const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; + return ( + + + + + ); + })}
- -

{venue.name}

- -
- -
+ +

{venue.name}

+ +
+ +
); diff --git a/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx index 10a90ed62..88c5232e7 100644 --- a/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx @@ -1,38 +1,13 @@ import { useQuery } from '@tanstack/react-query'; -import { useTranslation } from 'react-i18next'; import { getOpenVenues } from '~/api'; -import { Text } from '~/Components/Text'; import { VenueDto } from '~/dto'; -import { KEY } from '~/i18n/constants'; import { OpeningHours } from './OpeningHours'; export function OpeningHoursContainer() { - const { t } = useTranslation(); const { data: openVenues, isLoading, isError } = useQuery({ queryKey: ['openVenues'], queryFn: getOpenVenues, }); - if (isLoading) { - return {t(KEY.common_loading)}; - } - - if (isError || !openVenues) { - return {t(KEY.error_generic)}; - } - - const today = new Date().toISOString().split('T')[0]; - const day = new Date().toLocaleDateString('en-US', { weekday: 'long' }).toLowerCase(); - - const venues = openVenues.map((venue) => { - const openingTime = venue[`opening_${day}` as keyof VenueDto] as string; - const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; - return { - name: venue.name, - opening: `${today}T${openingTime}`, - closing: `${today}T${closingTime}`, - }; - }); - - return ; + return ; } From fcb4de4ed10558f39ec7f3a7e0ae6f702f4aea74 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 2 Oct 2025 18:32:45 +0200 Subject: [PATCH 12/48] Remove OpeningHoursContainer from HomePage --- frontend/src/Pages/HomePage/HomePage.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index 4e637006c..cb675d67a 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { OpeningHoursContainer } from '~/Components/OpeningHours/OpeningHoursContainer'; import { EventCarousel, LargeCard } from '~/Pages/HomePage/components'; import { getHomeData } from '~/api'; import type { HomePageDto, HomePageElementDto } from '~/dto'; @@ -53,7 +52,6 @@ export function HomePage() { <>
- {/**/} {isLoading && skeleton} From dc90eb25af3295ab071173fbd0c761270537d9c5 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 2 Oct 2025 18:50:17 +0200 Subject: [PATCH 13/48] BIOMEEEEEE --- frontend/src/Components/OpeningHours/OpeningHours.tsx | 4 ++-- .../src/Components/OpeningHours/OpeningHoursContainer.tsx | 8 ++++++-- frontend/src/api.ts | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 6fb1162b0..d1290edcb 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'; import { TimeDuration } from '~/Components'; import { Link } from '~/Components/Link/Link'; import { Text } from '~/Components/Text/Text'; -import { VenueDto } from '~/dto'; +import type { VenueDto } from '~/dto'; import { KEY } from '~/i18n/constants'; import styles from './OpeningHours.module.scss'; @@ -38,7 +38,7 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) return ( - +

{venue.name}

diff --git a/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx index 88c5232e7..65bbb7c46 100644 --- a/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHoursContainer.tsx @@ -1,10 +1,14 @@ import { useQuery } from '@tanstack/react-query'; import { getOpenVenues } from '~/api'; -import { VenueDto } from '~/dto'; +import type { VenueDto } from '~/dto'; import { OpeningHours } from './OpeningHours'; export function OpeningHoursContainer() { - const { data: openVenues, isLoading, isError } = useQuery({ + const { + data: openVenues, + isLoading, + isError, + } = useQuery({ queryKey: ['openVenues'], queryFn: getOpenVenues, }); diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 8987d63c9..1b4982be9 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -19,7 +19,6 @@ import type { MenuDto, MenuItemDto, OccupiedTimeslotDto, - OpenVenuesDto, OrganizationDto, PermissionDto, PositionsByTagResponse, From 28806264a30f211a23c72ce97949a94ce38d8b9d Mon Sep 17 00:00:00 2001 From: eilifhl Date: Thu, 2 Oct 2025 19:14:44 +0200 Subject: [PATCH 14/48] STYLELIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIINTTTTTT --- .../Components/OpeningHours/OpeningHours.module.scss | 10 +++++----- frontend/src/Components/OpeningHours/OpeningHours.tsx | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.module.scss b/frontend/src/Components/OpeningHours/OpeningHours.module.scss index a62f5a46d..f238771f0 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.module.scss +++ b/frontend/src/Components/OpeningHours/OpeningHours.module.scss @@ -1,4 +1,5 @@ @use 'src/constants' as *; + @use 'src/mixins' as *; .container { @@ -8,10 +9,10 @@ flex-direction: column; align-items: center; - & td { - border-left: 0; - border-right: 0; -} + .tableCell { + border-left: 0; + border-right: 0; + } @include theme-dark { background-color: $black-2; @@ -19,7 +20,6 @@ } } - .openingHoursText { margin: 0 0.2em; } diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index d1290edcb..01d9f3925 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -37,12 +37,12 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; return ( - +

{venue.name}

- + Date: Thu, 2 Oct 2025 19:47:59 +0200 Subject: [PATCH 15/48] Add correct storybook data --- .../OpeningHours/OpeningHours.stories.tsx | 78 +++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx b/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx index 2bf56de89..4a3a13132 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.stories.tsx @@ -15,13 +15,81 @@ export const Basic: Story = { args: { venues: [ { + id: 1, + slug: 'daglighallen', name: 'Daglighallen', - opening: '2011-10-05T14:00:00.000Z', - closing: '2011-10-05T17:00:00.000Z', + opening_monday: '08:00:00', + closing_monday: '20:00:00', + opening_tuesday: '08:00:00', + closing_tuesday: '20:00:00', + opening_wednesday: '08:00:00', + closing_wednesday: '20:00:00', + opening_thursday: '08:00:00', + closing_thursday: '20:00:00', + opening_friday: '08:00:00', + closing_friday: '20:00:00', + opening_saturday: '08:00:00', + closing_saturday: '20:00:00', + opening_sunday: '08:00:00', + closing_sunday: '20:00:00', + }, + { + id: 2, + slug: 'edgar', + name: 'Edgar', + opening_monday: '08:00:00', + closing_monday: '20:00:00', + opening_tuesday: '08:00:00', + closing_tuesday: '20:00:00', + opening_wednesday: '08:00:00', + closing_wednesday: '20:00:00', + opening_thursday: '08:00:00', + closing_thursday: '20:00:00', + opening_friday: '08:00:00', + closing_friday: '20:00:00', + opening_saturday: '08:00:00', + closing_saturday: '20:00:00', + opening_sunday: '08:00:00', + closing_sunday: '20:00:00', + }, + { + id: 3, + slug: 'klubben', + name: 'Klubben', + opening_monday: '08:00:00', + closing_monday: '20:00:00', + opening_tuesday: '08:00:00', + closing_tuesday: '20:00:00', + opening_wednesday: '08:00:00', + closing_wednesday: '20:00:00', + opening_thursday: '08:00:00', + closing_thursday: '20:00:00', + opening_friday: '08:00:00', + closing_friday: '20:00:00', + opening_saturday: '08:00:00', + closing_saturday: '20:00:00', + opening_sunday: '08:00:00', + closing_sunday: '20:00:00', + }, + { + id: 4, + slug: 'storsalen', + name: 'Storsalen', + opening_monday: '08:00:00', + closing_monday: '20:00:00', + opening_tuesday: '08:00:00', + closing_tuesday: '20:00:00', + opening_wednesday: '08:00:00', + closing_wednesday: '20:00:00', + opening_thursday: '08:00:00', + closing_thursday: '20:00:00', + opening_friday: '08:00:00', + closing_friday: '20:00:00', + opening_saturday: '08:00:00', + closing_saturday: '20:00:00', + opening_sunday: '08:00:00', + closing_sunday: '20:00:00', }, - { name: 'Edgar', opening: '2011-10-05T12:00:00.000Z', closing: '2011-10-05T17:00:00.000Z' }, - { name: 'Klubben', opening: '2011-10-05T16:00:00.000Z', closing: '2011-10-05T18:00:00.000Z' }, - { name: 'Storsalen', opening: '2011-10-05T14:00:00.000Z', closing: '2011-10-05T22:00:00.000Z' }, ], }, }; From 4779db94063f28a285eef6dbde716f62e5bb4588 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 2 Oct 2025 21:18:52 +0200 Subject: [PATCH 16/48] added edit button inside of event page --- .../src/Pages/EventPage/EventPage.module.scss | 21 ++++++++++++++++++- frontend/src/Pages/EventPage/EventPage.tsx | 9 ++++++++ frontend/src/Pages/HomePage/HomePage.tsx | 15 +++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/frontend/src/Pages/EventPage/EventPage.module.scss b/frontend/src/Pages/EventPage/EventPage.module.scss index 7d3abf0d8..0d228720e 100644 --- a/frontend/src/Pages/EventPage/EventPage.module.scss +++ b/frontend/src/Pages/EventPage/EventPage.module.scss @@ -2,6 +2,25 @@ @use 'src/constants' as *; +.admin_panel { + margin: 10px 0 10px 0; + padding: 10px 20px; + border-radius: 5px; + color: white; + background: $red_samf; + cursor: pointer; + transition: all 200ms ease-in-out; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + text-decoration: none; +} + +.admin_panel:hover { + background: lighten($red_samf, 10%); + box-shadow: rgba(0, 0, 0, 0.24) 0px 5px 8px; + text-decoration: none; + scale: 1.05; +} + .container { width: 100%; height: 100%; @@ -74,4 +93,4 @@ padding: 0 0.15rem 0 0.25rem; border: 1px solid $black; border-radius: 2rem; -} \ No newline at end of file +} diff --git a/frontend/src/Pages/EventPage/EventPage.tsx b/frontend/src/Pages/EventPage/EventPage.tsx index b47e3f85b..6af21f822 100644 --- a/frontend/src/Pages/EventPage/EventPage.tsx +++ b/frontend/src/Pages/EventPage/EventPage.tsx @@ -13,10 +13,13 @@ import { dbT } from '~/utils'; import styles from './EventPage.module.scss'; import { EventInformation } from './components/EventInformation/EventInformation'; import { EventTable } from './components/EventTable'; +import { useAuthContext } from '~/context/AuthContext'; export function EventPage() { const { t } = useTranslation(); const { id } = useParams(); + const { user } = useAuthContext(); + const isStaff = user?.is_staff; const { data: event, isLoading } = useQuery({ queryKey: id ? eventKeys.detail(Number(id)) : ['events', 'no-id'], @@ -31,6 +34,12 @@ export function EventPage() { {event && }
+ { isStaff && + + Rediger + + } +

{dbT(event, 'title')}

{event && } diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index cb675d67a..6023343d8 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -9,6 +9,7 @@ import { KEY } from '~/i18n/constants'; import type { Children } from '~/types'; import styles from './HomePage.module.scss'; import { Splash } from './components/Splash/Splash'; +import { OpeningHours } from '~/Components'; export function HomePage() { const [homePage, setHomePage] = useState(); @@ -48,6 +49,11 @@ export function HomePage() { ); + const s = new Date(); + const e = new Date(); + s.setHours(16, 0, 0, 0); + e.setHours(21, 0, 0, 0); + return ( <> @@ -55,6 +61,15 @@ export function HomePage() { {/**/} {isLoading && skeleton} +
+ +
+ {/* Render elements for frontpage. */} {homePage?.elements.map((el, index) => renderElement(index, el))}
From 5dde5b1371fc16c7c655cbcb2fa37d2f1f94ca9e Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 2 Oct 2025 21:43:51 +0200 Subject: [PATCH 17/48] added edit button to image card in events page --- .../ImageCard/ImageCard.module.scss | 27 +++++++++++++++++++ .../src/Components/ImageCard/ImageCard.tsx | 13 ++++++++- .../src/Pages/EventPage/EventPage.module.scss | 1 + frontend/src/Pages/EventPage/EventPage.tsx | 5 ++-- .../components/EventsList/EventsList.tsx | 1 + 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index 4c017eece..4483fc232 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -186,3 +186,30 @@ $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); max-height: 0; } } + +.badges { + display: flex; + align-items: center; + justify-content: space-between; +} + +.admin_edit_button { + border-radius: 5px; + width: fit-content; + padding: 5px; + color: white; + font-size: 10px; + background: $red_samf; + cursor: pointer; + transition: all 200ms ease-in-out; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + text-decoration: none; + z-index: 10; +} + +.admin_edit_button:hover { + background: lighten($red_samf, 10%); + box-shadow: rgba(0, 0, 0, 0.24) 0px 5px 8px; + text-decoration: none; + scale: 1.05; +} diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index ff21c2625..117d594cf 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -10,12 +10,14 @@ import { Badge } from '../Badge'; import { Link } from '../Link'; import { TimeDisplay } from '../TimeDisplay'; import styles from './ImageCard.module.scss'; +import { useAuthContext } from '~/context/AuthContext'; type ImageCardProps = { className?: string; title?: ReactNode; subtitle?: ReactNode; description?: ReactNode; + id?: number; date?: string | Date; url?: string; imageUrl?: string; @@ -33,6 +35,7 @@ export function ImageCard({ subtitle = , description = , date, + id, url = '#', imageUrl, compact, @@ -47,6 +50,8 @@ export function ImageCard({ const [displayTicketType, setTicketType] = useState(''); const [showTicket, setShowTicket] = useState(false); + const { user } = useAuthContext(); + const isStaff = user?.is_staff; useEffect(() => { if (ticket_type === EventTicketType.FREE || ticket_type === EventTicketType.REGISTRATION) { @@ -70,7 +75,12 @@ export function ImageCard({
-
+
+ {isStaff && + + Rediger + + } {showTicket && }
@@ -79,6 +89,7 @@ export function ImageCard({
{title}
{subtitle} +
{date && }
diff --git a/frontend/src/Pages/EventPage/EventPage.module.scss b/frontend/src/Pages/EventPage/EventPage.module.scss index 0d228720e..ad4613c29 100644 --- a/frontend/src/Pages/EventPage/EventPage.module.scss +++ b/frontend/src/Pages/EventPage/EventPage.module.scss @@ -12,6 +12,7 @@ transition: all 200ms ease-in-out; box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; text-decoration: none; + z-index: 10; } .admin_panel:hover { diff --git a/frontend/src/Pages/EventPage/EventPage.tsx b/frontend/src/Pages/EventPage/EventPage.tsx index 6af21f822..e1a870dfa 100644 --- a/frontend/src/Pages/EventPage/EventPage.tsx +++ b/frontend/src/Pages/EventPage/EventPage.tsx @@ -14,6 +14,7 @@ import styles from './EventPage.module.scss'; import { EventInformation } from './components/EventInformation/EventInformation'; import { EventTable } from './components/EventTable'; import { useAuthContext } from '~/context/AuthContext'; +import { Link } from '~/Components'; export function EventPage() { const { t } = useTranslation(); @@ -35,9 +36,9 @@ export function EventPage() {
{ isStaff && - + Rediger - + }

{dbT(event, 'title')}

diff --git a/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx b/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx index 0e9d70564..b30620878 100644 --- a/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx +++ b/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx @@ -83,6 +83,7 @@ export function EventsList({ events }: EventsListProps) { subtitle={time_display} description={dbT(event, 'description_short') ?? ''} compact={true} + id={event.id} url={reverse({ pattern: ROUTES.frontend.event, urlParams: { id: event.id } })} ticket_type={event.ticket_type} host={event.host} From b058f475889842ad66412a4ddb21785ef3257e34 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 2 Oct 2025 21:44:11 +0200 Subject: [PATCH 18/48] fixes --- frontend/src/Components/ImageCard/ImageCard.module.scss | 1 - .../Pages/HomePage/components/EventCarousel/EventCarousel.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index 4483fc232..13f14ed4d 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -204,7 +204,6 @@ $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); transition: all 200ms ease-in-out; box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; text-decoration: none; - z-index: 10; } .admin_edit_button:hover { diff --git a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx index 28bd7f3a8..1a107fd8d 100644 --- a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx +++ b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx @@ -49,6 +49,7 @@ export function EventCarousel({ element, skeletonCount = 0 }: EventCarouselProps return ( Date: Thu, 2 Oct 2025 21:52:18 +0200 Subject: [PATCH 19/48] fixed stylelint problems --- .../Components/ImageCard/ImageCard.module.scss | 6 +++--- .../src/Components/ImageCard/ImageCard.tsx | 8 ++++---- .../src/Pages/EventPage/EventPage.module.scss | 6 +++--- frontend/src/Pages/EventPage/EventPage.tsx | 8 ++++---- frontend/src/Pages/HomePage/HomePage.tsx | 18 +++++++++++------- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index 13f14ed4d..e3041e86e 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -202,13 +202,13 @@ $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); background: $red_samf; cursor: pointer; transition: all 200ms ease-in-out; - box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px; text-decoration: none; } .admin_edit_button:hover { - background: lighten($red_samf, 10%); - box-shadow: rgba(0, 0, 0, 0.24) 0px 5px 8px; + filter: brightness(120%); + box-shadow: rgba(0, 0, 0, 0.24) 0 5px 8px; text-decoration: none; scale: 1.05; } diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index 117d594cf..1ed0e67fd 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -3,6 +3,7 @@ import { t } from 'i18next'; import type { ReactNode } from 'react'; import { useEffect, useState } from 'react'; import { Skeleton } from '~/Components'; +import { useAuthContext } from '~/context/AuthContext'; import { KEY } from '~/i18n/constants'; import { type Children, EventTicketType } from '~/types'; import { backgroundImageFromUrl } from '~/utils'; @@ -10,7 +11,6 @@ import { Badge } from '../Badge'; import { Link } from '../Link'; import { TimeDisplay } from '../TimeDisplay'; import styles from './ImageCard.module.scss'; -import { useAuthContext } from '~/context/AuthContext'; type ImageCardProps = { className?: string; @@ -76,11 +76,11 @@ export function ImageCard({
- {isStaff && + {isStaff && ( Rediger - } + )} {showTicket && }
@@ -89,7 +89,7 @@ export function ImageCard({
{title}
{subtitle} - +
{date && }
diff --git a/frontend/src/Pages/EventPage/EventPage.module.scss b/frontend/src/Pages/EventPage/EventPage.module.scss index ad4613c29..9c1558532 100644 --- a/frontend/src/Pages/EventPage/EventPage.module.scss +++ b/frontend/src/Pages/EventPage/EventPage.module.scss @@ -10,14 +10,14 @@ background: $red_samf; cursor: pointer; transition: all 200ms ease-in-out; - box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px; text-decoration: none; z-index: 10; } .admin_panel:hover { - background: lighten($red_samf, 10%); - box-shadow: rgba(0, 0, 0, 0.24) 0px 5px 8px; + filter: brightness(120%); + box-shadow: rgba(0, 0, 0, 0.24) 0 5px 8px; text-decoration: none; scale: 1.05; } diff --git a/frontend/src/Pages/EventPage/EventPage.tsx b/frontend/src/Pages/EventPage/EventPage.tsx index e1a870dfa..2607c2927 100644 --- a/frontend/src/Pages/EventPage/EventPage.tsx +++ b/frontend/src/Pages/EventPage/EventPage.tsx @@ -2,10 +2,12 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; import { ExpandableHeader, ExternalHostBox, H1, Image, Page } from '~/Components'; +import { Link } from '~/Components'; import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; import { SamfMarkdown } from '~/Components/SamfMarkdown'; import { getEvent } from '~/api'; import { BACKEND_DOMAIN } from '~/constants'; +import { useAuthContext } from '~/context/AuthContext'; import { useTitle } from '~/hooks'; import { KEY } from '~/i18n/constants'; import { eventKeys } from '~/queryKeys'; @@ -13,8 +15,6 @@ import { dbT } from '~/utils'; import styles from './EventPage.module.scss'; import { EventInformation } from './components/EventInformation/EventInformation'; import { EventTable } from './components/EventTable'; -import { useAuthContext } from '~/context/AuthContext'; -import { Link } from '~/Components'; export function EventPage() { const { t } = useTranslation(); @@ -35,11 +35,11 @@ export function EventPage() { {event && }
- { isStaff && + {isStaff && ( Rediger - } + )}

{dbT(event, 'title')}

diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index 6023343d8..155ea88aa 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; +import { OpeningHours } from '~/Components'; import { EventCarousel, LargeCard } from '~/Pages/HomePage/components'; import { getHomeData } from '~/api'; import type { HomePageDto, HomePageElementDto } from '~/dto'; @@ -9,7 +10,6 @@ import { KEY } from '~/i18n/constants'; import type { Children } from '~/types'; import styles from './HomePage.module.scss'; import { Splash } from './components/Splash/Splash'; -import { OpeningHours } from '~/Components'; export function HomePage() { const [homePage, setHomePage] = useState(); @@ -62,12 +62,16 @@ export function HomePage() { {isLoading && skeleton}
- +
{/* Render elements for frontpage. */} From 388bed04b6fee12a10d8aba3cf43cc92fb913dce Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 7 Oct 2025 21:06:11 +0200 Subject: [PATCH 20/48] Fix styling of tableCell border --- .../OpeningHours/OpeningHours.module.scss | 13 ++++++++----- .../src/Components/OpeningHours/OpeningHours.tsx | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.module.scss b/frontend/src/Components/OpeningHours/OpeningHours.module.scss index f238771f0..25bf61013 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.module.scss +++ b/frontend/src/Components/OpeningHours/OpeningHours.module.scss @@ -9,17 +9,20 @@ flex-direction: column; align-items: center; - .tableCell { - border-left: 0; - border-right: 0; - } - @include theme-dark { background-color: $black-2; color: $white; } } +.tableCell { + @include theme-dark { + border-left: 0; + border-right: 0; + } +} + .openingHoursText { margin: 0 0.2em; } + diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 01d9f3925..6c4e9b57e 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -37,12 +37,12 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; return ( - +

{venue.name}

- + Date: Tue, 7 Oct 2025 22:03:54 +0200 Subject: [PATCH 21/48] Venues with midnight opening, closing are closed --- backend/samfundet/view/general_views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/samfundet/view/general_views.py b/backend/samfundet/view/general_views.py index 2e440a688..8c32afcda 100644 --- a/backend/samfundet/view/general_views.py +++ b/backend/samfundet/view/general_views.py @@ -4,6 +4,7 @@ from __future__ import annotations from typing import Any +from datetime import time from itertools import chain from rest_framework import status @@ -115,13 +116,12 @@ class VenueView(ModelViewSet): @action(detail=False, methods=['get']) def open_venues(self, request: Request) -> Response: - now = timezone.now() - day_name = now.strftime('%A').lower() + day_name = timezone.now().strftime('%A').lower() - q = Q( + q = ~Q( **{ - f'opening_{day_name}__lte': now.time(), - f'closing_{day_name}__gte': now.time(), + f'opening_{day_name}': time(0, 0, 0), + f'closing_{day_name}': time(0, 0, 0), } ) From c57912f41c24e32421d1fc72b643d5021b30b217 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 9 Oct 2025 20:09:53 +0200 Subject: [PATCH 22/48] Added event edit, delete and django access buttons on event card and page --- .../EventEditButtons.module.scss | 48 +++++++++++++ .../EventEditButtons.stories.tsx | 21 ++++++ .../EventEditButtons/EventEditButtons.tsx | 68 +++++++++++++++++++ .../src/Components/EventEditButtons/index.ts | 1 + .../ImageCard/ImageCard.module.scss | 42 +++++++----- .../src/Components/ImageCard/ImageCard.tsx | 21 +++--- frontend/src/Components/index.ts | 1 + .../src/Pages/EventPage/EventPage.module.scss | 20 ++---- frontend/src/Pages/EventPage/EventPage.tsx | 16 +++-- .../EventCarousel/EventCarousel.tsx | 34 ++-------- 10 files changed, 193 insertions(+), 79 deletions(-) create mode 100644 frontend/src/Components/EventEditButtons/EventEditButtons.module.scss create mode 100644 frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx create mode 100644 frontend/src/Components/EventEditButtons/EventEditButtons.tsx create mode 100644 frontend/src/Components/EventEditButtons/index.ts diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss b/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss new file mode 100644 index 000000000..630828e91 --- /dev/null +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss @@ -0,0 +1,48 @@ +.edit_icon { + color: white; + filter: brightness(1000%); + transition: all 200ms ease-in-out; +} + +.edit_button:hover { + .edit_icon { + rotate: 15deg; + } +} + +.edit_button { + pointer-events:all; + z-index: 10; + border-radius: 30%; + width: fit-content; + padding: 4px; + color: white; + cursor: pointer; + transition: all 200ms ease-in-out; + box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px; + text-decoration: none; +} + +.edit_button:hover { + scale: 1.1; + filter: brightness(110%); +} + +.default_edit { + @extend .edit_button; + background: #3498db; +} + +.detail_edit { + @extend .edit_button; + background: teal; +} + +.delete_edit { + @extend .edit_button; + background: crimson; + appearance: none; + border: none; +} + + diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx new file mode 100644 index 000000000..237c48083 --- /dev/null +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx @@ -0,0 +1,21 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { EventEditButtons } from './EventEditButtons'; + +// Local component config. +const meta: Meta = { + title: 'Components/Video', + component: EventEditButtons, + args: { + title: 'Approve', + }, +}; + +export default meta; + +type Story = StoryObj; + +//export const Basic: Story = { + // args: { + // embedId: '88kgbMcDIQ4', + //}, +//}; diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx new file mode 100644 index 000000000..550cdfcb5 --- /dev/null +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx @@ -0,0 +1,68 @@ +import styles from './EventEditButtons.module.scss'; +import { useAuthContext } from '~/context/AuthContext'; +import { hasPerm } from '~/utils'; +import { reverse } from '~/named-urls'; +import { PERM } from '~/permissions'; +import { ROUTES } from '~/routes'; +import { Link } from '../Link'; +import { Icon } from '@iconify/react'; +import { deleteEvent } from '~/api'; +import type { ReactNode } from 'react'; + +type EventEditButtons = { + title?: ReactNode; + id?: string; + icon_size?: number; +}; + +/** Component for displaying a youtube video */ +export function EventEditButtons({ title = "event", id, icon_size = 17 }: EventEditButtons) { + const { user } = useAuthContext(); + const isStaff = user?.is_staff; + const canChangeEvent = hasPerm({ user: user, permission: PERM.SAMFUNDET_CHANGE_EVENT, obj: id }); + + const editUrl = reverse({ pattern: ROUTES.frontend.admin_events_edit, urlParams: { id: id } }); + const detailUrl = reverse({ + pattern: ROUTES.backend.admin__samfundet_event_change, + urlParams: { objectId: id }, + }); + + return ( + <> + {canChangeEvent && ( + + + + )} + {canChangeEvent && ( + + )} + {isStaff && canChangeEvent && ( + + + + )} + + ); +} diff --git a/frontend/src/Components/EventEditButtons/index.ts b/frontend/src/Components/EventEditButtons/index.ts new file mode 100644 index 000000000..c6d7a1689 --- /dev/null +++ b/frontend/src/Components/EventEditButtons/index.ts @@ -0,0 +1 @@ +export { EventEditButtons } from "./EventEditButtons" diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index e3041e86e..4aa89f020 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -16,9 +16,11 @@ $card-text-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5); $card-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2); $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); +$inner-card-padding: 0.75rem; // TODO color variables .container { + position: relative; display: flex; flex-direction: column; align-items: stretch; @@ -55,7 +57,7 @@ $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); display: flex; justify-content: space-between; flex-direction: column; - padding: 0.75rem; + padding: $inner-card-padding; } .card_content { @@ -193,22 +195,30 @@ $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); justify-content: space-between; } -.admin_edit_button { - border-radius: 5px; - width: fit-content; - padding: 5px; - color: white; - font-size: 10px; - background: $red_samf; - cursor: pointer; +.edit_bar { + opacity: 0%; + position: absolute; + display: flex; + flex-direction: row; + justify-content: end; + gap: 10px; + padding-right: 13px; + align-items: end; + width: 100%; + height: 55%; + pointer-events: none; + margin-left: 20px; + transition: all 200ms ease-in-out; - box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px; - text-decoration: none; + + z-index: 10; } -.admin_edit_button:hover { - filter: brightness(120%); - box-shadow: rgba(0, 0, 0, 0.24) 0 5px 8px; - text-decoration: none; - scale: 1.05; +.container:hover { + .edit_bar { + opacity: 100%; + margin-left: 0; + } } + + diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index 1ed0e67fd..bb4e8dfb8 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -3,7 +3,6 @@ import { t } from 'i18next'; import type { ReactNode } from 'react'; import { useEffect, useState } from 'react'; import { Skeleton } from '~/Components'; -import { useAuthContext } from '~/context/AuthContext'; import { KEY } from '~/i18n/constants'; import { type Children, EventTicketType } from '~/types'; import { backgroundImageFromUrl } from '~/utils'; @@ -11,13 +10,14 @@ import { Badge } from '../Badge'; import { Link } from '../Link'; import { TimeDisplay } from '../TimeDisplay'; import styles from './ImageCard.module.scss'; +import { EventEditButtons } from '~/Components'; type ImageCardProps = { className?: string; title?: ReactNode; subtitle?: ReactNode; description?: ReactNode; - id?: number; + id?: string; date?: string | Date; url?: string; imageUrl?: string; @@ -50,8 +50,8 @@ export function ImageCard({ const [displayTicketType, setTicketType] = useState(''); const [showTicket, setShowTicket] = useState(false); - const { user } = useAuthContext(); - const isStaff = user?.is_staff; + + const icon_size = compact ? 14 : 17; useEffect(() => { if (ticket_type === EventTicketType.FREE || ticket_type === EventTicketType.REGISTRATION) { @@ -73,23 +73,22 @@ export function ImageCard({ return (
+
+ +
- {isStaff && ( - - Rediger - - )} {showTicket && }
-
{children}
+
+ {children} +
{title}
{subtitle} -
{date && }
diff --git a/frontend/src/Components/index.ts b/frontend/src/Components/index.ts index 134bf2db1..48b28e293 100644 --- a/frontend/src/Components/index.ts +++ b/frontend/src/Components/index.ts @@ -89,6 +89,7 @@ export { ToolTip } from './ToolTip'; export { UkaOutlet } from './UkaOutlet'; export { UserFeedback } from './UserFeedback'; export { Video } from './Video'; +export { EventEditButtons } from "./EventEditButtons" // Props export type { ButtonProps } from './Button'; export type { CheckboxProps } from './Checkbox'; diff --git a/frontend/src/Pages/EventPage/EventPage.module.scss b/frontend/src/Pages/EventPage/EventPage.module.scss index 9c1558532..accc5c3cd 100644 --- a/frontend/src/Pages/EventPage/EventPage.module.scss +++ b/frontend/src/Pages/EventPage/EventPage.module.scss @@ -3,23 +3,11 @@ @use 'src/constants' as *; .admin_panel { - margin: 10px 0 10px 0; - padding: 10px 20px; - border-radius: 5px; + display: flex; + flex-direction: row; + gap: 20px; + margin: 15px 0 10px 0; color: white; - background: $red_samf; - cursor: pointer; - transition: all 200ms ease-in-out; - box-shadow: rgba(0, 0, 0, 0.24) 0 3px 8px; - text-decoration: none; - z-index: 10; -} - -.admin_panel:hover { - filter: brightness(120%); - box-shadow: rgba(0, 0, 0, 0.24) 0 5px 8px; - text-decoration: none; - scale: 1.05; } .container { diff --git a/frontend/src/Pages/EventPage/EventPage.tsx b/frontend/src/Pages/EventPage/EventPage.tsx index 2607c2927..0a9ad2c77 100644 --- a/frontend/src/Pages/EventPage/EventPage.tsx +++ b/frontend/src/Pages/EventPage/EventPage.tsx @@ -2,7 +2,6 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; import { ExpandableHeader, ExternalHostBox, H1, Image, Page } from '~/Components'; -import { Link } from '~/Components'; import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; import { SamfMarkdown } from '~/Components/SamfMarkdown'; import { getEvent } from '~/api'; @@ -15,12 +14,15 @@ import { dbT } from '~/utils'; import styles from './EventPage.module.scss'; import { EventInformation } from './components/EventInformation/EventInformation'; import { EventTable } from './components/EventTable'; +import { EventEditButtons } from '~/Components'; +import { hasPerm } from '~/utils'; +import { PERM } from '~/permissions'; export function EventPage() { const { t } = useTranslation(); const { id } = useParams(); const { user } = useAuthContext(); - const isStaff = user?.is_staff; + const canChangeEvent = hasPerm({ user: user, permission: PERM.SAMFUNDET_CHANGE_EVENT, obj: id }); const { data: event, isLoading } = useQuery({ queryKey: id ? eventKeys.detail(Number(id)) : ['events', 'no-id'], @@ -35,11 +37,11 @@ export function EventPage() { {event && }
- {isStaff && ( - - Rediger - - )} + { canChangeEvent && +
+ +
+ }

{dbT(event, 'title')}

diff --git a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx index 1a107fd8d..06b3dc5ad 100644 --- a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx +++ b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx @@ -1,13 +1,11 @@ -import { Carousel, IconButton, ImageCard } from '~/Components'; -import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; +import { Carousel, ImageCard } from '~/Components'; +// import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; import { BACKEND_DOMAIN } from '~/constants'; import { useAuthContext } from '~/context/AuthContext'; import type { EventDto, HomePageElementDto } from '~/dto'; import { reverse } from '~/named-urls'; -import { PERM } from '~/permissions'; import { ROUTES } from '~/routes'; -import { COLORS } from '~/types'; -import { dbT, hasPerm } from '~/utils'; +import { dbT } from '~/utils'; import styles from './EventCarousel.module.scss'; type EventCarouselProps = { @@ -37,19 +35,13 @@ export function EventCarousel({ element, skeletonCount = 0 }: EventCarouselProps {element.events.map((event: EventDto) => { const url = reverse({ pattern: ROUTES.frontend.event, urlParams: { id: event.id } }); - const editUrl = reverse({ pattern: ROUTES.frontend.admin_events_edit, urlParams: { id: event.id } }); - const detailurl = reverse({ - pattern: ROUTES.backend.admin__samfundet_event_change, - urlParams: { objectId: event.id }, - }); - const canChangeEvent = hasPerm({ user: user, permission: PERM.SAMFUNDET_CHANGE_EVENT, obj: event.id }); const event_title = dbT(event, 'title') ?? ''; const event_short_dsc = dbT(event, 'description_short') ?? ''; return ( } > - {event.billig && } - -
- {canChangeEvent && ( - - )} - {isStaff && canChangeEvent && ( - - )} -
); })} From b7cedc0b715b63cf618383daed6d9cd2d13c9e52 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 9 Oct 2025 20:15:51 +0200 Subject: [PATCH 23/48] fixed formatation --- .../EventEditButtons.module.scss | 8 ++-- .../EventEditButtons.stories.tsx | 6 +-- .../EventEditButtons/EventEditButtons.tsx | 36 +++++++------- .../src/Components/EventEditButtons/index.ts | 2 +- .../ImageCard/ImageCard.module.scss | 47 +++++++++---------- .../src/Components/ImageCard/ImageCard.tsx | 8 ++-- frontend/src/Components/index.ts | 2 +- frontend/src/Pages/EventPage/EventPage.tsx | 14 +++--- .../EventCarousel/EventCarousel.tsx | 3 +- 9 files changed, 56 insertions(+), 70 deletions(-) diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss b/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss index 630828e91..82ec1687c 100644 --- a/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.module.scss @@ -4,11 +4,6 @@ transition: all 200ms ease-in-out; } -.edit_button:hover { - .edit_icon { - rotate: 15deg; - } -} .edit_button { pointer-events:all; @@ -24,6 +19,9 @@ } .edit_button:hover { + .edit_icon { + rotate: 15deg; + } scale: 1.1; filter: brightness(110%); } diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx index 237c48083..5cc1cf666 100644 --- a/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx @@ -15,7 +15,7 @@ export default meta; type Story = StoryObj; //export const Basic: Story = { - // args: { - // embedId: '88kgbMcDIQ4', - //}, +// args: { +// embedId: '88kgbMcDIQ4', +//}, //}; diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx index 550cdfcb5..81ab46496 100644 --- a/frontend/src/Components/EventEditButtons/EventEditButtons.tsx +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx @@ -1,13 +1,13 @@ -import styles from './EventEditButtons.module.scss'; +import { Icon } from '@iconify/react'; +import type { ReactNode } from 'react'; +import { deleteEvent } from '~/api'; import { useAuthContext } from '~/context/AuthContext'; -import { hasPerm } from '~/utils'; import { reverse } from '~/named-urls'; import { PERM } from '~/permissions'; import { ROUTES } from '~/routes'; +import { hasPerm } from '~/utils'; import { Link } from '../Link'; -import { Icon } from '@iconify/react'; -import { deleteEvent } from '~/api'; -import type { ReactNode } from 'react'; +import styles from './EventEditButtons.module.scss'; type EventEditButtons = { title?: ReactNode; @@ -16,7 +16,7 @@ type EventEditButtons = { }; /** Component for displaying a youtube video */ -export function EventEditButtons({ title = "event", id, icon_size = 17 }: EventEditButtons) { +export function EventEditButtons({ title = 'event', id, icon_size = 17 }: EventEditButtons) { const { user } = useAuthContext(); const isStaff = user?.is_staff; const canChangeEvent = hasPerm({ user: user, permission: PERM.SAMFUNDET_CHANGE_EVENT, obj: id }); @@ -30,36 +30,32 @@ export function EventEditButtons({ title = "event", id, icon_size = 17 }: EventE return ( <> {canChangeEvent && ( - + )} {canChangeEvent && ( - )} {isStaff && canChangeEvent && ( - + )} diff --git a/frontend/src/Components/EventEditButtons/index.ts b/frontend/src/Components/EventEditButtons/index.ts index c6d7a1689..fff6f9987 100644 --- a/frontend/src/Components/EventEditButtons/index.ts +++ b/frontend/src/Components/EventEditButtons/index.ts @@ -1 +1 @@ -export { EventEditButtons } from "./EventEditButtons" +export { EventEditButtons } from './EventEditButtons'; diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index 4aa89f020..e44ceaa56 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -152,6 +152,23 @@ $inner-card-padding: 0.75rem; float: right; } +.edit_bar { + opacity: 0%; + position: absolute; + display: flex; + flex-direction: row; + justify-content: end; + gap: 10px; + padding-right: 13px; + align-items: end; + width: 100%; + height: 55%; + pointer-events: none; + margin-left: 20px; + transition: all 200ms ease-in-out; + z-index: 10; +} + // Styling to container and children when it is hovered. .container:hover { .edit_button { @@ -175,6 +192,10 @@ $inner-card-padding: 0.75rem; opacity: 1; max-height: 3.5em; } + .edit_bar { + opacity: 100%; + margin-left: 0; + } } // Compact doesn't show description on hover @@ -195,30 +216,4 @@ $inner-card-padding: 0.75rem; justify-content: space-between; } -.edit_bar { - opacity: 0%; - position: absolute; - display: flex; - flex-direction: row; - justify-content: end; - gap: 10px; - padding-right: 13px; - align-items: end; - width: 100%; - height: 55%; - pointer-events: none; - margin-left: 20px; - - transition: all 200ms ease-in-out; - - z-index: 10; -} - -.container:hover { - .edit_bar { - opacity: 100%; - margin-left: 0; - } -} - diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index bb4e8dfb8..4fbd9dc2f 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -3,6 +3,7 @@ import { t } from 'i18next'; import type { ReactNode } from 'react'; import { useEffect, useState } from 'react'; import { Skeleton } from '~/Components'; +import { EventEditButtons } from '~/Components'; import { KEY } from '~/i18n/constants'; import { type Children, EventTicketType } from '~/types'; import { backgroundImageFromUrl } from '~/utils'; @@ -10,7 +11,6 @@ import { Badge } from '../Badge'; import { Link } from '../Link'; import { TimeDisplay } from '../TimeDisplay'; import styles from './ImageCard.module.scss'; -import { EventEditButtons } from '~/Components'; type ImageCardProps = { className?: string; @@ -74,7 +74,7 @@ export function ImageCard({ return (
- +
@@ -82,9 +82,7 @@ export function ImageCard({ {showTicket && }
-
- {children} -
+
{children}
{title}
diff --git a/frontend/src/Components/index.ts b/frontend/src/Components/index.ts index 48b28e293..e42ba1d95 100644 --- a/frontend/src/Components/index.ts +++ b/frontend/src/Components/index.ts @@ -89,7 +89,7 @@ export { ToolTip } from './ToolTip'; export { UkaOutlet } from './UkaOutlet'; export { UserFeedback } from './UserFeedback'; export { Video } from './Video'; -export { EventEditButtons } from "./EventEditButtons" +export { EventEditButtons } from './EventEditButtons'; // Props export type { ButtonProps } from './Button'; export type { CheckboxProps } from './Checkbox'; diff --git a/frontend/src/Pages/EventPage/EventPage.tsx b/frontend/src/Pages/EventPage/EventPage.tsx index 0a9ad2c77..4b818832c 100644 --- a/frontend/src/Pages/EventPage/EventPage.tsx +++ b/frontend/src/Pages/EventPage/EventPage.tsx @@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; import { ExpandableHeader, ExternalHostBox, H1, Image, Page } from '~/Components'; +import { EventEditButtons } from '~/Components'; import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; import { SamfMarkdown } from '~/Components/SamfMarkdown'; import { getEvent } from '~/api'; @@ -9,14 +10,13 @@ import { BACKEND_DOMAIN } from '~/constants'; import { useAuthContext } from '~/context/AuthContext'; import { useTitle } from '~/hooks'; import { KEY } from '~/i18n/constants'; +import { PERM } from '~/permissions'; import { eventKeys } from '~/queryKeys'; import { dbT } from '~/utils'; +import { hasPerm } from '~/utils'; import styles from './EventPage.module.scss'; import { EventInformation } from './components/EventInformation/EventInformation'; import { EventTable } from './components/EventTable'; -import { EventEditButtons } from '~/Components'; -import { hasPerm } from '~/utils'; -import { PERM } from '~/permissions'; export function EventPage() { const { t } = useTranslation(); @@ -37,11 +37,11 @@ export function EventPage() { {event && }
- { canChangeEvent && + {canChangeEvent && (
- -
- } + +
+ )}

{dbT(event, 'title')}

diff --git a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx index 06b3dc5ad..4d3e3f634 100644 --- a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx +++ b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx @@ -52,8 +52,7 @@ export function EventCarousel({ element, skeletonCount = 0 }: EventCarouselProps ticket_type={event.ticket_type} host={event.host} // {event.billig && } - > - + > ); })} From 042e83b81e7d54ea02b364b45dedc82ab0ea2263 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 9 Oct 2025 20:19:35 +0200 Subject: [PATCH 24/48] fixed non selfClosing without children --- .../Pages/HomePage/components/EventCarousel/EventCarousel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx index 4d3e3f634..79359d75b 100644 --- a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx +++ b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx @@ -52,7 +52,7 @@ export function EventCarousel({ element, skeletonCount = 0 }: EventCarouselProps ticket_type={event.ticket_type} host={event.host} // {event.billig && } - > + /> ); })} From fa1d5e86d762d356ff9ded0d96eb6331ea42e1ad Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 9 Oct 2025 20:23:44 +0200 Subject: [PATCH 25/48] fixed typescript issue that appeared in another file --- .../src/Pages/EventsPage/components/EventsList/EventsList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx b/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx index b30620878..b6d2030b8 100644 --- a/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx +++ b/frontend/src/Pages/EventsPage/components/EventsList/EventsList.tsx @@ -83,7 +83,7 @@ export function EventsList({ events }: EventsListProps) { subtitle={time_display} description={dbT(event, 'description_short') ?? ''} compact={true} - id={event.id} + id={event.id.toString()} url={reverse({ pattern: ROUTES.frontend.event, urlParams: { id: event.id } })} ticket_type={event.ticket_type} host={event.host} From 1b2162037442e023f4b0fc6052b715cf33191fdd Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 16 Oct 2025 20:48:37 +0200 Subject: [PATCH 26/48] Opening hours now display a descriptiv message when samf is in a closed period --- .../OpeningHours/OpeningHours.module.scss | 8 +++ .../Components/OpeningHours/OpeningHours.tsx | 67 ++++++++++++------- frontend/src/Components/OpeningHours/index.ts | 1 + frontend/src/Components/index.ts | 2 +- frontend/src/Pages/HomePage/HomePage.tsx | 2 + frontend/src/api.ts | 1 + 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.module.scss b/frontend/src/Components/OpeningHours/OpeningHours.module.scss index 25bf61013..f0b7d6f8a 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.module.scss +++ b/frontend/src/Components/OpeningHours/OpeningHours.module.scss @@ -26,3 +26,11 @@ margin: 0 0.2em; } +.closedBox { + border: 2px $red_samf solid; + border-radius: 10px; + padding: 20px; + margin-bottom: 2rem; + margin-top: 1rem; +} + diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 6c4e9b57e..e20c802b9 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -1,9 +1,12 @@ +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { TimeDuration } from '~/Components'; import { Link } from '~/Components/Link/Link'; import { Text } from '~/Components/Text/Text'; +import { getClosedPeriods } from '~/api'; import type { VenueDto } from '~/dto'; import { KEY } from '~/i18n/constants'; +import { dbT } from '~/utils'; import styles from './OpeningHours.module.scss'; type OpeningHoursProps = { @@ -14,6 +17,21 @@ type OpeningHoursProps = { export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) { const { t } = useTranslation(); + const [isClosed, setIsClosed] = useState(false); + const [closedText, setClosedText] = useState('Samf is closed'); + + useEffect(() => { + getClosedPeriods().then((periods) => { + const now = new Date(); + for (const period of periods) { + if (new Date(period.start_dt) < now && now < new Date(period.end_dt)) { + setIsClosed(true); + setClosedText(dbT(period, 'description')); + break; + } + } + }); + }); if (isLoading) { return {t(KEY.common_loading)}; @@ -25,34 +43,37 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const today = new Date().toISOString().split('T')[0]; const day = new Date().toLocaleDateString('en-US', { weekday: 'long' }).toLowerCase(); - return (
{t(KEY.common_opening_hours)} - - {venues.map((venue) => { - const openingTime = venue[`opening_${day}` as keyof VenueDto] as string; - const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; - return ( - - - - - ); - })} -
- -

{venue.name}

- -
- -
+ {isClosed ? ( +
{closedText}
+ ) : ( + + {venues.map((venue) => { + const openingTime = venue[`opening_${day}` as keyof VenueDto] as string; + const closingTime = venue[`closing_${day}` as keyof VenueDto] as string; + return ( + + + + + ); + })} +
+ +

{venue.name}

+ +
+ +
+ )}
); } diff --git a/frontend/src/Components/OpeningHours/index.ts b/frontend/src/Components/OpeningHours/index.ts index beb1448d2..37a62d505 100644 --- a/frontend/src/Components/OpeningHours/index.ts +++ b/frontend/src/Components/OpeningHours/index.ts @@ -1 +1,2 @@ export { OpeningHours } from './OpeningHours'; +export { OpeningHoursContainer } from './OpeningHoursContainer'; diff --git a/frontend/src/Components/index.ts b/frontend/src/Components/index.ts index 134bf2db1..b42396548 100644 --- a/frontend/src/Components/index.ts +++ b/frontend/src/Components/index.ts @@ -48,7 +48,7 @@ export { Navbar } from './Navbar'; export { NotificationBadge } from './NotificationBadge'; export { NumberInput } from './NumberInput'; export { OccupiedForm, OccupiedFormModal } from './OccupiedForm'; -export { OpeningHours } from './OpeningHours'; +export { OpeningHours, OpeningHoursContainer } from './OpeningHours'; export { Page } from './Page'; export { PagedPagination } from './Pagination'; export { PermissionRoute } from './PermissionRoute'; diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index cb675d67a..6afbadbce 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; +import { OpeningHoursContainer } from '~/Components'; import { EventCarousel, LargeCard } from '~/Pages/HomePage/components'; import { getHomeData } from '~/api'; import type { HomePageDto, HomePageElementDto } from '~/dto'; @@ -51,6 +52,7 @@ export function HomePage() { return ( <> +
{/**/} {isLoading && skeleton} diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 1b4982be9..8fab91687 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -492,6 +492,7 @@ export async function putGang(id: string | number, data: Partial): Prom } export async function getClosedPeriods(): Promise { + // start_dt og end_dt er strings ikke Date -_- const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__closedperiods_list; const response = await axios.get(url, { withCredentials: true }); return response.data; From 1452dcf72e3e5760a0263716dd899f7268332230 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 16 Oct 2025 20:56:45 +0200 Subject: [PATCH 27/48] changed text used from description to message --- frontend/src/Components/OpeningHours/OpeningHours.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index e20c802b9..6148f3088 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -26,7 +26,7 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) for (const period of periods) { if (new Date(period.start_dt) < now && now < new Date(period.end_dt)) { setIsClosed(true); - setClosedText(dbT(period, 'description')); + setClosedText(dbT(period, 'message')); break; } } From f8ceeaa36d2a69b302b97f6d8076b25fa97894c0 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 16 Oct 2025 21:11:31 +0200 Subject: [PATCH 28/48] removed accidental openingHours in homepage --- frontend/src/Pages/HomePage/HomePage.tsx | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/frontend/src/Pages/HomePage/HomePage.tsx b/frontend/src/Pages/HomePage/HomePage.tsx index 155ea88aa..cb675d67a 100644 --- a/frontend/src/Pages/HomePage/HomePage.tsx +++ b/frontend/src/Pages/HomePage/HomePage.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { OpeningHours } from '~/Components'; import { EventCarousel, LargeCard } from '~/Pages/HomePage/components'; import { getHomeData } from '~/api'; import type { HomePageDto, HomePageElementDto } from '~/dto'; @@ -49,11 +48,6 @@ export function HomePage() { ); - const s = new Date(); - const e = new Date(); - s.setHours(16, 0, 0, 0); - e.setHours(21, 0, 0, 0); - return ( <> @@ -61,19 +55,6 @@ export function HomePage() { {/**/} {isLoading && skeleton} -
- -
- {/* Render elements for frontpage. */} {homePage?.elements.map((el, index) => renderElement(index, el))}
From 9da6fd786c0c6302fe1a8ff0e6244dff21f8ffad Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 21 Oct 2025 19:59:22 +0200 Subject: [PATCH 29/48] work in progress --- .../ClosedPeriodFormAdminPage.tsx | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index caaf9f9e2..9af154565 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -16,8 +16,6 @@ import styles from './ClosedPeriodFormAdminPage.module.scss'; type formType = { message_no: string; message_en: string; - description_no: string; - description_en: string; start_dt: Date; end_dt: Date; }; @@ -46,11 +44,10 @@ export function ClosedPeriodFormAdminPage() { getClosedPeriod(id) .then((data) => { // setClosedPeriod(data); For posting + console.log(data) setInitialData({ message_no: data.message_no, message_en: data.message_en, - description_no: data.description_no, - description_en: data.description_en, start_dt: new Date(data.start_dt), end_dt: new Date(data.end_dt), }); @@ -67,6 +64,7 @@ export function ClosedPeriodFormAdminPage() { }, [id]); function handleOnSubmit(data: formType) { + // handle invalid dates, handle conflicting dates, handle short messages if (id !== undefined) { // TODO patch data } else { @@ -77,7 +75,6 @@ export function ClosedPeriodFormAdminPage() { } const labelMessage = `${t(KEY.common_message)} under '${t(KEY.common_opening_hours)}'`; - const labelDescription = `${t(KEY.common_description)} under '${t(KEY.common_whatsup)}'`; const title = id ? t(KEY.admin_closed_period_edit_period) : t(KEY.admin_closed_period_new_period); useTitle(title); @@ -88,18 +85,6 @@ export function ClosedPeriodFormAdminPage() {
-
- - -
From fd87ed68dc7649724af9f77bb29c4e7b4c2eb42d Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 21 Oct 2025 21:07:05 +0200 Subject: [PATCH 30/48] ... --- backend/samfundet/models/general.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/samfundet/models/general.py b/backend/samfundet/models/general.py index 84f9461ca..203498420 100644 --- a/backend/samfundet/models/general.py +++ b/backend/samfundet/models/general.py @@ -255,11 +255,11 @@ def __str__(self) -> str: class ClosedPeriod(CustomBaseModel): - message_nb = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)') + message_no = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)') message_en = models.TextField(blank=True, null=True, verbose_name='Melding (engelsk)') - description_nb = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)') - description_en = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (engelsk)') + #description_no = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)') + #description_en = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (engelsk)') start_dt = models.DateField(blank=True, null=False, verbose_name='Start dato') end_dt = models.DateField(blank=True, null=False, verbose_name='Slutt dato') @@ -269,7 +269,7 @@ class Meta: verbose_name_plural = 'ClosedPeriods' def __str__(self) -> str: - return f'{self.message_nb} {self.start_dt}-{self.end_dt}' + return f'{self.message_no} {self.start_dt}-{self.end_dt}' # GANGS ### From 5b2cf308d0c5e0ce517088468cfcc85ba6809cb4 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 21 Oct 2025 21:24:18 +0200 Subject: [PATCH 31/48] renamed message_nb to message_no for consistancy. removed desvription as currently not in use, and not expected to be used --- ...ve_closedperiod_description_en_and_more.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py diff --git a/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py b/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py new file mode 100644 index 000000000..821b7f62f --- /dev/null +++ b/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.9 on 2025-10-21 19:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('samfundet', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='closedperiod', + name='description_en', + ), + migrations.RemoveField( + model_name='closedperiod', + name='description_nb', + ), + migrations.RemoveField( + model_name='closedperiod', + name='message_nb', + ), + migrations.AddField( + model_name='closedperiod', + name='message_no', + field=models.TextField(blank=True, null=True, verbose_name='Melding (norsk)'), + ), + ] From ab0969bc91feef3feea0ef62822636254e49b6fc Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 21 Oct 2025 21:59:26 +0200 Subject: [PATCH 32/48] begynnelse av data sjekk --- .../ClosedPeriodFormAdminPage.tsx | 27 ++++++++++++++++--- frontend/src/dto.ts | 4 +-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index 9af154565..39abef6da 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -16,8 +16,8 @@ import styles from './ClosedPeriodFormAdminPage.module.scss'; type formType = { message_no: string; message_en: string; - start_dt: Date; - end_dt: Date; + start_dt: string; + end_dt: string; }; export function ClosedPeriodFormAdminPage() { @@ -48,8 +48,8 @@ export function ClosedPeriodFormAdminPage() { setInitialData({ message_no: data.message_no, message_en: data.message_en, - start_dt: new Date(data.start_dt), - end_dt: new Date(data.end_dt), + start_dt: data.start_dt, + end_dt: data.end_dt, }); setShowSpinner(false); }) @@ -65,6 +65,25 @@ export function ClosedPeriodFormAdminPage() { function handleOnSubmit(data: formType) { // handle invalid dates, handle conflicting dates, handle short messages + const start_dt = new Date(data.start_dt) + const end_dt = new Date(data.end_dt) + const now = new Date() + + if (end_dt === start_dt) { + alert("end is equal to start, please set it to be more") + return + } + if (end_dt > start_dt) { + alert("end is less then start") + return + } + if (data.message_no.length <= 4) { + alert("message norsk må være lengere") + } + if (data.message_en.length <= 4) { + alert("message engelsk må være lengere") + } + if (id !== undefined) { // TODO patch data } else { diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 9ba1c2def..45da7ed74 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -358,8 +358,8 @@ export type ClosedPeriodDto = { description_no: string; message_en: string; description_en: string; - start_dt: Date; - end_dt: Date; + start_dt: string; + end_dt: string; }; export type TagDto = { From 0f257d0ae79a54c83d8d543c6321311dc9157135 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 28 Oct 2025 21:30:25 +0100 Subject: [PATCH 33/48] You can now safely post closedPeriods in the admin panal, aswell as it being shown as closed instead of opening hours under opening hours --- .../ClosedPeriodFormAdminPage.tsx | 52 ++++++++----------- frontend/src/api.ts | 2 +- frontend/src/dto.ts | 2 - 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index 39abef6da..e048b319a 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -5,13 +5,14 @@ import { useParams } from 'react-router'; import { toast } from 'react-toastify'; import { SamfForm } from '~/Forms/SamfForm'; import { SamfFormField } from '~/Forms/SamfFormField'; -import { getClosedPeriod } from '~/api'; +import { getClosedPeriod, postClosedPeriod, putClosedPeriod } from '~/api'; import { useCustomNavigate, useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; import { KEY } from '~/i18n/constants'; import { ROUTES } from '~/routes'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './ClosedPeriodFormAdminPage.module.scss'; +import { reverse } from '~/named-urls'; type formType = { message_no: string; @@ -31,6 +32,8 @@ export function ClosedPeriodFormAdminPage() { // If form has a id, check if it exists, and then load that item. const { id } = useParams(); + const min_length_message = 10; + // Stuff to do on first render. // TODO add permissions on render // biome-ignore lint/correctness/useExhaustiveDependencies: t and navigate do not need to be in deplist @@ -64,33 +67,22 @@ export function ClosedPeriodFormAdminPage() { }, [id]); function handleOnSubmit(data: formType) { - // handle invalid dates, handle conflicting dates, handle short messages - const start_dt = new Date(data.start_dt) - const end_dt = new Date(data.end_dt) - const now = new Date() - - if (end_dt === start_dt) { - alert("end is equal to start, please set it to be more") - return - } - if (end_dt > start_dt) { - alert("end is less then start") - return - } - if (data.message_no.length <= 4) { - alert("message norsk må være lengere") - } - if (data.message_en.length <= 4) { - alert("message engelsk må være lengere") - } - if (id !== undefined) { - // TODO patch data + putClosedPeriod(id, data) + .then() + .catch(err => { + alert(err) + }) } else { - // TODO post data + postClosedPeriod(data) + .then(() => { + toast.success(t(KEY.common_creation_successful)) + navigate({url: reverse({pattern: ROUTES.frontend.admin_closed})}) + }) + .catch(() => { + toast.error(t(KEY.common_something_went_wrong)) + }) } - alert('TODO Submit'); - console.log(JSON.stringify(data)); } const labelMessage = `${t(KEY.common_message)} under '${t(KEY.common_opening_hours)}'`; @@ -99,14 +91,14 @@ export function ClosedPeriodFormAdminPage() { return ( - + onSubmit={handleOnSubmit} initialData={initialData}>
- - + state.message_no.length > min_length_message} field="message_no" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_norwegian)})`} /> + state.message_en.length > min_length_message} field="message_en" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_english)})`} />
- - + state.end_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true} field="start_dt" type="date" label={`${t(KEY.start_time)}`} /> + state.start_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true} field="end_dt" type="date" label={`${t(KEY.end_time)}`} />
diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 8fab91687..b62329072 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -512,7 +512,7 @@ export async function putClosedPeriod(id: string | number, data: Partial { +export async function postClosedPeriod(data: Partial): Promise { const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__closedperiods_list; const response = await axios.post(url, data, { withCredentials: true }); return response.data; diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 45da7ed74..387ac46c6 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -355,9 +355,7 @@ export type GangSectionDto = { export type ClosedPeriodDto = { id: number; message_no: string; - description_no: string; message_en: string; - description_en: string; start_dt: string; end_dt: string; }; From 4509f482d60330633f69b7f75b52325ee8050625 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 28 Oct 2025 22:01:44 +0100 Subject: [PATCH 34/48] added a checkbox for making samf closed, needs to be implemented in more places then just openinghours as it uses the globalcontext --- .../Components/OpeningHours/OpeningHours.tsx | 7 +++++++ .../AdminPageLayout/AdminPageLayout.module.scss | 1 + .../ClosedPeriodAdminPage.module.scss | 9 +++++++++ .../ClosedPeriodAdminPage.tsx | 17 ++++++++++++----- frontend/src/api.ts | 1 - frontend/src/context/GlobalContextProvider.tsx | 14 ++++++++++++++ 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 6148f3088..103a744b1 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -7,6 +7,7 @@ import { getClosedPeriods } from '~/api'; import type { VenueDto } from '~/dto'; import { KEY } from '~/i18n/constants'; import { dbT } from '~/utils'; +import { useGlobalContext } from '~/context/GlobalContextProvider'; import styles from './OpeningHours.module.scss'; type OpeningHoursProps = { @@ -19,8 +20,14 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const { t } = useTranslation(); const [isClosed, setIsClosed] = useState(false); const [closedText, setClosedText] = useState('Samf is closed'); + const globalContext = useGlobalContext() useEffect(() => { + if (globalContext.isClosed) { + setIsClosed(true) + setClosedText("Samfundet is closed"); + return + } getClosedPeriods().then((periods) => { const now = new Date(); for (const period of periods) { diff --git a/frontend/src/PagesAdmin/AdminPageLayout/AdminPageLayout.module.scss b/frontend/src/PagesAdmin/AdminPageLayout/AdminPageLayout.module.scss index 92b3009ab..eb91dd4b8 100644 --- a/frontend/src/PagesAdmin/AdminPageLayout/AdminPageLayout.module.scss +++ b/frontend/src/PagesAdmin/AdminPageLayout/AdminPageLayout.module.scss @@ -36,6 +36,7 @@ $header-bg-dark: #111111; flex-direction: row; padding-bottom: 1.5em; gap: 1em; + align-items: center; } .spinner_container { diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss index 2a8635da1..e208fcd75 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss @@ -1,3 +1,12 @@ @use 'src/mixins' as *; @use 'src/constants' as *; + +.admin_closed_switch { + display: flex; + align-items: center; + padding: 5px; + gap: 10px; + border-radius: 10px; + border: $red-samf 2px solid; +} diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index 9c20e233b..37b097ba6 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { Button, TimeDisplay } from '~/Components'; +import { Button, TimeDisplay, ToggleSwitch } from '~/Components'; import { Table } from '~/Components/Table'; import { deleteClosedPeriod, getClosedPeriods } from '~/api'; import type { ClosedPeriodDto } from '~/dto'; @@ -11,11 +11,13 @@ import { reverse } from '~/named-urls'; import { ROUTES } from '~/routes'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './ClosedPeriodAdminPage.module.scss'; +import { useGlobalContext } from '~/context/GlobalContextProvider'; export function ClosedPeriodAdminPage() { const [closedPeriods, setClosedPeriods] = useState([]); const [showSpinner, setShowSpinner] = useState(true); const { t } = useTranslation(); + const globalContext = useGlobalContext(); useTitle(t(KEY.command_menu_shortcut_closed)); const getAllClosedPeriods = useCallback(() => { @@ -51,9 +53,15 @@ export function ClosedPeriodAdminPage() { } const header = ( - + <> + + + Admin Closed + globalContext.toggleIsClosed()}/> + + ); const backendUrl = ROUTES.backend.admin__samfundet_closedperiod_changelist; @@ -76,7 +84,6 @@ export function ClosedPeriodAdminPage() { data={closedPeriods.map((element) => ({ cells: [ element.message_no, - element.description_no, { content: }, { content: }, { diff --git a/frontend/src/api.ts b/frontend/src/api.ts index b62329072..77d5318b8 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -492,7 +492,6 @@ export async function putGang(id: string | number, data: Partial): Prom } export async function getClosedPeriods(): Promise { - // start_dt og end_dt er strings ikke Date -_- const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__closedperiods_list; const response = await axios.get(url, { withCredentials: true }); return response.data; diff --git a/frontend/src/context/GlobalContextProvider.tsx b/frontend/src/context/GlobalContextProvider.tsx index bf387cdc2..2700351db 100644 --- a/frontend/src/context/GlobalContextProvider.tsx +++ b/frontend/src/context/GlobalContextProvider.tsx @@ -30,6 +30,10 @@ type GlobalContextProps = { setIsMobileNavigation: SetState; keyValues: KeyValueMap; + + // AdminToggels + isClosed: boolean; + toggleIsClosed: () => void; }; /** @@ -76,6 +80,8 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex const [mirrorDimension, setMirrorDimension] = useState(false); const { isMouseTrail, setIsMouseTrail, toggleMouseTrail } = useMouseTrail(); + const [isClosed, setIsClosed] = useState(false); + // =================================== // // Effects // // =================================== // @@ -86,6 +92,7 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex setMirrorDimension(user.user_preference.mirror_dimension); }, [user, enabled]); + // Stuff to do on first render. useEffect(() => { if (!enabled) return; @@ -140,6 +147,11 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex return toggledValue; } + + function toggleIsClosed() { + setIsClosed(v => !v) + } + // =================================== // // Finalize context with values // // =================================== // @@ -158,6 +170,8 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex toggleMouseTrail, toggleMirrorDimension, keyValues, + isClosed, + toggleIsClosed }; return {children}; From c050015f2f7861580dec84b88ab4c53a5ccd8f1b Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 19:11:29 +0100 Subject: [PATCH 35/48] added check for id for showing editing buttons and added id into admin page --- frontend/src/Components/ImageCard/ImageCard.tsx | 2 +- frontend/src/PagesAdmin/EventsAdminPage/EventsAdminPage.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index 4fbd9dc2f..09e4cc534 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -74,7 +74,7 @@ export function ImageCard({ return (
- + {id && }
diff --git a/frontend/src/PagesAdmin/EventsAdminPage/EventsAdminPage.tsx b/frontend/src/PagesAdmin/EventsAdminPage/EventsAdminPage.tsx index 32e7e740a..dd332dcaf 100644 --- a/frontend/src/PagesAdmin/EventsAdminPage/EventsAdminPage.tsx +++ b/frontend/src/PagesAdmin/EventsAdminPage/EventsAdminPage.tsx @@ -124,6 +124,7 @@ export function EventsAdminPage() { return ( Date: Thu, 30 Oct 2025 19:30:12 +0100 Subject: [PATCH 36/48] should be fixed now --- backend/samfundet/models/general.py | 4 ++-- frontend/src/Components/OpeningHours/OpeningHours.tsx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/samfundet/models/general.py b/backend/samfundet/models/general.py index 203498420..1ad080819 100644 --- a/backend/samfundet/models/general.py +++ b/backend/samfundet/models/general.py @@ -255,7 +255,7 @@ def __str__(self) -> str: class ClosedPeriod(CustomBaseModel): - message_no = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)') + message_nb = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)') message_en = models.TextField(blank=True, null=True, verbose_name='Melding (engelsk)') #description_no = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)') @@ -269,7 +269,7 @@ class Meta: verbose_name_plural = 'ClosedPeriods' def __str__(self) -> str: - return f'{self.message_no} {self.start_dt}-{self.end_dt}' + return f'{self.message_nb} {self.start_dt}-{self.end_dt}' # GANGS ### diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 103a744b1..4f2f58246 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -33,6 +33,7 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) for (const period of periods) { if (new Date(period.start_dt) < now && now < new Date(period.end_dt)) { setIsClosed(true); + console.log(period) setClosedText(dbT(period, 'message')); break; } From b54fbefc96e23822d80b31219c75e9fb6cc00ffc Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 19:31:30 +0100 Subject: [PATCH 37/48] ok now its good --- frontend/src/dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts index 387ac46c6..ef739a468 100644 --- a/frontend/src/dto.ts +++ b/frontend/src/dto.ts @@ -354,7 +354,7 @@ export type GangSectionDto = { export type ClosedPeriodDto = { id: number; - message_no: string; + message_nb: string; message_en: string; start_dt: string; end_dt: string; From 5aa8e0c9a03a55d1411e577dd83d96d41eed3587 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 19:34:20 +0100 Subject: [PATCH 38/48] changed closedPeriodadmin to match --- .../ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx | 4 ++-- .../ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index 37b097ba6..2e3f021da 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -83,7 +83,7 @@ export function ClosedPeriodAdminPage() { ]} data={closedPeriods.map((element) => ({ cells: [ - element.message_no, + element.message_nb, { content: }, { content: }, { @@ -105,7 +105,7 @@ export function ClosedPeriodAdminPage() { display="block" className={styles.smallButtons} onClick={() => { - if (window.confirm(`${t(KEY.form_confirm)} ${t(KEY.common_delete)} ${element.message_no}`)) { + if (window.confirm(`${t(KEY.form_confirm)} ${t(KEY.common_delete)} ${element.message_nb}`)) { deleteSelectedEvent(element.id); } }} diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index e048b319a..a0b04a78e 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -15,7 +15,7 @@ import styles from './ClosedPeriodFormAdminPage.module.scss'; import { reverse } from '~/named-urls'; type formType = { - message_no: string; + message_nb: string; message_en: string; start_dt: string; end_dt: string; @@ -49,7 +49,7 @@ export function ClosedPeriodFormAdminPage() { // setClosedPeriod(data); For posting console.log(data) setInitialData({ - message_no: data.message_no, + message_nb: data.message_nb, message_en: data.message_en, start_dt: data.start_dt, end_dt: data.end_dt, @@ -93,7 +93,7 @@ export function ClosedPeriodFormAdminPage() { onSubmit={handleOnSubmit} initialData={initialData}>
- state.message_no.length > min_length_message} field="message_no" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_norwegian)})`} /> + state.message_nb.length > min_length_message} field="message_nb" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_norwegian)})`} /> state.message_en.length > min_length_message} field="message_en" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_english)})`} />
From 8cd5403324135ebf88379020b2e8e555fd61e046 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 19:37:00 +0100 Subject: [PATCH 39/48] biome fix --- frontend/src/Components/ImageCard/ImageCard.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/Components/ImageCard/ImageCard.tsx b/frontend/src/Components/ImageCard/ImageCard.tsx index 09e4cc534..ad646b9fa 100644 --- a/frontend/src/Components/ImageCard/ImageCard.tsx +++ b/frontend/src/Components/ImageCard/ImageCard.tsx @@ -73,9 +73,7 @@ export function ImageCard({ return (
-
- {id && } -
+
{id && }
From b0edf9656ddef3f1045e2fb834f3fc4b1b75fc55 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 20:33:29 +0100 Subject: [PATCH 40/48] added radio buttons for choosing default, forced open or forced closed in closed periods --- frontend/' | 125 ++++++++++++++++++ .../Components/OpeningHours/OpeningHours.tsx | 8 +- .../ClosedPeriodAdminPage.module.scss | 10 +- .../ClosedPeriodAdminPage.tsx | 27 +++- .../src/context/GlobalContextProvider.tsx | 13 +- 5 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 frontend/' diff --git a/frontend/' b/frontend/' new file mode 100644 index 000000000..d09090710 --- /dev/null +++ b/frontend/' @@ -0,0 +1,125 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { toast } from 'react-toastify'; +import { Button, TimeDisplay, ToggleSwitch } from '~/Components'; +import { Table } from '~/Components/Table'; +import { deleteClosedPeriod, getClosedPeriods } from '~/api'; +import type { ClosedPeriodDto } from '~/dto'; +import { useTitle } from '~/hooks'; +import { KEY } from '~/i18n/constants'; +import { reverse } from '~/named-urls'; +import { ROUTES } from '~/routes'; +import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; +import styles from './ClosedPeriodAdminPage.module.scss'; +import { useGlobalContext } from '~/context/GlobalContextProvider'; +import { dbT } from '~/utils'; + +export function ClosedPeriodAdminPage() { + const [closedPeriods, setClosedPeriods] = useState([]); + const [showSpinner, setShowSpinner] = useState(true); + const { t } = useTranslation(); + const globalContext = useGlobalContext(); + useTitle(t(KEY.command_menu_shortcut_closed)); + + const getAllClosedPeriods = useCallback(() => { + setShowSpinner(true); + getClosedPeriods() + .then((data) => { + setClosedPeriods(data); + setShowSpinner(false); + }) + .catch((error) => { + toast.error(t(KEY.common_something_went_wrong)); + console.error(error); + }); + }, [t]); + + // Stuff to do on first render. + // TODO add permissions on render + + useEffect(() => { + getAllClosedPeriods(); + }, [getAllClosedPeriods]); + + function deleteSelectedEvent(id: number) { + deleteClosedPeriod(id) + .then(() => { + getAllClosedPeriods(); + toast.success(t(KEY.common_delete_successful)); + }) + .catch((error) => { + toast.error(t(KEY.common_something_went_wrong)); + console.error(error); + }); + } + + const header = ( + <> + + + {dbT({"text_nb": "Stenging status", "text_en": "Closing status"}, "text")} + globalContext.toggleIsClosed()}/> + + + ); + const backendUrl = ROUTES.backend.admin__samfundet_closedperiod_changelist; + + return ( + +
+ ({ + cells: [ + element.message_nb, + { content: }, + { content: }, + { + content: ( +
+ + {' '} +
+ ), + }, + ], + }))} + /> + + + ); +} diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 4f2f58246..8193c7d94 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -23,9 +23,11 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const globalContext = useGlobalContext() useEffect(() => { - if (globalContext.isClosed) { - setIsClosed(true) - setClosedText("Samfundet is closed"); + if (globalContext.isClosed !== "default") { + if (globalContext.isClosed === "closed") { + setIsClosed(true) + setClosedText("Samfundet is closed"); + } return } getClosedPeriods().then((periods) => { diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss index e208fcd75..02ae74981 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss @@ -2,11 +2,13 @@ @use 'src/constants' as *; -.admin_closed_switch { +.admin_closed_override_container { display: flex; align-items: center; - padding: 5px; + justify-content: center; gap: 10px; - border-radius: 10px; - border: $red-samf 2px solid; +} + +.admin_closed_radio { + margin-top: 10px; } diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index 2e3f021da..2c59a0ed0 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { Button, TimeDisplay, ToggleSwitch } from '~/Components'; +import { Button, RadioButton, TimeDisplay, ToggleSwitch } from '~/Components'; import { Table } from '~/Components/Table'; import { deleteClosedPeriod, getClosedPeriods } from '~/api'; import type { ClosedPeriodDto } from '~/dto'; @@ -12,6 +12,7 @@ import { ROUTES } from '~/routes'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './ClosedPeriodAdminPage.module.scss'; import { useGlobalContext } from '~/context/GlobalContextProvider'; +import { dbT } from '~/utils'; export function ClosedPeriodAdminPage() { const [closedPeriods, setClosedPeriods] = useState([]); @@ -57,9 +58,27 @@ export function ClosedPeriodAdminPage() { - - Admin Closed - globalContext.toggleIsClosed()}/> + + + {dbT({"text_nb": "Stenging status", "text_en": "Closing status"}, "text")} + + + + {dbT({"text_nb": "standar", "text_en": "default"}, "text")} + + + globalContext.setIsClosed("default")}/> + + + {dbT({"text_nb": "stengt", "text_en": "closed"}, "text")} + + globalContext.setIsClosed("closed")}/> + + + {dbT({"text_nb": "åpent", "text_en": "open"}, "text")} + + globalContext.setIsClosed("open")}/> + ); diff --git a/frontend/src/context/GlobalContextProvider.tsx b/frontend/src/context/GlobalContextProvider.tsx index 2700351db..f8bff93de 100644 --- a/frontend/src/context/GlobalContextProvider.tsx +++ b/frontend/src/context/GlobalContextProvider.tsx @@ -32,8 +32,8 @@ type GlobalContextProps = { keyValues: KeyValueMap; // AdminToggels - isClosed: boolean; - toggleIsClosed: () => void; + isClosed: string; + setIsClosed: React.Dispatch>; }; /** @@ -80,7 +80,7 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex const [mirrorDimension, setMirrorDimension] = useState(false); const { isMouseTrail, setIsMouseTrail, toggleMouseTrail } = useMouseTrail(); - const [isClosed, setIsClosed] = useState(false); + const [isClosed, setIsClosed] = useState("default"); // =================================== // // Effects // @@ -147,11 +147,6 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex return toggledValue; } - - function toggleIsClosed() { - setIsClosed(v => !v) - } - // =================================== // // Finalize context with values // // =================================== // @@ -171,7 +166,7 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex toggleMirrorDimension, keyValues, isClosed, - toggleIsClosed + setIsClosed }; return {children}; From bc93e7eaf43302451f32bacd17172b1851b77a90 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 20:46:00 +0100 Subject: [PATCH 41/48] readded almost sold out button --- .../HomePage/components/EventCarousel/EventCarousel.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx index 79359d75b..0a8d04ff6 100644 --- a/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx +++ b/frontend/src/Pages/HomePage/components/EventCarousel/EventCarousel.tsx @@ -1,5 +1,5 @@ import { Carousel, ImageCard } from '~/Components'; -// import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; +import { BuyEventTicket } from '~/Components/BuyEventTicket/BuyEventTicket'; import { BACKEND_DOMAIN } from '~/constants'; import { useAuthContext } from '~/context/AuthContext'; import type { EventDto, HomePageElementDto } from '~/dto'; @@ -51,8 +51,9 @@ export function EventCarousel({ element, skeletonCount = 0 }: EventCarouselProps url={url} ticket_type={event.ticket_type} host={event.host} - // {event.billig && } - /> + > + {event.billig && } + ); })} From 30d578e64628dcb8dd13829dc6e40a662e78105b Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 20:51:54 +0100 Subject: [PATCH 42/48] fixed old copyed code carrying over due too blindness --- .../EventEditButtons/EventEditButtons.stories.tsx | 15 +++------------ .../EventEditButtons/EventEditButtons.tsx | 1 - .../Components/ImageCard/ImageCard.module.scss | 3 +-- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx index 5cc1cf666..cc29d29cd 100644 --- a/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.stories.tsx @@ -1,21 +1,12 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta } from '@storybook/react'; import { EventEditButtons } from './EventEditButtons'; -// Local component config. const meta: Meta = { - title: 'Components/Video', + title: 'Components/EventEditButtons', component: EventEditButtons, args: { - title: 'Approve', + title: 'EditButtons', }, }; export default meta; - -type Story = StoryObj; - -//export const Basic: Story = { -// args: { -// embedId: '88kgbMcDIQ4', -//}, -//}; diff --git a/frontend/src/Components/EventEditButtons/EventEditButtons.tsx b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx index 81ab46496..e518e4ec9 100644 --- a/frontend/src/Components/EventEditButtons/EventEditButtons.tsx +++ b/frontend/src/Components/EventEditButtons/EventEditButtons.tsx @@ -15,7 +15,6 @@ type EventEditButtons = { icon_size?: number; }; -/** Component for displaying a youtube video */ export function EventEditButtons({ title = 'event', id, icon_size = 17 }: EventEditButtons) { const { user } = useAuthContext(); const isStaff = user?.is_staff; diff --git a/frontend/src/Components/ImageCard/ImageCard.module.scss b/frontend/src/Components/ImageCard/ImageCard.module.scss index e44ceaa56..8c1f11dfd 100644 --- a/frontend/src/Components/ImageCard/ImageCard.module.scss +++ b/frontend/src/Components/ImageCard/ImageCard.module.scss @@ -16,7 +16,6 @@ $card-text-shadow: 1px 1px 8px rgba(0, 0, 0, 0.5); $card-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2); $card-box-shadow-hover: 0 3px 8px 0 rgba(0, 0, 0, 0.4); -$inner-card-padding: 0.75rem; // TODO color variables .container { @@ -57,7 +56,7 @@ $inner-card-padding: 0.75rem; display: flex; justify-content: space-between; flex-direction: column; - padding: $inner-card-padding; + padding: 0.75rem; } .card_content { From 833e732c51f98af5608693b8501790bc8f3de273 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 21:08:53 +0100 Subject: [PATCH 43/48] biome fix --- .../Components/OpeningHours/OpeningHours.tsx | 16 +++--- .../ClosedPeriodAdminPage.tsx | 44 ++++++++-------- .../ClosedPeriodFormAdminPage.tsx | 50 ++++++++++++++----- .../src/context/GlobalContextProvider.tsx | 5 +- 4 files changed, 71 insertions(+), 44 deletions(-) diff --git a/frontend/src/Components/OpeningHours/OpeningHours.tsx b/frontend/src/Components/OpeningHours/OpeningHours.tsx index 8193c7d94..9c2a7f1ae 100644 --- a/frontend/src/Components/OpeningHours/OpeningHours.tsx +++ b/frontend/src/Components/OpeningHours/OpeningHours.tsx @@ -4,10 +4,10 @@ import { TimeDuration } from '~/Components'; import { Link } from '~/Components/Link/Link'; import { Text } from '~/Components/Text/Text'; import { getClosedPeriods } from '~/api'; +import { useGlobalContext } from '~/context/GlobalContextProvider'; import type { VenueDto } from '~/dto'; import { KEY } from '~/i18n/constants'; import { dbT } from '~/utils'; -import { useGlobalContext } from '~/context/GlobalContextProvider'; import styles from './OpeningHours.module.scss'; type OpeningHoursProps = { @@ -20,22 +20,22 @@ export function OpeningHours({ venues, isLoading, isError }: OpeningHoursProps) const { t } = useTranslation(); const [isClosed, setIsClosed] = useState(false); const [closedText, setClosedText] = useState('Samf is closed'); - const globalContext = useGlobalContext() + const globalContext = useGlobalContext(); useEffect(() => { - if (globalContext.isClosed !== "default") { - if (globalContext.isClosed === "closed") { - setIsClosed(true) - setClosedText("Samfundet is closed"); + if (globalContext.isClosed !== 'default') { + if (globalContext.isClosed === 'closed') { + setIsClosed(true); + setClosedText('Samfundet is closed'); } - return + return; } getClosedPeriods().then((periods) => { const now = new Date(); for (const period of periods) { if (new Date(period.start_dt) < now && now < new Date(period.end_dt)) { setIsClosed(true); - console.log(period) + console.log(period); setClosedText(dbT(period, 'message')); break; } diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index 2c59a0ed0..62f5c268b 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -1,18 +1,18 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { Button, RadioButton, TimeDisplay, ToggleSwitch } from '~/Components'; +import { Button, RadioButton, TimeDisplay } from '~/Components'; import { Table } from '~/Components/Table'; import { deleteClosedPeriod, getClosedPeriods } from '~/api'; +import { useGlobalContext } from '~/context/GlobalContextProvider'; import type { ClosedPeriodDto } from '~/dto'; import { useTitle } from '~/hooks'; import { KEY } from '~/i18n/constants'; import { reverse } from '~/named-urls'; import { ROUTES } from '~/routes'; +import { dbT } from '~/utils'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './ClosedPeriodAdminPage.module.scss'; -import { useGlobalContext } from '~/context/GlobalContextProvider'; -import { dbT } from '~/utils'; export function ClosedPeriodAdminPage() { const [closedPeriods, setClosedPeriods] = useState([]); @@ -59,26 +59,30 @@ export function ClosedPeriodAdminPage() { {t(KEY.admin_closed_period_new_period)} - - {dbT({"text_nb": "Stenging status", "text_en": "Closing status"}, "text")} - + + {dbT({ text_nb: 'Stenging status', text_en: 'Closing status' }, 'text')} + - - {dbT({"text_nb": "standar", "text_en": "default"}, "text")} - - - globalContext.setIsClosed("default")}/> - + {dbT({ text_nb: 'standar', text_en: 'default' }, 'text')} + + globalContext.setIsClosed('default')} + /> + - {dbT({"text_nb": "stengt", "text_en": "closed"}, "text")} - - globalContext.setIsClosed("closed")}/> - + {dbT({ text_nb: 'stengt', text_en: 'closed' }, 'text')} + + globalContext.setIsClosed('closed')} + /> + - {dbT({"text_nb": "åpent", "text_en": "open"}, "text")} - - globalContext.setIsClosed("open")}/> - + {dbT({ text_nb: 'åpent', text_en: 'open' }, 'text')} + + globalContext.setIsClosed('open')} /> + ); diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index a0b04a78e..99b48f9de 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -9,10 +9,10 @@ import { getClosedPeriod, postClosedPeriod, putClosedPeriod } from '~/api'; import { useCustomNavigate, useTitle } from '~/hooks'; import { STATUS } from '~/http_status_codes'; import { KEY } from '~/i18n/constants'; +import { reverse } from '~/named-urls'; import { ROUTES } from '~/routes'; import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; import styles from './ClosedPeriodFormAdminPage.module.scss'; -import { reverse } from '~/named-urls'; type formType = { message_nb: string; @@ -47,7 +47,7 @@ export function ClosedPeriodFormAdminPage() { getClosedPeriod(id) .then((data) => { // setClosedPeriod(data); For posting - console.log(data) + console.log(data); setInitialData({ message_nb: data.message_nb, message_en: data.message_en, @@ -70,18 +70,18 @@ export function ClosedPeriodFormAdminPage() { if (id !== undefined) { putClosedPeriod(id, data) .then() - .catch(err => { - alert(err) - }) + .catch((err) => { + alert(err); + }); } else { postClosedPeriod(data) .then(() => { - toast.success(t(KEY.common_creation_successful)) - navigate({url: reverse({pattern: ROUTES.frontend.admin_closed})}) + toast.success(t(KEY.common_creation_successful)); + navigate({ url: reverse({ pattern: ROUTES.frontend.admin_closed }) }); }) .catch(() => { - toast.error(t(KEY.common_something_went_wrong)) - }) + toast.error(t(KEY.common_something_went_wrong)); + }); } } @@ -93,12 +93,36 @@ export function ClosedPeriodFormAdminPage() { onSubmit={handleOnSubmit} initialData={initialData}>
- state.message_nb.length > min_length_message} field="message_nb" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_norwegian)})`} /> - state.message_en.length > min_length_message} field="message_en" required={true} type="text_long" label={`${labelMessage} (${t(KEY.common_english)})`} /> + state.message_nb.length > min_length_message} + field="message_nb" + required={true} + type="text_long" + label={`${labelMessage} (${t(KEY.common_norwegian)})`} + /> + state.message_en.length > min_length_message} + field="message_en" + required={true} + type="text_long" + label={`${labelMessage} (${t(KEY.common_english)})`} + />
- state.end_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true} field="start_dt" type="date" label={`${t(KEY.start_time)}`} /> - state.start_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true} field="end_dt" type="date" label={`${t(KEY.end_time)}`} /> + (state.end_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true)} + field="start_dt" + type="date" + label={`${t(KEY.start_time)}`} + /> + + state.start_dt ? new Date(state.start_dt) <= new Date(state.end_dt) : true + } + field="end_dt" + type="date" + label={`${t(KEY.end_time)}`} + />
diff --git a/frontend/src/context/GlobalContextProvider.tsx b/frontend/src/context/GlobalContextProvider.tsx index f8bff93de..e831d2c95 100644 --- a/frontend/src/context/GlobalContextProvider.tsx +++ b/frontend/src/context/GlobalContextProvider.tsx @@ -80,7 +80,7 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex const [mirrorDimension, setMirrorDimension] = useState(false); const { isMouseTrail, setIsMouseTrail, toggleMouseTrail } = useMouseTrail(); - const [isClosed, setIsClosed] = useState("default"); + const [isClosed, setIsClosed] = useState('default'); // =================================== // // Effects // @@ -92,7 +92,6 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex setMirrorDimension(user.user_preference.mirror_dimension); }, [user, enabled]); - // Stuff to do on first render. useEffect(() => { if (!enabled) return; @@ -166,7 +165,7 @@ export function GlobalContextProvider({ children, enabled = true }: GlobalContex toggleMirrorDimension, keyValues, isClosed, - setIsClosed + setIsClosed, }; return {children}; From 5a09679db0eadebe8904ca7f279046709acb8375 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 21:19:34 +0100 Subject: [PATCH 44/48] ruff reformat --- backend/samfundet/models/general.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/samfundet/models/general.py b/backend/samfundet/models/general.py index 1ad080819..f85a12df2 100644 --- a/backend/samfundet/models/general.py +++ b/backend/samfundet/models/general.py @@ -258,8 +258,8 @@ class ClosedPeriod(CustomBaseModel): message_nb = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)') message_en = models.TextField(blank=True, null=True, verbose_name='Melding (engelsk)') - #description_no = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)') - #description_en = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (engelsk)') + # description_no = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)') + # description_en = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (engelsk)') start_dt = models.DateField(blank=True, null=False, verbose_name='Start dato') end_dt = models.DateField(blank=True, null=False, verbose_name='Slutt dato') From 5f5b7af56c258ac26e9a8ba0a07c2428a0e7740d Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 21:26:29 +0100 Subject: [PATCH 45/48] make migration problems that now should be fixed --- ...ename_message_no_closedperiod_message_nb.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py diff --git a/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py b/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py new file mode 100644 index 000000000..32f8588c2 --- /dev/null +++ b/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.9 on 2025-11-04 20:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('samfundet', '0002_remove_closedperiod_description_en_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='closedperiod', + old_name='message_no', + new_name='message_nb', + ), + ] From 1e37f560c38abebe21224baebc78b41c31d21695 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 20 Jan 2026 21:57:12 +0100 Subject: [PATCH 46/48] removed the scary file --- frontend/' | 125 ----------------------------------------------------- 1 file changed, 125 deletions(-) delete mode 100644 frontend/' diff --git a/frontend/' b/frontend/' deleted file mode 100644 index d09090710..000000000 --- a/frontend/' +++ /dev/null @@ -1,125 +0,0 @@ -import { useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { toast } from 'react-toastify'; -import { Button, TimeDisplay, ToggleSwitch } from '~/Components'; -import { Table } from '~/Components/Table'; -import { deleteClosedPeriod, getClosedPeriods } from '~/api'; -import type { ClosedPeriodDto } from '~/dto'; -import { useTitle } from '~/hooks'; -import { KEY } from '~/i18n/constants'; -import { reverse } from '~/named-urls'; -import { ROUTES } from '~/routes'; -import { AdminPageLayout } from '../AdminPageLayout/AdminPageLayout'; -import styles from './ClosedPeriodAdminPage.module.scss'; -import { useGlobalContext } from '~/context/GlobalContextProvider'; -import { dbT } from '~/utils'; - -export function ClosedPeriodAdminPage() { - const [closedPeriods, setClosedPeriods] = useState([]); - const [showSpinner, setShowSpinner] = useState(true); - const { t } = useTranslation(); - const globalContext = useGlobalContext(); - useTitle(t(KEY.command_menu_shortcut_closed)); - - const getAllClosedPeriods = useCallback(() => { - setShowSpinner(true); - getClosedPeriods() - .then((data) => { - setClosedPeriods(data); - setShowSpinner(false); - }) - .catch((error) => { - toast.error(t(KEY.common_something_went_wrong)); - console.error(error); - }); - }, [t]); - - // Stuff to do on first render. - // TODO add permissions on render - - useEffect(() => { - getAllClosedPeriods(); - }, [getAllClosedPeriods]); - - function deleteSelectedEvent(id: number) { - deleteClosedPeriod(id) - .then(() => { - getAllClosedPeriods(); - toast.success(t(KEY.common_delete_successful)); - }) - .catch((error) => { - toast.error(t(KEY.common_something_went_wrong)); - console.error(error); - }); - } - - const header = ( - <> - - - {dbT({"text_nb": "Stenging status", "text_en": "Closing status"}, "text")} - globalContext.toggleIsClosed()}/> - - - ); - const backendUrl = ROUTES.backend.admin__samfundet_closedperiod_changelist; - - return ( - -
-
({ - cells: [ - element.message_nb, - { content: }, - { content: }, - { - content: ( -
- - {' '} -
- ), - }, - ], - }))} - /> - - - ); -} From e860d3444dc84625d1ca806bd448f3fcfbad831f Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 22 Jan 2026 14:43:34 +0100 Subject: [PATCH 47/48] fixing migrations --- backend/samfundet/migrations/0001_initial.py | 4 +-- ...ve_closedperiod_description_en_and_more.py | 30 ------------------- ...name_message_no_closedperiod_message_nb.py | 18 ----------- 3 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py delete mode 100644 backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py diff --git a/backend/samfundet/migrations/0001_initial.py b/backend/samfundet/migrations/0001_initial.py index 0ea8f1fdf..f43b5adae 100644 --- a/backend/samfundet/migrations/0001_initial.py +++ b/backend/samfundet/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.9 on 2025-08-09 16:11 +# Generated by Django 5.2.10 on 2026-01-22 13:43 import datetime import django.contrib.auth.models @@ -138,8 +138,6 @@ class Migration(migrations.Migration): ('updated_at', models.DateTimeField(blank=True, editable=False, null=True)), ('message_nb', models.TextField(blank=True, null=True, verbose_name='Melding (norsk)')), ('message_en', models.TextField(blank=True, null=True, verbose_name='Melding (engelsk)')), - ('description_nb', models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)')), - ('description_en', models.TextField(blank=True, null=True, verbose_name='Beskrivelse (engelsk)')), ('start_dt', models.DateField(blank=True, verbose_name='Start dato')), ('end_dt', models.DateField(blank=True, verbose_name='Slutt dato')), ('created_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), diff --git a/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py b/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py deleted file mode 100644 index 821b7f62f..000000000 --- a/backend/samfundet/migrations/0002_remove_closedperiod_description_en_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.1.9 on 2025-10-21 19:19 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('samfundet', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='closedperiod', - name='description_en', - ), - migrations.RemoveField( - model_name='closedperiod', - name='description_nb', - ), - migrations.RemoveField( - model_name='closedperiod', - name='message_nb', - ), - migrations.AddField( - model_name='closedperiod', - name='message_no', - field=models.TextField(blank=True, null=True, verbose_name='Melding (norsk)'), - ), - ] diff --git a/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py b/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py deleted file mode 100644 index 32f8588c2..000000000 --- a/backend/samfundet/migrations/0003_rename_message_no_closedperiod_message_nb.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.9 on 2025-11-04 20:25 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('samfundet', '0002_remove_closedperiod_description_en_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='closedperiod', - old_name='message_no', - new_name='message_nb', - ), - ] From c2e7f3556543e5a4ec8aff50a013a6ec8ed6deec Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 22 Jan 2026 21:22:14 +0100 Subject: [PATCH 48/48] fixed goof merge with main --- backend/samfundet/view/general_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/samfundet/view/general_views.py b/backend/samfundet/view/general_views.py index de8a53971..5d82a972a 100644 --- a/backend/samfundet/view/general_views.py +++ b/backend/samfundet/view/general_views.py @@ -4,7 +4,7 @@ from __future__ import annotations from typing import Any -from datetime import time +from datetime import time, timedelta from itertools import chain from rest_framework import status @@ -129,7 +129,7 @@ class VenueView(ModelViewSet): @action(detail=False, methods=['get']) def open_venues(self, request: Request) -> Response: - day_name = timezone.now().strftime('%A').lower() + day_name = (timezone.now() - timedelta(hours=4)).strftime('%A').lower() q = ~Q( **{