Event.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <template>
  2. <LayoutCommonSection>
  3. <v-row>
  4. <v-col cols="12" sm="12">
  5. <h4 class="mb-8">{{ $t('general_informations') }}</h4>
  6. <UiInputText
  7. v-model="proxyEntity.name"
  8. field="name"
  9. :rules="getAsserts('name')"
  10. />
  11. <span class="label">{{ $t('datetimeStart') }}</span>
  12. <UiInputDateTimePicker
  13. :model-value="proxyEntity.datetimeStart"
  14. field="datetimeStart"
  15. label="datetimeStart"
  16. :with-time-picker="true"
  17. class="my-2"
  18. :rules="getAsserts('datetimeStart')"
  19. validate-on-blur
  20. @update:model-value="onUpdateDateTimeStart(proxyEntity, $event)"
  21. />
  22. <span class="label">{{ $t('datetimeEnd') }}</span>
  23. <UiInputDateTimePicker
  24. :model-value="proxyEntity.datetimeEnd"
  25. field="datetimeEnd"
  26. label="datetimeEnd"
  27. :with-time-picker="true"
  28. class="my-2"
  29. :rules="getAsserts('datetimeEnd')"
  30. @update:model-value="onUpdateDateTimeEnd(proxyEntity, $event)"
  31. />
  32. <span class="label">{{ $t('description') }}</span>
  33. <UiInputTextArea v-model="proxyEntity.description" class="mt-3" />
  34. <UiInputAutocompleteApiResources
  35. v-model="proxyEntity.gender"
  36. field="gender"
  37. label="gender_event"
  38. :model="EventGender"
  39. list-value="id"
  40. list-label="name"
  41. :rules="getAsserts('gender')"
  42. :pagination="false"
  43. :apiFilters="queryConditions"
  44. />
  45. <UiInputTreeSelectEventCategories
  46. v-model="proxyEntity.categories"
  47. label="event_categories_choices"
  48. />
  49. <UiInputImage
  50. v-model="proxyEntity.image"
  51. field="image"
  52. label="event_image"
  53. :width="240"
  54. :cropping-enabled="true"
  55. />
  56. </v-col>
  57. </v-row>
  58. </LayoutCommonSection>
  59. <LayoutCommonSection>
  60. <v-row>
  61. <v-col cols="12">
  62. <h4 class="mb-8">{{ $t('place_event') }}</h4>
  63. <UiInputAutocompleteApiResources
  64. v-if="!newPlace"
  65. v-model="proxyEntity.place"
  66. field="place"
  67. :model="PlaceSearchItem"
  68. list-value="id"
  69. list-label="name"
  70. @update:model-value="getPlace(proxyEntity)"
  71. />
  72. <v-row class="mb-6 justify-center">
  73. <v-col
  74. v-if="newPlace"
  75. cols="12"
  76. sm="6"
  77. class="d-flex justify-center mb-2"
  78. >
  79. <v-btn
  80. prepend-icon="fa-solid fa-cancel"
  81. @click="onCancelPlaceClick(proxyEntity)"
  82. >
  83. {{ $t('cancel') }}
  84. </v-btn>
  85. </v-col>
  86. <v-col
  87. v-if="proxyEntity.place && !editPlace"
  88. cols="12"
  89. sm="6"
  90. class="d-flex justify-center mb-2"
  91. >
  92. <v-btn
  93. prepend-icon="fa-solid fa-pencil"
  94. @click="onEditPlaceClick(proxyEntity)"
  95. >
  96. {{ $t('edit_place') }}
  97. </v-btn>
  98. </v-col>
  99. <v-col
  100. v-if="!newPlace"
  101. cols="12" sm="6" class="d-flex justify-center mb-2">
  102. <v-btn
  103. prepend-icon="fa-solid fa-plus"
  104. @click="onAddPlaceClick(proxyEntity)"
  105. >
  106. {{ $t('add_place') }}
  107. </v-btn>
  108. </v-col>
  109. </v-row>
  110. <div v-if="newPlace || editPlace">
  111. <UiInputText
  112. v-model="proxyEntity.placeName"
  113. :readonly="!newPlace && !editPlace"
  114. field="placeName"
  115. />
  116. <UiInputText
  117. v-model="proxyEntity.streetAddress"
  118. :readonly="!newPlace && !editPlace"
  119. field="streetAddress"
  120. />
  121. <UiInputText
  122. v-model="proxyEntity.streetAddressSecond"
  123. :readonly="!newPlace && !editPlace"
  124. field="streetAddressSecond"
  125. />
  126. <UiInputText
  127. v-model="proxyEntity.streetAddressThird"
  128. :readonly="!newPlace && !editPlace"
  129. field="streetAddressThird"
  130. />
  131. <UiInputText
  132. v-model="proxyEntity.postalCode"
  133. :readonly="!newPlace && !editPlace"
  134. field="postalCode"
  135. />
  136. <UiInputText
  137. v-model="proxyEntity.addressCity"
  138. :readonly="!newPlace && !editPlace"
  139. field="addressCity"
  140. />
  141. <UiInputAutocompleteApiResources
  142. v-model="proxyEntity.addressCountry"
  143. :readonly="!newPlace && !editPlace"
  144. field="addressCountry"
  145. :model="Country"
  146. list-value="id"
  147. list-label="name"
  148. />
  149. <client-only>
  150. <UiMapLeaflet
  151. v-model:latitude="proxyEntity.latitude"
  152. v-model:longitude="proxyEntity.longitude"
  153. :readonly="!newPlace && !editPlace"
  154. :street-address="proxyEntity.streetAddress"
  155. :street-address-second="proxyEntity.streetAddressSecond"
  156. :street-address-third="proxyEntity.streetAddressThird"
  157. :postal-code="proxyEntity.postalCode"
  158. :address-city="proxyEntity.addressCity"
  159. :address-country-id="proxyEntity.addressCountry"
  160. :search-button="true"
  161. ></UiMapLeaflet>
  162. </client-only>
  163. </div>
  164. </v-col>
  165. </v-row>
  166. </LayoutCommonSection>
  167. <LayoutCommonSection>
  168. <v-row>
  169. <v-col cols="12">
  170. <h4 class="mb-8">{{ $t('communication_params') }}</h4>
  171. <UiInputText v-model="proxyEntity.url" field="url" :rules="getAsserts('url')" />
  172. <UiInputAutocompleteEnum
  173. v-model="proxyEntity.pricing"
  174. enum-name="pricing_event"
  175. field="pricing"
  176. />
  177. <UiInputText
  178. v-if="proxyEntity.pricing === 'PAID'"
  179. v-model="proxyEntity.urlTicket"
  180. :rules="getAsserts('urlTicket')"
  181. field="urlTicket"
  182. />
  183. <UiInputNumber
  184. v-if="proxyEntity.pricing === 'PAID'"
  185. v-model="proxyEntity.priceMini"
  186. field="priceMini"
  187. :rules="getAsserts('priceMini')"
  188. />
  189. <UiInputNumber
  190. v-if="proxyEntity.pricing === 'PAID'"
  191. v-model="proxyEntity.priceMaxi"
  192. field="priceMaxi"
  193. :rules="getAsserts('priceMaxi')"
  194. />
  195. </v-col>
  196. </v-row>
  197. </LayoutCommonSection>
  198. <LazyLayoutDialog :show="showAlert" theme="warning">
  199. <template #dialogType>{{ $t('important') }}</template>
  200. <template #dialogTitle>{{ $t('place_change_everywhere') }}</template>
  201. <template #dialogText>
  202. <v-card-text class="text">
  203. <p>
  204. {{ $t('warning_edit_place') }}
  205. </p>
  206. <br />
  207. <p>
  208. {{ $t('are_you_sure_to_process') }}
  209. </p>
  210. </v-card-text>
  211. </template>
  212. <template #dialogBtn>
  213. <v-btn class="mr-4 submitBtn theme-neutral-strong" @click="closeDialog">
  214. {{ $t('cancel') }}
  215. </v-btn>
  216. <v-btn class="mr-4 submitBtn theme-warning" @click="onEditPlaceConfirm">
  217. {{ $t('i_understand') }}
  218. </v-btn>
  219. </template>
  220. </LazyLayoutDialog>
  221. </template>
  222. <script setup lang="ts">
  223. import Event from '~/models/Freemium/Event'
  224. import Place from '~/models/Freemium/Place'
  225. import { getAssertUtils } from '~/services/asserts/getAssertUtils'
  226. import DateUtils from '~/services/utils/dateUtils'
  227. import Country from '~/models/Core/Country'
  228. import PlaceSearchItem from '~/models/Custom/Search/PlaceSearchItem'
  229. import { useEntityManager } from '~/composables/data/useEntityManager'
  230. import EventGender from "~/models/Booking/EventGender";
  231. import EqualFilter from "~/services/data/Filters/EqualFilter";
  232. const props = defineProps<{
  233. entity: Event
  234. }>()
  235. const { em } = useEntityManager()
  236. const getAsserts = (key) => getAssertUtils(Event.getAsserts(), key)
  237. const emit = defineEmits(['update:entity'])
  238. // Pour éviter l'erreur eslint "Unexpected mutation of "modelValue" prop"
  239. const proxyEntity = computed({
  240. get: () => props.entity,
  241. set: (value) => emit('update:entity', value),
  242. })
  243. const queryConditions = [new EqualFilter('type', 'CULTURAL_EVENT')]
  244. /**
  245. * Si la date de début est mise à jour, on s'assure que la date de fin est
  246. * après elle, sinon elle devient égale
  247. * @param entity
  248. * @param dateTime
  249. */
  250. const onUpdateDateTimeStart = (entity, dateTime) => {
  251. if (DateUtils.isBefore(props.entity.datetimeEnd, dateTime, false)) {
  252. const dateTimeEnd = new Date(dateTime);
  253. // Ajouter 1h
  254. dateTimeEnd.setHours(dateTimeEnd.getHours() + 1);
  255. entity.datetimeEnd = DateUtils.toIsoUtcOffset(dateTimeEnd)
  256. }
  257. entity.datetimeStart = dateTime
  258. emit('update:entity', entity)
  259. }
  260. /**
  261. * Si la date de fin est mise à jour, on s'assure que la date de début est
  262. * avant elle, sinon elle devient égale
  263. * @param entity
  264. * @param dateTime
  265. */
  266. const onUpdateDateTimeEnd = (entity, dateTime) => {
  267. if (DateUtils.isBefore(dateTime, props.entity.datetimeStart, false)) {
  268. const dateTimeStart = new Date(dateTime);
  269. // Retirer 1h
  270. dateTimeStart.setHours(dateTimeStart.getHours() - 1);
  271. entity.datetimeStart = DateUtils.toIsoUtcOffset(dateTimeStart)
  272. }
  273. entity.datetimeEnd = dateTime
  274. emit('update:entity', entity)
  275. }
  276. const showAlert: Ref<boolean> = ref(false)
  277. const newPlace: Ref<boolean> = ref(false)
  278. const editPlace: Ref<boolean> = ref(false)
  279. /**
  280. * Si on clique sur le bouton "Ajouter un lieu", le choix dans la liste déroulante
  281. * est mise à nulle, et les champs input de l'adresse sont vidées
  282. * @param entity
  283. */
  284. const onAddPlaceClick = function (entity: Event) {
  285. newPlace.value = true
  286. entity.place = null
  287. resetPlace(entity)
  288. }
  289. const onCancelPlaceClick = function (entity: Event) {
  290. newPlace.value = false
  291. entity.place = null
  292. resetPlace(entity)
  293. }
  294. /**
  295. * Quand on clique sur le bouton "Editer le lieu", une alerte s'affiche.
  296. */
  297. const onEditPlaceClick = function () {
  298. showAlert.value = true
  299. }
  300. /**
  301. * Quand on ferme la boite de dialogue
  302. */
  303. const closeDialog = function () {
  304. showAlert.value = false
  305. }
  306. /**
  307. * Si on décide d'éditer le lieu
  308. */
  309. const onEditPlaceConfirm = function () {
  310. showAlert.value = false
  311. editPlace.value = true
  312. }
  313. /**
  314. * Lorsque l'on choisit un lieu dans la liste déroulante, on met à jour les champs
  315. * input de l'adresse
  316. * @param entity
  317. */
  318. const getPlace = async (entity: Event) => {
  319. if (entity.place) {
  320. const placeInstance = await em.fetch(Place, entity.place as number)
  321. entity.placeName = placeInstance.name
  322. entity.streetAddress = placeInstance.streetAddress
  323. entity.streetAddressSecond = placeInstance.streetAddressSecond
  324. entity.streetAddressThird = placeInstance.streetAddressThird
  325. entity.addressCity = placeInstance.addressCity
  326. entity.postalCode = placeInstance.postalCode
  327. entity.addressCountry = placeInstance.addressCountry
  328. entity.latitude = placeInstance.latitude
  329. entity.longitude = placeInstance.longitude
  330. editPlace.value = false
  331. } else {
  332. // Dans le cas où l'on ne récupère aucune place on remet à null le formulaire de l'adresse
  333. resetPlace(entity)
  334. }
  335. emit('update:entity', entity)
  336. }
  337. /**
  338. * fonction permettant de remettre à vide tous les champs input de l'adresse
  339. * @param entity
  340. */
  341. const resetPlace = (entity: Event) => {
  342. entity.placeName = null
  343. entity.streetAddress = null
  344. entity.streetAddressSecond = null
  345. entity.streetAddressThird = null
  346. entity.addressCity = null
  347. entity.postalCode = null
  348. entity.addressCountry = null
  349. entity.latitude = null
  350. entity.longitude = null
  351. }
  352. // Nettoyer les données lors du démontage du composant
  353. onBeforeUnmount(() => {
  354. // Nettoyer les références du store si nécessaire
  355. if (import.meta.client) {
  356. clearNuxtData('/^' + Place.entity + '_/')
  357. useRepo(Place).flush()
  358. }
  359. })
  360. </script>
  361. <style scoped lang="scss">
  362. .label {
  363. font-size: 16px;
  364. color: rgb(var(--v-theme-on-primary-alt));
  365. }
  366. </style>