ifixkart-storefront/lib/servicePageLayout.ts

145 lines
3.6 KiB
TypeScript

/**
* Helpers for Repair/Services page CMS + catalog device types.
*/
import type { LucideIcon } from 'lucide-react';
import {
Award,
Clock,
Heart,
HelpCircle,
Laptop,
ShieldCheck,
Smartphone,
Tablet,
ThumbsUp,
Watch,
Wrench,
} from 'lucide-react';
import {
LayoutItem,
normalizeLayoutPayload,
parseMetadata,
resolveIsActive,
} from '@/lib/layoutConfig';
export const SERVICE_REGIONS = [
'service_hero',
'service_how_it_works',
'service_why_us',
'service_faq',
] as const;
export type ServiceRegion = (typeof SERVICE_REGIONS)[number];
const DEVICE_ICON_MAP: Record<string, LucideIcon> = {
mobile: Smartphone,
phone: Smartphone,
smartphone: Smartphone,
laptop: Laptop,
notebook: Laptop,
tablet: Tablet,
smartwatch: Watch,
watch: Watch,
wearable: Watch,
};
const WHY_ICON_MAP: Record<string, LucideIcon> = {
ShieldCheck,
Clock,
ThumbsUp,
Wrench,
Award,
Heart,
HelpCircle,
};
const DEFAULT_DEVICE_TYPES = ['mobile', 'laptop', 'tablet', 'smartwatch'];
export function normalizeServiceLayout(raw: unknown): LayoutItem[] {
return normalizeLayoutPayload(raw)
.map((item) => ({
...item,
metadata: parseMetadata(item),
metadata_json: parseMetadata(item),
}))
.sort(
(a, b) =>
(Number(a.display_order) || 0) - (Number(b.display_order) || 0)
);
}
export function findServiceSection(
layout: LayoutItem[],
region: ServiceRegion
): LayoutItem | null {
return (
layout.find((s) => {
const key =
parseMetadata(s).section_key ||
s.region ||
s.type ||
'';
return key === region || s.region === region || s.type === region;
}) || null
);
}
export function isServiceSectionVisible(
layout: LayoutItem[],
region: ServiceRegion
): boolean {
const section = findServiceSection(layout, region);
if (!section) return true; // show defaults when CMS row missing
return resolveIsActive(section);
}
export function formatDeviceTypeLabel(id: string): string {
const known: Record<string, string> = {
mobile: 'Mobile',
laptop: 'Laptop',
tablet: 'Tablet',
smartwatch: 'Smartwatch',
phone: 'Phone',
smartphone: 'Smartphone',
watch: 'Watch',
};
if (known[id]) return known[id];
return String(id || '')
.replace(/[_-]+/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase());
}
export function getDeviceTypeIcon(id: string): LucideIcon {
return DEVICE_ICON_MAP[String(id || '').toLowerCase()] || Wrench;
}
export function getWhyUsIcon(name?: string): LucideIcon {
if (!name) return ShieldCheck;
return WHY_ICON_MAP[name] || ShieldCheck;
}
export function normalizeDeviceTypes(raw: unknown): string[] {
if (!Array.isArray(raw) || raw.length === 0) return DEFAULT_DEVICE_TYPES;
const ids = raw
.map((item) => {
if (typeof item === 'string') return item.trim().toLowerCase();
if (item && typeof item === 'object') {
const o = item as Record<string, unknown>;
const id = o.id ?? o.value ?? o.slug ?? o.device_type ?? o.name;
return String(id || '')
.trim()
.toLowerCase();
}
return '';
})
.filter(Boolean);
return ids.length > 0 ? Array.from(new Set(ids)) : DEFAULT_DEVICE_TYPES;
}
export function resolveHeroImage(section: LayoutItem | null): string {
if (!section) return '';
const meta = parseMetadata(section);
return String(
meta.image_url || section.image_url || section.image || ''
).trim();
}