index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <!--
  2. Administration de la connexion Opentalent / HelloAsso
  3. -->
  4. <template>
  5. <LayoutContainer>
  6. <v-card>
  7. <v-row>
  8. <v-col cols="12" md="4" class="d-flex justify-center">
  9. <v-img src="/images/logos/Logo-HelloAsso.svg" class="logo" />
  10. </v-col>
  11. <v-col cols="12" md="8" class="presentation">
  12. {{ $t('helloasso_presentation') }}
  13. </v-col>
  14. </v-row>
  15. <v-row>
  16. <v-col cols="12" class="d-flex justify-center align-center w-100 mt-6">
  17. <v-progress-circular
  18. v-if="statusHelloAssoProfile === FETCHING_STATUS.PENDING"
  19. indeterminate
  20. size="32"
  21. />
  22. <UiButtonHelloAssoConnect
  23. v-else-if="!helloAssoProfile || !helloAssoProfile.token"
  24. @click="onHelloAssoConnectClicked"
  25. />
  26. <div v-else>
  27. <v-row>
  28. <v-icon icon="fas fa-check" color="success" class="mr-3" />
  29. {{ $t('your_helloasso_account_is_linked') }}
  30. </v-row>
  31. </div>
  32. </v-col>
  33. </v-row>
  34. </v-card>
  35. </LayoutContainer>
  36. </template>
  37. <script setup lang="ts">
  38. import AuthUrl from '~/models/HelloAsso/AuthUrl'
  39. import HelloAssoProfile from '~/models/HelloAsso/HelloAssoProfile'
  40. import { useEntityManager } from '~/composables/data/useEntityManager'
  41. import { useEntityFetch } from '~/composables/data/useEntityFetch'
  42. import { FETCHING_STATUS } from '~/types/enum/data'
  43. const { em } = useEntityManager()
  44. const onHelloAssoConnectClicked = async () => {
  45. // Important de régénérer une URL avec un nouveau challenge à chaque
  46. // essai (entre autres pour supporter le HMR pendant les tests en local,
  47. // ou en cas d'erreur et de ré-essai)
  48. const authUrl = await em.fetch(AuthUrl)
  49. navigateTo(authUrl.authUrl, {
  50. external: true,
  51. open: {
  52. target: '_blank',
  53. windowFeatures: {
  54. popup: true,
  55. width: 900,
  56. height: 600,
  57. },
  58. },
  59. })
  60. }
  61. onMounted(() => {
  62. window.addEventListener('message', (event) => {
  63. if (event.origin !== window.location.origin) {
  64. return
  65. }
  66. if (!event.data || !event.data.code) {
  67. return
  68. }
  69. onHelloAssoConnected()
  70. })
  71. })
  72. const { fetch } = useEntityFetch()
  73. const {
  74. status: statusHelloAssoProfile,
  75. refresh: refreshHelloAssoProfile,
  76. } = await fetch(HelloAssoProfile)
  77. const helloAssoProfile: ComputedRef<HelloAssoProfile | null> = computed(() => {
  78. if (statusHelloAssoProfile.value !== FETCHING_STATUS.SUCCESS) {
  79. return null
  80. }
  81. return em.find(HelloAssoProfile, 1)
  82. })
  83. const onHelloAssoConnected = async () => {
  84. // On attend 200ms pour laisser en attente du message SSE
  85. await new Promise(r => setTimeout(r, 200))
  86. if (!helloAssoProfile.value || !helloAssoProfile.value.token) {
  87. // Fallback en cas de défaut de fonctionnement du SSE
  88. console.log('Helloasso connected (fallback SSE)')
  89. await refreshHelloAssoProfile()
  90. }
  91. }
  92. </script>
  93. <style scoped lang="scss">
  94. .v-card {
  95. padding: 48px;
  96. max-width: 70%;
  97. margin: 36px auto;
  98. @media (max-width: 600px) {
  99. max-width: 90%;
  100. }
  101. }
  102. .logo {
  103. max-width: 80%;
  104. }
  105. .presentation {
  106. border-left: 3px solid rgb(var(--v-theme-info));
  107. padding: 0 24px;
  108. color: rgb(var(--v-theme-on-neutral));
  109. }
  110. .authDialog {
  111. max-width: 90%;
  112. }
  113. </style>