223 lines
13 KiB
Vue
223 lines
13 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
|
|
import type { AuthSession } from '../types/awards'
|
|
|
|
const props = defineProps<{
|
|
accountOpen: boolean
|
|
privacyOpen: boolean
|
|
deleteConfirm: boolean
|
|
session: AuthSession | null
|
|
privacyContentHtml: string
|
|
privacyEmail: string
|
|
accountActionError: string
|
|
accountActionSuccess: string
|
|
authLoading: boolean
|
|
}>()
|
|
|
|
defineEmits<{
|
|
'close-account': []
|
|
'close-privacy': []
|
|
'open-privacy': []
|
|
'request-delete': []
|
|
'cancel-delete': []
|
|
logout: []
|
|
'bind-team-twitch': []
|
|
'confirm-delete': []
|
|
}>()
|
|
|
|
const twitchUserId = computed(() => props.session?.twitchUserId ?? '')
|
|
const role = computed(() => props.session?.role ?? 'viewer')
|
|
const isTeamSession = computed(() => Boolean(props.session?.teamLogin))
|
|
const canBindTwitch = computed(() => isTeamSession.value && !props.session?.mustChangePassword)
|
|
</script>
|
|
|
|
<template>
|
|
<Teleport to="body">
|
|
<div
|
|
v-if="accountOpen"
|
|
style="position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(40,24,70,.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);"
|
|
@click.self="$emit('close-account')"
|
|
>
|
|
<div style="position:relative;width:100%;max-width:480px;background:#fff;border-radius:24px;box-shadow:0 40px 90px rgba(40,24,70,.4);overflow:hidden;">
|
|
<div style="display:flex;align-items:center;justify-content:space-between;padding:24px 28px 18px;border-bottom:1px solid #f1ecfb;">
|
|
<div>
|
|
<div style="font-size:11px;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:#8b6cdb;margin-bottom:4px;">Mein Profil</div>
|
|
<h2 style="font-family:'Cormorant Garamond',serif;font-weight:700;font-size:24px;margin:0;color:#3f3556;">@{{ twitchUserId }}</h2>
|
|
</div>
|
|
<button
|
|
style="width:34px;height:34px;border-radius:50%;border:none;background:#f1ecfb;color:#8b6cdb;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;"
|
|
@click="$emit('close-account')"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div style="padding:24px 28px;display:flex;flex-direction:column;gap:16px;">
|
|
<div style="display:flex;align-items:center;gap:10px;padding:13px 16px;border-radius:14px;background:#f6f1fd;border:1px solid #ede4fb;">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="#9146FF">
|
|
<path d="M4 2L2.4 6v14.5h5V23h2.7l2.5-2.5h4L21.6 16V2H4zm15.3 13.1l-2.9 2.9h-4.4l-2.5 2.5v-2.5H6.7V3.7h12.6v11.4z" />
|
|
<path d="M11.1 7.1h1.7v5h-1.7zM15.7 7.1h1.7v5h-1.7z" />
|
|
</svg>
|
|
<span style="font-size:14px;color:#5f44ad;font-weight:500;">Angemeldet über Twitch</span>
|
|
</div>
|
|
<div style="padding:16px;border-radius:14px;background:#fafafa;border:1px solid #f0eafc;">
|
|
<p style="font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;color:#a99fc0;margin:0 0 10px;">Gespeicherte Daten</p>
|
|
<div style="display:flex;flex-direction:column;gap:7px;">
|
|
<div style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Twitch-ID</span>
|
|
<span style="font-weight:600;color:#3f3556;">@{{ twitchUserId }}</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Rolle</span>
|
|
<span style="font-weight:700;color:#8b6cdb;text-transform:uppercase;font-size:11px;letter-spacing:1px;">{{ role }}</span>
|
|
</div>
|
|
<div v-if="session?.teamLogin" style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Team-Login</span>
|
|
<span style="font-weight:600;color:#3f3556;">@{{ session.teamLogin }}</span>
|
|
</div>
|
|
<div v-if="session?.boundTwitchUserId" style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Gebundenes Twitch</span>
|
|
<span style="font-weight:600;color:#3f3556;">@{{ session.boundTwitchUserId }}</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Einreichungen</span>
|
|
<span style="font-weight:600;color:#3f3556;">Clips, Votes, Nominierungen</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;font-size:13.5px;">
|
|
<span style="color:#6f6685;">Löschfrist</span>
|
|
<span style="font-weight:600;color:#059669;">März 2027 (auto.)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<form
|
|
v-if="isTeamSession"
|
|
style="padding:16px;border-radius:14px;background:#f8f5ff;border:1px solid #ede4fb;display:grid;gap:12px;"
|
|
@submit.prevent="$emit('bind-team-twitch')"
|
|
>
|
|
<div>
|
|
<p style="font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;color:#8b6cdb;margin:0 0 4px;">Twitch verbinden</p>
|
|
<p style="font-size:12.5px;color:#6f6685;margin:0;line-height:1.45;">Verbinde deinen privaten Twitch-Account über den offiziellen Twitch Login. Danach kannst du dich im Admin-Panel per Twitch anmelden.</p>
|
|
</div>
|
|
<div v-if="session?.boundTwitchUserId" style="display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 12px;border-radius:12px;background:white;border:1px solid #ede4fb;font-size:13px;">
|
|
<span style="color:#6f6685;">Aktuell verbunden</span>
|
|
<span style="font-weight:800;color:#3f3556;">@{{ session.boundTwitchUserId }}</span>
|
|
</div>
|
|
<p v-if="session?.mustChangePassword" style="font-size:12.5px;color:#b45309;margin:0;font-weight:700;">Bitte ändere zuerst dein temporäres Passwort.</p>
|
|
<p v-if="accountActionError" style="font-size:12.5px;color:#be123c;margin:0;font-weight:700;">{{ accountActionError }}</p>
|
|
<p v-if="accountActionSuccess" style="font-size:12.5px;color:#047857;margin:0;font-weight:700;">{{ accountActionSuccess }}</p>
|
|
<button
|
|
:disabled="authLoading || !canBindTwitch"
|
|
type="submit"
|
|
style="display:flex;align-items:center;justify-content:center;gap:8px;padding:11px 14px;border-radius:12px;border:none;background:#6f4fd1;color:white;font-family:'Outfit',sans-serif;font-size:13.5px;font-weight:800;cursor:pointer;disabled:opacity:.6;"
|
|
>
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
<path d="M4 2L2.4 6v14.5h5V23h2.7l2.5-2.5h4L21.6 16V2H4zm15.3 13.1l-2.9 2.9h-4.4l-2.5 2.5v-2.5H6.7V3.7h12.6v11.4z" />
|
|
<path d="M11.1 7.1h1.7v5h-1.7zM15.7 7.1h1.7v5h-1.7z" />
|
|
</svg>
|
|
{{ authLoading ? 'Twitch wird geöffnet...' : session?.boundTwitchUserId ? 'Twitch neu verbinden' : 'Mit Twitch verbinden' }}
|
|
</button>
|
|
</form>
|
|
<button
|
|
style="display:flex;align-items:center;gap:8px;padding:12px 16px;border-radius:12px;border:1px solid #ede4fb;background:#f9f6ff;color:#6a4fb8;font-family:'Outfit',sans-serif;font-size:13.5px;font-weight:600;cursor:pointer;text-align:left;width:100%;"
|
|
@click="$emit('open-privacy')"
|
|
>
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
|
</svg>
|
|
Datenschutzerklärung lesen
|
|
</button>
|
|
<button
|
|
style="display:flex;align-items:center;gap:8px;padding:12px 16px;border-radius:12px;border:1px solid #e2e8f0;background:#f8fafc;color:#64748b;font-family:'Outfit',sans-serif;font-size:13.5px;font-weight:600;cursor:pointer;text-align:left;width:100%;"
|
|
@click="$emit('logout')"
|
|
>
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
|
<polyline points="16 17 21 12 16 7" />
|
|
<line x1="21" y1="12" x2="9" y2="12" />
|
|
</svg>
|
|
Abmelden
|
|
</button>
|
|
<template v-if="!deleteConfirm">
|
|
<button
|
|
style="display:flex;align-items:center;gap:8px;padding:12px 16px;border-radius:12px;border:1px solid #fecdd3;background:#fff5f5;color:#e11d48;font-family:'Outfit',sans-serif;font-size:13.5px;font-weight:600;cursor:pointer;text-align:left;width:100%;"
|
|
@click="$emit('request-delete')"
|
|
>
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="3 6 5 6 21 6" />
|
|
<path d="M19 6l-1 14H6L5 6" />
|
|
<path d="M10 11v6M14 11v6" />
|
|
</svg>
|
|
Meine Daten löschen (Löschrecht Art. 17 DSGVO)
|
|
</button>
|
|
</template>
|
|
<template v-else>
|
|
<div style="padding:16px;border-radius:14px;background:#fff5f5;border:1.5px solid #fecdd3;">
|
|
<p style="font-size:13.5px;color:#9f1239;font-weight:600;margin:0 0 6px;">Alle deine Daten werden sofort gelöscht.</p>
|
|
<p style="font-size:12.5px;color:#e11d48;margin:0 0 14px;line-height:1.5;">Das umfasst deine Votes, Nominierungen und Clip-Einreichungen. Diese Aktion kann nicht rückgängig gemacht werden.</p>
|
|
<p v-if="accountActionError" style="font-size:12.5px;color:#be123c;margin:0 0 12px;line-height:1.5;font-weight:600;">{{ accountActionError }}</p>
|
|
<div style="display:flex;gap:8px;">
|
|
<button :disabled="authLoading" style="flex:1;padding:10px;border-radius:10px;border:1px solid #e6dcf6;background:white;color:#6f6685;font-family:'Outfit',sans-serif;font-weight:600;font-size:13px;cursor:pointer;" @click="$emit('cancel-delete')">Abbrechen</button>
|
|
<button :disabled="authLoading" style="flex:1;padding:10px;border-radius:10px;border:none;background:#e11d48;color:white;font-family:'Outfit',sans-serif;font-weight:700;font-size:13px;cursor:pointer;" @click="$emit('confirm-delete')">
|
|
{{ authLoading ? 'Löscht …' : 'Jetzt löschen' }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Teleport>
|
|
|
|
<Teleport to="body">
|
|
<div
|
|
v-if="privacyOpen"
|
|
style="position:fixed;inset:0;z-index:400;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(40,24,70,.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);"
|
|
@click.self="$emit('close-privacy')"
|
|
>
|
|
<div style="position:relative;width:100%;max-width:680px;max-height:88vh;overflow:hidden;display:flex;flex-direction:column;background:#fff;border-radius:24px;box-shadow:0 40px 90px rgba(40,24,70,.4);">
|
|
<div style="display:flex;align-items:center;justify-content:space-between;padding:24px 32px 18px;border-bottom:1px solid #f1ecfb;flex:none;">
|
|
<div>
|
|
<div style="font-size:11px;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:#8b6cdb;margin-bottom:4px;">Rechtliches</div>
|
|
<h2 style="font-family:'Cormorant Garamond',serif;font-weight:700;font-size:26px;margin:0;color:#3f3556;">Datenschutzerklärung</h2>
|
|
</div>
|
|
<button style="width:34px;height:34px;border-radius:50%;border:none;background:#f1ecfb;color:#8b6cdb;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;" @click="$emit('close-privacy')">✕</button>
|
|
</div>
|
|
<div style="overflow-y:auto;padding:28px 32px;flex:1;font-family:'Outfit',sans-serif;font-size:14px;line-height:1.65;color:#6f6685;">
|
|
<template v-if="privacyContentHtml">
|
|
<div class="app-shell-privacy-content" v-html="privacyContentHtml" />
|
|
</template>
|
|
<template v-else>
|
|
<div style="background:#f9f6ff;border:1px solid #ede4fb;border-radius:14px;padding:16px;">
|
|
<h3 style="font-size:15px;font-weight:700;color:#3f3556;margin:0 0 8px;">Datenschutztext wird geladen</h3>
|
|
<p style="margin:0;">Die Datenschutzerklärung wird aus der Landingpage-Konfiguration geladen.</p>
|
|
</div>
|
|
</template>
|
|
<p v-if="privacyEmail" style="font-size:12px;color:#a99fc0;margin:18px 0 0;">Kontakt: {{ privacyEmail }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Teleport>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.app-shell-privacy-content :deep(p) {
|
|
margin: 0 0 14px;
|
|
}
|
|
|
|
.app-shell-privacy-content :deep(p:last-child),
|
|
.app-shell-privacy-content :deep(ul:last-child),
|
|
.app-shell-privacy-content :deep(ol:last-child) {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.app-shell-privacy-content :deep(ul),
|
|
.app-shell-privacy-content :deep(ol) {
|
|
margin: 0 0 14px 20px;
|
|
padding-left: 16px;
|
|
}
|
|
|
|
.app-shell-privacy-content :deep(li) {
|
|
margin: 3px 0;
|
|
}
|
|
</style>
|