Commit 08ba96dc authored by GuiΩ's avatar GuiΩ
Browse files

feat(loading): add "loading" indicators

for themes, questions and evolution
parent f57fc659
......@@ -6,8 +6,8 @@
<script setup lang="ts">
import {computed, reactive, ref} from "vue"
import Modal from '@/components/Modal.vue'
import type {ClasseID, ThemeID} from "../types"
import {useThemesStore} from "../store/themes";
import type {ClasseID, ThemeID} from "@/types"
import {useThemesStore} from "@/store/themes";
import {useClassesStore} from "@/store/classes";
import EvolutionDialogQP from "@/components/EvolutionDialogQP.vue"
......@@ -76,7 +76,10 @@ Modal(
template(v-slot:title) Évolution de la classe {{ classe?.nom }} pour le thème "{{ themePath }}"
template(v-slot:body)
.EvolutionDialog__body(ref="body")
div(v-if="themes.isLoadingEvolution") Chargement...
div(v-if="!themes.isLoadingEvolution && ! questionPosees.length") Ce thème n'a jamais été abordé
EvolutionDialogQP(
v-else="themes.isLoadingEvolution"
v-for="questionPosee in questionPosees"
:key="questionPosee.id"
:questionPosee="questionPosee"
......@@ -94,4 +97,4 @@ Modal(
overflow: auto
display: flex
flex-direction: column
</style>
\ No newline at end of file
</style>
\ No newline at end of file
......@@ -185,19 +185,19 @@ EvolutionDialog(
ref="evolutionDialog"
@show-question-tooltip="onShowQuestionTooltip")/
#main-page
.MainPage
Toolbar.Toolbar(
@classe-changed="onClasseChanged")/
.Mainpanel
.Selector
ThemeTree.Selector_theme(
ThemeTree.Selector__theme(
:selection-ids="selectionThemeId"
@selection-changed="themes.setSelectedTheme($event[0])"
@show-context-menu="onShowContextMenu"
@show-evolution-dialog="onShowEvolutionDialog")/
.Selector_question
.Selector__question
button(data-testid="newQuestion" @click="$refs.questionEditor.edit()") Nouvelle question
QuestionList.Selector_questionList(
QuestionList.Selector__questionList(
ref="questionList"
:themeId="themes.getSelectedId"
:classeId="classes.getSelectedId"
......@@ -233,7 +233,7 @@ body
.QuestionEditor
z-index: 5
#main-page
.MainPage
position: absolute
top: 0
bottom: 0
......@@ -269,30 +269,24 @@ body
height: calc(100% - 24px)
.Selector_theme
.Selector__theme
flex: 1 1 auto
vertical-align: top
background-color: white
border: base.$borders
overflow: auto
/*max-height: 600px*/
/*overflow-y: scroll*/
min-width: 100px
margin: 0
.Selector_question
.Selector__question
text-align: center
display: flex
flex-direction: column
border-bottom: base.$borders
.Selector_questionList
.Selector__questionList
border: base.$borders
.FeuilleList
flex: 10 10 auto
......
......@@ -27,7 +27,7 @@ Events:
interface IQuestionListState {
questionsIds: QuestionID[],
questionsIds?: QuestionID[],
scores: {},
questionsSel: QuestionID[],
onLoaded?: () => void
......@@ -128,7 +128,7 @@ Events:
if (last < first)
inc = -1;
for (let i = first+inc; i*inc <= last*inc ; i+= inc) {
let qId = state.questionsIds[i];
let qId = state.questionsIds![i];
if (state.questionsSel.indexOf(qId) < 0)
state.questionsSel.push(qId);
}
......@@ -283,7 +283,7 @@ Events:
}
function changePosition(indexSource: number, indexDrop: number) {
const ids = questions.getForCurrTheme
const ids = questions.getForCurrTheme!
// const indexSource = this.dropEvent.dataTransfer.getData('index');
// const positionDest = questions.get(ids[indexDrop]).question.getPositionInTheme(props.themeId);
const positionDrop = questions.getPositionInTheme(ids[indexDrop], props.themeId!);
......@@ -323,7 +323,7 @@ Events:
}
}
} else if (indexDrop > indexSource) { // after the actual position
if (indexDrop === state.questionsIds.length - 1) {
if (indexDrop === state.questionsIds!.length - 1) {
for (let i = 0; i < selLength.value; i++) {
newPosition[i] = positionDrop + 128 * (i + 1) // after the last question
}
......@@ -373,7 +373,7 @@ Events:
*/
function findFirstOrdered() {
let index = 0;
while (questions.getPositionInTheme(questions.getForCurrTheme[index], props.themeId!) === null)
while (questions.getPositionInTheme(questions.getForCurrTheme![index], props.themeId!) === null)
index++
return questionNodes.value[index]
}
......@@ -395,8 +395,9 @@ Events:
<template lang="pug">
.QuestionList(ref="root")
|{{ questionsIds.length }} question{{ questionsIds.length > 1 ? 's' : '' }}
.QuestionList_list
span(v-if="themes.isLoading || questions.isLoading ") Chargement...
span(v-else="themes.isLoading || questions.isLoading") {{ questionsIds.length }} question{{ questionsIds.length > 1 ? 's' : '' }}
.QuestionList_list(v-if="! (themes.isLoading || questions.isLoading)")
QuestionListNode.QuestionList_node(
v-for="(questionId, index) in questionsIds"
:key="index"
......
......@@ -68,6 +68,12 @@ import {useClassesStore} from "@/store/classes";
}
return path
}
function onEvolutionClick(themeId: ThemeID) {
close()
emit('show-evolution-dialog', {themeId: themeId, classeId: classes.getSelectedId})
}
defineExpose({show, close})
</script>
......@@ -91,8 +97,8 @@ import {useClassesStore} from "@/store/classes";
img.QuestionTooltip__link(
src="/static/evolution.png"
:title="'Voir l\\'évolution pour \"' + themes.get(themeId).label + '\"'"
@click="$emit('show-evolution-dialog', {themeId: themeId, classeId: classes.getSelectedId})")
span(v-if="themeId !== question_order.theme") &nbsp;>&nbsp
@click.stop="onEvolutionClick(themeId)")
span(v-if="themeId !== question_order.theme") &nbsp;>&nbsp;
</template>
......
......@@ -118,15 +118,18 @@
</script>
<template lang="pug">
ul.ThemeTree(ref="themeTree")
ul.ThemeTree(ref="themeTree"
v-if="root")
themeTreeNode.ThemeTree__node(
:open-ids="state.openIds"
:selection-ids="props.selectionIds"
:theme="themes.get(1)"
:theme="root"
:show-empty="props.showEmpty"
@click-on-Theme="onClickOnTheme"
@show-context-menu="$emit('show-context-menu', $event)"
@show-evolution-dialog="$emit('show-evolution-dialog', $event)")/
div(v-else="root") Chargement des thèmes...
</template>
......
......@@ -15,16 +15,20 @@ import {$axios} from "@/store/axios-instance";
export interface IQuestionsStore {
_questions: Map<QuestionID, IQuestion>,
// TODO: remove any
_questionSavedStatus: {saved: boolean, errors: any}
_questionSavedStatus: {saved: boolean, errors: any},
_isLoading: boolean
}
export const useQuestionsStore = defineStore('questionsStore',{
state: (): IQuestionsStore => ({
_questions: new Map<QuestionID, IQuestion>(),
_questionSavedStatus: {saved: false, errors: {}},
_isLoading: false
}),
getters: {
isLoading: (state: IQuestionsStore) => state._isLoading,
/**
* @returns the list of the ids of the questions for the current theme
*/
......@@ -33,9 +37,7 @@ export const useQuestionsStore = defineStore('questionsStore',{
if (! themes.hasSelection)
return []
const theme = themes.getSelected
if (theme.questions === undefined)
return []
return theme.questions
return theme?.questions
},
get: (state: IQuestionsStore) => (questionId: QuestionID) =>
......@@ -70,23 +72,6 @@ export const useQuestionsStore = defineStore('questionsStore',{
},
// // mutations
// const mutations = {
// 'QUESTION'(state, data) {
// data.getPositionInTheme = getQuestionPositionInTheme;
// Vue.set(state.questions, data.id, data)
// },
// 'QUESTION_SAVE_INIT'(state) {
// state.questionSaveStatus = {saved: false, errors: {}}
// },
// 'QUESTION_SAVE_ERRORS'(state, errors) {
// Vue.set(state.questionSaveStatus, 'errors', errors)
// },
// 'QUESTION_SAVE_STATUS'(state, status) {
// Vue.set(state.questionSaveStatus, 'status', status)
// },
//
// }
actions: {
initSave() {
this._questionSavedStatus = {saved: false, errors: {}}
......@@ -154,6 +139,7 @@ export const useQuestionsStore = defineStore('questionsStore',{
loadQuestions(questionIds: QuestionID[]) {
if (questionIds.length === 0)
return
this._isLoading = true
return axios.get("api/question/?" + questionIds.map(id => 'ids[]=' + id).join('&'))
.then(response => {
for (let question of response.data) {
......@@ -161,6 +147,7 @@ export const useQuestionsStore = defineStore('questionsStore',{
}
})
.catch(error => console.error(error))
.finally(() => this._isLoading = false)
},
......
......@@ -10,6 +10,8 @@ interface IThemeStore {
_selectedId: ThemeID | undefined,
_selectedIds: ThemeID[],
_evolution: IQuestionPosee[],
_isLoading: boolean,
_isLoadingEvolution: boolean,
}
export const useThemesStore = defineStore('themesStore',{
......@@ -18,9 +20,13 @@ export const useThemesStore = defineStore('themesStore',{
_selectedId: undefined,
_selectedIds: [],
_evolution: [],
_isLoading: false,
_isLoadingEvolution: false,
}),
getters: {
isLoading: (state: IThemeStore) => state._isLoading,
/**
* @param themeId
* @returns the theme for the given id
......@@ -28,6 +34,7 @@ export const useThemesStore = defineStore('themesStore',{
get: (state: IThemeStore) => (themeId: ThemeID) => state._themes.get(themeId) as ITheme,
getSelectedId: (state:IThemeStore) => state._selectedId,
getSelected: (state: IThemeStore) => state._themes.get(state._selectedId as ThemeID) as ITheme,
isLoadingEvolution: (state: IThemeStore) => state._isLoadingEvolution,
getEvolution: (state:IThemeStore) => state._evolution,
hasSelection:(state: IThemeStore) => state._selectedId !== undefined
},
......@@ -71,15 +78,18 @@ export const useThemesStore = defineStore('themesStore',{
loadTheme(themeId: ThemeID, force = false) {
if (! force && this._themes.has(themeId))
return
this._isLoading = true
return $axios.get('api/theme/' + themeId + '/')
.then(response => {
const theme = response.data
this._themes.set(theme.id, theme)
})
.catch(error => console.error(error))
.finally(() => this._isLoading = false)
},
loadThemes() {
this._isLoading = true
return $axios.get("api/theme/")
.then(response => {
for (let theme of response.data)
......@@ -100,13 +110,16 @@ export const useThemesStore = defineStore('themesStore',{
}
})
.catch(error => console.error(error))
.finally(() => this._isLoading = false)
},
loadEvolution(themeId: ThemeID, classeId: ClasseID) {
this._isLoadingEvolution = true
this._evolution = []
return $axios.get("api/theme/" + themeId + '/get_evolution/?classe_id=' + classeId)
.then(response => this._evolution = response.data)
.catch(error => console.error(error))
.finally(() => this._isLoadingEvolution = false)
},
}
})
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment