Skip to content

Commit 1570327

Browse files
committed
Added auth cart and order routes plus payment method in the backend
1 parent e4a9b22 commit 1570327

File tree

17 files changed

+1059
-253
lines changed

17 files changed

+1059
-253
lines changed

server/config/auth.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { pool } from "./database.js";
2+
import GoogleStrategy from "passport-google-oauth20";
3+
4+
const googleOptions = {
5+
clientID: process.env.GOOGLE_CLIENT_ID,
6+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
7+
callbackURL: process.env.GOOGLE_CALLBACK_URL,
8+
};
9+
10+
const verifyCallback = async (accessToken, refreshToken, profile, done) => {
11+
const { id, displayName, emails, photos } = profile;
12+
13+
const googleUser = {
14+
id: id,
15+
username: displayName,
16+
email: emails[0].value,
17+
avatarUrl: photos[0].value,
18+
accessToken,
19+
};
20+
21+
try {
22+
const userQuery = "SELECT * FROM users WHERE id = $1";
23+
const userResult = await pool.query(userQuery, [googleUser.id]);
24+
25+
if (userResult.rowCount === 0) {
26+
const insertUserQuery = `
27+
INSERT INTO users (id, username, email, avatarurl, accesstoken)
28+
VALUES($1, $2, $3, $4, $5)
29+
RETURNING *
30+
`;
31+
const insertUserValues = [
32+
googleUser.id,
33+
googleUser.username,
34+
googleUser.email,
35+
googleUser.avatarUrl,
36+
googleUser.accessToken,
37+
];
38+
const newUserResult = await pool.query(insertUserQuery, insertUserValues);
39+
40+
const newUser = newUserResult.rows[0];
41+
return done(null, newUser);
42+
}
43+
44+
const user = userResult.rows[0];
45+
return done(null, user);
46+
} catch (error) {
47+
return done(error);
48+
}
49+
};
50+
51+
export const Google = new GoogleStrategy(googleOptions, verifyCallback);

server/config/data/data.json

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,41 @@
11
[
2-
{
3-
"id": 1,
4-
"brand_name": "Nike Air Force 1 Low Retro",
5-
"description": "Debuting in 1982 as a basketball must-have, the Air Force 1 came into its own in the '90s. The clean look of the classic white-on-white AF1 was endorsed from the basketball courts to the block and beyond. Finding its rhythm in hip-hop culture, releasing limited collabs and colorways, Air Force 1 became an iconic sneaker around the globe. And with over 2000 iterations of this staple, its impact on fashion, music and sneaker culture can’t be denied.",
6-
"sizes": 10.5,
7-
"price": 150.00,
8-
"img_url":"https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/bf80c9bb-3c07-4e5a-ba3f-677cc1889e4d/air-force-1-low-retro-mens-shoes-H7r1WF.png"
9-
},
10-
{
11-
"id": 2,
12-
"brand_name": "Nike Luka 2",
13-
"description": "You bring the speed. We'll bring the stability. The Luka 2 is built to support your skills, with an emphasis on step-backs, side-steps and quick-stop action. A stacked midsole features firm, flexible cushioning for added responsiveness as you shift back and forth on the court. Up top, the full-foot wrapped cage design helps you stay contained whether you're faking out a defender or driving down the lane. With all that tech in a lightweight package, we've got efficiency covered. The rest is up to you.",
14-
"sizes": 10.5,
15-
"price": 130.00,
16-
"img_url":"https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco,u_126ab356-44d8-4a06-89b4-fcdcc8df0245,c_scale,fl_relative,w_1.0,h_1.0,fl_layer_apply/58928cb8-74c0-4ad3-882a-4bfa65bab908/luka-2-basketball-shoes-vcXFrk.png"
17-
},
18-
{
19-
"id": 3,
20-
"brand_name": "LeBron XXI Akoya",
21-
"description": "Last time around, LeBron flipped the script on his shoe game as only the King can. The encore is even better. The LeBron XXI has a cabling system that works with Zoom Air cushioning and a light, low-to-the-ground design, giving you agile fluidity and explosiveness without excess weight. Created for your ascent and the next generation of hoopers, it’s ideal for Bron-like open-floor attacks and rising toward the rim when the game’s pace turns up. This special design celebrates the akoya pearl, with its perfect shapes and reflective nature. Its natural beauty and grace hold up across any era.",
22-
"sizes": 10.5,
23-
"price": 200.00,
24-
"img_url":"https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/02fbc834-6752-4778-9a95-1973de02b0b9/lebron-xxi-akoya-basketball-shoes-lnQSsH.png"
25-
}
26-
]
27-
2+
{
3+
"id": 1,
4+
"name": "Nike Air Force 1 Low Retro",
5+
"brand": "Nike",
6+
"description": "Debuting in 1982 as a basketball must-have, the Air Force 1 came into its own in the '90s. The clean look of the classic white-on-white AF1 was endorsed from the basketball courts to the block and beyond. Finding its rhythm in hip-hop culture, releasing limited collabs and colorways, Air Force 1 became an iconic sneaker around the globe. And with over 2000 iterations of this staple, its impact on fashion, music and sneaker culture can’t be denied.",
7+
"price": 150.0,
8+
"size": 10.5,
9+
"color": "White",
10+
"stockquantity": 100,
11+
"category": "Basketball",
12+
"targetaudience": "Men",
13+
"img_url": "https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/bf80c9bb-3c07-4e5a-ba3f-677cc1889e4d/air-force-1-low-retro-mens-shoes-H7r1WF.png"
14+
},
15+
{
16+
"id": 2,
17+
"name": "Nike Luka 2",
18+
"brand": "Nike",
19+
"description": "You bring the speed. We'll bring the stability. The Luka 2 is built to support your skills, with an emphasis on step-backs, side-steps and quick-stop action. A stacked midsole features firm, flexible cushioning for added responsiveness as you shift back and forth on the court. Up top, the full-foot wrapped cage design helps you stay contained whether you're faking out a defender or driving down the lane. With all that tech in a lightweight package, we've got efficiency covered. The rest is up to you.",
20+
"price": 130.0,
21+
"size": 10.5,
22+
"color": "Black",
23+
"stockquantity": 80,
24+
"category": "Basketball",
25+
"targetaudience": "Men",
26+
"img_url": "https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco,u_126ab356-44d8-4a06-89b4-fcdcc8df0245,c_scale,fl_relative,w_1.0,h_1.0,fl_layer_apply/58928cb8-74c0-4ad3-882a-4bfa65bab908/luka-2-basketball-shoes-vcXFrk.png"
27+
},
28+
{
29+
"id": 3,
30+
"name": "LeBron XXI Akoya",
31+
"brand": "Nike",
32+
"description": "Last time around, LeBron flipped the script on his shoe game as only the King can. The encore is even better. The LeBron XXI has a cabling system that works with Zoom Air cushioning and a light, low-to-the-ground design, giving you agile fluidity and explosiveness without excess weight. Created for your ascent and the next generation of hoopers, it’s ideal for Bron-like open-floor attacks and rising toward the rim when the game’s pace turns up. This special design celebrates the akoya pearl, with its perfect shapes and reflective nature. Its natural beauty and grace hold up across any era.",
33+
"price": 200.0,
34+
"size": 10.5,
35+
"color": "Silver",
36+
"stockquantity": 120,
37+
"category": "Basketball",
38+
"targetaudience": "Men",
39+
"img_url": "https://static.nike.com/a/images/t_PDP_1728_v1/f_auto,q_auto:eco/02fbc834-6752-4778-9a95-1973de02b0b9/lebron-xxi-akoya-basketball-shoes-lnQSsH.png"
40+
}
41+
]

server/config/reset.js

Lines changed: 149 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,168 @@
1-
import { pool } from './database.js'
2-
import './dotenv.js'
3-
import { fileURLToPath } from 'url'
4-
import path, { dirname } from 'path'
5-
import fs from 'fs'
1+
import { pool } from "./database.js";
2+
import "./dotenv.js";
3+
import { fileURLToPath } from "url";
4+
import path, { dirname } from "path";
5+
import fs from "fs";
66

7-
const currentPath = fileURLToPath(import.meta.url)
7+
const currentPath = fileURLToPath(import.meta.url);
88

9-
const sneakersFile = fs.readFileSync(path.join(dirname(currentPath), '../config/data/data.json'))
10-
const sneakersData = JSON.parse(sneakersFile)
9+
const sneakersFile = fs.readFileSync(
10+
path.join(dirname(currentPath), "../config/data/data.json")
11+
);
12+
const sneakersData = JSON.parse(sneakersFile);
1113

1214
const createSneakersTable = async () => {
1315
const createSneakersTableQuery = `
1416
CREATE TABLE IF NOT EXISTS sneakers (
1517
id serial PRIMARY KEY,
16-
brand_name varchar(100) NOT NULL,
18+
name varchar(100) NOT NULL,
19+
brand varchar(100) NOT NULL,
1720
description text NOT NULL,
18-
sizes numeric(7, 2) NOT NULL,
1921
price money NOT NULL,
20-
img_url text NOT NULL
22+
size numeric(7, 2) NOT NULL,
23+
color varchar(50) NOT NULL,
24+
stockquantity integer NOT NULL,
25+
category varchar(50) NOT NULL,
26+
targetaudience varchar(50) NOT NULL
2127
);
22-
`
28+
`;
29+
2330
try {
24-
const res = await pool.query(createSneakersTableQuery)
25-
console.log('🎉 sneakers table created successfully')
26-
}
27-
catch (err) {
28-
console.error('⚠️ error creating sneakers table', err)
29-
}
31+
const res = await pool.query(createSneakersTableQuery);
32+
console.log("🎉 sneakers table created successfully");
33+
} catch (err) {
34+
console.error("⚠️ error creating sneakers table", err);
3035
}
36+
};
3137

32-
const createCommentsTable = async () => {
33-
const createCommentsTableQuery = `
34-
CREATE TABLE IF NOT EXISTS comments (
35-
id serial PRIMARY KEY,
36-
sneaker_id integer NOT NULL,
37-
comment varchar(100) NOT NULL,
38-
num_votes integer DEFAULT 0,
39-
FOREIGN KEY(sneaker_id) REFERENCES sneakers(id)
38+
const createImagesTable = async () => {
39+
const createImagesTableQuery = `
40+
CREATE TABLE IF NOT EXISTS images (
41+
imageid serial PRIMARY KEY,
42+
productid integer NOT NULL,
43+
imageurl text NOT NULL,
44+
FOREIGN KEY(productid) REFERENCES sneakers(id)
4045
);
41-
`
42-
43-
try {
44-
const res = await pool.query(createCommentsTableQuery)
45-
console.log('🎉 comments table created successfully')
46-
}
47-
catch (err) {
48-
console.error('⚠️ error creating comments table', err)
49-
}
46+
`;
47+
48+
try {
49+
const res = await pool.query(createImagesTableQuery);
50+
console.log("🎉 images table created successfully");
51+
} catch (err) {
52+
console.error("⚠️ error creating images table", err);
5053
}
51-
54+
};
5255

5356
const seedSneakersTable = async () => {
54-
await createSneakersTable()
55-
56-
sneakersData.forEach((sneaker) => {
57-
const insertQuery = {
58-
text: 'INSERT INTO sneakers (brand_name, description, sizes, price, img_url) VALUES ($1, $2, $3, $4, $5)'
59-
}
60-
57+
await createSneakersTable();
58+
59+
sneakersData.forEach((sneaker) => {
60+
const insertQuery = {
61+
text: "INSERT INTO sneakers (name, brand, description, price, size, color, stockquantity, category, targetaudience) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
62+
};
63+
6164
const values = [
62-
sneaker.brand_name,
63-
sneaker.description,
64-
sneaker.sizes,
65-
sneaker.price,
66-
sneaker.img_url
67-
]
68-
69-
try {
70-
pool.query(insertQuery, values)
71-
console.log(`✅ ${sneaker.brand_name} added successfully`)
72-
}
73-
catch (err) {
74-
console.error('⚠️ error inserting sneaker', err)
75-
}
76-
77-
})
65+
sneaker.name,
66+
sneaker.brand,
67+
sneaker.description,
68+
sneaker.price,
69+
sneaker.size,
70+
sneaker.color,
71+
sneaker.stockquantity,
72+
sneaker.category,
73+
sneaker.targetaudience,
74+
];
75+
76+
try {
77+
pool.query(insertQuery, values);
78+
console.log(`✅ ${sneaker.name} added successfully`);
79+
} catch (err) {
80+
console.error("⚠️ error inserting sneaker", err);
7881
}
79-
80-
seedSneakersTable()
81-
createCommentsTable()
82-
82+
});
83+
};
84+
85+
// Add a function to seed the images table
86+
const seedImagesTable = async () => {
87+
await createImagesTable();
88+
89+
sneakersData.forEach((sneaker) => {
90+
const insertImageQuery = {
91+
text: "INSERT INTO images (productid, imageurl) VALUES ($1, $2)",
92+
};
93+
94+
const imageValues = [sneaker.id, sneaker.img_url];
95+
96+
try {
97+
pool.query(insertImageQuery, imageValues);
98+
console.log(`✅ Image for ${sneaker.name} added successfully`);
99+
} catch (err) {
100+
console.error("⚠️ error inserting image", err);
101+
}
102+
});
103+
};
104+
const createReviewsTable = async () => {
105+
const createReviewsTableQuery = `
106+
CREATE TABLE IF NOT EXISTS reviews (
107+
reviewid serial PRIMARY KEY,
108+
productid integer NOT NULL,
109+
userid integer NOT NULL,
110+
rating integer NOT NULL,
111+
reviewtext text NOT NULL,
112+
reviewdate date NOT NULL
113+
);
114+
`;
115+
116+
try {
117+
const res = await pool.query(createReviewsTableQuery);
118+
console.log("🎉 reviews table created successfully");
119+
} catch (err) {
120+
console.error("⚠️ error creating reviews table", err);
121+
}
122+
};
123+
const createUsersTable = async () => {
124+
const createUsersTableQuery = `
125+
CREATE TABLE IF NOT EXISTS user (
126+
id serial PRIMARY KEY,
127+
googleid integer NOT NULL,
128+
username varchar(100) NOT NULL,
129+
avatarurl varchar(500) NOT NULL,
130+
accesstoken varchar(500) NOT NULL
131+
);
132+
`;
133+
134+
try {
135+
const res = await pool.query(createUsersTableQuery);
136+
console.log("🎉 users table created successfully");
137+
} catch (err) {
138+
console.error("⚠️ error creating users table", err);
139+
}
140+
};
141+
142+
const createUserAddressTable = async () => {
143+
const createUserAddressTableQuery = `
144+
CREATE TABLE IF NOT EXISTS useraddress (
145+
id serial PRIMARY KEY,
146+
userid integer NOT NULL,
147+
address varchar(255) NOT NULL,
148+
city varchar(100) NOT NULL,
149+
postalcode varchar(10) NOT NULL,
150+
country varchar(100) NOT NULL,
151+
phone varchar(20) NOT NULL,
152+
FOREIGN KEY(userid) REFERENCES user(id)
153+
);
154+
`;
155+
156+
try {
157+
const res = await pool.query(createUserAddressTableQuery);
158+
console.log("🎉 useraddress table created successfully");
159+
} catch (err) {
160+
console.error("⚠️ error creating useraddress table", err);
161+
}
162+
};
163+
164+
seedSneakersTable();
165+
seedImagesTable();
166+
createReviewsTable();
167+
createUsersTable;
168+
createUserAddressTable();

server/controllers/cart.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
export const addToCart = (req, res) => {
2+
const { productId, quantity } = req.body;
3+
const cart = req.session.cart || {};
4+
5+
if (!cart[productId]) {
6+
cart[productId] = 0;
7+
}
8+
9+
cart[productId] += quantity;
10+
11+
req.session.cart = cart;
12+
res.status(201).json({ message: "Item added to cart" });
13+
};
14+
15+
export const getCart = (req, res) => {
16+
const cart = req.session.cart || {};
17+
res.status(200).json(cart);
18+
};
19+
20+
export const updateCartItemQuantity = (req, res) => {
21+
const itemId = req.params.productId;
22+
const newQuantity = req.body.quantity;
23+
const cart = req.session.cart || {};
24+
25+
if (cart[itemId] !== undefined) {
26+
cart[itemId] = newQuantity;
27+
req.session.cart = cart;
28+
res.status(200).json({ message: "Cart item quantity updated" });
29+
} else {
30+
res.status(404).json({ error: "Item not found in the cart" });
31+
}
32+
};
33+
34+
export const removeFromCart = (req, res) => {
35+
const itemId = req.params.productId;
36+
const cart = req.session.cart || {};
37+
38+
if (cart[itemId] !== undefined) {
39+
delete cart[itemId];
40+
req.session.cart = cart;
41+
res.status(200).json({ message: "Item removed from the cart" });
42+
} else {
43+
res.status(404).json({ error: "Item not found in the cart" });
44+
}
45+
};

0 commit comments

Comments
 (0)