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
15 changes: 12 additions & 3 deletions amplify/functions/storeImages/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const handler = async (event: any) => {
// Manejar diferentes acciones
switch (action) {
case 'list':
return await listImages(storeId, body.limit, body.prefix)
return await listImages(storeId, body.limit, body.prefix, body.continuationToken)
case 'upload':
return await uploadImage(storeId, body.filename, body.contentType, body.fileContent)
case 'delete':
Expand Down Expand Up @@ -93,7 +93,12 @@ export const handler = async (event: any) => {
}

// Función para listar imágenes
async function listImages(storeId: string, limit: number = 1000, prefix: string = '') {
async function listImages(
storeId: string,
limit: number = 18,
prefix: string = '',
continuationToken?: string
) {
try {
// Configurar el prefijo para las imágenes de la tienda
const storePrefix = prefix ? `products/${storeId}/${prefix}` : `products/${storeId}/`
Expand All @@ -103,6 +108,7 @@ async function listImages(storeId: string, limit: number = 1000, prefix: string
Bucket: bucketName,
Prefix: storePrefix,
MaxKeys: limit,
ContinuationToken: continuationToken,
})

const listResponse = await s3Client.send(listCommand)
Expand Down Expand Up @@ -163,7 +169,10 @@ async function listImages(storeId: string, limit: number = 1000, prefix: string

return {
statusCode: 200,
body: JSON.stringify({ images: validImages }),
body: JSON.stringify({
images: validImages,
nextContinuationToken: listResponse.NextContinuationToken,
}),
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
Expand Down
4 changes: 1 addition & 3 deletions app/(main-layout)/account-settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Amplify.configure({
},
})

// Client component that uses search params
function AccountSettingsContent() {
const searchParams = useSearchParams()
const sectionParam = searchParams.get('section')
Expand All @@ -32,7 +31,6 @@ function AccountSettingsContent() {
)

useEffect(() => {
// Update view when URL parameter changes
if (sectionParam && ['cuenta', 'pagos', 'sesiones'].includes(sectionParam)) {
if (isGoogleUser && sectionParam === 'sesiones') {
setCurrentView('cuenta')
Expand All @@ -43,7 +41,7 @@ function AccountSettingsContent() {
}, [sectionParam, isGoogleUser])

useEffect(() => {
document.title = 'Mi Perfil Fasttify'
document.title = 'Mi Perfil | Fasttify'
}, [])

return (
Expand Down
2 changes: 1 addition & 1 deletion app/(main-layout)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useEffect } from 'react'
import { getCurrentUser, fetchUserAttributes } from 'aws-amplify/auth'
import { ConsoleLogger, Hub } from 'aws-amplify/utils'
import { Hub } from 'aws-amplify/utils'
import { Amplify } from 'aws-amplify'
import 'aws-amplify/auth/enable-oauth-listener'
import DocsLanding from '@/app/(main-layout)/landing/components/DocsLanding'
Expand Down
1 change: 0 additions & 1 deletion app/(main-layout)/pricing/components/PricingCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export function PricingCard({ plan }: PricingCardProps) {
}
}, [isSubmitting])

// Render a skeleton or placeholder during SSR or when loading
if (!isClient || loading) {
return <LoadingIndicator text="Cargando..." />
}
Expand Down
7 changes: 7 additions & 0 deletions app/(main-layout)/pricing/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const metadata = {
title: 'Planes y precios',
}

export default function PricingLayout({ children }: { children: React.ReactNode }) {
return <>{children}</>
}
5 changes: 0 additions & 5 deletions app/(main-layout)/pricing/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client'

import { useEffect } from 'react'
import { motion } from 'framer-motion'
import { PricingCard } from '@/app/(main-layout)/pricing/components/PricingCard'
import { Footer } from '@/app/(main-layout)/landing/components/Footer'
Expand All @@ -22,10 +21,6 @@ Amplify.configure({
})

export default function PricingPage() {
useEffect(() => {
document.title = 'Planes y Pagos • Fasttify'
}, [])

return (
<>
<div className="min-h-screen p-8">
Expand Down
210 changes: 210 additions & 0 deletions app/(setup-layout)/first-steps/hooks/useFirstStepsSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { useState } from 'react'
import { useUserStoreData } from '@/app/(setup-layout)/first-steps/hooks/useUserStoreData'
import { useApiKeyEncryption } from '@/app/(setup-layout)/first-steps/hooks/useApiKeyEncryption'
import { useAuthUser } from '@/hooks/auth/useAuthUser'
import { v4 as uuidv4 } from 'uuid'
import { routes } from '@/utils/routes'
import {
personalInfoSchema,
storeInfoSchema,
additionalSettingsSchema,
} from '@/lib/zod-schemas/first-step'
import sellingOptionsData from '@/app/(setup-layout)/first-steps/data/selling-options.json'

export const useFirstStepsSetup = () => {
const [step, setStep] = useState(1)
const [isStepValid, setIsStepValid] = useState(false)
const [selectedOption, setSelectedOption] = useState<string | null>(null)
const [formData, setFormData] = useState({
fullName: '',
email: '',
phone: '',
documentType: '',
documentNumber: '',

storeName: '',
description: '',
location: '',
category: '',
policies: '',
customDomain: '',

wompiConfig: {
publicKey: '',
signature: '',
},
})

const [validationErrors, setValidationErrors] = useState<Record<string, any>>({})
const [saving, setSaving] = useState(false)
const { userData } = useAuthUser()
const { loading, createUserStore } = useUserStoreData()
const { encryptApiKey } = useApiKeyEncryption()

const cognitoUsername =
userData && userData['cognito:username'] ? userData['cognito:username'] : null

const updateFormData = (data: Partial<typeof formData>) => {
setFormData(prev => ({ ...prev, ...data }))
}
const { options } = sellingOptionsData

// Función para validar el paso actual
const validateStep = (): boolean => {
setValidationErrors({})
let result
if (step === 2) {
result = personalInfoSchema.safeParse(formData)
} else if (step === 3) {
result = storeInfoSchema.safeParse(formData)
} else if (step === 4) {
result = additionalSettingsSchema.safeParse(formData)
}
if (result && !result.success) {
if (step === 4) {
setValidationErrors(result.error.format())
} else {
setValidationErrors(result.error.flatten().fieldErrors)
}
return false
}
return true
}

// Función para avanzar de paso, ejecutando la validación en cada cambio de paso
const nextStep = async () => {
if (step >= 2 && step <= 4) {
const valid = validateStep()
if (!valid) return
}
if (step === 1 && selectedOption) {
setStep(2)
} else if (step < 4) {
setStep(prev => prev + 1)
} else if (step === 4) {
setSaving(true)

try {
// Cifrar las claves de Wompi usando la Lambda
let encryptedPublicKey = null
let encryptedSignature = null

if (formData.wompiConfig.publicKey) {
encryptedPublicKey = await encryptApiKey(
formData.wompiConfig.publicKey,
'wompi',
'publicKey'
)
}

if (formData.wompiConfig.signature) {
encryptedSignature = await encryptApiKey(
formData.wompiConfig.signature,
'wompi',
'signature'
)
}

const storeInput = {
userId: cognitoUsername,
storeId: `${uuidv4().slice(0, 7)}`,
storeType: selectedOption || '',
storeName: formData.storeName,
storeDescription: formData.description,
storeCurrency: 'COP',
storeAdress: formData.location,
contactEmail: formData.email,
contactPhone: parseInt(formData.phone),
contactName: formData.fullName,
customDomain:
formData.customDomain ||
`${formData.storeName.toLowerCase().replace(/\s+/g, '-')}.fasttify.com`,
conctactIdentification: formData.documentNumber,
contactIdentificationType: formData.documentType,
wompiConfig: JSON.stringify({
isActive: true,
publicKey: encryptedPublicKey || formData.wompiConfig.publicKey,
signature: encryptedSignature || formData.wompiConfig.signature,
}),
onboardingCompleted: true,
}

const result = await createUserStore(storeInput)
if (result) {
setTimeout(() => {
window.location.href = routes.store.dashboard.main(result.storeId)
}, 3000)
} else {
setSaving(false)
}
} catch (error) {
console.error('Error al cifrar las claves API:', error)
setSaving(false)
}
}
}

const handleQuickSetup = async () => {
if (!cognitoUsername) return

setSaving(true)
const quickStoreId = uuidv4()
const storeIdShort = quickStoreId.slice(0, 7)
const storeName = `Tienda ${storeIdShort}`

const quickStoreInput = {
userId: cognitoUsername,
storeId: storeIdShort,
storeName: storeName,
customDomain: `${storeName.toLowerCase().replace(/\s+/g, '-')}.fasttify.com`,
storeType: 'quick-setup',
storeCurrency: 'COP',
onboardingCompleted: true,
}

const result = await createUserStore(quickStoreInput)

if (result) {
setTimeout(() => {
window.location.href = routes.store.dashboard.main(result.storeId)
}, 3000)
} else {
setSaving(false)
}
}

const prevStep = () => {
if (step > 1) setStep(prev => prev - 1)
}

const handleStepValidation = (isValid: boolean) => {
setIsStepValid(isValid)
}

return {
step,
setStep,
isStepValid,
setIsStepValid,
selectedOption,
setSelectedOption,
formData,
setFormData,
validationErrors,
setValidationErrors,
saving,
setSaving,
userData,
loading,
createUserStore,
encryptApiKey,
cognitoUsername,
updateFormData,
options,
validateStep,
nextStep,
handleQuickSetup,
prevStep,
handleStepValidation,
}
}
7 changes: 7 additions & 0 deletions app/(setup-layout)/first-steps/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const metadata = {
title: 'Creando tu tienda',
}

export default function FirstStepsLayout({ children }: { children: React.ReactNode }) {
return <>{children}</>
}
Loading
Loading