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>
|
||||||
|
|
||||||
<div className="ui-form-field">
|
<div className="space-y-2">
|
||||||
<label className="text-label ml-0.5 mb-2 block">Data Limite de Repetição</label>
|
<DateTimePicker
|
||||||
<div className="relative group">
|
label="Data Limite de Repetição"
|
||||||
<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"
|
|
||||||
value={recurrenceEndDate}
|
value={recurrenceEndDate}
|
||||||
onChange={(e) => setRecurrenceEndDate(e.target.value)}
|
onChange={setRecurrenceEndDate}
|
||||||
className="ui-input w-full pl-10 h-12 [color-scheme:dark] text-sm bg-surface"
|
mode="date"
|
||||||
min={date ? date.split('T')[0] : undefined}
|
placeholder="Selecione a data limite"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<p className="text-[10px] text-muted mt-2 px-1">
|
<p className="text-[10px] text-muted mt-2 px-1">
|
||||||
Deixe em branco para repetir indefinidamente (será criado à medida que as peladas forem finalizadas).
|
Deixe em branco para repetir indefinidamente (será criado à medida que as peladas forem finalizadas).
|
||||||
</p>
|
</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'
|
'use client'
|
||||||
|
|
||||||
import { motion } from 'framer-motion'
|
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() {
|
export default function PeladaNotFound() {
|
||||||
|
const primaryColor = '#ef4444' // Red for error
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-zinc-950 flex items-center justify-center p-4">
|
<div className="min-h-screen bg-zinc-950 flex flex-col items-center justify-center p-4 relative overflow-hidden">
|
||||||
{/* Background gradient */}
|
{/* Background Effects */}
|
||||||
<div className="fixed inset-0 bg-gradient-to-br from-red-950/10 via-zinc-950 to-zinc-950" />
|
<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
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
className="relative text-center max-w-md"
|
className="relative z-10 text-center space-y-8 max-w-lg"
|
||||||
>
|
>
|
||||||
{/* Icon */}
|
{/* Icon Section */}
|
||||||
<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">
|
<div className="relative inline-block">
|
||||||
<AlertTriangle className="w-10 h-10 text-red-400" />
|
<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>
|
</div>
|
||||||
|
|
||||||
{/* Title */}
|
<div className="space-y-4">
|
||||||
<h1 className="text-3xl font-bold text-white mb-3">
|
<h1 className="text-4xl font-black italic tracking-tighter leading-none uppercase text-white">
|
||||||
Pelada não encontrada
|
Pelada <span style={{ color: primaryColor }} className="text-outline-sm">Não</span> Encontrada
|
||||||
</h1>
|
</h1>
|
||||||
|
<div className="h-1 w-20 bg-white/10 mx-auto rounded-full" />
|
||||||
{/* Description */}
|
<p className="text-zinc-500 text-sm font-medium leading-relaxed px-4">
|
||||||
<p className="text-zinc-400 mb-8">
|
O grupo que você buscou não está registrado em nosso sistema ou o endereço está incorreto.
|
||||||
O grupo que você está procurando não existe ou foi removido.
|
Verifique o link ou comece um novo esquadrão agora mesmo.
|
||||||
Verifique o endereço e tente novamente.
|
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Actions */}
|
<div className="pt-8 flex flex-col sm:flex-row items-center justify-center gap-4 px-4">
|
||||||
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
||||||
<a
|
<a
|
||||||
href="http://localhost"
|
href="/"
|
||||||
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"
|
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" />
|
<span className="relative z-10 flex items-center gap-2 text-white font-black uppercase tracking-widest text-[10px]">
|
||||||
Voltar ao início
|
<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>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="http://localhost/create"
|
href="/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"
|
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" />
|
<span className="relative z-10 flex items-center gap-2 text-black font-black uppercase tracking-widest text-[10px]">
|
||||||
Criar nova pelada
|
<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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Funny Footer */}
|
||||||
<p className="text-xs text-zinc-600 mt-8">
|
<p className="text-[10px] text-zinc-600 font-bold uppercase tracking-[0.3em] pt-12">
|
||||||
Erro 404 - Grupo não existe no sistema
|
Erro 404 • Grupo inexistente
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</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