dashboard.vue 7.5 KB

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