mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 06:31:13 -05:00
feat: Implement submission workflow tracking
This commit is contained in:
@@ -15,7 +15,11 @@ export type ActivityType =
|
||||
| 'user_banned'
|
||||
| 'user_unbanned'
|
||||
| 'review_created'
|
||||
| 'review_deleted';
|
||||
| 'review_deleted'
|
||||
| 'submission_created'
|
||||
| 'submission_claimed'
|
||||
| 'submission_escalated'
|
||||
| 'submission_reassigned';
|
||||
|
||||
export interface ActivityActor {
|
||||
id: string;
|
||||
@@ -99,6 +103,20 @@ export interface ReviewLifecycleDetails {
|
||||
was_moderated?: boolean;
|
||||
}
|
||||
|
||||
export interface SubmissionWorkflowDetails {
|
||||
submission_id: string;
|
||||
submission_type: string;
|
||||
user_id?: string;
|
||||
username?: string;
|
||||
assigned_to?: string;
|
||||
assigned_username?: string;
|
||||
escalation_reason?: string;
|
||||
from_moderator?: string;
|
||||
from_moderator_username?: string;
|
||||
to_moderator?: string;
|
||||
to_moderator_username?: string;
|
||||
}
|
||||
|
||||
export type ActivityDetails =
|
||||
| EntityChangeDetails
|
||||
| AdminActionDetails
|
||||
@@ -107,7 +125,8 @@ export type ActivityDetails =
|
||||
| ReviewModerationDetails
|
||||
| PhotoApprovalDetails
|
||||
| AccountLifecycleDetails
|
||||
| ReviewLifecycleDetails;
|
||||
| ReviewLifecycleDetails
|
||||
| SubmissionWorkflowDetails;
|
||||
|
||||
export interface SystemActivity {
|
||||
id: string;
|
||||
@@ -588,6 +607,87 @@ export async function fetchSystemActivities(
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch submission workflow events (recent 7 days)
|
||||
// 1. Submission creations
|
||||
const { data: newSubmissions, error: newSubmissionsError } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('id, user_id, submission_type, submitted_at')
|
||||
.gte('submitted_at', sevenDaysAgo.toISOString())
|
||||
.order('submitted_at', { ascending: false })
|
||||
.limit(Math.ceil(limit / 2));
|
||||
|
||||
if (!newSubmissionsError && newSubmissions) {
|
||||
for (const submission of newSubmissions) {
|
||||
activities.push({
|
||||
id: `submission-created-${submission.id}`,
|
||||
type: 'submission_created',
|
||||
timestamp: submission.submitted_at,
|
||||
actor_id: submission.user_id,
|
||||
action: 'created submission',
|
||||
details: {
|
||||
submission_id: submission.id,
|
||||
submission_type: submission.submission_type,
|
||||
user_id: submission.user_id,
|
||||
} as SubmissionWorkflowDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Submission claims/assignments
|
||||
const { data: claimedSubmissions, error: claimsError } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('id, submission_type, assigned_to, assigned_at, user_id')
|
||||
.not('assigned_at', 'is', null)
|
||||
.gte('assigned_at', sevenDaysAgo.toISOString())
|
||||
.order('assigned_at', { ascending: false })
|
||||
.limit(Math.ceil(limit / 2));
|
||||
|
||||
if (!claimsError && claimedSubmissions) {
|
||||
for (const submission of claimedSubmissions) {
|
||||
activities.push({
|
||||
id: `submission-claimed-${submission.id}`,
|
||||
type: 'submission_claimed',
|
||||
timestamp: submission.assigned_at!,
|
||||
actor_id: submission.assigned_to,
|
||||
action: 'claimed submission',
|
||||
details: {
|
||||
submission_id: submission.id,
|
||||
submission_type: submission.submission_type,
|
||||
user_id: submission.user_id,
|
||||
assigned_to: submission.assigned_to,
|
||||
} as SubmissionWorkflowDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Submission escalations
|
||||
const { data: escalatedSubmissions, error: escalationsError } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('id, submission_type, escalated_by, escalated_at, escalation_reason, user_id')
|
||||
.eq('escalated', true)
|
||||
.not('escalated_at', 'is', null)
|
||||
.gte('escalated_at', sevenDaysAgo.toISOString())
|
||||
.order('escalated_at', { ascending: false })
|
||||
.limit(Math.ceil(limit / 2));
|
||||
|
||||
if (!escalationsError && escalatedSubmissions) {
|
||||
for (const submission of escalatedSubmissions) {
|
||||
activities.push({
|
||||
id: `submission-escalated-${submission.id}`,
|
||||
type: 'submission_escalated',
|
||||
timestamp: submission.escalated_at!,
|
||||
actor_id: submission.escalated_by,
|
||||
action: 'escalated submission',
|
||||
details: {
|
||||
submission_id: submission.id,
|
||||
submission_type: submission.submission_type,
|
||||
user_id: submission.user_id,
|
||||
escalation_reason: submission.escalation_reason || undefined,
|
||||
} as SubmissionWorkflowDetails,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch review lifecycle events
|
||||
// 1. Review creations (recent 7 days)
|
||||
const { data: newReviews, error: newReviewsError } = await supabase
|
||||
@@ -780,6 +880,48 @@ export async function fetchSystemActivities(
|
||||
}
|
||||
}
|
||||
|
||||
// Enrich submission workflow users
|
||||
const submissionWorkflowUserIds = filteredActivities
|
||||
.filter(a => ['submission_created', 'submission_claimed', 'submission_escalated', 'submission_reassigned'].includes(a.type))
|
||||
.flatMap(a => {
|
||||
const details = a.details as SubmissionWorkflowDetails;
|
||||
return [details.user_id, details.assigned_to, details.from_moderator, details.to_moderator].filter(Boolean);
|
||||
})
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
if (submissionWorkflowUserIds.length > 0) {
|
||||
const { data: submissionProfiles } = await supabase
|
||||
.from('profiles')
|
||||
.select('user_id, username')
|
||||
.in('user_id', submissionWorkflowUserIds);
|
||||
|
||||
if (submissionProfiles) {
|
||||
const submissionProfileMap = new Map(submissionProfiles.map(p => [p.user_id, p]));
|
||||
|
||||
for (const activity of filteredActivities) {
|
||||
if (['submission_created', 'submission_claimed', 'submission_escalated', 'submission_reassigned'].includes(activity.type)) {
|
||||
const details = activity.details as SubmissionWorkflowDetails;
|
||||
if (details.user_id && !details.username) {
|
||||
const profile = submissionProfileMap.get(details.user_id);
|
||||
if (profile) details.username = profile.username;
|
||||
}
|
||||
if (details.assigned_to && !details.assigned_username) {
|
||||
const profile = submissionProfileMap.get(details.assigned_to);
|
||||
if (profile) details.assigned_username = profile.username;
|
||||
}
|
||||
if (details.from_moderator && !details.from_moderator_username) {
|
||||
const profile = submissionProfileMap.get(details.from_moderator);
|
||||
if (profile) details.from_moderator_username = profile.username;
|
||||
}
|
||||
if (details.to_moderator && !details.to_moderator_username) {
|
||||
const profile = submissionProfileMap.get(details.to_moderator);
|
||||
if (profile) details.to_moderator_username = profile.username;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enrich review entity names
|
||||
const parkReviewIds = filteredActivities
|
||||
.filter(a => ['review_created', 'review_deleted'].includes(a.type) && (a.details as ReviewLifecycleDetails).entity_type === 'park')
|
||||
|
||||
Reference in New Issue
Block a user