refactor(admin): restructure adult verification and erotic moderation views for improved layout

- Updated the AdultVerificationView and EroticModerationView components to utilize a new layout structure with content scrolling and hidden overflow for better user experience.
- Adjusted styles in styles.scss to support the new layout, ensuring proper height and overflow handling for content sections.
This commit is contained in:
Torsten Schulz (local)
2026-03-27 11:18:42 +01:00
parent 25b658acce
commit 02837c7b73
3 changed files with 178 additions and 165 deletions

View File

@@ -276,13 +276,16 @@ main,
} }
.app-content__inner > .contenthidden { .app-content__inner > .contenthidden {
height: auto; flex: 1 1 auto;
overflow: visible; min-height: 0;
height: 100%;
overflow: hidden;
} }
.app-content__inner > .contenthidden > .contentscroll { .app-content__inner > .contenthidden > .contentscroll {
height: auto; min-height: 0;
overflow: visible; height: 100%;
overflow: auto;
} }
.surface-card { .surface-card {

View File

@@ -1,97 +1,101 @@
<template> <template>
<div class="adult-verification"> <div class="contenthidden">
<section class="adult-verification__hero surface-card"> <div class="contentscroll">
<span class="adult-verification__eyebrow">Administration</span> <div class="adult-verification">
<h1>{{ $t('admin.adultVerification.title') }}</h1> <section class="adult-verification__hero surface-card">
<p>{{ $t('admin.adultVerification.intro') }}</p> <span class="adult-verification__eyebrow">Administration</span>
</section> <h1>{{ $t('admin.adultVerification.title') }}</h1>
<p>{{ $t('admin.adultVerification.intro') }}</p>
</section>
<section class="adult-verification__filters surface-card"> <section class="adult-verification__filters surface-card">
<button <button
v-for="option in filterOptions" v-for="option in filterOptions"
:key="option.value" :key="option.value"
type="button" type="button"
:class="{ active: statusFilter === option.value }" :class="{ active: statusFilter === option.value }"
@click="changeFilter(option.value)" @click="changeFilter(option.value)"
> >
{{ option.label }} {{ option.label }}
</button> </button>
</section> </section>
<section class="adult-verification__list surface-card"> <section class="adult-verification__list surface-card">
<div v-if="loading" class="adult-verification__state">{{ $t('general.loading') }}</div> <div v-if="loading" class="adult-verification__state">{{ $t('general.loading') }}</div>
<div v-else-if="rows.length === 0" class="adult-verification__state">{{ $t('admin.adultVerification.empty') }}</div> <div v-else-if="rows.length === 0" class="adult-verification__state">{{ $t('admin.adultVerification.empty') }}</div>
<table v-else> <table v-else>
<thead> <thead>
<tr> <tr>
<th>{{ $t('admin.adultVerification.username') }}</th> <th>{{ $t('admin.adultVerification.username') }}</th>
<th>{{ $t('admin.adultVerification.age') }}</th> <th>{{ $t('admin.adultVerification.age') }}</th>
<th>{{ $t('admin.adultVerification.statusLabel') }}</th> <th>{{ $t('admin.adultVerification.statusLabel') }}</th>
<th>{{ $t('admin.adultVerification.requestLabel') }}</th> <th>{{ $t('admin.adultVerification.requestLabel') }}</th>
<th>{{ $t('admin.adultVerification.actions') }}</th> <th>{{ $t('admin.adultVerification.actions') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="row in rows" :key="row.id"> <tr v-for="row in rows" :key="row.id">
<td>{{ row.username }}</td> <td>{{ row.username }}</td>
<td>{{ row.age }}</td> <td>{{ row.age }}</td>
<td> <td>
<span class="adult-verification__badge" :class="`adult-verification__badge--${row.adultVerificationStatus}`"> <span class="adult-verification__badge" :class="`adult-verification__badge--${row.adultVerificationStatus}`">
{{ $t(`admin.adultVerification.status.${row.adultVerificationStatus}`) }} {{ $t(`admin.adultVerification.status.${row.adultVerificationStatus}`) }}
</span> </span>
</td> </td>
<td class="adult-verification__request"> <td class="adult-verification__request">
<template v-if="row.adultVerificationRequest"> <template v-if="row.adultVerificationRequest">
<strong>{{ row.adultVerificationRequest.originalName }}</strong> <strong>{{ row.adultVerificationRequest.originalName }}</strong>
<span v-if="row.adultVerificationRequest.note">{{ row.adultVerificationRequest.note }}</span> <span v-if="row.adultVerificationRequest.note">{{ row.adultVerificationRequest.note }}</span>
<span v-if="!row.adultVerificationDocumentAvailable" class="adult-verification__missing-file"> <span v-if="!row.adultVerificationDocumentAvailable" class="adult-verification__missing-file">
{{ $t('admin.adultVerification.documentMissing') }} {{ $t('admin.adultVerification.documentMissing') }}
</span> </span>
<button <button
type="button" type="button"
class="secondary" class="secondary"
:disabled="!row.adultVerificationDocumentAvailable" :disabled="!row.adultVerificationDocumentAvailable"
@click="openDocument(row)" @click="openDocument(row)"
> >
{{ $t('admin.adultVerification.openDocument') }} {{ $t('admin.adultVerification.openDocument') }}
</button> </button>
</template> </template>
<span v-else></span> <span v-else></span>
</td> </td>
<td class="adult-verification__actions"> <td class="adult-verification__actions">
<button type="button" @click="setStatus(row, 'approved')">{{ $t('admin.adultVerification.approve') }}</button> <button type="button" @click="setStatus(row, 'approved')">{{ $t('admin.adultVerification.approve') }}</button>
<button type="button" class="secondary" @click="setStatus(row, 'rejected')">{{ $t('admin.adultVerification.reject') }}</button> <button type="button" class="secondary" @click="setStatus(row, 'rejected')">{{ $t('admin.adultVerification.reject') }}</button>
<button <button
v-if="row.adultVerificationStatus !== 'pending'" v-if="row.adultVerificationStatus !== 'pending'"
type="button" type="button"
class="secondary" class="secondary"
@click="setStatus(row, 'pending')" @click="setStatus(row, 'pending')"
> >
{{ $t('admin.adultVerification.resetPending') }} {{ $t('admin.adultVerification.resetPending') }}
</button> </button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</section> </section>
<section v-if="previewUrl" class="adult-verification__preview surface-card"> <section v-if="previewUrl" class="adult-verification__preview surface-card">
<div class="adult-verification__preview-header"> <div class="adult-verification__preview-header">
<div> <div>
<strong>{{ $t('admin.adultVerification.previewTitle') }}</strong> <strong>{{ $t('admin.adultVerification.previewTitle') }}</strong>
<span v-if="previewRow">{{ previewRow.username }} · {{ previewRow.adultVerificationRequest?.originalName }}</span> <span v-if="previewRow">{{ previewRow.username }} · {{ previewRow.adultVerificationRequest?.originalName }}</span>
</div> </div>
<button type="button" class="secondary" @click="clearPreview"> <button type="button" class="secondary" @click="clearPreview">
{{ $t('admin.adultVerification.closePreview') }} {{ $t('admin.adultVerification.closePreview') }}
</button> </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>
</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>
@@ -195,6 +199,7 @@ export default {
.adult-verification { .adult-verification {
display: grid; display: grid;
gap: 18px; gap: 18px;
padding-bottom: 24px;
} }
.adult-verification__hero, .adult-verification__hero,

View File

@@ -1,78 +1,82 @@
<template> <template>
<div class="adult-verification"> <div class="contenthidden">
<section class="adult-verification__hero surface-card"> <div class="contentscroll">
<span class="adult-verification__eyebrow">Administration</span> <div class="adult-verification">
<h1>{{ $t('admin.eroticModeration.title') }}</h1> <section class="adult-verification__hero surface-card">
<p>{{ $t('admin.eroticModeration.intro') }}</p> <span class="adult-verification__eyebrow">Administration</span>
</section> <h1>{{ $t('admin.eroticModeration.title') }}</h1>
<p>{{ $t('admin.eroticModeration.intro') }}</p>
</section>
<section class="adult-verification__filters surface-card"> <section class="adult-verification__filters surface-card">
<button <button
v-for="option in filterOptions" v-for="option in filterOptions"
:key="option.value" :key="option.value"
type="button" type="button"
:class="{ active: statusFilter === option.value }" :class="{ active: statusFilter === option.value }"
@click="changeFilter(option.value)" @click="changeFilter(option.value)"
> >
{{ option.label }} {{ option.label }}
</button> </button>
</section> </section>
<section class="adult-verification__list surface-card"> <section class="adult-verification__list surface-card">
<div v-if="loading" class="adult-verification__state">{{ $t('general.loading') }}</div> <div v-if="loading" class="adult-verification__state">{{ $t('general.loading') }}</div>
<div v-else-if="rows.length === 0" class="adult-verification__state">{{ $t('admin.eroticModeration.empty') }}</div> <div v-else-if="rows.length === 0" class="adult-verification__state">{{ $t('admin.eroticModeration.empty') }}</div>
<table v-else> <table v-else>
<thead> <thead>
<tr> <tr>
<th>{{ $t('admin.eroticModeration.target') }}</th> <th>{{ $t('admin.eroticModeration.target') }}</th>
<th>{{ $t('admin.eroticModeration.owner') }}</th> <th>{{ $t('admin.eroticModeration.owner') }}</th>
<th>{{ $t('admin.eroticModeration.reporter') }}</th> <th>{{ $t('admin.eroticModeration.reporter') }}</th>
<th>{{ $t('admin.eroticModeration.reason') }}</th> <th>{{ $t('admin.eroticModeration.reason') }}</th>
<th>{{ $t('admin.eroticModeration.statusLabel') }}</th> <th>{{ $t('admin.eroticModeration.statusLabel') }}</th>
<th>{{ $t('admin.eroticModeration.meta') }}</th> <th>{{ $t('admin.eroticModeration.meta') }}</th>
<th>{{ $t('admin.eroticModeration.actions') }}</th> <th>{{ $t('admin.eroticModeration.actions') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="row in rows" :key="row.id"> <tr v-for="row in rows" :key="row.id">
<td class="adult-verification__request"> <td class="adult-verification__request">
<strong>{{ row.targetType === 'image' ? $t('admin.eroticModeration.image') : $t('admin.eroticModeration.video') }}</strong> <strong>{{ row.targetType === 'image' ? $t('admin.eroticModeration.image') : $t('admin.eroticModeration.video') }}</strong>
<span>{{ row.target?.title || '—' }}</span> <span>{{ row.target?.title || '—' }}</span>
<span v-if="row.target?.isModeratedHidden" class="adult-verification__badge adult-verification__badge--rejected"> <span v-if="row.target?.isModeratedHidden" class="adult-verification__badge adult-verification__badge--rejected">
{{ $t('admin.eroticModeration.hidden') }} {{ $t('admin.eroticModeration.hidden') }}
</span> </span>
<button v-if="row.target" type="button" class="secondary" @click="previewTarget(row)"> <button v-if="row.target" type="button" class="secondary" @click="previewTarget(row)">
{{ $t('admin.eroticModeration.preview') }} {{ $t('admin.eroticModeration.preview') }}
</button> </button>
</td> </td>
<td>{{ row.owner?.username || '—' }}</td> <td>{{ row.owner?.username || '—' }}</td>
<td>{{ row.reporter?.username || '—' }}</td> <td>{{ row.reporter?.username || '—' }}</td>
<td class="adult-verification__request"> <td class="adult-verification__request">
<strong>{{ $t(`socialnetwork.erotic.reportReasons.${row.reason}`) }}</strong> <strong>{{ $t(`socialnetwork.erotic.reportReasons.${row.reason}`) }}</strong>
<span v-if="row.note">{{ row.note }}</span> <span v-if="row.note">{{ row.note }}</span>
</td> </td>
<td> <td>
<span class="adult-verification__badge" :class="`adult-verification__badge--${row.status}`"> <span class="adult-verification__badge" :class="`adult-verification__badge--${row.status}`">
{{ $t(`admin.eroticModeration.status.${row.status}`) }} {{ $t(`admin.eroticModeration.status.${row.status}`) }}
</span> </span>
</td> </td>
<td class="adult-verification__request"> <td class="adult-verification__request">
<span>{{ formatDate(row.createdAt) }}</span> <span>{{ formatDate(row.createdAt) }}</span>
<span v-if="row.actionTaken">{{ $t(`admin.eroticModeration.actionLabels.${row.actionTaken}`) }}</span> <span v-if="row.actionTaken">{{ $t(`admin.eroticModeration.actionLabels.${row.actionTaken}`) }}</span>
<span v-if="row.handledAt">{{ formatDate(row.handledAt) }}</span> <span v-if="row.handledAt">{{ formatDate(row.handledAt) }}</span>
</td> </td>
<td class="adult-verification__actions"> <td class="adult-verification__actions">
<button type="button" @click="applyAction(row, 'dismiss')">{{ $t('admin.eroticModeration.dismiss') }}</button> <button type="button" @click="applyAction(row, 'dismiss')">{{ $t('admin.eroticModeration.dismiss') }}</button>
<button type="button" class="secondary" @click="applyAction(row, 'hide_content')">{{ $t('admin.eroticModeration.hide') }}</button> <button type="button" class="secondary" @click="applyAction(row, 'hide_content')">{{ $t('admin.eroticModeration.hide') }}</button>
<button type="button" class="secondary" @click="applyAction(row, 'restore_content')">{{ $t('admin.eroticModeration.restore') }}</button> <button type="button" class="secondary" @click="applyAction(row, 'restore_content')">{{ $t('admin.eroticModeration.restore') }}</button>
<button type="button" class="secondary" @click="applyAction(row, 'delete_content')">{{ $t('admin.eroticModeration.delete') }}</button> <button type="button" class="secondary" @click="applyAction(row, 'delete_content')">{{ $t('admin.eroticModeration.delete') }}</button>
<button type="button" class="secondary" @click="applyAction(row, 'block_uploads')">{{ $t('admin.eroticModeration.blockUploads') }}</button> <button type="button" class="secondary" @click="applyAction(row, 'block_uploads')">{{ $t('admin.eroticModeration.blockUploads') }}</button>
<button type="button" class="secondary" @click="applyAction(row, 'revoke_access')">{{ $t('admin.eroticModeration.revokeAccess') }}</button> <button type="button" class="secondary" @click="applyAction(row, 'revoke_access')">{{ $t('admin.eroticModeration.revokeAccess') }}</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</section> </section>
</div>
</div>
</div> </div>
</template> </template>
@@ -158,6 +162,7 @@ export default {
.adult-verification { .adult-verification {
display: grid; display: grid;
gap: 18px; gap: 18px;
padding-bottom: 24px;
} }
.adult-verification__hero, .adult-verification__hero,