refactor(guide): improve code formatting and readability in page.tsx
This commit is contained in:
@@ -13,7 +13,10 @@ import type { ChannelResponse, ScheduledSlotResponse } from "@/lib/types";
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function fmtTime(iso: string) {
|
||||
return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
||||
return new Date(iso).toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
function fmtDuration(secs: number) {
|
||||
@@ -27,7 +30,9 @@ function slotLabel(slot: ScheduledSlotResponse) {
|
||||
if (item.content_type === "episode" && item.series_name) {
|
||||
const ep = [
|
||||
item.season_number != null ? `S${item.season_number}` : "",
|
||||
item.episode_number != null ? `E${String(item.episode_number).padStart(2, "0")}` : "",
|
||||
item.episode_number != null
|
||||
? `E${String(item.episode_number).padStart(2, "0")}`
|
||||
: "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("");
|
||||
@@ -45,7 +50,13 @@ function slotLabel(slot: ScheduledSlotResponse) {
|
||||
function ChannelRow({ channel }: { channel: ChannelResponse }) {
|
||||
const { token, isLoaded } = useAuthContext();
|
||||
|
||||
const { data: slots, isError, error, isPending, isFetching } = useQuery({
|
||||
const {
|
||||
data: slots,
|
||||
isError,
|
||||
error,
|
||||
isPending,
|
||||
isFetching,
|
||||
} = useQuery({
|
||||
queryKey: ["guide-epg", channel.id, token],
|
||||
queryFn: () => {
|
||||
const now = new Date();
|
||||
@@ -62,13 +73,17 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
|
||||
|
||||
const current = slots?.find(
|
||||
(s) =>
|
||||
new Date(s.start_at).getTime() <= now && now < new Date(s.end_at).getTime(),
|
||||
new Date(s.start_at).getTime() <= now &&
|
||||
now < new Date(s.end_at).getTime(),
|
||||
);
|
||||
const upcoming = slots?.filter((s) => new Date(s.start_at).getTime() > now).slice(0, 3) ?? [];
|
||||
const upcoming =
|
||||
slots?.filter((s) => new Date(s.start_at).getTime() > now).slice(0, 3) ??
|
||||
[];
|
||||
|
||||
const progress = current
|
||||
? (now - new Date(current.start_at).getTime()) /
|
||||
(new Date(current.end_at).getTime() - new Date(current.start_at).getTime())
|
||||
(new Date(current.end_at).getTime() -
|
||||
new Date(current.start_at).getTime())
|
||||
: 0;
|
||||
|
||||
const remaining = current
|
||||
@@ -81,7 +96,9 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
|
||||
<div className="flex items-center justify-between border-b border-zinc-800 px-4 py-3">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<Tv className="size-3.5 shrink-0 text-zinc-600" />
|
||||
<span className="truncate text-sm font-semibold text-zinc-100">{channel.name}</span>
|
||||
<span className="truncate text-sm font-semibold text-zinc-100">
|
||||
{channel.name}
|
||||
</span>
|
||||
{channel.description && (
|
||||
<span className="hidden truncate text-xs text-zinc-600 sm:block">
|
||||
— {channel.description}
|
||||
@@ -102,26 +119,32 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex items-baseline justify-between gap-4">
|
||||
<div className="flex min-w-0 items-baseline gap-2">
|
||||
<span className="shrink-0 rounded bg-red-600/20 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-red-400">
|
||||
<span className="shrink-0 rounded bg-primary/20 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-primary-foreground">
|
||||
Now
|
||||
</span>
|
||||
<span className="truncate text-sm font-medium text-zinc-100">
|
||||
{slotLabel(current)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="shrink-0 text-xs text-zinc-500">{remaining}m left</span>
|
||||
<span className="shrink-0 text-xs text-zinc-500">
|
||||
{remaining}m left
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-1 w-full overflow-hidden rounded-full bg-zinc-800">
|
||||
<div
|
||||
className="h-full rounded-full bg-red-600 transition-all duration-1000"
|
||||
className="h-full rounded-full bg-primary transition-all duration-1000"
|
||||
style={{ width: `${Math.round(progress * 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : isPending && isFetching ? (
|
||||
<p className="text-xs italic text-zinc-600">Loading…</p>
|
||||
) : isError && error instanceof ApiRequestError && error.status === 401 ? (
|
||||
<p className="text-xs italic text-zinc-600">Sign in to view this channel</p>
|
||||
) : isError &&
|
||||
error instanceof ApiRequestError &&
|
||||
error.status === 401 ? (
|
||||
<p className="text-xs italic text-zinc-600">
|
||||
Sign in to view this channel
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-xs italic text-zinc-600">
|
||||
{isError || !slots?.length
|
||||
@@ -134,12 +157,17 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
|
||||
{upcoming.length > 0 && (
|
||||
<ul className="space-y-1.5 border-t border-zinc-800 pt-2.5">
|
||||
{upcoming.map((slot) => (
|
||||
<li key={slot.id} className="flex items-baseline justify-between gap-4">
|
||||
<li
|
||||
key={slot.id}
|
||||
className="flex items-baseline justify-between gap-4"
|
||||
>
|
||||
<div className="flex min-w-0 items-baseline gap-2">
|
||||
<span className="shrink-0 font-mono text-[11px] text-zinc-500">
|
||||
{fmtTime(slot.start_at)}
|
||||
</span>
|
||||
<span className="truncate text-xs text-zinc-400">{slotLabel(slot)}</span>
|
||||
<span className="truncate text-xs text-zinc-400">
|
||||
{slotLabel(slot)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="shrink-0 font-mono text-[11px] text-zinc-600">
|
||||
{fmtDuration(slot.item.duration_secs)}
|
||||
@@ -161,7 +189,10 @@ export default function GuidePage() {
|
||||
const { data: channels, isLoading } = useChannels();
|
||||
|
||||
const now = new Date();
|
||||
const timeLabel = now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
||||
const timeLabel = now.toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
const dateLabel = now.toLocaleDateString([], {
|
||||
weekday: "long",
|
||||
month: "long",
|
||||
|
||||
Reference in New Issue
Block a user