Files
classroomio/src/components/Course/components/Lesson/Exercise/EditMode.svelte
T

352 lines
11 KiB
Svelte
Raw Normal View History

<script>
2021-06-26 22:38:48 +03:00
import {
questionnaire,
deleteConfirmation,
2021-08-18 19:47:02 +03:00
questionnaireValidation,
2021-06-26 22:38:48 +03:00
handleAddOption,
handleRemoveOption,
handleRemoveQuestion,
2021-07-03 19:29:41 +00:00
handleCode,
handleAnswerSelect,
2021-08-18 19:47:02 +03:00
addDynamicValue,
} from '../store/exercise';
import Delete24 from 'carbon-icons-svelte/lib/Delete24';
import AddFilled24 from 'carbon-icons-svelte/lib/AddFilled24';
import CheckmarkFilled24 from 'carbon-icons-svelte/lib/CheckmarkFilled24';
import CheckmarkOutline24 from 'carbon-icons-svelte/lib/CheckmarkOutline24';
// import Subtract24 from "carbon-icons-svelte/lib/Subtract24";
2021-08-18 19:47:02 +03:00
import TextField from '../../../../Form/TextField.svelte';
import Modal from '../../../../Modal/index.svelte';
2021-08-18 19:47:02 +03:00
import TextArea from '../../../../Form/TextArea.svelte';
import Checkbox from '../../../../Form/Checkbox.svelte';
2021-09-23 16:39:38 +03:00
import DateTime from '../../../../Form/DateTime.svelte';
2021-08-18 19:47:02 +03:00
import RadioItem from '../../../../Form/RadioItem.svelte';
import IconButton from '../../../../IconButton/index.svelte';
import ErrorMessage from '../../../../ErrorMessage/index.svelte';
import PrimaryButton from '../../../../PrimaryButton/index.svelte';
2021-09-23 16:39:38 +03:00
import EditContent from '../../../../EditContent/index.svelte';
2021-08-18 19:47:02 +03:00
import { VARIANTS } from '../../../../PrimaryButton/constants';
import Select from '../../../../Form/Select.svelte';
import QuestionContainer from '../../../../QuestionContainer/index.svelte';
import DeleteConfirmationModal from './DeleteConfirmation.svelte';
import OrderModal from './OrderModal.svelte';
import {
QUESTION_TYPE,
QUESTION_TYPES,
2021-08-18 19:47:02 +03:00
} from '../../../../Question/constants';
import { filterOutDeleted } from './functions';
2021-10-18 21:33:31 +03:00
import { deleteExercise } from '../../../../../utils/services/courses';
import { lesson } from '../store/lessons';
// import EditContent from "../../../../EditContent/index.svelte";
// import readme from "../../readme.js";
// let value = readme;
2021-08-18 19:47:02 +03:00
const extraActions = ['Code Snippets', 'Upload image'];
2021-07-03 19:29:41 +00:00
const initialQuestionsLength = $questionnaire.questions.length;
export let editDescription = false;
2021-10-18 21:33:31 +03:00
export let exerciseId;
export let goBack = () => {};
2021-08-18 19:47:02 +03:00
let errors = {};
let questionIdToDelete = null;
let questions = [];
2021-10-18 21:33:31 +03:00
let shouldDelete = false;
let isDeleting = false;
function shouldScrollToLast(questionId, questions) {
2021-07-03 19:29:41 +00:00
const currentQuestionsLength = questions.length;
const index = questions.findIndex((question) => question.id === questionId);
2021-07-03 19:29:41 +00:00
const isLast = index + 1 === currentQuestionsLength;
return isLast && initialQuestionsLength !== currentQuestionsLength;
}
function onInitDeleteClicked(questionId) {
return () => {
questionIdToDelete = questionId;
$deleteConfirmation.open = true;
};
}
function onFinalDeleteClicked() {
handleRemoveQuestion(questionIdToDelete)();
}
2021-07-03 19:29:41 +00:00
function handleOptionClick(questionIndex) {
return (actionIndex) => {
switch (actionIndex) {
case 0:
handleCode(questionIndex, true);
break;
case 1:
// uploadImage(questionIndex);
break;
default:
2021-08-18 19:47:02 +03:00
console.log('No option');
2021-07-03 19:29:41 +00:00
}
};
}
2021-08-18 19:47:02 +03:00
function getQuestionErrorMsg(errors, question, errorKey) {
return errors[question.id] ? errors[question.id][errorKey] : null;
}
2021-10-18 21:33:31 +03:00
async function handleDelete() {
console.log('delete');
isDeleting = true;
await deleteExercise(questions, exerciseId);
lesson.update((_lesson) => ({
..._lesson,
exercises: _lesson.exercises.filter(
(exercise) => exercise.id !== exerciseId
),
}));
shouldDelete = false;
goBack();
}
2021-08-18 19:47:02 +03:00
$: errors = $questionnaireValidation;
$: questions = filterOutDeleted($questionnaire.questions);
</script>
<DeleteConfirmationModal
onCancel={() => (questionIdToDelete = null)}
onDelete={onFinalDeleteClicked}
/>
<OrderModal />
<Modal
onClose={() => (editDescription = false)}
bind:open={editDescription}
width="w-2/4"
modalHeading="Update description"
>
2021-10-18 21:33:31 +03:00
{#if shouldDelete}
<form on:submit|preventDefault={() => (shouldDelete = false)}>
<h1 class="text-2xl">Are you sure?</h1>
<div class="mt-5 flex items-center justify-between">
<PrimaryButton
className="px-6 py-2"
variant={VARIANTS.OUTLINED}
label="No, cancel"
type="submit"
/>
<PrimaryButton
className="px-6 py-2"
variant={VARIANTS.CONTAINED_DANGER}
label={isDeleting ? 'Deleting...' : 'Yes, delete'}
isDisabled={isDeleting}
onClick={handleDelete}
/>
</div>
</form>
{:else}
<div>
<QuestionContainer isTitle={true}>
<TextField
placeholder="Title"
bind:value={$questionnaire.title}
className="mb-2"
onChange={() => ($questionnaire.is_title_dirty = true)}
/>
<DateTime
label="Due by"
className="w-50"
value={$questionnaire.due_by}
onInput={(e) => {
$questionnaire.due_by = e.target.value;
$questionnaire.is_due_by_dirty = true;
}}
/>
<EditContent
writeLabel="Description"
bind:value={$questionnaire.description}
placeholder="Start typing your lesson"
textAreaHeight="100px"
onInputChange={() => ($questionnaire.is_description_dirty = true)}
/>
</QuestionContainer>
<div class="float-right">
<PrimaryButton
className="px-6 py-2"
variant={VARIANTS.CONTAINED_DANGER}
label="Delete this exercise"
onClick={() => (shouldDelete = true)}
/>
</div>
</div>
{/if}
</Modal>
2021-06-26 21:32:42 +03:00
<div class="w-full">
2021-08-18 19:47:02 +03:00
{#if Object.values(errors).length}
<div class="w-full flex justify-center mb-4">
<ErrorMessage message="You have some errors" />
</div>
{/if}
<div class="questions pt-6 px-6">
{#each questions as question (question.id)}
<!-- {#key question.id} -->
<QuestionContainer
onClose={onInitDeleteClicked(question.id)}
scrollToQuestion={shouldScrollToLast(
question.id,
$questionnaire.questions
)}
bind:points={question.points}
hasError={!!errors[question.id]}
onPointsChange={() => {
question.is_dirty = true;
}}
>
<div class="flex justify-between items-center">
<div class="mr-2 w-3/5">
<TextField
placeholder="Question"
bind:value={question.title}
isRequired={true}
onChange={() => {
question.is_dirty = true;
}}
/>
</div>
2021-08-18 19:47:02 +03:00
<!-- <Dropdown
2021-07-03 19:29:41 +00:00
options={extraActions}
handleOptionClick={handleOptionClick(question.id)}
>
<AddFilled24 class="carbon-icon" />
<p class="ml-2 text-gray-600">Add</p>
2021-08-18 19:47:02 +03:00
</Dropdown> -->
2021-07-03 19:29:41 +00:00
<Select
bind:value={question.question_type}
options={QUESTION_TYPES}
onChange={() => {
question.is_dirty = true;
}}
2021-07-03 19:29:41 +00:00
/>
</div>
{#if typeof question.code === 'string'}
<div class="flex justify-between items-center my-3 w-3/5">
<TextArea
bind:value={question.code}
rows="2"
placeholder="Write your code"
/>
<IconButton
value="write-code"
onClick={() => handleCode(question.id, false)}
2021-06-26 21:32:42 +03:00
>
<Delete24 class="carbon-icon" />
</IconButton>
</div>
{/if}
2021-06-26 21:32:42 +03:00
<div class="flex flex-col mt-2">
{#if QUESTION_TYPE.RADIO === question.question_type.id}
{#each filterOutDeleted(question.options) as option}
<RadioItem
isEditable={true}
name={question.title || 'radio-name'}
bind:label={option.label}
onChange={addDynamicValue(question.id, option.id)}
>
<div slot="iconbutton" class="flex items-center">
<IconButton
value={option.id}
onClick={handleRemoveOption(question.id, option.id)}
>
<Delete24 class="carbon-icon" />
</IconButton>
<IconButton
value={option.id}
onClick={handleAnswerSelect(question.id, option.id)}
buttonClassName={option.is_correct && 'success'}
>
{#if option.is_correct}
<CheckmarkFilled24 class="carbon-icon" />
{:else}
<CheckmarkOutline24 class="carbon-icon" />
{/if}
</IconButton>
</div>
</RadioItem>
{/each}
{/if}
2021-06-26 21:32:42 +03:00
{#if QUESTION_TYPE.CHECKBOX === question.question_type.id}
{#each filterOutDeleted(question.options) as option}
<Checkbox
isEditable={true}
name={question || 'checkbox-name'}
bind:label={option.label}
onChange={addDynamicValue(question.id, option.id)}
>
<div slot="iconbutton" class="flex items-center">
<IconButton
value={option.id}
onClick={handleRemoveOption(question.id, option.id)}
>
<Delete24 class="carbon-icon" />
</IconButton>
<IconButton
value={option.id}
onClick={handleAnswerSelect(question.id, option.id)}
buttonClassName={option.is_correct && 'success'}
>
{#if option.is_correct}
<CheckmarkFilled24 class="carbon-icon" />
{:else}
<CheckmarkOutline24 class="carbon-icon" />
{/if}
</IconButton>
</div>
</Checkbox>
{/each}
{/if}
2021-08-18 19:47:02 +03:00
{#if QUESTION_TYPE.TEXTAREA === question.question_type.id}
<TextArea bind:value={question.value} />
{/if}
2021-06-26 21:32:42 +03:00
{#if getQuestionErrorMsg(errors, question, 'option')}
<ErrorMessage
message={getQuestionErrorMsg(errors, question, 'option')}
/>
{/if}
2021-06-26 21:32:42 +03:00
</div>
{#if QUESTION_TYPE.TEXTAREA !== question.question_type.id}
<div class="flex items-center mt-3">
<PrimaryButton
disablePadding={true}
className="p-2"
variant={VARIANTS.OUTLINED}
onClick={handleAddOption(question.id)}
>
<AddFilled24 class="carbon-icon" />
<p class="ml-2">Add option</p>
</PrimaryButton>
</div>
{/if}
</QuestionContainer>
<!-- {/key} -->
{/each}
</div>
</div>
<style>
:global(#dnd-action-dragged-el div) {
z-index: 100;
}
</style>