Skip to content

Commit 86b60e9

Browse files
committed
feat(Form): add upload file Form component
1 parent 16d152c commit 86b60e9

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

components/Gestion/ImportForm.vue

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<template>
2+
<section class="content">
3+
4+
<h1>{{title}}</h1>
5+
6+
<p>
7+
Vous pouvez importer des exercices depuis cette interface en tenant compte de ce
8+
<a href="https://sourcecodeoer.github.io/sourcecode_api/#operation/createMultipleExercises" target="_blank">
9+
format</a>.
10+
</p>
11+
<ValidationObserver ref="observer" tag="form"
12+
@submit.prevent="validateBeforeSubmit">
13+
<ValidationProvider tag="div"
14+
name="archive zip"
15+
rules="mimes:application/json"
16+
ref="fileObserver"
17+
v-slot="{ errors }">
18+
<span class="label__name">
19+
Uploadez votre fichier (json)
20+
</span>
21+
<input id="Archive" name="archive" ref="inputFile" @change="selectedFile" class="input--secondary-color"
22+
type="file">
23+
<label for="Archive">
24+
<Icon type="archive" theme="theme--white"/>
25+
{{labelFileText}}</label>
26+
<span class="error-message">{{errors[0]}}</span>
27+
<span class="message message--red" v-if="filename"
28+
style="text-decoration: underline; cursor: pointer;"
29+
@click="deleteFile">Supprimer le fichier</span>
30+
</ValidationProvider>
31+
32+
</ValidationObserver>
33+
34+
<p class="disclaimer">* champs obligatoires</p>
35+
<div class="cta__validate--wrapper">
36+
<button @click="validateBeforeSubmit"
37+
class="button--ternary-color-reverse cta__validate">
38+
Importer les exercices
39+
</button>
40+
</div>
41+
</section>
42+
43+
</template>
44+
45+
<script lang="ts">
46+
47+
import {Component, Vue, Prop, Ref} from "vue-property-decorator";
48+
import {ValidationProvider, ValidationObserver} from 'vee-validate';
49+
import {AxiosError} from "axios";
50+
import Icon from "~/components/Symbols/Icon.vue";
51+
import CustomSelect from "~/components/Input/CustomSelect.vue";
52+
53+
const debounce = require('lodash.debounce');
54+
55+
@Component({
56+
components: {CustomSelect, ValidationObserver, ValidationProvider, Icon}
57+
})
58+
export default class ExerciseForm extends Vue {
59+
/**
60+
* Validation Observer for the zip archive and the url
61+
*/
62+
@Ref() observer!: InstanceType<typeof ValidationObserver>;
63+
/**
64+
* Observer for the input file element
65+
*/
66+
@Ref() inputFile!: HTMLInputElement;
67+
/**
68+
* Validation Observer for the zip archive and the url
69+
*/
70+
@Ref() fileObserver!: InstanceType<typeof ValidationProvider>;
71+
72+
@Prop({type: String, required: true}) title!: string;
73+
74+
/**
75+
* The name of the uploaded file
76+
* Default is null
77+
*/
78+
filename: string | null = null;
79+
80+
81+
/**
82+
* Returns the name of the uploaded file or a default message instead
83+
*/
84+
protected get labelFileText() {
85+
if (this.filename !== null) {
86+
if (this.filename.length > 18) {
87+
return this.filename.slice(0, 18) + '...'
88+
}
89+
90+
return this.filename
91+
}
92+
93+
return 'Choisir un fichier...'
94+
}
95+
96+
/**
97+
* Get the json file from the input file element
98+
*/
99+
file(): File | null {
100+
101+
const inputFile: any = this.fileObserver.value;
102+
103+
if (!inputFile) {
104+
return null;
105+
}
106+
107+
return inputFile
108+
}
109+
110+
/**
111+
* Event for the changed state of the input file
112+
*/
113+
async selectedFile(event: Event) {
114+
const inputElement: HTMLInputElement | null = event.target as HTMLInputElement | null;
115+
116+
if (inputElement !== null) {
117+
const files = inputElement.files;
118+
if (files !== null) {
119+
const file: File | null = files.item(0);
120+
this.filename = file !== null ? file.name : null;
121+
await this.fileObserver.validate(file);
122+
}
123+
}
124+
}
125+
126+
/**
127+
* Delete file from input and reset the filename
128+
*/
129+
deleteFile() {
130+
this.filename = null;
131+
this.inputFile.files = null;
132+
this.fileObserver.reset();
133+
}
134+
135+
/**
136+
* Validate the entire page and send the new exercise
137+
*/
138+
async validateBeforeSubmit() {
139+
140+
// Basic validation form
141+
const isValid = await this.observer.validate();
142+
143+
let reader = new FileReader();
144+
145+
if (isValid) {
146+
147+
const file: File | null = this.file();
148+
149+
if (file !== null) {
150+
151+
reader.readAsText(file, "UTF-8");
152+
reader.onload = async (evt: any) => {
153+
const text: string = evt.target.result;
154+
try {
155+
this.$nuxt.$loading.start();
156+
await this.$axios.$post("/api/bulk/create_exercises", JSON.parse(text));
157+
this.$displaySuccess("L'importation s'est correctement déroulée.");
158+
} catch (e) {
159+
const error = e as AxiosError;
160+
161+
if (error.response) {
162+
const status = error.response.status;
163+
164+
if (status === 400) {
165+
this.$displayWarning("Votre fichier ne possède pas le bon format.")
166+
} else if (status === 401) {
167+
this.$displayWarning("Vous n'êtes pas autorisé à effectuer cette action.")
168+
} else if (status === 500) {
169+
this.$displayError("Une erreur est survenue depuis nos serveurs.")
170+
} else {
171+
this.$displayError("Une erreur est survenue.")
172+
}
173+
} else {
174+
this.$displayError("Une erreur est survenue.")
175+
}
176+
177+
} finally {
178+
this.$nuxt.$loading.finish();
179+
}
180+
};
181+
}
182+
183+
requestAnimationFrame(() => {
184+
this.observer.reset();
185+
});
186+
187+
} else {
188+
this.$displayWarning("Votre fichier ne possède pas le bon format.", {time: 5000})
189+
}
190+
}
191+
}
192+
193+
</script>
194+
195+
<style lang="scss" scoped>
196+
@import "../../assets/css/exercise-gestion";
197+
</style>

0 commit comments

Comments
 (0)