w-funnel/src/lib/funnel/variants.ts
dev.daminik00 6c50d05123 ab
2025-10-21 01:27:08 +02:00

83 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { matchesNavigationConditions, type UnleashChecker } from "./navigation";
import type {
FunnelAnswers,
ScreenDefinition,
ScreenVariantDefinition,
} from "./types";
function cloneScreen<T>(screen: T): T {
if (typeof globalThis.structuredClone === "function") {
return globalThis.structuredClone(screen);
}
return JSON.parse(JSON.stringify(screen)) as T;
}
function isPlainObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function deepMerge<T>(target: T, source: Partial<T> | undefined): T {
if (!source) {
return target;
}
const result: T = Array.isArray(target)
? ([...target] as unknown as T)
: ({ ...(target as Record<string, unknown>) } as T);
for (const key of Object.keys(source) as (keyof T)[]) {
const sourceValue = source[key];
if (sourceValue === undefined) {
continue;
}
const targetValue = (result as Record<string, unknown>)[key as unknown as string];
if (isPlainObject(sourceValue)) {
const baseValue = isPlainObject(targetValue) ? targetValue : {};
(result as Record<string, unknown>)[key as unknown as string] = deepMerge(
baseValue,
sourceValue as Record<string, unknown>
) as unknown as T[keyof T];
continue;
}
(result as Record<string, unknown>)[key as unknown as string] = sourceValue as unknown as T[keyof T];
}
return result;
}
function applyScreenOverrides<T extends ScreenDefinition>(
screen: T,
overrides: ScreenVariantDefinition<T>["overrides"]
): T {
const cloned = cloneScreen(screen);
// DeepPartial совместим с deepMerge, так как deepMerge обрабатывает вложенные объекты
return deepMerge(cloned, overrides as unknown as Partial<T>);
}
export function resolveScreenVariant<T extends ScreenDefinition>(
screen: T,
answers: FunnelAnswers,
allScreens?: ScreenDefinition[],
unleashChecker?: UnleashChecker
): T {
const variants = (screen as T & { variants?: ScreenVariantDefinition<T>[] }).variants;
if (!variants || variants.length === 0) {
return screen;
}
for (const variant of variants) {
// Передаем allScreens и unleashChecker для правильной проверки условий
if (matchesNavigationConditions(variant.conditions, answers, allScreens, unleashChecker)) {
return applyScreenOverrides(screen, variant.overrides);
}
}
return screen;
}