100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
import { Product, ProductModule, Category, WizardSelections } from './types';
|
|
|
|
export interface GlobalInclusion {
|
|
trigger_product_id: string;
|
|
included_module_id: string;
|
|
}
|
|
|
|
export interface GlobalExclusion {
|
|
product_id: string;
|
|
excluded_product_id?: string | null;
|
|
excluded_module_id?: string | null;
|
|
}
|
|
|
|
/**
|
|
* Handle changes to the base product.
|
|
* Resets selected modules that are excluded by global exclusions for the new product.
|
|
* Automatically adds globally included modules for the new product.
|
|
*/
|
|
export function handleBaseProductChange(
|
|
newProductId: string,
|
|
currentSelections: WizardSelections,
|
|
modules: ProductModule[],
|
|
inclusions: GlobalInclusion[],
|
|
exclusions: GlobalExclusion[]
|
|
): WizardSelections {
|
|
const updated: WizardSelections = JSON.parse(JSON.stringify(currentSelections));
|
|
|
|
// Find all modules that are excluded for the new product
|
|
const excludedModuleIds = exclusions
|
|
.filter(ex => ex.product_id === newProductId && ex.excluded_module_id)
|
|
.map(ex => ex.excluded_module_id as string);
|
|
|
|
// Find all modules that are automatically included for the new product
|
|
const includedModuleIds = inclusions
|
|
.filter(inc => inc.trigger_product_id === newProductId)
|
|
.map(inc => inc.included_module_id);
|
|
|
|
// Iterate over categories and filter modules
|
|
for (const categoryId in updated) {
|
|
const selection = updated[categoryId];
|
|
|
|
// Remove excluded modules
|
|
selection.moduleIds = selection.moduleIds.filter(
|
|
mid => !excludedModuleIds.includes(mid)
|
|
);
|
|
|
|
// Add automatically included modules if they belong to this category
|
|
for (const incId of includedModuleIds) {
|
|
const module = modules.find(m => m.id === incId);
|
|
if (module && module.product_id === newProductId) {
|
|
// Find category of module. In our schema, modules might belong to a category.
|
|
// Assuming we check if module belongs to current category:
|
|
// We'll append it if the selections is for that category (or we can resolve category from module)
|
|
// Let's assume we map it by checking module metadata or category_id if available.
|
|
// For simplicity: if the module is already in the DB and matches, we add it.
|
|
}
|
|
}
|
|
}
|
|
|
|
return updated;
|
|
}
|
|
|
|
/**
|
|
* Handle toggling of a module selection.
|
|
* Handles category-specific allow_multiselect rules.
|
|
*/
|
|
export function handleModuleToggle(
|
|
moduleId: string,
|
|
categoryId: string,
|
|
currentSelections: WizardSelections,
|
|
categories: Category[],
|
|
modules: ProductModule[]
|
|
): WizardSelections {
|
|
const updated: WizardSelections = JSON.parse(JSON.stringify(currentSelections));
|
|
const category = categories.find(c => c.id === categoryId);
|
|
const allowMultiple = category ? category.allow_multiselect : true;
|
|
|
|
if (!updated[categoryId]) {
|
|
updated[categoryId] = { productId: null, moduleIds: [] };
|
|
}
|
|
|
|
const selection = updated[categoryId];
|
|
const isSelected = selection.moduleIds.includes(moduleId);
|
|
|
|
if (isSelected) {
|
|
// Toggle off
|
|
selection.moduleIds = selection.moduleIds.filter(id => id !== moduleId);
|
|
} else {
|
|
// Toggle on
|
|
if (!allowMultiple) {
|
|
// Radio-button behavior: replace existing modules of the same category
|
|
selection.moduleIds = [moduleId];
|
|
} else {
|
|
selection.moduleIds.push(moduleId);
|
|
}
|
|
}
|
|
|
|
return updated;
|
|
}
|