NextJS Templates
Tutorial de aplicación de facturación con Next.js, Vercel y Back4app
26 min
en este tutorial, construiremos una completa invoicing app utilizando next js como el frontend, back4app como el backend, y servicios adicionales como clerk para la autenticación, stripe para los pagos, y resend para las notificaciones por correo electrónico esta guía explicará cómo configurar la autenticación, la gestión de facturas, el procesamiento de pagos y el despliegue en vercel 1\ requisitos previos antes de comenzar, asegúrate de tener lo siguiente una cuenta de back4app ( regístrate aquí https //www back4app com/ ) una cuenta de clerk ( clerk io https //clerk dev/ ) para la autenticación una cuenta de stripe ( stripe com https //stripe com/ ) para el procesamiento de pagos una cuenta de resend ( resend io https //resend io/ ) para las notificaciones por correo electrónico node js y npm instalados ( instalación de node js https //nodejs org/ ) 2\ configurando el backend (back4app) 2 1 crear un nuevo proyecto en back4app inicia sesión en back4app y crea un nuevo proyecto navega a la data browser y crea las siguientes clases 2 2 modelos de datos (clases) 2 2 1 usuario (manejado automáticamente por clerk) objectid nombre de usuario correo electrónico 2 2 2 organización crea una clase llamada organización agrega las siguientes columnas nombre (string) el nombre de la organización ownerid (pointer< user>) apunta a la usuario clase (creada automáticamente por clerk) miembros (array\<pointer< user>>) un array de usuarios que pertenecen a esta organización 2 2 3 cliente crea una clase llamada cliente agrega estas columnas nombre (string) nombre del cliente correo electrónico (string) correo electrónico del cliente organizationid (pointer) organización a la que pertenece este cliente 2 2 4 factura crea una clase llamada factura agrega estas columnas numerofactura (string) identificador único de la factura idcliente (pointer) enlaza al cliente idorganizacion (pointer) enlaza a la organización monto (number) monto total de la factura estado (string) las opciones incluyen 'borrador', 'enviado', 'pagado' y 'vencido' fechavencimiento (date) la fecha de vencimiento de la factura artículos (array) la lista de artículos en la factura 2 2 5 pago crea una clase llamada pago agrega estas columnas idfactura (pointer) enlaza a la factura relacionada monto (number) monto del pago idsesionstripe (string) el id de la sesión de stripe estado (string) estado del pago (por ejemplo, 'pendiente', 'exitoso', 'fallido') 3\ configuración del frontend (next js) 3 1 crear un proyecto next js comienza configurando tu proyecto next js con typescript, tailwind css y componentes de shadcn/ui npx create next app\@latest invoicing app typescript cd invoicing app npm install tailwindcss postcss autoprefixer npx tailwindcss init 3 2 configurar tailwind css configura tailwind actualizando el tailwind config js y añadiendo los estilos a globals css en tailwind config js module exports = { content \[ ' /pages/ / {js,ts,jsx,tsx}', ' /components/ / {js,ts,jsx,tsx}', ], theme { extend {}, }, plugins \[], }; en styles/globals css @tailwind base; @tailwind components; @tailwind utilities; 3 3 instalar parse sdk y servicios adicionales instala las dependencias necesarias para parse, clerk, stripe y resend npm install parse @clerk/clerk next stripe resend 3 4 inicializar parse sdk en next js en pages/ app tsx , inicializa el parse sdk con tus credenciales de back4app import { clerkprovider } from '@clerk/clerk react'; import parse from 'parse'; parse initialize('your app id', 'your javascript key'); parse serverurl = 'https //parseapi back4app com'; function myapp({ component, pageprops }) { return ( \<clerkprovider> \<component { pageprops} /> \</clerkprovider> ); } export default myapp; reemplaza 'your app id' y 'your javascript key' con tus credenciales de back4app 4\ implementación de la autenticación de usuarios 4 1 integración de clerk para autenticación configura clerk para la autenticación ve al panel de control de clerk, crea una aplicación y obtén tus claves api actualiza tu env local archivo con las claves de clerk next public clerk frontend api=your clerk frontend api clerk api key=your clerk api key ahora crea pages/sign in tsx y pages/sign up tsx para la funcionalidad de inicio de sesión y registro utilizando los componentes de clerk en pages/sign in tsx import { signin } from '@clerk/clerk react'; export default function signinpage() { return \<signin />; } en pages/sign up tsx import { signup } from '@clerk/clerk react'; export default function signuppage() { return \<signup />; } 5\ organización y gestión de clientes 5 1 crear organizaciones los usuarios pueden crear organizaciones que poseen crea una página pages/organizations/new\ tsx para crear nuevas organizaciones import { usestate } from 'react'; import parse from 'parse'; export default function neworganization() { const \[name, setname] = usestate(''); const handlecreateorganization = async () => { const organization = parse object extend('organization'); const organization = new organization(); organization set('name', name); organization set('ownerid', parse user current()); try { await organization save(); alert('organization created successfully!'); } catch (error) { console error('error creating organization ', error); } }; return ( \<div> \<h1>create new organization\</h1> \<input type="text" value={name} onchange={(e) => setname(e target value)} placeholder="organization name" /> \<button onclick={handlecreateorganization}>create\</button> \</div> ); } 5 2 gestionar clientes crea una página de gestión de clientes pages/customers/new\ tsx para agregar nuevos clientes import { usestate } from 'react'; import parse from 'parse'; export default function newcustomer() { const \[name, setname] = usestate(''); const \[email, setemail] = usestate(''); const handlecreatecustomer = async () => { const customer = parse object extend('customer'); const customer = new customer(); customer set('name', name); customer set('email', email); customer set('organizationid', parse user current() get('organizationid')); try { await customer save(); alert('customer created successfully!'); } catch (error) { console error('error creating customer ', error); } }; return ( \<div> \<h1>create new customer\</h1> \<input type="text" value={name} onchange={(e) => setname(e target value)} placeholder="customer name" /> \<input type="email" value={email} onchange={(e) => setemail(e target value)} placeholder="customer email" /> \<button onclick={handlecreatecustomer}>create\</button> \</div> ); } 6\ gestión de facturas 6 1 crear facturas crea una página de creación de facturas pages/invoices/new\ tsx para generar nuevas facturas import { usestate } from 'react'; import parse from 'parse'; export default function newinvoice() { const \[invoicenumber, setinvoicenumber] = usestate(''); const \[amount, setamount] = usestate(0); const handlecreateinvoice = async () => { const invoice = parse object extend('invoice'); const invoice = new invoice(); invoice set('invoicenumber', invoicenumber); invoice set('amount', amount); invoice set('organizationid', parse user current() get('organizationid')); try { await invoice save(); alert('invoice created successfully!'); } catch (error) { console error('error creating invoice ', error); } }; return ( \<div> \<h1>create new invoice\</h1> \<input type="text" value={invoicenumber} onchange={(e) => setinvoicenumber(e target value)} placeholder="invoice number" /> \<input type="number" value={amount} onchange={(e) => setamount(parsefloat(e target value))} placeholder="amount" /> \<button onclick={handlecreateinvoice}>create\</button> \</div> ); } 6 2 visualización de facturas crea una página pages/invoices/index tsx para ver todas las facturas con opciones de ordenamiento y filtrado import { useeffect, usestate } from 'react'; import parse from 'parse'; export default function invoiceslist() { const \[invoices, setinvoices] = usestate(\[]); useeffect(() => { const fetchinvoices = async () => { const invoice = parse object extend('invoice'); const query = new parse query(invoice); const results = await query find(); setinvoices(results); }; fetchinvoices(); }, \[]); return ( \<div> \<h1>invoices\</h1> {invoices map(invoice => ( \<div key={invoice id}> \<h2>invoice #{invoice get('invoicenumber')}\</h2> \<p>amount ${invoice get('amount')}\</p> \<p>status {invoice get('status')}\</p> \</div> ))} \</div> ); } 7\ procesamiento de pagos (integración de stripe) 7 1 configurar stripe checkout para procesar pagos, integra stripe en pages/invoices/\[id] tsx , implementa la creación del enlace de pago utilizando stripe checkout import { userouter } from 'next/router'; import { useeffect, usestate } from 'react'; import stripe from 'stripe'; export default function invoicedetail() { const router = userouter(); const { id } = router query; const \[invoice, setinvoice] = usestate(null); useeffect(() => { if (!id) return; const fetchinvoice = async () => { const invoice = parse object extend('invoice'); const query = new parse query(invoice); query equalto('objectid', id); const result = await query first(); setinvoice(result); }; fetchinvoice(); }, \[id]); const handlepayinvoice = async () => { const stripe = new stripe(process env stripe secret key); const session = await stripe checkout sessions create({ payment method types \['card'], line items \[ { price data { currency 'usd', product data { name `invoice #${invoice get('invoicenumber')}` }, unit amount invoice get('amount') 100, }, quantity 1, }, ], mode 'payment', success url window\ location origin + '/success', cancel url window\ location origin + '/cancel', }); window\ location href = session url; }; if (!invoice) return \<div>loading \</div>; return ( \<div> \<h1>invoice #{invoice get('invoicenumber')}\</h1> \<p>amount ${invoice get('amount')}\</p> \<button onclick={handlepayinvoice}>pay now\</button> \</div> ); } 8\ notificaciones por correo electrónico (integración de reenvío) 8 1 enviando correos electrónicos de facturas configura resend para enviar correos electrónicos de facturas a los clientes import { resend } from 'resend'; export default async function sendinvoiceemail(invoiceid) { const resend = new resend(process env resend api key); const invoice = await fetchinvoicedetails(invoiceid); // function to fetch invoice details const customer = await fetchcustomerdetails(invoice customerid); await resend sendemail({ from 'no reply\@invoicingapp com', to customer email, subject `invoice #${invoice invoicenumber}`, html `\<h1>invoice #${invoice invoicenumber}\</h1>\<p>amount ${invoice amount}\</p>`, }); } 9\ despliegue en vercel para desplegar la aplicación en vercel, instala la cli de vercel y despliega npm install g vercel vercel configura las variables de entorno para clerk, stripe, resend y back4app en el panel de vercel antes del despliegue 10\ conclusión en este tutorial, construimos una completa aplicación de facturación con next js, integrada con back4app para el backend, clerk para la autenticación, stripe para los pagos, y resend para las notificaciones por correo electrónico cubrimos la gestión de usuarios y organizaciones, la creación de facturas, el procesamiento de pagos y el despliegue