> = {
+ spotify_uri: t(KEY.event_spotify_uri_help),
+ youtube_link: t(KEY.event_youtube_link_help),
+ youtube_embed: t(KEY.event_youtube_embed_help),
+ };
+
+ return (
+ <>
+
+ {SOCIAL_KEYS.map((name) => (
+ (
+
+ {SOCIAL_LABELS[name]}
+
+
+
+ {SOCIAL_MEDIA_HELP[name] ? {SOCIAL_MEDIA_HELP[name]} : null}
+
+
+ )}
+ />
+ ))}
+
+ >
+ );
+}
diff --git a/frontend/src/PagesAdmin/EventCreatorAdminPage/steps/stepConfig.ts b/frontend/src/PagesAdmin/EventCreatorAdminPage/steps/stepConfig.ts
index e5027cbde..a8eb5f3d7 100644
--- a/frontend/src/PagesAdmin/EventCreatorAdminPage/steps/stepConfig.ts
+++ b/frontend/src/PagesAdmin/EventCreatorAdminPage/steps/stepConfig.ts
@@ -1,6 +1,6 @@
import type { FormType } from '../hooks/useEventCreatorForm';
-export type StepKey = 'text' | 'info' | 'payment' | 'graphics' | 'summary';
+export type StepKey = 'text' | 'info' | 'payment' | 'socialmedia' | 'graphics' | 'summary';
export type EventCreatorStep = {
key: StepKey;
@@ -48,6 +48,13 @@ export const steps: EventCreatorStep[] = [
title_en: 'Payment/registration',
validate: (d) => !!d.age_restriction && !!d.ticket_type,
},
+ // Social media links
+ {
+ key: 'socialmedia',
+ title_nb: 'Sosiale medier',
+ title_en: 'Social media',
+ validate: () => true,
+ },
{
key: 'graphics',
title_nb: 'Grafikk',
diff --git a/frontend/src/dto.ts b/frontend/src/dto.ts
index 41d555090..88221abde 100644
--- a/frontend/src/dto.ts
+++ b/frontend/src/dto.ts
@@ -188,6 +188,17 @@ export type EventDto = {
image_url: string;
capacity?: number;
+
+ spotify_uri?: string;
+ youtube_link?: string;
+ youtube_embed?: string;
+ facebook_link?: string;
+ soundcloud_link?: string;
+ instagram_link?: string;
+ x_link?: string;
+ lastfm_link?: string;
+ vimeo_link?: string;
+ general_link?: string;
};
export type EventWriteDto = {
diff --git a/frontend/src/i18n/constants.ts b/frontend/src/i18n/constants.ts
index bff73255a..f38f2337c 100644
--- a/frontend/src/i18n/constants.ts
+++ b/frontend/src/i18n/constants.ts
@@ -203,6 +203,7 @@ export const KEY = {
common_available: 'common_available',
common_comment: 'common_comment',
common_capacity: 'common_capacity',
+ common_link: 'common_link',
common_membership_number: 'common_membership_number',
common_to_payment: 'common_to_payment',
@@ -288,8 +289,15 @@ export const KEY = {
// EventPage:
event_registration_url: 'event_registration_url',
+ event_general_link: 'event_general_link',
+ event_spotify_uri_help: 'event_spotify_uri_help',
+ event_youtube_link_help: 'event_youtube_link_help',
+ event_youtube_embed_help: 'event_youtube_embed_help',
event_add_ticket: 'event_add_ticket',
event_invalid_form_error: 'event_invalid_form_error',
+ event_must_be_valid_url: 'event_must_be_valid_url',
+ event_must_be_valid_spotify_uri: 'event_must_be_valid_spotify_uri',
+ event_publication_date_required: 'event_publication_date_required',
// Purchase Ticket Info:
invalid_email_message: 'invalid_email_message',
diff --git a/frontend/src/i18n/translations.ts b/frontend/src/i18n/translations.ts
index b2824092c..502a45789 100644
--- a/frontend/src/i18n/translations.ts
+++ b/frontend/src/i18n/translations.ts
@@ -187,6 +187,7 @@ export const nb = prepareTranslations({
[KEY.common_available]: 'Tilgjengelig',
[KEY.common_comment]: 'Kommentar',
[KEY.common_capacity]: 'Kapasitet',
+ [KEY.common_link]: 'Lenke',
[KEY.common_membership_number]: 'Medlemsnummer',
[KEY.common_to_payment]: 'Til betaling',
@@ -278,8 +279,16 @@ export const nb = prepareTranslations({
// EventPage:
[KEY.event_registration_url]: 'Registreringslenke',
+ [KEY.event_general_link]: 'Generell lenke',
+ [KEY.event_spotify_uri_help]:
+ 'Legg til Spotify URI-en til en spilleliste, og en widget med denne listen vil dukke opp på arrangementsiden.',
+ [KEY.event_youtube_link_help]: 'Legg til YouTube-video som skal linkes til',
+ [KEY.event_youtube_embed_help]: 'Legg til YouTube-video som skal embeddes, så vil den vises på arrangementsiden.',
[KEY.event_add_ticket]: 'Legg til billett',
[KEY.event_invalid_form_error]: 'Skjemaet inneholder valideringsfeil. Vennligst sjekk de uthevede feltene.',
+ [KEY.event_must_be_valid_url]: 'Må være en gyldig URL',
+ [KEY.event_must_be_valid_spotify_uri]: 'Må være en gyldig Spotify URI',
+ [KEY.event_publication_date_required]: 'Publiseringsdato er påkrevd',
// Event categories
[KEY.event_category_art]: 'Kunst',
@@ -894,6 +903,7 @@ export const en = prepareTranslations({
[KEY.common_available]: 'Available',
[KEY.common_comment]: 'Comment',
[KEY.common_capacity]: 'Capacity',
+ [KEY.common_link]: 'Link',
[KEY.common_membership_number]: 'Membership number',
[KEY.common_to_payment]: 'To payment',
@@ -1005,8 +1015,16 @@ export const en = prepareTranslations({
// EventPage:
[KEY.event_registration_url]: 'Registration URL',
+ [KEY.event_general_link]: 'General link',
+ [KEY.event_spotify_uri_help]:
+ 'Add the Spotify URI of a playlist, and a widget will appear on the event page with the chosen playlist.',
+ [KEY.event_youtube_link_help]: 'Add a link to a YouTube video',
+ [KEY.event_youtube_embed_help]: 'Add a link to a YouTube video to be embedded, and it will appear on the event page.',
[KEY.event_add_ticket]: 'Add ticket',
[KEY.event_invalid_form_error]: 'Form contains validation errors. Please check highlighted fields.',
+ [KEY.event_must_be_valid_url]: 'Must be a valid URL',
+ [KEY.event_must_be_valid_spotify_uri]: 'Must be a valid Spotify URI',
+ [KEY.event_publication_date_required]: 'Publication date is required',
//Purchase Ticket Info:
[KEY.invalid_email_message]: 'Invalid email format',
diff --git a/frontend/src/schema/event.ts b/frontend/src/schema/event.ts
index f513fd153..0f67bc885 100644
--- a/frontend/src/schema/event.ts
+++ b/frontend/src/schema/event.ts
@@ -3,26 +3,54 @@ import { KEY } from '~/i18n/constants';
import { EventAgeRestriction, EventCategory, EventTicketType } from '~/types';
import { zodEnum } from './utils';
+const validUrl = z
+ .string()
+ .trim()
+ .refine((val) => val === '' || /^https?:\/\//.test(val), { message: KEY.event_must_be_valid_url });
+
+const validSpotifyUri = z
+ .string()
+ .trim()
+ .refine((val) => val === '' || /^spotify:(track|artist|album|playlist):[a-zA-Z0-9]{22}$/.test(val), {
+ message: KEY.event_must_be_valid_spotify_uri,
+ });
+
+// text and description
export const EVENT_TITLE = z.string().min(1, { message: KEY.event_form_title_required });
export const EVENT_DESCRIPTION_LONG = z.string().min(1, { message: KEY.event_form_description_long_required });
export const EVENT_DESCRIPTION_SHORT = z.string().min(1, { message: KEY.event_form_description_short_required });
+// Date and information
export const EVENT_START_DT = z.string().min(1, { message: KEY.event_form_start_dt_required });
export const EVENT_DURATION = z.number().min(1, { message: KEY.event_form_duration_min }).optional();
export const EVENT_END_DT = z.string().optional();
+export const EVENT_CATEGORY = zodEnum(EventCategory, KEY.event_form_category_required);
export const EVENT_HOST = z.string().min(1, { message: KEY.event_form_host_required });
export const EVENT_LOCATION = z.string().min(1, { message: KEY.event_form_location_required });
export const EVENT_CAPACITY = z.number().min(1, { message: KEY.event_form_capacity_min }).optional();
-export const EVENT_VISIBILITY_FROM_DT = z.string().min(1, { message: KEY.event_form_visibility_from_required });
-export const EVENT_VISIBILITY_TO_DT = z.string().optional();
-export const EVENT_PAID_OPTION = z.string().url().optional();
-export const EVENT_BILLIG_ID = z.number().optional();
-
-export const EVENT_REGISTRATION_URL = z.string().url().optional();
-export const EVENT_HOST_LINK = z.string().url().optional();
-export const EVENT_INSTAGRAM_LINK = z.string().url().optional();
-export const EVENT_FACEBOOK_LINK = z.string().url().optional();
-export const EVENT_X_LINK = z.string().url().optional();
-
-export const EVENT_CATEGORY = zodEnum(EventCategory, KEY.event_form_category_required);
+// Payment/registration
export const EVENT_AGE_RESTRICTION = zodEnum(EventAgeRestriction, KEY.event_form_age_restriction_required);
export const EVENT_TICKET_TYPE = zodEnum(EventTicketType, KEY.event_form_ticket_type_required);
+export const EVENT_CUSTOM_TICKET = z.object({
+ id: z.number(),
+ name_nb: z.string().min(1),
+ name_en: z.string().min(1),
+ price: z.number().min(0),
+});
+export const EVENT_REGISTRATION_URL = z.string().url().optional();
+export const EVENT_HOST_LINK = z.string().url().optional();
+export const EVENT_BILLIG_ID = z.number().optional();
+// Social media links
+export const EVENT_SPOTIFY_URI = validSpotifyUri;
+export const EVENT_YOUTUBE_LINK = validUrl;
+export const EVENT_YOUTUBE_EMBED = validUrl;
+export const EVENT_FACEBOOK_LINK = validUrl;
+export const EVENT_SOUNDCLOUD_LINK = validUrl;
+export const EVENT_INSTAGRAM_LINK = validUrl;
+export const EVENT_X_LINK = validUrl;
+export const EVENT_LASTFM_LINK = validUrl;
+export const EVENT_VIMEO_LINK = validUrl;
+export const EVENT_GENERAL_LINK = validUrl;
+// Summary/Publication date
+export const EVENT_VISIBILITY_FROM_DT = z.string().min(1, { message: KEY.event_publication_date_required });
+export const EVENT_VISIBILITY_TO_DT = z.string().optional();
+export const EVENT_PAID_OPTION = z.string().url().optional();