Files

244 lines
9.1 KiB
JavaScript

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { Controller, Get, Injectable, Module, NotFoundException, Param } from "@nestjs/common";
import { MediaModule } from "../media/media.controller.js";
import { MediaService } from "../media/media.service.js";
import { PrismaService } from "../prisma/prisma.service.js";
import { SectionsModule, SectionsService } from "../sections/sections.module.js";
const visible = { isPublished: true, category: { isPublished: true } };
const RELATED_LIMIT = 4;
const isAttribute = (a) => !!a && typeof a === "object" && typeof a.name === "string" && typeof a.value === "string";
let PublicService = class PublicService {
prisma;
media;
sections;
constructor(prisma, media, sections) {
this.prisma = prisma;
this.media = media;
this.sections = sections;
}
async site() {
const [sections, categories] = await Promise.all([this.sections.getAll(), this.categories()]);
return { sections, categories };
}
async categories() {
const rows = await this.prisma.category.findMany({
where: { isPublished: true },
orderBy: [{ sortOrder: "asc" }, { id: "asc" }],
include: {
coverImage: true,
_count: { select: { products: { where: { isPublished: true } } } },
},
});
return rows.map((c) => ({
slug: c.slug,
code: c.code,
name: c.name,
nameEn: c.nameEn,
shortDesc: c.shortDesc,
icon: c.icon,
coverImage: c.coverImage && this.media.url(c.coverImage.key),
productCount: c._count.products,
}));
}
async category(slug) {
const c = await this.prisma.category.findFirst({
where: { slug, isPublished: true },
include: {
coverImage: true,
groups: { orderBy: { sortOrder: "asc" } },
products: {
where: { isPublished: true },
orderBy: [{ sortOrder: "asc" }, { id: "asc" }],
include: { image: true, group: { select: { slug: true } } },
},
},
});
if (!c)
throw new NotFoundException("دسته‌بندی یافت نشد");
const products = c.products.map((p) => this.toPublicProduct(p));
const usedGroups = new Set(products.map((p) => p.group));
return {
slug: c.slug,
code: c.code,
name: c.name,
nameEn: c.nameEn,
shortDesc: c.shortDesc,
fullDesc: c.fullDesc,
icon: c.icon,
seoTitle: c.seoTitle,
seoDescription: c.seoDescription,
coverImage: c.coverImage && this.media.url(c.coverImage.key),
productCount: products.length,
groups: c.groups
.filter((g) => usedGroups.has(g.slug))
.map((g) => ({ slug: g.slug, name: g.name, desc: g.desc })),
products,
};
}
async product(slug) {
const p = await this.prisma.product.findFirst({
where: { slug, ...visible },
include: {
image: true,
gallery: { orderBy: { sortOrder: "asc" }, include: { media: true } },
group: true,
category: { include: { coverImage: true } },
},
});
if (!p)
throw new NotFoundException("محصول یافت نشد");
const media = new Map();
for (const m of [p.image, ...p.gallery.map((g) => g.media)])
if (m)
media.set(m.id, m);
const siblings = await this.prisma.product.findMany({
where: { categoryId: p.categoryId, isPublished: true, id: { not: p.id } },
orderBy: [{ sortOrder: "asc" }, { id: "asc" }],
include: { image: true, group: { select: { slug: true } } },
});
const sameGroup = (s) => p.groupId !== null && s.groupId === p.groupId;
const related = [...siblings.filter(sameGroup), ...siblings.filter((s) => !sameGroup(s))]
.slice(0, RELATED_LIMIT)
.map((s) => this.toPublicProduct(s));
return {
...this.toPublicProduct(p),
details: p.details,
brand: p.brand,
origin: p.origin,
sizes: p.sizes,
standards: p.standards,
features: p.features,
applications: p.applications,
attributes: Array.isArray(p.attributes) ? p.attributes.filter(isAttribute) : [],
packaging: p.packaging,
minOrder: p.minOrder,
seoTitle: p.seoTitle,
seoDescription: p.seoDescription,
images: [...media.values()].map((m) => ({
url: this.media.url(m.key),
alt: m.alt || p.name,
width: m.width,
height: m.height,
})),
groupName: p.group?.name ?? null,
category: {
slug: p.category.slug,
code: p.category.code,
name: p.category.name,
nameEn: p.category.nameEn,
fullDesc: p.category.fullDesc,
coverImage: p.category.coverImage && this.media.url(p.category.coverImage.key),
},
related,
updatedAt: p.updatedAt.toISOString(),
};
}
async productRefs() {
const rows = await this.prisma.product.findMany({
where: visible,
orderBy: [{ category: { sortOrder: "asc" } }, { sortOrder: "asc" }],
select: { slug: true, updatedAt: true },
});
return rows.map((r) => ({ slug: r.slug, updatedAt: r.updatedAt.toISOString() }));
}
toPublicProduct(p) {
return {
code: p.code,
slug: p.slug,
name: p.name,
nameEn: p.nameEn,
desc: p.desc,
specs: p.specs,
variants: p.variants,
image: p.image && this.media.url(p.image.key),
group: p.group?.slug ?? null,
};
}
};
PublicService = __decorate([
Injectable(),
__metadata("design:paramtypes", [PrismaService,
MediaService,
SectionsService])
], PublicService);
export { PublicService };
let PublicController = class PublicController {
publicData;
constructor(publicData) {
this.publicData = publicData;
}
site() {
return this.publicData.site();
}
categories() {
return this.publicData.categories();
}
category(slug) {
return this.publicData.category(slug);
}
products() {
return this.publicData.productRefs();
}
product(slug) {
return this.publicData.product(slug);
}
};
__decorate([
Get("site"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], PublicController.prototype, "site", null);
__decorate([
Get("categories"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], PublicController.prototype, "categories", null);
__decorate([
Get("categories/:slug"),
__param(0, Param("slug")),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], PublicController.prototype, "category", null);
__decorate([
Get("products"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], PublicController.prototype, "products", null);
__decorate([
Get("products/:slug"),
__param(0, Param("slug")),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], PublicController.prototype, "product", null);
PublicController = __decorate([
Controller("public"),
__metadata("design:paramtypes", [PublicService])
], PublicController);
export { PublicController };
let PublicModule = class PublicModule {
};
PublicModule = __decorate([
Module({
imports: [MediaModule, SectionsModule],
controllers: [PublicController],
providers: [PublicService],
})
], PublicModule);
export { PublicModule };
//# sourceMappingURL=public.module.js.map