Skip to content

Commit 28671d7

Browse files
committed
chore: consents + quizzes
1 parent 20387e8 commit 28671d7

File tree

15 files changed

+256
-40
lines changed

15 files changed

+256
-40
lines changed

frontend/app/api/generated.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,6 +2375,18 @@ export type DeleteProjectMutationVariables = Exact<{
23752375

23762376
export type DeleteProjectMutation = { __typename?: 'Mutation', deleteProject: boolean };
23772377

2378+
export type StartQuizMutationVariables = Exact<{
2379+
quizId: Scalars['ID']['input'];
2380+
}>;
2381+
2382+
2383+
export type StartQuizMutation = { __typename?: 'Mutation', startQuiz: { __typename?: 'QuizSubmission', id: string, startedAt: any, expiresAt?: any | null, isExpired: boolean, questionOrder: Array<string>, orderedQuestions: Array<
2384+
| { __typename?: 'FreeTextQuestion', id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
2385+
| { __typename?: 'JsonQuestion', id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
2386+
| { __typename?: 'NumberQuestion', minValue?: number | null, maxValue?: number | null, stepValue?: number | null, id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
2387+
| { __typename?: 'PredefinedQuestion', allowMultipleSelection: boolean, id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null, predefinedAnswers: Array<{ __typename?: 'QuizPredefinedAnswer', id: string, answerText: string, answerOrder: number, isCorrect?: boolean | null }> }
2388+
>, quiz: { __typename?: 'Quiz', id: string, name: string, timeoutSeconds?: number | null } } };
2389+
23782390
export type AssignRoleMutationVariables = Exact<{
23792391
input: AssignRoleInput;
23802392
}>;
@@ -2473,7 +2485,7 @@ export type ChallengePageQueryVariables = Exact<{
24732485

24742486
export type ChallengePageQuery = { __typename?: 'Query', challenge:
24752487
| { __typename: 'ExternalChallenge', url: string, id: string, name: string, description: any, userEnrolledAt?: any | null, userCompletedAt?: any | null }
2476-
| { __typename: 'QuizChallenge', id: string, name: string, description: any, userEnrolledAt?: any | null, userCompletedAt?: any | null, quiz: { __typename?: 'Quiz', id: string, name: string, description: string, timeoutSeconds?: number | null, randomizeQuestions: boolean, revealCorrectAnswers: boolean, allowRetakes: boolean, completionPoints: number, publishedAt?: any | null, endTime?: any | null, userCanStart: boolean, userSubmissions: Array<{ __typename?: 'QuizSubmission', id: string, startedAt: any, completedAt?: any | null, expiresAt?: any | null, isExpired: boolean, score?: number | null, maxScore?: number | null, scorePercentage?: number | null, orderedQuestions: Array<
2488+
| { __typename: 'QuizChallenge', id: string, name: string, description: any, userEnrolledAt?: any | null, userCompletedAt?: any | null, quiz: { __typename?: 'Quiz', id: string, name: string, description: string, timeoutSeconds?: number | null, randomizeQuestions: boolean, revealCorrectAnswers: boolean, allowRetakes: boolean, completionPoints: number, publishedAt?: any | null, endTime?: any | null, userCanStart: boolean, userActiveSubmission?: { __typename?: 'QuizSubmission', id: string } | null, userSubmissions: Array<{ __typename?: 'QuizSubmission', id: string, startedAt: any, completedAt?: any | null, expiresAt?: any | null, isExpired: boolean, score?: number | null, maxScore?: number | null, scorePercentage?: number | null, orderedQuestions: Array<
24772489
| { __typename: 'FreeTextQuestion', id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
24782490
| { __typename: 'JsonQuestion', id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
24792491
| { __typename: 'NumberQuestion', minValue?: number | null, maxValue?: number | null, stepValue?: number | null, id: string, questionText: string, questionOrder: number, timeoutSeconds?: number | null }
@@ -2510,7 +2522,7 @@ export type ProfilePageQuery = { __typename?: 'Query', me: { __typename?: 'User'
25102522
export type ConsentsPageQueryVariables = Exact<{ [key: string]: never; }>;
25112523

25122524

2513-
export type ConsentsPageQuery = { __typename?: 'Query', me: { __typename?: 'User', consentStatus: { __typename?: 'ConsentStatus', pendingConsents: Array<{ __typename: 'Consent', id: string, key: string, version: number, title: string, publishedAt?: any | null, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } }>, acceptedConsents: Array<{ __typename: 'UserConsent', id: string, action: ConsentAction, actionDate: any, consent: { __typename?: 'Consent', title: string, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } } }>, rejectedConsents: Array<{ __typename: 'UserConsent', id: string, action: ConsentAction, actionDate: any, consent: { __typename?: 'Consent', title: string, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } } }> } } };
2525+
export type ConsentsPageQuery = { __typename?: 'Query', me: { __typename?: 'User', consentStatus: { __typename?: 'ConsentStatus', pendingConsents: Array<{ __typename: 'Consent', id: string, key: string, version: number, title: string, publishedAt?: any | null, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } }>, acceptedConsents: Array<{ __typename: 'UserConsent', id: string, action: ConsentAction, actionDate: any, consent: { __typename?: 'Consent', id: string, title: string, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } } }>, rejectedConsents: Array<{ __typename: 'UserConsent', id: string, action: ConsentAction, actionDate: any, consent: { __typename?: 'Consent', id: string, title: string, managedBy?: string | null, managementType: ConsentManagementType, url?: string | null, body: { __typename?: 'MarkdownText', html: string } } }> } } };
25142526

25152527
export type StandingsGlobalPageQueryVariables = Exact<{
25162528
entityType: LeaderboardEntityType;
@@ -2957,6 +2969,46 @@ export const DeleteProjectDocument = gql`
29572969
export function useDeleteProjectMutation() {
29582970
return Urql.useMutation<DeleteProjectMutation, DeleteProjectMutationVariables>(DeleteProjectDocument);
29592971
};
2972+
export const StartQuizDocument = gql`
2973+
mutation StartQuiz($quizId: ID!) {
2974+
startQuiz(quizId: $quizId) {
2975+
id
2976+
startedAt
2977+
expiresAt
2978+
isExpired
2979+
questionOrder
2980+
orderedQuestions {
2981+
id
2982+
questionText
2983+
questionOrder
2984+
timeoutSeconds
2985+
... on PredefinedQuestion {
2986+
allowMultipleSelection
2987+
predefinedAnswers {
2988+
id
2989+
answerText
2990+
answerOrder
2991+
isCorrect
2992+
}
2993+
}
2994+
... on NumberQuestion {
2995+
minValue
2996+
maxValue
2997+
stepValue
2998+
}
2999+
}
3000+
quiz {
3001+
id
3002+
name
3003+
timeoutSeconds
3004+
}
3005+
}
3006+
}
3007+
`;
3008+
3009+
export function useStartQuizMutation() {
3010+
return Urql.useMutation<StartQuizMutation, StartQuizMutationVariables>(StartQuizDocument);
3011+
};
29603012
export const AssignRoleDocument = gql`
29613013
mutation AssignRole($input: AssignRoleInput!) {
29623014
assignRole(input: $input) {
@@ -3117,6 +3169,9 @@ export const ChallengePageDocument = gql`
31173169
publishedAt
31183170
endTime
31193171
userCanStart
3172+
userActiveSubmission {
3173+
id
3174+
}
31203175
userSubmissions {
31213176
id
31223177
startedAt
@@ -3269,6 +3324,7 @@ export const ConsentsPageDocument = gql`
32693324
__typename
32703325
id
32713326
consent {
3327+
id
32723328
title
32733329
body {
32743330
html
@@ -3284,6 +3340,7 @@ export const ConsentsPageDocument = gql`
32843340
__typename
32853341
id
32863342
consent {
3343+
id
32873344
title
32883345
body {
32893346
html

frontend/app/components/LocaleSelector.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ const selectedLocale = computed({
1414
<template>
1515
<DesignDrawer :title="$t('settings.language')">
1616
<slot :selected-locale="locales.find((l) => l.code === selectedLocale)" />
17-
<template #content="{ close }"></template>
17+
<template #content>
18+
<DesignButton
19+
v-for="l in locales"
20+
:key="l.code"
21+
variant="secondary"
22+
size="medium"
23+
class="w-full"
24+
@click="selectedLocale = l.code"
25+
>
26+
<span class="grow text-start">{{ l.name }}</span>
27+
<Icon v-if="selectedLocale === l.code" name="lucide:check" />
28+
</DesignButton>
29+
</template>
1830
</DesignDrawer>
1931
</template>

frontend/app/components/PageLayout.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ withDefaults(
2323
</template>
2424
</TitleBar>
2525
</div>
26-
<div
27-
:class="['p-list-outside flex grow flex-col', { 'pb-28': bottomPadding }]"
28-
>
26+
<div :class="['flex grow flex-col', { 'pb-28': bottomPadding }]">
2927
<slot />
3028
</div>
3129
</div>

frontend/app/components/challenges/QuizChallenge.vue

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,36 @@ type QuizChallengeData = Extract<
66
{ __typename: 'QuizChallenge' }
77
>
88
9-
defineProps<{
9+
const props = defineProps<{
1010
challenge: QuizChallengeData
1111
}>()
12+
13+
const emit = defineEmits<{
14+
start: []
15+
}>()
16+
17+
const { executeMutation: startQuiz } = useStartQuizMutation()
18+
19+
onMounted(() => {
20+
if (!props.challenge.quiz.userActiveSubmission?.id) {
21+
startQuiz({
22+
quizId: props.challenge.quiz.id,
23+
}).then(() => {
24+
emit('start')
25+
})
26+
}
27+
})
28+
29+
const activeSubmission = computed(() => {
30+
return props.challenge.quiz.userSubmissions.find(
31+
(submission) =>
32+
submission.id === props.challenge.quiz.userActiveSubmission?.id,
33+
)
34+
})
35+
36+
const questions = computed(() => {
37+
return activeSubmission.value?.orderedQuestions
38+
})
1239
</script>
1340

1441
<template>
@@ -19,22 +46,11 @@ defineProps<{
1946
</NuxtLink>
2047
</template>
2148
<template #title>
22-
<QuizProgress />
49+
<QuizProgress :submission="activeSubmission" />
2350
</template>
2451

25-
<div class="gap-medium flex flex-col">
26-
<QuizAlternative text="This is an alternative" />
27-
<QuizAlternative text="This is a highlighted alternative" highlighted />
28-
<QuizAlternative
29-
text="This is a confirmed and wrong alternative"
30-
confirmed
31-
wrong
32-
/>
33-
<QuizAlternative
34-
text="This is a confirmed and correct alternative"
35-
confirmed
36-
correct
37-
/>
52+
<div v-for="question in questions" :key="question.id">
53+
{{ question.questionText }}
3854
</div>
3955
</PageLayout>
4056
</template>
Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
1-
<script setup lang="ts"></script>
1+
<script setup lang="ts">
2+
import { cva } from 'cva'
3+
4+
type QuizChallengeData = Extract<
5+
ChallengePageQuery['challenge'],
6+
{ __typename: 'QuizChallenge' }
7+
>
8+
9+
type QuizSubmissionData = QuizChallengeData['quiz']['userSubmissions'][number]
10+
11+
defineProps<{
12+
submission?: QuizSubmissionData
13+
}>()
14+
15+
const dotClass = cva('', {
16+
variants: {
17+
active: {
18+
true: 'bg-accent-contrast',
19+
false: 'bg-border-default',
20+
},
21+
},
22+
})
23+
</script>
224

325
<template>
426
<div
5-
class="bg-background-raised gradient-border px-5 py-2 rounded-button-medium"
6-
></div>
27+
v-if="submission"
28+
class="bg-background-raised gradient-border px-5 py-2 rounded-button-medium flex items-center gap-medium"
29+
>
30+
<div
31+
v-for="question in submission.orderedQuestions"
32+
:key="question.id"
33+
:class="dotClass({ active: true })"
34+
class="w-2 h-2 rounded-full"
35+
/>
36+
</div>
737
</template>

frontend/app/components/consent/ConsentCard.vue

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ const { executeMutation: acceptConsent } = useAcceptConsentMutation()
1717
const { executeMutation: rejectConsent } = useRejectConsentMutation()
1818
1919
function handleAccept() {
20-
const consentId = props.consent.id
20+
const consentId =
21+
props.consent.__typename === 'UserConsent'
22+
? props.consent.consent.id
23+
: props.consent.id
2124
acceptConsent({ consentId }).then(({ error }) => {
2225
if (error) {
2326
console.error(error)
@@ -29,7 +32,10 @@ function handleAccept() {
2932
}
3033
3134
function handleReject() {
32-
const consentId = props.consent.id
35+
const consentId =
36+
props.consent.__typename === 'UserConsent'
37+
? props.consent.consent.id
38+
: props.consent.id
3339
rejectConsent({ consentId }).then(({ error }) => {
3440
if (error) {
3541
console.error(error)
@@ -150,14 +156,20 @@ const changing = ref(false)
150156
<Icon name="lucide:check" class="size-6" />
151157
{{ $t('consent.accepted') }}
152158
</span>
153-
<DesignButton
154-
size="small"
155-
variant="secondary"
156-
class="grow-0"
157-
@click="changing = true"
158-
>
159-
{{ $t('consent.change') }}
160-
</DesignButton>
159+
<DesignDrawer :title="$t('consent.change')">
160+
<DesignButton size="small" variant="secondary" class="grow-0">
161+
{{ $t('consent.change') }}
162+
</DesignButton>
163+
<template #content>
164+
<p class="text-label text-text-default px-default">
165+
{{
166+
$t('consent.changeDescription', {
167+
email: 'support@bcc.media',
168+
})
169+
}}
170+
</p>
171+
</template>
172+
</DesignDrawer>
161173
</div>
162174
</template>
163175
<template v-else-if="status === ConsentAction.Rejected">

frontend/app/components/design/DesignButton.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const classes = cva(
1818
variants: {
1919
variant: {
2020
primary: 'bg-accent text-on-accent gradient-border',
21-
secondary: 'bg-border-default text-text-default gradient-border',
21+
secondary:
22+
'bg-border-default text-text-default gradient-border backdrop-blur-2xl',
2223
tertiary: 'text-default',
2324
},
2425
size: {

frontend/app/components/design/DesignDrawer.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const close = () => {
3838
<DesignIconButton v-if="dismissible" icon="lucide:x" @click="close" />
3939
</template>
4040
</TitleBar>
41-
<div class="p-list-outside grow flex flex-col gap-list-section-gap">
41+
<div
42+
class="p-list-outside grow flex flex-col gap-list-section-gap overflow-auto"
43+
>
4244
<slot name="content" />
4345
</div>
4446
</template>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
mutation StartQuiz($quizId: ID!) {
2+
startQuiz(quizId: $quizId) {
3+
id
4+
startedAt
5+
expiresAt
6+
isExpired
7+
questionOrder
8+
orderedQuestions {
9+
id
10+
questionText
11+
questionOrder
12+
timeoutSeconds
13+
... on PredefinedQuestion {
14+
allowMultipleSelection
15+
predefinedAnswers {
16+
id
17+
answerText
18+
answerOrder
19+
isCorrect
20+
}
21+
}
22+
... on NumberQuestion {
23+
minValue
24+
maxValue
25+
stepValue
26+
}
27+
}
28+
quiz {
29+
id
30+
name
31+
timeoutSeconds
32+
}
33+
}
34+
}

frontend/app/graphql/queries/pages/challenge.gql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ query ChallengePage($challengeId: ID!) {
2525
publishedAt
2626
endTime
2727
userCanStart
28+
userActiveSubmission {
29+
id
30+
}
2831
userSubmissions {
2932
id
3033
startedAt

0 commit comments

Comments
 (0)