Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions app/[store]/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
'use client'

interface ErrorProps {
error: Error & { digest?: string }
reset: () => void
}

export default function StoreError({ error, reset }: ErrorProps) {
return (
<html lang="es">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Error - Fasttify</title>
<style
dangerouslySetInnerHTML={{
__html: `
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #333;
}
.error-container {
background: white;
border-radius: 20px;
padding: 3rem;
text-align: center;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
max-width: 500px;
margin: 2rem;
}
.error-icon {
font-size: 4rem;
margin-bottom: 1rem;
}
.error-title {
font-size: 2rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 1rem;
}
.error-message {
font-size: 1.1rem;
color: #718096;
margin-bottom: 2rem;
line-height: 1.6;
}
.suggestions {
background: #f7fafc;
border-radius: 12px;
padding: 1.5rem;
margin: 2rem 0;
text-align: left;
}
.suggestions h3 {
margin: 0 0 1rem 0;
color: #2d3748;
font-size: 1.1rem;
}
.suggestions ul {
margin: 0;
padding-left: 1.2rem;
color: #4a5568;
}
.suggestions li {
margin-bottom: 0.5rem;
}
.action-buttons {
margin: 2rem 0;
}
.action-button {
display: inline-block;
background: #667eea;
color: white;
padding: 0.8rem 2rem;
border-radius: 25px;
text-decoration: none;
font-weight: 600;
transition: background 0.3s ease;
margin: 0 0.5rem;
border: none;
cursor: pointer;
font-size: 1rem;
}
.action-button:hover {
background: #5a67d8;
}
.action-button.secondary {
background: transparent;
color: #667eea;
border: 2px solid #667eea;
}
.action-button.secondary:hover {
background: #667eea;
color: white;
}
.error-details {
margin-top: 2rem;
padding: 1rem;
background: #fed7d7;
border-radius: 8px;
border-left: 4px solid #e53e3e;
text-align: left;
font-family: monospace;
font-size: 0.9rem;
color: #742a2a;
max-height: 200px;
overflow-y: auto;
}
`,
}}
/>
</head>
<body>
<div className="error-container">
<div className="error-icon">🚧</div>
<h1 className="error-title">¡Oops! Algo salió mal</h1>
<p className="error-message">
Experimentamos un problema técnico temporal. Nuestro equipo ya está trabajando en
solucionarlo.
</p>

<div className="suggestions">
<h3>Puedes intentar:</h3>
<ul>
<li>Recargar la página</li>
<li>Volver a la página anterior</li>
<li>Contactar soporte si el problema persiste</li>
</ul>
</div>

<div className="action-buttons">
<button onClick={reset} className="action-button">
Intentar de nuevo
</button>
<button
onClick={() => (window.location.href = '/')}
className="action-button secondary"
>
Ir al inicio
</button>
</div>

{process.env.NODE_ENV === 'development' && (
<div className="error-details">
<strong>Detalles técnicos (solo en desarrollo):</strong>
<br />
{error.message}
<br />
{error.digest && `Digest: ${error.digest}`}
</div>
)}
</div>
</body>
</html>
)
}
16 changes: 11 additions & 5 deletions app/[store]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export default async function StorePage({ params, searchParams }: StorePageProps

// Validar que no sea una ruta de asset
if (isAssetPath(path)) {
console.warn(`[StorePage] Asset path ${path} should not be handled by page renderer`)
notFound()
}

Expand All @@ -79,12 +78,19 @@ export default async function StorePage({ params, searchParams }: StorePageProps
} catch (error: any) {
console.error(`Error rendering store page ${store}${path}:`, error)

// Mostrar 404 para tiendas no encontradas
if (error.type === 'STORE_NOT_FOUND' || error.statusCode === 404) {
// Si el error ya tiene HTML renderizado (páginas de error amigables),
// mostrar esa página en lugar de lanzar el error
if (error.html) {
return <div dangerouslySetInnerHTML={{ __html: error.html }} />
}

// Mostrar 404 solo para casos muy específicos
if (error.type === 'STORE_NOT_FOUND' && error.statusCode === 404) {
notFound()
}

// Para otros errores, mostrar página de error
// Para otros errores, intentar renderizar una página de error básica
// Si llegamos aquí, significa que falló el renderizado de error también
throw error
}
}
Expand Down Expand Up @@ -147,7 +153,7 @@ export async function generateMetadata({
: undefined,
}
} catch (error) {
console.error(`[Metadata] ERROR generating metadata for ${store}${path}:`, error)
console.error(`ERROR generating metadata for ${store}${path}:`, error)

// Metadata por defecto para errores
return {
Expand Down
2 changes: 0 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Metadata } from 'next'
import { inter } from '@/config/fonts'
import { ReactQueryProvider } from '@/utils/ReactQueryProvider'
import { Toaster } from '@/components/ui/sonner'
import ConfigureAmplifyClientSide from '@/utils/ConfigureAmplify'
import { Amplify } from 'aws-amplify'
import outputs from '@/amplify_outputs.json'
Expand Down Expand Up @@ -59,7 +58,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<body className={inter.className}>
<ConfigureAmplifyClientSide />
<ReactQueryProvider>{children}</ReactQueryProvider>
<Toaster position="top-center" />
</body>
</html>
)
Expand Down
7 changes: 0 additions & 7 deletions app/store/components/ai-chat/components/AiInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ export function AIInputWithSearch({
}
}

const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (file) {
onFileSelect?.(file)
}
}

return (
<div className={cn('w-full py-4', className)}>
<div className="relative max-w-xl w-full mx-auto">
Expand Down
27 changes: 13 additions & 14 deletions app/store/components/ai-chat/components/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { ChevronLeft } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { SheetHeader, SheetTitle } from '@/components/ui/sheet'
import { ArrowLeftIcon } from '@shopify/polaris-icons'
import { Box, Text, Button, InlineStack } from '@shopify/polaris'
import { GradientSparkles } from '@/app/store/components/ai-chat/components/GradientSparkles'
import { ChatHeaderProps } from '@/app/store/components/ai-chat/types/chat-types'

export function ChatHeader({ isMobile, onClose }: ChatHeaderProps) {
return (
<SheetHeader className="flex items-center bg-white/50 backdrop-blur-sm border-b border-gray-200 shrink-0">
<InlineStack align="center" blockAlign="center" gap="200" wrap={false}>
{isMobile && (
<Button
variant="ghost"
onClick={onClose}
className="h-2 w-2 rounded-full -ml-96"
aria-label="Regresar"
>
<ChevronLeft className="h-6 w-6 scale-150 text-gray-900" />
</Button>
accessibilityLabel="Regresar"
icon={ArrowLeftIcon}
variant="plain"
/>
)}
<div className="flex flex-1 justify-center items-center gap-2">
<InlineStack gap="200" blockAlign="center" wrap={false}>
<GradientSparkles />
<SheetTitle className="font-medium text-gray-800">FastBot</SheetTitle>
</div>
</SheetHeader>
<Text variant="headingMd" as="h2">
FastBot
</Text>
</InlineStack>
</InlineStack>
)
}
41 changes: 39 additions & 2 deletions app/store/components/ai-chat/components/ChatTrigger.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
import { useState } from 'react'
'use client'

import { useState, useCallback, useMemo } from 'react'
import { Button } from '@/components/ui/button'
import { RefinedAIAssistantSheet } from '@/app/store/components/ai-chat/components/RefinedAiAssistant'
import { GradientSparkles } from '@/app/store/components/ai-chat/components/GradientSparkles'
import { useChat } from '@/app/store/components/ai-chat/hooks/useChat'

export function ChatTrigger() {
const [isOpen, setIsOpen] = useState(false)
const { messages: chatMessages, loading, chat } = useChat()

const transformedMessages = useMemo(
() =>
chatMessages.map((msg: { content: string; role: 'user' | 'assistant' }, index: number) => ({
id: index.toString(),
content: msg.content,
type: msg.role === 'user' ? ('user' as const) : ('ai' as const),
timestamp: new Date(),
})),
[chatMessages]
)

const handleSubmit = useCallback(
async (value: string) => {
if (!value.trim()) return
await chat(value)
},
[chat]
)

const handleSuggestionClick = useCallback(
async (suggestion: string) => {
await chat(suggestion)
},
[chat]
)

return (
<>
Expand All @@ -17,7 +47,14 @@ export function ChatTrigger() {
<GradientSparkles className="w-30 h-30" />
</Button>

<RefinedAIAssistantSheet open={isOpen} onOpenChange={setIsOpen} />
<RefinedAIAssistantSheet
open={isOpen}
onOpenChange={setIsOpen}
messages={transformedMessages}
loading={loading}
onSubmit={handleSubmit}
onSuggestionClick={handleSuggestionClick}
/>
</>
)
}
Loading