mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 05:51:23 -05:00
feat: Add submissions and rankings to activity feed
This commit is contained in:
@@ -14,7 +14,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|||||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useUsernameValidation } from '@/hooks/useUsernameValidation';
|
import { useUsernameValidation } from '@/hooks/useUsernameValidation';
|
||||||
import { User, MapPin, Calendar, Star, Trophy, Settings, Camera, Edit3, Save, X, ArrowLeft, Check, AlertCircle, Loader2, UserX } from 'lucide-react';
|
import { User, MapPin, Calendar, Star, Trophy, Settings, Camera, Edit3, Save, X, ArrowLeft, Check, AlertCircle, Loader2, UserX, FileText, Image } from 'lucide-react';
|
||||||
import { Profile as ProfileType } from '@/types/database';
|
import { Profile as ProfileType } from '@/types/database';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
@@ -119,14 +119,21 @@ export default function Profile() {
|
|||||||
const fetchRecentActivity = async (userId: string) => {
|
const fetchRecentActivity = async (userId: string) => {
|
||||||
setActivityLoading(true);
|
setActivityLoading(true);
|
||||||
try {
|
try {
|
||||||
|
const isOwnProfile = currentUser && currentUser.id === userId;
|
||||||
|
|
||||||
// Fetch last 10 reviews
|
// Fetch last 10 reviews
|
||||||
const { data: reviews, error: reviewsError } = await supabase
|
let reviewsQuery = supabase
|
||||||
.from('reviews')
|
.from('reviews')
|
||||||
.select('id, rating, title, created_at, moderation_status, park_id, ride_id, parks(name, slug), rides(name, slug, parks(name, slug))')
|
.select('id, rating, title, created_at, moderation_status, park_id, ride_id, parks(name, slug), rides(name, slug, parks(name, slug))')
|
||||||
.eq('user_id', userId)
|
.eq('user_id', userId)
|
||||||
.order('created_at', { ascending: false })
|
.order('created_at', { ascending: false })
|
||||||
.limit(10);
|
.limit(10);
|
||||||
|
|
||||||
|
if (!isOwnProfile) {
|
||||||
|
reviewsQuery = reviewsQuery.eq('moderation_status', 'approved');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: reviews, error: reviewsError } = await reviewsQuery;
|
||||||
if (reviewsError) throw reviewsError;
|
if (reviewsError) throw reviewsError;
|
||||||
|
|
||||||
// Fetch last 10 ride credits
|
// Fetch last 10 ride credits
|
||||||
@@ -139,10 +146,38 @@ export default function Profile() {
|
|||||||
|
|
||||||
if (creditsError) throw creditsError;
|
if (creditsError) throw creditsError;
|
||||||
|
|
||||||
|
// Fetch last 10 submissions
|
||||||
|
let submissionsQuery = supabase
|
||||||
|
.from('content_submissions')
|
||||||
|
.select('id, submission_type, content, status, created_at')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.order('created_at', { ascending: false })
|
||||||
|
.limit(10);
|
||||||
|
|
||||||
|
if (!isOwnProfile) {
|
||||||
|
submissionsQuery = submissionsQuery.eq('status', 'approved');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: submissions, error: submissionsError } = await submissionsQuery;
|
||||||
|
if (submissionsError) throw submissionsError;
|
||||||
|
|
||||||
|
// Fetch last 10 rankings (public top lists)
|
||||||
|
const { data: rankings, error: rankingsError } = await supabase
|
||||||
|
.from('user_top_lists')
|
||||||
|
.select('id, title, description, list_type, created_at')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.eq('is_public', true)
|
||||||
|
.order('created_at', { ascending: false })
|
||||||
|
.limit(10);
|
||||||
|
|
||||||
|
if (rankingsError) throw rankingsError;
|
||||||
|
|
||||||
// Combine and sort by date
|
// Combine and sort by date
|
||||||
const combined = [
|
const combined = [
|
||||||
...(reviews?.map(r => ({ ...r, type: 'review' })) || []),
|
...(reviews?.map(r => ({ ...r, type: 'review' })) || []),
|
||||||
...(credits?.map(c => ({ ...c, type: 'credit' })) || [])
|
...(credits?.map(c => ({ ...c, type: 'credit' })) || []),
|
||||||
|
...(submissions?.map(s => ({ ...s, type: 'submission' })) || []),
|
||||||
|
...(rankings?.map(r => ({ ...r, type: 'ranking' })) || [])
|
||||||
].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
|
||||||
.slice(0, 15);
|
.slice(0, 15);
|
||||||
|
|
||||||
@@ -602,6 +637,14 @@ export default function Profile() {
|
|||||||
<div className="flex-shrink-0 mt-1">
|
<div className="flex-shrink-0 mt-1">
|
||||||
{activity.type === 'review' ? (
|
{activity.type === 'review' ? (
|
||||||
<Star className="w-5 h-5 text-accent" />
|
<Star className="w-5 h-5 text-accent" />
|
||||||
|
) : activity.type === 'credit' ? (
|
||||||
|
<Trophy className="w-5 h-5 text-accent" />
|
||||||
|
) : activity.type === 'submission' ? (
|
||||||
|
activity.submission_type === 'photo' ? (
|
||||||
|
<Image className="w-5 h-5 text-accent" />
|
||||||
|
) : (
|
||||||
|
<FileText className="w-5 h-5 text-accent" />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<Trophy className="w-5 h-5 text-accent" />
|
<Trophy className="w-5 h-5 text-accent" />
|
||||||
)}
|
)}
|
||||||
@@ -641,6 +684,43 @@ export default function Profile() {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
) : activity.type === 'submission' ? (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<p className="font-medium">
|
||||||
|
Submitted {activity.submission_type}
|
||||||
|
{activity.content?.name && `: ${activity.content.name}`}
|
||||||
|
</p>
|
||||||
|
{activity.status === 'pending' && (
|
||||||
|
<Badge variant="secondary" className="text-xs">Pending</Badge>
|
||||||
|
)}
|
||||||
|
{activity.status === 'approved' && (
|
||||||
|
<Badge variant="default" className="text-xs">Approved</Badge>
|
||||||
|
)}
|
||||||
|
{activity.status === 'rejected' && (
|
||||||
|
<Badge variant="destructive" className="text-xs">Rejected</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{activity.content?.description && (
|
||||||
|
<p className="text-sm text-muted-foreground line-clamp-2">
|
||||||
|
{activity.content.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : activity.type === 'ranking' ? (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<p className="font-medium">Created ranking: {activity.title}</p>
|
||||||
|
<Badge variant="outline" className="text-xs capitalize">
|
||||||
|
{activity.list_type.replace('_', ' ')}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
{activity.description && (
|
||||||
|
<p className="text-sm text-muted-foreground line-clamp-2">
|
||||||
|
{activity.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p className="font-medium mb-1">Added ride credit</p>
|
<p className="font-medium mb-1">Added ride credit</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user