feat: add premium 404 and Error pages, and fix hydration/build issues
This commit is contained in:
@@ -225,18 +225,14 @@ export default function ScheduleMatchPage() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="ui-form-field">
|
||||
<label className="text-label ml-0.5 mb-2 block">Data Limite de Repetição</label>
|
||||
<div className="relative group">
|
||||
<Calendar className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted group-focus-within:text-primary transition-colors z-10" />
|
||||
<input
|
||||
type="date"
|
||||
<div className="space-y-2">
|
||||
<DateTimePicker
|
||||
label="Data Limite de Repetição"
|
||||
value={recurrenceEndDate}
|
||||
onChange={(e) => setRecurrenceEndDate(e.target.value)}
|
||||
className="ui-input w-full pl-10 h-12 [color-scheme:dark] text-sm bg-surface"
|
||||
min={date ? date.split('T')[0] : undefined}
|
||||
onChange={setRecurrenceEndDate}
|
||||
mode="date"
|
||||
placeholder="Selecione a data limite"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-muted mt-2 px-1">
|
||||
Deixe em branco para repetir indefinidamente (será criado à medida que as peladas forem finalizadas).
|
||||
</p>
|
||||
|
||||
85
src/app/error.tsx
Normal file
85
src/app/error.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { AlertOctagon, RefreshCcw, Home } from 'lucide-react'
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
export default function Error({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string }
|
||||
reset: () => void
|
||||
}) {
|
||||
useEffect(() => {
|
||||
console.error(error)
|
||||
}, [error])
|
||||
|
||||
const primaryColor = '#ef4444'
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-zinc-950 flex flex-col items-center justify-center p-4 relative overflow-hidden">
|
||||
{/* Background Effects */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-20 pointer-events-none"
|
||||
style={{
|
||||
background: `radial-gradient(circle at 50% 50%, ${primaryColor}33 0%, transparent 70%)`
|
||||
}}
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="relative z-10 text-center space-y-8 max-w-lg"
|
||||
>
|
||||
{/* Icon Section */}
|
||||
<div className="relative inline-block">
|
||||
<div
|
||||
className="w-32 h-32 rounded-[2.5rem] bg-zinc-900 border border-white/5 flex items-center justify-center mx-auto shadow-2xl relative z-10"
|
||||
style={{ boxShadow: `0 20px 40px -10px ${primaryColor}22` }}
|
||||
>
|
||||
<AlertOctagon className="w-12 h-12 text-red-500 animate-pulse" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-4xl font-black italic tracking-tighter leading-none uppercase text-white">
|
||||
Erro no <span className="text-red-500 text-outline-sm">Sistema</span>
|
||||
</h1>
|
||||
<div className="h-1 w-20 bg-white/10 mx-auto rounded-full" />
|
||||
<p className="text-zinc-500 text-sm font-medium leading-relaxed px-4">
|
||||
Ocorreu um erro técnico inesperado. Nossa equipe de arbitragem (VAR) já foi notificada.
|
||||
</p>
|
||||
{error.digest && (
|
||||
<p className="text-[10px] font-mono text-zinc-700 uppercase tracking-widest">
|
||||
ID do Erro: {error.digest}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="pt-8 flex flex-col sm:flex-row items-center justify-center gap-4 px-4">
|
||||
<button
|
||||
onClick={() => reset()}
|
||||
className="ui-button w-full sm:w-auto px-8 h-14 flex items-center justify-center gap-2 group overflow-hidden relative bg-white text-black"
|
||||
>
|
||||
<span className="relative z-10 flex items-center gap-2 font-black uppercase tracking-widest text-[10px]">
|
||||
<RefreshCcw className="w-4 h-4 group-hover:rotate-180 transition-transform duration-500" />
|
||||
Tentar Novamente
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="/dashboard"
|
||||
className="ui-button w-full sm:w-auto px-8 h-14 flex items-center justify-center gap-2 group overflow-hidden relative border border-white/10 bg-zinc-900"
|
||||
>
|
||||
<span className="relative z-10 flex items-center gap-2 text-white font-black uppercase tracking-widest text-[10px]">
|
||||
<Home className="w-4 h-4" />
|
||||
Ir para o Painel
|
||||
</span>
|
||||
<div className="absolute inset-0 bg-white/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
</a>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,56 +1,81 @@
|
||||
'use client'
|
||||
|
||||
import { motion } from 'framer-motion'
|
||||
import { AlertTriangle, Home, Plus } from 'lucide-react'
|
||||
import { AlertTriangle, Home, Plus, Search, Ghost } from 'lucide-react'
|
||||
|
||||
export default function PeladaNotFound() {
|
||||
const primaryColor = '#ef4444' // Red for error
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-zinc-950 flex items-center justify-center p-4">
|
||||
{/* Background gradient */}
|
||||
<div className="fixed inset-0 bg-gradient-to-br from-red-950/10 via-zinc-950 to-zinc-950" />
|
||||
<div className="min-h-screen bg-zinc-950 flex flex-col items-center justify-center p-4 relative overflow-hidden">
|
||||
{/* Background Effects */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-20 pointer-events-none"
|
||||
style={{
|
||||
background: `radial-gradient(circle at 50% 50%, ${primaryColor}33 0%, transparent 70%)`
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Animación de Gramado/Grid */}
|
||||
<div className="absolute inset-0 opacity-[0.02] pointer-events-none"
|
||||
style={{ backgroundImage: `linear-gradient(${primaryColor} 1px, transparent 1px), linear-gradient(90deg, ${primaryColor} 1px, transparent 1px)`, backgroundSize: '60px 60px' }}
|
||||
/>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="relative text-center max-w-md"
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
className="relative z-10 text-center space-y-8 max-w-lg"
|
||||
>
|
||||
{/* Icon */}
|
||||
<div className="w-20 h-20 rounded-2xl bg-red-500/10 border border-red-500/20 flex items-center justify-center mx-auto mb-6">
|
||||
<AlertTriangle className="w-10 h-10 text-red-400" />
|
||||
{/* Icon Section */}
|
||||
<div className="relative inline-block">
|
||||
<div
|
||||
className="w-32 h-32 rounded-[2.5rem] bg-zinc-900 border border-white/5 flex items-center justify-center mx-auto shadow-2xl relative z-10"
|
||||
style={{ boxShadow: `0 20px 40px -10px ${primaryColor}22` }}
|
||||
>
|
||||
<Ghost className="w-16 h-16 text-white opacity-10 absolute" />
|
||||
<Search className="w-12 h-12" style={{ color: primaryColor }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="text-3xl font-bold text-white mb-3">
|
||||
Pelada não encontrada
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-4xl font-black italic tracking-tighter leading-none uppercase text-white">
|
||||
Pelada <span style={{ color: primaryColor }} className="text-outline-sm">Não</span> Encontrada
|
||||
</h1>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-zinc-400 mb-8">
|
||||
O grupo que você está procurando não existe ou foi removido.
|
||||
Verifique o endereço e tente novamente.
|
||||
<div className="h-1 w-20 bg-white/10 mx-auto rounded-full" />
|
||||
<p className="text-zinc-500 text-sm font-medium leading-relaxed px-4">
|
||||
O grupo que você buscou não está registrado em nosso sistema ou o endereço está incorreto.
|
||||
Verifique o link ou comece um novo esquadrão agora mesmo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
||||
<div className="pt-8 flex flex-col sm:flex-row items-center justify-center gap-4 px-4">
|
||||
<a
|
||||
href="http://localhost"
|
||||
className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-zinc-800 hover:bg-zinc-700 text-white font-medium rounded-xl transition-colors"
|
||||
href="/"
|
||||
className="ui-button w-full sm:w-auto px-8 h-14 flex items-center justify-center gap-2 group overflow-hidden relative border border-white/10 bg-zinc-900"
|
||||
>
|
||||
<Home className="w-5 h-5" />
|
||||
Voltar ao início
|
||||
<span className="relative z-10 flex items-center gap-2 text-white font-black uppercase tracking-widest text-[10px]">
|
||||
<Home className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
|
||||
Página Inicial
|
||||
</span>
|
||||
<div className="absolute inset-0 bg-white/5 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="http://localhost/create"
|
||||
className="inline-flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-emerald-500 to-emerald-600 hover:from-emerald-600 hover:to-emerald-700 text-white font-medium rounded-xl transition-colors"
|
||||
href="/create"
|
||||
className="ui-button w-full sm:w-auto px-8 h-14 flex items-center justify-center gap-2 group overflow-hidden relative"
|
||||
style={{ backgroundColor: '#10b981' }} // Use success color for creation
|
||||
>
|
||||
<Plus className="w-5 h-5" />
|
||||
Criar nova pelada
|
||||
<span className="relative z-10 flex items-center gap-2 text-black font-black uppercase tracking-widest text-[10px]">
|
||||
<Plus className="w-4 h-4 group-hover:scale-125 transition-transform" />
|
||||
Criar Nova Pelada
|
||||
</span>
|
||||
<div className="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 transition-opacity" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<p className="text-xs text-zinc-600 mt-8">
|
||||
Erro 404 - Grupo não existe no sistema
|
||||
{/* Funny Footer */}
|
||||
<p className="text-[10px] text-zinc-600 font-bold uppercase tracking-[0.3em] pt-12">
|
||||
Erro 404 • Grupo inexistente
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
81
src/app/not-found.tsx
Normal file
81
src/app/not-found.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import Link from 'next/link'
|
||||
import { getActiveGroup } from '@/lib/auth'
|
||||
import { Trophy, ArrowLeft, Ghost } from 'lucide-react'
|
||||
|
||||
export default async function NotFound() {
|
||||
// Tenta pegar o grupo para aplicar as cores personalizadas
|
||||
const group = await getActiveGroup().catch(() => null)
|
||||
const primaryColor = group?.primaryColor || '#10b981'
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-zinc-950 flex flex-col items-center justify-center p-4 relative overflow-hidden">
|
||||
{/* Background Effects */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-20 pointer-events-none"
|
||||
style={{
|
||||
background: `radial-gradient(circle at 50% 50%, ${primaryColor}44 0%, transparent 70%)`
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Animación de Gramado/Grid */}
|
||||
<div className="absolute inset-0 opacity-[0.03] pointer-events-none"
|
||||
style={{ backgroundImage: `linear-gradient(${primaryColor} 1px, transparent 1px), linear-gradient(90deg, ${primaryColor} 1px, transparent 1px)`, backgroundSize: '50px 50px' }}
|
||||
/>
|
||||
|
||||
<div className="relative z-10 text-center space-y-8 max-w-lg">
|
||||
{/* Icon Section */}
|
||||
<div className="relative inline-block">
|
||||
<div
|
||||
className="w-32 h-32 rounded-[2.5rem] bg-zinc-900 border border-white/5 flex items-center justify-center mx-auto shadow-2xl relative z-10"
|
||||
style={{ boxShadow: `0 20px 40px -10px ${primaryColor}33` }}
|
||||
>
|
||||
<Ghost className="w-16 h-16 text-white opacity-20 absolute" />
|
||||
<Trophy className="w-16 h-16" style={{ color: primaryColor }} />
|
||||
</div>
|
||||
{/* Pulsing rings */}
|
||||
<div className="absolute inset-0 rounded-full animate-ping opacity-20 scale-150" style={{ backgroundColor: primaryColor }} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<h1 className="text-8xl font-black italic tracking-tighter leading-none uppercase">
|
||||
4<span style={{ color: primaryColor }} className="text-outline-sm">0</span>4
|
||||
</h1>
|
||||
<div className="h-1 w-20 bg-white/10 mx-auto rounded-full" />
|
||||
<h2 className="text-2xl font-bold uppercase tracking-tight text-white/90">
|
||||
Você furou a pelada!
|
||||
</h2>
|
||||
<p className="text-zinc-500 text-sm font-medium leading-relaxed">
|
||||
A página que você está procurando foi substituída ou levada para o vestiário.
|
||||
Parece que esse lance foi <span className="italic">out</span>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="pt-8 flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className="ui-button w-full sm:w-auto px-8 h-14 flex items-center justify-center gap-2 group overflow-hidden relative"
|
||||
style={{ backgroundColor: primaryColor }}
|
||||
>
|
||||
<span className="relative z-10 flex items-center gap-2 text-black font-black uppercase tracking-widest text-xs">
|
||||
<ArrowLeft className="w-4 h-4 group-hover:-translate-x-1 transition-transform" />
|
||||
Voltar para o Jogo
|
||||
</span>
|
||||
<div className="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 transition-opacity" />
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/"
|
||||
className="ui-button-ghost w-full sm:w-auto px-8 h-14 text-xs font-black uppercase tracking-widest border-white/10 hover:bg-white/5"
|
||||
>
|
||||
Página Inicial
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Funny Footer */}
|
||||
<p className="text-[10px] text-zinc-600 font-bold uppercase tracking-[0.3em] pt-12">
|
||||
Cuidado com o carrinho • TemFut Engine
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user