refactor(guide): improve code formatting and readability in page.tsx

This commit is contained in:
2026-03-14 03:02:53 +01:00
parent c189056003
commit 9b6bcfc566

View File

@@ -13,7 +13,10 @@ import type { ChannelResponse, ScheduledSlotResponse } from "@/lib/types";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function fmtTime(iso: string) { 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) { function fmtDuration(secs: number) {
@@ -27,7 +30,9 @@ function slotLabel(slot: ScheduledSlotResponse) {
if (item.content_type === "episode" && item.series_name) { if (item.content_type === "episode" && item.series_name) {
const ep = [ const ep = [
item.season_number != null ? `S${item.season_number}` : "", 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) .filter(Boolean)
.join(""); .join("");
@@ -45,7 +50,13 @@ function slotLabel(slot: ScheduledSlotResponse) {
function ChannelRow({ channel }: { channel: ChannelResponse }) { function ChannelRow({ channel }: { channel: ChannelResponse }) {
const { token, isLoaded } = useAuthContext(); 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], queryKey: ["guide-epg", channel.id, token],
queryFn: () => { queryFn: () => {
const now = new Date(); const now = new Date();
@@ -62,13 +73,17 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
const current = slots?.find( const current = slots?.find(
(s) => (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 const progress = current
? (now - new Date(current.start_at).getTime()) / ? (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; : 0;
const remaining = current 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 items-center justify-between border-b border-zinc-800 px-4 py-3">
<div className="flex min-w-0 items-center gap-2"> <div className="flex min-w-0 items-center gap-2">
<Tv className="size-3.5 shrink-0 text-zinc-600" /> <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 && ( {channel.description && (
<span className="hidden truncate text-xs text-zinc-600 sm:block"> <span className="hidden truncate text-xs text-zinc-600 sm:block">
{channel.description} {channel.description}
@@ -102,26 +119,32 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
<div className="space-y-1.5"> <div className="space-y-1.5">
<div className="flex items-baseline justify-between gap-4"> <div className="flex items-baseline justify-between gap-4">
<div className="flex min-w-0 items-baseline gap-2"> <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 Now
</span> </span>
<span className="truncate text-sm font-medium text-zinc-100"> <span className="truncate text-sm font-medium text-zinc-100">
{slotLabel(current)} {slotLabel(current)}
</span> </span>
</div> </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>
<div className="h-1 w-full overflow-hidden rounded-full bg-zinc-800"> <div className="h-1 w-full overflow-hidden rounded-full bg-zinc-800">
<div <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)}%` }} style={{ width: `${Math.round(progress * 100)}%` }}
/> />
</div> </div>
</div> </div>
) : isPending && isFetching ? ( ) : isPending && isFetching ? (
<p className="text-xs italic text-zinc-600">Loading</p> <p className="text-xs italic text-zinc-600">Loading</p>
) : isError && error instanceof ApiRequestError && error.status === 401 ? ( ) : isError &&
<p className="text-xs italic text-zinc-600">Sign in to view this channel</p> 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"> <p className="text-xs italic text-zinc-600">
{isError || !slots?.length {isError || !slots?.length
@@ -134,12 +157,17 @@ function ChannelRow({ channel }: { channel: ChannelResponse }) {
{upcoming.length > 0 && ( {upcoming.length > 0 && (
<ul className="space-y-1.5 border-t border-zinc-800 pt-2.5"> <ul className="space-y-1.5 border-t border-zinc-800 pt-2.5">
{upcoming.map((slot) => ( {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"> <div className="flex min-w-0 items-baseline gap-2">
<span className="shrink-0 font-mono text-[11px] text-zinc-500"> <span className="shrink-0 font-mono text-[11px] text-zinc-500">
{fmtTime(slot.start_at)} {fmtTime(slot.start_at)}
</span> </span>
<span className="truncate text-xs text-zinc-400">{slotLabel(slot)}</span> <span className="truncate text-xs text-zinc-400">
{slotLabel(slot)}
</span>
</div> </div>
<span className="shrink-0 font-mono text-[11px] text-zinc-600"> <span className="shrink-0 font-mono text-[11px] text-zinc-600">
{fmtDuration(slot.item.duration_secs)} {fmtDuration(slot.item.duration_secs)}
@@ -161,7 +189,10 @@ export default function GuidePage() {
const { data: channels, isLoading } = useChannels(); const { data: channels, isLoading } = useChannels();
const now = new Date(); 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([], { const dateLabel = now.toLocaleDateString([], {
weekday: "long", weekday: "long",
month: "long", month: "long",