Files
TurboTrades/frontend/src/views/BannedPage.vue
iDefineHD af5c32561a
All checks were successful
Build Frontend / Build Frontend (push) Successful in 23s
update the ban page
2026-01-11 04:36:42 +00:00

526 lines
12 KiB
Vue

<template>
<div class="banned-page">
<div class="banned-container">
<!-- Icon -->
<div class="icon-wrapper">
<ShieldAlert class="banned-icon" />
</div>
<!-- Title -->
<h1 class="banned-title">Account Suspended</h1>
<!-- Ban Details and Appeal Section -->
<div class="ban-details-container">
<div v-if="banInfo" class="ban-details">
<div class="detail-item">
<span class="detail-label">Reason:</span>
<span class="detail-value">{{
banInfo.reason || "Violation of Terms of Service"
}}</span>
</div>
<div v-if="banInfo.bannedAt" class="detail-item">
<span class="detail-label">Banned on:</span>
<span class="detail-value">{{ formatDate(banInfo.bannedAt) }}</span>
</div>
<div
v-if="banInfo.bannedUntil && !banInfo.isPermanent"
class="detail-item"
>
<span class="detail-label">Ban expires:</span>
<span class="detail-value">{{
formatDate(banInfo.bannedUntil)
}}</span>
</div>
<div v-if="banInfo.isPermanent" class="detail-item permanent-ban">
<AlertCircle :size="18" />
<span>This is a permanent ban</span>
</div>
</div>
<div class="appeal-section">
<p class="appeal-text">
If you believe this ban was made in error, you can submit an appeal.
</p>
<a href="/support" class="appeal-btn">
<Mail :size="20" />
<span>Contact Support</span>
</a>
</div>
</div>
<!-- Logout Button -->
<button @click="handleLogout" class="logout-btn">
<LogOut :size="20" />
<span>Logout</span>
</button>
<!-- Footer Info -->
<div class="banned-footer">
<p>For more information, please review our</p>
<div class="footer-links">
<a href="/terms" class="footer-link">Terms of Service</a>
<span class="separator"></span>
<a href="/privacy" class="footer-link">Privacy Policy</a>
</div>
</div>
<!-- Social Links -->
<div class="social-links">
<a
:href="socialLinks.twitter"
target="_blank"
rel="noopener noreferrer"
class="social-link"
aria-label="X (Twitter)"
>
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
<path
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
/>
</svg>
</a>
<a
:href="socialLinks.discord"
target="_blank"
rel="noopener noreferrer"
class="social-link"
aria-label="Discord"
>
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
<path
d="M20.317 4.37a19.791 19.791 0 00-4.885-1.515.074.074 0 00-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 00-5.487 0 12.64 12.64 0 00-.617-1.25.077.077 0 00-.079-.037A19.736 19.736 0 003.677 4.37a.07.07 0 00-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 00.031.057 19.9 19.9 0 005.993 3.03.078.078 0 00.084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 00-.041-.106 13.107 13.107 0 01-1.872-.892.077.077 0 01-.008-.128 10.2 10.2 0 00.372-.292.074.074 0 01.077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 01.078.01c.12.098.246.198.373.292a.077.077 0 01-.006.127 12.299 12.299 0 01-1.873.892.077.077 0 00-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 00.084.028 19.839 19.839 0 006.002-3.03.077.077 0 00.032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 00-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"
/>
</svg>
</a>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/stores/auth";
import { ShieldAlert, AlertCircle, Info, Mail, LogOut } from "lucide-vue-next";
import axios from "@/utils/axios";
const router = useRouter();
const authStore = useAuthStore();
const socialLinks = ref({
twitter: "https://x.com",
discord: "https://discord.gg",
});
const banInfo = computed(() => {
if (!authStore.user) return null;
return {
reason: authStore.user.ban?.reason,
bannedUntil: authStore.user.ban?.expires,
isPermanent:
authStore.user.ban?.permanent || !authStore.user.ban?.bannedUntil,
};
});
const formatDate = (date) => {
if (!date) return "";
const d = new Date(date);
return d.toLocaleString("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
});
};
const handleLogout = async () => {
await authStore.logout();
router.push("/");
};
const fetchSocialLinks = async () => {
try {
const response = await axios.get("/api/config/public");
if (response.data.success && response.data.config.social) {
const social = response.data.config.social;
if (social.twitter) {
socialLinks.value.twitter = social.twitter;
}
if (social.discord) {
socialLinks.value.discord = social.discord;
}
}
} catch (error) {
console.error("Failed to fetch social links:", error);
// Keep default values if fetch fails
}
};
onMounted(() => {
// If user is not banned, redirect to home
if (!authStore.isBanned) {
router.push("/");
}
// Fetch social links
fetchSocialLinks();
});
</script>
<style scoped>
.banned-page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
padding: 2rem;
position: relative;
overflow: hidden;
}
.banned-page::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(
circle at 20% 50%,
rgba(239, 68, 68, 0.1) 0%,
transparent 50%
),
radial-gradient(
circle at 80% 80%,
rgba(220, 38, 38, 0.1) 0%,
transparent 50%
);
animation: pulse 4s ease-in-out infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.banned-container {
position: relative;
z-index: 1;
max-width: 600px;
width: 100%;
text-align: center;
background: rgba(30, 30, 46, 0.9);
backdrop-filter: blur(20px);
border-radius: 1.5rem;
padding: 3rem 2rem;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(239, 68, 68, 0.3);
}
.icon-wrapper {
margin-bottom: 2rem;
display: inline-block;
}
.banned-icon {
width: 80px;
height: 80px;
color: #ef4444;
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
10%,
30%,
50%,
70%,
90% {
transform: translateX(-5px);
}
20%,
40%,
60%,
80% {
transform: translateX(5px);
}
}
.banned-title {
font-size: 2.5rem;
font-weight: 700;
color: #ef4444;
margin-bottom: 1rem;
line-height: 1.2;
}
.banned-message {
font-size: 1.125rem;
color: #d1d5db;
margin-bottom: 2rem;
line-height: 1.6;
}
.detail-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.detail-item:last-child {
border-bottom: none;
}
.detail-label {
font-size: 0.875rem;
color: #9ca3af;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.detail-value {
font-size: 0.9375rem;
color: #ffffff;
font-weight: 600;
text-align: right;
}
.permanent-ban {
justify-content: center;
gap: 0.5rem;
color: #ef4444;
font-weight: 600;
font-size: 0.9375rem;
}
.info-box {
display: flex;
gap: 1rem;
padding: 1.25rem;
background: rgba(59, 130, 246, 0.1);
border: 1px solid rgba(59, 130, 246, 0.3);
border-radius: 1rem;
margin-bottom: 2rem;
text-align: left;
}
.info-icon {
flex-shrink: 0;
color: #3b82f6;
margin-top: 0.125rem;
}
.info-content {
flex: 1;
}
.info-title {
font-size: 0.9375rem;
font-weight: 600;
color: #ffffff;
margin: 0 0 0.5rem 0;
}
.info-text {
font-size: 0.875rem;
color: #d1d5db;
margin: 0;
line-height: 1.5;
}
.ban-details-container {
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 1rem;
padding: 1.5rem;
margin-bottom: 2rem;
}
.ban-details {
margin-bottom: 1.5rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid rgba(239, 68, 68, 0.2);
text-align: left;
}
.appeal-section {
margin: 0;
padding: 0;
background: none;
border: none;
text-align: center;
}
.appeal-text {
font-size: 0.9375rem;
color: #d1d5db;
margin: 0 0 1rem 0;
text-align: center;
}
.appeal-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 0.875rem 2rem;
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: white;
text-decoration: none;
border-radius: 0.5rem;
font-weight: 600;
font-size: 1rem;
transition: all 0.3s;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
border: 1px solid rgba(59, 130, 246, 0.5);
width: 100%;
max-width: 300px;
}
.appeal-btn:hover {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.5);
}
.appeal-btn:active {
transform: translateY(0);
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4);
}
.logout-btn {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1.5rem;
background: rgba(255, 255, 255, 0.05);
color: #d1d5db;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 0.5rem;
font-weight: 600;
font-size: 0.9375rem;
cursor: pointer;
transition: all 0.2s;
}
.logout-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: #ffffff;
border-color: rgba(255, 255, 255, 0.2);
}
.banned-footer {
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.banned-footer p {
color: #9ca3af;
font-size: 0.875rem;
margin: 0 0 0.5rem 0;
}
.footer-links {
display: flex;
justify-content: center;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
}
.footer-link {
color: #3b82f6;
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
transition: color 0.2s;
}
.footer-link:hover {
color: #60a5fa;
text-decoration: underline;
}
.separator {
color: #6b7280;
font-size: 0.875rem;
}
.social-links {
display: flex;
justify-content: center;
gap: 1rem;
margin-top: 2rem;
}
.social-link {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border-radius: 0.75rem;
background: rgba(255, 255, 255, 0.05);
color: #9ca3af;
transition: all 0.2s;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.social-link:hover {
background: rgba(59, 130, 246, 0.2);
color: #3b82f6;
border-color: rgba(59, 130, 246, 0.3);
transform: translateY(-2px);
}
@media (max-width: 640px) {
.banned-container {
padding: 2rem 1.5rem;
}
.banned-title {
font-size: 2rem;
}
.banned-icon {
width: 60px;
height: 60px;
}
.detail-item {
flex-direction: column;
align-items: flex-start;
gap: 0.25rem;
}
.detail-value {
text-align: left;
}
.appeal-btn {
max-width: 100%;
}
}
</style>