"use client";
import { useProgress } from "@bprogress/next";
import { Lock, Logs, Unlock } from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import {
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { shared } from "@/lib/comms";
import { sse } from "@/lib/db/sse-endpoints";
import { cn } from "@/lib/utils";
import { setFree, setLimit, toggleCheck, toggleLock } from "../api";
export function SidebarLink({
submission,
className,
prefetch = true,
}: {
submission: { id: string; name: string; checked: boolean; queue: number };
className?: string;
prefetch?: boolean;
}) {
const { stop } = useProgress();
const { id } = useParams();
const [checked, setChecked] = useState(submission.checked);
useEffect(() => {
setChecked(submission.checked);
}, [submission.checked]);
return (
{
if ((ev.target as HTMLButtonElement).type === "button") {
ev.preventDefault();
}
}}
>
{submission.queue}. {submission.name}
{
setChecked((x) => !x);
await toggleCheck(submission.id);
stop();
}}
/>
);
}
export function LimitManager({
config,
length,
...props
}: React.ComponentProps & {
config: Awaited>;
length: number;
}) {
const [dialog, setDialog] = useState(1);
return (
{length}
{config.limit >= 0 ? `/${config.limit}` : ""}
{config.free > 0 ? ` (เหลือคิวฟรี ${config.free})` : ""}
);
}
export function SubmissionList({
subs,
}: {
subs: {
id: string;
name: string;
checked: boolean;
queue: number;
publicQueue: number;
paid: boolean;
archived: boolean;
}[];
}) {
const [query, setQuery] = useState("");
const [debug] = shared.state("debug");
const bottomRef = useRef(null);
useEffect(() => {
void debug;
// Scrolls to the dummy div whenever 'items' changes
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [debug]);
return (
<>
setQuery(ev.target.value.toLowerCase())}
/>
{subs
.filter(
(s) =>
(debug || (s.paid && !s.archived)) &&
(s.queue + s.name).toLowerCase().includes(query),
)
.map((s) => (
))}
>
);
}
export function Watcher() {
const router = useRouter();
const count = useRef(undefined);
// Reload after connection restored
shared.signal("sync", () => router.refresh());
useEffect(() => {
const { clean } = sse.rubgram.sub("update", () => router.refresh());
const interval = setInterval(() => {
fetch("/api/rubgram/count")
.then((r) => r.json())
.then((r) => {
if (typeof count.current === "undefined") count.current = r;
if (count.current !== r) router.refresh();
count.current = r;
})
.catch((e) => console.error("Fetching rubgram count failed", e));
}, 60000);
return () => {
clean();
clearInterval(interval);
};
}, [router]);
return ;
}
export function SlipButton() {
return (
All time คิว
);
}