"use client"; import { Bot, Check, ChevronDown } from "lucide-react"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useMemo, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { useAnonymousMode } from "@/contexts/anonymous-mode"; import type { AnonModel } from "@/contracts/types/anonymous-chat.types"; import { anonymousChatApiService } from "@/lib/apis/anonymous-chat-api.service"; import { getProviderIcon } from "@/lib/provider-icons"; import { cn } from "@/lib/utils"; export function FreeModelSelector({ className }: { className?: string }) { const router = useRouter(); const anonMode = useAnonymousMode(); const currentSlug = anonMode.isAnonymous ? anonMode.modelSlug : ""; const [open, setOpen] = useState(false); const [models, setModels] = useState([]); useEffect(() => { const controller = new AbortController(); anonymousChatApiService .getModels() .then((data) => { if (!controller.signal.aborted) setModels(data); }) .catch((err) => { if (!controller.signal.aborted) console.error(err); }); return () => controller.abort(); }, []); const currentModel = useMemo( () => models.find((m) => m.seo_slug === currentSlug) ?? null, [models, currentSlug] ); // Free models first, premium last; immutable sort to avoid mutating state. const sortedModels = useMemo( () => models.toSorted((a, b) => Number(a.is_premium) - Number(b.is_premium)), [models] ); const handleSelect = useCallback( (model: AnonModel) => { setOpen(false); if (model.seo_slug === currentSlug) return; if (anonMode.isAnonymous) { anonMode.setModelSlug(model.seo_slug ?? ""); anonMode.resetChat(); } router.replace(`/free/${model.seo_slug}`); }, [currentSlug, anonMode, router] ); return ( (value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0)} > No models found. {sortedModels.map((model) => { const isSelected = model.seo_slug === currentSlug; return ( handleSelect(model)} className="gap-2.5" >
{getProviderIcon(model.provider, { className: "size-5" })}
{model.name} {model.is_premium ? "Premium" : "Free"}
{model.model_name}
{isSelected && }
); })}
); }