dashboard.vue 7.0 KB

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