feat(admin): add document preview functionality to adult verification
- Implemented a preview section for adult verification documents, allowing users to view images and PDFs inline. - Added localization support for preview titles and messages in German, English, and Spanish. - Enhanced the component's state management to handle preview visibility and cleanup.
This commit is contained in:
@@ -42,6 +42,9 @@
|
|||||||
"reject": "Ablehnen",
|
"reject": "Ablehnen",
|
||||||
"resetPending": "Auf Prüfung setzen",
|
"resetPending": "Auf Prüfung setzen",
|
||||||
"openDocument": "Dokument ansehen",
|
"openDocument": "Dokument ansehen",
|
||||||
|
"previewTitle": "Nachweis-Vorschau",
|
||||||
|
"closePreview": "Vorschau schließen",
|
||||||
|
"previewUnavailable": "Für diesen Dateityp ist hier keine Vorschau verfügbar.",
|
||||||
"empty": "Keine passenden Anfragen gefunden.",
|
"empty": "Keine passenden Anfragen gefunden.",
|
||||||
"loadError": "Die Freigaben konnten nicht geladen werden.",
|
"loadError": "Die Freigaben konnten nicht geladen werden.",
|
||||||
"updateError": "Der Status konnte nicht geändert werden.",
|
"updateError": "Der Status konnte nicht geändert werden.",
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
"reject": "Reject",
|
"reject": "Reject",
|
||||||
"resetPending": "Set pending",
|
"resetPending": "Set pending",
|
||||||
"openDocument": "Open document",
|
"openDocument": "Open document",
|
||||||
|
"previewTitle": "Proof preview",
|
||||||
|
"closePreview": "Close preview",
|
||||||
|
"previewUnavailable": "No inline preview is available for this file type.",
|
||||||
"empty": "No matching requests found.",
|
"empty": "No matching requests found.",
|
||||||
"loadError": "Could not load approvals.",
|
"loadError": "Could not load approvals.",
|
||||||
"updateError": "Could not update the status.",
|
"updateError": "Could not update the status.",
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
"reject": "Rechazar",
|
"reject": "Rechazar",
|
||||||
"resetPending": "Poner en revisión",
|
"resetPending": "Poner en revisión",
|
||||||
"openDocument": "Abrir documento",
|
"openDocument": "Abrir documento",
|
||||||
|
"previewTitle": "Vista previa de la prueba",
|
||||||
|
"closePreview": "Cerrar vista previa",
|
||||||
|
"previewUnavailable": "No hay vista previa integrada para este tipo de archivo.",
|
||||||
"empty": "No se han encontrado solicitudes.",
|
"empty": "No se han encontrado solicitudes.",
|
||||||
"loadError": "No se pudieron cargar las aprobaciones.",
|
"loadError": "No se pudieron cargar las aprobaciones.",
|
||||||
"updateError": "No se pudo actualizar el estado.",
|
"updateError": "No se pudo actualizar el estado.",
|
||||||
|
|||||||
@@ -66,6 +66,24 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section v-if="previewUrl" class="adult-verification__preview surface-card">
|
||||||
|
<div class="adult-verification__preview-header">
|
||||||
|
<div>
|
||||||
|
<strong>{{ $t('admin.adultVerification.previewTitle') }}</strong>
|
||||||
|
<span v-if="previewRow">{{ previewRow.username }} · {{ previewRow.adultVerificationRequest?.originalName }}</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="secondary" @click="clearPreview">
|
||||||
|
{{ $t('admin.adultVerification.closePreview') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img v-if="isImagePreview" :src="previewUrl" class="adult-verification__preview-image" />
|
||||||
|
<iframe v-else-if="isPdfPreview" :src="previewUrl" class="adult-verification__preview-pdf" />
|
||||||
|
<div v-else class="adult-verification__state">
|
||||||
|
{{ $t('admin.adultVerification.previewUnavailable') }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -79,7 +97,10 @@ export default {
|
|||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
statusFilter: 'pending',
|
statusFilter: 'pending',
|
||||||
rows: []
|
rows: [],
|
||||||
|
previewUrl: '',
|
||||||
|
previewMimeType: '',
|
||||||
|
previewRow: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -90,6 +111,12 @@ export default {
|
|||||||
{ value: 'rejected', label: this.$t('admin.adultVerification.filters.rejected') },
|
{ value: 'rejected', label: this.$t('admin.adultVerification.filters.rejected') },
|
||||||
{ value: 'all', label: this.$t('admin.adultVerification.filters.all') }
|
{ value: 'all', label: this.$t('admin.adultVerification.filters.all') }
|
||||||
];
|
];
|
||||||
|
},
|
||||||
|
isImagePreview() {
|
||||||
|
return this.previewMimeType.startsWith('image/');
|
||||||
|
},
|
||||||
|
isPdfPreview() {
|
||||||
|
return this.previewMimeType === 'application/pdf';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -109,6 +136,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async changeFilter(filter) {
|
async changeFilter(filter) {
|
||||||
this.statusFilter = filter;
|
this.statusFilter = filter;
|
||||||
|
this.clearPreview();
|
||||||
await this.load();
|
await this.load();
|
||||||
},
|
},
|
||||||
async setStatus(row, status) {
|
async setStatus(row, status) {
|
||||||
@@ -125,16 +153,28 @@ export default {
|
|||||||
const response = await apiClient.get(`/api/admin/users/${row.id}/adult-verification/document`, {
|
const response = await apiClient.get(`/api/admin/users/${row.id}/adult-verification/document`, {
|
||||||
responseType: 'blob'
|
responseType: 'blob'
|
||||||
});
|
});
|
||||||
const url = window.URL.createObjectURL(response.data);
|
this.clearPreview();
|
||||||
window.open(url, '_blank', 'noopener');
|
this.previewMimeType = response.data.type || '';
|
||||||
window.setTimeout(() => window.URL.revokeObjectURL(url), 10000);
|
this.previewUrl = window.URL.createObjectURL(response.data);
|
||||||
|
this.previewRow = row;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showApiError(this, error, this.$t('admin.adultVerification.documentError'));
|
showApiError(this, error, this.$t('admin.adultVerification.documentError'));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
clearPreview() {
|
||||||
|
if (this.previewUrl) {
|
||||||
|
window.URL.revokeObjectURL(this.previewUrl);
|
||||||
|
}
|
||||||
|
this.previewUrl = '';
|
||||||
|
this.previewMimeType = '';
|
||||||
|
this.previewRow = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.load();
|
await this.load();
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.clearPreview();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -147,7 +187,8 @@ export default {
|
|||||||
|
|
||||||
.adult-verification__hero,
|
.adult-verification__hero,
|
||||||
.adult-verification__filters,
|
.adult-verification__filters,
|
||||||
.adult-verification__list {
|
.adult-verification__list,
|
||||||
|
.adult-verification__preview {
|
||||||
background: linear-gradient(180deg, rgba(255, 252, 247, 0.97), rgba(250, 244, 235, 0.95));
|
background: linear-gradient(180deg, rgba(255, 252, 247, 0.97), rgba(250, 244, 235, 0.95));
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
@@ -232,10 +273,41 @@ export default {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.adult-verification__preview-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adult-verification__preview-header > div {
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adult-verification__preview-image,
|
||||||
|
.adult-verification__preview-pdf {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
border: 1px solid rgba(93, 64, 55, 0.08);
|
||||||
|
background: rgba(255, 255, 255, 0.78);
|
||||||
|
}
|
||||||
|
|
||||||
|
.adult-verification__preview-image {
|
||||||
|
max-height: 70vh;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adult-verification__preview-pdf {
|
||||||
|
min-height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 760px) {
|
@media (max-width: 760px) {
|
||||||
.adult-verification__hero,
|
.adult-verification__hero,
|
||||||
.adult-verification__filters,
|
.adult-verification__filters,
|
||||||
.adult-verification__list {
|
.adult-verification__list,
|
||||||
|
.adult-verification__preview {
|
||||||
padding: 18px;
|
padding: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user