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
Some checks failed
Deploy Canina / deploy (push) Failing after 29s
This commit is contained in:
parent
9e233bee27
commit
7cc9194827
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user