NextJS Templates
คู่มือการใช้แอปการออกใบแจ้งหนี้ด้วย Next.js, Vercel & Back4app
25 นาที
ในบทแนะนำนี้ เราจะสร้าง invoicing app ที่ใช้ next js เป็นส่วนหน้า, back4app เป็นส่วนหลัง, และบริการเพิ่มเติมเช่น clerk สำหรับการตรวจสอบสิทธิ์, stripe สำหรับการชำระเงิน, และ resend สำหรับการแจ้งเตือนทางอีเมล คู่มือนี้จะพาคุณผ่านการตั้งค่าการตรวจสอบสิทธิ์, การจัดการใบแจ้งหนี้, การประมวลผลการชำระเงิน, และการปรับใช้บน vercel 1\ ข้อกำหนดเบื้องต้น ก่อนเริ่มต้น โปรดตรวจสอบว่าคุณมีสิ่งต่อไปนี้ บัญชี back4app ( ลงทะเบียนที่นี่ https //www back4app com/ ) บัญชี clerk ( clerk io https //clerk dev/ ) สำหรับการตรวจสอบสิทธิ์ บัญชี stripe ( stripe com https //stripe com/ ) สำหรับการประมวลผลการชำระเงิน บัญชี resend ( resend io https //resend io/ ) สำหรับการแจ้งเตือนทางอีเมล ติดตั้ง node js และ npm ( การติดตั้ง node js https //nodejs org/ ) 2\ การตั้งค่าส่วนหลัง (back4app) 2 1 สร้างโปรเจกต์ใหม่ใน back4app เข้าสู่ระบบ back4app และสร้างโปรเจกต์ใหม่ ไปที่ data browser และสร้างคลาสต่อไปนี้ 2 2 โมเดลข้อมูล (คลาส) 2 2 1 ผู้ใช้ (จัดการโดย clerk อัตโนมัติ) รหัสวัตถุ ชื่อผู้ใช้ อีเมล 2 2 2 องค์กร สร้างคลาสชื่อ องค์กร เพิ่มคอลัมน์ต่อไปนี้ ชื่อ (string) ชื่อขององค์กร รหัสเจ้าของ (pointer< user>) ชี้ไปที่ ผู้ใช้ คลาส (สร้างโดย clerk อัตโนมัติ) สมาชิก (array\<pointer< user>>) อาร์เรย์ของผู้ใช้ที่เป็นสมาชิกขององค์กรนี้ 2 2 3 ลูกค้า สร้างคลาสชื่อ ลูกค้า เพิ่มคอลัมน์เหล่านี้ ชื่อ (string) ชื่อลูกค้า อีเมล (string) อีเมลของลูกค้า รหัสองค์กร (pointer) องค์กรที่ลูกค้าคนนี้เป็นสมาชิก 2 2 4 ใบแจ้งหนี้ สร้างคลาสชื่อ ใบแจ้งหนี้ เพิ่มคอลัมน์เหล่านี้ invoicenumber (string) รหัสประจำใบแจ้งหนี้ที่ไม่ซ้ำกัน customerid (pointer) เชื่อมโยงกับลูกค้า organizationid (pointer) เชื่อมโยงกับองค์กร amount (number) ยอดรวมสำหรับใบแจ้งหนี้ status (string) ตัวเลือกประกอบด้วย 'ร่าง', 'ส่ง', 'ชำระแล้ว', และ 'เกินกำหนด' duedate (date) วันครบกำหนดชำระใบแจ้งหนี้ items (array) รายการของสินค้าในใบแจ้งหนี้ 2 2 5 การชำระเงิน สร้างคลาสชื่อ การชำระเงิน เพิ่มคอลัมน์เหล่านี้ invoiceid (pointer) เชื่อมโยงกับใบแจ้งหนี้ที่เกี่ยวข้อง amount (number) จำนวนเงินที่ชำระ stripesessionid (string) รหัสของเซสชัน stripe status (string) สถานะการชำระเงิน (เช่น 'รอดำเนินการ', 'สำเร็จ', 'ล้มเหลว') 3\ การตั้งค่า frontend (next js) 3 1 สร้างโปรเจกต์ next js เริ่มต้นด้วยการตั้งค่าโปรเจกต์ next js ของคุณด้วย typescript, tailwind css, และ shadcn/ui components npx create next app\@latest invoicing app typescript cd invoicing app npm install tailwindcss postcss autoprefixer npx tailwindcss init 3 2 ตั้งค่า tailwind css กำหนดค่า tailwind โดยการอัปเดต tailwind config js และเพิ่มสไตล์ไปที่ globals css ใน tailwind config js module exports = { content \[ ' /pages/ / {js,ts,jsx,tsx}', ' /components/ / {js,ts,jsx,tsx}', ], theme { extend {}, }, plugins \[], }; ใน styles/globals css @tailwind base; @tailwind components; @tailwind utilities; 3 3 ติดตั้ง parse sdk และบริการเพิ่มเติม ติดตั้ง dependencies ที่จำเป็นสำหรับ parse, clerk, stripe, และ resend npm install parse @clerk/clerk next stripe resend 3 4 เริ่มต้น parse sdk ใน next js ใน pages/ app tsx , เริ่มต้น parse sdk ด้วยข้อมูลรับรอง 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; แทนที่ 'your app id' และ 'your javascript key' ด้วยข้อมูลรับรอง back4app ของคุณ 4\ การดำเนินการยืนยันตัวตนของผู้ใช้ 4 1 การรวม clerk สำหรับการตรวจสอบสิทธิ์ ตั้งค่า clerk สำหรับการตรวจสอบสิทธิ์ ไปที่แดชบอร์ดของ clerk สร้างแอปพลิเคชัน และดึง api keys ของคุณ อัปเดต env local ไฟล์ของคุณด้วยคีย์ของ clerk next public clerk frontend api=your clerk frontend api clerk api key=your clerk api key ตอนนี้สร้าง pages/sign in tsx และ pages/sign up tsx สำหรับฟังก์ชันการลงชื่อเข้าใช้และการลงทะเบียนโดยใช้ส่วนประกอบของ clerk ใน pages/sign in tsx import { signin } from '@clerk/clerk react'; export default function signinpage() { return \<signin />; } ใน pages/sign up tsx import { signup } from '@clerk/clerk react'; export default function signuppage() { return \<signup />; } 5\ การจัดการองค์กรและลูกค้า 5 1 สร้างองค์กร ผู้ใช้สามารถสร้างองค์กรที่พวกเขาเป็นเจ้าของ สร้างหน้า pages/organizations/new\ tsx สำหรับการสร้างองค์กรใหม่ 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 การจัดการลูกค้า สร้างหน้าการจัดการลูกค้า pages/customers/new\ tsx สำหรับการเพิ่มลูกค้าใหม่ 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\ การจัดการใบแจ้งหนี้ 6 1 สร้างใบแจ้งหนี้ สร้างหน้าการสร้างใบแจ้งหนี้ pages/invoices/new\ tsx สำหรับการสร้างใบแจ้งหนี้ใหม่ 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 การดูใบแจ้งหนี้ สร้างหน้า pages/invoices/index tsx เพื่อดูใบแจ้งหนี้ทั้งหมดพร้อมตัวเลือกการจัดเรียงและการกรอง 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\ การประมวลผลการชำระเงิน (การรวม stripe) 7 1 ตั้งค่า stripe checkout ในการประมวลผลการชำระเงิน ให้รวม stripe เข้าด้วยกัน ใน pages/invoices/\[id] tsx , นำไปใช้ในการสร้างลิงก์การชำระเงินโดยใช้ 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\ การแจ้งเตือนทางอีเมล (การรวมการส่งซ้ำ) 8 1 การส่งอีเมลใบแจ้งหนี้ ตั้งค่า resend เพื่อส่งอีเมลใบแจ้งหนี้ไปยังลูกค้า 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\ การปรับใช้บน vercel ในการปรับใช้แอปบน vercel ให้ติดตั้ง vercel cli และปรับใช้ npm install g vercel vercel กำหนดค่าตัวแปรสภาพแวดล้อมสำหรับ clerk, stripe, resend และ back4app ในแดชบอร์ด vercel ก่อนการปรับใช้ 10\ สรุป ในบทแนะนำนี้ เราได้สร้าง แอปใบแจ้งหนี้ ที่สมบูรณ์ด้วย next js, รวม back4app สำหรับแบ็คเอนด์, clerk สำหรับการตรวจสอบสิทธิ์, stripe สำหรับการชำระเงิน, และ resend สำหรับการแจ้งเตือนทางอีเมล เราได้ครอบคลุมการจัดการผู้ใช้และองค์กร, การสร้างใบแจ้งหนี้, การประมวลผลการชำระเงิน, และการปรับใช้