/** * Entity Resolution Utilities * * Functions for resolving entity names and display information * from cached entity data used in moderation workflows. */ /** * Entity cache structure (matching useEntityCache hook) */ interface EntityCache { rides: Map; parks: Map; companies: Map; } /** * Generic submission content type */ interface GenericSubmissionContent { name?: string; entity_id?: string; entity_name?: string; park_id?: string; ride_id?: string; company_id?: string; manufacturer_id?: string; designer_id?: string; operator_id?: string; property_owner_id?: string; [key: string]: unknown; } /** * Result of entity name resolution */ export interface ResolvedEntityNames { entityName: string; parkName?: string; } /** * Resolve entity name and related park name from submission content * * This function determines what entity is being modified based on the * submission type and content, then looks up cached entity data to * resolve display names. * * @param submissionType - Type of submission (e.g., 'ride', 'park', 'manufacturer') * @param content - Submission content containing entity IDs * @param entityCache - Cache of entity data * @returns Resolved entity and park names * * @example * ```tsx * const { entityName, parkName } = resolveEntityName( * 'ride', * { entity_id: 'ride-123' }, * entityCacheRef.current * ); * // Returns: { entityName: "Steel Vengeance", parkName: "Cedar Point" } * ``` */ export function resolveEntityName( submissionType: string, content: GenericSubmissionContent | null | undefined, entityCache: EntityCache ): ResolvedEntityNames { let entityName = content?.name || 'Unknown'; let parkName: string | undefined; // Handle ride submissions - look up ride name and park if (submissionType === 'ride' && content?.entity_id) { const ride = entityCache.rides.get(content.entity_id); if (ride) { entityName = ride.name; if (ride.park_id) { const park = entityCache.parks.get(ride.park_id); if (park) parkName = park.name; } } } // Handle park submissions else if (submissionType === 'park' && content?.entity_id) { const park = entityCache.parks.get(content.entity_id); if (park) entityName = park.name; } // Handle company submissions (manufacturer, operator, designer, property_owner) else if ( ['manufacturer', 'operator', 'designer', 'property_owner'].includes(submissionType) && content?.entity_id ) { const company = entityCache.companies.get(content.entity_id); if (company) entityName = company.name; } // Handle content with ride_id reference else if (content?.ride_id) { const ride = entityCache.rides.get(content.ride_id); if (ride) { entityName = ride.name; if (ride.park_id) { const park = entityCache.parks.get(ride.park_id); if (park) parkName = park.name; } } } // Handle content with park_id reference else if (content?.park_id) { const park = entityCache.parks.get(content.park_id); if (park) parkName = park.name; } return { entityName, parkName }; } /** * Get a display-ready entity identifier string * * Combines entity name and park name (if available) into a single * human-readable string for display in the moderation interface. * * @param entityName - Primary entity name * @param parkName - Optional related park name * @returns Formatted display string * * @example * ```tsx * getEntityDisplayName("Steel Vengeance", "Cedar Point") * // Returns: "Steel Vengeance at Cedar Point" * * getEntityDisplayName("Cedar Point") * // Returns: "Cedar Point" * ``` */ export function getEntityDisplayName( entityName: string, parkName?: string ): string { if (parkName) { return `${entityName} at ${parkName}`; } return entityName; } /** * Extract all entity IDs from a list of submissions * * Scans through submission content to find all referenced entity IDs, * grouped by entity type (rides, parks, companies). * * @param submissions - Array of submission objects * @returns Object containing Sets of IDs for each entity type */ export function extractEntityIds(submissions: Array<{ content: unknown; submission_type: string }>): { rideIds: Set; parkIds: Set; companyIds: Set; } { const rideIds = new Set(); const parkIds = new Set(); const companyIds = new Set(); submissions.forEach(submission => { const content = submission.content as GenericSubmissionContent | null | undefined; if (content && typeof content === 'object') { // Direct entity references if (content.ride_id) rideIds.add(content.ride_id); if (content.park_id) parkIds.add(content.park_id); if (content.company_id) companyIds.add(content.company_id); // Entity ID based on submission type if (content.entity_id) { if (submission.submission_type === 'ride') { rideIds.add(content.entity_id); } else if (submission.submission_type === 'park') { parkIds.add(content.entity_id); } else if ( ['manufacturer', 'operator', 'designer', 'property_owner'].includes( submission.submission_type ) ) { companyIds.add(content.entity_id); } } // Company role references if (content.manufacturer_id) companyIds.add(content.manufacturer_id); if (content.designer_id) companyIds.add(content.designer_id); if (content.operator_id) companyIds.add(content.operator_id); if (content.property_owner_id) companyIds.add(content.property_owner_id); } }); return { rideIds, parkIds, companyIds }; } /** * Determine submission type display label * * Converts internal submission type identifiers to human-readable labels. * * @param submissionType - Internal submission type * @returns Human-readable label */ export function getSubmissionTypeLabel(submissionType: string): string { const labels: Record = { park: 'Park', ride: 'Ride', manufacturer: 'Manufacturer', operator: 'Operator', designer: 'Designer', property_owner: 'Property Owner', ride_model: 'Ride Model', photo: 'Photo', photo_delete: 'Photo Deletion', milestone: 'Timeline Event', timeline_event: 'Timeline Event', review: 'Review', }; return labels[submissionType] || submissionType; }