From a9c7826ce451e151b091cbe7c0e9af07deea6e1c Mon Sep 17 00:00:00 2001 From: steel <mael.acier@ensiie.fr> Date: Sun, 1 Sep 2024 21:53:52 +0200 Subject: [PATCH] wip: level selector --- src/lib/data.ts | 31 +++---- src/lib/game.ts | 12 ++- src/lib/graphql/queries.ts | 4 +- src/lib/utils.ts | 2 + src/routes/quiz/+page.server.ts | 46 +++++++---- src/routes/quiz/+page.svelte | 31 +++---- src/routes/quiz/new/+page.server.ts | 109 +++++++++++++++++++++++++ src/routes/quiz/new/+page.svelte | 48 +++++++++++ src/routes/quiz/new/images/baby.png | Bin 0 -> 7183 bytes src/routes/quiz/new/images/index.ts | 7 ++ src/routes/quiz/new/images/student.png | Bin 0 -> 6793 bytes src/routes/quiz/new/schema.ts | 7 ++ 12 files changed, 247 insertions(+), 50 deletions(-) create mode 100644 src/routes/quiz/new/+page.server.ts create mode 100644 src/routes/quiz/new/+page.svelte create mode 100644 src/routes/quiz/new/images/baby.png create mode 100644 src/routes/quiz/new/images/index.ts create mode 100644 src/routes/quiz/new/images/student.png create mode 100644 src/routes/quiz/new/schema.ts diff --git a/src/lib/data.ts b/src/lib/data.ts index cf26ee64..bf92eed3 100644 --- a/src/lib/data.ts +++ b/src/lib/data.ts @@ -5,7 +5,7 @@ import { PROMOTION_QUERY, USER_DETAILS_QUERY } from './graphql/queries'; type UserId = string; type PromoCache = { lastUpdateMs: number; - promo: Set<UserId>; + promotion: Set<UserId>; }; const cache = new Map<number, PromoCache>(); @@ -26,8 +26,8 @@ async function cacheImages(users: UserId[]): Promise<void> { } } -async function fetchPromotion(promotion: number): Promise<PromoCache> { - const array = await Array.fromAsync(pageIterator(PROMOTION_QUERY, { promotion })); +async function fetchPromotion(year: number): Promise<PromoCache> { + const array = await Array.fromAsync(pageIterator(PROMOTION_QUERY, { year })); const users = array.map((node) => node.id); // background task @@ -35,30 +35,31 @@ async function fetchPromotion(promotion: number): Promise<PromoCache> { return { lastUpdateMs: new Date().getTime(), - promo: new Set(users) + promotion: new Set(users) }; } -export async function getPromotion(promo: number): Promise<Set<UserId>> { - if (cache.has(promo)) { - const data = cache.get(promo)!; - if (new Date().getTime() - data.lastUpdateMs < CACHE_DURATION_MS) return data.promo; +export async function getPromotion(year: number): Promise<Set<UserId>> { + if (cache.has(year)) { + const data = cache.get(year)!; + if (new Date().getTime() - data.lastUpdateMs < CACHE_DURATION_MS) return data.promotion; } - const freshData = await fetchPromotion(promo); - cache.set(promo, freshData); - return freshData.promo; + console.log('year', year, 'not in cache, fetching'); + const freshData = await fetchPromotion(year); + cache.set(year, freshData); + return freshData.promotion; } export async function* promotionIterator( min: number, max: number ): AsyncGenerator<UserId, void, undefined> { - for (let i = min; i <= max; i++) { - const promo = await getPromotion(i); - yield* promo; + for (let i = min; i < max; i++) { + const promotion = await getPromotion(i); + yield* promotion; } } -export function getPromotionRange(min: number, max: number): Promise<Set<UserId>> { +export function getPromotionRange(min: number, max = min): Promise<Set<UserId>> { return Array.fromAsync(promotionIterator(min, max)).then((array) => new Set(array)); } diff --git a/src/lib/game.ts b/src/lib/game.ts index 5ad81ad8..dcd2697a 100644 --- a/src/lib/game.ts +++ b/src/lib/game.ts @@ -3,6 +3,7 @@ import { SecureCookie } from './cookie'; import { z } from 'zod'; export enum GameStage { + NEW, PLAYING, SOLUTION, NEXT, @@ -15,6 +16,9 @@ export const gameStateSchema = z.object({ score: z.number(), options: z.array(z.string()), stage: z.nativeEnum(GameStage), + year: z.number(), + maxYear: z.number().optional(), + label: z.string(), solution: z.string() }); @@ -22,7 +26,7 @@ export type GameState = z.infer<typeof gameStateSchema>; export class Game { state: GameState; - protected cookie_name = 'qui-est-ce'; + protected cookie_name = 'quiestce-quiz'; protected cookie: SecureCookie<GameState>; constructor(protected cookies: Cookies) { @@ -32,12 +36,14 @@ export class Game { protected defaultState(): GameState { return { - stage: GameStage.NEXT, + stage: GameStage.NEW, history: [], step: 0, score: 0, + year: 0, options: [], - solution: '' + solution: '', + label: '?' }; } diff --git a/src/lib/graphql/queries.ts b/src/lib/graphql/queries.ts index c9bb02d9..f3aa344b 100644 --- a/src/lib/graphql/queries.ts +++ b/src/lib/graphql/queries.ts @@ -1,11 +1,11 @@ import { graphql } from '.'; export const PROMOTION_QUERY = graphql(` - query GetPromotion($first: Int!, $after: String, $promotion: Int!) { + query GetYear($first: Int!, $after: String, $year: Int!) { page: users( first: $first after: $after - filter: { promotion: { eq: [$promotion] }, nickname: { null: false }, photo: { null: false } } + filter: { year: { eq: [$year] }, nickname: { null: false }, photo: { null: false } } ) { pageInfo { endCursor diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 705385da..c92a0335 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -11,3 +11,5 @@ export function getRandomItems<T>(array: T[], count: number): T[] { items.push(item); return items; } + +export const sum = (a: number, b: number) => a + b; diff --git a/src/routes/quiz/+page.server.ts b/src/routes/quiz/+page.server.ts index ec9a25ef..943b4f0f 100644 --- a/src/routes/quiz/+page.server.ts +++ b/src/routes/quiz/+page.server.ts @@ -3,8 +3,8 @@ import { zod } from 'sveltekit-superforms/adapters'; import { schema } from './schema'; import { fail, redirect } from '@sveltejs/kit'; import { getRandomItems } from '$lib/utils'; -import { GameStage, Game } from '$lib/game'; -import { getPromotion } from '$lib/data'; +import { GameStage, Game, type GameState } from '$lib/game'; +import { getPromotionRange } from '$lib/data'; import { client } from '$lib/graphql'; import { USER_DETAILS_QUERY } from '$lib/graphql/queries'; import { handleGqlError } from '$lib/graphql/error'; @@ -14,21 +14,30 @@ type Option = { label: string; }; -export async function load(event) { - const game = new Game(event.cookies); - - if (game.state.stage === GameStage.GAME_OVER) redirect(303, '/quiz/game-over'); +async function next(state: GameState) { + const all = await getPromotionRange(state.year, state.maxYear); + const previous = new Set(state.history); + const available = all.difference(previous); - if (game.state.stage === GameStage.NEXT) { - const all = await getPromotion(2023); + state.options = getRandomItems(Array.from(available), 4); + state.solution = getRandomItems([...state.options], 1)[0]; + state.stage = GameStage.PLAYING; + state.step++; +} - const previous = new Set(game.state.history); - const available = all.difference(previous); +export async function load(event) { + const game = new Game(event.cookies); - game.state.options = getRandomItems(Array.from(available), 4); - game.state.solution = getRandomItems([...game.state.options], 1)[0]; - game.state.stage = GameStage.PLAYING; - game.state.step++; + switch (game.state.stage) { + case GameStage.NEW: + redirect(303, '/quiz/new'); + break; + case GameStage.GAME_OVER: + redirect(303, '/quiz/game-over'); + break; + case GameStage.NEXT: + await next(game.state); + break; } const details = await client @@ -46,7 +55,14 @@ export async function load(event) { const photo = users.find((node) => node.id === game.state.solution)?.photo; const form = await superValidate(zod(schema)); - return { form, options, score: game.state.score, step: game.state.step, photo }; + return { + form, + options, + score: game.state.score, + step: game.state.step, + photo, + label: game.state.label + }; } export const actions = { diff --git a/src/routes/quiz/+page.svelte b/src/routes/quiz/+page.svelte index 5ef86b11..4533b4c7 100644 --- a/src/routes/quiz/+page.svelte +++ b/src/routes/quiz/+page.svelte @@ -5,29 +5,31 @@ export let data; export let form; - const form2 = superForm(data.form, { + const sForm = superForm(data.form, { // On récupère les valeurs après affichage des résultats resetForm: false }); - const { form: formData, enhance } = form2; + const { form: formData, enhance } = sForm; const questionAmount = 10; </script> <div class="relative mx-auto my-12 w-full grow"> <section class="relative m-auto flex flex-col items-center"> - <h1 class="absolute -top-8 text-xl">Qui est-ce ?</h1> + <h1 class="absolute -top-8 text-xl">Qui est-ce ? {data.label}</h1> <div class="relative"> - <span class="absolute -left-14 flex flex-col items-end"> - <span class="text-9xl leading-[0.4] text-random-300"> {data.step} </span> - <span> / {questionAmount} </span> - </span> - <span - class="absolute right-[calc(100%_+_0.5rem)] top-24 whitespace-nowrap pt-4 text-xl text-zinc-800 before:absolute before:right-0 before:top-0 before:h-1.5 before:w-10 before:bg-zinc-800" - > - {data.score} - <small>pts</small> + <span class="absolute right-[calc(100%_+_0.5rem)] text-right"> + <span class="flex flex-col items-end"> + <span class="text-9xl leading-[0.4] text-random-300"> {data.step} </span> + <span> / {questionAmount} </span> + </span> + <span class="inline-block h-1.5 w-10 bg-zinc-800"></span> + <br /> + <span class="top-24 pt-4 text-xl text-zinc-800"> + {data.score} + <small>pts</small> + </span> </span> <div class="relative z-10 flex h-64 w-64 items-center justify-center overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-white before:absolute before:-z-10 before:h-32 before:w-32 before:rounded-full before:bg-slate-300 before:opacity-100 before:transition-[0.65s] before:duration-[ease-in-out] after:absolute after:-z-10 after:h-32 after:w-32 after:scale-0 after:rounded-full after:border-solid after:border-slate-300 after:transition-[0.4s] after:duration-[ease-in-out]" @@ -35,7 +37,7 @@ <img src={data.photo?.url} alt="Chargement..." class="w-auto" /> </div> <form method="post" use:enhance> - <Fieldset form={form2} name="choice"> + <Fieldset form={sForm} name="choice"> <div class="relative -top-6 z-20 mx-auto my-0 flex w-44 flex-col items-center space-y-0.5 rounded-2xl bg-zinc-800 px-5 py-0" > @@ -53,8 +55,7 @@ /> <Label tabindex={0} - data-solution={form?.solution || null} - class="relative block cursor-pointer select-none overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-slate-300 p-2 text-center text-lg transition-[0.45s] before:absolute before:left-2/4 before:top-2/4 before:-z-10 before:h-[200px] before:w-[200px] before:-translate-x-2/4 before:-translate-y-2/4 before:scale-0 before:rounded-full before:bg-indigo-300 before:transition-[0.2s] before:duration-[ease-in-out] focus:[outline:none] active:before:-translate-x-2/4 active:before:-translate-y-2/4 active:before:scale-100 peer-enabled:hover:translate-y-[-3px] peer-enabled:hover:bg-slate-400 peer-enabled:focus:border-indigo-500 peer-checked:peer-enabled:bg-indigo-300 data-[solution]:cursor-default data-[solution]:text-[#94acbd] peer-checked:data-[solution]:bg-red-400 peer-checked:data-[solution]:text-inherit peer-data-[valid]:!bg-lime-400 peer-data-[valid]:text-inherit" + class="relative block cursor-pointer select-none overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-slate-300 p-2 text-center text-lg transition-[0.45s] before:absolute before:left-2/4 before:top-2/4 before:-z-10 before:h-[200px] before:w-[200px] before:-translate-x-2/4 before:-translate-y-2/4 before:scale-0 before:rounded-full before:bg-indigo-300 before:transition-[0.2s] before:duration-[ease-in-out] focus:[outline:none] active:before:-translate-x-2/4 active:before:-translate-y-2/4 active:before:scale-100 peer-enabled:hover:translate-y-[-3px] peer-enabled:hover:bg-slate-400 peer-enabled:focus:border-indigo-500 peer-checked:peer-enabled:bg-indigo-300 peer-disabled:cursor-default peer-disabled:text-[#94acbd] peer-checked:peer-disabled:bg-red-400 peer-checked:peer-disabled:text-inherit peer-data-[valid]:!bg-lime-400 peer-data-[valid]:text-inherit" > {option.label} </Label> diff --git a/src/routes/quiz/new/+page.server.ts b/src/routes/quiz/new/+page.server.ts new file mode 100644 index 00000000..f839073e --- /dev/null +++ b/src/routes/quiz/new/+page.server.ts @@ -0,0 +1,109 @@ +import { superValidate } from 'sveltekit-superforms'; +import { zod } from 'sveltekit-superforms/adapters'; +import { schema } from './schema'; +import { fail, redirect } from '@sveltejs/kit'; +import { Game, GameStage } from '$lib/game'; +import { getPromotion } from '$lib/data'; +import images from './images'; +import { sum } from '$lib/utils'; + +type BaseLevel = { + year: number; + maxYear?: number; + name: string; + image: string; +}; + +type Level = BaseLevel & { + size: number; +}; + +const VIIEUX_YEAR = 20; + +export async function load(event) { + const game = new Game(event.cookies); + + if (game.state.stage !== GameStage.NEW) redirect(303, '/quiz'); + + const baseLevels: BaseLevel[] = [ + { + year: 1, + name: '1A', + image: images.baby + }, + { + year: 2, + name: '2A', + image: images.baby + }, + { + year: 3, + name: '3A', + image: images.student + }, + { + year: 1, + maxYear: 3, + name: '1-3A', + image: images.student + }, + { + year: 4, + name: '4A', + image: images.student + }, + { + year: 5, + name: '5A', + image: images.student + }, + { + year: 4, + maxYear: VIIEUX_YEAR, + name: 'Viieux', + image: images.student + }, + { + year: 1, + maxYear: VIIEUX_YEAR, + name: 'IIEns', + image: images.student + } + ]; + + const promoSizes = await Promise.all( + Array.from(new Array(VIIEUX_YEAR), (_, i) => getPromotion(i + 1).then((promo) => promo.size)) + ); + + const levels: Level[] = baseLevels.map((level) => { + const end = (level.maxYear ?? level.year) + 1; + return { + size: promoSizes.slice(level.year, end).reduce(sum, 0), + ...level + }; + }); + + const form = await superValidate(zod(schema)); + return { form, levels }; +} + +export const actions = { + async default(event) { + const form = await superValidate(event, zod(schema)); + + if (!form.valid) { + return fail(400, { form }); + } + + const state = new Game(event.cookies); + + state.state.year = form.data.year; + state.state.label = form.data.label; + state.state.maxYear = form.data.maxYear; + state.state.stage = GameStage.NEXT; + + state.save(); + + redirect(303, '/quiz'); + } +}; diff --git a/src/routes/quiz/new/+page.svelte b/src/routes/quiz/new/+page.svelte new file mode 100644 index 00000000..d7bc2c15 --- /dev/null +++ b/src/routes/quiz/new/+page.svelte @@ -0,0 +1,48 @@ +<script lang="ts"> + import { superForm } from 'sveltekit-superforms'; + import { Control, Field } from 'formsnap'; + + export let data; + + const form = superForm(data.form, { + // On récupère les valeurs après affichage des résultats + resetForm: false + }); + const { enhance } = form; +</script> + +<div class="m-16"> + <div class="flex flex-wrap items-center justify-center gap-8 text-gray-700"> + {#each data.levels as level} + <form method="post" use:enhance> + <Field {form} name="year"> + <Control let:attrs> + <input type="hidden" {...attrs} value={level.year} /> + </Control> + </Field> + <Field {form} name="maxYear"> + <Control let:attrs> + <input type="hidden" {...attrs} value={level.maxYear} /> + </Control> + </Field> + <Field {form} name="label"> + <Control let:attrs> + <input type="hidden" {...attrs} value={level.name} /> + </Control> + </Field> + <button + type="submit" + class="col-span-1 flex h-72 w-72 flex-col divide-y divide-gray-200 rounded-2xl border-6 border-solid border-zinc-800 bg-slate-100 text-center shadow transition-[0.45s] hover:translate-y-[-3px] hover:bg-slate-300 focus:border-indigo-500" + > + <div class="flex flex-1 flex-col p-8"> + <img class="mx-auto h-32 w-32 flex-shrink-0" src={level.image} alt="" /> + <h1 class="mt-4 text-6xl font-medium">{level.name}</h1> + <dl class="mt-1 flex flex-grow flex-col justify-between"> + <dd class="text-sm font-light text-gray-500">{level.size} personnes</dd> + </dl> + </div> + </button> + </form> + {/each} + </div> +</div> diff --git a/src/routes/quiz/new/images/baby.png b/src/routes/quiz/new/images/baby.png new file mode 100644 index 0000000000000000000000000000000000000000..60d09632825cea2366b7f0f19f7f2802ec29042c GIT binary patch literal 7183 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 I=akR{08NdI=Kufz literal 0 HcmV?d00001 diff --git a/src/routes/quiz/new/images/index.ts b/src/routes/quiz/new/images/index.ts new file mode 100644 index 00000000..a947a639 --- /dev/null +++ b/src/routes/quiz/new/images/index.ts @@ -0,0 +1,7 @@ +import baby from './baby.png'; +import student from './student.png'; + +export default { + baby, + student +}; diff --git a/src/routes/quiz/new/images/student.png b/src/routes/quiz/new/images/student.png new file mode 100644 index 0000000000000000000000000000000000000000..4df8222c20902f02cdb712ab556b047e1fa2ad68 GIT binary patch literal 6793 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 AX#fBK literal 0 HcmV?d00001 diff --git a/src/routes/quiz/new/schema.ts b/src/routes/quiz/new/schema.ts new file mode 100644 index 00000000..d561d4e5 --- /dev/null +++ b/src/routes/quiz/new/schema.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; + +export const schema = z.object({ + year: z.number(), + maxYear: z.number().optional(), + label: z.string() +}); -- GitLab