diff --git a/app/src/components/shared/EventSummary.svelte b/app/src/components/shared/EventSummary.svelte
index e636ad6..5f81810 100644
--- a/app/src/components/shared/EventSummary.svelte
+++ b/app/src/components/shared/EventSummary.svelte
@@ -43,7 +43,7 @@
diff --git a/app/src/components/shared/Footer.svelte b/app/src/components/shared/Footer.svelte
index 1fe7f4a..0b2ba61 100644
--- a/app/src/components/shared/Footer.svelte
+++ b/app/src/components/shared/Footer.svelte
@@ -20,31 +20,31 @@
Sertifiseringer
diff --git a/app/src/models/database.model.ts b/app/src/models/database.model.ts
index 51b3b76..b0c8496 100644
--- a/app/src/models/database.model.ts
+++ b/app/src/models/database.model.ts
@@ -44,6 +44,32 @@ export type Database = {
},
];
};
+ event_invitation: {
+ Row: {
+ email: string;
+ event_id: number;
+ full_name: string | null;
+ };
+ Insert: {
+ email: string;
+ event_id: number;
+ full_name?: string | null;
+ };
+ Update: {
+ email?: string;
+ event_id?: number;
+ full_name?: string | null;
+ };
+ Relationships: [
+ {
+ foreignKeyName: "event_invitation_event_id_fkey";
+ columns: ["event_id"];
+ isOneToOne: false;
+ referencedRelation: "event";
+ referencedColumns: ["event_id"];
+ },
+ ];
+ };
event_participant: {
Row: {
attending: boolean;
diff --git a/studio/components/event/EventFoodPreference.tsx b/studio/components/event/EventFoodPreference.tsx
index f667db4..b48b61c 100644
--- a/studio/components/event/EventFoodPreference.tsx
+++ b/studio/components/event/EventFoodPreference.tsx
@@ -1,12 +1,12 @@
import React from "react";
import { useQuery } from "@tanstack/react-query";
import { Card, Flex, Grid, Heading, Spinner, Stack, Text } from "@sanity/ui";
-import { getEventFoodPreferences } from "../../supabase/queries";
+import { getEventFoodPreferenceList } from "../../supabase/queries";
export default function EventFoodPreference({ documentId }: { documentId: string }) {
const { data, isLoading, isError } = useQuery({
queryKey: ["event-food-preference-list", documentId],
- queryFn: () => getEventFoodPreferences({ documentId }),
+ queryFn: () => getEventFoodPreferenceList({ documentId }),
});
const cardProps = { border: true, padding: 3, radius: 2 };
diff --git a/studio/components/event/EventInvitation.tsx b/studio/components/event/EventInvitation.tsx
new file mode 100644
index 0000000..b3a370f
--- /dev/null
+++ b/studio/components/event/EventInvitation.tsx
@@ -0,0 +1,207 @@
+import React, { useState } from "react";
+import { useQuery, useQueryClient } from "@tanstack/react-query";
+import {
+ Box,
+ Button,
+ Card,
+ Flex,
+ Grid,
+ Heading,
+ Label,
+ Spinner,
+ Stack,
+ Text,
+ TextInput,
+ useToast,
+} from "@sanity/ui";
+import { getEvent, getEventInvitationList, insertInvitation } from "../../supabase/queries";
+import { AddIcon } from "@sanity/icons";
+
+export default function EventInvitation({ documentId }: { documentId: string }) {
+ const toast = useToast();
+
+ const [email, setEmail] = useState
("");
+ const [fullName, setFullName] = useState("");
+
+ const { data: event } = useQuery({
+ queryKey: ["event", documentId],
+ queryFn: () => getEvent({ document_id: documentId }),
+ });
+
+ const { data, isLoading, isError } = useQuery({
+ queryKey: ["event-invitation-list", documentId],
+ queryFn: () => getEventInvitationList({ documentId }),
+ });
+
+ const queryClient = useQueryClient();
+
+ async function handleInvitationAdd() {
+ const emailRegex = new RegExp("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{1,}$");
+ if (!email || !emailRegex.test(email)) return;
+
+ try {
+ await insertInvitation({ document_id: documentId }, { full_name: fullName, email });
+
+ queryClient.invalidateQueries({ queryKey: ["event-invitation-list"] });
+
+ setEmail("");
+ setFullName("");
+
+ toast.push({
+ status: "success",
+ title: `${email} ble lagt til i listen`,
+ });
+ } catch (error) {
+ if (error instanceof Error) {
+ toast.push({
+ status: "error",
+ title: error.message,
+ });
+ }
+ }
+ }
+
+ const cardProps = { border: true, padding: 3, radius: 2 };
+
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ if (isError)
+ return (
+
+
+ Arrangement
+
+
+ En feil har oppstått
+
+
+ );
+
+ if (!data?.length) {
+ return (
+
+
+ Arrangement
+
+
+ Ingen invitasjoner
+
+
+ {event?.data ? (
+ <>
+
+
+
+ Fulltnavn
+
+ setFullName(event.currentTarget.value)}
+ padding={2}
+ value={fullName}
+ />
+
+
+
+ E-post*
+
+ setEmail(event.currentTarget.value)}
+ padding={2}
+ value={email}
+ />
+
+
+
+ handleInvitationAdd()}
+ padding={3}
+ text="Legg til"
+ />
+
+ >
+ ) : null}
+
+ );
+ }
+
+ return (
+ <>
+
+
+ Arrangement
+
+
+ Invitasjoner ({data.length})
+
+
+
+
+
+ Fulltnavn
+
+
+ setFullName(event.currentTarget.value)}
+ padding={2}
+ value={fullName}
+ />
+
+
+
+ E-post*
+
+ setEmail(event.currentTarget.value)}
+ padding={2}
+ value={email}
+ />
+
+
+
+
+ handleInvitationAdd()}
+ padding={3}
+ text="Legg til"
+ />
+
+
+
+
+ {data.map(({ email, full_name }, index) => (
+
+
+
+ {full_name ? `${full_name} - ${email}` : email}
+
+
+
+ ))}
+
+ >
+ );
+}
diff --git a/studio/config/structure.tsx b/studio/config/structure.tsx
index bf983bc..6399a7f 100644
--- a/studio/config/structure.tsx
+++ b/studio/config/structure.tsx
@@ -3,6 +3,7 @@ import { QueryClient } from "@tanstack/react-query";
import EventFoodPreference from "../components/event/EventFoodPreference";
import EventLayout from "../components/event/EventLayout";
import EventParticipant from "../components/event/EventParticipant";
+import EventInvitation from "../components/event/EventInvitation";
const queryClient = new QueryClient();
@@ -36,6 +37,15 @@ export const getDefaultDocumentNode = (
);
})
.title("Allergier/matpreferanser"),
+ S.view
+ .component(({ documentId }: { documentId: string }) => {
+ return (
+
+
+
+ );
+ })
+ .title("Invitasjoner"),
]);
}
return S.document().views([S.view.form()]);
diff --git a/studio/models/database.model.ts b/studio/models/database.model.ts
index 51b3b76..b0c8496 100644
--- a/studio/models/database.model.ts
+++ b/studio/models/database.model.ts
@@ -44,6 +44,32 @@ export type Database = {
},
];
};
+ event_invitation: {
+ Row: {
+ email: string;
+ event_id: number;
+ full_name: string | null;
+ };
+ Insert: {
+ email: string;
+ event_id: number;
+ full_name?: string | null;
+ };
+ Update: {
+ email?: string;
+ event_id?: number;
+ full_name?: string | null;
+ };
+ Relationships: [
+ {
+ foreignKeyName: "event_invitation_event_id_fkey";
+ columns: ["event_id"];
+ isOneToOne: false;
+ referencedRelation: "event";
+ referencedColumns: ["event_id"];
+ },
+ ];
+ };
event_participant: {
Row: {
attending: boolean;
diff --git a/studio/supabase/queries.ts b/studio/supabase/queries.ts
index 52a9be5..22424b7 100644
--- a/studio/supabase/queries.ts
+++ b/studio/supabase/queries.ts
@@ -1,6 +1,11 @@
import { Tables } from "../models/database.model";
import { supabase } from "./client";
+export const getEvent = async ({ document_id }: Pick, "document_id">) => {
+ const result = await supabase.from("event").select().eq("document_id", document_id).maybeSingle();
+ return result;
+};
+
export async function getEventParticipantList({ documentId }: { documentId: string }) {
try {
const { data } = await supabase
@@ -9,7 +14,6 @@ export async function getEventParticipantList({ documentId }: { documentId: stri
.eq("document_id", documentId)
.eq("event_participant.attending", true)
.maybeSingle();
-
return data;
} catch (error) {
console.error(error);
@@ -17,7 +21,7 @@ export async function getEventParticipantList({ documentId }: { documentId: stri
}
}
-export async function getEventFoodPreferences({ documentId }: { documentId: string }) {
+export async function getEventFoodPreferenceList({ documentId }: { documentId: string }) {
try {
const { data } = await supabase
.from("event")
@@ -34,6 +38,49 @@ export async function getEventFoodPreferences({ documentId }: { documentId: stri
}
}
+export async function getEventInvitationList({ documentId }: { documentId: string }) {
+ try {
+ const { data } = await supabase
+ .from("event")
+ .select("event_invitation(*)")
+ .eq("document_id", documentId);
+
+ if (data?.length) {
+ return data.flatMap(({ event_invitation }) => event_invitation);
+ }
+ return [];
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+}
+
+export const insertInvitation = async (
+ { document_id }: Pick, "document_id">,
+ payload: Pick, "email" | "full_name">
+) => {
+ const { data, error } = await supabase
+ .from("event")
+ .select()
+ .eq("document_id", document_id)
+ .maybeSingle();
+
+ if (error) {
+ throw new Error(error.message);
+ }
+
+ if (data) {
+ const { error: insertError } = await supabase
+ .from("event_invitation")
+ .insert({ event_id: data.event_id, ...payload })
+ .select("*");
+
+ if (insertError) {
+ throw new Error(`${payload.email} er allerede lagt til`);
+ }
+ }
+};
+
export const createEventIfNotExist = async ({
document_id,
}: Pick, "document_id">) => {