Refactor: Implement DashboardLayout, fix mobile nav, and resolve scroll issues

This commit is contained in:
ren
2026-01-29 14:41:46 +01:00
parent 0a04e0817d
commit 811c78ffa5
171 changed files with 1678 additions and 23983 deletions

5
.gitignore vendored
View File

@@ -32,3 +32,8 @@ next-env.d.ts
# Security # Security
server-settings.json server-settings.json
.env
auth-otp.json
# Local dev
local_Caddyfile

View File

@@ -1,13 +1,11 @@
'use client' 'use client'
import { Sidebar, Header, MobileNav } from '@/components/layout' import { DashboardLayout } from '@/components/layout/DashboardLayout'
import { AlertPanel, useAlerts } from '@/components/alerts' import { AlertPanel, useAlerts } from '@/components/alerts'
import { useSidebar } from '@/app/providers'
import { RefreshCw } from 'lucide-react' import { RefreshCw } from 'lucide-react'
export default function AlertsPage() { export default function AlertsPage() {
const { isOpen, toggle, close } = useSidebar() const { regenerateAlerts, dismissAll } = useAlerts()
const { regenerateAlerts, dismissAll, unreadCount } = useAlerts()
const handleRegenerateAlerts = () => { const handleRegenerateAlerts = () => {
regenerateAlerts() regenerateAlerts()
@@ -18,16 +16,10 @@ export default function AlertsPage() {
} }
return ( return (
<div className="min-h-screen bg-slate-950"> <DashboardLayout title="Alertas">
<Sidebar isOpen={isOpen} onClose={close} unreadAlertsCount={unreadCount} /> <div className="space-y-6">
<div className="lg:ml-64 min-h-screen flex flex-col">
<Header onMenuClick={toggle} title="Alertas" />
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20 lg:pb-8">
<div className="max-w-4xl mx-auto">
{/* Action Buttons */} {/* Action Buttons */}
<div className="flex flex-wrap gap-3 mb-6"> <div className="flex flex-wrap gap-3">
<button <button
onClick={handleRegenerateAlerts} onClick={handleRegenerateAlerts}
className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/20" className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/20"
@@ -49,10 +41,6 @@ export default function AlertsPage() {
<AlertPanel /> <AlertPanel />
</div> </div>
</div> </div>
</main> </DashboardLayout>
<MobileNav unreadAlertsCount={unreadCount} />
</div>
</div>
) )
} }

View File

@@ -0,0 +1,25 @@
import { NextResponse } from 'next/server';
import TelegramBot from 'node-telegram-bot-api';
import { generateOTP, saveOTP } from '@/lib/otp';
export async function POST() {
const token = process.env.TELEGRAM_BOT_TOKEN;
const chatId = process.env.TELEGRAM_CHAT_ID;
if (!token || !chatId) {
console.error("Telegram credentials missing");
return NextResponse.json({ error: 'Telegram not configured' }, { status: 500 });
}
const otp = generateOTP();
saveOTP(otp);
const bot = new TelegramBot(token, { polling: false });
try {
await bot.sendMessage(chatId, `🔐 Your Login Code: ${otp}`);
return NextResponse.json({ success: true });
} catch (error: any) {
console.error('Telegram Error:', error);
return NextResponse.json({ error: 'Failed to send message: ' + error.message }, { status: 500 });
}
}

View File

@@ -0,0 +1,24 @@
import { NextResponse } from 'next/server';
import { verifyOTP } from '@/lib/otp';
import { cookies } from 'next/headers';
export async function POST(req: Request) {
try {
const { code } = await req.json();
if (verifyOTP(code)) {
// Set cookie
cookies().set('auth_token', 'true', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24 * 7, // 1 week
path: '/'
});
return NextResponse.json({ success: true });
}
return NextResponse.json({ error: 'Invalid Code' }, { status: 401 });
} catch (error) {
return NextResponse.json({ error: 'Invalid Request' }, { status: 400 });
}
}

17
app/api/sync/route.ts Normal file
View File

@@ -0,0 +1,17 @@
import { NextResponse } from 'next/server';
import { getDatabase, saveDatabase } from '@/lib/server-db';
export async function GET() {
const data = getDatabase();
return NextResponse.json(data);
}
export async function POST(req: Request) {
try {
const body = await req.json();
saveDatabase(body);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json({ error: 'Invalid Data' }, { status: 400 });
}
}

View File

@@ -1,27 +1,12 @@
'use client' 'use client'
import { Sidebar, Header, MobileNav } from '@/components/layout' import { DashboardLayout } from '@/components/layout/DashboardLayout'
import { BudgetSection } from '@/components/budget' import { BudgetSection } from '@/components/budget'
import { useSidebar } from '@/app/providers'
import { useAlerts } from '@/components/alerts'
export default function BudgetPage() { export default function BudgetPage() {
const { isOpen, close, toggle } = useSidebar()
const { unreadCount } = useAlerts()
return ( return (
<div className="flex min-h-screen bg-slate-950"> <DashboardLayout title="Presupuesto">
<Sidebar isOpen={isOpen} onClose={close} unreadAlertsCount={unreadCount} />
<div className="flex-1 flex flex-col min-h-screen">
<Header onMenuClick={toggle} title="Presupuesto" />
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20">
<BudgetSection /> <BudgetSection />
</main> </DashboardLayout>
<MobileNav unreadAlertsCount={unreadCount} />
</div>
</div>
) )
} }

View File

@@ -1,27 +1,12 @@
'use client'; 'use client';
import { Sidebar, Header, MobileNav } from '@/components/layout'; import { DashboardLayout } from '@/components/layout/DashboardLayout';
import { CardSection } from '@/components/cards'; import { CardSection } from '@/components/cards';
import { useSidebar } from '@/app/providers';
import { useAlerts } from '@/components/alerts';
export default function CardsPage() { export default function CardsPage() {
const { isOpen, toggle, close } = useSidebar();
const { unreadCount } = useAlerts();
return ( return (
<div className="min-h-screen bg-slate-950"> <DashboardLayout title="Tarjetas de Crédito">
<Sidebar isOpen={isOpen} onClose={close} unreadAlertsCount={unreadCount} />
<div className="lg:ml-64 min-h-screen flex flex-col">
<Header onMenuClick={toggle} title="Tarjetas de Crédito" />
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20">
<CardSection /> <CardSection />
</main> </DashboardLayout>
</div>
<MobileNav unreadAlertsCount={unreadCount} />
</div>
); );
} }

View File

@@ -1,32 +1,12 @@
'use client' 'use client'
import { Sidebar, Header, MobileNav } from '@/components/layout' import { DashboardLayout } from '@/components/layout/DashboardLayout'
import { DebtSection } from '@/components/debts' import { DebtSection } from '@/components/debts'
import { useSidebar } from '@/app/providers'
import { useAlerts } from '@/components/alerts'
export default function DebtsPage() { export default function DebtsPage() {
const { isOpen, close, open } = useSidebar()
const { unreadCount } = useAlerts()
return ( return (
<div className="min-h-screen bg-slate-950"> <DashboardLayout title="Deudas">
{/* Sidebar */}
<Sidebar isOpen={isOpen} onClose={close} unreadAlertsCount={unreadCount} />
{/* Main content */}
<div className="lg:ml-64 min-h-screen flex flex-col">
{/* Header */}
<Header onMenuClick={open} title="Deudas" />
{/* Page content */}
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20 lg:pb-8">
<DebtSection /> <DebtSection />
</main> </DashboardLayout>
</div>
{/* Mobile Navigation */}
<MobileNav unreadAlertsCount={unreadCount} />
</div>
) )
} }

165
app/incomes/page.tsx Normal file
View File

@@ -0,0 +1,165 @@
'use client'
import { useState } from 'react'
import { useFinanzasStore } from '@/lib/store'
import { Plus, Trash2, TrendingUp, DollarSign } from 'lucide-react'
import { format } from 'date-fns'
import { es } from 'date-fns/locale'
import { DashboardLayout } from '@/components/layout/DashboardLayout'
export default function IncomesPage() {
const incomes = useFinanzasStore((state) => state.incomes) || []
const addIncome = useFinanzasStore((state) => state.addIncome)
const removeIncome = useFinanzasStore((state) => state.removeIncome)
const [newIncome, setNewIncome] = useState({
amount: '',
description: '',
category: 'salary' as const,
})
const handleAdd = () => {
if (!newIncome.amount || !newIncome.description) return
addIncome({
amount: parseFloat(newIncome.amount),
description: newIncome.description,
category: newIncome.category,
date: new Date().toISOString(),
})
setNewIncome({ amount: '', description: '', category: 'salary' })
}
const totalIncomes = incomes.reduce((acc, curr) => acc + curr.amount, 0)
return (
<DashboardLayout title="Ingresos">
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-3xl font-bold flex items-center gap-2 text-white">
<TrendingUp className="text-green-500" /> Ingresos
</h2>
<div className="text-right">
<p className="text-sm text-gray-400">Total Acumulado</p>
<p className="text-2xl font-bold text-green-400">
${totalIncomes.toLocaleString()}
</p>
</div>
</div>
<div className="grid md:grid-cols-3 gap-6">
{/* Formulario */}
<div className="bg-slate-800 border border-slate-700 rounded-xl md:col-span-1 h-fit overflow-hidden">
<div className="p-6 border-b border-slate-700">
<h3 className="font-semibold text-lg text-white">Nuevo Ingreso</h3>
</div>
<div className="p-6 space-y-4">
<div>
<label className="text-sm text-gray-400 block mb-2">Descripción</label>
<input
placeholder="Ej. Pago Freelance"
value={newIncome.description}
onChange={(e) =>
setNewIncome({ ...newIncome, description: e.target.value })
}
className="w-full bg-slate-700 border-slate-600 border rounded-lg px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
</div>
<div>
<label className="text-sm text-gray-400 block mb-2">Monto</label>
<div className="relative">
<DollarSign className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<input
type="number"
placeholder="0.00"
value={newIncome.amount}
onChange={(e) =>
setNewIncome({ ...newIncome, amount: e.target.value })
}
className="w-full pl-9 bg-slate-700 border-slate-600 border rounded-lg px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
</div>
</div>
<div>
<label className="text-sm text-gray-400 block mb-2">Categoría</label>
<select
className="w-full bg-slate-700 border border-slate-600 rounded-lg px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
value={newIncome.category}
onChange={(e) =>
setNewIncome({
...newIncome,
category: e.target.value as any,
})
}
>
<option value="salary">Salario</option>
<option value="freelance">Freelance</option>
<option value="business">Negocio</option>
<option value="gift">Regalo</option>
<option value="other">Otro</option>
</select>
</div>
<button
onClick={handleAdd}
className="w-full bg-emerald-600 hover:bg-emerald-700 text-white font-semibold py-2 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors"
>
<Plus className="w-4 h-4" /> Agregar Ingreso
</button>
</div>
</div>
{/* Lista */}
<div className="bg-slate-800 border border-slate-700 rounded-xl md:col-span-2 overflow-hidden">
<div className="p-6 border-b border-slate-700">
<h3 className="font-semibold text-lg text-white">Historial de Ingresos</h3>
</div>
<div className="p-6">
{incomes.length === 0 ? (
<p className="text-center text-gray-500 py-8">
No hay ingresos registrados aún.
</p>
) : (
<div className="space-y-4">
{incomes
.sort(
(a, b) =>
new Date(b.date).getTime() - new Date(a.date).getTime()
)
.map((income) => (
<div
key={income.id}
className="flex items-center justify-between p-4 bg-slate-700/50 rounded-lg border border-slate-700 hover:border-slate-600 transition-colors"
>
<div>
<p className="font-semibold text-white">
{income.description}
</p>
<p className="text-xs text-gray-400 capitalize">
{income.category} {' '}
{format(new Date(income.date), "d 'de' MMMM", {
locale: es,
})}
</p>
</div>
<div className="flex items-center gap-4">
<span className="text-emerald-400 font-mono font-bold">
+${income.amount.toLocaleString()}
</span>
<button
onClick={() => removeIncome(income.id)}
className="text-slate-500 hover:text-red-400 transition-colors"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
</div>
</DashboardLayout>
)
}

115
app/login/page.tsx Normal file
View File

@@ -0,0 +1,115 @@
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Lock, Send, Loader2 } from 'lucide-react';
export default function LoginPage() {
const [step, setStep] = useState<'initial' | 'verify'>('initial');
const [code, setCode] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const router = useRouter();
const sendCode = async () => {
setLoading(true);
setError('');
try {
const res = await fetch('/api/auth/send', { method: 'POST' });
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Failed to send code');
setStep('verify');
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};
const verifyCode = async () => {
setLoading(true);
setError('');
try {
const res = await fetch('/api/auth/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Invalid code');
// Redirect
router.push('/');
router.refresh();
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<div className="flex min-h-screen items-center justify-center bg-gray-900 text-white p-4">
<div className="w-full max-w-md bg-gray-800 rounded-lg shadow-xl p-8 border border-gray-700">
<div className="flex flex-col items-center mb-8">
<div className="bg-blue-600 p-3 rounded-full mb-4">
<Lock className="w-8 h-8 text-white" />
</div>
<h1 className="text-2xl font-bold">Secure Access</h1>
<p className="text-gray-400 mt-2 text-center">
Finanzas Personales
</p>
</div>
{error && (
<div className="bg-red-900/50 border border-red-500 text-red-200 p-3 rounded mb-4 text-sm">
{error}
</div>
)}
{step === 'initial' ? (
<div className="space-y-4">
<p className="text-gray-300 text-center text-sm">
Click below to receive a login code via Telegram.
</p>
<button
onClick={sendCode}
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-500 text-white font-semibold py-3 px-4 rounded-lg transition flex items-center justify-center gap-2 disabled:opacity-50"
>
{loading ? <Loader2 className="animate-spin" /> : <Send size={20} />}
Send Code to Telegram
</button>
</div>
) : (
<div className="space-y-4">
<p className="text-gray-300 text-center text-sm">
Enter the 6-digit code sent to your Telegram.
</p>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="123456"
className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-3 text-center text-2xl tracking-widest focus:outline-none focus:ring-2 focus:ring-blue-500"
maxLength={6}
/>
<button
onClick={verifyCode}
disabled={loading || code.length < 4}
className="w-full bg-green-600 hover:bg-green-500 text-white font-semibold py-3 px-4 rounded-lg transition flex items-center justify-center gap-2 disabled:opacity-50"
>
{loading ? <Loader2 className="animate-spin" /> : 'Verify & Login'}
</button>
<button
onClick={() => setStep('initial')}
className="w-full text-gray-400 hover:text-white text-sm"
>
Cancel
</button>
</div>
)}
</div>
</div>
);
}

View File

@@ -1,25 +1,21 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Sidebar, Header, MobileNav } from '@/components/layout'
import { SummarySection, QuickActions, RecentActivity } from '@/components/dashboard' import { SummarySection, QuickActions, RecentActivity } from '@/components/dashboard'
import { useSidebar } from '@/app/providers'
import { useFinanzasStore } from '@/lib/store' import { useFinanzasStore } from '@/lib/store'
import { AlertBanner, useAlerts } from '@/components/alerts' import { AlertBanner, useAlerts } from '@/components/alerts'
import { AddDebtModal } from '@/components/modals/AddDebtModal' import { AddDebtModal } from '@/components/modals/AddDebtModal'
import { AddCardModal } from '@/components/modals/AddCardModal' import { AddCardModal } from '@/components/modals/AddCardModal'
import { AddPaymentModal } from '@/components/modals/AddPaymentModal' import { AddPaymentModal } from '@/components/modals/AddPaymentModal'
import { DashboardLayout } from '@/components/layout/DashboardLayout'
export default function Home() { export default function Home() {
// Sidebar control
const sidebar = useSidebar()
// Datos del store // Datos del store
const markAlertAsRead = useFinanzasStore((state) => state.markAlertAsRead) const markAlertAsRead = useFinanzasStore((state) => state.markAlertAsRead)
const deleteAlert = useFinanzasStore((state) => state.deleteAlert) const deleteAlert = useFinanzasStore((state) => state.deleteAlert)
// Alertas // Alertas
const { unreadAlerts, unreadCount, regenerateAlerts } = useAlerts() const { unreadAlerts, regenerateAlerts } = useAlerts()
// Estados locales para modales // Estados locales para modales
const [isAddDebtModalOpen, setIsAddDebtModalOpen] = useState(false) const [isAddDebtModalOpen, setIsAddDebtModalOpen] = useState(false)
@@ -31,23 +27,6 @@ export default function Home() {
regenerateAlerts() regenerateAlerts()
}, [regenerateAlerts]) }, [regenerateAlerts])
// Efecto para manejar resize de ventana
useEffect(() => {
const handleResize = () => {
if (window.innerWidth >= 1024) {
sidebar.open()
} else {
sidebar.close()
}
}
// Estado inicial
handleResize()
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [sidebar])
// Handlers para modales // Handlers para modales
const handleAddDebt = () => { const handleAddDebt = () => {
setIsAddDebtModalOpen(true) setIsAddDebtModalOpen(true)
@@ -65,22 +44,8 @@ export default function Home() {
const topAlerts = unreadAlerts.slice(0, 3) const topAlerts = unreadAlerts.slice(0, 3)
return ( return (
<div className="flex min-h-screen bg-slate-950"> <DashboardLayout title="Dashboard">
{/* Sidebar */} <div className="space-y-6">
<Sidebar
isOpen={sidebar.isOpen}
onClose={sidebar.close}
unreadAlertsCount={unreadCount}
/>
{/* Main content */}
<div className="flex flex-1 flex-col lg:ml-0">
{/* Header */}
<Header onMenuClick={sidebar.toggle} title="Dashboard" />
{/* Main content area */}
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20 lg:pb-8">
<div className="mx-auto max-w-7xl space-y-6">
{/* Alertas destacadas */} {/* Alertas destacadas */}
{topAlerts.length > 0 && ( {topAlerts.length > 0 && (
<div className="space-y-3"> <div className="space-y-3">
@@ -108,11 +73,6 @@ export default function Home() {
{/* Actividad reciente */} {/* Actividad reciente */}
<RecentActivity limit={5} /> <RecentActivity limit={5} />
</div> </div>
</main>
</div>
{/* Mobile navigation */}
<MobileNav unreadAlertsCount={unreadCount} />
{/* Modales */} {/* Modales */}
<AddDebtModal <AddDebtModal
@@ -129,6 +89,6 @@ export default function Home() {
isOpen={isAddPaymentModalOpen} isOpen={isAddPaymentModalOpen}
onClose={() => setIsAddPaymentModalOpen(false)} onClose={() => setIsAddPaymentModalOpen(false)}
/> />
</div> </DashboardLayout>
) )
} }

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import { createContext, useContext, useState, ReactNode } from "react"; import { createContext, useContext, useState, ReactNode } from "react";
import { DataSync } from "@/components/DataSync";
interface SidebarContextType { interface SidebarContextType {
isOpen: boolean; isOpen: boolean;
@@ -27,6 +28,7 @@ export function Providers({ children }: { children: ReactNode }) {
open: openSidebar, open: openSidebar,
}} }}
> >
<DataSync />
{children} {children}
</SidebarContext.Provider> </SidebarContext.Provider>
); );

View File

@@ -7,6 +7,7 @@ import { formatCurrency } from '@/lib/utils'
import { Zap, Droplets, Flame, Wifi, TrendingUp, TrendingDown, Plus, History } from 'lucide-react' import { Zap, Droplets, Flame, Wifi, TrendingUp, TrendingDown, Plus, History } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { AddServiceModal } from '@/components/modals/AddServiceModal' import { AddServiceModal } from '@/components/modals/AddServiceModal'
import { DashboardLayout } from '@/components/layout/DashboardLayout'
const SERVICES = [ const SERVICES = [
{ id: 'electricity', label: 'Luz (Electricidad)', icon: Zap, color: 'text-yellow-400', bg: 'bg-yellow-400/10' }, { id: 'electricity', label: 'Luz (Electricidad)', icon: Zap, color: 'text-yellow-400', bg: 'bg-yellow-400/10' },
@@ -20,12 +21,13 @@ export default function ServicesPage() {
const [isAddModalOpen, setIsAddModalOpen] = useState(false) const [isAddModalOpen, setIsAddModalOpen] = useState(false)
return ( return (
<DashboardLayout title="Servicios">
<div className="space-y-6"> <div className="space-y-6">
{/* Header */} {/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4"> <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div> <div>
<h1 className="text-2xl font-bold text-white">Servicios y Predicciones</h1> <h2 className="text-2xl font-bold text-white">Servicios y Predicciones</h2>
<p className="text-slate-400 text-sm">Gestiona tus consumos de Luz, Agua y Gas.</p> <p className="text-slate-400 text-sm">Gestiona tus consumos de Luz, Agua y Gas.</p>
</div> </div>
<button <button
@@ -138,5 +140,6 @@ export default function ServicesPage() {
<AddServiceModal isOpen={isAddModalOpen} onClose={() => setIsAddModalOpen(false)} /> <AddServiceModal isOpen={isAddModalOpen} onClose={() => setIsAddModalOpen(false)} />
</div> </div>
</DashboardLayout>
) )
} }

View File

@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'
import { Save, Plus, Trash2, Bot, MessageSquare, Key, Link as LinkIcon, Lock, Send, CheckCircle2, XCircle, Loader2, Sparkles, Box } from 'lucide-react' import { Save, Plus, Trash2, Bot, MessageSquare, Key, Link as LinkIcon, Lock, Send, CheckCircle2, XCircle, Loader2, Sparkles, Box } from 'lucide-react'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { AIServiceConfig, AppSettings } from '@/lib/types' import { AIServiceConfig, AppSettings } from '@/lib/types'
import { DashboardLayout } from '@/components/layout/DashboardLayout'
export default function SettingsPage() { export default function SettingsPage() {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
@@ -159,11 +160,12 @@ export default function SettingsPage() {
if (loading) return <div className="p-8 text-center text-slate-400">Cargando configuración...</div> if (loading) return <div className="p-8 text-center text-slate-400">Cargando configuración...</div>
return ( return (
<DashboardLayout title="Configuración">
<div className="max-w-4xl mx-auto space-y-8 pb-10"> <div className="max-w-4xl mx-auto space-y-8 pb-10">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-2xl font-bold text-white">Configuración</h1> <h2 className="text-2xl font-bold text-white">Configuración</h2>
<p className="text-slate-400 text-sm">Gestiona la integración con Telegram e Inteligencia Artificial.</p> <p className="text-slate-400 text-sm">Gestiona la integración con Telegram e Inteligencia Artificial.</p>
</div> </div>
<button <button
@@ -365,5 +367,6 @@ export default function SettingsPage() {
</div> </div>
</section> </section>
</div> </div>
</DashboardLayout>
) )
} }

64
components/DataSync.tsx Normal file
View File

@@ -0,0 +1,64 @@
'use client';
import { useEffect, useRef } from 'react';
import { useFinanzasStore } from '@/lib/store';
export function DataSync() {
// const isHydrated = useFinanzasStore(state => state._hasHydrated);
const store = useFinanzasStore();
const initialized = useRef(false);
useEffect(() => {
async function init() {
if (initialized.current) return;
initialized.current = true;
try {
const res = await fetch('/api/sync');
if (!res.ok) return;
const serverData = await res.json();
// Simple logic: if server has data (debts or cards or something), trust server.
const hasServerData = serverData.fixedDebts?.length > 0 || serverData.creditCards?.length > 0;
if (hasServerData) {
console.log("Sync: Hydrating from Server");
useFinanzasStore.setState(serverData);
} else {
// Server is empty, but we might have local data.
// Push local data to server to initialize it.
console.log("Sync: Initializing Server with Local Data");
syncToServer(useFinanzasStore.getState());
}
} catch (e) {
console.error("Sync init error", e);
}
}
init();
}, []);
// Sync on change
useEffect(() => {
if (!initialized.current) return;
const unsub = useFinanzasStore.subscribe((state) => {
syncToServer(state);
});
return () => unsub();
}, []);
return null;
}
let timeout: NodeJS.Timeout;
function syncToServer(state: any) {
clearTimeout(timeout);
timeout = setTimeout(() => {
fetch('/api/sync', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(state)
}).catch(e => console.error("Sync error", e));
}, 2000); // Debounce 2s
}

View File

@@ -0,0 +1,60 @@
'use client'
import { ReactNode, useEffect } from 'react'
import { Sidebar, Header, MobileNav } from '@/components/layout'
import { useSidebar } from '@/app/providers'
import { useAlerts } from '@/components/alerts'
interface DashboardLayoutProps {
children: ReactNode
title: string
}
export function DashboardLayout({ children, title }: DashboardLayoutProps) {
const { isOpen, toggle, close, open } = useSidebar()
const { unreadCount } = useAlerts()
// Ensure sidebar is open on desktop mount
useEffect(() => {
const handleResize = () => {
if (window.innerWidth >= 1024) {
open()
} else {
close()
}
}
// Initial check
handleResize()
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [open, close])
return (
<div className="flex min-h-screen bg-slate-950">
{/* Sidebar */}
<Sidebar
isOpen={isOpen}
onClose={close}
unreadAlertsCount={unreadCount}
/>
{/* Main content wrapper */}
<div className="flex flex-1 flex-col lg:ml-0 min-w-0">
{/* Header */}
<Header onMenuClick={toggle} title={title} />
{/* Page content */}
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-24 lg:pb-8">
<div className="mx-auto max-w-7xl h-full">
{children}
</div>
</main>
</div>
{/* Mobile Navigation */}
<MobileNav unreadAlertsCount={unreadCount} />
</div>
)
}

View File

@@ -8,6 +8,7 @@ import {
Bell, Bell,
Lightbulb, Lightbulb,
Settings, Settings,
TrendingUp,
X, X,
} from 'lucide-react'; } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
@@ -22,6 +23,7 @@ interface SidebarProps {
const navigationItems = [ const navigationItems = [
{ name: 'Dashboard', href: '/', icon: LayoutDashboard }, { name: 'Dashboard', href: '/', icon: LayoutDashboard },
{ name: 'Ingresos', href: '/incomes', icon: TrendingUp },
{ name: 'Deudas', href: '/debts', icon: Wallet }, { name: 'Deudas', href: '/debts', icon: Wallet },
{ name: 'Tarjetas', href: '/cards', icon: CreditCard }, { name: 'Tarjetas', href: '/cards', icon: CreditCard },
{ name: 'Presupuesto', href: '/budget', icon: PiggyBank }, { name: 'Presupuesto', href: '/budget', icon: PiggyBank },

29
data/db.json Normal file
View File

@@ -0,0 +1,29 @@
{
"fixedDebts": [],
"variableDebts": [
{
"name": "netflix",
"amount": 5000,
"date": "2026-01-29T00:00:00.000Z",
"category": "shopping",
"isPaid": false,
"id": "f2e424ca-5f07-4f57-9386-822354e0ee1e"
},
{
"name": "youtube",
"amount": 2500,
"date": "2026-01-29T00:00:00.000Z",
"category": "shopping",
"isPaid": false,
"id": "621c3caf-529b-4c33-b46f-3d86b119dd75"
}
],
"creditCards": [],
"cardPayments": [],
"monthlyBudgets": [],
"currentMonth": 1,
"currentYear": 2026,
"alerts": [],
"serviceBills": [],
"incomes": []
}

1
dist/404.html vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
self.__BUILD_MANIFEST={__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/_error":["static/chunks/pages/_error-7ba65e1336b92748.js"],sortedPages:["/_app","/_error"]},self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View File

@@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[71],{2489:function(e,t,r){r.d(t,{Z:function(){return n}});let n=(0,r(8755).Z)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]])},4147:function(e,t,r){let n;r.d(t,{Z:function(){return u}});var o={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};let a=new Uint8Array(16),i=[];for(let e=0;e<256;++e)i.push((e+256).toString(16).slice(1));var u=function(e,t,r){return!o.randomUUID||t||e?function(e,t,r){let o=(e=e||{}).random??e.rng?.()??function(){if(!n){if("undefined"==typeof crypto||!crypto.getRandomValues)throw Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");n=crypto.getRandomValues.bind(crypto)}return n(a)}();if(o.length<16)throw Error("Random bytes length must be >= 16");if(o[6]=15&o[6]|64,o[8]=63&o[8]|128,t){if((r=r||0)<0||r+16>t.length)throw RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let e=0;e<16;++e)t[r+e]=o[e];return t}return function(e,t=0){return(i[e[t+0]]+i[e[t+1]]+i[e[t+2]]+i[e[t+3]]+"-"+i[e[t+4]]+i[e[t+5]]+"-"+i[e[t+6]]+i[e[t+7]]+"-"+i[e[t+8]]+i[e[t+9]]+"-"+i[e[t+10]]+i[e[t+11]]+i[e[t+12]]+i[e[t+13]]+i[e[t+14]]+i[e[t+15]]).toLowerCase()}(o)}(e,t,r):o.randomUUID()}},6885:function(e,t,r){r.d(t,{tJ:function(){return o}});let n=e=>t=>{try{let r=e(t);if(r instanceof Promise)return r;return{then:e=>n(e)(r),catch(e){return this}}}catch(e){return{then(e){return this},catch:t=>n(t)(e)}}},o=(e,t)=>(r,o,a)=>{let i,u={storage:function(e,t){let r;try{r=e()}catch(e){return}return{getItem:e=>{var t;let n=e=>null===e?null:JSON.parse(e,void 0),o=null!=(t=r.getItem(e))?t:null;return o instanceof Promise?o.then(n):n(o)},setItem:(e,t)=>r.setItem(e,JSON.stringify(t,void 0)),removeItem:e=>r.removeItem(e)}}(()=>localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...t},l=!1,s=0,c=new Set,d=new Set,f=u.storage;if(!f)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${u.name}', the given storage is currently unavailable.`),r(...e)},o,a);let m=()=>{let e=u.partialize({...o()});return f.setItem(u.name,{state:e,version:u.version})},g=a.setState;a.setState=(e,t)=>(g(e,t),m());let h=e((...e)=>(r(...e),m()),o,a);a.getInitialState=()=>h;let p=()=>{var e,t;if(!f)return;let a=++s;l=!1,c.forEach(e=>{var t;return e(null!=(t=o())?t:h)});let g=(null==(t=u.onRehydrateStorage)?void 0:t.call(u,null!=(e=o())?e:h))||void 0;return n(f.getItem.bind(f))(u.name).then(e=>{if(e){if("number"!=typeof e.version||e.version===u.version)return[!1,e.state];if(u.migrate){let t=u.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}return[!1,void 0]}).then(e=>{var t;if(a!==s)return;let[n,l]=e;if(r(i=u.merge(l,null!=(t=o())?t:h),!0),n)return m()}).then(()=>{a===s&&(null==g||g(i,void 0),i=o(),l=!0,d.forEach(e=>e(i)))}).catch(e=>{a===s&&(null==g||g(void 0,e))})};return a.persist={setOptions:e=>{u={...u,...e},e.storage&&(f=e.storage)},clearStorage:()=>{null==f||f.removeItem(u.name)},getOptions:()=>u,rehydrate:()=>p(),hasHydrated:()=>l,onHydrate:e=>(c.add(e),()=>{c.delete(e)}),onFinishHydration:e=>(d.add(e),()=>{d.delete(e)})},u.skipHydration||p(),i||h}},3011:function(e,t,r){r.d(t,{U:function(){return l}});var n=r(2265);let o=e=>{let t;let r=new Set,n=(e,n)=>{let o="function"==typeof e?e(t):e;if(!Object.is(o,t)){let e=t;t=(null!=n?n:"object"!=typeof o||null===o)?o:Object.assign({},t,o),r.forEach(r=>r(t,e))}},o=()=>t,a={setState:n,getState:o,getInitialState:()=>i,subscribe:e=>(r.add(e),()=>r.delete(e))},i=t=e(n,o,a);return a},a=e=>e?o(e):o,i=e=>e,u=e=>{let t=a(e),r=e=>(function(e,t=i){let r=n.useSyncExternalStore(e.subscribe,n.useCallback(()=>t(e.getState()),[e,t]),n.useCallback(()=>t(e.getInitialState()),[e,t]));return n.useDebugValue(r),r})(t,e);return Object.assign(r,t),r},l=e=>e?u(e):u}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[409],{7589:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_not-found/page",function(){return n(3634)}])},3634:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}}),n(7043);let i=n(7437);n(2265);let o={fontFamily:'system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"',height:"100vh",textAlign:"center",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"},l={display:"inline-block"},r={display:"inline-block",margin:"0 20px 0 0",padding:"0 23px 0 0",fontSize:24,fontWeight:500,verticalAlign:"top",lineHeight:"49px"},d={fontSize:14,fontWeight:400,lineHeight:"49px",margin:0};function s(){return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)("title",{children:"404: This page could not be found."}),(0,i.jsx)("div",{style:o,children:(0,i.jsxs)("div",{children:[(0,i.jsx)("style",{dangerouslySetInnerHTML:{__html:"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}),(0,i.jsx)("h1",{className:"next-error-h1",style:r,children:"404"}),(0,i.jsx)("div",{style:l,children:(0,i.jsx)("h2",{style:d,children:"This page could not be found."})})]})})]})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},function(e){e.O(0,[971,117,744],function(){return e(e.s=7589)}),_N_E=e.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[78],{4033:function(e,s,n){Promise.resolve().then(n.bind(n,5949))},5949:function(e,s,n){"use strict";n.r(s),n.d(s,{default:function(){return c}});var l=n(7437),t=n(553),i=n(3263),a=n(9294);let r=(0,n(8755).Z)("refresh-cw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);function c(){let{isOpen:e,toggle:s,close:n}=(0,a.A)(),{regenerateAlerts:c,dismissAll:o,unreadCount:u}=(0,i.Z7)();return(0,l.jsxs)("div",{className:"min-h-screen bg-slate-950",children:[(0,l.jsx)(t.YE,{isOpen:e,onClose:n,unreadAlertsCount:u}),(0,l.jsxs)("div",{className:"lg:ml-64 min-h-screen flex flex-col",children:[(0,l.jsx)(t.h4,{onMenuClick:s,title:"Alertas"}),(0,l.jsx)("main",{className:"flex-1 p-4 md:p-6 lg:p-8 pb-20 lg:pb-8",children:(0,l.jsxs)("div",{className:"max-w-4xl mx-auto",children:[(0,l.jsxs)("div",{className:"flex flex-wrap gap-3 mb-6",children:[(0,l.jsxs)("button",{onClick:()=>{c()},className:"inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500/20",children:[(0,l.jsx)(r,{className:"h-4 w-4"}),"Regenerar Alertas"]}),(0,l.jsx)("button",{onClick:()=>{o()},className:"inline-flex items-center gap-2 px-4 py-2 bg-slate-800 hover:bg-slate-700 text-slate-300 hover:text-white text-sm font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-slate-500/20",children:"Limpiar Todas"})]}),(0,l.jsx)("div",{className:"w-full",children:(0,l.jsx)(i.KG,{})})]})}),(0,l.jsx)(t.zM,{unreadAlertsCount:u})]})]})}}},function(e){e.O(0,[697,71,796,489,971,117,744],function(){return e(e.s=4033)}),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[185],{1556:function(e,n,t){Promise.resolve().then(t.bind(t,9294)),Promise.resolve().then(t.t.bind(t,8925,23)),Promise.resolve().then(t.t.bind(t,7960,23))},9294:function(e,n,t){"use strict";t.d(n,{A:function(){return u},Providers:function(){return s}});var r=t(7437),o=t(2265);let i=(0,o.createContext)(void 0);function s(e){let{children:n}=e,[t,s]=(0,o.useState)(!0);return(0,r.jsx)(i.Provider,{value:{isOpen:t,toggle:()=>s(e=>!e),close:()=>s(!1),open:()=>s(!0)},children:n})}function u(){let e=(0,o.useContext)(i);if(void 0===e)throw Error("useSidebar must be used within a Providers");return e}},7960:function(){},8925:function(e){e.exports={style:{fontFamily:"'__Inter_f367f3', '__Inter_Fallback_f367f3'",fontStyle:"normal"},className:"__className_f367f3",variable:"__variable_f367f3"}}},function(e){e.O(0,[832,971,117,744],function(){return e(e.s=1556)}),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[744],{2300:function(e,n,t){Promise.resolve().then(t.t.bind(t,2846,23)),Promise.resolve().then(t.t.bind(t,9107,23)),Promise.resolve().then(t.t.bind(t,1060,23)),Promise.resolve().then(t.t.bind(t,4707,23)),Promise.resolve().then(t.t.bind(t,80,23)),Promise.resolve().then(t.t.bind(t,6423,23))}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[971,117],function(){return n(4278),n(2300)}),_N_E=e.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[888],{1597:function(n,_,u){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return u(8141)}])}},function(n){var _=function(_){return n(n.s=_)};n.O(0,[774,179],function(){return _(1597),_(7253)}),_N_E=n.O()}]);

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[820],{1981:function(n,_,u){(window.__NEXT_P=window.__NEXT_P||[]).push(["/_error",function(){return u(8529)}])}},function(n){n.O(0,[888,774,179],function(){return n(n.s=1981)}),_N_E=n.O()}]);

View File

@@ -0,0 +1 @@
!function(){"use strict";var e,t,n,r,o,u,i,c,f,a={},l={};function s(e){var t=l[e];if(void 0!==t)return t.exports;var n=l[e]={exports:{}},r=!0;try{a[e].call(n.exports,n,n.exports,s),r=!1}finally{r&&delete l[e]}return n.exports}s.m=a,e=[],s.O=function(t,n,r,o){if(n){o=o||0;for(var u=e.length;u>0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[n,r,o];return}for(var i=1/0,u=0;u<e.length;u++){for(var n=e[u][0],r=e[u][1],o=e[u][2],c=!0,f=0;f<n.length;f++)i>=o&&Object.keys(s.O).every(function(e){return s.O[e](n[f])})?n.splice(f--,1):(c=!1,o<i&&(i=o));if(c){e.splice(u--,1);var a=r();void 0!==a&&(t=a)}}return t},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,{a:t}),t},n=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},s.t=function(e,r){if(1&r&&(e=this(e)),8&r||"object"==typeof e&&e&&(4&r&&e.__esModule||16&r&&"function"==typeof e.then))return e;var o=Object.create(null);s.r(o);var u={};t=t||[null,n({}),n([]),n(n)];for(var i=2&r&&e;"object"==typeof i&&!~t.indexOf(i);i=n(i))Object.getOwnPropertyNames(i).forEach(function(t){u[t]=function(){return e[t]}});return u.default=function(){return e},s.d(o,u),o},s.d=function(e,t){for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.f={},s.e=function(e){return Promise.all(Object.keys(s.f).reduce(function(t,n){return s.f[n](e,t),t},[]))},s.u=function(e){},s.miniCssF=function(e){},s.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r={},o="_N_E:",s.l=function(e,t,n,u){if(r[e]){r[e].push(t);return}if(void 0!==n)for(var i,c,f=document.getElementsByTagName("script"),a=0;a<f.length;a++){var l=f[a];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==o+n){i=l;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,s.nc&&i.setAttribute("nonce",s.nc),i.setAttribute("data-webpack",o+n),i.src=s.tu(e)),r[e]=[t];var d=function(t,n){i.onerror=i.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(function(e){return e(n)}),t)return t(n)},p=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),c&&document.head.appendChild(i)},s.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.tt=function(){return void 0===u&&(u={createScriptURL:function(e){return e}},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(u=trustedTypes.createPolicy("nextjs#bundler",u))),u},s.tu=function(e){return s.tt().createScriptURL(e)},s.p="/_next/",i={272:0,832:0},s.f.j=function(e,t){var n=s.o(i,e)?i[e]:void 0;if(0!==n){if(n)t.push(n[2]);else if(/^(27|83)2$/.test(e))i[e]=0;else{var r=new Promise(function(t,r){n=i[e]=[t,r]});t.push(n[2]=r);var o=s.p+s.u(e),u=Error();s.l(o,function(t){if(s.o(i,e)&&(0!==(n=i[e])&&(i[e]=void 0),n)){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;u.message="Loading chunk "+e+" failed.\n("+r+": "+o+")",u.name="ChunkLoadError",u.type=r,u.request=o,n[1](u)}},"chunk-"+e,e)}}},s.O.j=function(e){return 0===i[e]},c=function(e,t){var n,r,o=t[0],u=t[1],c=t[2],f=0;if(o.some(function(e){return 0!==i[e]})){for(n in u)s.o(u,n)&&(s.m[n]=u[n]);if(c)var a=c(s)}for(e&&e(t);f<o.length;f++)r=o[f],s.o(i,r)&&i[r]&&i[r][0](),i[r]=0;return s.O(a)},(f=self.webpackChunk_N_E=self.webpackChunk_N_E||[]).forEach(c.bind(null,0)),f.push=c.bind(null,f.push.bind(f))}();

File diff suppressed because one or more lines are too long

54
dist/alerts.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/alerts.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[5949,["697","static/chunks/697-93a9cd29100d0d50.js","71","static/chunks/71-fccb418814321416.js","796","static/chunks/796-9d56fd2c469c90a6.js","489","static/chunks/489-4b7fe4fae3b6ef80.js","78","static/chunks/app/alerts/page-6f170ee2c75a0961.js"],"default",1]
4:I[4707,[],""]
5:I[6423,[],""]
6:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["alerts",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["alerts",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","alerts","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L6",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

View File

@@ -1,25 +0,0 @@
{
"pages": {
"/layout": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/css/app/layout.css",
"static/chunks/app/layout.js"
],
"/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/page.js"
],
"/settings/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/settings/page.js"
],
"/_not-found/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/_not-found/page.js"
]
}
}

54
dist/budget.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/budget.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[7268,["697","static/chunks/697-93a9cd29100d0d50.js","71","static/chunks/71-fccb418814321416.js","796","static/chunks/796-9d56fd2c469c90a6.js","489","static/chunks/489-4b7fe4fae3b6ef80.js","379","static/chunks/app/budget/page-1c1157916eee3b45.js"],"default",1]
4:I[4707,[],""]
5:I[6423,[],""]
6:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["budget",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["budget",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","budget","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L6",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

View File

@@ -1,19 +0,0 @@
{
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [
"static/development/_buildManifest.js",
"static/development/_ssgManifest.js"
],
"rootMainFiles": [
"static/chunks/webpack.js",
"static/chunks/main-app.js"
],
"pages": {
"/_app": []
},
"ampFirstPages": []
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

54
dist/cards.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/cards.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[3234,["697","static/chunks/697-93a9cd29100d0d50.js","71","static/chunks/71-fccb418814321416.js","796","static/chunks/796-9d56fd2c469c90a6.js","489","static/chunks/489-4b7fe4fae3b6ef80.js","137","static/chunks/app/cards/page-a9843d3be56b680d.js"],"default",1]
4:I[4707,[],""]
5:I[6423,[],""]
6:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["cards",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["cards",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","cards","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L6",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

54
dist/debts.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/debts.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[9220,["697","static/chunks/697-93a9cd29100d0d50.js","71","static/chunks/71-fccb418814321416.js","796","static/chunks/796-9d56fd2c469c90a6.js","489","static/chunks/489-4b7fe4fae3b6ef80.js","273","static/chunks/app/debts/page-28aedff94a342b70.js"],"default",1]
4:I[4707,[],""]
5:I[6423,[],""]
6:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["debts",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["debts",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","debts","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L6",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

69
dist/index.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/index.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[291,["697","static/chunks/697-93a9cd29100d0d50.js","71","static/chunks/71-fccb418814321416.js","796","static/chunks/796-9d56fd2c469c90a6.js","838","static/chunks/838-3b22f3c21887b523.js","489","static/chunks/489-4b7fe4fae3b6ef80.js","931","static/chunks/app/page-c63080d1806e3966.js"],"default",1]
4:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
5:I[4707,[],""]
6:I[6423,[],""]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L4",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

1
dist/login.html vendored Normal file

File diff suppressed because one or more lines are too long

8
dist/login.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
2:I[9107,[],"ClientPageRoot"]
3:I[6374,["626","static/chunks/app/login/page-6be400e8521677b4.js"],"default",1]
4:I[4707,[],""]
5:I[6423,[],""]
6:I[9294,["185","static/chunks/app/layout-639440f4d8b9b6b3.js"],"Providers"]
0:["4SrcMtBIfNF-pqHyUpitS",[[["",{"children":["login",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",{"children":["login",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","login","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/9effa8aa186c096c.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"es","className":"__variable_f367f3","suppressHydrationWarning":true,"children":["$","body",null,{"className":"__className_f367f3 antialiased min-h-screen bg-slate-950 text-slate-50","children":["$","$L6",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]}]],null],null],["$L7",null]]]]
7:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Finanzas Personales"}],["$","meta","3",{"name":"description","content":"Gestiona tus finanzas personales de forma inteligente"}],["$","meta","4",{"name":"keywords","content":"finanzas,presupuesto,gastos,ingresos,ahorro"}],["$","meta","5",{"name":"next-size-adjust"}]]
1:null

1
dist/package.json vendored
View File

@@ -1 +0,0 @@
{"type": "commonjs"}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1,7 +0,0 @@
{
"/page": "app/page.js",
"/api/settings/route": "app/api/settings/route.js",
"/settings/page": "app/settings/page.js",
"/api/test/ai/route": "app/api/test/ai/route.js",
"/api/proxy/models/route": "app/api/proxy/models/route.js"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"

View File

@@ -1,21 +0,0 @@
self.__BUILD_MANIFEST = {
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [],
"rootMainFiles": [
"static/chunks/webpack.js",
"static/chunks/main-app.js"
],
"pages": {
"/_app": []
},
"ampFirstPages": []
};
self.__BUILD_MANIFEST.lowPriorityFiles = [
"/static/" + process.env.__NEXT_BUILD_ID + "/_buildManifest.js",
,"/static/" + process.env.__NEXT_BUILD_ID + "/_ssgManifest.js",
];

View File

@@ -1,6 +0,0 @@
{
"version": 3,
"middleware": {},
"functions": {},
"sortedMiddleware": []
}

View File

@@ -1 +0,0 @@
self.__REACT_LOADABLE_MANIFEST="{}"

View File

@@ -1 +0,0 @@
self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}"

View File

@@ -1 +0,0 @@
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}

View File

@@ -1 +0,0 @@
{}

View File

@@ -1 +0,0 @@
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\"\n}"

View File

@@ -1,5 +0,0 @@
{
"node": {},
"edge": {},
"encryptionKey": "bNoGWlCooOUGQMrF3XDKlehaXh5PleSvIPcww3mfySw="
}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More