feat: implement authentication context and hooks for user management
- Add AuthContext to manage user authentication state and token storage. - Create hooks for login, registration, and logout functionalities. - Implement dashboard layout with authentication check and loading state. - Enhance dashboard page with channel management features including create, edit, and delete channels. - Integrate API calls for channel operations and current broadcast retrieval. - Add stream URL resolution via server-side API route to handle redirects. - Update TV page to utilize new hooks for channel and broadcast management. - Refactor components for better organization and user experience. - Update application metadata for improved branding.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import Link from "next/link";
|
||||
import { Pencil, Trash2, RefreshCw, Tv2 } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import type { ChannelResponse } from "@/lib/types";
|
||||
|
||||
interface ChannelCardProps {
|
||||
channel: ChannelResponse;
|
||||
isGenerating: boolean;
|
||||
onEdit: () => void;
|
||||
onDelete: () => void;
|
||||
onGenerateSchedule: () => void;
|
||||
}
|
||||
|
||||
export function ChannelCard({
|
||||
channel,
|
||||
isGenerating,
|
||||
onEdit,
|
||||
onDelete,
|
||||
onGenerateSchedule,
|
||||
}: ChannelCardProps) {
|
||||
const blockCount = channel.schedule_config.blocks.length;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 rounded-xl border border-zinc-800 bg-zinc-900 p-5 transition-colors hover:border-zinc-700">
|
||||
{/* Top row */}
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0 space-y-1">
|
||||
<h2 className="truncate text-base font-semibold text-zinc-100">
|
||||
{channel.name}
|
||||
</h2>
|
||||
{channel.description && (
|
||||
<p className="line-clamp-2 text-sm text-zinc-500">
|
||||
{channel.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={onEdit}
|
||||
title="Edit channel"
|
||||
>
|
||||
<Pencil className="size-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={onDelete}
|
||||
title="Delete channel"
|
||||
className="text-zinc-600 hover:text-red-400"
|
||||
>
|
||||
<Trash2 className="size-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Meta */}
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-zinc-500">
|
||||
<span>
|
||||
<span className="text-zinc-400">{channel.timezone}</span>
|
||||
</span>
|
||||
<span>
|
||||
{blockCount} {blockCount === 1 ? "block" : "blocks"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={onGenerateSchedule}
|
||||
disabled={isGenerating}
|
||||
className="flex-1"
|
||||
>
|
||||
<RefreshCw
|
||||
className={`size-3.5 ${isGenerating ? "animate-spin" : ""}`}
|
||||
/>
|
||||
{isGenerating ? "Generating…" : "Generate schedule"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
asChild
|
||||
title="Watch on TV"
|
||||
className="border-zinc-700 text-zinc-400 hover:text-zinc-100"
|
||||
>
|
||||
<Link href="/tv">
|
||||
<Tv2 className="size-3.5" />
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user