From 7b07c7d04a80d45023bc086cc6d5dc593fc059ca Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Wed, 22 Apr 2026 13:47:34 -0400 Subject: [PATCH] feat: restore request flow in dashboard --- .../components/SearchRequestModal.tsx | 104 ++++++++++++++++++ frontend/src/app/dashboard/page.tsx | 13 +++ 2 files changed, 117 insertions(+) create mode 100644 frontend/src/app/dashboard/components/SearchRequestModal.tsx diff --git a/frontend/src/app/dashboard/components/SearchRequestModal.tsx b/frontend/src/app/dashboard/components/SearchRequestModal.tsx new file mode 100644 index 0000000..5b8cef4 --- /dev/null +++ b/frontend/src/app/dashboard/components/SearchRequestModal.tsx @@ -0,0 +1,104 @@ +"use client"; + +import { useState } from "react"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { api } from "@/lib/api"; + +export function SearchRequestModal({ + open, + onOpenChange, + costs, +}: { + open: boolean; + onOpenChange: (open: boolean) => void; + costs: { movie: number; tv: number }; +}) { + const [query, setQuery] = useState(""); + const [results, setResults] = useState([]); + const [loading, setLoading] = useState(false); + + const search = async () => { + setLoading(true); + try { + const res = await api.get( + `/overseer/search?query=${encodeURIComponent(query)}`, + ); + setResults(res.data?.results || res.data || []); + } catch { + toast.error("Search failed"); + } finally { + setLoading(false); + } + }; + + const request = async (item: any, mediaType: string) => { + try { + await api.post("/overseer/request", { + mediaType, + mediaId: item.id || item.tmdbId, + title: item.title || item.name, + seasons: item.seasons, + }); + toast.success("Request sent"); + onOpenChange(false); + } catch (e: any) { + toast.error(e?.response?.data?.error || "Request failed"); + } + }; + + return ( + + + + Request content + + Search and send request. Movie cost {costs.movie}. TV cost{" "} + {costs.tv}. + + +
+ setQuery(e.target.value)} + placeholder="Search movie or show" + /> + +
+ {results.map((r) => ( +
+
+
{r.title || r.name}
+
+ {r.media_type || r.mediaType} +
+
+ +
+ ))} +
+
+
+
+ ); +} diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx index 0d4eb4f..085ef9c 100644 --- a/frontend/src/app/dashboard/page.tsx +++ b/frontend/src/app/dashboard/page.tsx @@ -10,6 +10,7 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api, overseerApi } from "@/lib/api"; import { useSocket } from "@/lib/socket"; @@ -18,6 +19,7 @@ import { formatNumber } from "@/lib/utils"; import { ActivityFeed } from "./components/ActivityFeed"; import { Leaderboard } from "./components/Leaderboard"; import { RequestHistory } from "./components/RequestHistory"; +import { SearchRequestModal } from "./components/SearchRequestModal"; import { WatchHistory } from "./components/WatchHistory"; interface WalletData { @@ -32,6 +34,7 @@ export default function DashboardPage() { const [wallet, setWallet] = useState(null); const [requestCosts, setRequestCosts] = useState({ movie: 500, tv: 1000 }); const [isLoading, setIsLoading] = useState(true); + const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); const socket = useSocket(); useEffect(() => { @@ -101,6 +104,11 @@ export default function DashboardPage() { +
+ +
@@ -123,6 +131,11 @@ export default function DashboardPage() { +
); }