CookiesConsent.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <template>
  2. <div v-if="showPopupStatus">
  3. <div class="cookie-consent-banner">
  4. <div class="continue-wrapper">
  5. <a class="continue" href="#" @click.prevent="continueWithoutAccepting">
  6. Continuer sans accepter
  7. </a>
  8. <v-icon
  9. size="20"
  10. class="fa-solid fa-arrow-right ml-6"
  11. @click="showPopupStatus = false"
  12. ></v-icon>
  13. </div>
  14. <v-row justify="center">
  15. <v-col cols="12">
  16. <img
  17. src="/images/logos/cookies/A_cute_and_beautiful_illustration_of_a_cookie_list-removebg-preview.png"
  18. alt="Cookie"
  19. class="cookie-image"
  20. />
  21. </v-col>
  22. </v-row>
  23. <v-row no-gutters>
  24. <v-col cols="12">
  25. <div class="text">
  26. <p>GESTION DES COOKIES</p>
  27. </div>
  28. </v-col>
  29. </v-row>
  30. <p class="details-cookies" style="padding-left: 20px">
  31. Le site Opentalent.fr utilise des cookies fonctionnels nécessaires à la
  32. navigation du site et d'autres technologies similaire pour plusieurs
  33. objectifs : des cookies d'analyse de l'audience du site, des cookies de
  34. personnalisation de contenu et des cookies publicitaires. Pour plus de
  35. détail, veuillez consulter notre
  36. <NuxtLink to="/politique-de-confidentialite#cookie-policy">
  37. Politique de confidentialité</NuxtLink
  38. >. Vous pouvez ajuster vos préférences en matière de cookies à tout
  39. moment en cliquant sur le bouton "Gérer mes préférences"
  40. </p>
  41. <div class="horizontal-line"></div>
  42. <div class="actions">
  43. <button
  44. class="customize-button"
  45. @click="showCustomizationOptions = true"
  46. >
  47. Gérer mes préférences
  48. </button>
  49. <button class="accept-button" @click="acceptAllCookies">
  50. Tout accepter
  51. </button>
  52. <!-- <button class="decline-button" @click="declineCookies">Refuser</button> -->
  53. </div>
  54. </div>
  55. <v-dialog v-model="showCustomizationOptions" persistent max-width="600px">
  56. <v-card>
  57. <v-row class="headline">
  58. <v-btn
  59. class="close-dialog"
  60. :icon="true"
  61. @click="showCustomizationOptions = false"
  62. >
  63. <v-icon size="20" class="fas fa-times" />
  64. </v-btn>
  65. <v-card-title>Gérer mes préferences</v-card-title>
  66. </v-row>
  67. <p class="gestion-preferences">
  68. Vous pouvez définir vos préférences sur la manière dont vous souhaitez
  69. que vos données soient utilisées en fonction des finalités et des
  70. entreprises tierces ci-dessous. Certains tiers peuvent traiter des
  71. données sur la base d'un intérêt légitime et vous pouvez choisir de
  72. vous désinscrire.
  73. </p>
  74. <v-container class="preferences-actions text-end">
  75. <button class="decline-button" @click="declineCookies">
  76. Tout refuser
  77. </button>
  78. <button class="accept-button" @click="acceptAllCookies">
  79. Tout accepter
  80. </button>
  81. </v-container>
  82. <v-card-text>
  83. <h4>Des cookies tiers permettant de réaliser des statistiques</h4>
  84. <v-row align="center">
  85. <v-col cols="auto">
  86. <v-switch
  87. v-model="cookiesPreferences.allowGoogleAnalytics"
  88. label="Google Analytics"
  89. hide-details
  90. color="green"
  91. inset
  92. />
  93. </v-col>
  94. <v-col>{{
  95. cookiesPreferences.allowGoogleAnalytics
  96. ? 'Autorisé'
  97. : 'Non-autorisé'
  98. }}</v-col>
  99. </v-row>
  100. <p>
  101. Ces cookies nous permettent d'établir des statistiques, des volumes
  102. de fréquentation et d'utilisation des divers éléments de notre site,
  103. nous permettant d’optimiser son fonctionnement. Lien vers la
  104. Politique de protection des données de Google Analytics :
  105. <a href="https://policies.google.com/">
  106. https://policies.google.com/</a
  107. >
  108. </p>
  109. <h4 class="mt-6">Des cookies tiers à visée publicitaire</h4>
  110. <v-row align="center">
  111. <v-col cols="auto">
  112. <v-switch
  113. v-model="cookiesPreferences.allowMetaPixel"
  114. label="Meta Pixel"
  115. hide-details
  116. color="green"
  117. inset
  118. />
  119. </v-col>
  120. <v-col>{{
  121. cookiesPreferences.allowMetaPixel ? 'Autorisé' : 'Non-autorisé'
  122. }}</v-col>
  123. </v-row>
  124. <p>
  125. Ces cookies sont installés par Facebook. Ce service nous permet
  126. d'établir des statistiques de consultation des publicités. Lien vers
  127. la Politique de protection des données de Facebook Pixel :
  128. <a
  129. href="https://www.facebook.com/privacy/policies/cookies/?entry_point=cookie_policy_redirect&entry=0"
  130. >
  131. https://www.facebook.com/privacy/policies/cookies/?entry_point=cookie_policy_redirect&entry=0
  132. </a>
  133. </p>
  134. </v-card-text>
  135. <v-card-actions>
  136. <v-btn color="secondary" @click="showCustomizationOptions = false">
  137. Fermer
  138. </v-btn>
  139. <v-spacer />
  140. <button class="accept-button" @click="saveCookiesPreferences">
  141. Sauvegarder
  142. </button>
  143. </v-card-actions>
  144. </v-card>
  145. </v-dialog>
  146. </div>
  147. <v-alert
  148. v-model="showNotification"
  149. title="Confirmation"
  150. type="warning"
  151. width="400"
  152. closable
  153. transition="fade-transition"
  154. density="compact"
  155. class="alert"
  156. >
  157. Vous avez refusé nos cookies. Si vous le souhaitez, vous pouvez encore
  158. modifier votre décision en
  159. <a href="#" @click="showPopup()">cliquant ici</a>.
  160. </v-alert>
  161. </template>
  162. <script setup lang="ts">
  163. import { onMounted, type Ref, ref } from 'vue'
  164. import { useCookies } from 'vue3-cookies'
  165. import CookieManager from '~/services/CookieManager'
  166. import { COOKIE_CONSENT_CHOICE } from '~/types/enum/enums'
  167. import type { CookiesPreferences } from '~/types/interface'
  168. const { cookies } = useCookies()
  169. const showPopupStatus = ref(false)
  170. const showCustomizationOptions = ref(false)
  171. const showNotification = ref(false)
  172. /**
  173. * Cookies options
  174. */
  175. const cookiesPreferences: Ref<CookiesPreferences> = ref({
  176. allowGoogleAnalytics: true,
  177. allowMetaPixel: true,
  178. })
  179. const showPopup = () => {
  180. showPopupStatus.value = true
  181. showCustomizationOptions.value = false
  182. showNotification.value = false
  183. }
  184. const closePopup = () => {
  185. showPopupStatus.value = false
  186. }
  187. const notify = () => {
  188. showNotification.value = true
  189. // Hide the notification after 1 minute
  190. // setTimeout(() => {
  191. // showNotification.value = false
  192. // }, 60000)
  193. }
  194. const setupCookies = (
  195. choice: COOKIE_CONSENT_CHOICE,
  196. allowGoogleAnalytics: boolean,
  197. allowMetaPixel: boolean,
  198. duration: number = 365
  199. ) => {
  200. cookies.set('cookie_consent', choice, duration + 'd')
  201. cookiesPreferences.value.allowGoogleAnalytics = allowGoogleAnalytics
  202. cookies.set('ga_consent', allowGoogleAnalytics.toString(), duration + 'd')
  203. if (allowGoogleAnalytics) {
  204. CookieManager.makeGoogleAnalyticsCookies('UA-XXXXX-Y')
  205. } else {
  206. purgeGoogleCookies()
  207. }
  208. cookiesPreferences.value.allowMetaPixel = allowMetaPixel
  209. cookies.set('mp_consent', allowMetaPixel.toString(), duration + 'd')
  210. if (allowMetaPixel) {
  211. CookieManager.makeMetaPixelCookies('1045498113172655')
  212. } else {
  213. purgeMetaCookies()
  214. }
  215. // Store consent date and status
  216. localStorage.setItem(
  217. 'cookie_consent',
  218. JSON.stringify({
  219. date: new Date(),
  220. consent: { allowGoogleAnalytics, allowMetaPixel },
  221. })
  222. )
  223. }
  224. const purgeGoogleCookies = () => {
  225. cookies.remove('google') // TODO: complete
  226. }
  227. const purgeMetaCookies = () => {
  228. cookies.remove('google') // TODO: complete
  229. }
  230. /**
  231. * Accept and setup all the cookies and close the popup
  232. */
  233. const acceptAllCookies = () => {
  234. setupCookies(COOKIE_CONSENT_CHOICE.ACCEPTED, true, true)
  235. closePopup()
  236. }
  237. /**
  238. * Refuse all the cookies, set up the cookie_consent cookie and close the popup
  239. */
  240. const declineCookies = () => {
  241. setupCookies(COOKIE_CONSENT_CHOICE.DECLINED, false, false, 7)
  242. notify()
  243. closePopup()
  244. }
  245. /**
  246. * Set up the cookies following user preferences and close the popup
  247. */
  248. const saveCookiesPreferences = () => {
  249. setupCookies(
  250. COOKIE_CONSENT_CHOICE.CUSTOMIZED,
  251. cookiesPreferences.value.allowGoogleAnalytics,
  252. cookiesPreferences.value.allowMetaPixel
  253. )
  254. closePopup()
  255. }
  256. /**
  257. * Continue without accepting cookies
  258. */
  259. const continueWithoutAccepting = () => {
  260. closePopup()
  261. }
  262. const loadActivePreferences = () => {
  263. cookiesPreferences.value.allowGoogleAnalytics =
  264. cookies.get('ga_consent') === 'true'
  265. cookiesPreferences.value.allowMetaPixel = cookies.get('mp_consent') === 'true'
  266. }
  267. /**
  268. * Check if the user has already accepted the cookies when page is mounted
  269. */
  270. onMounted(() => {
  271. const cookieConsent = cookies.get('cookie_consent')
  272. if (!cookieConsent) {
  273. showPopup()
  274. }
  275. loadActivePreferences()
  276. })
  277. </script>
  278. <style scoped lang="scss">
  279. .gestion-preferences {
  280. font-size: 1.2rem;
  281. font-weight: 500;
  282. margin-bottom: 10px;
  283. padding: 20px;
  284. text-align: justify;
  285. }
  286. .preferences-actions {
  287. overflow: visible;
  288. }
  289. .headline {
  290. font-size: 1.5rem;
  291. font-weight: 500;
  292. margin: 0 0 10px 0;
  293. background-color: var(--secondary-color);
  294. color: var(--on-secondary-color);
  295. text-transform: uppercase;
  296. padding: 15px;
  297. }
  298. .cookie-consent-banner {
  299. background: var(--neutral-color);
  300. position: fixed;
  301. bottom: 10px;
  302. left: 15px;
  303. max-width: 550px;
  304. z-index: 1000 !important;
  305. display: flex;
  306. flex-direction: column;
  307. align-items: center;
  308. box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  309. border-radius: 15px;
  310. padding: 20px;
  311. }
  312. .cookie-image {
  313. width: 150px;
  314. margin: 0;
  315. }
  316. .text {
  317. padding-top: 10px;
  318. padding-bottom: 0;
  319. font-weight: 600;
  320. font-size: 1.3rem;
  321. text-align: center;
  322. }
  323. .details-cookies {
  324. padding: 10px;
  325. text-align: justify;
  326. }
  327. .horizontal-line {
  328. width: 90%;
  329. height: 1px;
  330. background-color: var(--neutral-color-alt-strong);
  331. margin-top: 10px;
  332. margin-bottom: 10px;
  333. }
  334. .actions {
  335. margin-top: 10px;
  336. margin-bottom: 10px;
  337. display: flex;
  338. justify-content: center;
  339. }
  340. .accept-button,
  341. .customize-button {
  342. background-color: var(--on-primary-color-alt);
  343. border: none;
  344. padding: 10px 20px;
  345. margin: 5px;
  346. cursor: pointer;
  347. }
  348. .decline-button {
  349. border: 1px solid var(--on-neutral-color);
  350. padding: 10px 20px;
  351. margin: 5px;
  352. cursor: pointer;
  353. }
  354. .accept-button:hover,
  355. .customize-button:hover {
  356. background-color: var(--on-primary-color-alt);
  357. }
  358. .cookie-description {
  359. margin: 0;
  360. font-size: 0.875rem;
  361. color: var(--on-neutral-color-light);
  362. }
  363. .custom-switch .v-input--selection-controls__ripple .v-ripple__container {
  364. background-color: var(--v-primary-color);
  365. }
  366. .custom-switch,
  367. .v-input--selection-controls__ripple--active,
  368. .v-ripple__container {
  369. background-color: var(--v-primary-darken4);
  370. }
  371. .custom-switch .v-input--selection-controls__input {
  372. --v-theme-primary: var(--v-primary-base);
  373. --v-theme-primary-lighten4: var(--v-primary-lighten4);
  374. --v-theme-primary-darken4: var(--v-primary-darken4);
  375. }
  376. .custom-switch,
  377. .v-input--selection-controls__input,
  378. input:checked,
  379. + .v-input--selection-controls__ripple,
  380. .v-ripple__container {
  381. background-color: var(--v-primary-darken4);
  382. }
  383. .custom-switch,
  384. .v-input--selection-controls__input,
  385. input:checked,
  386. + .v-input--selection-controls__ripple,
  387. .v-ripple__container,
  388. .v-ripple__animation {
  389. background-color: var(--v-primary-darken4);
  390. }
  391. :deep(.v-switch__track) {
  392. background-color: var(--warning-color);
  393. }
  394. .close-dialog {
  395. background: none !important;
  396. box-shadow: none !important;
  397. }
  398. .continue {
  399. font-size: 0.9rem;
  400. font-weight: 500;
  401. cursor: pointer;
  402. text-decoration: none !important;
  403. color: var(--on-neutral-color);
  404. }
  405. .continue-wrapper {
  406. display: flex;
  407. justify-content: end;
  408. align-items: center;
  409. margin-left: auto;
  410. }
  411. :deep(.v-switch .v-label) {
  412. opacity: 0.8;
  413. }
  414. .alert {
  415. position: fixed;
  416. bottom: 20px;
  417. right: 20px;
  418. z-index: 1000;
  419. a {
  420. color: var(--on-primary-color);
  421. font-weight: 700;
  422. text-decoration: none;
  423. }
  424. a:hover {
  425. text-decoration: underline;
  426. }
  427. }
  428. </style>