✨ feat(epic-4): chemins narratifs, easter eggs, challenge et contact
Epic 4: Chemins Narratifs, Challenge & Contact Stories implementees: - 4.1: Composant ChoiceCards pour choix narratifs binaires - 4.2: Sequence d'intro narrative avec Le Bug - 4.3: Chemins narratifs differencies avec useNarrativePath - 4.4: Table easter_eggs et systeme de detection (API + composable) - 4.5: Easter eggs UI (popup, notification, collection) - 4.6: Page challenge avec puzzle de code - 4.7: Page revelation "Monde de Code" - 4.8: Page contact avec formulaire et stats Fichiers crees: - Frontend: ChoiceCards, IntroSequence, ZoneEndChoice, EasterEggPopup, CodePuzzle, ChallengeSuccess, CodeWorld, et pages intro/challenge/revelation - API: EasterEggController, Model, Migration, Seeder Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
83
frontend/app/composables/useFetchEasterEggs.ts
Normal file
83
frontend/app/composables/useFetchEasterEggs.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
export type TriggerType = 'click' | 'hover' | 'konami' | 'scroll' | 'sequence'
|
||||
export type RewardType = 'snippet' | 'anecdote' | 'image' | 'badge'
|
||||
|
||||
export interface EasterEggMeta {
|
||||
slug: string
|
||||
location: string
|
||||
trigger_type: TriggerType
|
||||
difficulty: number
|
||||
}
|
||||
|
||||
export interface EasterEggReward {
|
||||
slug: string
|
||||
reward_type: RewardType
|
||||
reward: string
|
||||
difficulty: number
|
||||
}
|
||||
|
||||
interface EasterEggListResponse {
|
||||
data: EasterEggMeta[]
|
||||
meta: { total: number }
|
||||
}
|
||||
|
||||
interface EasterEggValidateResponse {
|
||||
data: EasterEggReward
|
||||
}
|
||||
|
||||
export function useFetchEasterEggs() {
|
||||
const config = useRuntimeConfig()
|
||||
const { locale } = useI18n()
|
||||
|
||||
// Cache des easter eggs disponibles
|
||||
const availableEasterEggs = ref<EasterEggMeta[]>([])
|
||||
const isLoaded = ref(false)
|
||||
|
||||
async function fetchList(): Promise<EasterEggMeta[]> {
|
||||
if (isLoaded.value) return availableEasterEggs.value
|
||||
|
||||
try {
|
||||
const response = await $fetch<EasterEggListResponse>('/easter-eggs', {
|
||||
baseURL: config.public.apiUrl as string,
|
||||
headers: {
|
||||
'X-API-Key': config.public.apiKey as string,
|
||||
},
|
||||
})
|
||||
|
||||
availableEasterEggs.value = response.data
|
||||
isLoaded.value = true
|
||||
return response.data
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function validate(slug: string): Promise<EasterEggReward | null> {
|
||||
try {
|
||||
const response = await $fetch<EasterEggValidateResponse>(`/easter-eggs/${slug}/validate`, {
|
||||
method: 'POST',
|
||||
baseURL: config.public.apiUrl as string,
|
||||
headers: {
|
||||
'X-API-Key': config.public.apiKey as string,
|
||||
'Accept-Language': locale.value,
|
||||
},
|
||||
})
|
||||
return response.data
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function getByLocation(location: string): EasterEggMeta[] {
|
||||
return availableEasterEggs.value.filter(
|
||||
e => e.location === location || e.location === 'global'
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
availableEasterEggs: readonly(availableEasterEggs),
|
||||
isLoaded: readonly(isLoaded),
|
||||
fetchList,
|
||||
validate,
|
||||
getByLocation,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user