IdCard.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <template>
  2. <v-card class="id-card">
  3. <div
  4. v-if="!appStore.altchaPayload || !idCardData"
  5. class="skeleton-container"
  6. >
  7. <div class="layout">
  8. <v-skeleton-loader
  9. type="image"
  10. :max-height="110"
  11. boilerplate
  12. />
  13. <v-skeleton-loader
  14. type="article"
  15. :max-height="110"
  16. boilerplate
  17. />
  18. </div>
  19. <v-btn v-if="!appStore.altchaPayload" flat class="btn-overlay" @click="onClick">
  20. <v-icon class="fas fa-eye" />
  21. </v-btn>
  22. <v-progress-circular v-else :indeterminate="true" class="btn-overlay" />
  23. <AltchaValidation
  24. v-if="showCaptcha"
  25. />
  26. </div>
  27. <div v-else-if="idCardData">
  28. <div class="layout">
  29. <v-img
  30. :src="'data:image/png;base64,' + idCardData.photo"
  31. :height="110"
  32. />
  33. <div class="details">
  34. <div>Olivier Massot</div>
  35. <div>{{ idCardData.place }}</div>
  36. <div>{{ $t('id_age', { years: idCardData.age }) }}</div>
  37. <div>{{ $t(idCardData.status) }}</div>
  38. </div>
  39. </div>
  40. </div>
  41. </v-card>
  42. </template>
  43. <script setup lang="ts">
  44. import type { Ref } from '@vue/reactivity'
  45. import type { ComputedRef } from 'vue'
  46. interface IdCardData {
  47. photo: string,
  48. age: number,
  49. place: string,
  50. status: string
  51. }
  52. const appStore = useAppStore()
  53. const { altchaPayload } = storeToRefs(appStore)
  54. const downloadRequested: Ref<boolean> = ref(false)
  55. const showCaptcha: ComputedRef<boolean> = computed(() => {
  56. return downloadRequested.value && !appStore.altchaPayload
  57. })
  58. const idCardData: Ref<IdCardData | null> = ref(null)
  59. const onClick = () => {
  60. downloadRequested.value = true
  61. }
  62. watch(() => appStore.altchaPayload, () => {
  63. submit()
  64. }, { immediate: false })
  65. const submit = async () => {
  66. const url = 'https://api.ogene.fr/api/id-card?payload=' + encodeURI(appStore.altchaPayload ?? '');
  67. try {
  68. const response = await fetch(url, {
  69. method: 'GET',
  70. });
  71. if (!response.ok) {
  72. throw new Error(`HTTP error! status: ${response.status}`);
  73. }
  74. idCardData.value = await response.json();
  75. } catch (error) {
  76. console.error('There was a problem with the fetch operation: ', error);
  77. }
  78. }
  79. </script>
  80. <style scoped lang="scss">
  81. .id-card {
  82. width: 280px;
  83. height: 140px;
  84. max-width: 280px;
  85. max-height: 140px;
  86. min-width: 280px;
  87. min-height: 140px;
  88. padding: 15px;
  89. }
  90. .layout {
  91. display: flex;
  92. flex-direction: row;
  93. >*:first-child {
  94. width: 40%;
  95. }
  96. >* {
  97. width: 70%;
  98. }
  99. .v-skeleton-loader {
  100. :deep(.v-skeleton-loader__image) {
  101. max-height: 100%;
  102. }
  103. :deep(.v-skeleton-loader__article) {
  104. max-height: 100%;
  105. }
  106. :deep(.v-skeleton-loader__heading) {
  107. margin: 6px 16px;
  108. }
  109. }
  110. }
  111. .skeleton-container {
  112. position: relative;
  113. height: 100%;
  114. }
  115. .btn-overlay {
  116. position: absolute;
  117. top: 0;
  118. left: 0;
  119. width: 100%;
  120. height: 100% !important;
  121. display: flex;
  122. justify-content: center;
  123. align-items: center;
  124. opacity: 0.5;
  125. :deep(.v-icon) {
  126. font-size: 28px;
  127. }
  128. }
  129. altcha-widget {
  130. position: absolute;
  131. top: 15px; /* Ajustez cette valeur en fonction de la hauteur de votre bouton */
  132. left: 30px;
  133. background: rgb(var(--v-theme-surface));
  134. border-radius: 4px;
  135. z-index: 10;
  136. }
  137. .details {
  138. font-size: 13px;
  139. >div {
  140. margin: 2px 0;
  141. }
  142. }
  143. </style>