import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import type { SchoolMetadata } from '../../types'; import { POI_GROUP_COLORS } from '../../lib/consts'; import { getPoiIconUrl } from '../../lib/map-utils'; import { ts } from '../../i18n/server'; export interface PoiPopupCardData { name: string; category: string; icon_category?: string; group: string; emoji: string; school?: SchoolMetadata; } function getPoiGroupColor(group: string): [number, number, number] { const color = POI_GROUP_COLORS[group]; if (!color) { throw new Error(`Missing POI group color for '${group}'`); } return color; } /** Best-effort web URL from a free-text website field. GIAS stores some with * "http://", some without, and some as bare hostnames. */ function normalizeSchoolWebsiteUrl(raw: string): string | null { const trimmed = raw.trim(); if (!trimmed) return null; if (/^https?:\/\//i.test(trimmed)) return trimmed; if (/^[\w.-]+\.[a-z]{2,}/i.test(trimmed)) return `http://${trimmed}`; return null; } function renderSchoolMetadata(school: SchoolMetadata, t: TFunction) { // First line collects the headline classification (phase, type, religious // character) so the popup is scannable even when most fields are absent. const headline: string[] = []; if (school.phase) headline.push(school.phase); if (school.type) headline.push(school.type); const pupilsLine = school.pupils !== undefined && school.capacity !== undefined ? `${school.pupils.toLocaleString()} / ${school.capacity.toLocaleString()} ${t('poiPopup.school.pupils')}` : school.pupils !== undefined ? `${school.pupils.toLocaleString()} ${t('poiPopup.school.pupils')}` : school.capacity !== undefined ? `${t('poiPopup.school.capacity')} ${school.capacity.toLocaleString()}` : null; const websiteUrl = school.website ? normalizeSchoolWebsiteUrl(school.website) : null; return (
{headline.length > 0 && ( <>
{t('poiPopup.school.type')}
{headline.join(' ยท ')}
)} {school.age_range && ( <>
{t('poiPopup.school.ages')}
{school.age_range}
)} {school.gender && school.gender !== 'Mixed' && ( <>
{t('poiPopup.school.gender')}
{school.gender}
)} {pupilsLine && ( <>
{t('poiPopup.school.pupilsLabel')}
{pupilsLine}
)} {school.fsm_percent !== undefined && ( <>
{t('poiPopup.school.freeMeal')}
{school.fsm_percent.toFixed(1)}%
)} {school.ofsted_rating && ( <>
{t('poiPopup.school.ofsted')}
{school.ofsted_rating}
)} {school.sixth_form === 'Has a sixth form' && ( <>
{t('poiPopup.school.sixthForm')}
{t('common.yes')}
)} {school.religious_character && school.religious_character !== 'Does not apply' && school.religious_character !== 'None' && ( <>
{t('poiPopup.school.religion')}
{school.religious_character}
)} {school.admissions_policy && ( <>
{t('poiPopup.school.admissions')}
{school.admissions_policy}
)} {school.trust && ( <>
{t('poiPopup.school.trust')}
{school.trust}
)} {(school.address || school.postcode) && ( <>
{t('poiPopup.school.address')}
{[school.address, school.postcode].filter(Boolean).join(', ')}
)} {school.local_authority && ( <>
{t('poiPopup.school.localAuthority')}
{school.local_authority}
)} {school.head_name && ( <>
{t('poiPopup.school.head')}
{school.head_name}
)} {websiteUrl && ( <>
{t('poiPopup.school.website')}
{websiteUrl.replace(/^https?:\/\//, '')}
)}
); } export const PoiPopupCardContent = memo(function PoiPopupCardContent({ poi, }: { poi: PoiPopupCardData; }) { const { t } = useTranslation(); return (
{poi.name}
{ts(poi.category)}
{poi.school && renderSchoolMetadata(poi.school, t)}
); });