mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 15:51:13 -05:00
Add contributor leaderboard
Add types, hook, UI components, and integration for leaderboard showing top users with badges
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
-- Create function to get contributor leaderboard
|
||||
CREATE OR REPLACE FUNCTION public.get_contributor_leaderboard(
|
||||
limit_count integer DEFAULT 50,
|
||||
time_period text DEFAULT 'all_time' -- 'all_time', 'month', 'week'
|
||||
)
|
||||
RETURNS jsonb
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
result jsonb;
|
||||
date_filter timestamp;
|
||||
BEGIN
|
||||
-- Determine date filter based on time period
|
||||
CASE time_period
|
||||
WHEN 'week' THEN date_filter := NOW() - INTERVAL '7 days';
|
||||
WHEN 'month' THEN date_filter := NOW() - INTERVAL '30 days';
|
||||
ELSE date_filter := '1970-01-01'::timestamp;
|
||||
END CASE;
|
||||
|
||||
WITH contributor_stats AS (
|
||||
SELECT
|
||||
p.user_id,
|
||||
p.username,
|
||||
p.display_name,
|
||||
p.avatar_url,
|
||||
p.created_at as join_date,
|
||||
|
||||
-- Count approved submissions by type
|
||||
COALESCE(SUM(CASE WHEN es.entity_type = 'park' AND es.status = 'approved' AND es.created_at >= date_filter THEN 1 ELSE 0 END), 0) as parks_added,
|
||||
COALESCE(SUM(CASE WHEN es.entity_type = 'ride' AND es.status = 'approved' AND es.created_at >= date_filter THEN 1 ELSE 0 END), 0) as rides_added,
|
||||
COALESCE(SUM(CASE WHEN es.entity_type = 'company' AND es.status = 'approved' AND es.created_at >= date_filter THEN 1 ELSE 0 END), 0) as companies_added,
|
||||
COALESCE(SUM(CASE WHEN es.entity_type = 'ride_model' AND es.status = 'approved' AND es.created_at >= date_filter THEN 1 ELSE 0 END), 0) as models_added,
|
||||
|
||||
-- Count photos
|
||||
COALESCE((
|
||||
SELECT COUNT(*)
|
||||
FROM entity_photos ep
|
||||
WHERE ep.uploaded_by = p.user_id
|
||||
AND ep.status = 'approved'
|
||||
AND ep.created_at >= date_filter
|
||||
), 0) as photos_added,
|
||||
|
||||
-- Count reviews
|
||||
COALESCE((
|
||||
SELECT COUNT(*)
|
||||
FROM reviews r
|
||||
WHERE r.user_id = p.user_id
|
||||
AND r.status = 'approved'
|
||||
AND r.created_at >= date_filter
|
||||
), 0) as reviews_added,
|
||||
|
||||
-- Count edits (from entity_history)
|
||||
COALESCE((
|
||||
SELECT COUNT(*)
|
||||
FROM entity_history eh
|
||||
WHERE eh.changed_by = p.user_id
|
||||
AND eh.created_at >= date_filter
|
||||
), 0) as edits_made,
|
||||
|
||||
-- All-time stats for achievements
|
||||
COALESCE((SELECT COUNT(*) FROM entity_submissions WHERE user_id = p.user_id AND status = 'approved' AND entity_type = 'park'), 0) as total_parks,
|
||||
COALESCE((SELECT COUNT(*) FROM entity_submissions WHERE user_id = p.user_id AND status = 'approved' AND entity_type = 'ride'), 0) as total_rides,
|
||||
COALESCE((SELECT COUNT(*) FROM entity_photos WHERE uploaded_by = p.user_id AND status = 'approved'), 0) as total_photos,
|
||||
COALESCE((SELECT COUNT(*) FROM reviews WHERE user_id = p.user_id AND status = 'approved'), 0) as total_reviews,
|
||||
COALESCE((SELECT COUNT(*) FROM entity_history WHERE changed_by = p.user_id), 0) as total_edits
|
||||
|
||||
FROM profiles p
|
||||
LEFT JOIN entity_submissions es ON es.user_id = p.user_id
|
||||
WHERE p.user_id IS NOT NULL
|
||||
GROUP BY p.user_id, p.username, p.display_name, p.avatar_url, p.created_at
|
||||
),
|
||||
|
||||
scored_contributors AS (
|
||||
SELECT
|
||||
*,
|
||||
-- Calculate contribution score (weighted)
|
||||
(parks_added * 10) +
|
||||
(rides_added * 8) +
|
||||
(companies_added * 5) +
|
||||
(models_added * 5) +
|
||||
(photos_added * 2) +
|
||||
(reviews_added * 3) +
|
||||
(edits_made * 1) as contribution_score,
|
||||
|
||||
(total_parks * 10) +
|
||||
(total_rides * 8) +
|
||||
(total_photos * 2) +
|
||||
(total_reviews * 3) +
|
||||
(total_edits * 1) as total_score
|
||||
|
||||
FROM contributor_stats
|
||||
),
|
||||
|
||||
ranked_contributors AS (
|
||||
SELECT
|
||||
*,
|
||||
ROW_NUMBER() OVER (ORDER BY contribution_score DESC, total_score DESC, join_date ASC) as rank,
|
||||
|
||||
-- Determine achievement level
|
||||
CASE
|
||||
WHEN total_score >= 5000 THEN 'legend'
|
||||
WHEN total_score >= 1000 THEN 'platinum'
|
||||
WHEN total_score >= 500 THEN 'gold'
|
||||
WHEN total_score >= 100 THEN 'silver'
|
||||
WHEN total_score >= 10 THEN 'bronze'
|
||||
ELSE 'newcomer'
|
||||
END as achievement_level,
|
||||
|
||||
-- Calculate special badges
|
||||
jsonb_build_array(
|
||||
CASE WHEN total_parks >= 100 THEN 'park_explorer' END,
|
||||
CASE WHEN total_rides >= 200 THEN 'ride_master' END,
|
||||
CASE WHEN total_photos >= 500 THEN 'photographer' END,
|
||||
CASE WHEN total_reviews >= 100 THEN 'critic' END,
|
||||
CASE WHEN total_edits >= 500 THEN 'editor' END,
|
||||
CASE WHEN total_parks >= 10 AND total_rides >= 50 AND total_photos >= 100 THEN 'completionist' END,
|
||||
CASE WHEN EXTRACT(days FROM (NOW() - join_date)) >= 365 THEN 'veteran' END,
|
||||
CASE WHEN rank = 1 THEN 'top_contributor' END
|
||||
) - 'null'::jsonb as special_badges
|
||||
|
||||
FROM scored_contributors
|
||||
WHERE contribution_score > 0 OR total_score > 0
|
||||
)
|
||||
|
||||
SELECT jsonb_build_object(
|
||||
'contributors', (
|
||||
SELECT jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'rank', rank,
|
||||
'user_id', user_id,
|
||||
'username', username,
|
||||
'display_name', display_name,
|
||||
'avatar_url', avatar_url,
|
||||
'join_date', join_date,
|
||||
'contribution_score', contribution_score,
|
||||
'total_score', total_score,
|
||||
'achievement_level', achievement_level,
|
||||
'special_badges', special_badges,
|
||||
'stats', jsonb_build_object(
|
||||
'parks_added', parks_added,
|
||||
'rides_added', rides_added,
|
||||
'companies_added', companies_added,
|
||||
'models_added', models_added,
|
||||
'photos_added', photos_added,
|
||||
'reviews_added', reviews_added,
|
||||
'edits_made', edits_made
|
||||
),
|
||||
'total_stats', jsonb_build_object(
|
||||
'total_parks', total_parks,
|
||||
'total_rides', total_rides,
|
||||
'total_photos', total_photos,
|
||||
'total_reviews', total_reviews,
|
||||
'total_edits', total_edits
|
||||
)
|
||||
)
|
||||
ORDER BY rank
|
||||
)
|
||||
FROM ranked_contributors
|
||||
LIMIT limit_count
|
||||
),
|
||||
'total_contributors', (SELECT COUNT(*) FROM ranked_contributors),
|
||||
'generated_at', NOW()
|
||||
) INTO result;
|
||||
|
||||
RETURN result;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Grant execute permission to authenticated users
|
||||
GRANT EXECUTE ON FUNCTION public.get_contributor_leaderboard(integer, text) TO authenticated;
|
||||
Reference in New Issue
Block a user