Add Khanegi uiVariant modular/newTheme with get_user payload split.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
-- Khanegi appearance family: modular (default) vs newTheme.
|
||||||
|
CREATE TYPE "KhanegiUiVariant" AS ENUM ('modular', 'newTheme');
|
||||||
|
|
||||||
|
ALTER TABLE "tenants"
|
||||||
|
ADD COLUMN "ui_variant" "KhanegiUiVariant" NOT NULL DEFAULT 'modular';
|
||||||
|
|
||||||
|
-- Pilot already on new theme
|
||||||
|
UPDATE "tenants"
|
||||||
|
SET "ui_variant" = 'newTheme'
|
||||||
|
WHERE "product" = 'khanegi'
|
||||||
|
AND (
|
||||||
|
"domain" = 'app.aygingold.ir'
|
||||||
|
OR ("domains"::text ILIKE '%app.aygingold.ir%')
|
||||||
|
);
|
||||||
@@ -13,6 +13,12 @@ enum ProductType {
|
|||||||
khanegi
|
khanegi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Khanegi front-end appearance family (ignored for hamkar).
|
||||||
|
enum KhanegiUiVariant {
|
||||||
|
modular
|
||||||
|
newTheme
|
||||||
|
}
|
||||||
|
|
||||||
enum UserRole {
|
enum UserRole {
|
||||||
super_admin
|
super_admin
|
||||||
viewer
|
viewer
|
||||||
@@ -63,6 +69,8 @@ model Tenant {
|
|||||||
smsSyncedAt DateTime? @map("sms_synced_at")
|
smsSyncedAt DateTime? @map("sms_synced_at")
|
||||||
/// Full Khanegi UI JSON (theme, navigation, pages). Hamkar: unused for now.
|
/// Full Khanegi UI JSON (theme, navigation, pages). Hamkar: unused for now.
|
||||||
appUiConfig Json? @map("app_ui_config")
|
appUiConfig Json? @map("app_ui_config")
|
||||||
|
/// Khanegi only: which appearance editor / get_user payload shape to use.
|
||||||
|
uiVariant KhanegiUiVariant @default(modular) @map("ui_variant")
|
||||||
/// Client cache-bust / force-reload signal for this sold version (GET /get_version).
|
/// Client cache-bust / force-reload signal for this sold version (GET /get_version).
|
||||||
appVersion String @default("1") @map("app_version")
|
appVersion String @default("1") @map("app_version")
|
||||||
isActive Boolean @default(true) @map("is_active")
|
isActive Boolean @default(true) @map("is_active")
|
||||||
|
|||||||
@@ -43,19 +43,23 @@ export class GetUserService {
|
|||||||
? registryMode
|
? registryMode
|
||||||
: 'dynamicMode'
|
: 'dynamicMode'
|
||||||
|
|
||||||
|
const isKhanegi = tenant.product === 'khanegi';
|
||||||
|
const uiVariant =
|
||||||
|
isKhanegi && tenant.uiVariant === 'newTheme' ? 'newTheme' : 'modular';
|
||||||
|
|
||||||
const color =
|
const color =
|
||||||
hamkarBrand?.primaryColor ||
|
hamkarBrand?.primaryColor ||
|
||||||
khanegiColors?.primary ||
|
(uiVariant === 'newTheme' ? khanegiColors?.primary : null) ||
|
||||||
tenant.primaryColor ||
|
tenant.primaryColor ||
|
||||||
null
|
null
|
||||||
const secondary =
|
const secondary =
|
||||||
hamkarBrand?.secondaryColor ||
|
hamkarBrand?.secondaryColor ||
|
||||||
khanegiColors?.secondary ||
|
(uiVariant === 'newTheme' ? khanegiColors?.secondary : null) ||
|
||||||
tenant.secondaryColor ||
|
tenant.secondaryColor ||
|
||||||
null
|
null
|
||||||
const background =
|
const background =
|
||||||
hamkarBrand?.backgroundColor ||
|
hamkarBrand?.backgroundColor ||
|
||||||
khanegiColors?.background ||
|
(uiVariant === 'newTheme' ? khanegiColors?.background : null) ||
|
||||||
tenant.backgroundColor ||
|
tenant.backgroundColor ||
|
||||||
null
|
null
|
||||||
|
|
||||||
@@ -75,8 +79,12 @@ export class GetUserService {
|
|||||||
product: tenant.product,
|
product: tenant.product,
|
||||||
theme: themeMode,
|
theme: themeMode,
|
||||||
mode: themeMode,
|
mode: themeMode,
|
||||||
|
/** Khanegi front-end family for consumers */
|
||||||
|
ui_variant: isKhanegi ? uiVariant : undefined,
|
||||||
app_ui_config:
|
app_ui_config:
|
||||||
tenant.product === 'khanegi' ? this.stripKhanegiSaMeta(ui) : undefined,
|
isKhanegi && uiVariant === 'newTheme'
|
||||||
|
? this.stripKhanegiSaMeta(ui)
|
||||||
|
: undefined,
|
||||||
/** Laravel-compatible overlay; Hamkar merges only when present */
|
/** Laravel-compatible overlay; Hamkar merges only when present */
|
||||||
ui_settings: uiSettings.length ? uiSettings : undefined,
|
ui_settings: uiSettings.length ? uiSettings : undefined,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
MaxLength,
|
MaxLength,
|
||||||
MinLength,
|
MinLength,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { ProductType } from '@prisma/client';
|
import { KhanegiUiVariant, ProductType } from '@prisma/client';
|
||||||
|
|
||||||
export class CreateTenantDto {
|
export class CreateTenantDto {
|
||||||
@IsEnum(ProductType)
|
@IsEnum(ProductType)
|
||||||
@@ -80,6 +80,11 @@ export class CreateTenantDto {
|
|||||||
@IsObject()
|
@IsObject()
|
||||||
appUiConfig?: Record<string, unknown>;
|
appUiConfig?: Record<string, unknown>;
|
||||||
|
|
||||||
|
/** Khanegi only; default modular. */
|
||||||
|
@IsOptional()
|
||||||
|
@IsEnum(KhanegiUiVariant)
|
||||||
|
uiVariant?: KhanegiUiVariant;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@MaxLength(64)
|
@MaxLength(64)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export class TenantsService {
|
|||||||
appUrl: true,
|
appUrl: true,
|
||||||
adminUrl: true,
|
adminUrl: true,
|
||||||
appUiConfig: true,
|
appUiConfig: true,
|
||||||
|
uiVariant: true,
|
||||||
appVersion: true,
|
appVersion: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
notes: true,
|
notes: true,
|
||||||
@@ -81,6 +82,10 @@ export class TenantsService {
|
|||||||
appUiConfig: dto.appUiConfig
|
appUiConfig: dto.appUiConfig
|
||||||
? (dto.appUiConfig as Prisma.InputJsonValue)
|
? (dto.appUiConfig as Prisma.InputJsonValue)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
uiVariant:
|
||||||
|
dto.product === ProductType.khanegi
|
||||||
|
? dto.uiVariant ?? 'modular'
|
||||||
|
: 'modular',
|
||||||
appVersion: dto.appVersion?.trim() || '1',
|
appVersion: dto.appVersion?.trim() || '1',
|
||||||
isActive: dto.isActive ?? true,
|
isActive: dto.isActive ?? true,
|
||||||
notes: dto.notes,
|
notes: dto.notes,
|
||||||
@@ -144,6 +149,7 @@ export class TenantsService {
|
|||||||
...(dto.appUiConfig !== undefined && {
|
...(dto.appUiConfig !== undefined && {
|
||||||
appUiConfig: dto.appUiConfig as Prisma.InputJsonValue,
|
appUiConfig: dto.appUiConfig as Prisma.InputJsonValue,
|
||||||
}),
|
}),
|
||||||
|
...(dto.uiVariant !== undefined && { uiVariant: dto.uiVariant }),
|
||||||
...(dto.appVersion !== undefined && {
|
...(dto.appVersion !== undefined && {
|
||||||
appVersion: dto.appVersion.trim() || '1',
|
appVersion: dto.appVersion.trim() || '1',
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user