Skip to content

Commit

Permalink
Merge pull request #130 from ssciwr/fix-userquestions-in-admin
Browse files Browse the repository at this point in the history
Integrate admin interface into user landing page
  • Loading branch information
MaHaWo authored Oct 29, 2024
2 parents 83b2e59 + 7679af8 commit 1ed8ef3
Show file tree
Hide file tree
Showing 29 changed files with 423 additions and 461 deletions.
10 changes: 5 additions & 5 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 39 additions & 10 deletions frontend/src/lib/client/schemas.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,13 +615,20 @@ export const UserAnswerPublicSchema = {
type: 'integer',
title: 'Question Id'
},
non_standard: {
type: 'boolean',
title: 'Non Standard'
additional_answer: {
anyOf: [
{
type: 'string'
},
{
type: 'null'
}
],
title: 'Additional Answer'
}
},
type: 'object',
required: ['answer', 'question_id', 'non_standard'],
required: ['answer', 'question_id', 'additional_answer'],
title: 'UserAnswerPublic',
description: `External data model for UserAnswers
Expand Down Expand Up @@ -705,9 +712,15 @@ export const UserQuestionAdminSchema = {
type: 'integer',
title: 'Order'
},
input: {
component: {
type: 'string',
title: 'Component',
default: 'select'
},
type: {
type: 'string',
title: 'Input'
title: 'Type',
default: 'text'
},
options: {
type: 'string',
Expand All @@ -720,10 +733,15 @@ export const UserQuestionAdminSchema = {
type: 'object',
title: 'Text',
default: {}
},
additional_option: {
type: 'string',
title: 'Additional Option',
default: ''
}
},
type: 'object',
required: ['id', 'order', 'input', 'options'],
required: ['id', 'order', 'options'],
title: 'UserQuestionAdmin'
} as const;

Expand All @@ -733,9 +751,15 @@ export const UserQuestionPublicSchema = {
type: 'integer',
title: 'Id'
},
input: {
component: {
type: 'string',
title: 'Input'
title: 'Component',
default: 'select'
},
type: {
type: 'string',
title: 'Type',
default: 'text'
},
text: {
additionalProperties: {
Expand All @@ -744,10 +768,15 @@ export const UserQuestionPublicSchema = {
type: 'object',
title: 'Text',
default: {}
},
additional_option: {
type: 'string',
title: 'Additional Option',
default: ''
}
},
type: 'object',
required: ['id', 'input'],
required: ['id'],
title: 'UserQuestionPublic'
} as const;

Expand Down
10 changes: 7 additions & 3 deletions frontend/src/lib/client/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export type MilestoneTextPublic = {
export type UserAnswerPublic = {
answer: string;
question_id: number;
non_standard: boolean;
additional_answer: string | null;
};

export type UserCreate = {
Expand All @@ -183,19 +183,23 @@ export type UserCreate = {
export type UserQuestionAdmin = {
id: number;
order: number;
input: string;
component?: string;
type?: string;
options: string;
text?: {
[key: string]: UserQuestionText;
};
additional_option?: string;
};

export type UserQuestionPublic = {
id: number;
input: string;
component?: string;
type?: string;
text?: {
[key: string]: UserQuestionTextPublic;
};
additional_option?: string;
};

export type UserQuestionText = {
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/lib/components/Admin/EditMilestoneGroupModal.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<svelte:options runes={true} />

<script lang="ts">
import { InputAddon, Textarea, Label, ButtonGroup, Fileupload, Modal } from 'flowbite-svelte';
import { _, locales } from 'svelte-i18n';
import { onMount } from 'svelte';
import type { MilestoneGroupAdmin } from '$lib/client/types.gen';
import { updateMilestoneGroupAdmin, uploadMilestoneGroupImage } from '$lib/client/services.gen';
import { milestoneGroupImageUrl, refreshMilestoneGroups } from '$lib/admin.svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import { updateMilestoneGroupAdmin, uploadMilestoneGroupImage } from '$lib/client/services.gen';
import type { MilestoneGroupAdmin } from '$lib/client/types.gen';
import CancelButton from '$lib/components/Admin/CancelButton.svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import { ButtonGroup, Fileupload, InputAddon, Label, Modal, Textarea } from 'flowbite-svelte';
import { onMount } from 'svelte';
import { _, locales } from 'svelte-i18n';
let {
open = $bindable(false),
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/lib/components/Admin/EditMilestoneModal.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<svelte:options runes={true} />

<script lang="ts">
import { InputAddon, Textarea, Label, ButtonGroup, Fileupload, Modal } from 'flowbite-svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import CancelButton from '$lib/components/Admin/CancelButton.svelte';
import { _, locales } from 'svelte-i18n';
import type { MilestoneAdmin } from '$lib/client/types.gen';
import { refreshMilestoneGroups } from '$lib/admin.svelte';
import { updateMilestone, uploadMilestoneImage } from '$lib/client/services.gen';
import type { MilestoneAdmin } from '$lib/client/types.gen';
import CancelButton from '$lib/components/Admin/CancelButton.svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import { ButtonGroup, Fileupload, InputAddon, Label, Modal, Textarea } from 'flowbite-svelte';
import { _, locales } from 'svelte-i18n';
let { open = $bindable(false), milestone }: { open: boolean; milestone: MilestoneAdmin | null } =
$props();
Expand Down
66 changes: 39 additions & 27 deletions frontend/src/lib/components/Admin/EditUserQuestionModal.svelte
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
<svelte:options runes={true} />

<script lang="ts">
import { refreshUserQuestions } from '$lib/admin.svelte';
import { updateUserQuestion } from '$lib/client/services.gen';
import type { UserQuestionAdmin } from '$lib/client/types.gen';
import CancelButton from '$lib/components/Admin/CancelButton.svelte';
import InputPreview from '$lib/components/Admin/InputPreview.svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import {
Button,
Badge,
Button,
ButtonGroup,
Card,
InputAddon,
Textarea,
Input,
InputAddon,
Label,
ButtonGroup,
Modal,
Select,
Textarea,
type SelectOptionType
} from 'flowbite-svelte';
import { _, locales } from 'svelte-i18n';
import { updateUserQuestion } from '$lib/client/services.gen';
import InputPreview from '$lib/components/Admin/InputPreview.svelte';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import CancelButton from '$lib/components/Admin/CancelButton.svelte';
import type { UserQuestionAdmin } from '$lib/client/types.gen';
import { refreshUserQuestions } from '$lib/admin.svelte';
let {
open = $bindable(false),
userQuestion
}: { open: boolean; userQuestion: UserQuestionAdmin | undefined } = $props();
let preview_lang_id = $state('1');
let preview_lang = $state('de');
let preview_answer = $state('');
// FIXME: use the componentTable here
const inputTypes: Array<SelectOptionType<string>> = [
{ value: 'text', name: 'text' },
{ value: 'select', name: 'select' }
Expand All @@ -40,7 +41,7 @@
return;
}
const values = userQuestion.options.split(';');
for (const lang_id in $locales) {
for (const lang_id of $locales) {
const items = userQuestion.text[lang_id].options.split(';');
userQuestion.text[lang_id].options_json = JSON.stringify(
values.map(function (value, index) {
Expand Down Expand Up @@ -73,47 +74,62 @@
{#each Object.values(userQuestion.text) as text}
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>{$locales[text.lang_id]}</InputAddon>
<InputAddon>{text.lang_id}</InputAddon>
<Input
bind:value={text.question}
on:input={() => {
userQuestion = userQuestion;
}}
placeholder={$_('admin.question')}
placeholder={$_('admin.placeholder')}
/>
</ButtonGroup>
</div>
{/each}
</div>
<div class="mb-5">
<Label class="mb-2">Input type</Label>
<Select class="mt-2" items={inputTypes} bind:value={userQuestion.input} placeholder="" />
<Select
class="mt-2"
items={inputTypes}
bind:value={userQuestion.component}
placeholder=""
/>
</div>
{#if userQuestion.input === 'select'}
{#if userQuestion.component === 'select'}
<div class="mb-5">
<Label class="mb-2">Options</Label>
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>name</InputAddon>
<InputAddon>Option values</InputAddon>
<Textarea
bind:value={userQuestion.options}
on:input={updateOptionsJson}
placeholder="Option names"
placeholder="Option values"
/>
</ButtonGroup>
</div>
{#each Object.values(userQuestion.text) as text}
{console.log('text: ', text)}
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>{$locales[text.lang_id]}</InputAddon>
<InputAddon>{text.lang_id}</InputAddon>
<Textarea
bind:value={text.options}
on:input={updateOptionsJson}
placeholder="Options"
placeholder="Displayed options"
/>
</ButtonGroup>
</div>
{/each}
<Label class="mb-2">Additional Option</Label>
<div class="mb-1">
<ButtonGroup class="w-full">
<Textarea
bind:value={userQuestion.additional_option}
placeholder="Displayed additional option"
/>
</ButtonGroup>
</div>
</div>
{/if}
</div>
Expand All @@ -125,21 +141,17 @@
<ButtonGroup class="mb-2 mr-2">
{#each $locales as lang_id}
<Button
checked={preview_lang_id === lang_id}
checked={preview_lang === lang_id}
on:click={(e) => {
e.stopPropagation();
preview_lang_id = lang_id;
preview_lang = lang_id;
}}>{lang_id}</Button
>
{/each}
</ButtonGroup>
</div>
<Card class="mb-4 bg-blue-300">
<InputPreview
data={userQuestion}
lang_id={preview_lang_id}
bind:answer={preview_answer}
/>
<InputPreview data={userQuestion} lang={preview_lang} bind:answer={preview_answer} />
</Card>
<Label class="mb-2">Generated answer:</Label>
<Badge large border color="dark">{preview_answer}</Badge>
Expand Down
12 changes: 5 additions & 7 deletions frontend/src/lib/components/Admin/InputPreview.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
<svelte:options runes={true} />

<script lang="ts">
import { Input, Select, Label, type SelectOptionType } from 'flowbite-svelte';
import type { UserQuestionAdmin } from '$lib/client/types.gen';
let { data, lang_id, answer }: { data: UserQuestionAdmin; lang_id: string; answer: string } =
$props();
import { Input, Label, Select, type SelectOptionType } from 'flowbite-svelte';
let { data, lang, answer }: { data: UserQuestionAdmin; lang: string; answer: string } = $props();
let items: Array<SelectOptionType<string>> = $derived(parse_options_json());
function parse_options_json() {
try {
const options_json = data.text[lang_id].options_json;
const options_json = data.text[lang].options_json;
return JSON.parse(options_json);
} catch (e) {
console.log("Couldn't parse options_json");
Expand All @@ -20,11 +19,10 @@
</script>

<div class="mb-5">
<Label class="font-semibold text-gray-700 dark:text-gray-400">{data.text[lang_id].question}</Label
>
<Label class="font-semibold text-gray-700 dark:text-gray-400">{data.text[lang].question}</Label>
</div>
<div class="mb-5">
{#if data.input === 'select'}
{#if data.component === 'select'}
<Select {items} bind:value={answer} placeholder="" />
{:else}
<Input type="text" bind:value={answer} />
Expand Down
Loading

0 comments on commit 1ed8ef3

Please sign in to comment.