A
Anonymous

Booking Form - Copy this React, Tailwind Component to your project

Dame los mejores estilos para este formulario de reserva, dame el css por favor: import { useState, useEffect } from "react"; import { v4 as uuidv4 } from "uuid"; const BtnPayu = () => { const [integritySignature, setIntegritySignature] = useState(""); const [referenceCode, setReferenceCode] = useState(""); const currency = "COP"; const [step, setStep] = useState(1); const [buyerData, setBuyerData] = useState({ nombre: "", email: "", telefono: "", }); const [buyerId, setBuyerId] = useState(null); const [locationData, setLocationData] = useState([]); const [dateData, setDateData] = useState([]); const [selectedRoute, setSelectedRoute] = useState(""); const [selectedDate, setSelectedDate] = useState(""); const [formData, setFormData] = useState({ id_ruta: "", id_experiencia: "", id_comprador: "", id_plan: 2, fecha_reserva: "", codigo_descuento: "", descuento: 0, is_active: false, invoice_code: "", precio_base: 0, }); const [loading, setLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(""); const token = localStorage.getItem("token"); useEffect(() => { if (selectedRoute) { // const generatedReferenceCode = `pedido_${uuidv4()}`; // setReferenceCode(generatedReferenceCode); // preProcessWompi(); } }, [selectedRoute]) const preProcessWompi = async () => { const generatedReferenceCode = `pedido_${uuidv4()}`; // setReferenceCode(generatedReferenceCode); const amountInCents = formData.precio_base * 100; const secretKey = 'test_integrity_lsgL5qV3aUYy3CCXYvxoNxD6i8r1xypV'; const currency = "COP"; const concatenatedString = `${generatedReferenceCode}${amountInCents}${currency}${secretKey}`; console.log(`Concatenacion ${concatenatedString}`); try { const response = await fetch(`${import.meta.env.VITE_API_URL}wompi/integrity signature`, { method: "POST", headers: { "Content Type": "application/json", }, body: JSON.stringify({ concatenatedString }), }); console.log('Los datos de wompi: ', response); if (!response.ok) { throw new Error("Error al generar la firma de integridad"); } const data = await response.json(); // setIntegritySignature(data.integritySignature); await wompiCheckoutServices(currency, generatedReferenceCode, amountInCents, data.integritySignature); console.log(`Clave ${data.integritySignature}`); // Guardar la firma generada } catch (error) { console.error("Error al obtener la firma:", error); } }; const wompiCheckoutServices = async (currencyProp, referenceProp, amountPro, integrityProp) => { try { const response = await fetch(`${import.meta.env.VITE_API_URL}bookings`, { method: "POST", headers: { "Content Type": "application/json" }, body: JSON.stringify(formData), }); if (!response.ok) throw new Error("Error al enviar la reserva"); console.log(`Concatenacion 2 ${currencyProp}${amountPro}${referenceProp}`); console.log(`Clave 2 ${integrityProp}`); const checkoutUrl = new URL("https://checkout.wompi.co/p/"); checkoutUrl.searchParams.append("public key", "pub_test_pSDR5jSAYd500xYVraKCBKZAJQeaZj2X"); checkoutUrl.searchParams.append("currency", currencyProp); checkoutUrl.searchParams.append("amount in cents", amountPro); // Enviar en centavos checkoutUrl.searchParams.append("reference", referenceProp); checkoutUrl.searchParams.append("signature:integrity", integrityProp); // Firma generada por el backend window.location.href = checkoutUrl.toString(); } catch (error) { console.error("Error al procesar la reserva:", error); alert("Ocurrió un error al procesar la reserva. Por favor, inténtalo de nuevo."); } }; const handleBuyerChange = (e) => { const { name, value } = e.target; setBuyerData({ ...buyerData, [name]: value, }); }; const handleCreateBuyer = async () => { if (!buyerData.nombre || !buyerData.email || !buyerData.telefono) { alert("Por favor, completa todos los campos del comprador."); return; } try { setLoading(true); // Verificar si el comprador ya existe en la base de datos const checkResponse = await fetch(`${import.meta.env.VITE_API_URL}buyers/`, { method: "GET", headers: { "Content Type": "application/json", "Authorization": `${token}` }, }); const checkData = await checkResponse.json(); const existsBuyer = checkData.find((buyer) => { if (buyer.email === buyerData.email) { return buyer; } }) let buyerId; if (existsBuyer) { // Si ya existe, usar su ID buyerId = existsBuyer.id_comprador; } else { // Si no existe, crearlo const createResponse = await fetch(`${import.meta.env.VITE_API_URL}buyers`, { method: "POST", headers: { "Content Type": "application/json", "Authorization": `${token}` }, body: JSON.stringify(buyerData), }); if (!createResponse.ok) { throw new Error("Error al crear el comprador."); } const createData = await createResponse.json(); buyerId = createData.id_comprador; } // Guardar el ID del comprador y pasar al siguiente paso setBuyerId(buyerId); setFormData((prevFormData) => ({ ...prevFormData, id_comprador: buyerId })); alert("Comprador verificado exitosamente."); setStep(2); } catch (error) { console.error("Error al verificar/crear el comprador:", error); alert("Ocurrió un error. Intenta nuevamente."); } finally { setLoading(false); } }; const handleSubmitReserve = async () => { try { let finalBuyerId = buyerId; // Validación de datos del comprador if (!finalBuyerId && (!buyerData.nombre || !buyerData.email || !buyerData.telefono)) { alert("Por favor, completa los datos del comprador antes de continuar."); return; } setLoading(true); // Si no hay buyerId, verificar o crear comprador if (!finalBuyerId) { const checkResponse = await fetch(`${import.meta.env.VITE_API_URL}buyers/`, { method: "POST", headers: { "Content Type": "application/json", "Authorization": `${token}` }, body: JSON.stringify({ email: buyerData.email }), }); const checkData = await checkResponse.json(); if (!checkResponse.ok) throw new Error(checkData.message || "Error verificando comprador."); finalBuyerId = checkData.exists ? checkData.id : null; // Si el comprador no existe, crearlo if (!finalBuyerId) { const createResponse = await fetch(`${import.meta.env.VITE_API_URL}buyers/`, { method: "POST", headers: { "Content Type": "application/json", "Authorization": `${token}` }, body: JSON.stringify(buyerData), }); const createData = await createResponse.json(); if (!createResponse.ok) throw new Error(createData.message || "Error al crear el comprador."); finalBuyerId = createData.id_comprador; } setFormData(prevFormData => ({ ...prevFormData, id_comprador: finalBuyerId })); } // Enviar la reserva const response = await fetch(`${import.meta.env.VITE_API_URL}bookings/`, { method: "POST", headers: { "Content Type": "application/json", "Authorization": `${token}` }, body: JSON.stringify({ ...formData, id_comprador: finalBuyerId }), }); const data = await response.json(); if (!response.ok) throw new Error(data.message || "Error al crear la reserva."); alert("Reserva creada exitosamente"); // Redirigir a Wompi Checkout preProcessWompi(); } catch (error) { console.error("Error en la reserva:", error); alert(error.message || "Ocurrió un error al procesar la reserva."); } finally { setLoading(false); } }; const getNameReserves = async () => { try { setLoading(true); const response = await fetch(`${import.meta.env.VITE_API_URL}routes`); const data = await response.json(); setLocationData(data); } catch (error) { setErrorMessage("Error al obtener las rutas."); console.error("Error obteniendo las rutas:", error); } finally { setLoading(false); } }; const getExperiences = async (routeId) => { if (!routeId) return; setLoading(true); const response = await fetch(`${import.meta.env.VITE_API_URL}experiences/route/${routeId}`, { method: "GET", headers: { "Content Type": "application/json", "Authorization": `${token}` }, }); const data = await response.json(); setLoading(false); if (Array.isArray(data)) { setDateData(data); } else { console.error("La respuesta de la API no es un arreglo:", data); setDateData([]); } }; const handleRouteSelect = (e) => { const routeId = e.target.value; let price = Math.trunc(Number((locationData.find((route) => route.id_ruta === Number(routeId)).precio_base))); setSelectedRoute(routeId); setFormData({ ...formData, id_ruta: routeId, precio_base: price }); getExperiences(routeId); // Llamar a getExperiences con el routeId }; const handleDateSelect = (e) => { const selectedExperience = e.target.value; const selectedExperienceData = dateData.find((d) => d.id_experiencia === Number(selectedExperience)); if (selectedExperienceData) { setSelectedDate(selectedExperienceData.fecha_realizacion); setFormData((prevFormData) => ({ ...prevFormData, id_experiencia: selectedExperience, fecha_reserva: selectedExperienceData.fecha_realizacion, })) } else { alert("Error al seleccionar la fecha."); } }; useEffect(() => { if (step === 2) { getNameReserves(); } }, [step]); useEffect(() => { if (selectedRoute) { getExperiences(selectedRoute); } }, [selectedRoute]); return ( <div> {step === 1 && ( <div> <h1>Información del Comprador</h1> <form onSubmit={(e) => e.preventDefault()}> <div> <label htmlFor="nombre">Nombre:</label> <input type="text" id="nombre" name="nombre" value={buyerData.nombre} onChange={handleBuyerChange} required /> </div> <div> <label htmlFor="email">Email:</label> <input type="email" id="email" name="email" value={buyerData.email} onChange={handleBuyerChange} required /> </div> <div> <label htmlFor="telefono">Teléfono:</label> <input type="tel" id="telefono" name="telefono" value={buyerData.telefono} onChange={handleBuyerChange} required /> </div> <button type="button" onClick={handleCreateBuyer} disabled={loading}> {loading ? "Cargando..." : "Verificar Comprador"} </button> </form> </div> )} {step === 2 && ( <div> <h2>Reserva</h2> <div> <label htmlFor="route">Ruta:</label> <select id="route" onChange={handleRouteSelect}> <option value="">Selecciona una ruta</option> {locationData.map((route) => ( <option key={route.id_ruta} value={route.id_ruta}> {route.nombre} </option> ))} </select> </div> <div> <label htmlFor="date">Fecha:</label> <select id="date" onChange={handleDateSelect}> <option value="">Selecciona una fecha</option> {dateData.map((experience) => ( <option key={experience.id_experiencia} value={experience.id_experiencia}> {experience.fecha_realizacion} </option> ))} </select> </div> <button onClick={handleSubmitReserve} disabled={loading}> {loading ? "Cargando..." : "Confirmar Reserva"} </button> </div> )} </div> ); }; export default BtnPayu;

Prompt
Component Preview

About

BookingForm - A user-friendly reservation system with buyer verification, route selection, and date picker, built with React and Tail. Free code available!

Share

Last updated 1 month ago