-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from atlp-rwanda/187354255-create-product
Feature for enabling product to be created by seller
- Loading branch information
Showing
19 changed files
with
1,155 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Request, Response } from 'express'; | ||
import { Category, CategoryCreationAttributes } from '../database/models/Category'; | ||
import logger from '../logs/config'; | ||
|
||
export const createCategory = async (req: Request, res: Response) => { | ||
try { | ||
const { name, description } = req.body as CategoryCreationAttributes; | ||
await Category.create({ | ||
name, | ||
description, | ||
}); | ||
res.status(201).json({ ok: true, message: 'New category created successully!' }); | ||
} catch (error) { | ||
if (error instanceof Error) { | ||
logger.error(error.message); | ||
} | ||
res.status(500).json({ error: 'Failed to create category' }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* eslint-disable @typescript-eslint/no-unnecessary-condition */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { Request, Response } from 'express'; | ||
import uploadImage from '../helpers/claudinary'; | ||
import { sendInternalErrorResponse } from '../validations'; | ||
import { Product, ProductAttributes } from '../database/models/Product'; | ||
import { Size, SizeAttributes } from '../database/models/Size'; | ||
|
||
export const createProduct = async (req: Request, res: Response) => { | ||
try { | ||
const { name, description, colors } = req.body as ProductAttributes; | ||
const { categoryId } = req.params; | ||
const seller = (await req.user) as any; | ||
const sellerId = seller.id; | ||
|
||
// when products exists | ||
const thisProductExists = await Product.findOne({ where: { name } }); | ||
|
||
if (thisProductExists) { | ||
return res.status(400).json({ | ||
ok: false, | ||
message: 'This Product already exists, You can update the stock levels instead.', | ||
data: thisProductExists, | ||
}); | ||
} | ||
// handle images | ||
const productImages = ['asdf', 'asdf', 'asdf', 'asdf']; | ||
const images: unknown = req.files; | ||
if (images instanceof Array && images.length > 3) { | ||
for (const image of images) { | ||
const imageBuffer: Buffer = image.buffer; | ||
const url = await uploadImage(imageBuffer); | ||
productImages.push(url); | ||
} | ||
} else { | ||
return res.status(400).json({ | ||
message: 'Product should have at least 4 images', | ||
}); | ||
} | ||
|
||
// create product | ||
await Product.create({ | ||
sellerId, | ||
name, | ||
description, | ||
categoryId, | ||
colors, | ||
images: productImages, | ||
}); | ||
|
||
res.status(201).json({ | ||
ok: true, | ||
message: 'Thank you for adding new product in the store!', | ||
}); | ||
} catch (error) { | ||
sendInternalErrorResponse(res, error); | ||
} | ||
}; | ||
|
||
export const createSize = async (req: Request, res: Response) => { | ||
try { | ||
const { productId } = req.params; | ||
const { size, price, discount, expiryDate } = req.body as SizeAttributes; | ||
await Size.create({ size, price, discount, expiryDate, productId }); | ||
res.status(201).json({ | ||
ok: true, | ||
message: 'Product size added successfully', | ||
}); | ||
} catch (error) { | ||
sendInternalErrorResponse(res, error); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { Request, Response } from 'express'; | ||
import { sendErrorResponse } from '../helpers/helper'; | ||
import { Wishlist } from '../database/models/wishlist'; | ||
import { Product } from '../database/models/Product'; | ||
import { Size } from '../database/models/Size'; | ||
import { sendInternalErrorResponse } from '../validations'; | ||
|
||
interface UserInterface { | ||
id: string; | ||
name: string; | ||
email: string; | ||
} | ||
|
||
export const addToWishlist = async (req: Request, res: Response) => { | ||
const { productId } = req.body; | ||
const user = req.user as UserInterface; | ||
|
||
try { | ||
const product = await Product.findOne({ | ||
where: { id: productId }, | ||
}); | ||
if (!product) { | ||
return sendErrorResponse(res, 'Product not found'); | ||
} | ||
const size = await Size.findOne({ | ||
where: { productId: productId }, | ||
}); | ||
if (!size) { | ||
return sendErrorResponse(res, 'No sizes found !'); | ||
} | ||
//check if the product is already added in the wishlist | ||
const itemExist = await Wishlist.findOne({ | ||
where: { | ||
userId: user.id, | ||
productId: productId, | ||
}, | ||
}); | ||
if (itemExist) { | ||
return res.status(400).json({ | ||
ok: false, | ||
message: 'Product already added to wishlist', | ||
}); | ||
} | ||
const wishlistItem = await Wishlist.create({ | ||
userId: user.id, | ||
productId: productId, | ||
name: product.name, | ||
price: size.price, | ||
images: product.images, | ||
}); | ||
|
||
return res.status(201).json({ | ||
ok: true, | ||
message: 'Product added to wishlist successfully', | ||
data: wishlistItem, | ||
}); | ||
} catch (err) { | ||
console.log(err); | ||
return sendInternalErrorResponse(res, err); | ||
} | ||
}; | ||
export const getWishlist = async (req: Request, res: Response) => { | ||
const { id } = req.user as UserInterface; | ||
|
||
try { | ||
const wishlistItems = await Wishlist.findAll({ | ||
where: { userId: id }, | ||
}); | ||
|
||
return res.status(200).json({ | ||
ok: true, | ||
message: 'Wishlist fetched successfully', | ||
data: wishlistItems, | ||
}); | ||
} catch (err) { | ||
return sendInternalErrorResponse(res, err); | ||
} | ||
}; | ||
|
||
export const deleteWishlist = async (req: Request, res: Response) => { | ||
const { id } = req.user as UserInterface; | ||
try { | ||
await Wishlist.destroy({ where: { userId: id } }); | ||
return res.status(200).json({ | ||
ok: true, | ||
message: 'Wishlist cleared successfully', | ||
}); | ||
} catch (err) { | ||
return sendInternalErrorResponse(res, err); | ||
} | ||
}; | ||
export const deleteWishlistItem = async (req: Request, res: Response) => { | ||
const user = req.user as UserInterface; | ||
const { productId } = req.body; | ||
try { | ||
await Wishlist.destroy({ where: { userId: user.id, productId: productId } }); | ||
return res.status(200).json({ | ||
ok: true, | ||
message: 'Wishlist item deleted successfully', | ||
}); | ||
} catch (err) { | ||
return sendInternalErrorResponse(res, err); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
'use strict'; | ||
|
||
const sequelize = require('sequelize'); | ||
|
||
/** @type {import('sequelize-cli').Migration} */ | ||
module.exports = { | ||
async up(queryInterface, Sequelize) { | ||
await queryInterface.createTable('categories', { | ||
id: { | ||
allowNull: false, | ||
primaryKey: true, | ||
type: Sequelize.UUID, | ||
defaultValue: sequelize.UUIDV4, | ||
unique: true, | ||
}, | ||
name: { | ||
type: Sequelize.STRING, | ||
allowNull: false, | ||
}, | ||
description: { | ||
type: Sequelize.TEXT, | ||
allowNull: true, | ||
}, | ||
createdAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('NOW()'), | ||
}, | ||
updatedAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'), | ||
}, | ||
}); | ||
}, | ||
async down(queryInterface) { | ||
await queryInterface.dropTable('categories'); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
'use strict'; | ||
|
||
const sequelize = require('sequelize'); | ||
|
||
/** @type {import('sequelize-cli').Migration} */ | ||
module.exports = { | ||
async up(queryInterface, Sequelize) { | ||
await queryInterface.createTable('products', { | ||
id: { | ||
allowNull: false, | ||
primaryKey: true, | ||
type: Sequelize.UUID, | ||
defaultValue: sequelize.UUIDV4, | ||
}, | ||
name: { | ||
type: Sequelize.STRING, | ||
allowNull: false, | ||
}, | ||
description: { | ||
type: Sequelize.TEXT, | ||
allowNull: false, | ||
}, | ||
images: { | ||
type: Sequelize.ARRAY(Sequelize.STRING), | ||
allowNull: false, | ||
}, | ||
colors: { | ||
type: Sequelize.ARRAY(Sequelize.STRING), | ||
allowNull: true, | ||
}, | ||
sellerId: { | ||
type: Sequelize.UUID, | ||
references: { | ||
model: 'Users', | ||
key: 'id', | ||
}, | ||
onDelete: 'CASCADE', | ||
onUpdate: 'CASCADE', | ||
allowNull: false, | ||
}, | ||
categoryId: { | ||
type: Sequelize.UUID, | ||
allowNull: false, | ||
references: { | ||
model: 'categories', | ||
key: 'id', | ||
}, | ||
onUpdate: 'CASCADE', | ||
onDelete: 'CASCADE', | ||
}, | ||
createdAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('NOW()'), | ||
}, | ||
updatedAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'), | ||
}, | ||
}); | ||
}, | ||
async down(queryInterface) { | ||
await queryInterface.dropTable('product_sizes'); | ||
await queryInterface.dropTable('products'); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
'use strict'; | ||
|
||
const sequelize = require('sequelize'); | ||
|
||
/** @type {import('sequelize-cli').Migration} */ | ||
module.exports = { | ||
async up(queryInterface, Sequelize) { | ||
await queryInterface.createTable('sizes', { | ||
id: { | ||
allowNull: false, | ||
primaryKey: true, | ||
type: Sequelize.UUID, | ||
defaultValue: sequelize.UUIDV4, | ||
}, | ||
size: { | ||
type: Sequelize.STRING, | ||
allowNull: true, | ||
}, | ||
price: { | ||
type: Sequelize.FLOAT, | ||
allowNull: false, | ||
}, | ||
quantity: { | ||
type: Sequelize.INTEGER, | ||
defaultValue: 1, | ||
}, | ||
discount: { | ||
type: Sequelize.FLOAT, | ||
allowNull: true, | ||
}, | ||
expiryDate: { | ||
type: Sequelize.DATE, | ||
allowNull: true, | ||
}, | ||
productId: { | ||
type: Sequelize.UUID, | ||
references: { | ||
model: 'products', | ||
key: 'id', | ||
}, | ||
onDelete: 'CASCADE', | ||
onUpdate: 'CASCADE', | ||
allowNull: false, | ||
}, | ||
createdAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('NOW()'), | ||
}, | ||
updatedAt: { | ||
allowNull: false, | ||
type: Sequelize.DATE, | ||
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'), | ||
}, | ||
}); | ||
}, | ||
async down(queryInterface) { | ||
await queryInterface.dropTable('sizes'); | ||
}, | ||
}; |
Oops, something went wrong.