Accept custom color hexes when saving category color variations.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
00d0284454
commit
a1e73d1c9e
@@ -131,6 +131,7 @@ export class CategoryTechnicalFormAiService {
|
||||
- multi_value یک لیست تکراری از مقادیر متنی آزاد است (بدون گزینه) برای مقادیر کوتاه چندتایی.
|
||||
- text برای مقادیر کوتاه (ابعاد، وزن، سال مدل).
|
||||
- textarea برای مشخصات طولانیتر (ویژگیها، دستورالعمل نگهداری).
|
||||
- اگر برای این دسته مناسب است، فیلدهای «ابعاد» و «وزن» را بهصورت text اضافه کن (واحد متریک رایج ایران را در برچسب بیاور، مثلاً سانتیمتر / کیلوگرم). اگر برای دسته بیمعناست، اضافه نکن.
|
||||
- مشخصات مهم خریدار را الزامی علامت بزن.
|
||||
- برچسبها باید یکتا و خوانا باشند.
|
||||
- همیشه برچسبها و گزینهها را به فارسی بنویس.
|
||||
|
||||
@@ -54,6 +54,31 @@ function uniqueSlug(base: string, used: Set<string>, fallbackIndex: number): str
|
||||
return next;
|
||||
}
|
||||
|
||||
function normalizeHex(value: string | null | undefined): string | null {
|
||||
if (value == null) return null;
|
||||
const trimmed = value.trim();
|
||||
if (!isHexColor(trimmed)) return null;
|
||||
return trimmed.toUpperCase();
|
||||
}
|
||||
|
||||
/** Map value labels → provided hex (later entries win for duplicate labels). */
|
||||
function buildColorHexByLabel(
|
||||
values: string[],
|
||||
colorHexes: (string | null)[] | undefined,
|
||||
): Map<string, string> {
|
||||
const map = new Map<string, string>();
|
||||
if (!colorHexes?.length) return map;
|
||||
|
||||
values.forEach((raw, index) => {
|
||||
const label = raw.trim();
|
||||
if (!label) return;
|
||||
const hex = normalizeHex(colorHexes[index] ?? null);
|
||||
if (hex) map.set(label, hex);
|
||||
});
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
type ExistingVariation = {
|
||||
id: bigint;
|
||||
name: string;
|
||||
@@ -126,6 +151,10 @@ export class CategoryVariationsService {
|
||||
const uniqueValues = [
|
||||
...new Set(variation.values.map((v) => v.trim()).filter(Boolean)),
|
||||
];
|
||||
const hexByLabel = buildColorHexByLabel(
|
||||
variation.values,
|
||||
variation.colorHexes,
|
||||
);
|
||||
|
||||
if (current) {
|
||||
matchedExistingIds.add(current.id);
|
||||
@@ -137,7 +166,7 @@ export class CategoryVariationsService {
|
||||
sortOrder: index,
|
||||
},
|
||||
});
|
||||
await this.syncOptions(tx, current, variation.type, uniqueValues);
|
||||
await this.syncOptions(tx, current, variation.type, uniqueValues, hexByLabel);
|
||||
} else {
|
||||
const created = await tx.categoryVariation.create({
|
||||
data: {
|
||||
@@ -148,7 +177,13 @@ export class CategoryVariationsService {
|
||||
sortOrder: index,
|
||||
},
|
||||
});
|
||||
await this.createOptions(tx, created.id, variation.type, uniqueValues);
|
||||
await this.createOptions(
|
||||
tx,
|
||||
created.id,
|
||||
variation.type,
|
||||
uniqueValues,
|
||||
hexByLabel,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +238,7 @@ export class CategoryVariationsService {
|
||||
current: ExistingVariation,
|
||||
type: CategoryVariationInputDto['type'],
|
||||
labels: string[],
|
||||
hexByLabel: Map<string, string> = new Map(),
|
||||
) {
|
||||
const usedSlugs = new Set<string>();
|
||||
const matchedOptionIds = new Set<bigint>();
|
||||
@@ -215,7 +251,8 @@ export class CategoryVariationsService {
|
||||
|
||||
const colorHex =
|
||||
type === 'color'
|
||||
? resolveColorHex(label) ??
|
||||
? hexByLabel.get(label) ??
|
||||
resolveColorHex(label) ??
|
||||
existingOption?.colorHex ??
|
||||
(existingOption && isHexColor(existingOption.value)
|
||||
? existingOption.value.trim()
|
||||
@@ -270,6 +307,7 @@ export class CategoryVariationsService {
|
||||
variationId: bigint,
|
||||
type: CategoryVariationInputDto['type'],
|
||||
labels: string[],
|
||||
hexByLabel: Map<string, string> = new Map(),
|
||||
) {
|
||||
const usedSlugs = new Set<string>();
|
||||
await tx.categoryVariationOption.createMany({
|
||||
@@ -277,7 +315,10 @@ export class CategoryVariationsService {
|
||||
variationId,
|
||||
label,
|
||||
value: uniqueSlug(slugifyValue(label), usedSlugs, optionIndex + 1),
|
||||
colorHex: type === 'color' ? resolveColorHex(label) : null,
|
||||
colorHex:
|
||||
type === 'color'
|
||||
? hexByLabel.get(label) ?? resolveColorHex(label)
|
||||
: null,
|
||||
sortOrder: optionIndex,
|
||||
})),
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ArrayMinSize,
|
||||
IsArray,
|
||||
IsIn,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MinLength,
|
||||
ValidateNested,
|
||||
@@ -21,6 +22,11 @@ export class CategoryVariationInputDto {
|
||||
@ArrayMinSize(1)
|
||||
@IsString({ each: true })
|
||||
values!: string[];
|
||||
|
||||
/** Optional parallel list of hex colors for `color` variations (same order as values). */
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
colorHexes?: (string | null)[];
|
||||
}
|
||||
|
||||
export class ReplaceCategoryVariationsDto {
|
||||
|
||||
Reference in New Issue
Block a user