Performing logins, mobile cards, and other tasks
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/** Shared catalog of landing hero highlights (platform-wide, not per-category). */
|
||||
|
||||
export const BUSINESS_HIGHLIGHT_KEYS = [
|
||||
'customer_satisfaction',
|
||||
'professional_staff',
|
||||
'online_booking',
|
||||
'fair_pricing',
|
||||
'clean_space',
|
||||
'modern_equipment',
|
||||
'quality_materials',
|
||||
'fast_service',
|
||||
'experienced_team',
|
||||
'easy_access',
|
||||
'secure_payment',
|
||||
'friendly_support',
|
||||
] as const;
|
||||
|
||||
export type BusinessHighlightKey = (typeof BUSINESS_HIGHLIGHT_KEYS)[number];
|
||||
|
||||
export const DEFAULT_BUSINESS_HIGHLIGHT_KEYS: BusinessHighlightKey[] = [
|
||||
'customer_satisfaction',
|
||||
'professional_staff',
|
||||
'online_booking',
|
||||
];
|
||||
|
||||
const KEY_SET = new Set<string>(BUSINESS_HIGHLIGHT_KEYS);
|
||||
|
||||
export function isBusinessHighlightKey(value: string): value is BusinessHighlightKey {
|
||||
return KEY_SET.has(value);
|
||||
}
|
||||
|
||||
/** Keep at most 3 unique valid keys; empty/invalid input → empty array (caller may fall back to defaults). */
|
||||
export function sanitizeBusinessHighlightKeys(
|
||||
keys: string[] | null | undefined,
|
||||
): BusinessHighlightKey[] {
|
||||
if (!keys?.length) return [];
|
||||
const seen = new Set<string>();
|
||||
const result: BusinessHighlightKey[] = [];
|
||||
for (const raw of keys) {
|
||||
const key = String(raw).trim();
|
||||
if (!isBusinessHighlightKey(key) || seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
result.push(key);
|
||||
if (result.length >= 3) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddBusinessHeroHighlightKeys1789047600000 implements MigrationInterface {
|
||||
name = 'AddBusinessHeroHighlightKeys1789047600000';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "businesses"
|
||||
ADD COLUMN IF NOT EXISTS "hero_highlight_keys" jsonb
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "businesses"
|
||||
DROP COLUMN IF EXISTS "hero_highlight_keys"
|
||||
`);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,10 @@ export class BusinessEntity {
|
||||
@Column({ type: 'varchar', length: 20, default: 'first_booking' })
|
||||
promoDiscountMode!: 'first_booking' | 'always';
|
||||
|
||||
/** Up to 3 keys from the platform highlight catalog for the landing hero. */
|
||||
@Column({ name: 'hero_highlight_keys', type: 'jsonb', nullable: true })
|
||||
heroHighlightKeys!: string[] | null;
|
||||
|
||||
@Column({ name: 'logo_light_url', type: 'varchar', length: 500, nullable: true })
|
||||
logoLightUrl!: string | null;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import { AssignBusinessOwnerDto } from './dto/assign-business-owner.dto';
|
||||
import { CreateBusinessDto } from './dto/create-business.dto';
|
||||
import { SetAvailabilityDto } from './dto/set-availability.dto';
|
||||
import { UpdateBusinessDto } from './dto/update-business.dto';
|
||||
import { sanitizeBusinessHighlightKeys } from '../../common/constants/business-highlights';
|
||||
|
||||
type FindAllFilters = {
|
||||
categoryId?: string;
|
||||
@@ -165,6 +166,11 @@ export class BusinessesService {
|
||||
|
||||
Object.assign(business, payload);
|
||||
|
||||
if (payload.heroHighlightKeys !== undefined) {
|
||||
const sanitized = sanitizeBusinessHighlightKeys(payload.heroHighlightKeys);
|
||||
business.heroHighlightKeys = sanitized.length ? sanitized : null;
|
||||
}
|
||||
|
||||
if (business.promoDiscountEnabled) {
|
||||
if (
|
||||
!business.promoDiscountPercent ||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import {
|
||||
IsArray,
|
||||
ArrayMaxSize,
|
||||
IsBoolean,
|
||||
IsInt,
|
||||
IsLatitude,
|
||||
@@ -179,4 +181,15 @@ export class UpdateBusinessDto {
|
||||
@IsString()
|
||||
@Matches(/^(first_booking|always)$/)
|
||||
promoDiscountMode?: 'first_booking' | 'always';
|
||||
|
||||
@ApiPropertyOptional({
|
||||
type: [String],
|
||||
example: ['customer_satisfaction', 'professional_staff', 'online_booking'],
|
||||
description: 'Up to 3 highlight keys from the platform catalog for the landing hero',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ArrayMaxSize(3)
|
||||
@IsString({ each: true })
|
||||
heroHighlightKeys?: string[] | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user