fix(validation & catalog): disable strict forbidNonWhitelisted in NestJS ValidationPipe and wire full catalog mode & maintenance mode settings to frontend
Some checks failed
Deploy Canina / deploy (push) Failing after 29s

This commit is contained in:
parsa aghaei 2026-08-08 18:38:48 +03:30
parent 9e233bee27
commit 7cc9194827
3 changed files with 44 additions and 16 deletions

View File

@ -61,7 +61,7 @@ async function bootstrap() {
new ValidationPipe({ new ValidationPipe({
transform: true, transform: true,
whitelist: true, whitelist: true,
forbidNonWhitelisted: true, forbidNonWhitelisted: false,
exceptionFactory: (errors) => { exceptionFactory: (errors) => {
const formattedDetails = errors.map((err) => { const formattedDetails = errors.map((err) => {
const constraints = err.constraints const constraints = err.constraints

View File

@ -13,7 +13,17 @@ export class SettingsService {
constructor(private prisma: PrismaService) {} constructor(private prisma: PrismaService) {}
async getUiTexts() { async getUiTexts() {
return this.prisma.uiText.findMany(); const [uiTexts, settings] = await Promise.all([
this.prisma.uiText.findMany(),
this.prisma.setting.findMany(),
]);
const merged = [...uiTexts];
settings.forEach((s) => {
merged.push({ key: s.key, value: String(s.value) } as any);
});
return merged;
} }
async updateUiText(key: string, value: string) { async updateUiText(key: string, value: string) {

View File

@ -32,6 +32,12 @@ function ProductCard({ product }: { product: Product }) {
return { type: "neutral", text: `مناسب برای ${activePet.name}` }; return { type: "neutral", text: `مناسب برای ${activePet.name}` };
}, [product, activePet]); }, [product, activePet]);
const getText = useSettingsStore((state) => state.getText);
const isCatalogOnly = getText('CATALOG_ONLY_MODE', 'false') === 'true';
const showPrices = !isCatalogOnly || getText('CATALOG_SHOW_PRICES', 'true') === 'true';
const allowCart = !isCatalogOnly || getText('CATALOG_ALLOW_CART', 'false') === 'true';
const showPreorderBtn = isCatalogOnly && getText('CATALOG_PREORDER_BTN', 'false') === 'true';
return ( return (
<motion.div <motion.div
initial={{ opacity: 0, y: 24 }} initial={{ opacity: 0, y: 24 }}
@ -72,19 +78,23 @@ function ProductCard({ product }: { product: Product }) {
<div <div
onClick={(e) => { e.stopPropagation(); router.push(`/shop/${product.slug || product.id}`); }} onClick={(e) => { e.stopPropagation(); router.push(`/shop/${product.slug || product.id}`); }}
className="w-11 h-11 rounded-full bg-white text-canina-blue flex items-center justify-center hover:scale-110 transition-transform shadow-lg cursor-pointer" className="w-11 h-11 rounded-full bg-white text-canina-blue flex items-center justify-center hover:scale-110 transition-transform shadow-lg cursor-pointer"
title="مشاهده جزئیات"
> >
<Eye className="w-5 h-5" /> <Eye className="w-5 h-5" />
</div> </div>
<div {allowCart && (
onClick={(e) => { <div
e.stopPropagation(); onClick={(e) => {
addItem(product, 1); e.stopPropagation();
toast.success(`${nameFa} به سبد خرید اضافه شد.`); addItem(product, 1);
}} toast.success(`${nameFa} به سبد خرید اضافه شد.`);
className="w-11 h-11 rounded-full bg-canina-blue text-white flex items-center justify-center hover:scale-110 transition-transform shadow-lg border border-white/20 cursor-pointer" }}
> className="w-11 h-11 rounded-full bg-canina-blue text-white flex items-center justify-center hover:scale-110 transition-transform shadow-lg border border-white/20 cursor-pointer"
<ShoppingCart className="w-5 h-5" /> title="افزودن به سبد خرید"
</div> >
<ShoppingCart className="w-5 h-5" />
</div>
)}
</div> </div>
</div> </div>
@ -109,10 +119,18 @@ function ProductCard({ product }: { product: Product }) {
{/* Footer: Price + CTA */} {/* Footer: Price + CTA */}
<div className="flex items-center justify-between pt-3 border-t border-medical-gray-100"> <div className="flex items-center justify-between pt-3 border-t border-medical-gray-100">
<div className="text-base font-black text-medical-gray-900 font-vazir whitespace-nowrap">{product.price}</div> <div className="text-base font-black text-medical-gray-900 font-vazir whitespace-nowrap">
<span className="text-[11px] font-black text-canina-blue uppercase tracking-widest border-b-2 border-canina-blue pb-0.5 hover:text-medical-gray-900 hover:border-medical-gray-900 transition-all whitespace-nowrap"> {showPrices ? product.price : 'تماس بگیرید'}
{getText("product_view_details", "مشاهده جزئیات")} </div>
</span> {showPreorderBtn ? (
<span className="text-[11px] font-black text-amber-600 bg-amber-50 px-3 py-1 rounded-full border border-amber-200">
ثبت پیشخرید
</span>
) : (
<span className="text-[11px] font-black text-canina-blue uppercase tracking-widest border-b-2 border-canina-blue pb-0.5 hover:text-medical-gray-900 hover:border-medical-gray-900 transition-all whitespace-nowrap">
{getText("product_view_details", "مشاهده جزئیات")}
</span>
)}
</div> </div>
</Link> </Link>
</motion.div> </motion.div>