From a95be0b1311688cc9ef80cf3c7651e70bcbbf657 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 11 Jun 2026 12:39:14 +0200 Subject: [PATCH] feat: add search input on user profile pages --- spa/src/components/profile-view.tsx | 33 ++++++++++++++++++++++++----- spa/src/lib/api/users.ts | 1 + spa/src/routes/_app/profile.tsx | 4 ++++ spa/src/routes/_app/users.$id.tsx | 5 +++++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/spa/src/components/profile-view.tsx b/spa/src/components/profile-view.tsx index de9405a..ab71082 100644 --- a/spa/src/components/profile-view.tsx +++ b/spa/src/components/profile-view.tsx @@ -2,11 +2,12 @@ import { Link } from "@tanstack/react-router" import { useCallback } from "react" import { useTranslation } from "react-i18next" import { Bar, BarChart, XAxis, YAxis } from "recharts" -import { User } from "lucide-react" +import { Search, User } from "lucide-react" import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ui/chart" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Skeleton } from "@/components/ui/skeleton" +import { Input } from "@/components/ui/input" import { MovieCard } from "@/components/movie-card" import { EmptyState } from "@/components/empty-state" import { SwipeTabs } from "@/components/swipe-tabs" @@ -19,6 +20,8 @@ type ProfileViewProps = { actions?: React.ReactNode headerRight?: React.ReactNode userId?: string + search?: string + onSearchChange?: (value: string) => void } export function ProfileView({ @@ -26,6 +29,8 @@ export function ProfileView({ actions, headerRight, userId, + search, + onSearchChange, }: ProfileViewProps) { const { t } = useTranslation() const initial = (data.username || "?")[0]?.toUpperCase() ?? "?" @@ -72,6 +77,18 @@ export function ProfileView({ + {onSearchChange && ( +
+ + onSearchChange(e.target.value)} + className="pl-9" + /> +
+ )} + {actions} ( <> {tab === "recent" && ( - + )} {tab === "top_rated" && ( )} {tab === "trends" && } @@ -108,19 +126,24 @@ function StatCell({ label, value }: { label: string; value: string | number }) { ) } -function DiaryTab({ sortBy }: { sortBy: string; userId?: string }) { +function DiaryTab({ sortBy, search }: { sortBy: string; userId?: string; search?: string }) { const { t } = useTranslation() const { data, isPending, hasNextPage, isFetchingNextPage, fetchNextPage } = useInfiniteDiary({ sort_by: sortBy, movie_id: undefined }) const items = data?.pages.flatMap((p) => p.items) ?? [] + const filtered = search + ? items.filter((e) => + e.movie.title.toLowerCase().includes(search.toLowerCase()) + ) + : items const loadMore = useCallback(() => fetchNextPage(), [fetchNextPage]) if (isPending) return - if (!items.length) return + if (!filtered.length) return return ( diff --git a/spa/src/routes/_app/profile.tsx b/spa/src/routes/_app/profile.tsx index a9e580d..694092d 100644 --- a/spa/src/routes/_app/profile.tsx +++ b/spa/src/routes/_app/profile.tsx @@ -24,6 +24,8 @@ function ProfilePage() { view: "trends", }) + const [search, setSearch] = useState("") + if (!auth) return null if (isPending) return if (!data) return null @@ -39,6 +41,8 @@ function ProfilePage() { diff --git a/spa/src/routes/_app/users.$id.tsx b/spa/src/routes/_app/users.$id.tsx index bbcda23..88c5f04 100644 --- a/spa/src/routes/_app/users.$id.tsx +++ b/spa/src/routes/_app/users.$id.tsx @@ -1,4 +1,5 @@ import { createFileRoute } from "@tanstack/react-router" +import { useState } from "react" import { useTranslation } from "react-i18next" import { UserCheck, UserPlus } from "lucide-react" import { BackButton } from "@/components/back-button" @@ -22,6 +23,8 @@ function UserProfilePage() { const followMutation = useFollow() const unfollowMutation = useUnfollow() + const [search, setSearch] = useState("") + if (isPending) return if (!data) return null @@ -35,6 +38,8 @@ function UserProfilePage() {