mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 03:31:12 -05:00
210 lines
5.8 KiB
TypeScript
210 lines
5.8 KiB
TypeScript
/**
|
|
* Realtime Subscription Utilities
|
|
*
|
|
* Helper functions for processing realtime subscription events in the moderation queue.
|
|
*/
|
|
|
|
import type { ModerationItem, EntityFilter, StatusFilter } from '@/types/moderation';
|
|
|
|
interface SubmissionContent {
|
|
name?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
/**
|
|
* Check if a submission matches the entity filter
|
|
*/
|
|
export function matchesEntityFilter(
|
|
submission: { submission_type: string },
|
|
entityFilter: EntityFilter
|
|
): boolean {
|
|
if (entityFilter === 'all') return true;
|
|
|
|
if (entityFilter === 'photos') {
|
|
return submission.submission_type === 'photo';
|
|
}
|
|
|
|
if (entityFilter === 'submissions') {
|
|
return submission.submission_type !== 'photo';
|
|
}
|
|
|
|
if (entityFilter === 'reviews') {
|
|
return submission.submission_type === 'review';
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if a submission matches the status filter
|
|
*/
|
|
export function matchesStatusFilter(
|
|
submission: { status: string },
|
|
statusFilter: StatusFilter
|
|
): boolean {
|
|
if (statusFilter === 'all') return true;
|
|
|
|
if (statusFilter === 'pending') {
|
|
return ['pending', 'partially_approved'].includes(submission.status);
|
|
}
|
|
|
|
return statusFilter === submission.status;
|
|
}
|
|
|
|
/**
|
|
* Deep comparison of ModerationItem fields to detect actual changes
|
|
*/
|
|
export function hasItemChanged(
|
|
current: ModerationItem,
|
|
updated: ModerationItem
|
|
): boolean {
|
|
// Check critical fields
|
|
if (
|
|
current.status !== updated.status ||
|
|
current.reviewed_at !== updated.reviewed_at ||
|
|
current.reviewer_notes !== updated.reviewer_notes ||
|
|
current.assigned_to !== updated.assigned_to ||
|
|
current.locked_until !== updated.locked_until ||
|
|
current.escalated !== updated.escalated
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
// Check submission_items
|
|
if (current.submission_items?.length !== updated.submission_items?.length) {
|
|
return true;
|
|
}
|
|
|
|
// Check content (one level deep for performance)
|
|
if (current.content && updated.content) {
|
|
// Compare content reference first
|
|
if (current.content !== updated.content) {
|
|
const currentKeys = Object.keys(current.content).sort();
|
|
const updatedKeys = Object.keys(updated.content).sort();
|
|
|
|
// Different number of keys = changed
|
|
if (currentKeys.length !== updatedKeys.length) {
|
|
return true;
|
|
}
|
|
|
|
// Different key names = changed
|
|
if (!currentKeys.every((key, i) => key === updatedKeys[i])) {
|
|
return true;
|
|
}
|
|
|
|
// Check each key's value
|
|
for (const key of currentKeys) {
|
|
if (current.content[key] !== updated.content[key]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Extract only changed fields for minimal updates
|
|
*/
|
|
export function extractChangedFields(
|
|
current: ModerationItem,
|
|
updated: ModerationItem
|
|
): Partial<ModerationItem> {
|
|
const changes: Partial<ModerationItem> = {};
|
|
|
|
if (current.status !== updated.status) {
|
|
changes.status = updated.status;
|
|
}
|
|
|
|
if (current.reviewed_at !== updated.reviewed_at) {
|
|
changes.reviewed_at = updated.reviewed_at;
|
|
}
|
|
|
|
if (current.reviewer_notes !== updated.reviewer_notes) {
|
|
changes.reviewer_notes = updated.reviewer_notes;
|
|
}
|
|
|
|
if (current.assigned_to !== updated.assigned_to) {
|
|
changes.assigned_to = updated.assigned_to;
|
|
}
|
|
|
|
if (current.locked_until !== updated.locked_until) {
|
|
changes.locked_until = updated.locked_until;
|
|
}
|
|
|
|
if (current.escalated !== updated.escalated) {
|
|
changes.escalated = updated.escalated;
|
|
}
|
|
|
|
// Check content changes
|
|
if (current.content !== updated.content) {
|
|
changes.content = updated.content;
|
|
}
|
|
|
|
// Check submission_items
|
|
if (updated.submission_items) {
|
|
changes.submission_items = updated.submission_items;
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
/**
|
|
* Build a full ModerationItem from submission data
|
|
*/
|
|
export function buildModerationItem(
|
|
submission: any,
|
|
profile?: any,
|
|
entityName?: string,
|
|
parkName?: string
|
|
): ModerationItem {
|
|
return {
|
|
id: submission.id,
|
|
type: 'content_submission',
|
|
content: submission.content,
|
|
|
|
// Handle both created_at (from view) and submitted_at (from realtime)
|
|
created_at: submission.created_at || submission.submitted_at,
|
|
submitted_at: submission.submitted_at,
|
|
|
|
// Support both user_id and submitter_id
|
|
user_id: submission.user_id || submission.submitter_id,
|
|
submitter_id: submission.submitter_id || submission.user_id,
|
|
|
|
status: submission.status,
|
|
submission_type: submission.submission_type,
|
|
|
|
// Use new profile structure from view if available
|
|
submitter_profile: submission.submitter_profile || (profile ? {
|
|
user_id: submission.user_id || submission.submitter_id,
|
|
username: profile.username,
|
|
display_name: profile.display_name,
|
|
avatar_url: profile.avatar_url,
|
|
} : undefined),
|
|
|
|
reviewer_profile: submission.reviewer_profile,
|
|
assigned_profile: submission.assigned_profile,
|
|
|
|
// Legacy support: create user_profile from submitter_profile
|
|
user_profile: submission.submitter_profile ? {
|
|
username: submission.submitter_profile.username,
|
|
display_name: submission.submitter_profile.display_name,
|
|
avatar_url: submission.submitter_profile.avatar_url,
|
|
} : (profile ? {
|
|
username: profile.username,
|
|
display_name: profile.display_name,
|
|
avatar_url: profile.avatar_url,
|
|
} : undefined),
|
|
|
|
entity_name: entityName || (submission.content as SubmissionContent)?.name || 'Unknown',
|
|
park_name: parkName,
|
|
reviewed_at: submission.reviewed_at || undefined,
|
|
reviewer_notes: submission.reviewer_notes || undefined,
|
|
escalated: submission.escalated || false,
|
|
assigned_to: submission.assigned_to || undefined,
|
|
locked_until: submission.locked_until || undefined,
|
|
submission_items: submission.submission_items || undefined,
|
|
};
|
|
}
|