parent
							
								
									53374ed2d9
								
							
						
					
					
						commit
						beec0d19f5
					
				@ -1,218 +1,175 @@ | 
				
			||||
<template> | 
				
			||||
    <q-form> | 
				
			||||
      <v-container> | 
				
			||||
        <v-row> | 
				
			||||
          <v-col> | 
				
			||||
            <q-input | 
				
			||||
                id="item_title" | 
				
			||||
                v-model="item.title" | 
				
			||||
                :error="v$.item.title.$error" | 
				
			||||
                :error-message="titleErrors" | 
				
			||||
                :placeholder="$t('Title')" | 
				
			||||
                @blur="v$.item.title.$touch()" | 
				
			||||
                @input="v$.item.title.$touch()" | 
				
			||||
  <form | 
				
			||||
    action="#" | 
				
			||||
    class="flex flex-col gap-4" | 
				
			||||
  > | 
				
			||||
    <div class="form__field"> | 
				
			||||
      <div class="p-float-label"> | 
				
			||||
        <InputText | 
				
			||||
          id="item_title" | 
				
			||||
          v-model="v$.item.title.$model" | 
				
			||||
          :class="{'p-invalid': v$.item.title.$invalid}" | 
				
			||||
        /> | 
				
			||||
        <label | 
				
			||||
          v-t="'Title'" | 
				
			||||
          for="item_title" | 
				
			||||
        /> | 
				
			||||
      </div> | 
				
			||||
      <small | 
				
			||||
        v-if="v$.item.title.$invalid || v$.item.title.$pending.$response" | 
				
			||||
        v-t="v$.item.title.required.$message" | 
				
			||||
        class="p-error" | 
				
			||||
      /> | 
				
			||||
    </div> | 
				
			||||
 | 
				
			||||
    <div class="flex gap-4"> | 
				
			||||
      <div class="w-1/2 flex flex-col gap-4"> | 
				
			||||
        <div class="form__field"> | 
				
			||||
          <div class="p-float-label"> | 
				
			||||
            <Calendar | 
				
			||||
              id="start_date" | 
				
			||||
              v-model="item.startDate" | 
				
			||||
              :show-icon="true" | 
				
			||||
              :show-time="true" | 
				
			||||
            /> | 
				
			||||
 | 
				
			||||
            <q-input v-model="item.startDate" filled> | 
				
			||||
              <template v-slot:prepend> | 
				
			||||
                <q-icon class="cursor-pointer" name="event"> | 
				
			||||
                  <q-popup-proxy transition-hide="scale" transition-show="scale"> | 
				
			||||
                    <q-date v-model="item.startDate" mask="YYYY-MM-DD HH:mm"> | 
				
			||||
                      <div class="row items-center justify-end"> | 
				
			||||
                        <q-btn v-close-popup color="primary" flat label="Close"/> | 
				
			||||
                      </div> | 
				
			||||
                    </q-date> | 
				
			||||
                  </q-popup-proxy> | 
				
			||||
                </q-icon> | 
				
			||||
              </template> | 
				
			||||
 | 
				
			||||
              <template v-slot:append> | 
				
			||||
                <q-icon class="cursor-pointer" name="access_time"> | 
				
			||||
                  <q-popup-proxy transition-hide="scale" transition-show="scale"> | 
				
			||||
                    <q-time v-model="item.startDate" format24h mask="YYYY-MM-DD HH:mm"> | 
				
			||||
                      <div class="row items-center justify-end"> | 
				
			||||
                        <q-btn v-close-popup color="primary" flat label="Close"/> | 
				
			||||
                      </div> | 
				
			||||
                    </q-time> | 
				
			||||
                  </q-popup-proxy> | 
				
			||||
                </q-icon> | 
				
			||||
              </template> | 
				
			||||
            </q-input> | 
				
			||||
 | 
				
			||||
            <q-input v-model="item.endDate" filled> | 
				
			||||
              <template v-slot:prepend> | 
				
			||||
                <q-icon class="cursor-pointer" name="event"> | 
				
			||||
                  <q-popup-proxy transition-hide="scale" transition-show="scale"> | 
				
			||||
                    <q-date v-model="item.endDate" mask="YYYY-MM-DD HH:mm"> | 
				
			||||
                      <div class="row items-center justify-end"> | 
				
			||||
                        <q-btn v-close-popup color="primary" flat label="Close"/> | 
				
			||||
                      </div> | 
				
			||||
                    </q-date> | 
				
			||||
                  </q-popup-proxy> | 
				
			||||
                </q-icon> | 
				
			||||
              </template> | 
				
			||||
 | 
				
			||||
              <template v-slot:append> | 
				
			||||
                <q-icon class="cursor-pointer" name="access_time"> | 
				
			||||
                  <q-popup-proxy transition-hide="scale" transition-show="scale"> | 
				
			||||
                    <q-time v-model="item.endDate" format24h mask="YYYY-MM-DD HH:mm"> | 
				
			||||
                      <div class="row items-center justify-end"> | 
				
			||||
                        <q-btn v-close-popup color="primary" flat label="Close"/> | 
				
			||||
                      </div> | 
				
			||||
                    </q-time> | 
				
			||||
                  </q-popup-proxy> | 
				
			||||
                </q-icon> | 
				
			||||
              </template> | 
				
			||||
            </q-input> | 
				
			||||
 | 
				
			||||
            <!--                <q-input--> | 
				
			||||
            <!--                    v-model="item.content"--> | 
				
			||||
            <!--                    :error="v$.item.content.$error"--> | 
				
			||||
            <!--                    :error-message="contentErrors"--> | 
				
			||||
            <!--                    :placeholder="$t('Content')"--> | 
				
			||||
            <!--                    type="textarea"--> | 
				
			||||
            <!--                    @blur="v$.item.content.$touch()"--> | 
				
			||||
            <!--                    @input="v$.item.content.$touch()"--> | 
				
			||||
            <!--                />--> | 
				
			||||
 | 
				
			||||
            <TinyEditor | 
				
			||||
                v-model="item.content" | 
				
			||||
                required | 
				
			||||
                :init="{ | 
				
			||||
                  skin_url: '/build/libs/tinymce/skins/ui/oxide', | 
				
			||||
                  content_css: '/build/libs/tinymce/skins/content/default/content.css', | 
				
			||||
                  branding: false, | 
				
			||||
                  relative_urls: false, | 
				
			||||
                  height: 250, | 
				
			||||
                  toolbar_mode: 'sliding', | 
				
			||||
                  file_picker_callback : browser, | 
				
			||||
                  autosave_ask_before_unload: true, | 
				
			||||
                  plugins: [ | 
				
			||||
                    'advlist autolink lists link image charmap print preview anchor', | 
				
			||||
                    'searchreplace visualblocks code fullscreen', | 
				
			||||
                    'insertdatetime media table paste wordcount emoticons' | 
				
			||||
                  ], | 
				
			||||
                  toolbar: 'undo redo | bold italic underline strikethrough | insertfile image media template link | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent |  numlist bullist | forecolor backcolor removeformat | pagebreak | charmap emoticons | fullscreen  preview save print | code codesample | ltr rtl', | 
				
			||||
                }" | 
				
			||||
            <label | 
				
			||||
              v-t="'From'" | 
				
			||||
              for="start_date" | 
				
			||||
            /> | 
				
			||||
          </v-col> | 
				
			||||
 | 
				
			||||
          <v-col> | 
				
			||||
            <div | 
				
			||||
                v-text="$t('Invitees')" | 
				
			||||
                class="text-h6" | 
				
			||||
            > | 
				
			||||
            </div> | 
				
			||||
 | 
				
			||||
            <EditLinks | 
				
			||||
                :item="item" | 
				
			||||
                :show-status="false" | 
				
			||||
                :edit-status="false" | 
				
			||||
                :links-type="linksType" | 
				
			||||
          </div> | 
				
			||||
        </div> | 
				
			||||
 | 
				
			||||
        <div class="form__field"> | 
				
			||||
          <div class="p-float-label"> | 
				
			||||
            <Calendar | 
				
			||||
              id="end_date" | 
				
			||||
              v-model="item.endDate" | 
				
			||||
              :show-icon="true" | 
				
			||||
              :show-time="true" | 
				
			||||
            /> | 
				
			||||
            <q-checkbox | 
				
			||||
                v-model="item.collective" | 
				
			||||
                :label="$t('Is it editable by the invitees?')" | 
				
			||||
            <label | 
				
			||||
              v-t="'From'" | 
				
			||||
              for="end_date" | 
				
			||||
            /> | 
				
			||||
          </v-col> | 
				
			||||
 | 
				
			||||
          <slot></slot> | 
				
			||||
        </v-row> | 
				
			||||
      </v-container> | 
				
			||||
    </q-form> | 
				
			||||
          </div> | 
				
			||||
        </div> | 
				
			||||
 | 
				
			||||
        <TinyEditor | 
				
			||||
          v-model="item.content" | 
				
			||||
          :init="{ | 
				
			||||
            skin_url: '/build/libs/tinymce/skins/ui/oxide', | 
				
			||||
            content_css: '/build/libs/tinymce/skins/content/default/content.css', | 
				
			||||
            branding: false, | 
				
			||||
            relative_urls: false, | 
				
			||||
            height: 250, | 
				
			||||
            toolbar_mode: 'sliding', | 
				
			||||
            file_picker_callback : browser, | 
				
			||||
            autosave_ask_before_unload: true, | 
				
			||||
            plugins: [ | 
				
			||||
              'advlist autolink lists link image charmap print preview anchor', | 
				
			||||
              'searchreplace visualblocks code fullscreen', | 
				
			||||
              'insertdatetime media table paste wordcount emoticons' | 
				
			||||
            ], | 
				
			||||
            toolbar: 'undo redo | bold italic underline strikethrough | insertfile image media template link | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent |  numlist bullist | forecolor backcolor removeformat | pagebreak | charmap emoticons | fullscreen  preview save print | code codesample | ltr rtl', | 
				
			||||
          }" | 
				
			||||
          required | 
				
			||||
        /> | 
				
			||||
      </div> | 
				
			||||
 | 
				
			||||
      <div class="w-1/2 flex flex-col gap-4"> | 
				
			||||
        <div | 
				
			||||
          v-t="'Invitees'" | 
				
			||||
          class="text-h6" | 
				
			||||
        /> | 
				
			||||
 | 
				
			||||
        <EditLinks | 
				
			||||
          :edit-status="false" | 
				
			||||
          :item="item" | 
				
			||||
          :links-type="linksType" | 
				
			||||
          :show-status="false" | 
				
			||||
        /> | 
				
			||||
 | 
				
			||||
        <div class="form__field"> | 
				
			||||
          <Checkbox | 
				
			||||
            id="is_collective" | 
				
			||||
            v-model="item.collective" | 
				
			||||
          /> | 
				
			||||
          <label | 
				
			||||
            v-t="'Is it editable by the invitees?'" | 
				
			||||
            for="is_collective" | 
				
			||||
          /> | 
				
			||||
        </div> | 
				
			||||
      </div> | 
				
			||||
    </div> | 
				
			||||
 | 
				
			||||
    <slot /> | 
				
			||||
  </form> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import has from 'lodash/has'; | 
				
			||||
import useVuelidate from '@vuelidate/core'; | 
				
			||||
import {required} from '@vuelidate/validators'; | 
				
			||||
import EditLinks from "../resource_links/EditLinks.vue"; | 
				
			||||
import {computed, ref} from "vue"; | 
				
			||||
import {useStore} from "vuex"; | 
				
			||||
 | 
				
			||||
export default { | 
				
			||||
  name: 'CCalendarEventForm', | 
				
			||||
  components: { | 
				
			||||
    EditLinks | 
				
			||||
<script setup> | 
				
			||||
import { computed, ref } from 'vue'; | 
				
			||||
import { useStore } from 'vuex'; | 
				
			||||
import { useVuelidate } from '@vuelidate/core'; | 
				
			||||
import { required } from '@vuelidate/validators'; | 
				
			||||
import InputText from 'primevue/inputtext'; | 
				
			||||
import Calendar from 'primevue/calendar'; | 
				
			||||
import EditLinks from '../resource_links/EditLinks.vue'; | 
				
			||||
import Checkbox from 'primevue/checkbox'; | 
				
			||||
 | 
				
			||||
const store = useStore(); | 
				
			||||
 | 
				
			||||
// eslint-disable-next-line no-undef | 
				
			||||
const props = defineProps({ | 
				
			||||
  values: { | 
				
			||||
    type: Object, | 
				
			||||
    required: true, | 
				
			||||
  }, | 
				
			||||
  errors: { | 
				
			||||
    type: Object, | 
				
			||||
    default: () => {}, | 
				
			||||
  }, | 
				
			||||
  setup() { | 
				
			||||
    const store = useStore(); | 
				
			||||
    const linksType = ref('users'); | 
				
			||||
    const isCurrentTeacher = computed(() => store.getters['security/isCurrentTeacher']); | 
				
			||||
    const isAdmin = computed(() => store.getters['security/isAdmin']); | 
				
			||||
 | 
				
			||||
    if (!isAdmin.value) { | 
				
			||||
      if (isCurrentTeacher.value) { | 
				
			||||
        linksType.value = 'course_students'; | 
				
			||||
      } else { | 
				
			||||
        linksType.value = 'user_rel_users'; | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return { | 
				
			||||
      v$: useVuelidate(), | 
				
			||||
      linksType | 
				
			||||
    } | 
				
			||||
  initialValues: { | 
				
			||||
    type: Object, | 
				
			||||
    default: () => {}, | 
				
			||||
  }, | 
				
			||||
  props: { | 
				
			||||
    values: { | 
				
			||||
      type: Object, | 
				
			||||
      required: true | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
const item = computed(() => props.initialValues || props.values); | 
				
			||||
 | 
				
			||||
const rules = computed(() => ({ | 
				
			||||
  item: { | 
				
			||||
    title: { | 
				
			||||
      required, | 
				
			||||
    }, | 
				
			||||
    errors: { | 
				
			||||
      type: Object, | 
				
			||||
      default: () => { | 
				
			||||
      } | 
				
			||||
    content: { | 
				
			||||
      required, | 
				
			||||
    }, | 
				
			||||
    initialValues: { | 
				
			||||
      type: Object, | 
				
			||||
      default: () => { | 
				
			||||
      } | 
				
			||||
    startDate: { | 
				
			||||
      required, | 
				
			||||
    }, | 
				
			||||
  }, | 
				
			||||
  data() { | 
				
			||||
    return { | 
				
			||||
      title: null, | 
				
			||||
      content: null, | 
				
			||||
      parentResourceNodeId: null, | 
				
			||||
      collective: null, | 
				
			||||
    }; | 
				
			||||
  }, | 
				
			||||
  computed: { | 
				
			||||
    item() { | 
				
			||||
      return this.initialValues || this.values; | 
				
			||||
    endDate: { | 
				
			||||
      required, | 
				
			||||
    }, | 
				
			||||
    titleErrors() { | 
				
			||||
      const errors = []; | 
				
			||||
      if (!this.v$.item.title.$dirty) return errors; | 
				
			||||
      has(this.violations, 'title') && errors.push(this.violations.title); | 
				
			||||
    collective: {} | 
				
			||||
  } | 
				
			||||
})); | 
				
			||||
 | 
				
			||||
      if (this.v$.item.title.required) { | 
				
			||||
        return this.$t('Field is required') | 
				
			||||
      } | 
				
			||||
const v$ = useVuelidate(rules, { item }); | 
				
			||||
 | 
				
			||||
      return errors; | 
				
			||||
    }, | 
				
			||||
// eslint-disable-next-line no-undef | 
				
			||||
defineExpose({ | 
				
			||||
  v$, | 
				
			||||
}) | 
				
			||||
 | 
				
			||||
    violations() { | 
				
			||||
      return this.errors || {}; | 
				
			||||
    } | 
				
			||||
  }, | 
				
			||||
  validations: { | 
				
			||||
    item: { | 
				
			||||
      title: { | 
				
			||||
        required, | 
				
			||||
      }, | 
				
			||||
      content: { | 
				
			||||
        required, | 
				
			||||
      }, | 
				
			||||
      startDate: { | 
				
			||||
        required, | 
				
			||||
      }, | 
				
			||||
      endDate: { | 
				
			||||
        required, | 
				
			||||
      }, | 
				
			||||
    } | 
				
			||||
const linksType = ref('users'); | 
				
			||||
const isCurrentTeacher = computed(() => store.getters['security/isCurrentTeacher']); | 
				
			||||
const isAdmin = computed(() => store.getters['security/isAdmin']); | 
				
			||||
 | 
				
			||||
if (!isAdmin.value) { | 
				
			||||
  if (isCurrentTeacher.value) { | 
				
			||||
    linksType.value = 'course_students'; | 
				
			||||
  } else { | 
				
			||||
    linksType.value = 'user_rel_users'; | 
				
			||||
  } | 
				
			||||
}; | 
				
			||||
} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
@ -1,33 +1,37 @@ | 
				
			||||
<template> | 
				
			||||
  <h5>{{ event.title }}</h5> | 
				
			||||
  {{ $filters.abbreviatedDatetime(event.startDate) }} | 
				
			||||
     | 
				
			||||
  <p v-if="event.endDate"> | 
				
			||||
    {{ $filters.abbreviatedDatetime(event.endDate) }} | 
				
			||||
  </p> | 
				
			||||
  <div class="flex flex-col gap-4"> | 
				
			||||
    <h5 v-text="event.title" /> | 
				
			||||
 | 
				
			||||
  <hr class="my-2"> | 
				
			||||
    <p v-text="useAbbreviatedDatetime(event.startDate)" /> | 
				
			||||
 | 
				
			||||
  <div class="mb-3" v-html="event.content" /> | 
				
			||||
    <p | 
				
			||||
      v-if="event.endDate" | 
				
			||||
      v-text="useAbbreviatedDatetime(event.endDate)" | 
				
			||||
    /> | 
				
			||||
 | 
				
			||||
  <h6 class="text-h5"> {{ $t('Invitees') }}</h6> | 
				
			||||
    <hr> | 
				
			||||
 | 
				
			||||
  <ShowLinks | 
				
			||||
    <div v-html="event.content" /> | 
				
			||||
 | 
				
			||||
    <h6 v-t="'Invitees'" /> | 
				
			||||
 | 
				
			||||
    <ShowLinks | 
				
			||||
      :item="event" | 
				
			||||
      :show-status="false" | 
				
			||||
  /> | 
				
			||||
    /> | 
				
			||||
  </div> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import ShowLinks from "../resource_links/ShowLinks"; | 
				
			||||
export default { | 
				
			||||
  name: "CCalendarEventInfo", | 
				
			||||
  components: {ShowLinks}, | 
				
			||||
  props: { | 
				
			||||
    event: { | 
				
			||||
      type: Object, | 
				
			||||
      required: true | 
				
			||||
    } | 
				
			||||
<script setup> | 
				
			||||
import { useAbbreviatedDatetime } from '../../composables/formatDate.js'; | 
				
			||||
 | 
				
			||||
import ShowLinks from '../resource_links/ShowLinks'; | 
				
			||||
 | 
				
			||||
// eslint-disable-next-line no-undef | 
				
			||||
defineProps({ | 
				
			||||
  event: { | 
				
			||||
    type: Object, | 
				
			||||
    required: true | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
}); | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
@ -1,9 +1,6 @@ | 
				
			||||
<template> | 
				
			||||
  <router-view></router-view> | 
				
			||||
  <router-view /> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
  export default { | 
				
			||||
      name: 'CCalendarEventLayout' | 
				
			||||
  } | 
				
			||||
<script setup> | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
@ -1,399 +1,401 @@ | 
				
			||||
<template> | 
				
			||||
  <div> | 
				
			||||
    <FullCalendar ref="cal" :options="calendarOptions"/> | 
				
			||||
    <FullCalendar | 
				
			||||
      ref="cal" | 
				
			||||
      :options="calendarOptions" | 
				
			||||
    /> | 
				
			||||
 | 
				
			||||
    <Loading :visible="isLoading"/> | 
				
			||||
    <Loading :visible="isLoading" /> | 
				
			||||
 | 
				
			||||
    <!-- Add form--> | 
				
			||||
    <q-dialog v-model="dialog" persistent> | 
				
			||||
      <q-card style="min-width: 800px"> | 
				
			||||
        <q-card-section> | 
				
			||||
          <div class="text-h6">{{ item['@id'] ? $t('Edit event') : $t('Add event') }}</div> | 
				
			||||
        </q-card-section> | 
				
			||||
 | 
				
			||||
        <q-card-section class="q-pt-none"> | 
				
			||||
          <CCalendarEventForm | 
				
			||||
              v-if="dialog" | 
				
			||||
              ref="createForm" | 
				
			||||
              :values="item" | 
				
			||||
          > | 
				
			||||
          </CCalendarEventForm> | 
				
			||||
        </q-card-section> | 
				
			||||
 | 
				
			||||
        <q-card-actions align="right" class="text-primary"> | 
				
			||||
          <q-btn v-close-popup flat :label="$t('Cancel')" /> | 
				
			||||
          <q-btn :label="item['@id'] ? $t('Edit') : $t('Add') " flat @click="onCreateEventForm"/> | 
				
			||||
        </q-card-actions> | 
				
			||||
      </q-card> | 
				
			||||
    </q-dialog> | 
				
			||||
    <Dialog | 
				
			||||
      v-model:visible="dialog" | 
				
			||||
      :header="item['@id'] ? t('Edit event') : t('Add event')" | 
				
			||||
      :modal="true" | 
				
			||||
    > | 
				
			||||
      <CCalendarEventForm | 
				
			||||
        v-if="dialog" | 
				
			||||
        ref="createForm" | 
				
			||||
        :values="item" | 
				
			||||
      /> | 
				
			||||
      <template #footer> | 
				
			||||
        <Button | 
				
			||||
          :label="t('Cancel')" | 
				
			||||
          class="p-button-outlined p-button-plain" | 
				
			||||
          icon="pi pi-times" | 
				
			||||
          @click="dialog = false" | 
				
			||||
        /> | 
				
			||||
        <Button | 
				
			||||
          :label="item['@id'] ? t('Edit') : t('Add')" | 
				
			||||
          class="p-button-secondary" | 
				
			||||
          @click="onCreateEventForm" | 
				
			||||
        /> | 
				
			||||
      </template> | 
				
			||||
    </Dialog> | 
				
			||||
 | 
				
			||||
    <!-- Show form--> | 
				
			||||
    <q-dialog v-model="dialogShow" persistent> | 
				
			||||
      <q-card style="min-width: 500px"> | 
				
			||||
        <q-card-section> | 
				
			||||
          <CCalendarEventInfo :event="item" /> | 
				
			||||
        </q-card-section> | 
				
			||||
        <q-card-actions align="right" class="text-primary"> | 
				
			||||
          <q-btn color="primary" flat no-caps :label="$t('Delete')" @click="confirmDelete"/> | 
				
			||||
          <q-btn v-if="isEventEditable" color="primary" flat no-caps :label="$t('Edit')" @click="dialog = true"/> | 
				
			||||
          <q-btn v-close-popup flat no-caps :label="$t('Close')" /> | 
				
			||||
        </q-card-actions> | 
				
			||||
      </q-card> | 
				
			||||
    </q-dialog> | 
				
			||||
    <Dialog | 
				
			||||
      v-model:visible="dialogShow" | 
				
			||||
      :header="t('Event')" | 
				
			||||
      :modal="true" | 
				
			||||
    > | 
				
			||||
      <CCalendarEventInfo :event="item" /> | 
				
			||||
 | 
				
			||||
      <template #footer> | 
				
			||||
        <Button | 
				
			||||
          :label="t('Cancel')" | 
				
			||||
          class="p-button-outlined p-button-plain" | 
				
			||||
          icon="pi pi-times" | 
				
			||||
          @click="dialogShow = false" | 
				
			||||
        /> | 
				
			||||
        <Button | 
				
			||||
          :label="t('Delete')" | 
				
			||||
          class="p-button-outlined p-button-danger" | 
				
			||||
          icon="pi pi-trash" | 
				
			||||
          @click="confirmDelete" | 
				
			||||
        /> | 
				
			||||
        <Button | 
				
			||||
          v-if="isEventEditable" | 
				
			||||
          :label="t('Edit')" | 
				
			||||
          class="p-button-secondary" | 
				
			||||
          @click="dialog = true" | 
				
			||||
        /> | 
				
			||||
      </template> | 
				
			||||
    </Dialog> | 
				
			||||
 | 
				
			||||
    <!-- Show form--> | 
				
			||||
    <q-dialog v-model="showSessionDialog"> | 
				
			||||
      <q-card> | 
				
			||||
        <q-card-section class="row items-center q-pb-none" icon="mdi-book-open"> | 
				
			||||
          <div class="text-h6">{{ sessionAsEvent.title }}</div> | 
				
			||||
          <q-space/> | 
				
			||||
          <q-btn v-close-popup dense flat icon="close" round/> | 
				
			||||
        </q-card-section> | 
				
			||||
 | 
				
			||||
        <q-card-section> | 
				
			||||
          <div v-if="sessionAsEvent.start"> | 
				
			||||
            <q-icon name="event"/> | 
				
			||||
            {{ $t('From:') }} | 
				
			||||
            {{ $filters.abbreviatedDatetime(sessionAsEvent.start) }} | 
				
			||||
          </div> | 
				
			||||
 | 
				
			||||
          <div v-if="sessionAsEvent.end"> | 
				
			||||
            <q-icon name="event"/> | 
				
			||||
            {{ $t('Until:') }} | 
				
			||||
            {{ $filters.abbreviatedDatetime(sessionAsEvent.end) }} | 
				
			||||
          </div> | 
				
			||||
        </q-card-section> | 
				
			||||
        <q-card-actions align="right" class="text-primary"> | 
				
			||||
          <q-btn color="primary" flat :label="$t('Go to session')" type="a" | 
				
			||||
                 :href="`/sessions/${sessionAsEvent.id}/about`" /> | 
				
			||||
        </q-card-actions> | 
				
			||||
      </q-card> | 
				
			||||
    </q-dialog> | 
				
			||||
    <Dialog | 
				
			||||
      v-model:visible="sessionState.showSessionDialog" | 
				
			||||
      :header="t('Session')" | 
				
			||||
      :modal="true" | 
				
			||||
    > | 
				
			||||
      <div class="flex flex-col gap-4"> | 
				
			||||
        <h5>{{ sessionState.sessionAsEvent.title }}</h5> | 
				
			||||
        <p | 
				
			||||
          v-if="sessionState.sessionAsEvent.start" | 
				
			||||
          v-t="{ path: 'From: {date}', args: { 'date': useAbbreviatedDatetime(sessionState.sessionAsEvent.start) } }" | 
				
			||||
        /> | 
				
			||||
        <p | 
				
			||||
          v-if="sessionState.sessionAsEvent.end" | 
				
			||||
          v-t="{ path: 'Until: {date}', args: { 'date': useAbbreviatedDatetime(sessionState.sessionAsEvent.end) } }" | 
				
			||||
        /> | 
				
			||||
      </div> | 
				
			||||
 | 
				
			||||
      <template #footer> | 
				
			||||
        <a | 
				
			||||
          v-t="'Go to session'" | 
				
			||||
          :href="`/sessions/${sessionState.sessionAsEvent.id}/about`" | 
				
			||||
          class="btn btn--secondary" | 
				
			||||
        /> | 
				
			||||
      </template> | 
				
			||||
    </Dialog> | 
				
			||||
  </div> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import {mapActions, mapGetters, useStore} from 'vuex'; | 
				
			||||
import {mapFields} from 'vuex-map-fields'; | 
				
			||||
import Loading from '../../components/Loading.vue'; | 
				
			||||
import Toolbar from '../../components/Toolbar.vue'; | 
				
			||||
import {computed, reactive, ref, toRefs, onMounted} from "vue"; | 
				
			||||
<script setup> | 
				
			||||
import { computed, inject, reactive, ref, watch } from 'vue'; | 
				
			||||
import { useStore } from 'vuex'; | 
				
			||||
import { useRoute } from 'vue-router'; | 
				
			||||
import { useI18n } from 'vue-i18n'; | 
				
			||||
import axios from 'axios'; | 
				
			||||
import { useConfirm } from 'primevue/useconfirm'; | 
				
			||||
import { useAbbreviatedDatetime } from '../../composables/formatDate.js'; | 
				
			||||
 | 
				
			||||
//import '@fullcalendar/core/vdom' // solve problem with Vite | 
				
			||||
import Loading from '../../components/Loading.vue'; | 
				
			||||
import FullCalendar from '@fullcalendar/vue3'; | 
				
			||||
import dayGridPlugin from '@fullcalendar/daygrid'; | 
				
			||||
import interactionPlugin from '@fullcalendar/interaction'; | 
				
			||||
import timeGridPlugin from '@fullcalendar/timegrid'; | 
				
			||||
import axios from "axios"; | 
				
			||||
import CCalendarEventForm from "../../components/ccalendarevent/Form.vue"; | 
				
			||||
import CreateMixin from "../../mixins/CreateMixin"; | 
				
			||||
import {useRoute, useRouter} from "vue-router"; | 
				
			||||
import {useQuasar} from 'quasar'; | 
				
			||||
import CCalendarEventInfo from "../../components/ccalendarevent/Info"; | 
				
			||||
import {ENTRYPOINT} from "../../config/entrypoint"; | 
				
			||||
import {useI18n} from "vue-i18n"; | 
				
			||||
import CCalendarEventForm from '../../components/ccalendarevent/Form.vue'; | 
				
			||||
import CCalendarEventInfo from '../../components/ccalendarevent/Info'; | 
				
			||||
import { ENTRYPOINT } from '../../config/entrypoint'; | 
				
			||||
import allLocales from '@fullcalendar/core/locales-all'; | 
				
			||||
import toInteger from "lodash/toInteger"; | 
				
			||||
const servicePrefix = 'CCalendarEvent'; | 
				
			||||
 | 
				
			||||
export default { | 
				
			||||
  name: 'CCalendarEventList', | 
				
			||||
  components: { | 
				
			||||
    CCalendarEventInfo, | 
				
			||||
    CCalendarEventForm, | 
				
			||||
    Loading, | 
				
			||||
    Toolbar, | 
				
			||||
    FullCalendar | 
				
			||||
import toInteger from 'lodash/toInteger'; | 
				
			||||
import Dialog from 'primevue/dialog'; | 
				
			||||
import Button from 'primevue/button'; | 
				
			||||
 | 
				
			||||
const store = useStore(); | 
				
			||||
const route = useRoute(); | 
				
			||||
const confirm = useConfirm(); | 
				
			||||
 | 
				
			||||
const item = ref({}); | 
				
			||||
const dialog = ref(false); | 
				
			||||
const dialogShow = ref(false); | 
				
			||||
const isEventEditable = ref(false); | 
				
			||||
 | 
				
			||||
const currentUser = computed(() => store.getters['security/getUser']); | 
				
			||||
const { t, locale } = useI18n(); | 
				
			||||
 | 
				
			||||
let currentEvent = null; | 
				
			||||
 | 
				
			||||
const sessionState = reactive({ | 
				
			||||
  sessionAsEvent: { | 
				
			||||
    id: '', | 
				
			||||
    title: '', | 
				
			||||
    start: '', | 
				
			||||
    end: '', | 
				
			||||
    extendedProps: {}, | 
				
			||||
  }, | 
				
			||||
 | 
				
			||||
  mixins: [CreateMixin], | 
				
			||||
  //mixins: [ShowMixin], | 
				
			||||
  setup() { | 
				
			||||
    const $q = useQuasar(); | 
				
			||||
 | 
				
			||||
    const calendarOptions = ref([]); | 
				
			||||
    const item = ref({}); | 
				
			||||
    const dialog = ref(false); | 
				
			||||
    const dialogShow = ref(false); | 
				
			||||
    const isEventEditable = ref(false); | 
				
			||||
 | 
				
			||||
    const store = useStore(); | 
				
			||||
    const route = useRoute(); | 
				
			||||
    const currentUser = computed(() => store.getters['security/getUser']); | 
				
			||||
    const { t, locale } = useI18n(); | 
				
			||||
 | 
				
			||||
    let currentEvent = null; | 
				
			||||
 | 
				
			||||
    const sessionState = reactive({ | 
				
			||||
      sessionAsEvent: { | 
				
			||||
        id: '', | 
				
			||||
        title: '', | 
				
			||||
        start: '', | 
				
			||||
        end: '', | 
				
			||||
        extendedProps: {}, | 
				
			||||
      }, | 
				
			||||
      showSessionDialog: false | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    const cid = toInteger(route.query.cid); | 
				
			||||
    const sid = toInteger(route.query.sid); | 
				
			||||
    const gid = toInteger(route.query.gid); | 
				
			||||
 | 
				
			||||
    if (cid) { | 
				
			||||
      let courseIri = '/api/courses/' + cid; | 
				
			||||
      store.dispatch('course/findCourse', { id: courseIri }); | 
				
			||||
  showSessionDialog: false | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
const cid = toInteger(route.query.cid); | 
				
			||||
const sid = toInteger(route.query.sid); | 
				
			||||
const gid = toInteger(route.query.gid); | 
				
			||||
 | 
				
			||||
if (cid) { | 
				
			||||
  let courseIri = '/api/courses/' + cid; | 
				
			||||
  store.dispatch('course/findCourse', { id: courseIri }); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
async function getCalendarEvents ({ startStr, endStr }) { | 
				
			||||
  const calendarEvents = await axios.get( | 
				
			||||
    ENTRYPOINT + 'c_calendar_events', | 
				
			||||
    { | 
				
			||||
      params: { | 
				
			||||
        'startDate': startStr, | 
				
			||||
        'endDate': endStr, | 
				
			||||
        //          'startDate[after]': startStr, | 
				
			||||
        //          'startDate[before]': startStr, | 
				
			||||
        //'startDate[between]': startStr+'..'+endStr, | 
				
			||||
        'cid': cid, | 
				
			||||
        'sid': sid, | 
				
			||||
        'gid': gid, | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    function onCreated(item) { | 
				
			||||
      //showNotification(t('Updated')); | 
				
			||||
      reFetch(); | 
				
			||||
  ); | 
				
			||||
 | 
				
			||||
  return calendarEvents.data['hydra:member'].map(event => ({ | 
				
			||||
      ...event, | 
				
			||||
      start: event.startDate, | 
				
			||||
      end: event.endDate, | 
				
			||||
    }) | 
				
			||||
  ); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
async function getSessions ({ startStr, endStr }) { | 
				
			||||
  if ('true' !== window.config['agenda.personal_calendar_show_sessions_occupation']) { | 
				
			||||
    return []; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  const sessions = await axios.get( | 
				
			||||
    ENTRYPOINT + `session_rel_users`, | 
				
			||||
    { | 
				
			||||
      params: { | 
				
			||||
        'user': currentUser.value['@id'], | 
				
			||||
        'displayStartDate[after]': startStr, | 
				
			||||
        'displayEndDate[before]': endStr, | 
				
			||||
        'relationType': 3 | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
  ); | 
				
			||||
 | 
				
			||||
  return sessions.data['hydra:member'].map(sessionRelUser => ({ | 
				
			||||
      ...sessionRelUser.session, | 
				
			||||
      title: sessionRelUser.session.name, | 
				
			||||
      start: sessionRelUser.session.displayStartDate, | 
				
			||||
      end: sessionRelUser.session.displayEndDate, | 
				
			||||
    }) | 
				
			||||
  ); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// @todo fix locale connection between fullcalendar + chamilo | 
				
			||||
 | 
				
			||||
if ('en_US' === locale.value) { | 
				
			||||
  locale.value = 'en'; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
if ('fr_FR' === locale.value) { | 
				
			||||
  locale.value = 'fr'; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
if ('pl_PL' === locale.value) { | 
				
			||||
  locale.value = 'pl'; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
const calendarOptions = ref({ | 
				
			||||
  plugins: [ | 
				
			||||
    dayGridPlugin, | 
				
			||||
    timeGridPlugin, | 
				
			||||
    interactionPlugin | 
				
			||||
  ], | 
				
			||||
  locales: allLocales, | 
				
			||||
  locale: locale.value, | 
				
			||||
  customButtons: { | 
				
			||||
    addEvent: { | 
				
			||||
      text: t('Add event'), | 
				
			||||
      click: function () { | 
				
			||||
        item.value = {}; | 
				
			||||
        item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
        item.value['collective'] = false; | 
				
			||||
 | 
				
			||||
    async function getCalendarEvents({startStr, endStr})  { | 
				
			||||
      const calendarEvents = await axios.get(ENTRYPOINT + 'c_calendar_events', { | 
				
			||||
        params: { | 
				
			||||
          'startDate': startStr, | 
				
			||||
          'endDate': endStr, | 
				
			||||
//          'startDate[after]': startStr, | 
				
			||||
//          'startDate[before]': startStr, | 
				
			||||
          //'startDate[between]': startStr+'..'+endStr, | 
				
			||||
          'cid': cid, | 
				
			||||
          'sid': sid, | 
				
			||||
          'gid': gid, | 
				
			||||
        } | 
				
			||||
      }); | 
				
			||||
 | 
				
			||||
      return calendarEvents.data['hydra:member']; | 
				
			||||
        dialog.value = true; | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
  }, | 
				
			||||
  headerToolbar: { | 
				
			||||
    left: 'prev,next today,addEvent', | 
				
			||||
    center: 'title', | 
				
			||||
    right: 'dayGridMonth,timeGridWeek,timeGridDay' | 
				
			||||
  }, | 
				
			||||
  nowIndicator: true, | 
				
			||||
  initialView: 'dayGridMonth', | 
				
			||||
  startParam: 'startDate[after]', | 
				
			||||
  endParam: 'endDate[before]', | 
				
			||||
  selectable: true, | 
				
			||||
  eventClick (EventClickArg) { | 
				
			||||
    let event = EventClickArg.event.toPlainObject(); | 
				
			||||
 | 
				
			||||
    if (event.extendedProps['@type'] && event.extendedProps['@type'] === 'Session') { | 
				
			||||
      sessionState.sessionAsEvent = event; | 
				
			||||
      sessionState.showSessionDialog = true; | 
				
			||||
      EventClickArg.jsEvent.preventDefault(); | 
				
			||||
 | 
				
			||||
      return; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    async function getSessions({startStr, endStr}) { | 
				
			||||
      if ('true' !== window.config['agenda.personal_calendar_show_sessions_occupation']) { | 
				
			||||
        return []; | 
				
			||||
      } | 
				
			||||
    currentEvent = event; | 
				
			||||
 | 
				
			||||
      const sessions = await axios.get(ENTRYPOINT + `users/${currentUser.value['id']}/sessions_rel_users`, { | 
				
			||||
        params: { | 
				
			||||
          'displayStartDate[after]': startStr, | 
				
			||||
          'displayEndDate[before]': endStr | 
				
			||||
        } | 
				
			||||
      }); | 
				
			||||
    item.value = { ...event.extendedProps }; | 
				
			||||
 | 
				
			||||
      return sessions.data['hydra:member']; | 
				
			||||
    } | 
				
			||||
    item.value['title'] = event.title; | 
				
			||||
    item.value['startDate'] = event.start; | 
				
			||||
    item.value['endDate'] = event.end; | 
				
			||||
    item.value['parentResourceNodeId'] = event.extendedProps.resourceNode.creator.id; | 
				
			||||
 | 
				
			||||
    // @todo fix locale connection between fullcalendar + chamilo | 
				
			||||
    isEventEditable.value = item.value['parentResourceNodeId'] === currentUser.value['id']; | 
				
			||||
 | 
				
			||||
    if ('en_US' === locale.value) { | 
				
			||||
      locale.value = 'en'; | 
				
			||||
    } | 
				
			||||
    if (!isEventEditable.value | 
				
			||||
      && event.extendedProps.collective | 
				
			||||
      && event.extendedProps.resourceLinkListFromEntity | 
				
			||||
    ) { | 
				
			||||
      const resourceLink = event.extendedProps.resourceLinkListFromEntity.find(linkEntity => linkEntity.user.id === currentUser.value.id); | 
				
			||||
 | 
				
			||||
    if ('fr_FR' === locale.value) { | 
				
			||||
      locale.value = 'fr'; | 
				
			||||
      if (resourceLink) { | 
				
			||||
        isEventEditable.value = true; | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if ('pl_PL' === locale.value) { | 
				
			||||
      locale.value = 'pl'; | 
				
			||||
    } | 
				
			||||
    dialogShow.value = true; | 
				
			||||
  }, | 
				
			||||
  dateClick (info) { | 
				
			||||
    item.value = {}; | 
				
			||||
    item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
    item.value['collective'] = false; | 
				
			||||
    item.value['allDay'] = info.allDay; | 
				
			||||
    item.value['startDate'] = info.startStr; | 
				
			||||
    item.value['endDate'] = info.endStr; | 
				
			||||
 | 
				
			||||
    dialog.value = true; | 
				
			||||
  }, | 
				
			||||
  select (info) { | 
				
			||||
    item.value = {}; | 
				
			||||
    item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
    item.value['collective'] = false; | 
				
			||||
    item.value['allDay'] = info.allDay; | 
				
			||||
    item.value['startDate'] = info.startStr; | 
				
			||||
    item.value['endDate'] = info.endStr; | 
				
			||||
 | 
				
			||||
    dialog.value = true; | 
				
			||||
  }, | 
				
			||||
  events (info, successCallback) { | 
				
			||||
    Promise | 
				
			||||
      .all([getCalendarEvents(info), getSessions(info)]) | 
				
			||||
      .then(values => { | 
				
			||||
        const events = values[0].concat(values[1]); | 
				
			||||
 | 
				
			||||
    calendarOptions.value = { | 
				
			||||
      plugins: [ | 
				
			||||
        dayGridPlugin, | 
				
			||||
        timeGridPlugin, | 
				
			||||
        interactionPlugin | 
				
			||||
      ], | 
				
			||||
      locales: allLocales, | 
				
			||||
      locale: locale.value, | 
				
			||||
      customButtons: { | 
				
			||||
        addEvent: { | 
				
			||||
          text: t('Add event'), | 
				
			||||
          click: function () { | 
				
			||||
            item.value = {}; | 
				
			||||
            item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
            item.value['collective'] = false; | 
				
			||||
 | 
				
			||||
            dialog.value = true; | 
				
			||||
          } | 
				
			||||
        } | 
				
			||||
      }, | 
				
			||||
      headerToolbar: { | 
				
			||||
        left: 'prev,next today,addEvent', | 
				
			||||
        center: 'title', | 
				
			||||
        right: 'dayGridMonth,timeGridWeek,timeGridDay' | 
				
			||||
      }, | 
				
			||||
      nowIndicator: true, | 
				
			||||
      initialView: 'dayGridMonth', | 
				
			||||
      startParam: "startDate[after]", | 
				
			||||
      endParam: 'endDate[before]', | 
				
			||||
      selectable: true, | 
				
			||||
      eventClick(EventClickArg) { | 
				
			||||
        let event = EventClickArg.event.toPlainObject(); | 
				
			||||
 | 
				
			||||
        if (event.extendedProps['@type'] && event.extendedProps['@type'] === 'Session') { | 
				
			||||
          sessionState.sessionAsEvent = event; | 
				
			||||
          sessionState.showSessionDialog = true; | 
				
			||||
          EventClickArg.jsEvent.preventDefault(); | 
				
			||||
 | 
				
			||||
          return; | 
				
			||||
        successCallback(events); | 
				
			||||
      }); | 
				
			||||
  }, | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
const cal = ref(null); | 
				
			||||
 | 
				
			||||
function reFetch () { | 
				
			||||
  cal.value.getApi().refetchEvents(); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
function confirmDelete () { | 
				
			||||
  confirm.require({ | 
				
			||||
    message: t('Are you sure you want to delete this event?'), | 
				
			||||
    header: t('Delete'), | 
				
			||||
    icon: 'pi pi-exclamation-triangle', | 
				
			||||
    acceptClass: 'p-button-danger', | 
				
			||||
    rejectClass: 'p-button-plain p-button-outlined', | 
				
			||||
    accept () { | 
				
			||||
      if (item.value['parentResourceNodeId'] === currentUser.value['id']) { | 
				
			||||
        store.dispatch('ccalendarevent/del', item.value); | 
				
			||||
 | 
				
			||||
        dialogShow.value = false; | 
				
			||||
        dialog.value = false; | 
				
			||||
        reFetch(); | 
				
			||||
      } else { | 
				
			||||
        let filteredLinks = item.value['resourceLinkListFromEntity'] | 
				
			||||
          .filter(resourceLinkFromEntity => resourceLinkFromEntity['user']['id'] === currentUser.value['id']); | 
				
			||||
 | 
				
			||||
        if (filteredLinks.length > 0) { | 
				
			||||
          store.dispatch('resourcelink/del', { '@id': `/api/resource_links/${filteredLinks[0]['id']}` }); | 
				
			||||
 | 
				
			||||
          currentEvent.remove(); | 
				
			||||
          dialogShow.value = false; | 
				
			||||
          dialog.value = false; | 
				
			||||
          reFetch(); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    }, | 
				
			||||
  }); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
        currentEvent = event; | 
				
			||||
 | 
				
			||||
        item.value = {...event.extendedProps}; | 
				
			||||
 | 
				
			||||
        item.value['title'] = event.title; | 
				
			||||
        item.value['startDate'] = event.start; | 
				
			||||
        item.value['endDate'] = event.end; | 
				
			||||
        item.value['parentResourceNodeId'] = event.extendedProps.resourceNode.creator.id; | 
				
			||||
const isLoading = computed(() => store.getters['ccalendarevent/isLoading']); | 
				
			||||
 | 
				
			||||
        isEventEditable.value = item.value['parentResourceNodeId'] === currentUser.value['id']; | 
				
			||||
const createForm = ref(null); | 
				
			||||
 | 
				
			||||
        if (!isEventEditable.value | 
				
			||||
            && event.extendedProps.collective | 
				
			||||
            && event.extendedProps.resourceLinkListFromEntity | 
				
			||||
        ) { | 
				
			||||
          const resourceLink = event.extendedProps.resourceLinkListFromEntity.find(linkEntity => linkEntity.user.id === currentUser.value.id); | 
				
			||||
function onCreateEventForm () { | 
				
			||||
  if (createForm.value.v$.$invalid) { | 
				
			||||
    return; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
          if (resourceLink) { | 
				
			||||
            isEventEditable.value = true; | 
				
			||||
          } | 
				
			||||
        } | 
				
			||||
  let itemModel = createForm.value.v$.item.$model; | 
				
			||||
 | 
				
			||||
        dialogShow.value = true; | 
				
			||||
      }, | 
				
			||||
      dateClick(info) { | 
				
			||||
        item.value = {}; | 
				
			||||
        item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
        item.value['collective'] = false; | 
				
			||||
        item.value['allDay'] = info.allDay; | 
				
			||||
        item.value['startDate'] = info.startStr; | 
				
			||||
        item.value['endDate'] = info.endStr; | 
				
			||||
  if (itemModel['@id']) { | 
				
			||||
    store.dispatch('ccalendarevent/update', itemModel); | 
				
			||||
  } else { | 
				
			||||
    store.dispatch('ccalendarevent/create', itemModel); | 
				
			||||
 | 
				
			||||
        dialog.value = true; | 
				
			||||
      }, | 
				
			||||
      select(info) { | 
				
			||||
        item.value = {}; | 
				
			||||
        item.value['parentResourceNodeId'] = currentUser.value.resourceNode['id']; | 
				
			||||
        item.value['collective'] = false; | 
				
			||||
        item.value['allDay'] = info.allDay; | 
				
			||||
        item.value['startDate'] = info.startStr; | 
				
			||||
        item.value['endDate'] = info.endStr; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
        dialog.value = true; | 
				
			||||
      }, | 
				
			||||
      events(info, successCallback, failureCallback) { | 
				
			||||
        Promise | 
				
			||||
            .all([getCalendarEvents(info), getSessions(info)]) | 
				
			||||
            .then(values => { | 
				
			||||
              const calendarEvents = Array.prototype.slice.call(values[0]) | 
				
			||||
                  .map(event => ({ | 
				
			||||
                    ...event, | 
				
			||||
                    start: event.startDate, | 
				
			||||
                    end: event.endDate, | 
				
			||||
                  })); | 
				
			||||
 | 
				
			||||
              const sessionEvents = values[1].map(sessionRelUser => ( | 
				
			||||
                  { | 
				
			||||
                    ...sessionRelUser.session, | 
				
			||||
                    title: sessionRelUser.session.name, | 
				
			||||
                    start: sessionRelUser.session.displayStartDate, | 
				
			||||
                    end: sessionRelUser.session.displayEndDate, | 
				
			||||
                  } | 
				
			||||
              )); | 
				
			||||
 | 
				
			||||
              const events = [...calendarEvents, ...sessionEvents]; | 
				
			||||
 | 
				
			||||
              successCallback(events); | 
				
			||||
            }); | 
				
			||||
      }, | 
				
			||||
    } | 
				
			||||
  dialog.value = false; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
    const cal = ref(null); | 
				
			||||
    function reFetch() { | 
				
			||||
      const calendarApi = cal.value.getApi(); | 
				
			||||
      calendarApi.refetchEvents(); | 
				
			||||
    } | 
				
			||||
const flashMessageList = inject('flashMessageList'); | 
				
			||||
 | 
				
			||||
    function confirmDelete() { | 
				
			||||
      $q.dialog({ | 
				
			||||
          title: 'Delete', | 
				
			||||
          message: 'Are you sure you want to delete this event?', | 
				
			||||
          persistent: true, | 
				
			||||
          cancel: true | 
				
			||||
        }) | 
				
			||||
        .onOk(function () { | 
				
			||||
          if (item.value['parentResourceNodeId'] === currentUser.value['id']) { | 
				
			||||
            store.dispatch('ccalendarevent/del', item.value); | 
				
			||||
 | 
				
			||||
            dialogShow.value = false; | 
				
			||||
            dialog.value = false; | 
				
			||||
            reFetch(); | 
				
			||||
          } else { | 
				
			||||
            let filteredLinks = item.value['resourceLinkListFromEntity'] | 
				
			||||
                .filter(resourceLinkFromEntity => resourceLinkFromEntity['user']['id'] === currentUser.value['id']); | 
				
			||||
 | 
				
			||||
            if (filteredLinks.length > 0) { | 
				
			||||
              store.dispatch('resourcelink/del', {'@id': `/api/resource_links/${filteredLinks[0]['id']}`}) | 
				
			||||
 | 
				
			||||
              currentEvent.remove(); | 
				
			||||
              dialogShow.value = false; | 
				
			||||
              dialog.value = false; | 
				
			||||
              reFetch(); | 
				
			||||
            } | 
				
			||||
          } | 
				
			||||
        }); | 
				
			||||
    } | 
				
			||||
watch( | 
				
			||||
  () => store.state.ccalendarevent.created, | 
				
			||||
  (created) => { | 
				
			||||
    flashMessageList.value.push({ | 
				
			||||
      severity: 'success', | 
				
			||||
      detail: t( | 
				
			||||
        '{resource} created', | 
				
			||||
        { 'resource': created.resourceNode.title } | 
				
			||||
      ), | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
    return { | 
				
			||||
      cal, | 
				
			||||
      onCreated, | 
				
			||||
      calendarOptions, | 
				
			||||
      dialog, | 
				
			||||
      item, | 
				
			||||
      dialogShow, | 
				
			||||
      reFetch, | 
				
			||||
      isEventEditable, | 
				
			||||
      confirmDelete, | 
				
			||||
      ...toRefs(sessionState), | 
				
			||||
    }; | 
				
			||||
  }, | 
				
			||||
  computed: { | 
				
			||||
    ...mapFields('ccalendarevent', { | 
				
			||||
      isLoading: 'isLoading', | 
				
			||||
      created: 'created', | 
				
			||||
      violations: 'violations', | 
				
			||||
    }), | 
				
			||||
    ...mapGetters('ccalendarevent', ['find']), | 
				
			||||
    ...mapGetters({ | 
				
			||||
      'isAuthenticated': 'security/isAuthenticated', | 
				
			||||
      'isAdmin': 'security/isAdmin', | 
				
			||||
      'isCurrentTeacher': 'security/isCurrentTeacher', | 
				
			||||
    }), | 
				
			||||
  }, | 
				
			||||
  methods: { | 
				
			||||
    onCreateEventForm() { | 
				
			||||
      const createForm = this.$refs.createForm; | 
				
			||||
      createForm.v$.$touch(); | 
				
			||||
      if (!createForm.v$.$invalid) { | 
				
			||||
        let itemModel = createForm.v$.item.$model; | 
				
			||||
 | 
				
			||||
        if (itemModel['@id']) { | 
				
			||||
          this.updateItem(itemModel); | 
				
			||||
        } else { | 
				
			||||
          this.create(itemModel); | 
				
			||||
        } | 
				
			||||
    reFetch(); | 
				
			||||
  } | 
				
			||||
); | 
				
			||||
 | 
				
			||||
watch( | 
				
			||||
  () => store.state.ccalendarevent.updated, | 
				
			||||
  (updated) => { | 
				
			||||
    flashMessageList.value.push({ | 
				
			||||
      severity: 'success', | 
				
			||||
      detail: t( | 
				
			||||
        '{resource} updated', | 
				
			||||
        { 'resource': updated.resourceNode.title } | 
				
			||||
      ), | 
				
			||||
    }); | 
				
			||||
 | 
				
			||||
        this.reFetch(); | 
				
			||||
        this.dialog = false; | 
				
			||||
      } | 
				
			||||
    }, | 
				
			||||
    ...mapActions('ccalendarevent', { | 
				
			||||
      create: 'create', | 
				
			||||
      deleteItem: 'del', | 
				
			||||
      reset: 'resetShow', | 
				
			||||
      retrieve: 'loadWithQuery', | 
				
			||||
      updateItem: 'update' | 
				
			||||
    }), | 
				
			||||
  }, | 
				
			||||
  servicePrefix | 
				
			||||
}; | 
				
			||||
    reFetch(); | 
				
			||||
  } | 
				
			||||
); | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue