From 575a4994bdff31b45bb13a42cf1f6d67baf4f204 Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 23 Sep 2025 20:59:19 +0200 Subject: [PATCH 01/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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/44] 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 388bed04b6fee12a10d8aba3cf43cc92fb913dce Mon Sep 17 00:00:00 2001 From: eilifhl Date: Tue, 7 Oct 2025 21:06:11 +0200 Subject: [PATCH 16/44] 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 17/44] 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 1b2162037442e023f4b0fc6052b715cf33191fdd Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 16 Oct 2025 20:48:37 +0200 Subject: [PATCH 18/44] 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 19/44] 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 9da6fd786c0c6302fe1a8ff0e6244dff21f8ffad Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 21 Oct 2025 19:59:22 +0200 Subject: [PATCH 20/44] 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 21/44] ... --- 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 22/44] 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 23/44] 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 24/44] 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 25/44] 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 d162b0afd8a72836f4ee23fe0670a742f25440db Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 19:30:12 +0100 Subject: [PATCH 26/44] 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 27/44] 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 28/44] 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 b0edf9656ddef3f1045e2fb834f3fc4b1b75fc55 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 30 Oct 2025 20:33:29 +0100 Subject: [PATCH 29/44] 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 833e732c51f98af5608693b8501790bc8f3de273 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 21:08:53 +0100 Subject: [PATCH 30/44] 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 31/44] 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 32/44] 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 b73730bfb353ceedd845d278bf2a7b6532c73341 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 4 Nov 2025 21:30:13 +0100 Subject: [PATCH 33/44] removed the shamefull file named: ' its a real disgrace --- 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 a68b469c4f445d4ef60b949c22946a1b7bb7d1d7 Mon Sep 17 00:00:00 2001 From: specter Date: Thu, 13 Nov 2025 19:05:06 +0100 Subject: [PATCH 34/44] changed radio buttons to dropdown and imporved styling --- .../ClosedPeriodAdminPage.module.scss | 6 ++ .../ClosedPeriodAdminPage.tsx | 57 +++++++++---------- .../ClosedPeriodFormAdminPage.tsx | 9 ++- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss index 02ae74981..0132b5b57 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.module.scss @@ -12,3 +12,9 @@ .admin_closed_radio { margin-top: 10px; } + +.edit_buttons { + display: flex; + flex-direction: column; + gap: 5px; +} diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index 62f5c268b..ea058114b 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -1,7 +1,8 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import { Button, RadioButton, TimeDisplay } from '~/Components'; +import { Button, TimeDisplay } from '~/Components'; +import { Dropdown } from '~/Components'; import { Table } from '~/Components/Table'; import { deleteClosedPeriod, getClosedPeriods } from '~/api'; import { useGlobalContext } from '~/context/GlobalContextProvider'; @@ -58,32 +59,25 @@ export function ClosedPeriodAdminPage() { - - - {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')} /> - - + {dbT({ text_nb: 'Stenging status', text_en: 'Closing status' }, 'text')} + globalContext.setIsClosed(value)} + /> ); const backendUrl = ROUTES.backend.admin__samfundet_closedperiod_changelist; @@ -98,20 +92,21 @@ export function ClosedPeriodAdminPage() {
({ cells: [ element.message_nb, + element.message_en, { content: }, { content: }, { content: ( -
+
{dbT({ text_nb: 'Stenging status', text_en: 'Closing status' }, 'text')} From 5987fad34d5e501d06ef38e1f0e819933f15c3c2 Mon Sep 17 00:00:00 2001 From: specter Date: Tue, 10 Feb 2026 21:31:01 +0100 Subject: [PATCH 43/44] using react query instead --- .../ClosedPeriodAdminPage.tsx | 3 +- .../ClosedPeriodFormAdminPage.tsx | 100 +++++++++--------- frontend/src/i18n/constants.ts | 1 + frontend/src/i18n/translations.ts | 2 + 4 files changed, 53 insertions(+), 53 deletions(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx index a64547eaa..8020bf956 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodAdminPage/ClosedPeriodAdminPage.tsx @@ -11,7 +11,6 @@ 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'; @@ -59,7 +58,7 @@ export function ClosedPeriodAdminPage() { - {dbT({ text_nb: 'Stenging status', text_en: 'Closing status' }, 'text')} + {t(KEY.admin_closed_period_closing_status)} (true); - // const [closedPeriod, setClosedPeriod] = useState(undefined); For posting - const [initialData, setInitialData] = useState(undefined); - - // 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 + const { + data: initialData, + isLoading, + isError, + error, + } = useQuery({ + queryKey: ['closed-period', id], + queryFn: () => getClosedPeriod(id as string), + enabled: !!id, + select: (data) => ({ + message_nb: data.message_nb, + message_en: data.message_en, + start_dt: data.start_dt, + end_dt: data.end_dt, + }), + }); + useEffect(() => { - // TODO add fix on no id on editpage - if (id === undefined) { - setShowSpinner(false); - return; + if (isError) { + navigate({ url: ROUTES.frontend.admin_closed, replace: true }); + toast.error(t(KEY.common_something_went_wrong)); } + }, [isError, t, navigate]); + + const updateMutation = useMutation({ + mutationFn: (data: FormType) => putClosedPeriod(id as string, data), + onSuccess: () => { + toast.success(t(KEY.common_update_successful)); + navigate({ url: reverse({ pattern: ROUTES.frontend.admin_closed }) }); + }, + onError: () => { + toast.error(t(KEY.common_something_went_wrong)); + }, + }); - getClosedPeriod(id) - .then((data) => { - setInitialData({ - message_nb: data.message_nb, - message_en: data.message_en, - start_dt: data.start_dt, - end_dt: data.end_dt, - }); - setShowSpinner(false); - }) - .catch((data: AxiosError) => { - if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { - navigate({ url: ROUTES.frontend.admin_closed, replace: true }); - } - toast.error(t(KEY.common_something_went_wrong)); - }); - }, [id]); + const createMutation = useMutation({ + mutationFn: (data: formType) => postClosedPeriod(data), + onSuccess: () => { + toast.success(t(KEY.common_creation_successful)); + navigate({ url: reverse({ pattern: ROUTES.frontend.admin_closed }) }); + }, + onError: () => { + toast.error(t(KEY.common_something_went_wrong)); + }, + }); function handleOnSubmit(data: formType) { - if (id !== undefined) { - putClosedPeriod(id, data) - .then(() => { - toast.success(t(KEY.common_update_successful)); - navigate({ url: reverse({ pattern: ROUTES.frontend.admin_closed }) }); - }) - .catch(() => { - toast.error(t(KEY.common_something_went_wrong)); - }); + if (id) { + updateMutation.mutate(data); } else { - 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)); - }); + createMutation.mutate(data); } } @@ -89,7 +87,7 @@ export function ClosedPeriodFormAdminPage() { useTitle(title); return ( - + onSubmit={handleOnSubmit} initialData={initialData}>
Date: Tue, 10 Feb 2026 21:37:59 +0100 Subject: [PATCH 44/44] biome --- .../ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx index aad74e13d..118b27b22 100644 --- a/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx +++ b/frontend/src/PagesAdmin/ClosedPeriodFormAdminPage/ClosedPeriodFormAdminPage.tsx @@ -7,7 +7,6 @@ import { type FormType, SamfForm } from '~/Forms/SamfForm'; import { SamfFormField } from '~/Forms/SamfFormField'; 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';