Skip to content

Commit 3d66cdc

Browse files
feat(tutor): fix how files are handled when added, removed, replaced
1 parent 6de9b0b commit 3d66cdc

File tree

3 files changed

+92
-40
lines changed

3 files changed

+92
-40
lines changed

src/components/tutor/FirstStep.vue

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,72 @@
22
import { ref } from 'vue';
33
const props = defineProps<{
44
disabled?: boolean;
5-
addFile?: (e: Event) => void;
5+
addFile?: (e: Event, id?: string) => void;
6+
removeFile?: (id: string) => void;
67
searchError?: boolean;
78
}>();
8-
const inputGroupLength = ref(1);
9+
const inputGroupLength = ref(document.querySelectorAll('.input-group input').length || 1);
10+
const uid = ref(0);
11+
const inputGroupRef = ref<HTMLElement | null>(null);
12+
const inputContainerRef = ref<HTMLElement | null>(null);
13+
const fileInputRef = ref<HTMLInputElement | null>(null);
14+
const deleteButtonRef = ref<HTMLButtonElement | null>(null);
15+
16+
const updateInputGroupLength = () => {
17+
inputGroupLength.value = document.querySelectorAll('.input-group input').length;
18+
};
19+
20+
const createInput = (id: string) => {
21+
const input = fileInputRef.value?.cloneNode(false) as HTMLInputElement;
22+
input.id = id;
23+
input.files = new DataTransfer().files; // Clear previous files
24+
input.addEventListener('change', (e) => props.addFile(e, id));
25+
return input;
26+
};
27+
28+
const createDeletebutton = (container: HTMLElement) => {
29+
const delButton = deleteButtonRef.value?.cloneNode(true) as HTMLButtonElement;
30+
delButton.addEventListener('click', () => {
31+
props.removeFile(container.id);
32+
if (container && container.parentNode === inputGroupRef.value) {
33+
inputGroupRef.value.removeChild(container);
34+
}
35+
updateInputGroupLength();
36+
});
37+
return delButton;
38+
};
939
10-
// TODO: think of a vue way of doing this
1140
const appendNewInputFile = () => {
12-
const inputGroup = document.querySelector('.input-group');
13-
const div = document.createElement('div');
14-
div.className = 'is-flex is-flex-direction-row';
15-
const deleteButton = document.createElement('button');
16-
deleteButton.className = 'button';
17-
deleteButton.innerHTML = 'x';
18-
deleteButton.onclick = () => {
19-
inputGroup.removeChild(div);
20-
inputGroupLength.value -= 1;
21-
};
22-
const input = document.createElement('input');
23-
input.id = `file-${inputGroupLength.value}`;
24-
input.type = 'file';
25-
input.className = 'input';
26-
input.accept = 'application/pdf, text/*';
27-
input.placeholder = 'Enter the new file';
28-
input.setAttribute('data-testid', 'file-input');
29-
input.onchange = (e) => props.addFile(e);
30-
div.appendChild(input);
31-
div.appendChild(deleteButton);
32-
inputGroup.appendChild(div);
33-
inputGroupLength.value += 1;
41+
if (!inputGroupRef.value || !inputContainerRef.value) {
42+
console.error('Input group is not defined');
43+
return;
44+
}
45+
46+
const elementId = `file_${++uid.value}`;
47+
48+
const container = inputContainerRef.value.cloneNode(false) as HTMLElement;
49+
container.id = elementId;
50+
const input = createInput(elementId);
51+
const delButton = createDeletebutton(container);
52+
53+
container.appendChild(input);
54+
container.appendChild(delButton);
55+
inputGroupRef.value.appendChild(container);
56+
updateInputGroupLength();
3457
};
3558
3659
const removeFirstChild = () => {
37-
const inputGroup = document.querySelector('.input-group');
60+
const inputGroup = inputGroupRef.value;
3861
inputGroup.removeChild(inputGroup.firstChild);
39-
inputGroupLength.value -= 1;
62+
props.removeFile('file_0');
63+
updateInputGroupLength();
4064
};
4165
4266
const removeLastInputFile = () => {
4367
const inputGroup = document.querySelector('.input-group');
4468
inputGroup.removeChild(inputGroup.lastChild);
45-
inputGroupLength.value -= 1;
69+
props.removeFile(`file_${inputGroupLength.value}`);
70+
updateInputGroupLength();
4671
};
4772
</script>
4873
<template>
@@ -79,17 +104,26 @@ const removeLastInputFile = () => {
79104
</div>
80105
</div>
81106
<div>
82-
<div class="input-group is-flex is-flex-direction-column">
83-
<div class="is-flex is-flex-direction-row" id="first">
107+
<div ref="inputGroupRef" class="input-group is-flex is-flex-direction-column">
108+
<div ref="inputContainerRef" class="is-flex is-flex-direction-row" id="first">
84109
<input
110+
ref="fileInputRef"
85111
class="input"
86112
type="file"
87113
accept="application/pdf, text/*"
114+
<<<<<<< HEAD
88115
placeholder="Enter the new file"
89116
data-testid="file-input"
90117
@change="addFile"
118+
||||||| parent of aeaf9fa (feat(tutor): fix how files are handled when added, removed, replaced)
119+
placeholder="Enter the name of the file"
120+
@change="addFile"
121+
=======
122+
placeholder="Enter the name of the file"
123+
@change="(e) => addFile(e, 'file_0')"
124+
>>>>>>> aeaf9fa (feat(tutor): fix how files are handled when added, removed, replaced)
91125
/>
92-
<button class="button" @click="removeFirstChild">x</button>
126+
<button ref="deleteButtonRef" class="button" @click="removeFirstChild">x</button>
93127
</div>
94128
</div>
95129
<button class="button" :disabled="inputGroupLength === 3" @click="appendNewInputFile">

src/stores/tutor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ type TutorSyllabus = {
1919
export const useTutorStore = defineStore('tutor', () => {
2020
const tutorSearch: Ref<TutorSearch | null> = ref(null);
2121

22-
const retrieveTutorSearch = async (arg: FormData): Promise<TutorSearch> => {
23-
const resp = await postAxios('/tutor/search', arg, {
22+
const retrieveTutorSearch = async (arg: { string: File }): Promise<TutorSearch> => {
23+
const formData = new FormData();
24+
const files = Object.values(arg);
25+
files.forEach((file) => formData.append('files', file));
26+
27+
const resp = await postAxios('/tutor/search', formData, {
2428
headers: { 'content-type': 'multipart/form-data' }
2529
});
2630

src/views/TutorPage.vue

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,55 @@ import { convertMarkdownToDocx, downloadDocx } from '@/utils/md-to-docx';
1010
import i18n from '@/localisation/i18n';
1111
const store = useTutorStore();
1212
13-
const files: Ref<File[]> = ref([]);
13+
const files: Ref<{ string: File }> = ref({});
1414
const response: Ref<TutorSearch | null> = ref(null);
1515
const syllabus = ref<[]>([]);
1616
const step = ref(1);
1717
const isLoading = ref(false);
1818
const searchError = ref(false);
1919
20-
const formData = new FormData();
2120
2221
// TODO: handle remove document
23-
const addFile = (e: any) => {
22+
const addFile = (e: any, input_id?: str = 'files') => {
2423
if (e.target.files[0].size > 5 * 1024 * 1024) {
2524
alert(i18n.global.t('tutor.fileSizeExceeded'));
2625
return;
2726
}
27+
2828
searchError.value = false;
29-
formData.append('files', e.target.files[0]);
30-
files.value.push(e.target.files);
29+
files.value = {
30+
...files.value,
31+
[input_id]: e.target.files[0]
32+
};
33+
console.log('Current files:', files.value);
34+
};
35+
36+
const handleRemoveFile = (id: string) => {
37+
if (files.value[id]) {
38+
delete files.value[id];
39+
} else {
40+
console.error('File not found:', id);
41+
}
3142
};
3243
3344
const handleSearch = async () => {
3445
response.value = null;
3546
searchError.value = false;
3647
37-
if (!files.value.length) {
48+
if (!Object.keys(files.value).length) {
49+
console.error('No files selected');
3850
return;
3951
}
4052
isLoading.value = true;
4153
4254
try {
43-
const resp = await store.retrieveTutorSearch(formData);
55+
const resp = await store.retrieveTutorSearch(files.value);
4456
response.value = resp;
4557
} catch (error) {
4658
isLoading.value = false;
4759
response.value = { documents: [] };
4860
searchError.value = true;
61+
console.error('Error during search:', error);
4962
return;
5063
} finally {
5164
isLoading.value = false;
@@ -113,6 +126,7 @@ const stepToAction = {
113126
:disabled="step > 1"
114127
v-if="step >= 1"
115128
:addFile="addFile"
129+
:removeFile="handleRemoveFile"
116130
/>
117131
<SecondStep
118132
data-test="second-step"

0 commit comments

Comments
 (0)