0% found this document useful (0 votes)
28 views50 pages

Abhis Synopsys Final

The document is a project synopsis for an E-commerce application developed by Abhishek Kumar as part of his Master of Computer Application degree. It outlines the project's objectives, technical specifications, and features, emphasizing its role as a cloud storage and file-sharing platform built using modern technologies like React, Next.js, and Appwrite. The synopsis includes sections on project scope, user interface, backend integration, and requirements for successful implementation.

Uploaded by

roheja7539
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views50 pages

Abhis Synopsys Final

The document is a project synopsis for an E-commerce application developed by Abhishek Kumar as part of his Master of Computer Application degree. It outlines the project's objectives, technical specifications, and features, emphasizing its role as a cloud storage and file-sharing platform built using modern technologies like React, Next.js, and Appwrite. The synopsis includes sections on project scope, user interface, backend integration, and requirements for successful implementation.

Uploaded by

roheja7539
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 50

A PROJECT SYNOPSIS

ON

“E-commerce project”

(KCA 451)
Submitted in Partial Fulfillment of the requirements for The
Award of the Degree of

MASTER OF COMPUTER APPLICATION

BY

ABHISHEK KUMAR
(2300160140002)
Under the Supervision of
UDIT AGARWAL
(DEAN)

M.C.A DEPARTMENT

RBMI GROUP OF INSTITUTIONS,


BAREILLY, UTTAR PRADESH, 243001

(AFFILIATED TO DR. A. P. J. ABDUL


KALAM TECHNICAL UNIVERSITY,
LUCKNOW, UTTAR PRADESH, 226031)

(2025)
Table of Contents
Acknowledgement
Certificate

Declaration

1.Introduction
2.Background and Overview
3. Aims and Objectives
a. Technical Objectives
b.Code Architecture
c. Data Management Objectives
d.Educational, Functional, and Technical Objectives
e. Features of E-Commerce
f. Project Screenshots
4. Project Scope
a. User Interface
b.File Management Features
c. File Sharing & Collaboration
d.Authentication & User
Management
e. Technical Implementation
5. Survey of Technologies
6.Frontend
7. Backend and Database
8.Requirement and Analysis
a. Hardware Requirements
b.Software Requirements
c. Functional Requirements
d. Installation Requirements

e. Steps to run project locally


9. Data Flow Analysis
a. Data Flow Diagram for Login System
b.Data Flow Diagram for Web App
Usage
c. Application Workflow Diagram
10. Codebase
11. Testing
a. Functional Testing
b.Performance Testing
c. Security Testing
12. Setup of Project
13. Bibliography
Acknowledgement
As anyone who has written a project work, it is quite impossible to
acknowledge by name every individual who has played a part in this
work. I feel difficult to express in words my profound sense of
gratitude to the most respected persons who helped me to make this
possible.

I acknowledge my gratitude to respected Mr. Udit Agrawal (DEAN)


and Mr. Dhanish Tandon (HOD) who has been kind enough to
suggest improvements and guidance of this work and make it broad
based.

I also extend my sincere thanks to RBMI Group of Institution and


all the MCA Department faculty members for providing me with
the necessary resources and a conducive learning environment.

ABHISHEK KUMAR
(2300160140002)
M.C.A 2nd Year (4th Semester)
Certificate

This is to certify that the project titled “E-commerce” submitted to


RBMI Group of Institutions is a bonafide work carried out by
ABHISHEK KUMAR under my supervision and guidance for the
partial fulfillment of the requirements for the award of the degree of
Master of Computer Application.

This project is an original work and has not been


submitted elsewhere for any other degree.

DATE:
TEACHER:
SIGNATURE:
DEPARTMENT: MCA

RBMI GROUP OF INSTITUTIONS, BAREILLY


Declaration

I declare that the project report entitled, “E-Commerce”


submitted to RBMI Group of Institutions for consideration of
degree of Master of Computer Application embodies my own
work with suggestions received during the work, which have
been suitably acknowledged.

ABHISHEK
KUMAR
(2300160140002)
M.C.A 2nd Year (4th Semester)
1

1. Introduction
A website is a collection of interlinked web pages that are hosted on
a server and accessed through the internet using a web browser.
Websites are primarily designed to provide information or
showcase content to visitors. They can range from simple static
pages to complex, dynamic platforms.
A web application (web app) is a software application that runs in a
web browser. Unlike a traditional website, which focuses on
presenting static or dynamic content, a web app is designed for
interactivity and functionality, allowing users to perform specific
tasks.
Key Characteristics of a Web App:

1. Functionality-Focused: Web apps enable users to interact with


the software to perform tasks such as filling out forms, creating
content, managing data, or collaborating in real-time.
2. Dynamic and Interactive: The content and interface
often change based on user input or actions.
3. Technology:

○ Built with modern web technologies like HTML, CSS,


JavaScript, and frameworks like React, Vue.js, or
Angular.
○ Often involves a backend for processing requests and
storing data (e.g., Node.js, Mongodb).
4.
5. Authentication: Many web apps require users to log in for
access or to save personalized data.
6. Cross-Platform: Accessible on any device with a browser,
and they may also have mobile-optimized versions or
companion apps.
2

E-Commerce is a modern cloud storage and file-sharing platform


designed to meet the growing need for efficient and user-friendly
digital file management. It enables users to securely upload, organize,
and share various file types with ease. The platform is developed
using cutting-edge technologies like React 19, Next.js 15, and
Appwrite’s backend-as-a-service features, ensuring optimal
performance, scalability, and developer experience. With an intuitive
user interface and robust backend integration, E-Commerce serves as
an open-source alternative to commercial cloud storage solutions.
3

2. Background and Overview


As digital workspaces expand, there is an increasing demand
for seamless file storage and collaboration tools.
Existing platforms like Google Drive, Dropbox, and OneDrive offer
extensive services, but they often come with limitations such as
restricted customizability, complex pricing models, and vendor
lock-in and boring user interface.
E-Commerce was created to provide a lightweight yet powerful
alternative, leveraging Appwrite for authentication, storage, and
backend logic.
By using Next.js for server-side rendering and optimized routing,
and TailwindCSS and ShadCN for UI, the application achieves
high responsiveness, simplicity, and maintainability.
The project addresses common challenges like:

● Real-time file sharing


● Intuitive menu navigation
● Efficient search and filtering
● Responsive mobile-first design
● Secure File Access Control: Ensuring only authorized users
can view, download, or manage specific files.
● User-Friendly File Organization: Allowing users to easily
sort, rename, and categorize their files for better productivity.
● High-Performance File Uploads: Handling large file
uploads without performance drops or timeouts.
● Optimized Cross-Device Experience: Delivering a consistent and
smooth user interface across desktops, tablets, and
smartphones.
● Good User Interface and Experience
4

3. Aims and Objectives


● To build a secure, intuitive, and feature-rich cloud storage
system
● To provide a modern, responsive UI across all devices
● To implement robust file management (upload, view,
rename, delete, download)
● To support file sharing with controlled access
● To offer storage analytics and insights through a
dynamic dashboard
● To ensure seamless integration of backend functionalities
using Appwrite
● To maintain modular and reusable code for scalability and
future enhancements
Technical Objectives:

● Implement secure file upload and storage using Appwrite’s


storage service.
● Develop a responsive and scalable front-end using React 19
and TailwindCSS.
● Integrate user authentication with Appwrite, supporting
signup, login, and logout.
● Enable real-time file management operations such as
renaming, deleting, and sharing files.
Code Architecture:

● Maintain modular code structure for scalability and


reusability using component-based architecture in React.
● Leverage Next.js 15’s App Router and server actions for
better server-client separation.
Utilize TypeScript for type safety and better developer
experience.
5

● Follow clean folder structure and naming conventions


for consistency across the codebase.
Data Management Objectives:

● Store and retrieve user files efficiently using Appwrite


buckets. ● Maintain metadata (file name, type, size,
timestamps) for quick
access and filtering.
● Implement global search for seamless file discovery.
● Provide file statistics and storage insights on the user dashboard.

Educational, Functional and Technical Objectives:

● Demonstrate full-stack web application development using


modern frameworks.
● Showcase integration of third-party BaaS
(Backend-as-a-Service) tools like Appwrite.
● Allow users to upload, manage, and share files from a
central dashboard.
● Provide dynamic insights like total storage used, file types,
and recent activity.
● Build using modern stack: React 19, Next.js 15,
TypeScript, TailwindCSS, and ShadCN.
● Integrate Appwrite SDKs for authentication, database, and
storage services.
● Ensure scalability and responsiveness with optimized
component design.
● Offer a clean and intuitive UI that supports both desktop
and mobile users.
6

Features of E-Commerce
● User authentication using Appwrite (signup, login, logout)
● Upload various file types (documents, images, videos, audio,
etc.)
● Preview files in a new tab
● - Rename, Delete and Download files from
storage
● - File sharing via unique share links
● - Dashboard with:
○ Total and used storage display
○ Recent uploads
○ File type categorization and summary
● - Global search across all uploaded files and shared
content
● - Sorting options by date, name, or file size
● - Responsive and modern user interface
● - Integration with Appwrite Node SDK
● - Environment configuration via
.env.local
● - Secure access and API communication with
environment variables
● - Clean and reusable component architecture
● - Modern state management and API handling
practices
● - Clean Modern Interface
7
Project Screenshots:
8
1
1
11

4. Project Scope
E-Commerce's functionality encompasses both individual users and
small teams.
a. User Interface
● Dashboard with overview of storage usage and file statistics
● Upload section with drag-and-drop and browse functionality

Responsive design across devices (desktop, tablet, mobile)


● Global search bar to locate files quickly

b. File Management Features


● Support for uploading documents, images, audio, and
video
● View files in a new tab (images, etc.)
Rename files directly from the dashboard
● Delete unwanted or old files with confirmation
prompt
● Download files with a single click
● Sorting by name, type, size, or upload date

c. File Sharing & Collaboration


● Generate shareable links for any uploaded file
● Toggle public/private access to control
visibility
● Copy file URLs to clipboard for easy
distribution
● View count or access logs (future enhancement possibility)
12

d. Authentication & User Management


● Signup and login using Appwrite
authentication
● Session persistence with secure tokens
● Logout functionality to destroy session
● User-based file storage: files linked to specific user accounts

e. Technical Implementation
● Built using React 19 and Next.js 15 with App Router
● Appwrite Node SDK integration for storage and
authentication
● TailwindCSS and ShadCN for clean, modern UI components
● TypeScript for strong typing and developer safety
● Environment variable management for secure project
configuration
● Optimized routing and lazy loading for performance
● File size and type validation before upload

5. Survey of Technologies
● JavaScript: JavaScript is a scripting programming language
used to create interactions and control over the contents of the
webpage. JS is used here in this project mostly. Although I am
not using pure vanilla JS here instead I am using ReactJS which
is a Library of JavaScript itself.
● React 19: Enables the development of modular,
component-driven UIs with high performance.
● Next.js 15: Provides routing, server-side rendering, and
API routes, making it ideal for scalable applications.
● Appwrite: Serves as the BaaS backend, offering services
like authentication, storage, and databases.
● CSS: Cascading style sheets is used to format and give
the structure to the content of the webpage. It is used to
give the overall look to the webpage.
● TailwindCSS: A utility-first CSS framework that promotes
clean, responsive, and customizable UIs.
13
● ShadCN UI: A modern React component library that speeds
up frontend development.
● TypeScript: Adds type safety to JavaScript, improving
reliability and developer productivity.
● VSCode: It is a Integrated development env for
programming which Includes built-in support for JavaScript,
TypeScript, and Node.js, plus extensions for other
languages and runtimes.
● NPM and NodeJS: Nodejs is a runtime env which is used
to create backends for javascript based webapps, NPM is
used to manage node packages and modules.
14

6. Frontend
The frontend consists of:

● Authentication screens (login, signup, logout)


● File upload interface with drag-and-drop
support
● Dashboard for storage statistics and recent activities
● File manager for previewing, renaming, deleting, and
downloading files
● Global search bar and sorting filters
● Sharing modal with options to generate public or restricted
links ● Fully responsive layout with mobile-first design

7. Backend and Database


Appwrite acts as the backend and database engine. It facilitates:

● User session management and OAuth


support
● Secure file uploads to Appwrite Buckets
● Database records for file metadata (e.g., name, size, type,
date) ● Custom APIs using Appwrite Functions for advanced
processing
● Permission handling to ensure secure file sharing and access
● Users Collection: Tracks registered users and their associated
data
● Files Collection: Holds metadata (filename, file ID, user
ID, timestamp, type, size)
● Storage Buckets: Contains the actual file binaries
● Logs Collection (optional): Records actions like
downloads, shares, and deletions for analytics

8. Requirement / Analysis of Hardware and


15
Software
Hardware Requirements:

● Minimum RAM: 8 GB
● Processor: Multi-core CPU (i5 or higher recommended)
● Storage: At least 10 GB for development and test files
Internet: Stable connection for API integration and
Appwrite services
Software Requirements:

● Operating System: Windows 10+, macOS, or Linux

● Code Editor: Visual Studio Code or any modern


IDE
● Node.js v18 or higher
● Package Manager: npm or yarn
● Web Browser: Chrome, Firefox, or Safari (latest versions)

Functional Requirements

● Secure user registration, login, and logout


● Upload files (images,)
● Preview files in a new tab (for supported formats)
● Rename or delete existing files
● Download any file with a single click
● Generate shareable file links with permission
control
● Track storage space consumed
● View recent uploads and summary by file
type ● Search and sort through all files

- Installation Requirements
- Steps to run E-Commerce locally:
1. Copy the code
2. Install Node.js (version 18+).
3. Create a .env.local file with the following keys:
16

NEXT_PUBLIC_APPWRITE_ENDPOINT="https://cloud.appwrite.i
o/v 1"
NEXT_PUBLIC_APPWRITE_PROJECT="your_project_id"
NEXT_PUBLIC_APPWRITE_DATABASE="your_database_id"
NEXT_PUBLIC_APPWRITE_USERS_COLLECTION="users_colle
cti
on_id"
NEXT_PUBLIC_APPWRITE_FILES_COLLECTION="files_collect
io
n_id"
NEXT_PUBLIC_APPWRITE_BUCKET="bucket_id"
NEXT_APPWRITE_KEY="your_appwrite_key"

Install dependencies using npm:

npm install

Run the project:

npm run dev


17

9. Data Flow Analysis

(Data Flow Diagram for Login System)

(Data Flow Diagram for Web App Usage)


1
9
3

10. Codebase
app/(root)/page.js
import { Route, Routes } from "react-router-dom";
import AuthLayout from "./components/auth/layout";
import AuthLogin from "./pages/auth/login";
import AuthRegister from "./pages/auth/register";
import AdminLayout from "./components/admin-view/layout";
import AdminDashboard from "./pages/admin-view/dashboard";
import AdminProducts from "./pages/admin-view/products";
import AdminOrders from "./pages/admin-view/orders";
import AdminFeatures from "./pages/admin-view/features";
import ShoppingLayout from "./components/shopping-view/layout";
import NotFound from "./pages/not-found";
import ShoppingHome from "./pages/shopping-view/home";
import ShoppingListing from "./pages/shopping-view/listing";
import ShoppingCheckout from "./pages/shopping-view/checkout";
import ShoppingAccount from "./pages/shopping-view/account";
import CheckAuth from "./components/common/check-auth";
import UnauthPage from "./pages/unauth-page";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { checkAuth } from "./store/auth-slice";
import { Skeleton } from "@/components/ui/skeleton";
import PaypalReturnPage from "./pages/shopping-view/paypal-return";
import PaymentSuccessPage from "./pages/shopping-view/payment-success";
import SearchProducts from "./pages/shopping-view/search";

function App() {
const { user, isAuthenticated, isLoading } = useSelector(
(state) => state.auth
);
const dispatch = useDispatch();

useEffect(() => {
dispatch(checkAuth());
}, [dispatch]);

if (isLoading) return <Skeleton className="w-[800] bg-black h-[600px]" />;

console.log(isLoading, user);

return (
<div className="flex flex-col overflow-hidden bg-white">
<Routes>
<Route
path="/"
element={
<CheckAuth
isAuthenticated={isAuthenticated}
user={user}
></CheckAuth>
}
/>
<Route
path="/auth"
element={
<CheckAuth isAuthenticated={isAuthenticated} user={user}>
3
<AuthLayout />
</CheckAuth>
}
>
<Route path="login" element={<AuthLogin />} />
<Route path="register" element={<AuthRegister />} />
</Route>
<Route
path="/admin"
element={
<CheckAuth isAuthenticated={isAuthenticated} user={user}>
<AdminLayout />
</CheckAuth>
}
>
<Route path="dashboard" element={<AdminDashboard />} />
<Route path="products" element={<AdminProducts />} />
<Route path="orders" element={<AdminOrders />} />
<Route path="features" element={<AdminFeatures />} />
</Route>
<Route
path="/shop"
element={
<CheckAuth isAuthenticated={isAuthenticated} user={user}>
<ShoppingLayout />
</CheckAuth>
}
>
<Route path="home" element={<ShoppingHome />} />
<Route path="listing" element={<ShoppingListing />} />
<Route path="checkout" element={<ShoppingCheckout />} />
<Route path="account" element={<ShoppingAccount />} />
<Route path="paypal-return" element={<PaypalReturnPage />} />
<Route path="payment-success" element={<PaymentSuccessPage />} />
<Route path="search" element={<SearchProducts />} />
</Route>
<Route path="/unauth-page" element={<UnauthPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
);
}

export default App;

auth/login
import CommonForm from "@/components/common/form";
import { useToast } from "@/components/ui/use-toast";
import { loginFormControls } from "@/config";
import { loginUser } from "@/store/auth-slice";
import { useState } from "react";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";

const initialState = {
email: "",
password: "",
};

function AuthLogin() {
3
const [formData, setFormData] = useState(initialState);
const dispatch = useDispatch();
const { toast } = useToast();

function onSubmit(event) {
event.preventDefault();

dispatch(loginUser(formData)).then((data) => {
if (data?.payload?.success) {
toast({
title: data?.payload?.message,
});
} else {
toast({
title: data?.payload?.message,
variant: "destructive",
});
}
});
}

return (
<div className="mx-auto w-full max-w-md space-y-6">
<div className="text-center">
<h1 className="text-3xl font-bold tracking-tight text-foreground">
Sign in to your account
</h1>
<p className="mt-2">
Don't have an account
<Link
className="font-medium ml-2 text-primary hover:underline"
to="/auth/register"
>
Register
</Link>
</p>
</div>
<CommonForm
formControls={loginFormControls}
buttonText={"Sign In"}
formData={formData}
setFormData={setFormData}
onSubmit={onSubmit}
/>
</div>
);
}

export default AuthLogin;

auth/registreation
import CommonForm from "@/components/common/form";

import { useToast } from "@/components/ui/use-toast";

import { registerFormControls } from "@/config";

import { registerUser } from "@/store/auth-slice";

import { useState } from "react";


3
import { useDispatch } from "react-redux";

import { Link, useNavigate } from "react-router-dom";

const initialState = {

userName: "",

email: "",

password: "",

};

function AuthRegister() {

const [formData, setFormData] = useState(initialState);

const dispatch = useDispatch();

const navigate = useNavigate();

const { toast } = useToast();

function onSubmit(event) {

event.preventDefault();

dispatch(registerUser(formData)).then((data) => {

if (data?.payload?.success) {

toast({

title: data?.payload?.message,

});

navigate("/auth/login");

} else {

toast({

title: data?.payload?.message,

variant: "destructive",

});

});

}
3

console.log(formData);

return (

<div className="mx-auto w-full max-w-md space-y-6">

<div className="text-center">

<h1 className="text-3xl font-bold tracking-tight text-foreground">

Create new account

</h1>

<p className="mt-2">

Already have an account

<Link

className="font-medium ml-2 text-primary hover:underline"

to="/auth/login"

>

Login

</Link>

</p>

</div>

<CommonForm

formControls={registerFormControls}

buttonText={"Sign Up"}

formData={formData}

setFormData={setFormData}

onSubmit={onSubmit}

/>

</div>

);

export default AuthRegister;


3
App/Pagenotfound.js
function NotFound() {
return <div>page doesn't exists</div>;
}export default NotFound;

Shopping_view/account.jsx

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";


import accImg from "../../assets/account.jpg";
import Address from "@/components/shopping-view/address";
import ShoppingOrders from "@/components/shopping-view/orders";

function ShoppingAccount() {
return (
<div className="flex flex-col">
<div className="relative h-[300px] w-full overflow-hidden">
<img
src={accImg}
className="h-full w-full object-cover object-center"
/>
</div>
<div className="container mx-auto grid grid-cols-1 gap-8 py-8">
<div className="flex flex-col rounded-lg border bg-background p-6 shadow-sm">
<Tabs defaultValue="orders">
<TabsList>
<TabsTrigger value="orders">Orders</TabsTrigger>
<TabsTrigger value="address">Address</TabsTrigger>
</TabsList>
<TabsContent value="orders">
<ShoppingOrders />
</TabsContent>
<TabsContent value="address">
<Address />
</TabsContent>
</Tabs>
</div>
</div>
</div>
);
}
export default ShoppingAccount;
3
Page/Chackout.jsx
import Address from "@/components/shopping-view/address";
import img from "../../assets/account.jpg";
import { useDispatch, useSelector } from "react-redux";
import UserCartItemsContent from "@/components/shopping-view/cart-items-content";
import { Button } from "@/components/ui/button";
import { useState } from "react";
import { createNewOrder } from "@/store/shop/order-slice";
import { Navigate } from "react-router-dom";
import { useToast } from "@/components/ui/use-toast";

function ShoppingCheckout() {
const { cartItems } = useSelector((state) => state.shopCart);
const { user } = useSelector((state) => state.auth);
const { approvalURL } = useSelector((state) => state.shopOrder);
const [currentSelectedAddress, setCurrentSelectedAddress] = useState(null);
const [isPaymentStart, setIsPaymemntStart] = useState(false);
const dispatch = useDispatch();
const { toast } = useToast();

console.log(currentSelectedAddress, "cartItems");

const totalCartAmount =
cartItems && cartItems.items && cartItems.items.length > 0
? cartItems.items.reduce(
(sum, currentItem) =>
sum +
(currentItem?.salePrice > 0
? currentItem?.salePrice
: currentItem?.price) *
currentItem?.quantity,
0
)
: 0;

function handleInitiatePaypalPayment() {
if (cartItems.length === 0) {
toast({
title: "Your cart is empty. Please add items to proceed",
variant: "destructive",
});

return;
}
if (currentSelectedAddress === null) {
toast({
title: "Please select one address to proceed.",
variant: "destructive",
});

return;
}

const orderData = {
userId: user?.id,
cartId: cartItems?._id,
cartItems: cartItems.items.map((singleCartItem) => ({
productId: singleCartItem?.productId,
title: singleCartItem?.title,
image: singleCartItem?.image,
3
price:
singleCartItem?.salePrice > 0
? singleCartItem?.salePrice
: singleCartItem?.price,
quantity: singleCartItem?.quantity,
})),
addressInfo: {
addressId: currentSelectedAddress?._id,
address: currentSelectedAddress?.address,
city: currentSelectedAddress?.city,
pincode: currentSelectedAddress?.pincode,
phone: currentSelectedAddress?.phone,
notes: currentSelectedAddress?.notes,
},
orderStatus: "pending",
paymentMethod: "paypal",
paymentStatus: "pending",
totalAmount: totalCartAmount,
orderDate: new Date(),
orderUpdateDate: new Date(),
paymentId: "",
payerId: "",
};

dispatch(createNewOrder(orderData)).then((data) => {
console.log(data, "sangam");
if (data?.payload?.success) {
setIsPaymemntStart(true);
} else {
setIsPaymemntStart(false);
}
});
}

if (approvalURL) {
window.location.href = approvalURL;
}

return (
<div className="flex flex-col">
<div className="relative h-[300px] w-full overflow-hidden">
<img src={img} className="h-full w-full object-cover object-center" />
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-5 mt-5 p-5">
<Address
selectedId={currentSelectedAddress}
setCurrentSelectedAddress={setCurrentSelectedAddress}
/>
<div className="flex flex-col gap-4">
{cartItems && cartItems.items && cartItems.items.length > 0
? cartItems.items.map((item) => (
<UserCartItemsContent cartItem={item} />
))
: null}
<div className="mt-8 space-y-4">
<div className="flex justify-between">
<span className="font-bold">Total</span>
<span className="font-bold">${totalCartAmount}</span>
</div>
</div>
<div className="mt-4 w-full">
3
<Button onClick={handleInitiatePaypalPayment} className="w-full">
{isPaymentStart
? "Processing Paypal Payment..."
: "Checkout with Paypal"}
</Button>
</div>
</div>
</div>
</div>
);
}

export default ShoppingCheckout;

Pages/Home.jsx
import { Button } from "@/components/ui/button";
import bannerOne from "../../assets/banner-1.webp";
import bannerTwo from "../../assets/banner-2.webp";
import bannerThree from "../../assets/banner-3.webp";
import {
Airplay,
BabyIcon,
ChevronLeftIcon,
ChevronRightIcon,
CloudLightning,
Heater,
Images,
Shirt,
ShirtIcon,
ShoppingBasket,
UmbrellaIcon,
WashingMachine,
WatchIcon,
} from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
fetchAllFilteredProducts,
fetchProductDetails,
} from "@/store/shop/products-slice";
import ShoppingProductTile from "@/components/shopping-view/product-tile";
import { useNavigate } from "react-router-dom";
import { addToCart, fetchCartItems } from "@/store/shop/cart-slice";
import { useToast } from "@/components/ui/use-toast";
import ProductDetailsDialog from "@/components/shopping-view/product-details";
import { getFeatureImages } from "@/store/common-slice";

const categoriesWithIcon = [
{ id: "men", label: "Men", icon: ShirtIcon },
{ id: "women", label: "Women", icon: CloudLightning },
{ id: "kids", label: "Kids", icon: BabyIcon },
{ id: "accessories", label: "Accessories", icon: WatchIcon },
{ id: "footwear", label: "Footwear", icon: UmbrellaIcon },
];

const brandsWithIcon = [
{ id: "nike", label: "Nike", icon: Shirt },
3
{ id: "adidas", label: "Adidas", icon: WashingMachine },
{ id: "puma", label: "Puma", icon: ShoppingBasket },
{ id: "levi", label: "Levi's", icon: Airplay },
{ id: "zara", label: "Zara", icon: Images },
{ id: "h&m", label: "H&M", icon: Heater },
];
function ShoppingHome() {
const [currentSlide, setCurrentSlide] = useState(0);
const { productList, productDetails } = useSelector(
(state) => state.shopProducts
);
const { featureImageList } = useSelector((state) => state.commonFeature);

const [openDetailsDialog, setOpenDetailsDialog] = useState(false);

const { user } = useSelector((state) => state.auth);

const dispatch = useDispatch();


const navigate = useNavigate();
const { toast } = useToast();

function handleNavigateToListingPage(getCurrentItem, section) {


sessionStorage.removeItem("filters");
const currentFilter = {
[section]: [getCurrentItem.id],
};

sessionStorage.setItem("filters", JSON.stringify(currentFilter));
navigate(`/shop/listing`);
}

function handleGetProductDetails(getCurrentProductId) {
dispatch(fetchProductDetails(getCurrentProductId));
}

function handleAddtoCart(getCurrentProductId) {
dispatch(
addToCart({
userId: user?.id,
productId: getCurrentProductId,
quantity: 1,
})
).then((data) => {
if (data?.payload?.success) {
dispatch(fetchCartItems(user?.id));
toast({
title: "Product is added to cart",
});
}
});
}

useEffect(() => {
if (productDetails !== null) setOpenDetailsDialog(true);
}, [productDetails]);

useEffect(() => {
const timer = setInterval(() => {
setCurrentSlide((prevSlide) => (prevSlide + 1) % featureImageList.length);
}, 15000);
3
return () => clearInterval(timer);
}, [featureImageList]);

useEffect(() => {
dispatch(
fetchAllFilteredProducts({
filterParams: {},
sortParams: "price-lowtohigh",
})
);
}, [dispatch]);

console.log(productList, "productList");

useEffect(() => {
dispatch(getFeatureImages());
}, [dispatch]);

return (
<div className="flex flex-col min-h-screen">
<div className="relative w-full h-[600px] overflow-hidden">
{featureImageList && featureImageList.length > 0
? featureImageList.map((slide, index) => (
<img
src={slide?.image}
key={index}
className={`${
index === currentSlide ? "opacity-100" : "opacity-0"
} absolute top-0 left-0 w-full h-full object-cover transition-opacity duration-1000`}
/>
))
: null}
<Button
variant="outline"
size="icon"
onClick={() =>
setCurrentSlide(
(prevSlide) =>
(prevSlide - 1 + featureImageList.length) %
featureImageList.length
)
}
className="absolute top-1/2 left-4 transform -translate-y-1/2 bg-white/80"
>
<ChevronLeftIcon className="w-4 h-4" />
</Button>
<Button
variant="outline"
size="icon"
onClick={() =>
setCurrentSlide(
(prevSlide) => (prevSlide + 1) % featureImageList.length
)
}
className="absolute top-1/2 right-4 transform -translate-y-1/2 bg-white/80"
>
<ChevronRightIcon className="w-4 h-4" />
</Button>
</div>
<section className="py-12 bg-gray-50">
<div className="container mx-auto px-4">
3
<h2 className="text-3xl font-bold text-center mb-8">
Shop by category
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
{categoriesWithIcon.map((categoryItem) => (
<Card
onClick={() =>
handleNavigateToListingPage(categoryItem, "category")
}
className="cursor-pointer hover:shadow-lg transition-shadow"
>
<CardContent className="flex flex-col items-center justify-center p-6">
<categoryItem.icon className="w-12 h-12 mb-4 text-primary" />
<span className="font-bold">{categoryItem.label}</span>
</CardContent>
</Card>
))}
</div>
</div>
</section>

<section className="py-12 bg-gray-50">


<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold text-center mb-8">Shop by Brand</h2>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
{brandsWithIcon.map((brandItem) => (
<Card
onClick={() => handleNavigateToListingPage(brandItem, "brand")}
className="cursor-pointer hover:shadow-lg transition-shadow"
>
<CardContent className="flex flex-col items-center justify-center p-6">
<brandItem.icon className="w-12 h-12 mb-4 text-primary" />
<span className="font-bold">{brandItem.label}</span>
</CardContent>
</Card>
))}
</div>
</div>
</section>

<section className="py-12">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold text-center mb-8">
Feature Products
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
{productList && productList.length > 0
? productList.map((productItem) => (
<ShoppingProductTile
handleGetProductDetails={handleGetProductDetails}
product={productItem}
handleAddtoCart={handleAddtoCart}
/>
))
: null}
</div>
</div>
</section>
<ProductDetailsDialog
open={openDetailsDialog}
setOpen={setOpenDetailsDialog}
3
productDetails={productDetails}
/>
</div>
);
}

export default ShoppingHome;

/lib/appwrite/index.ts
import ProductFilter from "@/components/shopping-view/filter";
import ProductDetailsDialog from "@/components/shopping-view/product-details";
import ShoppingProductTile from "@/components/shopping-view/product-tile";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useToast } from "@/components/ui/use-toast";
import { sortOptions } from "@/config";
import { addToCart, fetchCartItems } from "@/store/shop/cart-slice";
import {
fetchAllFilteredProducts,
fetchProductDetails,
} from "@/store/shop/products-slice";
import { ArrowUpDownIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useSearchParams } from "react-router-dom";

function createSearchParamsHelper(filterParams) {
const queryParams = [];

for (const [key, value] of Object.entries(filterParams)) {


if (Array.isArray(value) && value.length > 0) {
const paramValue = value.join(",");

queryParams.push(`${key}=${encodeURIComponent(paramValue)}`);
}
}

console.log(queryParams, "queryParams");

return queryParams.join("&");
}

function ShoppingListing() {
const dispatch = useDispatch();
const { productList, productDetails } = useSelector(
(state) => state.shopProducts
);
const { cartItems } = useSelector((state) => state.shopCart);
const { user } = useSelector((state) => state.auth);
const [filters, setFilters] = useState({});
const [sort, setSort] = useState(null);
const [searchParams, setSearchParams] = useSearchParams();
const [openDetailsDialog, setOpenDetailsDialog] = useState(false);
const { toast } = useToast();
3

const categorySearchParam = searchParams.get("category");

function handleSort(value) {
setSort(value);
}

function handleFilter(getSectionId, getCurrentOption) {


let cpyFilters = { ...filters };
const indexOfCurrentSection = Object.keys(cpyFilters).indexOf(getSectionId);

if (indexOfCurrentSection === -1) {


cpyFilters = {
...cpyFilters,
[getSectionId]: [getCurrentOption],
};
} else {
const indexOfCurrentOption =
cpyFilters[getSectionId].indexOf(getCurrentOption);

if (indexOfCurrentOption === -1)


cpyFilters[getSectionId].push(getCurrentOption);
else cpyFilters[getSectionId].splice(indexOfCurrentOption, 1);
}

setFilters(cpyFilters);
sessionStorage.setItem("filters", JSON.stringify(cpyFilters));
}

function handleGetProductDetails(getCurrentProductId) {
console.log(getCurrentProductId);
dispatch(fetchProductDetails(getCurrentProductId));
}

function handleAddtoCart(getCurrentProductId, getTotalStock) {


console.log(cartItems);
let getCartItems = cartItems.items || [];

if (getCartItems.length) {
const indexOfCurrentItem = getCartItems.findIndex(
(item) => item.productId === getCurrentProductId
);
if (indexOfCurrentItem > -1) {
const getQuantity = getCartItems[indexOfCurrentItem].quantity;
if (getQuantity + 1 > getTotalStock) {
toast({
title: `Only ${getQuantity} quantity can be added for this item`,
variant: "destructive",
});

return;
}
}
}

dispatch(
addToCart({
userId: user?.id,
productId: getCurrentProductId,
quantity: 1,
})
3
).then((data) => {
if (data?.payload?.success) {
dispatch(fetchCartItems(user?.id));
toast({
title: "Product is added to cart",
});
}
});
}

useEffect(() => {
setSort("price-lowtohigh");
setFilters(JSON.parse(sessionStorage.getItem("filters")) || {});
}, [categorySearchParam]);

useEffect(() => {
if (filters && Object.keys(filters).length > 0) {
const createQueryString = createSearchParamsHelper(filters);
setSearchParams(new URLSearchParams(createQueryString));
}
}, [filters]);

useEffect(() => {
if (filters !== null && sort !== null)
dispatch(
fetchAllFilteredProducts({ filterParams: filters, sortParams: sort })
);
}, [dispatch, sort, filters]);

useEffect(() => {
if (productDetails !== null) setOpenDetailsDialog(true);
}, [productDetails]);

console.log(productList, "productListproductListproductList");

return (
<div className="grid grid-cols-1 md:grid-cols-[200px_1fr] gap-6 p-4 md:p-6">
<ProductFilter filters={filters} handleFilter={handleFilter} />
<div className="bg-background w-full rounded-lg shadow-sm">
<div className="p-4 border-b flex items-center justify-between">
<h2 className="text-lg font-extrabold">All Products</h2>
<div className="flex items-center gap-3">
<span className="text-muted-foreground">
{productList?.length} Products
</span>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
className="flex items-center gap-1"
>
<ArrowUpDownIcon className="h-4 w-4" />
<span>Sort by</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[200px]">
<DropdownMenuRadioGroup value={sort} onValueChange={handleSort}>
{sortOptions.map((sortItem) => (
<DropdownMenuRadioItem
value={sortItem.id}
3
key={sortItem.id}
>
{sortItem.label}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 p-4">
{productList && productList.length > 0
? productList.map((productItem) => (
<ShoppingProductTile
handleGetProductDetails={handleGetProductDetails}
product={productItem}
handleAddtoCart={handleAddtoCart}
/>
))
: null}
</div>
</div>
<ProductDetailsDialog
open={openDetailsDialog}
setOpen={setOpenDetailsDialog}
productDetails={productDetails}
/>
</div>
);
}

export default ShoppingListing;


0
3
31

/hooks/use-toast.ts
"use client"

import * as React from "react"

import type

{ ToastActionElement,

ToastProps,

} from

"@/components/ui/toast"

const TOAST_LIMIT = 1

const TOAST_REMOVE_DELAY =

1000000 type ToasterToast = ToastProps

&{

id: string

title?: React.ReactNode

description?: React.ReactNode

action?: ToastActionElement

const actionTypes =

{ ADD_TOAST:

"ADD_TOAST",

UPDATE_TOAST: "UPDATE_TOAST",

DISMISS_TOAST: "DISMISS_TOAST",

REMOVE_TOAST:

"REMOVE_TOAST", } as const

let count = 0

function genId() {

count = (count + 1) % Number.MAX_SAFE_INTEGER


32

return count.toString()

type ActionType = typeof actionTypes

type Action =

|{

type: ActionType["ADD_TOAST"]

toast: ToasterToast

|{

type: ActionType["UPDATE_TOAST"]

toast: Partial<ToasterToast>

|{

type: ActionType["DISMISS_TOAST"]

toastId?: ToasterToast["id"]

|{

type: ActionType["REMOVE_TOAST"]

toastId?: ToasterToast["id"]

interface State

{ toasts:

ToasterToast[]

}
33

const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()

const addToRemoveQueue = (toastId: string) => {

if (toastTimeouts.has(toastId))

{ return

const timeout = setTimeout(() =>

{ toastTimeouts.delete(toastId)

dispatch({

type: "REMOVE_TOAST",

toastId: toastId,

})

}, TOAST_REMOVE_DELAY)

toastTimeouts.set(toastId, timeout)

export const reducer = (state: State, action: Action): State

=> { switch (action.type)

{ case

"ADD_TOAST":

return {

...state,

toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),

case "UPDATE_TOAST":

return {
34

...state,

toasts: state.toasts.map((t) =>

t.id === action.toast.id ? { ...t, ...action.toast } : t

),

case "DISMISS_TOAST": {

const { toastId } = action

if (toastId) {

addToRemoveQueue(toastId)

} else

{ state.toasts.forEach((toast) =>

{ addToRemoveQueue(toast.id)

})}

return {

...state,

toasts: state.toasts.map((t) =>

t.id === toastId || toastId === undefined

?{

...t,

open: false,

}: t),}

case "REMOVE_TOAST":

if (action.toastId === undefined) {


35

return {

...state,

toasts: [],

}}

return {

...state,

toasts: state.toasts.filter((t) => t.id !== action.toastId),

} }}

const listeners: Array<(state: State) => void> = []

let memoryState: State = { toasts: [] }

function dispatch(action: Action)

{ memoryState = reducer(memoryState, action)

listeners.forEach((listener) => {

listener(memoryState)

}) }

type Toast = Omit<ToasterToast, "id">

function toast({ ...props }: Toast)

{ const id = genId()

const update = (props: ToasterToast) =>

dispatch({

type: "UPDATE_TOAST",

toast: { ...props, id },

})

const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })


36

dispatch({

type: "ADD_TOAST",

toast: {

...props,

id,

open: true,

onOpenChange: (open) =>

{ if (!open) dismiss()

},

}, })

return {

id: id,

dismiss,

update, }}

function useToast() {

const [state, setState] =

React.useState<State>(memoryState) React.useEffect(() =>

listeners.push(setState)

return () => {

const index = listeners.indexOf(setState)

if (index > -1) {

listeners.splice(index, 1)

}
37

}, [state])

return {

...state,

toast,

dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),

}}

export { useToast, toast }

11. Testing
- Define Testing Objectives: Identify key functionalities (like file upload,
sharing, authentication) that need validation for correctness,
performance, and security.
- Testing Environment Setup: Prepare development, staging, and production
environments using the same Appwrite configurations to ensure
consistency.
- Testing Tools & Schedule: Choose tools for unit testing (Jest),
end-to-end testing (Cypress/Playwright), and API testing (Postman),
and define the testing schedule and milestones.
Functional Testing:

- Authentication Flow: Test the complete user journey – signup,


login, session persistence, and logout using Appwrite Auth.
- File Handling Operations: Verify that uploads, renaming,
deletions, previews, and downloads behave as expected.
- Dashboard and Search: Ensure storage analytics, file categorization,
and search results work correctly under different data conditions.
Performance Testing:

- File Upload and Download Speed: Test how the system performs
when uploading/downloading files of various sizes and types.
- Concurrent Usage: Simulate multiple users uploading files
simultaneously to evaluate backend handling and app stability.
38

- App Load Time: Measure the initial load time, dashboard


responsiveness, and delay in search functionality on various devices.
Security Testing:

- Authentication & Authorization: Ensure only logged-in users can


access files and that shared links have proper access controls.
- Input Validation: Test for XSS, injection attacks, or malformed
input through forms (e.g., file name inputs or search queries).
- Environment Secrets Protection: Verify that sensitive keys in
.env.local are never exposed on the client side and access tokens are
securely managed.

12. Setup of Project


cd /directory

npm install // install dependencies

npm run dev // to start the project

Create a new file named .env.local in the root of your project and
add the following content:
NEXT_PUBLIC_APPWRITE_ENDPOINT="https://cloud.appwrite.io/v1"

NEXT_PUBLIC_APPWRITE_PROJECT=""

NEXT_PUBLIC_APPWRITE_DATABASE=""

NEXT_PUBLIC_APPWRITE_USERS_COLLECTION=""

NEXT_PUBLIC_APPWRITE_FILES_COLLECTION=""

NEXT_PUBLIC_APPWRITE_BUCKET=""

NEXT_APPWRITE_KEY=""
39

13. Bibliography
- Next.js 15 Documentation
Vercel. (2024). Next.js Documentation (App
Router & Features). Retrieved from:
https://nextjs.org/docs
- React 19 Documentation
Meta. (2024). React – A JavaScript library for
building user interfaces. Retrieved from:
https://reactjs.org
- Appwrite Documentation
Appwrite. (2024). Secure Backend Server for Web, Mobile &
Flutter Developers. Retrieved from: https://appwrite.io/docs
- TypeScript Handbook
Microsoft. (2024). TypeScript
Documentation. Retrieved from:
https://www.typescriptlang.org/docs/
- Tailwind CSS Documentation
Tailwind Labs. (2024). Tailwind CSS – Rapidly build
modern websites. Retrieved from:
https://tailwindcss.com/docs
- ShadCN UI Components
ShadCN. (2024). Beautifully designed components built with Radix
UI and Tailwind CSS. Retrieved from: https://ui.shadcn.dev
- MDN Web Docs
Mozilla Foundation. (2024). JavaScript, HTML, and
CSS Documentation. Retrieved from:
https://developer.mozilla.org
- Excalidraw
https://excalidraw.com
- Vercel Retrieved from: https://vercel.com
- Stack Overflow
Retrieved from: https://stackoverflow.com
- Google.com

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy