برنامه نویسی

چگونه با Next.js 13، Typescript و Firebase یک برنامه مدیریت فروش ساختم

در این آموزش، نحوه ساختن یک برنامه مدیریت فروش را به شما توضیح می دهم که به صاحبان فروشگاه یا صندوقداران امکان می دهد با استفاده از Next.js v13، Typescript و Firebase، فروش را ثبت و پیگیری کنند.

پس از تکمیل، می‌توانید با استفاده از ویژگی‌های شگفت‌انگیز Firebase، مانند پایگاه‌داده بلادرنگ و احراز هویت، برنامه‌های کاربردی وب پیشرفته در دنیای واقعی ایجاد کنید.

💡 PS: این آموزش فرض می کند که شما دانش اولیه React یا Next.js را دارید.

کاملا آماده است

گردش کار برنامه

قبل از شروع کدنویسی، اجازه دهید نحوه عملکرد برنامه را خلاصه کنم. اپلیکیشن موارد زیر را انجام می دهد:

  • احراز هویت کاربران از طریق ایمیل و رمز عبور با Firebase،
  • به کاربر (صندوقدار یا صاحب فروشگاه) اجازه می دهد تا دسته بندی های مختلفی برای محصولات ایجاد کند،
  • افزودن و حذف محصولات از برنامه، و
  • فروش روزانه را ثبت و پیگیری کنید.

در اینجا یک نسخه ی نمایشی کوتاه از برنامه است:
https://www.youtube.com/watch?v=Vq1xlL1g9eY

💡 نسخه زنده برنامه را بررسی کنید. نام کاربری است admin@test.com و رمز عبور است admin123

فرآیند طراحی رابط کاربری

در اینجا، من شما را از طریق ایجاد صفحات مورد نیاز برای برنامه وب راهنمایی می کنم.
اول از همه، شما باید یک صفحه ورود ایجاد کنید. شما نیازی به ایجاد یک صفحه ثبت نام ندارید زیرا این صفحه منحصر به فرد کاربر (صندوقدار/صاحب فروشگاه) است.

صفحه ثبت نام

در مرحله بعد، یک صفحه داشبورد که معیارهای برنامه را نشان می دهد و همچنین شامل پیمایش به صفحات دیگر است.

صفحه داشبورد

شما همچنین به یک صفحه محصولات نیاز دارید که در آن کاربر بتواند محصولات جدید را در صورت موجود بودن اضافه کند و در هر زمانی محصولات را حذف کند.

صفحه محصولات

بعد، یک صفحه دسته‌ها ایجاد کنید تا کاربران بتوانند دسته‌ها را اضافه یا حذف کنند.

صفحه دسته ها

در نهایت، باید بخش اصلی برنامه – صفحه فروش را ایجاد کنید، جایی که کاربر می تواند فروش های قبلی را مشاهده کند و موارد جدید اضافه کند.

می‌توانید یک فیلد ورودی تاریخ را در این صفحه اضافه کنید تا کاربر بتواند فروش‌های انجام شده برای هر روز را مانند تصویر زیر واکشی کند.

صفحه فروش

مولفه افزودن فروش جدید می‌تواند یک مودال باشد که وقتی کاربر روی آن کلیک می‌کند نشان داده می‌شود Add New Sales دکمه.

فروش جدید اضافه کنید

در بخش‌های آینده، نحوه ایجاد و اتصال پایگاه داده پشتیبان به رابط کاربری و تعامل با Firebase در برنامه Next.js را خواهید آموخت.

Firebase چیست؟

Firebase یک Backend-as-a-Service (Baas) متعلق به گوگل است که به توسعه دهندگان این امکان را می دهد تا در چند دقیقه برنامه های تحت وب کامل را بسازند. خدماتی مانند Firebase ساخت برنامه های کاربردی وب تمام پشته با مهارت های برنامه نویسی کم یا بدون مهارت را برای توسعه دهندگان فرانت اند بسیار آسان می کند.

Firebase روش های مختلف احراز هویت، پایگاه داده NoSQL، پایگاه داده بلادرنگ، ذخیره سازی فایل، توابع ابری، خدمات میزبانی و بسیاری موارد دیگر را ارائه می دهد.

چگونه Firebase را به برنامه Next.js اضافه کنیم

برای افزودن Firebase به برنامه Next.js، مراحل زیر را دنبال کنید:

یک برنامه Next.js 13 ایجاد کنید که از Typescript و the استفاده می کند app روتر.

npx create-next-app sales-app
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از کنسول Firebase دیدن کنید و با یک حساب Gmail وارد شوید.

پس از ورود به سیستم، یک پروژه Firebase ایجاد کنید.

انتخاب کنید </> برای ایجاد یک برنامه وب Firebase جدید.

ایجاد برنامه وب Firebase

نام برنامه خود را وارد کنید و برنامه را ثبت کنید.

برنامه Firebase خود را ثبت کنید

با اجرای قطعه کد زیر Firebase SDK را نصب کنید.

npm install firebase
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ایجاد یک firebase.ts فایل را در ریشه پروژه Next.js خود قرار دهید و کد پیکربندی Firebase را برای برنامه خود در فایل کپی کنید.

پیکربندی Firebase

import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";

const firebaseConfig = {
  apiKey: "*****",
  authDomain: "*****",
  projectId: "*****",
  storageBucket: "*****",
  messagingSenderId: "*******",
  appId: "********",
  measurementId: "********"
};

const app = initializeApp(firebaseConfig);
const analytics = getAnalytics(app);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت، به روز رسانی کنید firebase.ts حاوی برخی از ماژول های مورد نیاز برای احراز هویت Firebase و پایگاه داده Firestore.

import { initializeApp, getApps } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { EmailAuthProvider } from "firebase/auth";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: "AIzaSyCtmI3jLzqDSr3UIwuUdBa5ocsN5vjzpW8",
  authDomain: "stock-taking-19198.firebaseapp.com",
  projectId: "stock-taking-19198",
  storageBucket: "stock-taking-19198.appspot.com",
  messagingSenderId: "228033001185",
  appId: "1:228033001185:web:b2020053fb824a87d9a9a0",
  measurementId: "G-79BQVKMPSR"
};

// Initialize Firebase
let app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
const provider = new EmailAuthProvider();
const db = getFirestore(app);
const auth = getAuth(app);

export { provider, auth };
export default db;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تبریک می‌گوییم!🎉 شما با موفقیت Firebase را به برنامه Next.js خود اضافه کردید. در مرحله بعد، بیایید ویژگی های Firebase مورد نیاز را تنظیم کنیم.

راه اندازی Firebase Authentication

قبل از اینکه بتوانید احراز هویت Firebase را به برنامه خود اضافه کنید، باید آن را در کنسول خود تنظیم کنید.

در پنل سمت چپ Build را انتخاب کرده و روی Authentication کلیک کنید.
احراز هویت را اضافه کنید

روی دکمه شروع کلیک کنید، روش ایمیل/رمز عبور را فعال کنید و روی ذخیره کلیک کنید.

Firebase Email/Password Auth

اگر موفقیت آمیز بود، صفحه شما باید این را نشان دهد:

Firebase Auth موفقیت آمیز بود

راه اندازی Firebase Firestore

Firestore Database را از منوی سمت چپ انتخاب کنید و یک پایگاه داده ایجاد کنید.

پایگاه داده را در حالت تست ایجاد کنید و از تنظیمات مکان پیش فرض Cloud Firestore استفاده کنید.

تنظیمات مکان Firebase

پس از ایجاد پایگاه داده خود را انتخاب کنید Usage از نوار منوی بالا، قوانین را ویرایش کنید و تغییرات را منتشر کنید. این به شما امکان می دهد برای مدت زمان طولانی تری به پایگاه داده درخواست دهید.

قوانین پایگاه داده Firebase

💡 PS: اگر این را به عنوان یک پروژه جانبی نمی‌سازید، مطمئن شوید که پایگاه داده را به حالت تولید تغییر دهید تا از حملات سایبری برنامه خود جلوگیری کنید.

در نهایت، سه مجموعه پایگاه داده برای دسته ها، محصولات و داده های فروش ایجاد کنید.

مجموعه های پایگاه داده

تبریک می گویم!🎉 پایگاه داده شما آماده است. به زودی نحوه تعامل با آن را خواهید آموخت.

احراز هویت کاربر با Firebase Auth

در این بخش، شما را با جنبه احراز هویت سیستم مدیریت فروش آشنا خواهم کرد. شما یاد خواهید گرفت که چگونه کاربران را وارد و از برنامه خارج کنید و چگونه از صفحات حاوی داده های محرمانه در برابر کاربران احراز هویت نشده محافظت کنید.

ابتدا a ایجاد کنید utils.ts فایلی که حاوی توابع و وارد کردن آنها به اجزای مورد نیاز است.

ورود به برنامه

تابع زیر به کاربر امکان دسترسی به برنامه را می دهد. ایمیل و رمز عبور کاربر را می پذیرد و یک شی کاربر حاوی تمام اطلاعات کاربر را برمی گرداند.

می توانید یک کاربر جدید در کنسول Firebase خود ایجاد کنید و هنگام ارسال فرم ورود به سیستم، عملکرد زیر را اجرا کنید.

import { AppRouterInstance } from "next/dist/shared/lib/app-router-context";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase";

export const LoginUser = (email: string, password: string, router: AppRouterInstance) => {
    signInWithEmailAndPassword(auth, email, password)
        .then((userCredential) => {
            const user = userCredential.user;
            //👇🏻 logs user's details
            console.log("User >>", user);
            successMessage("Authentication successful 🎉");
            router.push("/dashboard");
        })
        .catch((error) => {
            console.error(error);
            errorMessage("Incorrect Email/Password ❌");
        });
};
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قطعه کد بالا اعتبار کاربر را تأیید می کند و یک شی حاوی تمام اطلاعات مربوط به کاربر را برمی گرداند. اگر فرآیند موفقیت آمیز باشد، کاربر را به صفحه داشبورد هدایت می کند. در غیر این صورت یک خطا برمی گرداند.

خروج کاربران از برنامه

Firebase همچنین ارائه می دهد signOut عملکردی که کاربران را قادر می سازد از برنامه خارج شوند.

هم اکنون به چگونگی کارکرد آن می پردازیم:

import { AppRouterInstance } from "next/dist/shared/lib/app-router-context";
import { signOut } from "firebase/auth";
import { auth } from "./firebase";

export const LogOut = (router: AppRouterInstance) => {
    signOut(auth)
        .then(() => {
            successMessage("Logout successful! 🎉");
            router.push("/");
        })
        .catch((error) => {
            errorMessage("Couldn't sign out ❌");
        });
};
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قطعه کد بالا، کاربران را با دریافت اطلاعات کاربر فعال و خروج آنها از برنامه خارج می کند. signOut تابع.

محافظت از صفحات در برابر کاربران احراز هویت نشده

برای انجام این کار، می‌توانید شی جزئیات کاربر را پس از ورود به سیستم ذخیره کنید یا از Firebase استفاده کنید onAuthStateChanged قلاب.

با استفاده از onAuthStateChanged قلاب:

"use client"
import { auth } from '@/firebase'
import { onAuthStateChanged } from "firebase/auth";
import { useState, useCallback, useEffect } from "react"

const isUserLoggedIn = useCallback(() => {
        onAuthStateChanged(auth, (user) => {
            if (user) {
                setUser({ email: user.email, uid: user.uid });
                //👉🏻 Perform an authenticated request
            } else {
                return router.push("/");
            }
        });
    }, [router]);

useEffect(() => {
    isUserLoggedIn();
}, [isUserLoggedIn]);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این onAuthStateChanged hook بررسی می کند که آیا کاربر فعال است یا خیر و شیء حاوی تمام جزئیات کاربر را برمی گرداند. می‌توانید این تابع را در بارگذاری صفحه برای همه مسیرها، به جز صفحه ورود، اجرا کنید.

ارتباط بلادرنگ با Firebase: ساختار داده و عملیات CRUD

در این بخش، شما را با راه اندازی ساختار داده برای برنامه کاربردی و تعامل با Firebase آشنا می کنم.

مجموعه دسته ها

اولین صفحه ای که در این برنامه راه اندازی می شود صفحه دسته بندی ها است زیرا زمانی که کاربر محصولی را اضافه می کند، باید تحت یک دسته باشد.
بنابراین صفحه دسته بندی های خود را مشابه تصویر زیر ایجاد کنید.

صفحه دسته ها

وقتی کاربر دسته جدیدی را اضافه می کند، قطعه کد زیر را اجرا کنید.

import { collection, addDoc } from "firebase/firestore";
import db from "./firebase";

export const addCategory = async (name: string) => {
    try {
        await addDoc(collection(db, "categories"), {
            name
        })
        successMessage(`${name} category added! 🎉`)
    } catch (err) {
        errorMessage("Error! ❌")
        console.error(err)
}
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قطعه کد بالا نام دسته را از قسمت ورودی می پذیرد و یک سند (دسته) جدید در Firebase ایجاد می کند.

برای حذف یک دسته، قطعه کد زیر را زمانی که کاربر روی دکمه حذف کلیک کرد اجرا کنید.

export const deleteCategory =  async (id: string, name:string) => {
    try {
        //👇🏻 deletes the category
        await deleteDoc(doc(db, "categories", id));
        //👇🏻 delets the products within the category
        const q = query(collection(db, "products"), where("category", "==", name));
        const unsubscribe = onSnapshot(q, (querySnapshot) => {
            querySnapshot.forEach((document) => {
                deleteDoc(doc(db, "products", document.id));
            });
        });
        successMessage(`${name} category deleted 🎉`)
    } catch (err) {
        errorMessage("Encountered an error ❌")
        console.log(err)
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این deleteCategory تابع بالا شناسه و نام دسته انتخابی را می پذیرد، دسته را از لیست حذف می کند و محصولات زیر دسته انتخابی را حذف می کند.

در نهایت، شما باید لیست دسته ها را هنگام بارگیری صفحه از Firebase دریافت کنید. برای این کار تابع زیر را اجرا کنید:

export const getCategories = async (setCategories: any) => {
    try {
        const unsub = onSnapshot(collection(db, "categories"), doc => {
            const docs: any = []
            doc.forEach((d: any) => {
              docs.push( { ...d.data(), id: d.id })
            });
            setCategories(docs)
        }) 
    } catch (err) {
        console.error(err)
        setCategories([])
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قطعه کد بالا یک پارامتر به نام را می پذیرد setCategories – حالت React که شامل همه دسته ها است. سپس درخواستی برای بازیابی لیست دسته ها به Firebase ارسال می کند و آن را به روز می کند setCategories با داده ها بیان کنید.

مجموعه محصولات

پس از راه‌اندازی صفحه دسته‌ها، باید به کاربران اجازه دهید تا محصولات را تحت هر دسته‌بندی موجود اضافه و حذف کنند.

افزودن محصول

ایجاد یک Products صفحه مشابه تصویر بالا است و قطعه کد زیر را زمانی که کاربر محصول جدیدی اضافه می کند، اجرا کنید.

export const addProduct = async (name: string, price: number, category: string) => {
    try {
        await addDoc(collection(db, "products"), {
            name, price, category
        })
        successMessage(`${name} product added! 🎉`)
    }   
         catch (err) {
        errorMessage("Error! ❌")
        console.error(err)
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قطعه کد بالا نام، قیمت و دسته بندی محصول را از فیلد فرم می پذیرد و به آن اضافه می کند. products مجموعه.

برای نمایش محصولات در بارگذاری صفحه، این تابع را اجرا کنید.

export const getProducts = async (setProducts: any) => {
    try {
        const unsub = onSnapshot(collection(db, "products"), doc => {
            const docs: any = []
            doc.forEach((d: any) => {
              docs.unshift( { ...d.data(), id: d.id })
            });
            setProducts(docs)
        }) 
    } catch (err) {
        console.error(err)
        setProducts([])
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت، به کاربر اجازه دهید تا محصولات را از قسمت حذف کند products مجموعه. بنابراین، زمانی که کاربر روی دکمه حذف کلیک می کند، عملکرد زیر را اجرا کنید.

export const deleteProduct =  async (id: string, name:string) => {
    try {
        await deleteDoc(doc(db, "products", id));
        successMessage(`${name} deleted 🎉`)
    } catch (err) {
        errorMessage("Encountered an error ❌")
        console.log(err)
    }

}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تابع نام و شناسه محصول را می پذیرد، سپس محصول را از طریق شناسه خود از مجموعه حذف می کند.

مجموعه فروش

در اینجا، باید عملکردهایی ایجاد کنید که کاربر را قادر می‌سازد تا فروش یک روز خاص و کل فروش انجام شده در پلتفرم را اضافه کند و دریافت کند.

export const addSales = async (customerName: string, customerEmail: string, products: Items[], totalAmount: number, setAddNew: any) => {
    try {
        await addDoc(collection(db, "sales"), {
            customerName, customerEmail, products, totalAmount, timestamp: serverTimestamp()
        })
        successMessage("Sales recorded! 🎉")
        setAddNew(false)

    } catch (err) {
        console.error(err)
        errorMessage("Error! Try again ❌")
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تابع زیر جزئیات مشتری و محصولات را می پذیرد، سپس آنها را به آن اضافه می کند sales مجموعه.

برای دریافت تمام فروش، قطعه کد زیر را در بارگذاری صفحه اجرا کنید. پرس و جو می کند sales جمع آوری و تمام داده ها را برمی گرداند.

export const getSales = async (setSales: any) => {
try {
    const docRef = collection(db, "sales")
    const q = query(docRef, orderBy("timestamp"))
    onSnapshot(q, (snapshot) => {
        const docs: any = []
            snapshot.forEach((d: any) => {
              docs.unshift( { ...d.data(), id: d.id })
            });
        setSales(docs)
    })  
    } catch (err) {
        console.error(err)
        setSales([])
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در صفحه داشبورد، یک کادر کل مبلغ حاصل از فروش را نشان می دهد. قطعه کد زیر کل مبلغ را برمی گرداند.

export const getTotalSales = async (setTotalSales: any) => {
try {
        const unsub = onSnapshot(collection(db, "sales"), doc => {
            let totalSales:number = 0
            doc.forEach((d: any) => {
              totalSales += d.data().totalAmount
            });
            setTotalSales(totalSales)
        }) 
    } catch (err) {
    console.error(err)
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در نهایت، در صفحه محصولات، ممکن است بخواهید فروش هایی را که فقط در یک روز خاص انجام شده است را نمایش دهید. قطعه کد زیر پرس و جو می کند sales جمع آوری و بازگرداندن فروش انجام شده در یک روز خاص.
می توانید عملکرد را ویرایش کنید تا فروش هفتگی، ماهانه، سه ماهه یا سالانه را بازگردانید. فقط باید فرمت Date را با مدت زمان مناسب به روز کنید.

export const getSalesForDay = async (date: Date | null, setSales: any) => {
    try {
        const day = date?.getDate()
        const month = date?.getMonth()
        const year: number | undefined = date?.getFullYear()

        if (day !== undefined && month !== undefined && year !== undefined) {
            const startDate = new Date(year, month, day, 0, 0, 0);
            const endDate = new Date(year, month, day, 23, 59, 59);

            const docRef = collection(db, "sales")
            const q = query(docRef, orderBy("timestamp"), where("timestamp", ">=", Timestamp.fromDate(startDate)), where("timestamp", "<=", Timestamp.fromDate(endDate)))

            onSnapshot(q, (snapshot) => {
                const docs: any = []
                snapshot.forEach((d: any) => {
                docs.unshift( { ...d.data(), id: d.id })
                });
                setSales(docs)
        })
        }

     }
    catch (err) {
        console.error(err)
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه

تبریک می گویم بابت ساختن آن تا اینجای کار! تو یاد گرفتی

  • Firebase چیست،
  • چگونه Firebase را به برنامه Next.js اضافه کنیم،
  • نحوه کار با Firebase Auth و Firebase Firestore و
  • نحوه ساخت اپلیکیشن مدیریت فروش

من یک نسخه زنده از برنامه ساخته ام، آن را بررسی کنید. کد منبع نیز در اینجا موجود است.

Firebase یک ابزار عالی است که تقریباً همه چیزهایی را که برای ساختن یک برنامه وب تمام پشته نیاز دارید را فراهم می کند. اگر می خواهید یک برنامه وب تمام پشته بدون هیچ گونه تجربه برنامه نویسی Backend ایجاد کنید، از Firebase استفاده کنید.

با تشکر از شما برای خواندن! 🎉

باز به کار🙂

آیا از این مقاله لذت بردید یا برای یک نقش از راه دور، تمام وقت یا مبتنی بر قرارداد به یک نویسنده فنی / React Developer با تجربه نیاز دارید؟ هر موقع خواستی با من تماس بگیر.
گیت هاب || لینکدین || توییتر

برای دیوید قهوه بخر
متشکرم

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا