Configuración inicial del proyecto: estructura de directorios y dependencias mínimas instaladas

This commit is contained in:
manu
2025-12-05 09:36:39 -05:00
commit 002c79abcb
60 changed files with 11057 additions and 0 deletions

8
app/(auth)/layout.tsx Normal file
View File

@@ -0,0 +1,8 @@
export default function AuthLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}

View File

@@ -0,0 +1,9 @@
export default function LoginPage() {
return (
<div>
<h1>Login Page</h1>
{/* Login form will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,9 @@
export default function RegisterPage() {
return (
<div>
<h1>Register Page</h1>
{/* Register form will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,9 @@
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
{/* Dashboard content will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,14 @@
export default function EditVehiclePage({
params,
}: {
params: { id: string };
}) {
return (
<div>
<h1>Edit Vehicle</h1>
<p>Vehicle ID: {params.id}</p>
{/* Vehicle edit form will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,9 @@
export default function CreateVehiclePage() {
return (
<div>
<h1>Create Vehicle</h1>
{/* Vehicle creation form will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,8 @@
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}

View File

@@ -0,0 +1,9 @@
export default function ProfilePage() {
return (
<div>
<h1>Profile</h1>
{/* Profile content will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,9 @@
export default function ReservationsPage() {
return (
<div>
<h1>Reservations</h1>
{/* Reservations list will be implemented here */}
</div>
);
}

8
app/(public)/layout.tsx Normal file
View File

@@ -0,0 +1,8 @@
export default function PublicLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}

View File

@@ -0,0 +1,9 @@
export default function SearchPage() {
return (
<div>
<h1>Search Page</h1>
{/* Search functionality will be implemented here */}
</div>
);
}

View File

@@ -0,0 +1,14 @@
export default function VehicleDetailPage({
params,
}: {
params: { id: string };
}) {
return (
<div>
<h1>Vehicle Detail Page</h1>
<p>Vehicle ID: {params.id}</p>
{/* Vehicle details will be implemented here */}
</div>
);
}

51
app/error.tsx Normal file
View File

@@ -0,0 +1,51 @@
'use client'
import { useEffect } from 'react';
import Link from 'next/link';
import { ROUTES } from '@/lib/constants/routes';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log error to monitoring service (Sentry, etc.)
console.error('Error:', error);
}, [error]);
return (
<div className="flex min-h-screen flex-col items-center justify-center p-4">
<div className="text-center space-y-4 max-w-md">
<h2 className="text-2xl font-bold text-turo-primary">
Algo salió mal
</h2>
<p className="text-muted-foreground">
{error.message || 'Ocurrió un error inesperado'}
</p>
{error.digest && (
<p className="text-sm text-muted-foreground">
Error ID: {error.digest}
</p>
)}
<div className="flex gap-4 justify-center">
<button
onClick={reset}
className="px-4 py-2 bg-turo-accent text-white rounded-lg hover:bg-turo-accent-hover transition-colors"
>
Intentar de nuevo
</button>
<Link
href={ROUTES.HOME}
className="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
Volver al inicio
</Link>
</div>
</div>
</div>
);
}

BIN
app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

45
app/global-error.tsx Normal file
View File

@@ -0,0 +1,45 @@
'use client'
import { useEffect } from 'react';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log error to monitoring service (Sentry, etc.)
console.error('Global error:', error);
}, [error]);
return (
<html>
<body>
<div className="flex min-h-screen flex-col items-center justify-center p-4 bg-background">
<div className="text-center space-y-4 max-w-md">
<h2 className="text-2xl font-bold text-turo-primary">
Error Crítico
</h2>
<p className="text-muted-foreground">
{error.message || 'Ocurrió un error crítico en la aplicación'}
</p>
{error.digest && (
<p className="text-sm text-muted-foreground">
Error ID: {error.digest}
</p>
)}
<button
onClick={reset}
className="px-4 py-2 bg-turo-accent text-white rounded-lg hover:bg-turo-accent-hover transition-colors"
>
Reintentar
</button>
</div>
</div>
</body>
</html>
);
}

157
app/globals.css Normal file
View File

@@ -0,0 +1,157 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* Turo Brand Colors */
--color-turo-primary: var(--turo-primary);
--color-turo-secondary: var(--turo-secondary);
--color-turo-accent: var(--turo-accent);
--color-turo-accent-hover: var(--turo-accent-hover);
--color-turo-accent-alt: var(--turo-accent-alt);
--color-turo-white: var(--turo-white);
--color-turo-gray-light: var(--turo-gray-light);
--color-turo-gray-medium: var(--turo-gray-medium);
--color-turo-gray-dark: var(--turo-gray-dark);
--color-turo-black: var(--turo-black);
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
/* Turo Brand Colors */
--turo-primary: #1A1A2E;
--turo-secondary: #16213E;
--turo-accent: #00A676;
--turo-accent-hover: #008A5E;
--turo-accent-alt: #E94560;
--turo-white: #FFFFFF;
--turo-gray-light: #F0F0F0;
--turo-gray-medium: #282828;
--turo-gray-dark: #141414;
--turo-black: #000000;
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
/* Turo Brand Colors - Dark Mode */
--turo-primary: #2A3A4E;
--turo-secondary: #1A2A3E;
--turo-accent: #00C896;
--turo-accent-hover: #00A676;
--turo-accent-alt: #FF6B7A;
--turo-white: #FFFFFF;
--turo-gray-light: #2A2A2A;
--turo-gray-medium: #3A3A3A;
--turo-gray-dark: #1A1A1A;
--turo-black: #000000;
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

34
app/layout.tsx Normal file
View File

@@ -0,0 +1,34 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
);
}

6
app/loading.tsx Normal file
View File

@@ -0,0 +1,6 @@
import { Loading } from '@/components/common/Loading';
export default function GlobalLoading() {
return <Loading />;
}

31
app/not-found.tsx Normal file
View File

@@ -0,0 +1,31 @@
import Link from 'next/link';
import { ROUTES } from '@/lib/constants/routes';
export default function NotFound() {
return (
<div className="flex min-h-screen flex-col items-center justify-center p-4">
<div className="text-center space-y-4 max-w-md">
<h2 className="text-4xl font-bold text-turo-primary">404</h2>
<h3 className="text-2xl font-semibold">Página no encontrada</h3>
<p className="text-muted-foreground">
La página que buscas no existe o ha sido movida.
</p>
<div className="flex gap-4 justify-center">
<Link
href={ROUTES.HOME}
className="px-4 py-2 bg-turo-accent text-white rounded-lg hover:bg-turo-accent-hover transition-colors"
>
Volver al inicio
</Link>
<Link
href={ROUTES.SEARCH}
className="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
Buscar vehículos
</Link>
</div>
</div>
</div>
);
}

65
app/page.tsx Normal file
View File

@@ -0,0 +1,65 @@
import Image from "next/image";
export default function Home() {
return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
</div>
);
}