Skip to content

Commit

Permalink
Update home page
Browse files Browse the repository at this point in the history
  • Loading branch information
aelassas committed Oct 7, 2024
1 parent bf7caa4 commit cba4589
Show file tree
Hide file tree
Showing 85 changed files with 1,341 additions and 458 deletions.
3 changes: 2 additions & 1 deletion api/src/config/categoryRoutes.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export default {
update: '/api/update-category/:id',
delete: '/api/delete-category/:id',
getCategory: '/api/category/:id/:language',
getCategories: '/api/categories/:language',
getCategories: '/api/categories/:language/:imageRequired',
getFeaturedCategories: '/api/featured-categories/:language/:size',
searchCategories: '/api/search-categories/:language',
createImage: '/api/create-category-image',
updateImage: '/api/update-category-image/:id',
Expand Down
2 changes: 1 addition & 1 deletion api/src/config/productRoutes.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export default {
getProduct: '/api/product/:id/:language',
getBackendProducts: '/api/backend-products/:user/:page/:size/:category?',
getFrontendProducts: '/api/frontend-products/:page/:size/:category?',
getFeaturedProducts: '/api/featured-products/:size',
getFeaturedProducts: '/api/featured-products',
}
148 changes: 147 additions & 1 deletion api/src/controllers/categoryController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as env from '../config/env.config'
import Category from '../models/Category'
import Value from '../models/Value'
import Product from '../models/Product'
import Cart from '../models/Cart'

/**
* Validate category name by language.
Expand Down Expand Up @@ -249,9 +250,18 @@ export const getCategory = async (req: Request, res: Response) => {
*/
export const getCategories = async (req: Request, res: Response) => {
try {
const { language } = req.params
const { language, imageRequired } = req.params
const _imageRequired = helper.StringToBoolean(imageRequired)

let $match: mongoose.FilterQuery<env.Category> = {}
if (_imageRequired) {
$match = { image: { $ne: null } }
}

const categories = await Category.aggregate([
{
$match,
},
{
$lookup: {
from: 'Value',
Expand Down Expand Up @@ -282,6 +292,142 @@ export const getCategories = async (req: Request, res: Response) => {
}
}

/**
* Get featured categories.
*
* @async
* @param {Request} req
* @param {Response} res
* @returns {unknown}
*/
export const getFeaturedCategories = async (req: Request, res: Response) => {
try {
const { language, size: _size } = req.params
const cartId = String(req.query.c || '')
const size = Number.parseInt(_size, 10)

let cartProducts: mongoose.Types.ObjectId[] = []
if (cartId) {
const _cart = await Cart
.findById(cartId)
.populate<{ cartItems: env.CartItem[] }>('cartItems')
.lean()

if (_cart) {
cartProducts = _cart.cartItems.map((cartItem) => cartItem.product)
}
}

const data = await Product.aggregate([
{
$match: { soldOut: false, hidden: false, quantity: { $gt: 0 } },
},
//
// Add inCart field
//
{
$addFields: {
inCart: {
$cond: [{ $in: ['$_id', cartProducts] }, 1, 0],
},
},
},
//
// lookup categories
//
{
$lookup: {
from: 'Category',
let: { categories: '$categories' },
pipeline: [
{
$match: {
$expr: { $in: ['$_id', '$$categories'] },
},
},
{
$lookup: {
from: 'Value',
let: { values: '$values' },
pipeline: [
{
$match: {
$and: [
{ $expr: { $in: ['$_id', '$$values'] } },
{ $expr: { $eq: ['$language', language] } },
],
},
},
],
as: 'value',
},
},
{ $unwind: { path: '$value', preserveNullAndEmptyArrays: false } },
{ $addFields: { name: '$value.value' } },
],
as: 'category',
},
},
//
// unwind category
//
{ $unwind: { path: '$category', preserveNullAndEmptyArrays: false } },
//
// Skip categories and description fields
//
{
$project: {
categories: 0,
description: 0,
},
},
//
// Sort products by createdAt desc
//
{
$sort: { createdAt: -1 },
},
//
// Group products by category
//
{
$group: {
_id: '$category._id',
name: { $first: '$category.name' },
image: { $first: '$category.image' },
featured: { $first: '$category.featured' },
products: { $push: '$$ROOT' },
},
},
//
// Sort categories by name
//
{
$sort: { name: 1 },
},
//
// Build final result and take only (size) products
//
{
$project: {
_id: 0,
category: {
_id: '$_id',
name: '$name',
image: '$image',
featured: '$featured',
},
products: { $slice: ['$products', size] },
},
},
])
return res.json(data)
} catch (err) {
logger.error(`[category.getFeaturedCategories] ${i18n.t('DB_ERROR')}`, err)
return res.status(400).send(i18n.t('DB_ERROR') + err)
}
}

/**
* Search categories.
*
Expand Down
34 changes: 17 additions & 17 deletions api/src/controllers/productController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ export const update = async (req: Request, res: Response) => {
product.hidden = hidden
product.featured = featured

if (quantity > 0) {
product.soldOut = false
}

if (image) {
const oldImage = path.join(env.CDN_PRODUCTS, product.image!)
if (await helper.exists(oldImage)) {
Expand Down Expand Up @@ -552,7 +556,8 @@ export const getFrontendProducts = async (req: Request, res: Response) => {
category = new mongoose.Types.ObjectId(req.params.category)
}

const { cart: cartId } = req.body
const { body }: { body: wexcommerceTypes.GetProductsPayload } = req
const { cart: cartId } = body
let cartProducts: mongoose.Types.ObjectId[] = []
if (cartId) {
const _cart = await Cart
Expand Down Expand Up @@ -635,7 +640,7 @@ export const getFrontendProducts = async (req: Request, res: Response) => {
}

/**
* Get frontend products.
* Get featured products.
*
* @async
* @param {Request} req
Expand All @@ -644,7 +649,10 @@ export const getFrontendProducts = async (req: Request, res: Response) => {
*/
export const getFeaturedProducts = async (req: Request, res: Response) => {
try {
const { cart: cartId, size } = req.body
const { body }: { body: wexcommerceTypes.GetProductsPayload } = req
const { cart: cartId, size: _size } = body

const size: number = _size || 10

let cartProducts: mongoose.Types.ObjectId[] = []
if (cartId) {
Expand All @@ -658,10 +666,9 @@ export const getFeaturedProducts = async (req: Request, res: Response) => {
}
}

// TODO after: sort by price asc, desc
const products = await Product.aggregate([
{
$match: { featured: true },
$match: { featured: true, soldOut: false, hidden: false, quantity: { $gt: 0 } },
},
{
$addFields: {
Expand All @@ -677,23 +684,16 @@ export const getFeaturedProducts = async (req: Request, res: Response) => {
},
},
{
$facet: {
resultData: [
{ $sort: { createdAt: -1 } },
{ $limit: size },
],
pageInfo: [
{
$count: 'totalRecords',
},
],
},
$sort: { createdAt: -1 },
},
{
$limit: size,
},
], { collation: { locale: env.DEFAULT_LANGUAGE, strength: 2 } })

return res.json(products)
} catch (err) {
logger.error(i18n.t('DB_ERROR'), err)
logger.error(`[product.getFeaturedProducts] ${i18n.t('DB_ERROR')}`, err)
return res.status(400).send(i18n.t('DB_ERROR') + err)
}
}
1 change: 1 addition & 0 deletions api/src/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import validator from 'validator'
import { Schema, model } from 'mongoose'
import * as wexcommerceTypes from ':wexcommerce-types'
// import * as wexcommerceHelper from ':wexcommerce-helper'
import * as env from '../config/env.config'

export const USER_EXPIRE_AT_INDEX_NAME = 'expireAt'
Expand Down
1 change: 1 addition & 0 deletions api/src/routes/categoryRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ routes.route(routeNames.update).put(authJwt.verifyToken, categoryController.upda
routes.route(routeNames.delete).delete(authJwt.verifyToken, categoryController.deleteCategory)
routes.route(routeNames.getCategory).get(authJwt.verifyToken, categoryController.getCategory)
routes.route(routeNames.getCategories).get(categoryController.getCategories)
routes.route(routeNames.getFeaturedCategories).get(categoryController.getFeaturedCategories)
routes.route(routeNames.searchCategories).get(authJwt.verifyToken, categoryController.searchCategories)
routes.route(routeNames.createImage).post([authJwt.verifyToken, multer({ storage: multer.memoryStorage() }).single('image')], categoryController.createImage)
routes.route(routeNames.updateImage).post([authJwt.verifyToken, multer({ storage: multer.memoryStorage() }).single('image')], categoryController.updateImage)
Expand Down
1 change: 1 addition & 0 deletions api/src/routes/productRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ routes.route(routeNames.delete).delete(authJwt.verifyToken, productController.de
routes.route(routeNames.getProduct).post(productController.getProduct)
routes.route(routeNames.getBackendProducts).post(authJwt.verifyToken, productController.getBackendProducts)
routes.route(routeNames.getFrontendProducts).post(productController.getFrontendProducts)
routes.route(routeNames.getFeaturedProducts).post(productController.getFeaturedProducts)

export default routes
6 changes: 5 additions & 1 deletion backend/src/app/(pages)/(dashboard)/category/page.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ const CategoryForm: React.FC<CategoryFormProps> = ({ category }) => {
type="category"
categoryId={category._id}
image={image}
onMainImageUpsert={(img) => setImage(img)}
onMainImageUpsert={(img) => {
setImage(img)
router.refresh()
}}
/>

{
Expand Down Expand Up @@ -199,6 +202,7 @@ const CategoryForm: React.FC<CategoryFormProps> = ({ category }) => {
size="small"
onClick={() => {
router.push('/categories')
router.refresh()
}}
>
{commonStrings.CANCEL}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ const CreateProductForm: React.FC<CreateProductFormProps> = ({ product }) => {
helper.error(err)
}
router.push('/products')
router.refresh()
}}
>
{commonStrings.CANCEL}
Expand Down
16 changes: 15 additions & 1 deletion backend/src/app/(pages)/(dashboard)/products/page.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ const ProductsWrapper: React.FC<ProductsWrapperProps> = ({ children }) => {
{strings.NEW_PRODUCT}
</Button>
}

<ul className={styles.categories}>
<li>
<Link href='/products' className={!categoryId ? styles.selected : ''}>
Expand All @@ -129,13 +130,26 @@ const ProductsWrapper: React.FC<ProductsWrapperProps> = ({ children }) => {

</Link>
</li>

{
categories.map((category) => (
<li key={category._id}>
<Link
href={`/products?c=${category._id}`}
className={categoryId === category._id ? styles.selected : ''}
title={category.name}>
title={category.name}
onClick={() => {
if (env.isMobile() && leftPanelRef.current) {
leftPanelRef.current.style.display = 'none'
if (productsRef.current) {
productsRef.current.style.display = 'block'
}
if (closeIconRef.current) {
closeIconRef.current.style.visibility = 'hidden'
}
}
}}
>

<CategoryIcon className={styles.categoryIcon} />
<span>{category.name}</span>
Expand Down
7 changes: 7 additions & 0 deletions backend/src/app/(pages)/(login)/sign-up/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,11 @@ const SignUp: React.FC = () => {
)
}

export function getStaticProps() {
return {
// returns the default 404 page with a status code of 404 in production
notFound: process.env.NODE_ENV === 'production'
}
}

export default SignUp
Loading

0 comments on commit cba4589

Please sign in to comment.