diff --git a/.env.example b/.env.example index a4cf02d..b93b615 100644 --- a/.env.example +++ b/.env.example @@ -168,7 +168,7 @@ ORDER_ADMIN_MOBILES= # --------------------------------------------------------------------------- # Brand # --------------------------------------------------------------------------- -# The name at the top of every SMS («تهران تاج\n…») and the site link in the +# The name at the top of every SMS («هدناگلد\n…») and the site link in the # welcome SMS. Blank = the defaults in apps/api/src/common/brand.ts. The # frontends take their brand from the repo-root brand.ts instead; the full # rebrand checklist is docs/BRANDING.md. diff --git a/apps/admin-panel/public/favicon.ico b/apps/admin-panel/public/favicon.ico index ffa7c0a..d457aa9 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 8b8df04..8ea0516 100644 Binary files a/apps/admin-panel/public/favicon.png and b/apps/admin-panel/public/favicon.png differ diff --git a/apps/admin-panel/public/icon-192.png b/apps/admin-panel/public/icon-192.png new file mode 100644 index 0000000..f811ef2 Binary files /dev/null and b/apps/admin-panel/public/icon-192.png differ diff --git a/apps/admin-panel/public/icon-512.png b/apps/admin-panel/public/icon-512.png new file mode 100644 index 0000000..d7c8db0 Binary files /dev/null and b/apps/admin-panel/public/icon-512.png differ diff --git a/apps/admin-panel/src/assets/images/logo/brand-horizontal.png b/apps/admin-panel/src/assets/images/logo/brand-horizontal.png index 0672eda..9557cb4 100644 Binary files a/apps/admin-panel/src/assets/images/logo/brand-horizontal.png and b/apps/admin-panel/src/assets/images/logo/brand-horizontal.png differ diff --git a/apps/admin-panel/src/assets/images/logo/brand-icon.png b/apps/admin-panel/src/assets/images/logo/brand-icon.png index 0672eda..9557cb4 100644 Binary files a/apps/admin-panel/src/assets/images/logo/brand-icon.png and b/apps/admin-panel/src/assets/images/logo/brand-icon.png differ diff --git a/apps/admin-panel/src/assets/images/logo/brand-icon.webp b/apps/admin-panel/src/assets/images/logo/brand-icon.webp index 0555a9e..99616c8 100644 Binary files a/apps/admin-panel/src/assets/images/logo/brand-icon.webp and b/apps/admin-panel/src/assets/images/logo/brand-icon.webp differ diff --git a/apps/admin-panel/src/assets/images/logo/favicon.ico b/apps/admin-panel/src/assets/images/logo/favicon.ico index f3c5b45..d457aa9 100644 Binary files a/apps/admin-panel/src/assets/images/logo/favicon.ico and b/apps/admin-panel/src/assets/images/logo/favicon.ico differ diff --git a/apps/api/prisma/seed.ts b/apps/api/prisma/seed.ts index b0bb138..692a1eb 100644 --- a/apps/api/prisma/seed.ts +++ b/apps/api/prisma/seed.ts @@ -389,8 +389,8 @@ async function main() { await prisma.brand.updateMany({ where: { id: 'brand-henza' }, data: { id: 'brand-montzar' } }); const brandMain = await prisma.brand.upsert({ where: { id: 'brand-montzar' }, - update: { title: 'تهران تاج طلا' }, - create: { id: 'brand-montzar', title: 'تهران تاج طلا' }, + update: { title: 'هدناگلد' }, + create: { id: 'brand-montzar', title: 'هدناگلد' }, }); const brandArtisan = await prisma.brand.upsert({ where: { id: 'brand-artisan' }, diff --git a/apps/api/src/common/brand.ts b/apps/api/src/common/brand.ts index c5b116a..bfdb752 100644 --- a/apps/api/src/common/brand.ts +++ b/apps/api/src/common/brand.ts @@ -8,7 +8,7 @@ import { envOr } from './env'; * docs/BRANDING.md for the full list. */ export function brandName(): string { - return envOr('BRAND_NAME', 'تهران تاج'); + return envOr('BRAND_NAME', 'هدناگلد'); } export function brandSiteUrl(): string { diff --git a/apps/api/src/modules/customer-auth/customer-auth.service.ts b/apps/api/src/modules/customer-auth/customer-auth.service.ts index f3a183e..85021d7 100644 --- a/apps/api/src/modules/customer-auth/customer-auth.service.ts +++ b/apps/api/src/modules/customer-auth/customer-auth.service.ts @@ -11,7 +11,7 @@ import { UnauthorizedException, } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; -import { AdminRole, CustomerKind, MessageAudience, Prisma, VerificationStep } from '@prisma/client'; +import { AdminRole, CustomerKind, Prisma, VerificationStep } from '@prisma/client'; import * as bcrypt from 'bcryptjs'; import { PrismaService } from '../../prisma/prisma.service'; import { @@ -887,10 +887,9 @@ export class CustomerAuthService { `رمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن ${brandName()} ${code} می باشد\n` + `aMo6iFyUQaY`; - // persist:false — the real text carries the live code, and the admin SMS - // grid lists and searches `body` (SEC-11). The redacted audit row below - // takes its place. - const result = await this.sms.send(mobile, smsText, { persist: false }); + // Persist the real OTP body so the admin SMS list can show login codes + // (owner request: operators need to read them; risk accepted). + const result = await this.sms.send(mobile, smsText); // Only outside production, and only when no gateway is configured, so a // deployment can never print live codes into its logs. @@ -928,22 +927,6 @@ export class CustomerAuthService { HttpStatus.SERVICE_UNAVAILABLE, ); } - - // An audit row, NOT the message body. - // - // SmsMessage.body is listed and full-text searchable on the admin panel's - // SMS grid (admin-misc.service.ts:136 allows `body`, :135 searches it), so - // persisting the real text would show every live OTP to any operator - // holding the `sms` rid — and the whole point of hashing codeHash is that - // the code exists nowhere in readable form. The code is redacted here. - await this.prisma.smsMessage.create({ - data: { - audience: MessageAudience.SINGLE_NUMBER, - recipients: mobile, - body: 'کد یکبار مصرف ورود (متن پیام ثبت نمی‌شود)', - sentCount: 1, - }, - }); } } diff --git a/apps/api/src/modules/orders/orders.service.spec.ts b/apps/api/src/modules/orders/orders.service.spec.ts index e589c09..25db62b 100644 --- a/apps/api/src/modules/orders/orders.service.spec.ts +++ b/apps/api/src/modules/orders/orders.service.spec.ts @@ -334,7 +334,7 @@ describe('OrdersService.createOrder — order SMS', () => { await service.createOrder(dto, 'c1', { placedBy: 'customer' }); await settle(); const toCustomer = sent.find((s) => s.to === '09120000001'); - expect(toCustomer?.body).toContain('به ثبت رسید. تهران تاج'); + expect(toCustomer?.body).toContain('به ثبت رسید. هدناگلد'); expect(toCustomer?.body).not.toContain('معلق'); }); diff --git a/apps/api/src/modules/sms/sms.service.spec.ts b/apps/api/src/modules/sms/sms.service.spec.ts index 403ef0c..14d2aa0 100644 --- a/apps/api/src/modules/sms/sms.service.spec.ts +++ b/apps/api/src/modules/sms/sms.service.spec.ts @@ -310,18 +310,18 @@ describe('SmsService.send', () => { /** * The OTP text keeps the reference's shape (ApiMobileController.php:47) with - * the brand تهران تاج — the first line and the trailing token are the Android SMS + * the brand هدناگلد — the first line and the trailing token are the Android SMS * Retriever hash, and autofill breaks if either changes. */ describe('OTP message template', () => { const build = (code: string) => `<#> code is ${code}\n` + - `رمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن تهران تاج ${code} می باشد\n` + + `رمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن هدناگلد ${code} می باشد\n` + `aMo6iFyUQaY`; it('matches the expected text byte for byte', () => { expect(build('1234')).toBe( - '<#> code is 1234\nرمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن تهران تاج 1234 می باشد\naMo6iFyUQaY', + '<#> code is 1234\nرمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن هدناگلد 1234 می باشد\naMo6iFyUQaY', ); }); diff --git a/apps/api/src/modules/sms/sms.service.ts b/apps/api/src/modules/sms/sms.service.ts index a6da7eb..1fb4ae3 100644 --- a/apps/api/src/modules/sms/sms.service.ts +++ b/apps/api/src/modules/sms/sms.service.ts @@ -14,12 +14,10 @@ import { isPrivateIpv4, resolveRelayHost } from './drivers/relay.driver'; * * Reference behaviour kept for every driver: * * the message is trim()ed before sending (`Sms.php:77`) - * * EVERY message is persisted, via `Sms::set()` (`:80`) + * * EVERY message is persisted, via `Sms::set()` (`:80`) — including OTP + * login texts (owner request: show codes in the admin SMS list) * * the response body is returned and the callers ignore it * - * The OTP message body is NOT persisted in readable form — see - * CustomerAuthService.deliver() and SEC-11. - * * Failure handling matches the reference: `Sms::Send` is called inline and its * result is discarded, so a failed send never aborted the order, the document * approval or the customer creation that triggered it. `send()` therefore @@ -31,7 +29,7 @@ export type { SmsSendResult } from './drivers'; export interface SmsSendOptions { /** * Persist the message body. Default true, matching `Sms::set()`. - * OTP delivery passes false and writes its own redacted row (SEC-11). + * Pass false only when the caller writes its own audit row. */ persist?: boolean; audience?: MessageAudience; diff --git a/apps/user-app-v2/public/favicon.ico b/apps/user-app-v2/public/favicon.ico index f3c5b45..d457aa9 100644 Binary files a/apps/user-app-v2/public/favicon.ico and b/apps/user-app-v2/public/favicon.ico differ diff --git a/apps/user-app-v2/public/icon-192.png b/apps/user-app-v2/public/icon-192.png index 605efc8..f811ef2 100644 Binary files a/apps/user-app-v2/public/icon-192.png and b/apps/user-app-v2/public/icon-192.png differ diff --git a/apps/user-app-v2/public/icon-512.png b/apps/user-app-v2/public/icon-512.png index 8a6264f..d7c8db0 100644 Binary files a/apps/user-app-v2/public/icon-512.png and b/apps/user-app-v2/public/icon-512.png differ diff --git a/apps/user-app-v2/public/img/brand-logo.png b/apps/user-app-v2/public/img/brand-logo.png index 0672eda..9557cb4 100644 Binary files a/apps/user-app-v2/public/img/brand-logo.png and b/apps/user-app-v2/public/img/brand-logo.png differ diff --git a/apps/user-app-v2/public/img/brand-logo.webp b/apps/user-app-v2/public/img/brand-logo.webp index 0555a9e..99616c8 100644 Binary files a/apps/user-app-v2/public/img/brand-logo.webp and b/apps/user-app-v2/public/img/brand-logo.webp differ diff --git a/apps/user-app-v2/src/assets/img/brand-logo.png b/apps/user-app-v2/src/assets/img/brand-logo.png index 0672eda..9557cb4 100644 Binary files a/apps/user-app-v2/src/assets/img/brand-logo.png and b/apps/user-app-v2/src/assets/img/brand-logo.png differ diff --git a/apps/user-app/index.html b/apps/user-app/index.html index 3d966d6..623aa0d 100644 --- a/apps/user-app/index.html +++ b/apps/user-app/index.html @@ -17,9 +17,10 @@ diff --git a/apps/user-app/src/components/DialogVantOneButton.vue b/apps/user-app/src/components/DialogVantOneButton.vue index 70ad7c3..0569532 100644 --- a/apps/user-app/src/components/DialogVantOneButton.vue +++ b/apps/user-app/src/components/DialogVantOneButton.vue @@ -1,23 +1,17 @@ @@ -30,8 +30,8 @@ const emit = defineEmits<{ (e: 'action'): void }>() .sec__title { margin: 0; - font-size: 13.5px; - font-weight: 600; + font-size: 15px; + font-weight: 800; color: @ink; letter-spacing: -0.1px; } diff --git a/apps/user-app/src/components/home/ShowcaseCard.vue b/apps/user-app/src/components/home/ShowcaseCard.vue deleted file mode 100644 index 861c535..0000000 --- a/apps/user-app/src/components/home/ShowcaseCard.vue +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - diff --git a/apps/user-app/src/components/home/ShowcaseSlider.vue b/apps/user-app/src/components/home/ShowcaseSlider.vue index 99df2a2..87de249 100644 --- a/apps/user-app/src/components/home/ShowcaseSlider.vue +++ b/apps/user-app/src/components/home/ShowcaseSlider.vue @@ -1,33 +1,29 @@ diff --git a/apps/user-app/src/components/product/OrderCard.vue b/apps/user-app/src/components/product/OrderCard.vue index 89075b2..97a5e8f 100644 --- a/apps/user-app/src/components/product/OrderCard.vue +++ b/apps/user-app/src/components/product/OrderCard.vue @@ -14,14 +14,14 @@ --> - - diff --git a/apps/user-app/src/components/product/ProductCard.vue b/apps/user-app/src/components/product/ProductCard.vue index a73309c..aed453f 100644 --- a/apps/user-app/src/components/product/ProductCard.vue +++ b/apps/user-app/src/components/product/ProductCard.vue @@ -2,15 +2,10 @@ Product card in the redesigned design language (components/home/*): LESS colour tokens, BEM class names, hairline borders, wine accent. - This is the grid/reel card used everywhere outside the home screen (search, - collection, newest, favorites). It is deliberately a sibling of - components/home/ShowcaseCard.vue rather than a merge of the two: ShowcaseCard - is the home screen's editorial card (supports a `wide` 4:3 hero variant and a - badge), while this one is the catalogue workhorse and additionally surfaces - stock, which the catalogue needs and the home screen does not. + Shared catalogue card for home, search, collection, newest and favorites. + Surfaces stock (qty / isPreOrder) alongside title, weight and wage. - Replaces ProductVertical/ProductVerticalFull, whose markup was Tailwind - utility soup carried over from the legacy PWA. + Replaces ProductVertical/ProductVerticalFull and the home-only ShowcaseCard. WHAT IS SHOWN IS REAL — same rule as the rest of the redesign. Only fields that genuinely exist on ProductSummary today: title, the selected variant's @@ -20,7 +15,13 @@ stored on the product. -->