diff --git a/apps/admin-panel/dist/favicon.ico b/apps/admin-panel/dist/favicon.ico
index 78ba2d0..ffa7c0a 100644
Binary files a/apps/admin-panel/dist/favicon.ico and b/apps/admin-panel/dist/favicon.ico differ
diff --git a/apps/admin-panel/dist/favicon.png b/apps/admin-panel/dist/favicon.png
index 7c1cb2d..8b8df04 100644
Binary files a/apps/admin-panel/dist/favicon.png and b/apps/admin-panel/dist/favicon.png differ
diff --git a/apps/admin-panel/dist/index.html b/apps/admin-panel/dist/index.html
index 9582ffa..1295f4b 100644
--- a/apps/admin-panel/dist/index.html
+++ b/apps/admin-panel/dist/index.html
@@ -1,17 +1,17 @@
-
-
-
-
-
-
- تهران تاج — پنل مدیریت
+
+
+
+
+
+
+ تهران تاج — پنل مدیریت
-
-
-
-
-
+
+
+
+
+
diff --git a/apps/admin-panel/index.html b/apps/admin-panel/index.html
index 04ce988..5972844 100644
--- a/apps/admin-panel/index.html
+++ b/apps/admin-panel/index.html
@@ -3,7 +3,8 @@
-
+
+
%BRAND_TITLE%
diff --git a/apps/admin-panel/public/favicon.ico b/apps/admin-panel/public/favicon.ico
index 78ba2d0..ffa7c0a 100644
Binary files a/apps/admin-panel/public/favicon.ico and b/apps/admin-panel/public/favicon.ico differ
diff --git a/apps/admin-panel/public/favicon.png b/apps/admin-panel/public/favicon.png
index 7c1cb2d..8b8df04 100644
Binary files a/apps/admin-panel/public/favicon.png and b/apps/admin-panel/public/favicon.png differ
diff --git a/apps/api/release/app.js b/apps/api/release/app.js
index c427f2b..48ab618 100644
--- a/apps/api/release/app.js
+++ b/apps/api/release/app.js
@@ -164101,8 +164101,21 @@ var require_prisma_exception_filter = __commonJS({
};
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.PrismaExceptionFilter = void 0;
+ exports2.uniqueViolationMessage = uniqueViolationMessage;
var common_12 = require_common();
var client_1 = require("@prisma/client");
+ function uniqueViolationMessage(target) {
+ const fields = (Array.isArray(target) ? target : [target]).map((t) => String(t ?? "")).join(",").toLowerCase();
+ if (fields.includes("mobile"))
+ return "\u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A";
+ if (fields.includes("nationalcode"))
+ return "\u0627\u06CC\u0646 \u06A9\u062F \u0645\u0644\u06CC \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A";
+ if (fields.includes("membercode"))
+ return "\u0627\u06CC\u0646 \u06A9\u062F \u0639\u0636\u0648\u06CC\u062A \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A";
+ if (fields.includes("ordernumber"))
+ return "\u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u0633\u0641\u0627\u0631\u0634 \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A";
+ return "\u0627\u06CC\u0646 \u0645\u0642\u062F\u0627\u0631 \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A \u0648 \u062A\u06A9\u0631\u0627\u0631\u06CC \u0627\u0633\u062A";
+ }
var PrismaExceptionFilter = class PrismaExceptionFilter {
logger = new common_12.Logger("PrismaExceptionFilter");
catch(exception, host) {
@@ -164133,7 +164146,7 @@ var require_prisma_exception_filter = __commonJS({
return response.status(common_12.HttpStatus.CONFLICT).json({
statusCode: common_12.HttpStatus.CONFLICT,
error: "Conflict",
- message: `Unique constraint failed on: ${exception.meta?.target?.join(", ")}`
+ message: uniqueViolationMessage(exception.meta?.target)
});
case "P2003":
return response.status(common_12.HttpStatus.BAD_REQUEST).json({
diff --git a/apps/api/src/prisma/prisma-exception.filter.spec.ts b/apps/api/src/prisma/prisma-exception.filter.spec.ts
new file mode 100644
index 0000000..a8b6d86
--- /dev/null
+++ b/apps/api/src/prisma/prisma-exception.filter.spec.ts
@@ -0,0 +1,21 @@
+import { uniqueViolationMessage } from './prisma-exception.filter';
+
+describe('uniqueViolationMessage', () => {
+ it('names a duplicate mobile in Persian, whether Prisma sends columns or an index name', () => {
+ expect(uniqueViolationMessage(['mobile'])).toBe('این شماره موبایل قبلاً ثبت شده است');
+ expect(uniqueViolationMessage('Customer_mobile_key')).toBe('این شماره موبایل قبلاً ثبت شده است');
+ expect(uniqueViolationMessage('Admin_mobile_key')).toBe('این شماره موبایل قبلاً ثبت شده است');
+ });
+
+ it('names a duplicate national code', () => {
+ expect(uniqueViolationMessage(['nationalCode'])).toBe('این کد ملی قبلاً ثبت شده است');
+ });
+
+ it('never leaks the English Prisma wording, even for an unknown column or no target', () => {
+ for (const t of [['somethingElse'], undefined, null, []]) {
+ const msg = uniqueViolationMessage(t);
+ expect(msg).toBe('این مقدار قبلاً ثبت شده است و تکراری است');
+ expect(msg).not.toMatch(/[A-Za-z]/);
+ }
+ });
+});
diff --git a/apps/api/src/prisma/prisma-exception.filter.ts b/apps/api/src/prisma/prisma-exception.filter.ts
index da93c8f..ca03381 100644
--- a/apps/api/src/prisma/prisma-exception.filter.ts
+++ b/apps/api/src/prisma/prisma-exception.filter.ts
@@ -2,6 +2,27 @@ import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus, Logger } from '@nest
import { Response } from 'express';
import { Prisma } from '@prisma/client';
+/**
+ * Persian, user-facing text for a unique-index violation. The panel shows
+ * `message` as-is, and the raw Prisma wording ("Unique constraint failed on:
+ * mobile") is meaningless to the operator.
+ *
+ * `target` is the list of columns on Postgres, or the index name when the
+ * driver only reports that — so both are matched by substring.
+ */
+export function uniqueViolationMessage(target: unknown): string {
+ const fields = (Array.isArray(target) ? target : [target])
+ .map((t) => String(t ?? ''))
+ .join(',')
+ .toLowerCase();
+
+ if (fields.includes('mobile')) return 'این شماره موبایل قبلاً ثبت شده است';
+ if (fields.includes('nationalcode')) return 'این کد ملی قبلاً ثبت شده است';
+ if (fields.includes('membercode')) return 'این کد عضویت قبلاً ثبت شده است';
+ if (fields.includes('ordernumber')) return 'این شماره سفارش قبلاً ثبت شده است';
+ return 'این مقدار قبلاً ثبت شده است و تکراری است';
+}
+
/**
* Without this, an unmigrated table (P2021), a bad foreign key (P2003), etc.
* all surfaced as an opaque "Internal Server Error" with no indication of
@@ -44,7 +65,7 @@ export class PrismaExceptionFilter implements ExceptionFilter {
return response.status(HttpStatus.CONFLICT).json({
statusCode: HttpStatus.CONFLICT,
error: 'Conflict',
- message: `Unique constraint failed on: ${(exception.meta?.target as string[] | undefined)?.join(', ')}`,
+ message: uniqueViolationMessage(exception.meta?.target),
});
case 'P2003': // foreign key constraint violation
return response.status(HttpStatus.BAD_REQUEST).json({