dashboard.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <template>
  2. <v-container fluid class="inner-container">
  3. <v-row>
  4. <!-- Bloc événements -->
  5. <v-col cols="12" md="7">
  6. <v-card>
  7. <v-tabs v-model="tab" class="tabs-title">
  8. <v-tab value="future">{{$t('futur_event')}}</v-tab>
  9. <v-tab value="past">{{$t('past_event')}}</v-tab>
  10. </v-tabs>
  11. <v-btn color="primary" to="events/new" class="ml-5 mt-5">{{$t('add_event')}}</v-btn>
  12. <v-tabs-window v-model="tab">
  13. <v-tabs-window-item value="future">
  14. <UiLoadingPanel v-if="statusUpcomingEvents == FETCHING_STATUS.PENDING" />
  15. <UiEventList
  16. v-if="statusUpcomingEvents == FETCHING_STATUS.SUCCESS && upcomingEvents?.items"
  17. :events="upcomingEvents.items"
  18. :pagination="upcomingEvents.pagination"
  19. @load="loadUpcomingEvents"
  20. @edit="editEvent"
  21. />
  22. <span v-if="upcomingEvents.items.length == 0" class="no_event">
  23. {{$t('no_future_event')}}
  24. </span>
  25. </v-tabs-window-item>
  26. <v-tabs-window-item value="past">
  27. <UiLoadingPanel v-if="statusPastEvents == FETCHING_STATUS.PENDING" />
  28. <UiEventList
  29. v-if="statusPastEvents == FETCHING_STATUS.SUCCESS && pastEvents?.items"
  30. :events="pastEvents.items"
  31. :pagination="pastEvents.pagination"
  32. @load="loadPastEvents"
  33. @edit="editEvent"
  34. />
  35. <span v-if="pastEvents.items.length == 0" class="no_event">
  36. {{$t('no_past_event')}}
  37. </span>
  38. </v-tabs-window-item>
  39. </v-tabs-window>
  40. </v-card>
  41. </v-col>
  42. <!-- Bloc structure -->
  43. <v-col cols="12" md="5">
  44. <v-card v-if="statusOrganization == FETCHING_STATUS.SUCCESS" class="pa-5">
  45. <v-card-title class="text-h6" >
  46. <v-icon icon="fa fa-hotel" class="text-button icon-hotel" />
  47. <span class="organization_title">{{$t('my_organization')}}</span>
  48. </v-card-title>
  49. <v-card-text>
  50. <div><strong>{{$t('name')}} :</strong> {{ organization?.name }}</div>
  51. <div><strong>{{$t('email')}} :</strong> {{ organization?.email }}</div>
  52. </v-card-text>
  53. </v-card>
  54. <v-btn block class="mb-2 btn btn_edit_orga" to="organization">
  55. <i class="fa fa-pen mr-2" />{{$t('edit_organization')}}
  56. </v-btn>
  57. <v-btn block class="text-black btn btn_trial" @click="startTrial">
  58. <span><v-icon icon="fa fa-ticket" /> {{$t('try_premium_light')}}<br /> {{$t('30_days_free')}}</span>
  59. </v-btn>
  60. </v-col>
  61. </v-row>
  62. </v-container>
  63. <LayoutDialogTrialAlreadyDid
  64. :show="showDialogTrialAlReadyDid"
  65. @close-dialog="showDialogTrialAlReadyDid = false"
  66. />
  67. </template>
  68. <script setup lang="ts">
  69. import Query from "~/services/data/Query";
  70. definePageMeta({
  71. name: 'freemium_dashboard_page',
  72. })
  73. import {type Ref, ref} from 'vue'
  74. import {useEntityFetch} from "~/composables/data/useEntityFetch";
  75. import Organization from "~/models/Freemium/Organization";
  76. import Event from "~/models/Freemium/Event";
  77. import type {AsyncData} from "#app";
  78. import OrderBy from "~/services/data/Filters/OrderBy";
  79. import {FETCHING_STATUS, ORDER_BY_DIRECTION, TIME_STRATEGY} from "~/types/enum/data";
  80. import PageFilter from "~/services/data/Filters/PageFilter";
  81. import TimeFilter from "~/services/data/Filters/TimeFilter";
  82. import Country from "~/models/Core/Country";
  83. import DateUtils from "~/services/utils/dateUtils";
  84. import UrlUtils from "~/services/utils/urlUtils";
  85. import {useApiLegacyRequestService} from "~/composables/data/useApiLegacyRequestService";
  86. import {useAdminUrl} from "~/composables/utils/useAdminUrl";
  87. //Ref Définition
  88. const runtimeConfig = useRuntimeConfig()
  89. const { fetch, fetchCollection } = useEntityFetch()
  90. const { apiRequestService } = useApiLegacyRequestService()
  91. const {makeAdminUrl} = useAdminUrl()
  92. const tab = ref(null)
  93. const upcomingPage = ref(1)
  94. const pastPage = ref(1)
  95. const showDialogTrialAlReadyDid: Ref<boolean> = ref(false)
  96. //Fetch
  97. const { data: organization, status:statusOrganization } = fetch(Organization)
  98. const { data: upcomingEvents, status: statusUpcomingEvents, refresh: refreshUpcomingEvents } = fetchEvents()
  99. const { data: pastEvents, status: statusPastEvents, refresh: refreshPastEvents } = fetchEvents(true)
  100. /**
  101. * Charge une page des événements à venir
  102. * @param pageNumber
  103. */
  104. function loadUpcomingEvents(pageNumber: number) {
  105. upcomingPage.value = pageNumber
  106. refreshPastEvents()
  107. }
  108. /**
  109. * Cahrge une page des événements passées
  110. * @param pageNumber
  111. */
  112. function loadPastEvents(pageNumber: number) {
  113. pastPage.value = pageNumber
  114. refreshPastEvents()
  115. }
  116. /**
  117. * Redirige vers la page d'édition d'un événement
  118. * @param eventId
  119. */
  120. function editEvent(eventId: number) {
  121. navigateTo(UrlUtils.join('events', eventId))
  122. }
  123. /**
  124. * Récupère la liste des événements
  125. * @param past
  126. */
  127. function fetchEvents(past:boolean = false){
  128. const today = computed(() => DateUtils.formatIsoShortDate(new Date()))
  129. const query =
  130. new Query(
  131. new OrderBy('datetimeStart', past ? ORDER_BY_DIRECTION.DESC : ORDER_BY_DIRECTION.ASC),
  132. new PageFilter(past ? pastPage : upcomingPage, ref(5)),
  133. new TimeFilter('datetimeStart', today, past ? TIME_STRATEGY.BEFORE : TIME_STRATEGY.AFTER)
  134. )
  135. return fetchCollection(Event, null, query)
  136. }
  137. /**
  138. * Action lorsque l'on souhaite démarrer l'essai
  139. */
  140. async function startTrial() {
  141. try {
  142. await apiRequestService.get('/trial/is_available')
  143. await navigateTo(makeAdminUrl('trial'), {
  144. external: true,
  145. })
  146. } catch (error) {
  147. showDialogTrialAlReadyDid.value = true
  148. }
  149. }
  150. /**
  151. * Nettoyage du store
  152. */
  153. onUnmounted(() => {
  154. useRepo(Organization).flush()
  155. useRepo(Event).flush()
  156. useRepo(Country).flush()
  157. })
  158. </script>
  159. <style scoped lang="scss">
  160. .tabs-title{
  161. margin-top: 20px;
  162. padding-left: 20px;
  163. background-color: rgb(var(--v-theme-neutral));
  164. .v-tab--selected{
  165. color: rgb(var(--v-theme-on-neutral--clickable));
  166. }
  167. }
  168. .v-card {
  169. margin-bottom: 16px;
  170. color: rgb(var(--v-theme-on-primary-alt));
  171. }
  172. .v-card-text{
  173. div{
  174. line-height: 2;
  175. }
  176. }
  177. .organization_title{
  178. font-weight: 500;
  179. }
  180. .icon-hotel{
  181. margin: 0 5px 4px 0;
  182. }
  183. .btn {
  184. border: 1px solid;
  185. cursor: pointer;
  186. }
  187. .inner-container {
  188. margin: 0 auto;
  189. padding: 30px;
  190. }
  191. .btn_trial {
  192. height: 55px;
  193. background-color: rgb(var(--v-theme-x-create-btn));
  194. color: #000;
  195. span {
  196. text-align: center;
  197. line-height: 1.2; /* optionnel : pour resserrer ou espacer */
  198. }
  199. .v-icon {
  200. transform: rotate(135deg); /* angle en degrés */
  201. font-size: 16px;
  202. padding-right: 5px;
  203. margin: 0 5px 4px 0;
  204. }
  205. }
  206. .btn_edit_orga{
  207. color: rgb(var(--v-theme-on-primary-alt)) !important;
  208. }
  209. .no_event{
  210. padding: 25px;
  211. font-size: 16px;
  212. }
  213. </style>