feat(products): fix search query filter overwrite and add minPrice maxPrice sorting filters [TASK-26.10] [TASK-26.11]
This commit is contained in:
parent
7f3c04acf5
commit
3497a743b3
@ -25,4 +25,24 @@ export class GetProductsDto extends PaginationDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
requiresRx?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'حداقل قیمت (تومان)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
minPrice?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'حداکثر قیمت (تومان)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
maxPrice?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'فیلد مرتبسازی', enum: ['priceValue', 'createdAt', 'nameFa'] })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sortBy?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'جهت مرتبسازی', enum: ['asc', 'desc'] })
|
||||
@IsOptional()
|
||||
@IsEnum(['asc', 'desc'])
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
@ -13,66 +13,68 @@ export class ProductsService {
|
||||
search,
|
||||
symptom,
|
||||
requiresRx,
|
||||
minPrice,
|
||||
maxPrice,
|
||||
page = 1,
|
||||
limit = 10,
|
||||
sortBy = 'createdAt',
|
||||
sortOrder = 'desc',
|
||||
} = filters;
|
||||
|
||||
const whereClause: any = {};
|
||||
const andConditions: any[] = [];
|
||||
|
||||
if (requiresRx !== undefined && requiresRx !== null && requiresRx !== '') {
|
||||
whereClause.requiresRx = requiresRx === 'true' || requiresRx === '1';
|
||||
andConditions.push({ requiresRx: requiresRx === 'true' || requiresRx === '1' });
|
||||
}
|
||||
|
||||
if (category) {
|
||||
whereClause.categorySlug = category;
|
||||
andConditions.push({ categorySlug: category });
|
||||
}
|
||||
|
||||
if (petType && petType !== 'all') {
|
||||
whereClause.suitableFor = { in: [petType, 'هر دو'] };
|
||||
andConditions.push({ suitableFor: { in: [petType, 'هر دو'] } });
|
||||
}
|
||||
|
||||
// Filter by a specific symptom (from URL param ?symptom=...)
|
||||
if (symptom) {
|
||||
whereClause.symptoms = {
|
||||
some: {
|
||||
symptom: { contains: symptom, mode: 'insensitive' },
|
||||
andConditions.push({
|
||||
symptoms: {
|
||||
some: {
|
||||
symptom: { contains: symptom, mode: 'insensitive' },
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (minPrice) {
|
||||
andConditions.push({ priceValue: { gte: Number(minPrice) } });
|
||||
}
|
||||
|
||||
if (maxPrice) {
|
||||
andConditions.push({ priceValue: { lte: Number(maxPrice) } });
|
||||
}
|
||||
|
||||
if (search) {
|
||||
// If symptom filter is already applied, extend via AND to also search names/desc
|
||||
// If not, use OR across names, description AND symptoms
|
||||
const searchConditions = [
|
||||
{ artNo: { contains: search, mode: 'insensitive' } },
|
||||
{ barcode: { contains: search, mode: 'insensitive' } },
|
||||
{ nameFa: { contains: search, mode: 'insensitive' } },
|
||||
{ nameEn: { contains: search, mode: 'insensitive' } },
|
||||
{ description: { contains: search, mode: 'insensitive' } },
|
||||
{ shortDescription: { contains: search, mode: 'insensitive' } },
|
||||
{
|
||||
symptoms: {
|
||||
some: {
|
||||
symptom: { contains: search, mode: 'insensitive' },
|
||||
andConditions.push({
|
||||
OR: [
|
||||
{ artNo: { contains: search, mode: 'insensitive' } },
|
||||
{ barcode: { contains: search, mode: 'insensitive' } },
|
||||
{ nameFa: { contains: search, mode: 'insensitive' } },
|
||||
{ nameEn: { contains: search, mode: 'insensitive' } },
|
||||
{ description: { contains: search, mode: 'insensitive' } },
|
||||
{ shortDescription: { contains: search, mode: 'insensitive' } },
|
||||
{
|
||||
symptoms: {
|
||||
some: {
|
||||
symptom: { contains: search, mode: 'insensitive' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
if (symptom) {
|
||||
// Already have a symptom filter; combine with AND
|
||||
whereClause.AND = [
|
||||
{ symptoms: whereClause.symptoms },
|
||||
{ OR: searchConditions.filter((c) => !('symptoms' in c)) },
|
||||
];
|
||||
delete whereClause.symptoms;
|
||||
} else {
|
||||
whereClause.OR = searchConditions;
|
||||
}
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
const whereClause: any = andConditions.length > 0 ? { AND: andConditions } : {};
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
const [rawProducts, total] = await Promise.all([
|
||||
|
||||
@ -207,8 +207,8 @@
|
||||
- [ ] **TASK-26.7 [SSR & HttpOnly Cookie Auth]:** ذخیره توکنها درون HttpOnly Cookie جهت همگامسازی کامل Server & Client Components در Next.js.
|
||||
- [x] **TASK-26.8 [Logout State Cleanup]:** پاکسازی کامل کاتالوگ، سبد خرید و تمام کشهای کاربر هنگام خروج (Logout Cleanup).
|
||||
- [x] **TASK-26.9 [Admin Token Validation Guard]:** اعتبارسنجی واقعی توکن ادمین در `ProtectedRoute.tsx` از طریق فراخوانی API پروفایل در هنگام لود پنل.
|
||||
- [ ] **TASK-26.10 [Fix Pagination & Search Query Overwrite]:** اصلاح منطق `whereClause` در `products.service.ts` جهت جلوگیری از اوررایت شدن فیلترها.
|
||||
- [ ] **TASK-26.11 [Price Range & Sorting Filters]:** افزودن فیلتر محدوده قیمت (`minPrice`, `maxPrice`) و مرتبسازی (`sort`) به DTO و اندپویینتهای محصولات.
|
||||
- [x] **TASK-26.10 [Fix Pagination & Search Query Overwrite]:** اصلاح منطق `whereClause` در `products.service.ts` جهت جلوگیری از اوررایت شدن فیلترها.
|
||||
- [x] **TASK-26.11 [Price Range & Sorting Filters]:** افزودن فیلتر محدوده قیمت (`minPrice`, `maxPrice`) و مرتبسازی (`sort`) به DTO و اندپویینتهای محصولات.
|
||||
- [ ] **TASK-26.12 [Sync Fallback IDs with Database]:** همگامسازی شناسه محصولات استاتیک فرانتاند با دیتابیس واقعی جهت جلوگیری از 404 در سفارش.
|
||||
- [ ] **TASK-26.13 [Admin Products Table Pagination]:** پیادهسازی پجینیشن سرورساید کامل در جدول مدیریت محصولات پنل ادمین.
|
||||
- [ ] **TASK-26.14 [Admin Wallet Adjust Endpoint]:** ایجاد اندپویینت `POST /api/users/:id/wallet-adjust` و فرم شارژ/کسر مستقیم کیفپول در پنل ادمین.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user