Parcourir la source

implements prefs form, input date picker, and firs prefs fields

Olivier Massot il y a 2 ans
Parent
commit
5a1e1dc5bf

+ 88 - 29
components/Layout/Parameters/PreferencesTab.vue

@@ -1,41 +1,100 @@
 <template>
 
-  <v-container>
-    <v-row>
-      <span>{{ $t('start_date_of_financial_season')}}</span>
-      <UiDatePicker v-model="financialSeasonStartDate"></UiDatePicker>
-    </v-row>
-    <v-row>
-      <span>{{ $t('start_date_of_activity_season')}}</span>
-      <UiDatePicker v-model="activitySeasonStartDate"></UiDatePicker>
-    </v-row>
-    <v-row>
-      <span>{{ $t('start_date_of_courses')}}</span>
-      <UiDatePicker v-model="coursesStartDate"></UiDatePicker>
-    </v-row>
-    <v-row>
-      <span>{{ $t('end_date_of_courses')}}</span>
-      <UiDatePicker v-model="coursesEndDate"></UiDatePicker>
-    </v-row>
-    <v-row>
-      <v-checkbox :label="$t('show_adherents_list_and_their_coordinates') + ' *'"></v-checkbox>
-    </v-row>
-    <v-row>
-      <v-checkbox :label="$t('students_are_also_association_members') + ' *'"></v-checkbox>
-    </v-row>
-
-  </v-container>
+  <LayoutContainer>
+    <v-col cols="12" sm="12" md="12">
+      <UiLoadingPanel v-if="pending" />
+      <UiForm
+          v-else-if="parameters !== null"
+          :model="Parameters"
+          :entity="parameters"
+      >
+        <v-expansion-panels :multiple="true" v-model="openedPanels">
+
+          <UiExpansionPanel title="general_parameters" icon="fas fa-info">
+            <LayoutParametersPreferencesTabGeneralParameters :parameters="parameters" />
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="website" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="teaching" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="intranet_access" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="educationNotations" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="bulletin" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="educationTimings" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="attendances" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="residenceAreas" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="sms_option" icon="fas fa-info">
+          </UiExpansionPanel>
+
+          <UiExpansionPanel title="super_admin" icon="fas fa-info">
+          </UiExpansionPanel>
+        </v-expansion-panels>
+      </UiForm>
+      <span v-else>
+        {{ $t('an_error_happened') }}
+      </span>
+    </v-col>
+  </LayoutContainer>
+
+
+
 
 
 </template>
 
 <script setup lang="ts">
 
+// On déplie les expansion panels dans le onMounted en attendant la résolution du bug : https://github.com/vuetifyjs/vuetify/issues/16427#issuecomment-1380927133
+// TODO: quand le bug ci dessus est résolu, remplacer par `const openedPanels: Ref<Array<string>> = ref(['informations', 'bills', 'more_features'])`
+import {Ref} from "@vue/reactivity";
+import {useEntityFetch} from "~/composables/data/useEntityFetch";
+import {useOrganizationProfileStore} from "~/stores/organizationProfile";
+import Parameters from "~/models/Organization/Parameters";
+
+const openedPanels: Ref<Array<string>> = ref([])
+onMounted(() => {
+  openedPanels.value = [
+    'general_parameters',
+    'website',
+    'teaching',
+    'intranet_access',
+    'educationNotations',
+    'bulletin',
+    'educationTimings',
+    'attendances',
+    'residenceAreas',
+    'sms_option',
+    'super_admin',
+  ]
+})
+
+const { fetch } = useEntityFetch()
+
+const organizationProfile = useOrganizationProfileStore()
+
+if (organizationProfile.parametersId === null) {
+  throw new Error('Missing organization parameters id')
+}
+
+const { data: parameters, pending } = fetch(Parameters, organizationProfile.parametersId)
+
+
 
-  const financialSeasonStartDate: Date = new Date()
-  const activitySeasonStartDate: Date = new Date()
-  const coursesStartDate: Date = new Date()
-  const coursesEndDate: Date = new Date()
 
 </script>
 

+ 74 - 0
components/Layout/Parameters/PreferencesTab/GeneralParameters.vue

@@ -0,0 +1,74 @@
+<template>
+  <v-container>
+    <v-row>
+      <v-col cols="6">
+        <UiInputDatePicker
+            v-model="parameters.financialDate"
+            label="start_date_of_financial_season"
+            field="financialDate"
+        />
+      </v-col>
+
+      <v-col cols="6">
+        <UiInputDatePicker
+            v-model="parameters.musicalDate"
+            label="start_date_of_activity_season"
+            field="musicalDate"
+        />
+      </v-col>
+    </v-row>
+
+    <v-row>
+      <v-col cols="6">
+        <UiInputDatePicker
+            v-model="parameters.startCourseDate"
+            label="start_date_of_courses"
+            field="startCourseDate"
+        />
+      </v-col>
+      <v-col cols="6">
+        <UiInputDatePicker
+            v-model="parameters.endCourseDate"
+            label="end_date_of_courses"
+            field="endCourseDate"
+        />
+      </v-col>
+    </v-row>
+
+    <v-row>
+      <v-col cols="6">
+        <v-checkbox :label="$t('show_adherents_list_and_their_coordinates') + ' *'"></v-checkbox>
+      </v-col>
+      <v-col cols="6">
+        <v-checkbox :label="$t('students_are_also_association_members') + ' *'"></v-checkbox>
+      </v-col>
+    </v-row>
+
+    <v-row>
+      <v-combobox
+          :label="$t('timezone')"
+          :items="['Europe / Paris', 'Europe / Zurich', 'Indian / La Réunion']"
+      />
+    </v-row>
+
+  </v-container>
+</template>
+
+<script setup lang="ts">
+import {PropType} from "@vue/runtime-core";
+import Parameters from "~/models/Organization/Parameters";
+
+const props = defineProps({
+  parameters: {
+    type: Object as PropType<Parameters>
+  }
+})
+
+const activitySeasonStartDate: Ref<Date> = ref(new Date())
+const coursesStartDate: Ref<Date> = ref(new Date())
+const coursesEndDate: Ref<Date> = ref(new Date())
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 6 - 4
components/Ui/DatePicker.vue

@@ -1,12 +1,11 @@
 <!--
 Sélecteur de dates
 
-@see https://vuetifyjs.com/en/components/date-pickers/
+@see https://vue3datepicker.com/
 -->
 
 <template>
   <main>
-    <!-- @see https://vue3datepicker.com/props/modes/#multi-calendars -->
     <VueDatePicker
         :model-value="modelValue"
         :locale="i18n.locale.value"
@@ -18,20 +17,19 @@ Sélecteur de dates
         :auto-apply="true"
         :select-text="$t('select')"
         :cancel-text="$t('cancel')"
+        :disabled="readonly"
         @update:model-value="onUpdate"
     />
   </main>
 </template>
 
 <script setup lang="ts">
-import {computed} from "@vue/reactivity";
 import DateUtils, {supportedLocales} from "~/services/utils/dateUtils";
 import {PropType} from "@vue/runtime-core";
 
 const i18n = useI18n()
 
 const fnsLocale = DateUtils.getFnsLocale(i18n.locale.value as supportedLocales)
-const defaultFormatPattern = DateUtils.getFormatPattern(i18n.locale.value as supportedLocales)
 
 const props = defineProps({
   modelValue: {
@@ -56,6 +54,10 @@ const props = defineProps({
   }
 })
 
+const defaultFormatPattern = props.withTime ?
+    DateUtils.getFormatPattern(i18n.locale.value as supportedLocales) :
+    DateUtils.getShortFormatPattern(i18n.locale.value as supportedLocales)
+
 const dateFormat: Ref<string> = ref(props.format ?? defaultFormatPattern)
 
 const emit = defineEmits(['update:model-value'])

+ 4 - 3
components/Ui/Form.vue

@@ -29,7 +29,7 @@ Formulaire générique
       </v-container>
 
       <!-- Content -->
-      <slot name="form.input" v-bind="{model, entity}"/>
+      <slot v-bind="{model, entity}"/>
 
       <!-- Bottom action bar -->
       <v-container fluid class="container btnActions">
@@ -77,7 +77,6 @@ Formulaire générique
 
 <script setup lang="ts">
 import {computed, ComputedRef, ref, Ref} from "@vue/reactivity";
-import {AnyJson} from "~/types/enum/data";
 import {FORM_FUNCTION, SUBMIT_TYPE, TYPE_ALERT} from "~/types/enum/enums";
 import { useFormStore } from "~/stores/form";
 import {Route} from "@intlify/vue-router-bridge";
@@ -85,6 +84,8 @@ import {useEntityManager} from "~/composables/data/useEntityManager";
 import ApiModel from "~/models/ApiModel";
 import {usePageStore} from "~/stores/page";
 import {watch} from "@vue/runtime-core";
+import {AnyJson} from "~/types/data";
+import * as _ from 'lodash-es'
 
 const props = defineProps({
   model: {
@@ -305,7 +306,7 @@ const quitForm = () => {
 }
 
 const actions = computed(()=>{
-  return useKeys(props.submitActions)
+  return _.keys(props.submitActions)
 })
 </script>
 

+ 31 - 94
components/Ui/Input/DatePicker.vue

@@ -1,66 +1,47 @@
 <!--
 Sélecteur de dates
-
-@see https://vuetifyjs.com/en/components/date-pickers/
 -->
 
 <template>
   <main>
-    <v-text-field
-      ref="input"
-      v-model="datesFormatted"
-      autocomplete="off"
-      :label="$t(fieldLabel)"
-      prepend-icon="mdi:mdi-calendar"
-      :disabled="readonly"
-      :density="dense ? 'compact' : 'default'"
-      :single-line="singleLine"
-      :error="error || !!fieldViolations"
-      :error-messages="errorMessage || fieldViolations ? $t(fieldViolations) : ''"
-      @update:focused=""
-      @focus="onInputFocused($event); $emit('focus', $event)"
-      @blur="onInputBlured($event); $emit('blur', $event)"
-    />
-
-    <v-menu
-      activator="input"
-      :model-value="dateOpen"
-      :close-on-content-click="false"
-      :nudge-right="40"
-      transition="scale-transition"
-      offset-y
-      min-width="auto"
-    >
-      <!-- TODO: terminer une fois v-date-picker implémenté dans vuetify 3 -->
-      <v-date-picker
-          v-model="datesParsed"
-          :range="range"
-          color="primary lighten-1"
-          @input="dateOpen = range && datesParsed.length < 2"
+    <div class="d-flex flex-column">
+      <span>{{ $t(fieldLabel) }}</span>
+
+      <UiDatePicker
+          v-model="date"
+          :readonly="readonly"
+          :format="format"
+          @update:model-value="onUpdate($event)"
+          @change="onChange($event)"
       />
-    </v-menu>
+
+      <span v-if="error || !!fieldViolations" class="theme-danger">
+        {{ errorMessage || fieldViolations ? $t(fieldViolations) : '' }}
+      </span>
+    </div>
   </main>
 </template>
 
 <script setup lang="ts">
 import {useFieldViolation} from "~/composables/form/useFieldViolation";
-import {computed, ComputedRef, Ref} from "@vue/reactivity";
-import DateUtils from "~/services/utils/dateUtils";
-import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
+import {formatISO} from "date-fns";
 
 const props = defineProps({
-  field: {
+  /**
+   * v-model
+   */
+  modelValue: {
     type: String,
     required: false,
     default: null
   },
-  label: {
+  field: {
     type: String,
     required: false,
     default: null
   },
-  data: {
-    type: [String, Array],
+  label: {
+    type: String,
     required: false,
     default: null
   },
@@ -68,22 +49,10 @@ const props = defineProps({
     type: Boolean,
     required: false
   },
-  range: {
-    type: Boolean,
-    required: false
-  },
-  dense: {
-    type: Boolean,
-    required: false
-  },
-  singleLine: {
-    type: Boolean,
-    required: false
-  },
   format: {
     type: String,
     required: false,
-    default: 'DD/MM/YYYY'
+    default: null
   },
   error: {
     type: Boolean,
@@ -98,55 +67,23 @@ const props = defineProps({
 
 const input = ref(null)
 
-const { emit } = useNuxtApp()
-
-const { data, range } = props
-
 const {fieldViolations, updateViolationState} = useFieldViolation(props.field)
 
-const datesParsed: Ref<Array<string>|string|null> = range ? ref(Array<string>()) : ref(null)
-
 const fieldLabel = props.label ?? props.field
 
-const dateOpen: Ref<boolean> = ref(false)
+const emit = defineEmits(['update:model-value', 'change'])
 
-const onInputFocused = (event: any) => {
-  dateOpen.value = true
-}
+const date: Ref<Date> = ref(new Date(props.modelValue))
+console.log(date.value)
 
-const onInputBlured = (event: any) => {
-  dateOpen.value = false
+const onUpdate = (event: string) => {
+  emit('update:model-value', formatISO(date.value))
 }
 
-
-
-if (Array.isArray(datesParsed.value)) {
-  for (const date of data as Array<string>) {
-    if (date) {
-      datesParsed.value.push(DateUtils.format(date, 'YYYY-MM-DD'))
-    }
-  }
-} else {
-  datesParsed.value = data ? DateUtils.format(data, 'YYYY-MM-DD') : null
+const onChange = (event: Event | undefined) => {
+  updateViolationState(event)
+  emit('change', formatISO(date.value))
 }
-
-const datesFormatted: ComputedRef<string|null> = computed(() => {
-  if (props.range && datesParsed.value && datesParsed.value.length < 2) {
-    return null
-  }
-  return datesParsed.value ? DateUtils.formatAndConcat(datesParsed.value, props.format) :  null
-})
-
-const unwatch: WatchStopHandle = watch(datesParsed, (newValue, oldValue) => {
-  if (newValue === oldValue) { return }
-  if (props.range && newValue && newValue.length < 2) { return }
-  updateViolationState(Array.isArray(newValue) ? DateUtils.sort(newValue) : newValue)
-})
-
-onUnmounted(() => {
-  unwatch()
-})
-
 </script>
 
 <style scoped>

+ 19 - 0
components/Ui/LoadingPanel.vue

@@ -0,0 +1,19 @@
+<template>
+  <v-row
+      class="fill-height ma-0"
+      align="center"
+      justify="center"
+  >
+    <v-progress-circular
+        :indeterminate="true"
+        color="neutral"
+    />
+  </v-row>
+</template>
+
+<script setup lang="ts">
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 11 - 1
lang/fr.json

@@ -594,5 +594,15 @@
   "start_date_of_courses": "Date de début des cours",
   "end_date_of_courses": "Date de fin des cours",
   "show_adherents_list_and_their_coordinates": "Afficher la liste des adhérents et leurs coordonnées",
-  "students_are_also_association_members": "Les élèves sont adhérents également de l'association"
+  "students_are_also_association_members": "Les élèves sont adhérents également de l'association",
+  "general_parameters": "Paramètres généraux",
+  "teaching": "Enseignements",
+  "intranet_access": "Accès intranet (professeurs, élèves...)",
+  "educationNotations": "Suivi pédagogique",
+  "bulletin": "Bulletins",
+  "educationTimings": "Durée des cours (en minutes)",
+  "residenceAreas": "Zones de résidence",
+  "sms_option": "Option SMS",
+  "super_admin": "Compte super-admin",
+  "an_error_happened": "Une erreur s'est produite"
 }