Skip to content

Commit

Permalink
Feature/option text (#74)
Browse files Browse the repository at this point in the history
Co-authored-by: Sofie Aasheim <[email protected]>
Co-authored-by: Anton Lilleby <[email protected]>
  • Loading branch information
3 people authored Jun 25, 2024
1 parent b88f89f commit 433508b
Show file tree
Hide file tree
Showing 26 changed files with 5,716 additions and 7,078 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,5 @@ Hvis du vil teste e-post lokalt, kan du legge til http://localhost:5173 i Access
I tillegg må denne linjen kommenteres ut:

```
if (process.env.MODE === "development") return;
process.env.MODE !== "development"
```
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"prettier-plugin-svelte": "^3.2.2",
"prettier-plugin-tailwindcss": "^0.6.1",
"svelte": "^4.2.12",
"sveltekit-rate-limiter": "^0.5.1",
"sveltekit-superforms": "^2.13.1",
"tailwindcss": "^3.4.3",
"tslib": "^2.6.2",
Expand Down
7 changes: 5 additions & 2 deletions app/src/components/external/EventFormExternal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import {
registrationSchemaExternal,
unregistrationSchemaExternal,
type RegistrationFormExternalType,
type UnregistrationFormExternalType,
} from "$lib/schemas/external/schema";
import { getAlertColor } from "$lib/utils/form.util";
import type { Event } from "$models/sanity.model";
Expand All @@ -20,7 +22,7 @@
errors: registrationErrors,
delayed: registrationDelayed,
enhance: registrationEnhance,
} = superForm(data.registrationForm, {
} = superForm<RegistrationFormExternalType>(data.registrationForm, {
validators: zod(registrationSchemaExternal),
delayMs: 500,
async onSubmit() {
Expand All @@ -34,8 +36,9 @@
errors: unregistrationErrors,
delayed: unregistrationDelayed,
enhance: unregistrationEnhance,
} = superForm(data.unregistrationForm, {
} = superForm<UnregistrationFormExternalType>(data.unregistrationForm, {
validators: zod(unregistrationSchemaExternal),
dataType: "json",
delayMs: 500,
async onSubmit() {
await new Promise((result) => setTimeout(result, 500));
Expand Down
8 changes: 6 additions & 2 deletions app/src/components/external/RegistrationFormExternal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import RegistrationFoodPreference from "$components/shared/RegistrationFoodPreference.svelte";
import Deadline from "$components/shared/Deadline.svelte";
import RegistrationCustomOption from "$components/shared/RegistrationCustomOption.svelte";
import { sanitize } from "$lib/utils/sanitize.util";
import { dateHasPassed } from "$lib/utils/date.util";
import { vercelStegaCleanAll } from "@sanity/client/stega";
export let event: Event;
export let numberOfParticipants: number;
Expand Down Expand Up @@ -92,7 +92,11 @@

{#if event.customOptions?.length}
{#each event.customOptions as customOption}
<RegistrationCustomOption label={customOption} option={sanitize(customOption)} {form} />
<RegistrationCustomOption
{form}
type={vercelStegaCleanAll(customOption.fieldType)}
option={vercelStegaCleanAll(customOption.fieldOption)}
/>
{/each}
{/if}

Expand Down
13 changes: 8 additions & 5 deletions app/src/components/internal/EventFormInternal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import UnregistrationFormInternal from "$components/internal/UnregistrationFormInternal.svelte";
import type { Event } from "$models/sanity.model";
import { superForm } from "sveltekit-superforms/client";
import { zod } from "sveltekit-superforms/adapters";
import {
registrationSchemaInternal,
unregistrationSchemaInternal,
type RegistrationFormInternalType,
type UnregistrationFormInternalType,
} from "$lib/schemas/internal/schema";
import { Alert } from "flowbite-svelte";
import { getAlertColor } from "$lib/utils/form.util";
import { zod } from "sveltekit-superforms/adapters";
export let data;
export let event: Event;
Expand All @@ -20,23 +22,24 @@
message: registrationMessage,
delayed: registrationDelayed,
enhance: registrationEnhance,
} = superForm(data.registrationForm, {
} = superForm<RegistrationFormInternalType>(data.registrationForm, {
validators: zod(registrationSchemaInternal),
dataType: "json",
delayMs: 500,
async onSubmit() {
await new Promise((result) => setTimeout(result, 500));
await new Promise((result) => setTimeout(result, 250));
},
});
const {
message: unregistrationMessage,
delayed: unregistrationDelayed,
enhance: unregistrationEnhance,
} = superForm(data.unregistrationForm, {
} = superForm<UnregistrationFormInternalType>(data.unregistrationForm, {
validators: zod(unregistrationSchemaInternal),
delayMs: 500,
async onSubmit() {
await new Promise((result) => setTimeout(result, 500));
await new Promise((result) => setTimeout(result, 250));
},
});
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
</span>
{/each}
{:else}
<p>Det er foreløpig ingen påmeldte 😔</p>
<p>Det er foreløpig ingen kollegaer som er påmeldt 😔</p>
{/if}
10 changes: 7 additions & 3 deletions app/src/components/internal/RegistrationFormInternal.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts">
import type { Event } from "$models/sanity.model";
import { Alert, Button, Spinner } from "flowbite-svelte";
import { Button, Spinner } from "flowbite-svelte";
import RegistrationFoodPreference from "$components/shared/RegistrationFoodPreference.svelte";
import RegistrationAttendingType from "$components/shared/RegistrationAttendingType.svelte";
import RegistrationCustomOption from "$components/shared/RegistrationCustomOption.svelte";
import { sanitize } from "$lib/utils/sanitize.util";
import { dateHasPassed } from "$lib/utils/date.util";
import Deadline from "$components/shared/Deadline.svelte";
import { vercelStegaCleanAll } from "@sanity/client/stega";
export let event: Event;
export let numberOfParticipants: number;
Expand Down Expand Up @@ -43,7 +43,11 @@

{#if event.customOptions?.length}
{#each event.customOptions as customOption}
<RegistrationCustomOption label={customOption} option={sanitize(customOption)} {form} />
<RegistrationCustomOption
{form}
option={vercelStegaCleanAll(customOption.fieldOption)}
type={vercelStegaCleanAll(customOption.fieldType)}
/>
{/each}
{/if}

Expand Down
8 changes: 2 additions & 6 deletions app/src/components/shared/Deadline.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
<script lang="ts">
import { formatDateWithWeekDay, formatTime } from "$lib/utils/date.util";
import { Badge } from "flowbite-svelte";
export let deadline: string;
</script>

<div class="flex gap-1">
<p class="text-sm">Fristen for å melde seg på er</p>
<Badge color="yellow" rounded class="h-5"
>{formatDateWithWeekDay(deadline)} kl {formatTime(deadline)}</Badge
>
<p>Fristen for å melde seg på er</p>
{formatDateWithWeekDay(deadline)} kl {formatTime(deadline)}
</div>
51 changes: 45 additions & 6 deletions app/src/components/shared/RegistrationCustomOption.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
<script lang="ts">
import { Checkbox } from "flowbite-svelte";
import { Checkbox, Input } from "flowbite-svelte";
import { writable } from "svelte/store";
export let form;
export let option;
export let label;
export let form = writable<{
customOptions: {
value: string;
option: string;
}[];
}>();
export let option: string;
export let type: string;
function handleCheckboxChange(event: Event) {
const target = event.target as HTMLInputElement;
if (target) {
handleValueChange(option, target.checked ? "Ja" : "");
}
}
function handleInputChange(event: Event) {
const target = event.target as HTMLInputElement;
if (target) {
handleValueChange(option, target.value);
}
}
function handleValueChange(option: string, value: string) {
form.update((currentForm) => {
const updatedOptions = currentForm.customOptions.filter(
(customOption) => customOption.value && customOption.option !== option
);
if (value) {
updatedOptions.push({ option, value });
}
currentForm.customOptions = updatedOptions;
return currentForm;
});
}
</script>

<div class="flex flex-col gap-1">
<span class="block text-sm font-bold text-gray-900 rtl:text-right dark:text-gray-300"
>{label}</span
>{option}</span
>
<Checkbox value={option} name="customOptions" bind:group={$form.customOptions}>Ja</Checkbox>
{#if type === "checkbox"}
<Checkbox name="customOptions" on:change={handleCheckboxChange}>Ja!</Checkbox>
{:else}
<Input name="customOptions" on:input={handleInputChange} />
{/if}
</div>
64 changes: 46 additions & 18 deletions app/src/lib/actions/external/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import validator from "validator";
import { type Actions } from "@sveltejs/kit";
import { superValidate, message } from "sveltekit-superforms/server";
import { zod } from "sveltekit-superforms/adapters";
import { sanitize } from "$lib/utils/sanitize.util";
import { getUnsubscribeSecret } from "$lib/auth/secret";
import { getEventContent } from "$lib/server/sanity/queries";
import { getEvent, getEventParticipant } from "$lib/server/supabase/queries";
Expand All @@ -20,11 +19,25 @@ import {
} from "$lib/schemas/external/schema";
import { sendRegistrationConfirmed } from "$lib/email/event/registration";
import { sendConfirmUnregistration } from "$lib/email/event/unregistration";
import { RateLimiter } from "sveltekit-rate-limiter/server";

/**
** IP: Allows 20 requests per hour from the same IP address.
** IPUA (IP and User-Agent): Allows 10 requests per 5 minutes when both the IP address and the User-Agent of the requester are considered.
**/
const limiter = new RateLimiter({
IP: [20, "h"],
IPUA: [10, "m"],
});

export const submitRegistrationExternal: Actions["submitRegistrationExternal"] = async (
requestEvent
) => {
const {
request,
params: { id },
} = requestEvent;

export const submitRegistrationExternal: Actions["submitRegistrationExternal"] = async ({
request,
params: { id },
}) => {
const registrationForm = await superValidate(request, zod(registrationSchemaExternal));

if (!registrationForm.valid) {
Expand All @@ -45,6 +58,13 @@ export const submitRegistrationExternal: Actions["submitRegistrationExternal"] =
});
}

if (await limiter.isLimited(requestEvent)) {
return message(registrationForm, {
text: "Du har nådd grensen for antall forsøk. Vennligst vent en stund før du prøver igjen.",
error: true,
});
}

const { data: event } = await getEvent({ document_id: id });

if (!event) {
Expand Down Expand Up @@ -114,14 +134,12 @@ export const submitRegistrationExternal: Actions["submitRegistrationExternal"] =
participantPayload
);

if (customOptions.length && eventContent.customOptions?.length) {
const participantOptionsPayload = eventContent.customOptions
.filter((field) => customOptions.includes(sanitize(field)))
.map((option) => ({
option,
event_participant_id,
value: true,
}));
if (customOptions.length) {
const participantOptionsPayload = customOptions.map(({ option, value }) => ({
event_participant_id,
option,
value,
}));

await insertEventParticipantOptions(transaction, participantOptionsPayload);
}
Expand Down Expand Up @@ -169,10 +187,14 @@ export const submitRegistrationExternal: Actions["submitRegistrationExternal"] =
});
};

export const submitUnregistrationExternal: Actions["submitUnregistrationExternal"] = async ({
request,
params: { id },
}) => {
export const submitUnregistrationExternal: Actions["submitUnregistrationExternal"] = async (
requestEvent
) => {
const {
request,
params: { id },
} = requestEvent;

const unregistrationForm = await superValidate(request, zod(unregistrationSchemaExternal));

if (!unregistrationForm.valid) {
Expand All @@ -193,6 +215,13 @@ export const submitUnregistrationExternal: Actions["submitUnregistrationExternal
});
}

if (await limiter.isLimited(requestEvent)) {
return message(unregistrationForm, {
text: "Du har nådd grensen for antall forsøk. Vennligst vent en stund før du prøver igjen.",
error: true,
});
}

const event = await getEvent({ document_id: id });

if (!event.data?.event_id) {
Expand Down Expand Up @@ -258,7 +287,6 @@ export const submitUnregistrationExternal: Actions["submitUnregistrationExternal
}

return message(unregistrationForm, {
token,
text: "En e-post har blitt sendt til adressen du oppga. Vennligst følg instruksjonen i e-posten for å fullføre.",
success: true,
});
Expand Down
Loading

0 comments on commit 433508b

Please sign in to comment.