mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 04:31:16 -05:00
223 lines
6.5 KiB
TypeScript
223 lines
6.5 KiB
TypeScript
/**
|
|
* 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<string, { id: string; name: string; park_id?: string }>;
|
|
parks: Map<string, { id: string; name: string }>;
|
|
companies: Map<string, { id: string; name: string }>;
|
|
}
|
|
|
|
/**
|
|
* 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<string>;
|
|
parkIds: Set<string>;
|
|
companyIds: Set<string>;
|
|
} {
|
|
const rideIds = new Set<string>();
|
|
const parkIds = new Set<string>();
|
|
const companyIds = new Set<string>();
|
|
|
|
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<string, string> = {
|
|
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;
|
|
}
|