import { error, redirect, type Action, type Actions } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; import { createAdventureApiAdventuresPost, getUserProfileBffUserProfileGet } from '@client'; import * as v from 'valibot'; import { randomItemInArray, shuffleArray } from '$lib'; import { formatLanguage } from '$lib/formatters'; const allVibes = [ 'Melancholic', 'Gothic', 'Sun-drenched', 'Bleak', 'Whimsical', 'Eerie', 'Cosy', 'Tense', 'Witty', 'Propulsive', 'Mentor and student', 'Unlikely duo', 'Lone wolf', 'Queer-norm', 'Class tensions', 'Chosen family', 'Diaspora', 'Academia', 'Small town', 'The sea', 'Grand house', 'Road trip', 'A single night', 'Heist', 'Mystery box', 'Reluctant hero', 'Redemption', 'Animal companions', 'Gentle', 'Happy ever after', 'Bittersweet', 'Epistolary (letters / diary entries)', "A big city that isn't the capital", 'Parenthood', 'Sly', 'Slapstick', 'Recovery', 'Political', 'Apocalyptic', 'Post-apocalyptic', 'Survival', 'War', 'Spy thriller', 'Time travel' ]; const allGenres = [ 'Crime Fiction', 'Crime noir', 'Who-dun-it mystery', 'Paranormal', 'Horror', 'Psychological thriller', 'Romance', 'Family', 'Fantasy', 'Science Fiction' ]; export const load: PageServerLoad = async ({ locals }) => { let languageCode = 'fr'; let competency = 'A1'; const profile = await getUserProfileBffUserProfileGet({ headers: { Authorization: `Bearer ${locals.authToken}` } }); if (profile.error) { console.error({ error: profile.error }); } else { languageCode = profile.data?.learnable_languages[0].target_language ?? 'fr'; competency = profile.data?.learnable_languages[0].proficiencies[0] ?? competency; } return { lengths: ['100-200 Words', '200-350 Words', '350-500 Words', '500-750 Words'], competency: competency, language: { code: languageCode, label: formatLanguage(languageCode) }, competencies: ['A1', 'A2', 'B1', 'B2', 'C1'], languages: [ { code: 'fr', name: 'French' }, { code: 'de', name: 'German' }, { code: 'it', name: 'Italian' }, { code: 'es', name: 'Spanish' }, { code: 'pt', name: 'Portuguese' } ], genres: allGenres.sort((a, b) => a.localeCompare(b)), selectedGenre: randomItemInArray(allGenres), eras: [ 'Ancient/Classical', 'Medieval', '1500-1800', 'Renaissance', '19th century', 'Early 20th century', 'Mid-century', 'Contemporary', 'Near future', 'Far future' ], settings: [ 'Capital city', 'Large city (not the capital)', 'Urban', 'The suburbs', 'Rural', 'Pastoral', 'Small town', 'Wilderness', 'Space', 'Another planet' ], allVibes: allVibes, selectedVibes: shuffleArray(allVibes) .slice(0, 6) .sort((a, b) => a.localeCompare(b)) }; }; const CreateFormSchema = v.object({ vibes: v.array(v.string()), genre: v.string(), setting: v.string(), competency: v.pipe(v.string(), v.picklist(['A1', 'A2', 'B1', 'B2', 'C1'])), language: v.pipe(v.string(), v.picklist(['fr', 'it', 'de', 'it', 'es'])), length: v.string(), protagonist_gender: v.string(), protagonist_age: v.string() }); export const actions = { default: async ({ locals, request }) => { const { authToken } = locals; const formData = await request.formData(); const data = v.safeParse(CreateFormSchema, { vibes: formData.getAll('vibes') as string[], genre: formData.get('genre') as string, setting: formData.get('setting') as string, competency: formData.get('competency') as string, language: formData.get('language') as string, length: formData.get('length') as string, protagonist_gender: formData.get('protagonist_gender') as string, protagonist_age: formData.get('protagonist_age') as string }); if (data.success == false) { console.error({ formError: data.issues }); throw error(400, { message: data.issues.map((e) => `${e.path?.[0].key}: ${e.message}`).join(', ') }); } const { competency, language, length, genre, setting, protagonist_gender, protagonist_age, vibes } = data.output; const { data: apiData, error: apiError } = await createAdventureApiAdventuresPost({ headers: { Authorization: `Bearer ${authToken}` }, body: { competencies: [competency], language: language, genres: [genre], setting: [setting], vibes: vibes, protagonist: [protagonist_gender, protagonist_age], source_language: 'en', entry_word_count_range: length, max_entry_count: 6 } }); if (apiError) { return { error: `Error creating new adventure, try again` }; } redirect(303, '/app/adventures?created=true'); } } satisfies Actions;