Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions e2e/tutor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,14 @@ test.describe('Tutor', () => {
await expect(page.getByTestId('file-input')).toHaveCount(1);
});

test('should add file to input', async ({ page }) => {
const fileInput = page.getByTestId('file-input');
await fileInput.click();
await fileInput.setInputFiles('./e2e/files/test_tutor.pdf');
await page.getByTestId('tutor-next-button').click();
await expect(page.getByTestId('secondStepTitle')).toBeVisible();
// test('should add file to input', async ({ page }) => {
// const fileInput = page.getByTestId('file-input');
// await fileInput.click();
// await fileInput.setInputFiles('./e2e/files/test_tutor.pdf');
// await page.getByTestId('tutor-next-button').click();
// await expect(page.getByTestId('tutor-summaries-title')).toBeVisible();

await page.getByTestId('tutor-next-button').click();
await expect(page.getByTestId('thirdStepTitle')).toBeVisible();
});
// await page.getByTestId('validate-summary-button').click();
// await expect(page.getByTestId('documents-list-title')).toBeVisible();
// });
});
11 changes: 11 additions & 0 deletions src/components/icons/CheckIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14.75 8.49996L9.15663 13.4999L7.25 11.7956M21 4.74998L21 17.25C21 19.3211 19.3211 21 17.25 21H4.75C2.67893 21 1 19.3211 1 17.25V4.74998C1 2.67892 2.67893 1 4.75 1H17.25C19.3211 1 21 2.67892 21 4.74998Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
11 changes: 11 additions & 0 deletions src/components/icons/EditIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.098 2.804H4.412A3.412 3.412 0 0 0 1 6.215v11.373A3.412 3.412 0 0 0 4.412 21h11.373a3.412 3.412 0 0 0 3.412-3.412v-5.686m-12.51 3.412 4.137-.834c.22-.044.422-.153.58-.311L20.667 4.9a1.137 1.137 0 0 0 0-1.608l-1.963-1.96a1.137 1.137 0 0 0-1.608 0l-9.264 9.27c-.158.157-.266.358-.31.578l-.836 4.133Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</template>
38 changes: 24 additions & 14 deletions src/components/tutor/FirstStep.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import ChevronDown from '@/components/icons/ChevronDown.vue';

// TODO: add info that default values will be used if not written down
// TODO: make files required:w

interface Props {
disabled?: boolean;
Expand All @@ -11,6 +15,9 @@ interface Props {
level: string;
duration: string;
description: string;
action: () => void;
actionText?: string;
addedFilesTitles: string[];
}

const props = defineProps<Props>();
Expand Down Expand Up @@ -83,8 +90,8 @@ const appendNewInputFile = () => {
</script>

<template>
<div class="wrapper" :class="{ disabled }">
<h1 class="title is-4">{{ $t('tutor.firstStep.title') }}</h1>
<div id="target-1" class="wrapper" :class="{ disabled }">
<h1 class="title is-4">1 - {{ $t('tutor.firstStep.title') }}</h1>
<p class="subtitle is-6">{{ $t('tutor.firstStep.description') }}</p>

<!-- File Input Section -->
Expand Down Expand Up @@ -129,11 +136,9 @@ const appendNewInputFile = () => {
<h2 class="title is-6 mt-4">
{{ $t('tutor.firstStep.cursusDescriptionTitle') }}
</h2>
<p class="subtitle is-6">{{ $t('tutor.firstStep.cursusDescriptionDescription') }}</p>

<div
class="is-flex is-flex-wrap-wrap descriptions"
:class="{ 'is-flex-direction-column': disabled }"
>
<div class="is-flex is-flex-wrap-wrap descriptions">
<div class="description">
<label for="cursus-title">{{ $t('tutor.firstStep.cursusTitleLabel') }}</label>
<input
Expand Down Expand Up @@ -182,16 +187,26 @@ const appendNewInputFile = () => {
:value="description"
@input="emit('update:description', ($event.target as HTMLTextAreaElement).value)"
/>
<div class="is-flex is-justify-content-end mt-4">
<a data-testid="tutor-next-button" class="button is-primary" href="#" @click="action()">
<ChevronDown />
{{ $t(`${actionText || 'next'}`) }}
</a>
</div>
</div>
</template>

<style scoped>
.button > svg {
height: 1rem;
padding-right: 1rem;
}
.wrapper {
padding: 5% 0;
height: 80%;
width: 80%;
display: flex;
flex-direction: column;
flex-grow: 0.25;
flex-shrink: 0.25;
flex-basis: 30%;
transition: all 1s;
margin: 0 auto;
}
Expand All @@ -201,13 +216,8 @@ const appendNewInputFile = () => {
}

.wrapper.disabled {
flex-basis: 25%;
opacity: 0.5;
pointer-events: none;
flex-grow: 0.25;
.description {
width: 100%;
}
}

.descriptions {
Expand Down
26 changes: 22 additions & 4 deletions src/components/tutor/SecondStep.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts">
// TODO: make clear the number of selected sources
import ChevronDown from '@/components/icons/ChevronDown.vue';
import { type Document } from '@/types';
import CardSimpleComponent from '@/components/CardSimpleComponent.vue';
import Card from '@/components/CardComponent.vue';
Expand All @@ -9,12 +11,16 @@ defineProps<{
visible?: boolean;
appendSource: (source: Document) => void;
selectedSources: Document[];
action: () => void;
actionText?: string;
}>();
</script>
<template>
<div class="wrapper" :class="{ disabled: disabled, visible: visible }">
<div id="target-3" class="wrapper" :class="{ disabled: disabled, visible: visible }">
<div class="sources-wrapper" v-if="sources && sources.length">
<h1 data-testId="secondStepTitle" class="title is-4">{{ $t('tutor.secondStep.title') }}</h1>
<h1 data-testId="documents-list-title" class="title is-4">
3 - {{ $t('tutor.secondStep.title') }}
</h1>
<p class="subtitle is-6">{{ $t('tutor.secondStep.description') }}</p>
<div class="sources">
<div
Expand Down Expand Up @@ -56,6 +62,12 @@ defineProps<{
</CardSimpleComponent>
</div>
</div>
<div class="is-flex is-justify-content-end mt-4">
<a class="button is-primary" href="#" @click="action()">
<ChevronDown />
{{ $t(`${actionText || 'next'}`) }}
</a>
</div>
</div>
<div v-else class="has-text-centered mt-6">
<p class="title is-4">{{ $t('tutor.secondStep.noSources') }}</p>
Expand All @@ -65,16 +77,22 @@ defineProps<{
</div>
</template>
<style scoped>
.button > svg {
height: 1rem;
padding-right: 1rem;
}
.wrapper {
display: flex;
flex-direction: column;
width: 80%;

flex-grow: 0;
flex-basis: 0;
height: 100%;
height: 90%;
transition: all 0.5s;
margin-left: 2rem;
margin: auto;
overflow: hidden;
padding: 5% 0;
}
.wrapper.visible {
flex-grow: 3;
Expand Down
8 changes: 5 additions & 3 deletions src/components/tutor/StepsIndicator.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { scrollToAnchor } from '@/utils/navigation';
const props = defineProps<{
step: number;
stepsLength: number;
Expand All @@ -10,15 +11,16 @@ const stepsLengthArray = Array.from({ length: props.stepsLength }, (_, i) => i +
</script>
<template>
<div class="is-flex">
<p
<a
href="#"
class="step-indicator"
v-for="i in stepsLengthArray"
:key="i"
:class="{ active: i === step || advancement >= i, disabled: i > advancement }"
@click="setStep(i)"
@click="scrollToAnchor(`target-${i}`)"
>
{{ i }}
</p>
</a>
</div>
</template>
<style scoped>
Expand Down
143 changes: 143 additions & 0 deletions src/components/tutor/SummariesStep.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<script setup lang="ts">
// TODO: use button to make summary editable
// TODO: use button to validate summary --> make it required to go to the next step
// TODO: send edited summaries to the search request
import CheckIcon from '@/components/icons/CheckIcon.vue';
import ChevronDown from '@/components/icons/ChevronDown.vue';
import EditIcon from '@/components/icons/EditIcon.vue';
import { ref } from 'vue';

const props = defineProps<{
summaries: [string];
files: File;
updateSummary: () => void;
action: () => void;
actionText?: string;
disabled: boolean;
}>();

const editableParagraphs = ref(props.summaries.map(() => true));

function toggleEdit(index, value) {
editableParagraphs.value[index] = value;

if (editableParagraphs.value[index]) {
requestAnimationFrame(() => {
const el = document.getElementById(`summary_${index}`);
if (!el) return;
el.focus();

const range = document.createRange();
const sel = window.getSelection();
range.selectNodeContents(el);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
});
}
}

function preventLineBreaks(e) {
if (e.key === 'Enter') {
e.preventDefault();
}
}

function sanitizePaste(e) {
e.preventDefault();
const text = e.clipboardData.getData('text/plain').replace(/\r?\n|\r/g, ' ');
document.execCommand('insertText', false, text);
}

const handleTextEdit = (event, index) => {
const newValue = event.target.innerText;
props.updateSummary(index, newValue);
};
</script>
<template>
<div id="target-2" class="summaries-section" :class="{ disabled: disabled }">
<h2 data-testid="tutor-summaries-title" class="title is-4 mt-4">
2 - {{ $t('tutor.summaries.title') }}
</h2>
<p class="subtitle is-6">
{{ $t('tutor.summaries.description') }}
</p>
<div id="summaries" :key="index" v-for="(summary, index) in summaries">
<h2 class="title is-6 mt-4">
{{ Object.values(files)[index]?.name || $t('tutor.summaries.noFileName') }}
</h2>
<div class="is-flex">
<p
:id="`summary_${index}`"
class="input summary"
:contenteditable="editableParagraphs[index]"
@keydown="preventLineBreaks"
@paste="sanitizePaste"
@blur="handleTextEdit($event, index)"
:class="{ validated: !editableParagraphs[index] }"
>
{{ summary }}
</p>
<div class="mt-2 ml-2">
<button class="button is-white mt-2" @click="toggleEdit(index, true)">
<span class="icon is-small">
<EditIcon />
</span>
<span>{{ $t('edit') }}</span>
</button>
<button
data-testid="validate-summary-button"
class="button is-white"
@click="toggleEdit(index, false)"
:class="{ validated: !editableParagraphs[index] }"
>
<span class="icon is-small">
<CheckIcon />
</span>
<span>{{ editableParagraphs[index] ? $t('validate') : $t('validated') }}</span>
</button>
</div>
</div>
</div>
<div class="is-flex is-justify-content-end mt-4">
<a class="button is-primary" href="#" @click="action()">
<ChevronDown />
{{ $t(`${actionText || 'next'}`) }}
</a>
</div>
</div>
</template>
<style scoped>
.button > svg {
height: 1rem;
padding-right: 1rem;
}
.summaries-section {
margin: auto;
height: 80%;
padding: 5% 0;
width: 80%;
}
.summaries-section.disabled {
height: 10%;
& > * {
opacity: 50%;
}
}

button.validated {
color: green;
}

p.validated {
background-color: var(--neutral-10);
}

.summary {
width: 100%;
height: auto;
padding: 1rem;
resize: none;
margin-top: 0.5rem;
}
</style>
Loading
Loading