index.vue 8.0 KB

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