MVP #6.1 #82

Merged
matthieu42morin merged 34 commits from master into deploy/prod 2023-03-31 17:40:26 +00:00
6 changed files with 85 additions and 27 deletions
Showing only changes of commit 59f98fadad - Show all commits

View File

@ -39,4 +39,5 @@ export type Experience = {
ExpURL: string ExpURL: string
UserID: string UserID: string
checkPoints: Array<CheckPoint> checkPoints: Array<CheckPoint>
rating: number
} }

View File

@ -0,0 +1,20 @@
<script lang="ts">
import { Progressbar } from 'flowbite-svelte'
export let max: number
export let progress: number
export let showWrittenProgress = false
export let labelInside: boolean = false
$: value = JSON.stringify((progress / max) * 100)
let className = ''
export { className as class }
</script>
<div class={`w-full h-auto flex flex-wrap flex-row justify-center ${className}`}>
{#if showWrittenProgress}
<span>{progress}/{max}</span>
{/if}
<Progressbar {labelInside} progress={value} />
</div>

View File

@ -50,18 +50,19 @@ export const answer = async (experienceId: string, checkPointId: string, answer:
const checkPoint = await databases.getDocument('63cef30d6da945dd4250', '63cef84d908acf805758', checkPointId) const checkPoint = await databases.getDocument('63cef30d6da945dd4250', '63cef84d908acf805758', checkPointId)
console.log({ checkPoint }) console.log({ checkPoint })
const { CPType, CPAnswerID } = checkPoint const { CPType, CPAnswerID } = checkPoint
const correctAnswer = (await databases.getDocument('63cef30d6da945dd4250', '63dd5c2b764061e40025', CPAnswerID)).CPAnswer const correctAnswer = CPType !== 'INFO' ? (await databases.getDocument('63cef30d6da945dd4250', '63dd5c2b764061e40025', CPAnswerID)).CPAnswer : true
let correct: boolean = false let correct: boolean = false
if (CPType === 'CHECKBOX') correct = JSON.stringify(answer) === JSON.stringify(correctAnswer) if (CPType === 'CHECKBOX') correct = JSON.stringify(answer) === JSON.stringify(correctAnswer)
if (CPType === 'RADIO' || CPType === 'NUMBER' || CPType === 'TEXT') correct = answer === correctAnswer[0] if (CPType === 'RADIO' || CPType === 'NUMBER' || CPType === 'TEXT') correct = answer === correctAnswer[0]
if (CPType === 'INFO') correct = false
await saveAnswerIntoDatabase(experienceId, checkPointId, correct) await saveAnswerIntoDatabase(experienceId, checkPointId, correct)
return correct return correct
} catch (error) { } catch (error) {
throw new Error(error) throw new Error(error)
//operation only for sveltekit 401, 500, 403 //operation only for sveltekit 401, 500, 403
} }
} }
@ -136,10 +137,12 @@ export const getUserProgress = async (experienceId: string) => {
} }
export const getUserProgressAsStore = (experienceId: string) => { export const getUserProgressAsStore = (experienceId: string) => {
const store = writable<Models.Document[]>([]) const store = writable<Models.Document[]>([])
const loading = writable<boolean>(true)
getUserProgress(experienceId).then((documents) => { getUserProgress(experienceId).then((documents) => {
store.set(documents) store.set(documents)
loading.set(false)
}) })
return [store] as const return [store, loading] as const
} }
// !pridat trideni podle kategorie! export const getExperiencesByCategory = async (category: string) => {} // !pridat trideni podle kategorie! export const getExperiencesByCategory = async (category: string) => {}

View File

@ -3,10 +3,12 @@
import Button from '$lib/components/Buttons/Button.svelte' import Button from '$lib/components/Buttons/Button.svelte'
import Image from '$lib/components/Common/Image.svelte' import Image from '$lib/components/Common/Image.svelte'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import Loading from '$lib/components/Common/Loading.svelte'
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let control: 'wrong-firstTime' | 'wrong-secondTime' | 'correct' | 'not-control' | null export let control: 'wrong-firstTime' | 'wrong-secondTime' | 'correct' | 'not-control' | null
export let imgSrc export let imgSrc
export let loading: boolean
</script> </script>
<div> <div>
@ -43,7 +45,13 @@
{#if control === 'not-control' || control === 'correct' || control === 'wrong-secondTime'} {#if control === 'not-control' || control === 'correct' || control === 'wrong-secondTime'}
<Button on:submit={() => dispatch('nextQuestion')} primary class="w-3/4 max-w-sm min-w-[400px] h-16 bottom-0 m-10 relative">Na další otázku</Button> <Button on:submit={() => dispatch('nextQuestion')} primary class="w-3/4 max-w-sm min-w-[400px] h-16 bottom-0 m-10 relative">Na další otázku</Button>
{:else if control === 'wrong-firstTime' || control === null} {:else if control === 'wrong-firstTime' || control === null}
<Button on:submit primary class="w-3/4 max-w-sm min-w-[400px] h-16 bottom-0 m-10 relative">Vyhodnotit</Button> <Button disabled={loading} on:submit primary class="w-3/4 max-w-sm min-w-[400px] h-16 bottom-0 m-10 relative">
{#if loading}
<Loading />
{:else}
Vyhodnotit
{/if}
</Button>
{/if} {/if}
</div> </div>
</div> </div>

View File

@ -12,11 +12,12 @@
import Info from './Info.svelte' import Info from './Info.svelte'
import { Experience } from '$lib/TStypes/experiences' import { Experience } from '$lib/TStypes/experiences'
import Layout from '../Components/Layout.svelte' import Layout from '../Components/Layout.svelte'
import { answer, AnswerState, getUserAnswer } from '$lib/utils/database/experience' import { answer, AnswerState, getUserAnswer, getUserProgressAsStore } from '$lib/utils/database/experience'
import { user } from '$lib/appwrite' import { user } from '$lib/appwrite'
import Button from '$lib/components/Buttons/Button.svelte' import Button from '$lib/components/Buttons/Button.svelte'
import LayoutImg from '$lib/components/Layouts/LayoutImg.svelte' import LayoutImg from '$lib/components/Layouts/LayoutImg.svelte'
import { Models } from 'appwrite' import { Models } from 'appwrite'
import { Writable } from 'svelte/store'
const components = { const components = {
TEXT: TextForm, TEXT: TextForm,
@ -31,17 +32,24 @@
export let control: AnswerState = null export let control: AnswerState = null
let view: 'question' | 'map' | 'end' | 'start' | 'start-map' = 'start-map' let view: 'question' | 'map' | 'end' | 'start' | 'start-map' = 'start-map'
export let gameData: Experience //data export let gameData: Experience //data
export let userProgress: Models.Document[] $: [userProgress, userProgressLoading] = gameData ? getUserProgressAsStore(gameData?.$id) : []
let client = { let client = {
//user data about game //user data about game
pos: userProgress.length, pos: 0,
end: gameData.checkPoints.length - 1, //kolik otázek end: gameData.ExpCPsID.length - 1, //kolik otázek
points: 0, //body points: 0, //body
possiblePointsToSeize: gameData.checkPoints.length * 2, possiblePointsToSeize: gameData.checkPoints.length * 2,
} }
$: if (client.pos < $userProgress?.length - 1 + 1) {
// nastaví na continue
client.pos = $userProgress?.length - 1 + 1
view = 'map'
}
$: if (gameData.checkPoints[client.pos].CPType === 'INFO') control = 'not-control' $: if (gameData.checkPoints[client.pos].CPType === 'INFO' && !$userProgressLoading) control = 'not-control'
$: console.log(control)
const nextQuestion = () => { const nextQuestion = () => {
//další otázka //další otázka
@ -53,35 +61,41 @@
} }
} }
//let answers $: checkPoint = gameData.checkPoints[client.pos]
//$: if (client.pos < client.end) answers = parseQuestion(gameData.questions[client.pos].answer, gameData.questions[client.pos].type) //delete $: checkPointType = checkPoint.CPType
let page = null let page = null
$: page = view === 'question' ? components[gameData.checkPoints[client.pos].CPType] : null $: page = view === 'question' ? components[checkPointType] : null
let [lat, lng] = [null, null] let [lat, lng] = [null, null]
$: if (client.pos < client.end) [lat, lng] = view === 'map' ? gameData.checkPoints[client.pos].CPLocation : gameData.ExpLocation $: if (client.pos < client.end) [lat, lng] = view === 'map' ? gameData.checkPoints[client.pos].CPLocation : gameData.ExpLocation
let userLocation = { lat: 0, lng: 0 } let userLocation = { lat: 0, lng: 0 }
$: checkPoint = gameData.checkPoints[client.pos]
let myAnswer: string | string[] let myAnswer: string | string[]
let clear: boolean = false let clear: boolean = false
let answerLoading = false
const checkAnswer = async () => { const checkAnswer = async () => {
answerLoading = true
try { try {
const res = await answer(gameData.$id, checkPoint.$id, myAnswer) const res = await answer(gameData.$id, checkPoint.$id, myAnswer)
if (checkPointType === 'INFO') {
if (res) { nextQuestion()
control = 'correct' } else {
client.points += 2 if (res) {
} else if (control === null) { control = 'correct'
control = 'wrong-firstTime' client.points += 2
clear = true } else if (control === null) {
} else control = 'wrong-secondTime' control = 'wrong-firstTime'
setTimeout(() => (clear = false), 400) clear = true
} else control = 'wrong-secondTime'
setTimeout(() => (clear = false), 400)
}
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
answerLoading = false
} }
</script> </script>
@ -106,7 +120,16 @@
{/if} {/if}
{#if view === 'question'} {#if view === 'question'}
<Layout imgSrc={'gameData.question.thumbnail'} on:submit={() => checkAnswer()} on:nextQuestion={nextQuestion} {control}> <Layout
loading={answerLoading}
imgSrc={'gameData.question.thumbnail'}
on:submit={() => checkAnswer()}
on:nextQuestion={() => {
if (checkPointType === 'INFO') checkAnswer()
else nextQuestion()
}}
{control}
>
<span slot="title">{checkPoint.CPName}</span> <span slot="title">{checkPoint.CPName}</span>
<span slot="about">{@html checkPoint.CPText}</span> <span slot="about">{@html checkPoint.CPText}</span>

View File

@ -16,11 +16,11 @@
import { getLocationDataFromLatAndLong } from '$lib/utils/locations' import { getLocationDataFromLatAndLong } from '$lib/utils/locations'
import { navigate } from '$lib/router' import { navigate } from '$lib/router'
import { Experience } from '$lib/TStypes/experiences' import { Experience } from '$lib/TStypes/experiences'
import Progressbar from '$lib/components/erant/Progressbar.svelte'
export let params: { gameurl: string } export let params: { gameurl: string }
let gameData: Experience // let gameData: Experience //
$: [userProgress] = gameData ? getUserProgressAsStore(gameData?.$id) : [] $: [userProgress] = gameData ? getUserProgressAsStore(gameData?.$id) : []
$: console.log($userProgress)
onMount(async () => { onMount(async () => {
try { try {
@ -57,7 +57,7 @@
<div class="bubbles"> <div class="bubbles">
<Bubble background="blue"> <Bubble background="blue">
<span slot="icon"><IconStar /></span> <span slot="icon"><IconStar /></span>
<span> {'gameData.rating'} </span> <span> {gameData.rating} </span>
</Bubble> </Bubble>
<Bubble background="white"> <Bubble background="white">
<span slot="icon"><IconPoint /></span> <span slot="icon"><IconPoint /></span>
@ -83,6 +83,9 @@
</div> </div>
</div> </div>
</Section> </Section>
<Section title="Progress">
<Progressbar max={gameData.ExpCPsID.length} progress={$userProgress.length} showWrittenProgress />
</Section>
<div class="w-full relative"> <div class="w-full relative">
<div class="px-4 m-auto" style="max-width: var(--max-viewport-width);"> <div class="px-4 m-auto" style="max-width: var(--max-viewport-width);">
@ -95,11 +98,11 @@
</div> </div>
{#if gameData.checkPoints.length} {#if gameData.checkPoints.length}
<Button on:click={() => (view = 'experience-play')} primary>Hrát</Button> <Button on:click={() => (view = 'experience-play')} primary>{$userProgress ? 'Pokračovat' : 'Hrát'}</Button>
{/if} {/if}
</Overlay> </Overlay>
{:else if view === 'experience-play'} {:else if view === 'experience-play'}
<Renderer {gameData} {userProgress} /> <Renderer {gameData} />
{/if} {/if}
<style> <style>