410 lines
15 KiB
TypeScript
410 lines
15 KiB
TypeScript
/**
|
|
* Demo repair catalog used when the live API returns no brands/series/models.
|
|
* Lets you verify the storefront service wizard without admin seed data.
|
|
*/
|
|
|
|
export type DemoBrand = { brand_id: string; name: string };
|
|
export type DemoSeries = { series_id: string; name: string; brand_id: string };
|
|
export type DemoModel = {
|
|
model_id: string;
|
|
name: string;
|
|
series_id: string;
|
|
release_year?: number;
|
|
};
|
|
export type DemoVariant = {
|
|
variant_id: string;
|
|
name: string;
|
|
price: number;
|
|
warranty_days: number;
|
|
duration_minutes: number;
|
|
};
|
|
export type DemoCategory = {
|
|
service_type_id: string;
|
|
repair_service_id?: string;
|
|
category_name: string;
|
|
description?: string;
|
|
variants: DemoVariant[];
|
|
};
|
|
|
|
const DEVICE_TYPES = ['mobile', 'laptop', 'tablet', 'smartwatch'] as const;
|
|
|
|
function normalizeDeviceType(deviceType?: string): string {
|
|
const key = (deviceType || 'mobile').toLowerCase().trim();
|
|
if ((DEVICE_TYPES as readonly string[]).includes(key)) return key;
|
|
if (key.includes('watch')) return 'smartwatch';
|
|
if (key.includes('laptop') || key.includes('computer')) return 'laptop';
|
|
if (key.includes('tablet') || key.includes('ipad')) return 'tablet';
|
|
return 'mobile';
|
|
}
|
|
|
|
const DEMO_BRANDS: Record<string, DemoBrand[]> = {
|
|
mobile: [
|
|
{ brand_id: 'demo-brand-apple-mobile', name: 'Apple' },
|
|
{ brand_id: 'demo-brand-samsung-mobile', name: 'Samsung' },
|
|
{ brand_id: 'demo-brand-oneplus-mobile', name: 'OnePlus' },
|
|
{ brand_id: 'demo-brand-xiaomi-mobile', name: 'Xiaomi' },
|
|
],
|
|
laptop: [
|
|
{ brand_id: 'demo-brand-apple-laptop', name: 'Apple' },
|
|
{ brand_id: 'demo-brand-dell-laptop', name: 'Dell' },
|
|
{ brand_id: 'demo-brand-hp-laptop', name: 'HP' },
|
|
{ brand_id: 'demo-brand-lenovo-laptop', name: 'Lenovo' },
|
|
],
|
|
tablet: [
|
|
{ brand_id: 'demo-brand-apple-tablet', name: 'Apple' },
|
|
{ brand_id: 'demo-brand-samsung-tablet', name: 'Samsung' },
|
|
{ brand_id: 'demo-brand-lenovo-tablet', name: 'Lenovo' },
|
|
],
|
|
smartwatch: [
|
|
{ brand_id: 'demo-brand-apple-watch', name: 'Apple' },
|
|
{ brand_id: 'demo-brand-samsung-watch', name: 'Samsung' },
|
|
{ brand_id: 'demo-brand-noise-watch', name: 'Noise' },
|
|
{ brand_id: 'demo-brand-boat-watch', name: 'boAt' },
|
|
],
|
|
};
|
|
|
|
const DEMO_SERIES: DemoSeries[] = [
|
|
// Mobile
|
|
{ series_id: 'demo-series-iphone-15', name: 'iPhone 15 Series', brand_id: 'demo-brand-apple-mobile' },
|
|
{ series_id: 'demo-series-iphone-14', name: 'iPhone 14 Series', brand_id: 'demo-brand-apple-mobile' },
|
|
{ series_id: 'demo-series-s24', name: 'Galaxy S24 Series', brand_id: 'demo-brand-samsung-mobile' },
|
|
{ series_id: 'demo-series-a5x', name: 'Galaxy A Series', brand_id: 'demo-brand-samsung-mobile' },
|
|
{ series_id: 'demo-series-op12', name: 'OnePlus 12 Series', brand_id: 'demo-brand-oneplus-mobile' },
|
|
{ series_id: 'demo-series-redmi-note', name: 'Redmi Note Series', brand_id: 'demo-brand-xiaomi-mobile' },
|
|
// Laptop
|
|
{ series_id: 'demo-series-macbook-air', name: 'MacBook Air', brand_id: 'demo-brand-apple-laptop' },
|
|
{ series_id: 'demo-series-xps', name: 'XPS Series', brand_id: 'demo-brand-dell-laptop' },
|
|
{ series_id: 'demo-series-pavilion', name: 'Pavilion Series', brand_id: 'demo-brand-hp-laptop' },
|
|
{ series_id: 'demo-series-thinkpad', name: 'ThinkPad Series', brand_id: 'demo-brand-lenovo-laptop' },
|
|
// Tablet
|
|
{ series_id: 'demo-series-ipad-air', name: 'iPad Air', brand_id: 'demo-brand-apple-tablet' },
|
|
{ series_id: 'demo-series-tab-s9', name: 'Galaxy Tab S9', brand_id: 'demo-brand-samsung-tablet' },
|
|
{ series_id: 'demo-series-tab-m', name: 'Tab M Series', brand_id: 'demo-brand-lenovo-tablet' },
|
|
// Smartwatch
|
|
{ series_id: 'demo-series-watch-ultra', name: 'Apple Watch Ultra', brand_id: 'demo-brand-apple-watch' },
|
|
{ series_id: 'demo-series-watch-se', name: 'Apple Watch SE', brand_id: 'demo-brand-apple-watch' },
|
|
{ series_id: 'demo-series-galaxy-watch', name: 'Galaxy Watch', brand_id: 'demo-brand-samsung-watch' },
|
|
{ series_id: 'demo-series-noise-colorfit', name: 'ColorFit Series', brand_id: 'demo-brand-noise-watch' },
|
|
{ series_id: 'demo-series-boat-wave', name: 'Wave Series', brand_id: 'demo-brand-boat-watch' },
|
|
];
|
|
|
|
const DEMO_MODELS: DemoModel[] = [
|
|
{ model_id: 'demo-model-iphone-15', name: 'iPhone 15', series_id: 'demo-series-iphone-15', release_year: 2023 },
|
|
{ model_id: 'demo-model-iphone-15-pro', name: 'iPhone 15 Pro', series_id: 'demo-series-iphone-15', release_year: 2023 },
|
|
{ model_id: 'demo-model-iphone-14', name: 'iPhone 14', series_id: 'demo-series-iphone-14', release_year: 2022 },
|
|
{ model_id: 'demo-model-s24', name: 'Galaxy S24', series_id: 'demo-series-s24', release_year: 2024 },
|
|
{ model_id: 'demo-model-s24-ultra', name: 'Galaxy S24 Ultra', series_id: 'demo-series-s24', release_year: 2024 },
|
|
{ model_id: 'demo-model-a54', name: 'Galaxy A54', series_id: 'demo-series-a5x', release_year: 2023 },
|
|
{ model_id: 'demo-model-op12', name: 'OnePlus 12', series_id: 'demo-series-op12', release_year: 2024 },
|
|
{ model_id: 'demo-model-note-13', name: 'Redmi Note 13 Pro', series_id: 'demo-series-redmi-note', release_year: 2024 },
|
|
{ model_id: 'demo-model-mba-m2', name: 'MacBook Air M2', series_id: 'demo-series-macbook-air', release_year: 2022 },
|
|
{ model_id: 'demo-model-xps-15', name: 'Dell XPS 15', series_id: 'demo-series-xps', release_year: 2023 },
|
|
{ model_id: 'demo-model-pav-15', name: 'HP Pavilion 15', series_id: 'demo-series-pavilion', release_year: 2023 },
|
|
{ model_id: 'demo-model-t14', name: 'ThinkPad T14', series_id: 'demo-series-thinkpad', release_year: 2023 },
|
|
{ model_id: 'demo-model-ipad-air-5', name: 'iPad Air (5th gen)', series_id: 'demo-series-ipad-air', release_year: 2022 },
|
|
{ model_id: 'demo-model-tab-s9', name: 'Galaxy Tab S9', series_id: 'demo-series-tab-s9', release_year: 2023 },
|
|
{ model_id: 'demo-model-tab-m9', name: 'Lenovo Tab M9', series_id: 'demo-series-tab-m', release_year: 2023 },
|
|
{ model_id: 'demo-model-watch-ultra-2', name: 'Apple Watch Ultra 2', series_id: 'demo-series-watch-ultra', release_year: 2023 },
|
|
{ model_id: 'demo-model-watch-se-2', name: 'Apple Watch SE (2nd gen)', series_id: 'demo-series-watch-se', release_year: 2022 },
|
|
{ model_id: 'demo-model-gw6', name: 'Galaxy Watch 6', series_id: 'demo-series-galaxy-watch', release_year: 2023 },
|
|
{ model_id: 'demo-model-colorfit-pro', name: 'ColorFit Pro 5', series_id: 'demo-series-noise-colorfit', release_year: 2023 },
|
|
{ model_id: 'demo-model-wave-call', name: 'Wave Call 2', series_id: 'demo-series-boat-wave', release_year: 2023 },
|
|
];
|
|
|
|
function buildRepairConfig(modelId: string, deviceTypeHint: string): { categories: DemoCategory[] } {
|
|
const hint = normalizeDeviceType(deviceTypeHint);
|
|
const isWatch =
|
|
hint === 'smartwatch' ||
|
|
modelId.includes('watch') ||
|
|
modelId.includes('colorfit') ||
|
|
modelId.includes('wave');
|
|
const isLaptop =
|
|
hint === 'laptop' ||
|
|
modelId.includes('mba') ||
|
|
modelId.includes('xps') ||
|
|
modelId.includes('pav') ||
|
|
modelId.includes('t14');
|
|
const isTablet =
|
|
hint === 'tablet' || modelId.includes('ipad') || modelId.includes('tab');
|
|
|
|
if (isWatch) {
|
|
return {
|
|
categories: [
|
|
{
|
|
service_type_id: `${modelId}-cat-display`,
|
|
category_name: 'Display / Glass',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-oem-glass`,
|
|
name: 'OEM Glass Replacement',
|
|
price: 2499,
|
|
warranty_days: 180,
|
|
duration_minutes: 45,
|
|
},
|
|
{
|
|
variant_id: `${modelId}-var-compat-glass`,
|
|
name: 'Compatible Glass',
|
|
price: 1499,
|
|
warranty_days: 90,
|
|
duration_minutes: 40,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-battery`,
|
|
category_name: 'Battery',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-battery`,
|
|
name: 'Battery Replacement',
|
|
price: 1999,
|
|
warranty_days: 180,
|
|
duration_minutes: 35,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-strap`,
|
|
category_name: 'Strap / Band',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-strap`,
|
|
name: 'Strap Replacement',
|
|
price: 799,
|
|
warranty_days: 90,
|
|
duration_minutes: 15,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
if (isLaptop) {
|
|
return {
|
|
categories: [
|
|
{
|
|
service_type_id: `${modelId}-cat-screen`,
|
|
category_name: 'Screen',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-screen`,
|
|
name: 'LCD Panel Replacement',
|
|
price: 8999,
|
|
warranty_days: 180,
|
|
duration_minutes: 120,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-keyboard`,
|
|
category_name: 'Keyboard',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-keyboard`,
|
|
name: 'Keyboard Replacement',
|
|
price: 4499,
|
|
warranty_days: 180,
|
|
duration_minutes: 90,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-battery`,
|
|
category_name: 'Battery',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-battery`,
|
|
name: 'Battery Replacement',
|
|
price: 5499,
|
|
warranty_days: 180,
|
|
duration_minutes: 75,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
if (isTablet) {
|
|
return {
|
|
categories: [
|
|
{
|
|
service_type_id: `${modelId}-cat-screen`,
|
|
category_name: 'Screen',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-oem`,
|
|
name: 'OEM Display Assembly',
|
|
price: 6999,
|
|
warranty_days: 180,
|
|
duration_minutes: 90,
|
|
},
|
|
{
|
|
variant_id: `${modelId}-var-compat`,
|
|
name: 'Compatible Display',
|
|
price: 4499,
|
|
warranty_days: 90,
|
|
duration_minutes: 90,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-battery`,
|
|
category_name: 'Battery',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-battery`,
|
|
name: 'Battery Replacement',
|
|
price: 2999,
|
|
warranty_days: 180,
|
|
duration_minutes: 60,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
// Default mobile
|
|
return {
|
|
categories: [
|
|
{
|
|
service_type_id: `${modelId}-cat-screen`,
|
|
category_name: 'Screen / Display',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-oem`,
|
|
name: 'OEM Original Display',
|
|
price: 5499,
|
|
warranty_days: 180,
|
|
duration_minutes: 60,
|
|
},
|
|
{
|
|
variant_id: `${modelId}-var-compat`,
|
|
name: 'Compatible Display',
|
|
price: 2999,
|
|
warranty_days: 90,
|
|
duration_minutes: 55,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-battery`,
|
|
category_name: 'Battery',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-battery`,
|
|
name: 'Battery Replacement',
|
|
price: 1799,
|
|
warranty_days: 180,
|
|
duration_minutes: 40,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
service_type_id: `${modelId}-cat-charging`,
|
|
category_name: 'Charging Port',
|
|
variants: [
|
|
{
|
|
variant_id: `${modelId}-var-charging`,
|
|
name: 'Charging Port Repair',
|
|
price: 1299,
|
|
warranty_days: 90,
|
|
duration_minutes: 45,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
export function getDemoBrands(deviceType?: string): DemoBrand[] {
|
|
return DEMO_BRANDS[normalizeDeviceType(deviceType)] || DEMO_BRANDS.mobile;
|
|
}
|
|
|
|
export function getDemoSeries(brandId: string): DemoSeries[] {
|
|
return DEMO_SERIES.filter((s) => s.brand_id === brandId);
|
|
}
|
|
|
|
export function getDemoModels(seriesId: string): DemoModel[] {
|
|
return DEMO_MODELS.filter((m) => m.series_id === seriesId);
|
|
}
|
|
|
|
export function getDemoRepairConfig(
|
|
modelId: string,
|
|
opts?: { deviceType?: string; modelName?: string }
|
|
): { categories: DemoCategory[] } {
|
|
const model = DEMO_MODELS.find((m) => m.model_id === modelId);
|
|
const series = model
|
|
? DEMO_SERIES.find((s) => s.series_id === model.series_id)
|
|
: undefined;
|
|
const brandId = series?.brand_id || '';
|
|
const name = (
|
|
opts?.modelName ||
|
|
model?.name ||
|
|
modelId ||
|
|
''
|
|
).toLowerCase();
|
|
|
|
let hint = 'mobile';
|
|
if (opts?.deviceType) {
|
|
hint = normalizeDeviceType(opts.deviceType);
|
|
} else if (
|
|
brandId.includes('watch') ||
|
|
name.includes('watch') ||
|
|
name.includes('colorfit') ||
|
|
name.includes('wave call')
|
|
) {
|
|
hint = 'smartwatch';
|
|
} else if (
|
|
brandId.includes('laptop') ||
|
|
name.includes('macbook') ||
|
|
name.includes('laptop') ||
|
|
name.includes('thinkpad') ||
|
|
name.includes('xps') ||
|
|
name.includes('pavilion')
|
|
) {
|
|
hint = 'laptop';
|
|
} else if (
|
|
brandId.includes('tablet') ||
|
|
name.includes('ipad') ||
|
|
name.includes('tab ')
|
|
) {
|
|
hint = 'tablet';
|
|
}
|
|
|
|
const raw = buildRepairConfig(modelId, hint);
|
|
return {
|
|
categories: raw.categories.map((c) => ({
|
|
...c,
|
|
repair_service_id: c.repair_service_id || `${c.service_type_id}-rs`,
|
|
description:
|
|
c.description ||
|
|
`Hardcoded demo repair option for verification (${c.category_name}).`,
|
|
})),
|
|
};
|
|
}
|
|
|
|
export function isDemoCatalogId(id: string | undefined | null): boolean {
|
|
return Boolean(id && String(id).startsWith('demo-'));
|
|
}
|
|
|
|
/** Generate a few slots for today/selected date so schedule step can be tested */
|
|
export function getDemoSlots(targetDate: string): {
|
|
start_time: string;
|
|
end_time: string;
|
|
technician_id: string;
|
|
}[] {
|
|
const date = targetDate || new Date().toISOString().split('T')[0];
|
|
const hours = [10, 12, 14, 16, 18];
|
|
return hours.map((h, i) => {
|
|
const start = new Date(`${date}T${String(h).padStart(2, '0')}:00:00`);
|
|
const end = new Date(start.getTime() + 60 * 60 * 1000);
|
|
return {
|
|
start_time: start.toISOString(),
|
|
end_time: end.toISOString(),
|
|
technician_id: `demo-tech-${i + 1}`,
|
|
};
|
|
});
|
|
}
|