diff --git a/app/(setup)/first-steps/hooks/useUserStoreData.ts b/app/(setup)/first-steps/hooks/useUserStoreData.ts index f3405c61..6c499371 100644 --- a/app/(setup)/first-steps/hooks/useUserStoreData.ts +++ b/app/(setup)/first-steps/hooks/useUserStoreData.ts @@ -8,11 +8,11 @@ import { type PaymentGatewayConfig, type StoreInitializationResult, type CreateUserStoreInput, -} from '@/lib/amplify-client'; +} from '@/lib/clients/amplify-client'; import useAuthStore from '@/context/core/userStore'; // Re-exportar tipos para compatibilidad -export type { PaymentGatewayType, PaymentGatewayConfig, StoreInitializationResult } from '@/lib/amplify-client'; +export type { PaymentGatewayType, PaymentGatewayConfig, StoreInitializationResult } from '@/lib/clients/amplify-client'; export const useUserStoreData = () => { const [loading, setLoading] = useState(false); diff --git a/app/(setup)/layout.tsx b/app/(setup)/layout.tsx index c6150b99..a3c15ae6 100644 --- a/app/(setup)/layout.tsx +++ b/app/(setup)/layout.tsx @@ -1,6 +1,6 @@ 'use client'; -import { inter } from '@/lib/fonts'; +import { inter } from '@/lib/fonts/fonts'; import { useAuthInitializer } from '@/hooks/auth/useAuthInitializer'; import { AppProvider } from '@shopify/polaris'; import '@shopify/polaris/build/esm/styles.css'; diff --git a/app/(setup)/login/components/sing-up/SignUpForm.tsx b/app/(setup)/login/components/sing-up/SignUpForm.tsx index ce17aeae..d94f6096 100644 --- a/app/(setup)/login/components/sing-up/SignUpForm.tsx +++ b/app/(setup)/login/components/sing-up/SignUpForm.tsx @@ -12,7 +12,7 @@ import { Input } from '@/components/ui/input'; import { signUpSchema, type SignUpFormData } from '@/lib/zod-schemas/schemas'; import Link from 'next/link'; import { useAuth } from '@/context/hooks/useAuth'; -import { getSignUpErrorMessage } from '@/lib/auth-error-messages'; +import { getSignUpErrorMessage } from '@/lib/auth/auth-error-messages'; interface SignUpFormProps { onVerificationNeeded: (email: string, password: string) => void; diff --git a/app/(setup)/login/components/verification-form/VerificationForm.tsx b/app/(setup)/login/components/verification-form/VerificationForm.tsx index 3807fcd4..0b9fcc4c 100644 --- a/app/(setup)/login/components/verification-form/VerificationForm.tsx +++ b/app/(setup)/login/components/verification-form/VerificationForm.tsx @@ -12,7 +12,7 @@ import { verificationSchema, type VerificationFormData } from '@/lib/zod-schemas import { OTPInput, type SlotProps } from 'input-otp'; import { cn } from '@/lib/utils'; import { useAuth } from '@/context/hooks/useAuth'; -import { getConfirmSignUpErrorMessage } from '@/lib/auth-error-messages'; +import { getConfirmSignUpErrorMessage } from '@/lib/auth/auth-error-messages'; interface VerificationFormProps { email: string; diff --git a/app/(setup)/login/hooks/SignIn.ts b/app/(setup)/login/hooks/SignIn.ts index d6d1e92b..8ac88ba7 100644 --- a/app/(setup)/login/hooks/SignIn.ts +++ b/app/(setup)/login/hooks/SignIn.ts @@ -2,7 +2,7 @@ import { resendSignUpCode, signIn, type SignInInput } from 'aws-amplify/auth'; import { useRouter } from 'next/navigation'; import { useCallback, useState } from 'react'; import { useAuth } from '@/context/hooks/useAuth'; -import { getSignInErrorMessage } from '@/lib/auth-error-messages'; +import { getSignInErrorMessage } from '@/lib/auth/auth-error-messages'; import { getLastVisitedStoreClient } from '@/lib/cookies/last-store'; interface UseAuthReturn { diff --git a/app/(setup)/my-store/hooks/useUserStores.ts b/app/(setup)/my-store/hooks/useUserStores.ts index f1a61180..448cd297 100644 --- a/app/(setup)/my-store/hooks/useUserStores.ts +++ b/app/(setup)/my-store/hooks/useUserStores.ts @@ -1,5 +1,5 @@ import { use } from 'react'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; import type { Store, UseUserStoresResult } from '../types/store.types'; const STORE_LIMITS = { diff --git a/app/(www)/layout.tsx b/app/(www)/layout.tsx index cad83728..7b5acf5b 100644 --- a/app/(www)/layout.tsx +++ b/app/(www)/layout.tsx @@ -1,5 +1,5 @@ import '@/app/global.css'; -import { inter } from '@/lib/fonts'; +import { inter } from '@/lib/fonts/fonts'; import { Navbar } from '@/app/(www)/landing/components/NavBar'; export default function WithNavbarLayout({ children }: { children: React.ReactNode }) { diff --git a/app/auth/layout.tsx b/app/auth/layout.tsx index 600b237e..e37edca9 100644 --- a/app/auth/layout.tsx +++ b/app/auth/layout.tsx @@ -1,5 +1,5 @@ import '@/app/global.css'; -import { inter } from '@/lib/fonts'; +import { inter } from '@/lib/fonts/fonts'; export default function AuthLayout({ children }: { children: React.ReactNode }) { return ( diff --git a/app/orders/layout.tsx b/app/orders/layout.tsx index 5048fb32..8a7944cf 100644 --- a/app/orders/layout.tsx +++ b/app/orders/layout.tsx @@ -1,5 +1,5 @@ import type { Metadata } from 'next'; -import { nunitoSans } from '@/lib/fonts'; +import { nunitoSans } from '@/lib/fonts/fonts'; import StyledComponentsRegistry from './registry'; import { ReactQueryProvider } from '@/utils/client/ReactQueryProvider'; diff --git a/app/store/components/ai-chat/context/ConversationHistoryContext.tsx b/app/store/components/ai-chat/context/ConversationHistoryContext.tsx index 2454c70b..f0bc927b 100644 --- a/app/store/components/ai-chat/context/ConversationHistoryContext.tsx +++ b/app/store/components/ai-chat/context/ConversationHistoryContext.tsx @@ -1,7 +1,7 @@ 'use client'; import { createContext, useContext, ReactNode, useState, useCallback, useEffect, useRef } from 'react'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; export interface Conversation { id: string; diff --git a/app/store/components/ai-chat/hooks/useConversation.ts b/app/store/components/ai-chat/hooks/useConversation.ts index d1ea418a..c04e803e 100644 --- a/app/store/components/ai-chat/hooks/useConversation.ts +++ b/app/store/components/ai-chat/hooks/useConversation.ts @@ -5,7 +5,7 @@ import { useState, useCallback, useRef } from 'react'; import { useConversationContext } from '../context/ConversationContext'; import { generateConversationName, generateTemporaryConversationName } from '../utils/conversation-naming'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; export interface Message { id: string; diff --git a/app/store/components/ai-chat/hooks/useCurrentConversation.ts b/app/store/components/ai-chat/hooks/useCurrentConversation.ts index e4ddb4a8..389f15e8 100644 --- a/app/store/components/ai-chat/hooks/useCurrentConversation.ts +++ b/app/store/components/ai-chat/hooks/useCurrentConversation.ts @@ -1,7 +1,7 @@ 'use client'; import { useState, useCallback, useEffect } from 'react'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; interface UseCurrentConversationProps { conversationId?: string; diff --git a/app/store/components/images-selector/components/ImageCard.tsx b/app/store/components/images-selector/components/ImageCard.tsx index be1cb4c3..83d47fa5 100644 --- a/app/store/components/images-selector/components/ImageCard.tsx +++ b/app/store/components/images-selector/components/ImageCard.tsx @@ -118,8 +118,8 @@ const ImageCard = memo(function ImageCard({ ...CARD_STYLES.checkboxContainer, backgroundColor: deleteMode ? isMarkedForDeletion - ? '#d72c0d' - : 'rgba(255,255,255,0.9)' + ? 'transparent' + : 'transparent' : isSelected ? 'transparent' : 'rgba(255, 255, 255, 0.9)', diff --git a/app/store/components/images-selector/components/ImageGallery.tsx b/app/store/components/images-selector/components/ImageGallery.tsx index 796a8b0c..b3286458 100644 --- a/app/store/components/images-selector/components/ImageGallery.tsx +++ b/app/store/components/images-selector/components/ImageGallery.tsx @@ -2,8 +2,8 @@ import { useToast } from '@/app/store/context/ToastContext'; import { S3Image } from '@/app/store/hooks/storage/useS3Images'; import { Box, Button, ButtonGroup, EmptyState, Grid, InlineStack, Spinner, Text } from '@shopify/polaris'; import { DeleteIcon } from '@shopify/polaris-icons'; -import { useCallback, useState, memo } from 'react'; -import ImageCard from './ImageCard'; +import { useCallback, useState, memo, useMemo } from 'react'; +import ImageCard from '@/app/store/components/images-selector/components/ImageCard'; interface ImageGalleryProps { images: S3Image[]; @@ -15,6 +15,10 @@ interface ImageGalleryProps { onImageSelect: (image: S3Image) => void; onDeleteImage: (key: string) => Promise; onDeleteMultiple?: (keys: string[]) => Promise; + nextContinuationToken?: string; + loadingMore?: boolean; + hasActiveFilters?: boolean; + allImages?: S3Image[]; } const ImageGallery = memo(function ImageGallery({ @@ -27,6 +31,10 @@ const ImageGallery = memo(function ImageGallery({ onImageSelect, onDeleteImage, onDeleteMultiple, + nextContinuationToken, + loadingMore = false, + hasActiveFilters = false, + allImages = [], }: ImageGalleryProps) { const [deleteMode, setDeleteMode] = useState(false); const [imagesToDelete, setImagesToDelete] = useState>(new Set()); @@ -34,6 +42,21 @@ const ImageGallery = memo(function ImageGallery({ const { showToast } = useToast(); + // Determinar si debemos mostrar el estado de carga cuando no hay imágenes + const shouldShowLoadingState = useMemo(() => { + if (images.length > 0) return false; + + // Si estamos cargando más, siempre mostrar spinner + if (loadingMore) return true; + + // Si no hay filtros activos y no hay imágenes en total, pero hay más disponibles, mostrar spinner + if (!hasActiveFilters && nextContinuationToken && allImages.length === 0) { + return true; + } + + return false; + }, [images.length, loadingMore, nextContinuationToken, hasActiveFilters, allImages.length]); + // Memoizar funciones para evitar re-creaciones const isSelected = useCallback( (image: S3Image) => { @@ -219,6 +242,15 @@ const ImageGallery = memo(function ImageGallery({ } if (images.length === 0) { + // Si debemos mostrar estado de carga, mostrar spinner en lugar del estado vacío + if (shouldShowLoadingState) { + return ( +
+ +
+ ); + } + return ( import('./ImageGallery')); -const SearchAndFilters = lazy(() => import('./SearchAndFilters')); -const UploadDropZone = lazy(() => import('./UploadDropZone')); +const ImageGallery = lazy(() => import('@/app/store/components/images-selector/components/ImageGallery')); +const SearchAndFilters = lazy(() => import('@/app/store/components/images-selector/components/SearchAndFilters')); +const UploadDropZone = lazy(() => import('@/app/store/components/images-selector/components/UploadDropZone')); // Hooks y utilidades import { useImageSelection } from '@/app/store/components/images-selector/hooks/useImageSelection'; import { useImageUpload } from '@/app/store/components/images-selector/hooks/useImageUpload'; -import { filterAndSortImages, getFilterStats } from '../utils/filterUtils'; -import type { FilterState } from '../hooks/useImageFilters'; +import { filterAndSortImages, getFilterStats } from '@/app/store/components/images-selector/utils/filterUtils'; +import type { FilterState } from '@/app/store/components/images-selector/hooks/useImageFilters'; interface ImageSelectorModalProps { open: boolean; @@ -55,6 +55,17 @@ const ImageSelectorModal = memo(function ImageSelectorModal({ return getFilterStats(images, filteredImages); }, [images, filteredImages]); + // Calcular si hay filtros activos + const hasActiveFilters = useMemo(() => { + return ( + filters.fileTypes.length > 0 || + filters.fileSizes.length > 0 || + filters.usedIn.length > 0 || + filters.products.length > 0 || + filters.searchTerm.length > 0 + ); + }, [filters]); + const { selectedImage, handleImageSelect, getSelectedImages, removeFromSelection, addToSelection } = useImageSelection({ initialSelectedImage, @@ -280,16 +291,12 @@ const ImageSelectorModal = memo(function ImageSelectorModal({ onImageSelect={handleImageSelect} onDeleteImage={handleDeleteImage} onDeleteMultiple={handleDeleteMultiple} + nextContinuationToken={nextContinuationToken} + loadingMore={loadingMore} + hasActiveFilters={hasActiveFilters} + allImages={images} /> - - {loadingMore && ( -
- - - -
- )} diff --git a/app/store/components/payments/components/PaymentGatewayCard.tsx b/app/store/components/payments/components/PaymentGatewayCard.tsx index e7624dac..90734918 100644 --- a/app/store/components/payments/components/PaymentGatewayCard.tsx +++ b/app/store/components/payments/components/PaymentGatewayCard.tsx @@ -10,7 +10,14 @@ interface PaymentGatewayCardProps { } export function PaymentGatewayCard({ gateway, isConfigured, onActivate }: PaymentGatewayCardProps) { - const gatewayConfig = { + const gatewayConfig: Record< + PaymentGatewayType, + { + name: string; + logo: string; + PaymentIcons: () => JSX.Element; + } + > = { wompi: { name: 'Wompi', logo: 'https://cdn.fasttify.com/assets/b/wompi.webp', diff --git a/app/store/components/product-management/inventory/pages/InventoryManager.tsx b/app/store/components/product-management/inventory/pages/InventoryManager.tsx index 4aff2bd1..940ff5f1 100644 --- a/app/store/components/product-management/inventory/pages/InventoryManager.tsx +++ b/app/store/components/product-management/inventory/pages/InventoryManager.tsx @@ -37,7 +37,9 @@ export function InventoryManager({ storeId }: InventoryManagerProps) { images = undefined; } } else if (Array.isArray(product.images)) { - images = product.images.map((img) => (typeof img === 'string' ? { url: img } : img)); + images = product.images.map((img: string | { url: string; alt?: string }) => + typeof img === 'string' ? { url: img } : img + ); } return { diff --git a/app/store/components/product-management/products/hooks/usePriceSuggestion.ts b/app/store/components/product-management/products/hooks/usePriceSuggestion.ts index 1a400652..1341a0a5 100644 --- a/app/store/components/product-management/products/hooks/usePriceSuggestion.ts +++ b/app/store/components/product-management/products/hooks/usePriceSuggestion.ts @@ -4,7 +4,7 @@ * y categoría del producto. */ import { useState, useCallback } from 'react'; -import { aiClient } from '@/lib/amplify-client'; +import { aiClient } from '@/lib/clients/amplify-client'; /** * Interfaz para los resultados de la sugerencia de precios. diff --git a/app/store/components/product-management/products/hooks/useProductDescription.ts b/app/store/components/product-management/products/hooks/useProductDescription.ts index 9b766134..a82f692b 100644 --- a/app/store/components/product-management/products/hooks/useProductDescription.ts +++ b/app/store/components/product-management/products/hooks/useProductDescription.ts @@ -4,7 +4,7 @@ * y categoría del producto. */ import { useState, useCallback } from 'react'; -import { aiClient } from '@/lib/amplify-client'; +import { aiClient } from '@/lib/clients/amplify-client'; /** * Hook personalizado que gestiona la generación de descripciones de productos con IA. diff --git a/app/store/components/product-management/shared/utils/exportUtils.ts b/app/store/components/product-management/shared/utils/exportUtils.ts index a3a7003a..f69207b4 100644 --- a/app/store/components/product-management/shared/utils/exportUtils.ts +++ b/app/store/components/product-management/shared/utils/exportUtils.ts @@ -78,7 +78,9 @@ export const exportProductsToCSV = (products: IProduct[], fileName: string): boo // Prepara los datos de imágenes const imagesString = Array.isArray(product.images) - ? product.images.map((img) => img.url).join(', ') + ? product.images + .map((img: string | { url: string; alt?: string }) => (typeof img === 'string' ? img : img.url)) + .join(', ') : typeof product.images === 'string' ? product.images : ''; diff --git a/app/store/components/product-management/utils/exportUtils.ts b/app/store/components/product-management/utils/exportUtils.ts index a3a7003a..f69207b4 100644 --- a/app/store/components/product-management/utils/exportUtils.ts +++ b/app/store/components/product-management/utils/exportUtils.ts @@ -78,7 +78,9 @@ export const exportProductsToCSV = (products: IProduct[], fileName: string): boo // Prepara los datos de imágenes const imagesString = Array.isArray(product.images) - ? product.images.map((img) => img.url).join(', ') + ? product.images + .map((img: string | { url: string; alt?: string }) => (typeof img === 'string' ? img : img.url)) + .join(', ') : typeof product.images === 'string' ? product.images : ''; diff --git a/app/store/hooks/data/useAutoTaskCompletion/useAutoTaskCompletion.ts b/app/store/hooks/data/useAutoTaskCompletion/useAutoTaskCompletion.ts index 697b6584..716ad339 100644 --- a/app/store/hooks/data/useAutoTaskCompletion/useAutoTaskCompletion.ts +++ b/app/store/hooks/data/useAutoTaskCompletion/useAutoTaskCompletion.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { useOnboardingProgress } from '../useOnboardingProgress/useOnboardingProgress'; +import { useOnboardingProgress } from '@/app/store/hooks/data/useOnboardingProgress/useOnboardingProgress'; /** * Hook para marcar automáticamente las tareas del onboarding cuando se completen las acciones reales diff --git a/app/store/hooks/data/useCheckoutSessions/mutations/useCheckoutSessionMutations.ts b/app/store/hooks/data/useCheckoutSessions/mutations/useCheckoutSessionMutations.ts index f8e78f4c..99aae51b 100644 --- a/app/store/hooks/data/useCheckoutSessions/mutations/useCheckoutSessionMutations.ts +++ b/app/store/hooks/data/useCheckoutSessions/mutations/useCheckoutSessionMutations.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { getCurrentUser } from 'aws-amplify/auth'; import type { ICheckoutSession, CheckoutSessionCreateInput, CheckoutSessionUpdateInput } from '../types'; import { useCheckoutSessionCacheUtils } from '../utils/checkoutSessionCacheUtils'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; /** * Hook para manejar todas las mutaciones de sesiones de checkout diff --git a/app/store/hooks/data/useCheckoutSessions/queries/useCheckoutSessionQueries.ts b/app/store/hooks/data/useCheckoutSessions/queries/useCheckoutSessionQueries.ts index 7a72446c..57cd838d 100644 --- a/app/store/hooks/data/useCheckoutSessions/queries/useCheckoutSessionQueries.ts +++ b/app/store/hooks/data/useCheckoutSessions/queries/useCheckoutSessionQueries.ts @@ -1,6 +1,6 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import type { ICheckoutSession, PaginationOptions, CheckoutSessionsQueryResult, CheckoutSessionStatus } from '../types'; -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; /** * Hook para manejar las queries de sesiones de checkout diff --git a/app/store/hooks/data/useCheckoutSessions/types/useCheckoutSessions-types.ts b/app/store/hooks/data/useCheckoutSessions/types/useCheckoutSessions-types.ts index 4fc408c6..5b424bb8 100644 --- a/app/store/hooks/data/useCheckoutSessions/types/useCheckoutSessions-types.ts +++ b/app/store/hooks/data/useCheckoutSessions/types/useCheckoutSessions-types.ts @@ -1,4 +1,4 @@ -import { type StoreCheckoutSession } from '@/lib/amplify-client'; +import { type StoreCheckoutSession } from '@/lib/clients/amplify-client'; /** * Interfaz para representar una sesión de checkout diff --git a/app/store/hooks/data/useCollection/useCollections.ts b/app/store/hooks/data/useCollection/useCollections.ts index 7e07d306..b098c042 100644 --- a/app/store/hooks/data/useCollection/useCollections.ts +++ b/app/store/hooks/data/useCollection/useCollections.ts @@ -1,7 +1,7 @@ import { useCacheInvalidation } from '@/hooks/cache/useCacheInvalidation'; import { useMutation, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query'; import { useState } from 'react'; -import { storeClient, type StoreCollection } from '@/lib/amplify-client'; +import { storeClient, type StoreCollection } from '@/lib/clients/amplify-client'; import { ensureUniqueCollectionSlug } from './utils/slugUnique'; import { generateProductSlug } from '@/lib/utils/slug'; diff --git a/app/store/hooks/data/useCollection/utils/slugUnique.ts b/app/store/hooks/data/useCollection/utils/slugUnique.ts index f2aacba0..dfd57297 100644 --- a/app/store/hooks/data/useCollection/utils/slugUnique.ts +++ b/app/store/hooks/data/useCollection/utils/slugUnique.ts @@ -1,4 +1,4 @@ -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; // Genera un slug único para colecciones: base, base-1, base-2, ... export async function ensureUniqueCollectionSlug( diff --git a/app/store/hooks/data/useNavigationMenu/useNavigationMenus.ts b/app/store/hooks/data/useNavigationMenu/useNavigationMenus.ts index 710714e7..e3f19c7b 100644 --- a/app/store/hooks/data/useNavigationMenu/useNavigationMenus.ts +++ b/app/store/hooks/data/useNavigationMenu/useNavigationMenus.ts @@ -3,7 +3,7 @@ import { validateMenuItems, validateNavigationMenu, validateUpdateNavigationMenu import { useMutation, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query'; import { getCurrentUser } from 'aws-amplify/auth'; import { useCallback, useState } from 'react'; -import { storeClient, type StoreNavigationMenu } from '@/lib/amplify-client'; +import { storeClient, type StoreNavigationMenu } from '@/lib/clients/amplify-client'; const NAVIGATION_MENUS_KEY = 'navigationMenus'; diff --git a/app/store/hooks/data/useNotifications/mutations/useNotificationMutations.ts b/app/store/hooks/data/useNotifications/mutations/useNotificationMutations.ts index 4477f8bd..2e949412 100644 --- a/app/store/hooks/data/useNotifications/mutations/useNotificationMutations.ts +++ b/app/store/hooks/data/useNotifications/mutations/useNotificationMutations.ts @@ -1,7 +1,7 @@ import { useMutation } from '@tanstack/react-query'; import type { Notification } from '../types'; import { useNotificationCacheUtils } from '../utils/notificationCacheUtils'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; /** * Hook para manejar todas las mutaciones de notificaciones diff --git a/app/store/hooks/data/useNotifications/queries/useNotificationQueries.ts b/app/store/hooks/data/useNotifications/queries/useNotificationQueries.ts index 2c93a109..969c3790 100644 --- a/app/store/hooks/data/useNotifications/queries/useNotificationQueries.ts +++ b/app/store/hooks/data/useNotifications/queries/useNotificationQueries.ts @@ -1,6 +1,6 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import type { Notification, NotificationFilterOptions, NotificationsQueryResult, PaginationOptions } from '../types'; -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; /** * Hook para manejar las queries de notificaciones diff --git a/app/store/hooks/data/useNotifications/types/useNotification-types.ts b/app/store/hooks/data/useNotifications/types/useNotification-types.ts index 57d639e7..2b5b7d15 100644 --- a/app/store/hooks/data/useNotifications/types/useNotification-types.ts +++ b/app/store/hooks/data/useNotifications/types/useNotification-types.ts @@ -1,5 +1,5 @@ import { ConnectionState } from 'aws-amplify/api'; -import { type StoreNotification } from '@/lib/amplify-client'; +import { type StoreNotification } from '@/lib/clients/amplify-client'; /** * Interfaz para representar una notificación diff --git a/app/store/hooks/data/useNotifications/useNotifications.ts b/app/store/hooks/data/useNotifications/useNotifications.ts index 5578b0ab..c13c8ebd 100644 --- a/app/store/hooks/data/useNotifications/useNotifications.ts +++ b/app/store/hooks/data/useNotifications/useNotifications.ts @@ -10,7 +10,7 @@ import { CONNECTION_STATE_CHANGE, ConnectionState } from 'aws-amplify/api'; import { Hub } from 'aws-amplify/utils'; import { useNotificationMutations } from './mutations'; import { useNotificationQueries } from './queries'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; /** * Hook para gestionar notificaciones con paginación y caché usando React Query diff --git a/app/store/hooks/data/useOnboardingProgress/useOnboardingProgress.ts b/app/store/hooks/data/useOnboardingProgress/useOnboardingProgress.ts index d1ccc14c..bca787a5 100644 --- a/app/store/hooks/data/useOnboardingProgress/useOnboardingProgress.ts +++ b/app/store/hooks/data/useOnboardingProgress/useOnboardingProgress.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; interface OnboardingProgressParams { storeId: string; diff --git a/app/store/hooks/data/useOrders/mutations/useOrderMutations.ts b/app/store/hooks/data/useOrders/mutations/useOrderMutations.ts index c7227ba5..692d83ae 100644 --- a/app/store/hooks/data/useOrders/mutations/useOrderMutations.ts +++ b/app/store/hooks/data/useOrders/mutations/useOrderMutations.ts @@ -3,7 +3,7 @@ import { getCurrentUser } from 'aws-amplify/auth'; import type { IOrder, OrderCreateInput, OrderUpdateInput, OrderStatus, PaymentStatus } from '../types'; import { useOrderCacheUtils } from '../utils/orderCacheUtils'; import { useOrderNotifications } from '../notifications/useOrderNotifications'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; /** * Hook para manejar todas las mutaciones de órdenes diff --git a/app/store/hooks/data/useOrders/queries/useOrderQueries.ts b/app/store/hooks/data/useOrders/queries/useOrderQueries.ts index ce9b1de1..43dab15b 100644 --- a/app/store/hooks/data/useOrders/queries/useOrderQueries.ts +++ b/app/store/hooks/data/useOrders/queries/useOrderQueries.ts @@ -1,6 +1,6 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import type { IOrder, PaginationOptions, OrdersQueryResult, OrderStatus, PaymentStatus } from '../types'; -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; /** * Hook para manejar las queries de órdenes diff --git a/app/store/hooks/data/useOrders/types/useOrders-types.ts b/app/store/hooks/data/useOrders/types/useOrders-types.ts index 1f1ff3f3..b85dd113 100644 --- a/app/store/hooks/data/useOrders/types/useOrders-types.ts +++ b/app/store/hooks/data/useOrders/types/useOrders-types.ts @@ -1,4 +1,4 @@ -import { type StoreOrder, type StoreOrderItem } from '@/lib/amplify-client'; +import { type StoreOrder, type StoreOrderItem } from '@/lib/clients/amplify-client'; /** * Interfaz para representar una orden diff --git a/app/store/hooks/data/usePage/usePage.ts b/app/store/hooks/data/usePage/usePage.ts index df4196ec..df89476a 100644 --- a/app/store/hooks/data/usePage/usePage.ts +++ b/app/store/hooks/data/usePage/usePage.ts @@ -3,7 +3,7 @@ import { CreatePageInput, createPageSchema, UpdatePageInput, updatePageSchema } import { useMutation, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query'; import { getCurrentUser } from 'aws-amplify/auth'; import { useCallback, useState } from 'react'; -import { storeClient, type StorePage } from '@/lib/amplify-client'; +import { storeClient, type StorePage } from '@/lib/clients/amplify-client'; import { ensureUniquePageSlug } from './utils/slugUnique'; // Clave base para las consultas de páginas diff --git a/app/store/hooks/data/usePage/utils/slugUnique.ts b/app/store/hooks/data/usePage/utils/slugUnique.ts index 63ceb0bc..383b8ebf 100644 --- a/app/store/hooks/data/usePage/utils/slugUnique.ts +++ b/app/store/hooks/data/usePage/utils/slugUnique.ts @@ -1,4 +1,4 @@ -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; // Genera un slug único para páginas: base, base-1, base-2, ... export async function ensureUniquePageSlug( diff --git a/app/store/hooks/data/useProducts/mutations/useProductMutations.ts b/app/store/hooks/data/useProducts/mutations/useProductMutations.ts index d186aa3f..6560c7ca 100644 --- a/app/store/hooks/data/useProducts/mutations/useProductMutations.ts +++ b/app/store/hooks/data/useProducts/mutations/useProductMutations.ts @@ -1,4 +1,4 @@ -import { normalizeAttributesField, normalizeTagsField, withLowercaseName } from '@/app/store/hooks/utils/productUtils'; +import { normalizeAttributesField, normalizeTagsField } from '@/app/store/hooks/utils/productUtils'; import { useCacheInvalidation } from '@/hooks/cache/useCacheInvalidation'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { getCurrentUser } from 'aws-amplify/auth'; @@ -6,7 +6,7 @@ import type { IProduct, ProductCreateInput, ProductUpdateInput } from '../types' import { useProductCacheUtils } from '../utils'; import { generateProductSlug } from '@/lib/utils/slug'; import { ensureUniqueSlug } from '@/app/store/hooks/data/useProducts/utils/slugUnique'; -import { client } from '@/lib/amplify-client'; +import { client } from '@/lib/clients/amplify-client'; /** * Hook para manejar todas las mutaciones de productos @@ -34,7 +34,7 @@ export const useProductMutations = (storeId: string | undefined) => { slug = await ensureUniqueSlug(storeId, slug); } - const dataToSend = withLowercaseName({ + const dataToSend = { ...productData, slug, attributes: normalizeAttributesField( @@ -45,7 +45,8 @@ export const useProductMutations = (storeId: string | undefined) => { owner: username, status: productData.status || 'DRAFT', quantity: productData.quantity || 0, - }); + nameLowercase: productData.name?.toLowerCase(), + }; const { data } = await client.models.Product.create(dataToSend); return data as IProduct; @@ -75,14 +76,15 @@ export const useProductMutations = (storeId: string | undefined) => { nextSlug = await ensureUniqueSlug(storeId, nextSlug, productData.id); } - const dataToSend = withLowercaseName({ + const dataToSend = { ...productData, ...(nextSlug ? { slug: nextSlug } : {}), attributes: normalizeAttributesField( productData.attributes as string | { name?: string; values?: string[] }[] | undefined ), tags: normalizeTagsField(productData.tags as string[] | string | undefined), - }); + nameLowercase: (productData as any).name?.toLowerCase(), + }; const { data } = await client.models.Product.update(dataToSend); return data as IProduct; @@ -174,7 +176,7 @@ export const useProductMutations = (storeId: string | undefined) => { duplicatedSlug = await ensureUniqueSlug(originalProduct.storeId, duplicatedSlug); // Crear una copia del producto sin campos que se generan automáticamente - const duplicatedProduct = withLowercaseName({ + const duplicatedProduct = { storeId: originalProduct.storeId, name: duplicatedName, nameLowercase: duplicatedName.toLowerCase(), @@ -196,7 +198,7 @@ export const useProductMutations = (storeId: string | undefined) => { collectionId: originalProduct.collectionId, supplier: originalProduct.supplier, owner: username, - }); + }; const { data } = await client.models.Product.create(duplicatedProduct); return data as IProduct; diff --git a/app/store/hooks/data/useProducts/queries/useProductQueries.ts b/app/store/hooks/data/useProducts/queries/useProductQueries.ts index e831b822..ddd79012 100644 --- a/app/store/hooks/data/useProducts/queries/useProductQueries.ts +++ b/app/store/hooks/data/useProducts/queries/useProductQueries.ts @@ -1,6 +1,6 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import type { IProduct, PaginationOptions, ProductsQueryResult } from '../types'; -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; /** * Hook para manejar las queries de productos diff --git a/app/store/hooks/data/useProducts/types/useProducts-types.ts b/app/store/hooks/data/useProducts/types/useProducts-types.ts index 21bae8e2..a60d91ea 100644 --- a/app/store/hooks/data/useProducts/types/useProducts-types.ts +++ b/app/store/hooks/data/useProducts/types/useProducts-types.ts @@ -1,4 +1,4 @@ -import { type StoreProduct } from '@/lib/amplify-client'; +import { type StoreProduct } from '@/lib/clients/amplify-client'; /** * Interfaz para representar un producto diff --git a/app/store/hooks/data/useProducts/utils/slugUnique.ts b/app/store/hooks/data/useProducts/utils/slugUnique.ts index ce4653bb..e9d25710 100644 --- a/app/store/hooks/data/useProducts/utils/slugUnique.ts +++ b/app/store/hooks/data/useProducts/utils/slugUnique.ts @@ -1,4 +1,4 @@ -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; // Genera un slug único estilo Shopify: base, base-1, base-2, ... export async function ensureUniqueSlug( diff --git a/app/store/hooks/data/useStoreAnalytics/queries/useStoreAnalyticsQueries.ts b/app/store/hooks/data/useStoreAnalytics/queries/useStoreAnalyticsQueries.ts index b98d2e0f..63f7a833 100644 --- a/app/store/hooks/data/useStoreAnalytics/queries/useStoreAnalyticsQueries.ts +++ b/app/store/hooks/data/useStoreAnalytics/queries/useStoreAnalyticsQueries.ts @@ -5,7 +5,7 @@ import type { AnalyticsPeriod, } from '@/app/store/hooks/data/useStoreAnalytics/types'; import { useAnalyticsCacheUtils, isValidDateFormatAnalytics } from '@/app/store/hooks/data/useStoreAnalytics/utils'; -import { storeClient } from '@/lib/amplify-client'; +import { storeClient } from '@/lib/clients/amplify-client'; /** * Hook para manejar las queries de analíticas de tienda diff --git a/app/store/hooks/data/useStoreAnalytics/types/useStoreAnalytics-types.ts b/app/store/hooks/data/useStoreAnalytics/types/useStoreAnalytics-types.ts index 0d517530..b853244a 100644 --- a/app/store/hooks/data/useStoreAnalytics/types/useStoreAnalytics-types.ts +++ b/app/store/hooks/data/useStoreAnalytics/types/useStoreAnalytics-types.ts @@ -1,4 +1,4 @@ -import { type StoreAnalyticsType } from '@/lib/amplify-client'; +import { type StoreAnalyticsType } from '@/lib/clients/amplify-client'; /** * Tipo principal para las analíticas de tienda diff --git a/app/store/hooks/storage/useLogoUpload.ts b/app/store/hooks/storage/useLogoUpload.ts index bc82578d..00cbaf99 100644 --- a/app/store/hooks/storage/useLogoUpload.ts +++ b/app/store/hooks/storage/useLogoUpload.ts @@ -1,14 +1,10 @@ -import outputs from '@/amplify_outputs.json'; import { getCdnUrlForKey } from '@/utils/client'; -import { Amplify } from 'aws-amplify'; import { getCurrentUser } from 'aws-amplify/auth'; import { uploadData } from 'aws-amplify/storage'; import { useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { getFileExtension } from '@/lib/utils/file-utils'; -Amplify.configure(outputs); - type UploadType = 'logo' | 'favicon'; type UploadStatus = 'idle' | 'uploading' | 'success' | 'error'; diff --git a/app/store/hooks/storage/useS3ImageDelete.ts b/app/store/hooks/storage/useS3ImageDelete.ts index 24e1520a..c7f6ffb8 100644 --- a/app/store/hooks/storage/useS3ImageDelete.ts +++ b/app/store/hooks/storage/useS3ImageDelete.ts @@ -99,19 +99,7 @@ export function useS3ImageDelete() { [storeId, processDeleteChunk] ); - /** - * Función legacy para compatibilidad hacia atrás - elimina una sola imagen - */ - const deleteImage = useCallback( - async (key: string): Promise => { - const result = await deleteImages([key]); - return result ? result.successCount > 0 : false; - }, - [deleteImages] - ); - return { deleteImages, - deleteImage, // Legacy }; } diff --git a/app/store/hooks/storage/useS3ImagesWithOperations.ts b/app/store/hooks/storage/useS3ImagesWithOperations.ts index 454667cf..7e1743d9 100644 --- a/app/store/hooks/storage/useS3ImagesWithOperations.ts +++ b/app/store/hooks/storage/useS3ImagesWithOperations.ts @@ -63,24 +63,26 @@ export function useS3ImagesWithOperations(options: UseS3ImagesWithOperationsOpti const failedKeys = new Set(result.failedDeletes.map((f) => f.key)); const successfullyDeletedKeys = keys.filter((key) => !failedKeys.has(key)); - updateImages((prev) => { - const newImages = prev.filter((img) => !successfullyDeletedKeys.includes(img.key)); - - // Si no quedan imágenes pero hay más disponibles, cargar automáticamente - if (newImages.length === 0 && nextContinuationToken) { - // Usar setTimeout para evitar conflictos con el estado actual - setTimeout(() => { - checkAndLoadMoreIfNeeded(); - }, 100); - } + // Verificar si necesitaremos auto-cargar antes de actualizar el estado + const willNeedAutoLoad = + images.length - successfullyDeletedKeys.length === 0 && nextContinuationToken && fetchMoreImages; - return newImages; + updateImages((prev) => { + return prev.filter((img) => !successfullyDeletedKeys.includes(img.key)); }); + + // Auto-cargar después de la actualización si es necesario + if (willNeedAutoLoad) { + // Usar setTimeout para permitir que la actualización del estado se complete + setTimeout(() => { + fetchMoreImages(); + }, 150); + } } return result; }, - [deleteImagesBase, updateImages, nextContinuationToken, checkAndLoadMoreIfNeeded] + [deleteImagesBase, updateImages, nextContinuationToken, fetchMoreImages, images.length] ); /** @@ -94,14 +96,6 @@ export function useS3ImagesWithOperations(options: UseS3ImagesWithOperationsOpti [uploadImages] ); - const deleteImage = useCallback( - async (key: string): Promise => { - const result = await deleteImages([key]); - return result ? result.successCount > 0 : false; - }, - [deleteImages] - ); - return { // Estado de las imágenes images, @@ -120,7 +114,6 @@ export function useS3ImagesWithOperations(options: UseS3ImagesWithOperationsOpti // Funciones legacy uploadImage, - deleteImage, // Utilidades validateFile, diff --git a/app/store/layout.tsx b/app/store/layout.tsx index a33476ed..60a88695 100644 --- a/app/store/layout.tsx +++ b/app/store/layout.tsx @@ -1,6 +1,6 @@ import '@/app/global.css'; import { StoreLayoutClient } from '@/app/store/layout/StoreLayoutClient'; -import { inter } from '@/lib/fonts'; +import { inter } from '@/lib/fonts/fonts'; export const metadata = { title: 'Mi tienda', diff --git a/app/themes/layout.tsx b/app/themes/layout.tsx index 0af795f3..3571d5db 100644 --- a/app/themes/layout.tsx +++ b/app/themes/layout.tsx @@ -1,4 +1,4 @@ -import { inter } from '@/lib/fonts'; +import { inter } from '@/lib/fonts/fonts'; import '@/app/global.css'; import { Metadata } from 'next'; diff --git a/context/core/storeDataStore.ts b/context/core/storeDataStore.ts index f933f678..ab9306a0 100644 --- a/context/core/storeDataStore.ts +++ b/context/core/storeDataStore.ts @@ -1,7 +1,7 @@ import { CONNECTION_STATE_CHANGE, ConnectionState } from 'aws-amplify/data'; import { Hub } from 'aws-amplify/utils'; import { create } from 'zustand'; -import { storeClient, type StoreUserStore } from '@/lib/amplify-client'; +import { storeClient, type StoreUserStore } from '@/lib/clients/amplify-client'; type StoreType = StoreUserStore; diff --git a/context/core/useSubscriptionStore.ts b/context/core/useSubscriptionStore.ts index ddc8ebe6..47b666d7 100644 --- a/context/core/useSubscriptionStore.ts +++ b/context/core/useSubscriptionStore.ts @@ -1,5 +1,5 @@ import { create } from 'zustand'; -import { storeClient, type StoreUserSubscription } from '@/lib/amplify-client'; +import { storeClient, type StoreUserSubscription } from '@/lib/clients/amplify-client'; // tipo con solo los campos necesarios export type MinimalSubscription = StoreUserSubscription; @@ -60,9 +60,24 @@ function createResource() { // Función auxiliar para obtener los datos de suscripción async function fetchSubscriptionData(username: string): Promise { try { - const { data, errors } = await storeClient.models.UserSubscription.listUserSubscriptionByUserId({ - userId: username, - }); + const { data, errors } = await storeClient.models.UserSubscription.listUserSubscriptionByUserId( + { + userId: username, + }, + { + selectionSet: [ + 'id', + 'userId', + 'subscriptionId', + 'planName', + 'createdAt', + 'updatedAt', + 'nextPaymentDate', + 'pendingPlan', + 'pendingStartDate', + ], + } + ); if (errors && errors.length > 0) { throw new Error('Error getting subscription'); diff --git a/lib/auth-error-messages.ts b/lib/auth/auth-error-messages.ts similarity index 100% rename from lib/auth-error-messages.ts rename to lib/auth/auth-error-messages.ts diff --git a/lib/amplify-client.ts b/lib/clients/amplify-client.ts similarity index 100% rename from lib/amplify-client.ts rename to lib/clients/amplify-client.ts diff --git a/lib/fonts.ts b/lib/fonts/fonts.ts similarity index 100% rename from lib/fonts.ts rename to lib/fonts/fonts.ts diff --git a/lib/utils.ts b/lib/utils.ts index 6f2e64cb..76996cd2 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -21,7 +21,6 @@ export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -// Re-export all utilities for backward compatibility export { getContentType } from './utils/file-utils'; export * from './utils/file-utils'; export * from './utils/validation-utils'; diff --git a/packages/liquid-forge/types/cart.ts b/packages/liquid-forge/types/cart.ts index 77abbb8b..0cb821c5 100644 --- a/packages/liquid-forge/types/cart.ts +++ b/packages/liquid-forge/types/cart.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { StoreCart, StoreCartItem } from '@/lib/amplify-client'; +import type { StoreCart, StoreCartItem } from '@/lib/clients/amplify-client'; export type Cart = Omit & { items: CartItem[];