mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
191 lines
5.6 KiB
TypeScript
191 lines
5.6 KiB
TypeScript
import type { OrganizationSubtype } from '@/schemas/organizationSubtype.ts';
|
|
import {
|
|
Banknote,
|
|
Briefcase,
|
|
Building,
|
|
Building2,
|
|
Car,
|
|
Church,
|
|
Circle,
|
|
Construction,
|
|
Cpu,
|
|
Factory,
|
|
GraduationCap,
|
|
Heart,
|
|
Hotel,
|
|
Scissors,
|
|
ShoppingBag,
|
|
Theater,
|
|
Truck,
|
|
UtensilsCrossed,
|
|
Zap
|
|
} from 'lucide-react';
|
|
import React from 'react';
|
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
|
|
/**
|
|
* Database subtypes (actual values from database)
|
|
* These are the granular subtypes stored in the database
|
|
*/
|
|
export type DatabaseSubtype =
|
|
| 'retail'
|
|
| 'healthcare'
|
|
| 'educational'
|
|
| 'personal_services'
|
|
| 'food_beverage'
|
|
| 'automotive'
|
|
| 'religious'
|
|
| 'professional_services'
|
|
| 'energy'
|
|
| 'financial'
|
|
| 'government'
|
|
| 'manufacturing'
|
|
| 'cultural'
|
|
| 'hospitality'
|
|
| 'transportation'
|
|
| 'infrastructure'
|
|
| 'technology'
|
|
| 'other';
|
|
|
|
/**
|
|
* Get the appropriate Lucide icon component for an organization subtype
|
|
*/
|
|
function getLucideIconForSubtype(subtype: string): React.ComponentType<{ size?: number; color?: string }> {
|
|
const subtypeLower = subtype.toLowerCase().trim();
|
|
|
|
// Map database subtypes to Lucide icons
|
|
switch (subtypeLower) {
|
|
case 'retail':
|
|
return ShoppingBag;
|
|
case 'food_beverage':
|
|
return UtensilsCrossed;
|
|
case 'automotive':
|
|
return Car;
|
|
case 'personal_services':
|
|
return Scissors;
|
|
case 'professional_services':
|
|
return Briefcase;
|
|
case 'financial':
|
|
return Banknote;
|
|
case 'manufacturing':
|
|
return Factory;
|
|
case 'hospitality':
|
|
return Hotel;
|
|
case 'transportation':
|
|
return Truck;
|
|
case 'energy':
|
|
return Zap;
|
|
case 'technology':
|
|
return Cpu;
|
|
case 'commercial':
|
|
return Building2;
|
|
case 'cultural':
|
|
return Theater;
|
|
case 'government':
|
|
return Building;
|
|
case 'religious':
|
|
return Church;
|
|
case 'educational':
|
|
return GraduationCap;
|
|
case 'infrastructure':
|
|
return Construction;
|
|
case 'healthcare':
|
|
return Heart;
|
|
case 'other':
|
|
default:
|
|
return Circle;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get organization icon SVG as string (for use in Leaflet DivIcon)
|
|
* Uses Lucide icons rendered to HTML strings
|
|
*/
|
|
export function getOrganizationIconSvg(
|
|
subtype: OrganizationSubtype | DatabaseSubtype | string | undefined | null,
|
|
size: number,
|
|
iconColor: string,
|
|
backgroundColor: string
|
|
): string {
|
|
// Debug logging in development
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.log('[organizationIcons] getOrganizationIconSvg called with:', {
|
|
subtype,
|
|
size,
|
|
iconColor,
|
|
backgroundColor,
|
|
sizeType: typeof size,
|
|
iconColorType: typeof iconColor,
|
|
backgroundColorType: typeof backgroundColor
|
|
});
|
|
}
|
|
|
|
// Ensure all parameters are valid with proper type checking
|
|
const safeSize = Math.max(1, Number.isFinite(size) && size > 0 ? size : 24);
|
|
// Increase icon size to 65% of marker size for better visibility (was 50%)
|
|
const safeIconSize = Math.round(safeSize * 0.65);
|
|
const subtypeValue = (subtype || '').toLowerCase().trim();
|
|
|
|
// Ensure colors are never undefined and are valid strings
|
|
const safeBackgroundColor = (typeof backgroundColor === 'string' && backgroundColor.trim()) ? backgroundColor : '#6b7280';
|
|
|
|
/**
|
|
* Calculate a contrasting color for the icon based on background brightness
|
|
* Returns a color that will stand out against the background
|
|
*/
|
|
function getContrastingIconColor(bgColor: string): string {
|
|
// Parse hex color
|
|
const hex = bgColor.replace('#', '');
|
|
if (hex.length !== 6) {
|
|
// If invalid color, return white as fallback
|
|
return '#ffffff';
|
|
}
|
|
|
|
// Convert to RGB
|
|
const r = parseInt(hex.substr(0, 2), 16);
|
|
const g = parseInt(hex.substr(2, 2), 16);
|
|
const b = parseInt(hex.substr(4, 2), 16);
|
|
|
|
// Calculate brightness (luminance)
|
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
|
|
// If background is light, use dark contrasting color
|
|
// If background is dark, use light contrasting color
|
|
if (brightness > 128) {
|
|
// Light background - use darker, more saturated color for contrast
|
|
// Darken and saturate the background color
|
|
const darkerR = Math.max(0, Math.min(255, r * 0.4));
|
|
const darkerG = Math.max(0, Math.min(255, g * 0.4));
|
|
const darkerB = Math.max(0, Math.min(255, b * 0.4));
|
|
return `rgb(${Math.round(darkerR)}, ${Math.round(darkerG)}, ${Math.round(darkerB)})`;
|
|
} else {
|
|
// Dark background - use lighter, contrasting color
|
|
// Lighten the background color or use a complementary light color
|
|
const lighterR = Math.min(255, r + (255 - r) * 0.7);
|
|
const lighterG = Math.min(255, g + (255 - g) * 0.7);
|
|
const lighterB = Math.min(255, b + (255 - b) * 0.7);
|
|
return `rgb(${Math.round(lighterR)}, ${Math.round(lighterG)}, ${Math.round(lighterB)})`;
|
|
}
|
|
}
|
|
|
|
// Calculate contrasting icon color based on background
|
|
const contrastingIconColor = getContrastingIconColor(safeBackgroundColor);
|
|
|
|
// Get the appropriate Lucide icon component
|
|
const IconComponent = getLucideIconForSubtype(subtypeValue);
|
|
|
|
// Render the icon to HTML string using renderToStaticMarkup (appropriate for Leaflet markers)
|
|
// Use contrasting color for better visibility against the background
|
|
const iconHtml = renderToStaticMarkup(
|
|
React.createElement(IconComponent, {
|
|
size: safeIconSize,
|
|
color: contrastingIconColor, // Use contrasting color instead of plain white
|
|
strokeWidth: 2.5, // Slightly thicker for better visibility
|
|
})
|
|
);
|
|
|
|
// Return the icon SVG directly (the wrapper div in iconCache.ts will handle centering and background)
|
|
return iconHtml;
|
|
}
|
|
|