diff --git a/app/[locale]/festival/_components/festival-tabs.tsx b/app/[locale]/festival/_components/festival-tabs.tsx index bfadde1..4504de1 100644 --- a/app/[locale]/festival/_components/festival-tabs.tsx +++ b/app/[locale]/festival/_components/festival-tabs.tsx @@ -30,6 +30,8 @@ export const FestivalTabs = async () => { diff --git a/app/[locale]/festival/page.tsx b/app/[locale]/festival/page.tsx index 8b3ace7..f230622 100644 --- a/app/[locale]/festival/page.tsx +++ b/app/[locale]/festival/page.tsx @@ -5,6 +5,7 @@ import { Suspense } from "react"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { FestivalTabs } from "./_components/festival-tabs"; +import { Loader2 } from "lucide-react"; type Props = { params: { locale: string; username: string }; @@ -45,7 +46,13 @@ export default function Festival({ {/*
foo
*/} - loading...}> + + + + } + > diff --git a/components/Ranking/Cadenas.tsx b/components/Ranking/Cadenas.tsx index a6ef193..4b702d7 100644 --- a/components/Ranking/Cadenas.tsx +++ b/components/Ranking/Cadenas.tsx @@ -9,11 +9,13 @@ import LoadingSkeleton from "./LoadingSkeleton"; interface Props { highlines_ids: string[]; + startDate?: Date; + endDate?: Date; } const PAGE_SIZE = 5; -function Cadenas({ highlines_ids }: Props) { +function Cadenas({ highlines_ids, startDate, endDate }: Props) { const supabase = useSupabaseBrowser(); async function fetchCadenas({ pageParam = 1 }) { @@ -21,6 +23,8 @@ function Cadenas({ highlines_ids }: Props) { highline_ids: highlines_ids, page_number: pageParam, page_size: PAGE_SIZE, + start_date: startDate?.toISOString(), + end_date: endDate?.toISOString(), }); return data; } diff --git a/components/Ranking/Distance.tsx b/components/Ranking/Distance.tsx index 77bc7ec..7e49fa5 100644 --- a/components/Ranking/Distance.tsx +++ b/components/Ranking/Distance.tsx @@ -9,18 +9,22 @@ import LoadingSkeleton from "./LoadingSkeleton"; interface Props { highlines_ids: string[]; + startDate?: Date; + endDate?: Date; } const PAGE_SIZE = 5; -function Distance({ highlines_ids }: Props) { +function Distance({ highlines_ids, startDate, endDate }: Props) { const supabase = useSupabaseBrowser(); async function fetchEntries({ pageParam = 1 }) { - const { data, error } = await supabase.rpc("get_total_walked", { + const { data } = await supabase.rpc("get_total_walked", { highline_ids: highlines_ids, page_number: pageParam, page_size: PAGE_SIZE, + start_date: startDate?.toISOString(), + end_date: endDate?.toISOString(), }); return data; } diff --git a/components/Ranking/FullLine.tsx b/components/Ranking/FullLine.tsx index 813bd39..16843a8 100644 --- a/components/Ranking/FullLine.tsx +++ b/components/Ranking/FullLine.tsx @@ -9,11 +9,13 @@ import LoadingSkeleton from "./LoadingSkeleton"; interface Props { highlines_ids: string[]; + startDate?: Date; + endDate?: Date; } const PAGE_SIZE = 5; -function FullLine({ highlines_ids }: Props) { +function FullLine({ highlines_ids, startDate, endDate }: Props) { const supabase = useSupabaseBrowser(); async function fetchFullLine({ pageParam = 1 }) { @@ -21,6 +23,8 @@ function FullLine({ highlines_ids }: Props) { highline_ids: highlines_ids, page_number: pageParam, page_size: PAGE_SIZE, + start_date: startDate?.toISOString(), + end_date: endDate?.toISOString(), }); return data; } diff --git a/components/Ranking/index.tsx b/components/Ranking/index.tsx index b3e8906..28dab91 100644 --- a/components/Ranking/index.tsx +++ b/components/Ranking/index.tsx @@ -11,6 +11,8 @@ import Speedline from "./Speedline"; interface Props { highlines_ids: string[]; visibleCategories?: Category[]; + startDate?: Date; + endDate?: Date; } export type Category = "speedline" | "distance" | "cadenas" | "fullLine"; @@ -19,17 +21,35 @@ const CategoryRenderer: React.FC< Props & { category: Category; } -> = ({ category, highlines_ids, visibleCategories }) => { +> = ({ category, highlines_ids, visibleCategories, startDate, endDate }) => { if (!visibleCategories?.includes(category)) return null; switch (category) { case "speedline": return ; case "distance": - return ; + return ( + + ); case "cadenas": - return ; + return ( + + ); case "fullLine": - return ; + return ( + + ); default: return null; } @@ -38,6 +58,8 @@ const CategoryRenderer: React.FC< export const Ranking: React.FC = ({ highlines_ids, visibleCategories = ["cadenas", "distance", "fullLine", "speedline"], // All categories visible by default, + startDate, + endDate, }) => { const { searchParams } = useQueryString(); const selectedCategory = diff --git a/supabase/migrations/20240522152724_ranking_with_date_range.sql b/supabase/migrations/20240522152724_ranking_with_date_range.sql new file mode 100644 index 0000000..1dc75b8 --- /dev/null +++ b/supabase/migrations/20240522152724_ranking_with_date_range.sql @@ -0,0 +1,84 @@ +set check_function_bodies = off; + +DROP FUNCTION IF EXISTS public.get_total_cadenas ( + highline_ids UUID[], + page_number INTEGER, + page_size INTEGER +); + +CREATE OR REPLACE FUNCTION public.get_total_cadenas(highline_ids uuid[], page_number integer, page_size integer, start_date timestamp with time zone DEFAULT NULL::timestamp with time zone, end_date timestamp with time zone DEFAULT NULL::timestamp with time zone) + RETURNS TABLE(instagram text, total_cadenas integer, profile_picture text) + LANGUAGE plpgsql +AS $function$ +BEGIN +RETURN QUERY +SELECT e.instagram, SUM(e.cadenas)::integer AS total_cadenas, COALESCE(p.profile_picture, '') AS profile_picture +FROM public.entry e +LEFT JOIN public.profiles p ON e.instagram = p.username +WHERE e.highline_id = ANY(get_total_cadenas.highline_ids) +AND (e.created_at >= COALESCE(start_date, '1970-01-01'::timestamp) OR start_date IS NULL) +AND (e.created_at <= COALESCE(end_date, now()) OR end_date IS NULL) +GROUP BY e.instagram, p.profile_picture +HAVING SUM(e.cadenas) > 0 +ORDER BY total_cadenas DESC +OFFSET (get_total_cadenas.page_number - 1) * get_total_cadenas.page_size +LIMIT get_total_cadenas.page_size; +END; +$function$ +; + +DROP FUNCTION IF EXISTS public.get_total_full_lines ( + highline_ids UUID[], + page_number INTEGER, + page_size INTEGER +); + +CREATE OR REPLACE FUNCTION public.get_total_full_lines(highline_ids uuid[], page_number integer, page_size integer, start_date timestamp with time zone DEFAULT NULL::timestamp with time zone, end_date timestamp with time zone DEFAULT NULL::timestamp with time zone) + RETURNS TABLE(instagram text, total_full_lines integer, profile_picture text) + LANGUAGE plpgsql +AS $function$ +BEGIN +RETURN QUERY +SELECT e.instagram, SUM(e.full_lines)::integer AS total_full_lines, COALESCE(p.profile_picture, '') AS profile_picture +FROM public.entry e +LEFT JOIN public.profiles p ON e.instagram = p.username +WHERE e.highline_id = ANY(get_total_full_lines.highline_ids) +AND (e.created_at >= COALESCE(start_date, '1970-01-01'::timestamp) OR start_date IS NULL) +AND (e.created_at <= COALESCE(end_date, now()) OR end_date IS NULL) +GROUP BY e.instagram, p.profile_picture +HAVING SUM(e.full_lines) > 0 +ORDER BY total_full_lines DESC +OFFSET (get_total_full_lines.page_number - 1) * get_total_full_lines.page_size +LIMIT get_total_full_lines.page_size; +END; +$function$ +; + +DROP FUNCTION IF EXISTS public.get_total_walked ( + highline_ids UUID[], + page_number INTEGER, + page_size INTEGER +); + +CREATE OR REPLACE FUNCTION public.get_total_walked(highline_ids uuid[], page_number integer, page_size integer, start_date timestamp with time zone DEFAULT NULL::timestamp with time zone, end_date timestamp with time zone DEFAULT NULL::timestamp with time zone) + RETURNS TABLE(instagram text, total_distance_walked integer, profile_picture text) + LANGUAGE plpgsql +AS $function$ +BEGIN +RETURN QUERY +SELECT e.instagram, SUM(e.distance_walked)::integer AS total_distance_walked, COALESCE(p.profile_picture, '') AS profile_picture +FROM public.entry e +LEFT JOIN public.profiles p ON e.instagram = p.username +WHERE e.highline_id = ANY(get_total_walked.highline_ids) +AND (e.created_at >= COALESCE(start_date, '1970-01-01'::timestamp) OR start_date IS NULL) +AND (e.created_at <= COALESCE(end_date, now()) OR end_date IS NULL) +AND e.distance_walked IS NOT NULL +GROUP BY e.instagram, p.profile_picture +ORDER BY total_distance_walked DESC +OFFSET (get_total_walked.page_number - 1) * get_total_walked.page_size +LIMIT page_size; +END; +$function$ +; + + diff --git a/utils/supabase/database.types.ts b/utils/supabase/database.types.ts index 7bc2f09..47e5b14 100644 --- a/utils/supabase/database.types.ts +++ b/utils/supabase/database.types.ts @@ -264,6 +264,8 @@ export type Database = { highline_ids: string[]; page_number: number; page_size: number; + start_date?: string; + end_date?: string; }; Returns: { instagram: string; @@ -276,6 +278,8 @@ export type Database = { highline_ids: string[]; page_number: number; page_size: number; + start_date?: string; + end_date?: string; }; Returns: { instagram: string; @@ -288,6 +292,8 @@ export type Database = { highline_ids: string[]; page_number: number; page_size: number; + start_date?: string; + end_date?: string; }; Returns: { instagram: string;