refactor(api): literal-union the closed-value string fields (R7 S3a·1)
Video.status, Playlist.kind/source (+ PlaylistDetail), DownloadJob.job_kind
were bare `string`; type them as named unions verified against the backend
(VALID_STATES={new,watched,hidden}; kind user|watch_later; source local|
youtube; job_kind download|edit). VideoStatus then propagates through the
optimistic-override map, onState, and the VideoCard/VirtualFeed/PlayerModal
props — tsc now rejects a status typo (e.g. a stale "in_progress", which is a
derived filter, never a stored status) at every call site.
This commit is contained in:
@@ -18,7 +18,7 @@ import Avatar from "./Avatar";
|
||||
import AddToPlaylist from "./AddToPlaylist";
|
||||
import DownloadButton from "./DownloadButton";
|
||||
import clsx from "clsx";
|
||||
import type { Video } from "../lib/api";
|
||||
import type { Video, VideoStatus } from "../lib/api";
|
||||
import { FEED_VIEW_SPEC, type FeedView } from "../lib/feedView";
|
||||
import { formatDate, formatDuration, formatViews, relativeTime } from "../lib/format";
|
||||
|
||||
@@ -30,14 +30,14 @@ function Actions({
|
||||
dense = false,
|
||||
}: {
|
||||
video: Video;
|
||||
onState: (id: string, status: string) => void;
|
||||
onState: (id: string, status: VideoStatus) => void;
|
||||
onResetState?: (id: string) => void;
|
||||
onToggleSave: (id: string, saved: boolean) => void;
|
||||
/** Tighter buttons for the small card, whose column bottoms out at 180px. */
|
||||
dense?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const act = (status: string) => (e: React.MouseEvent) => {
|
||||
const act = (status: VideoStatus) => (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onState(video.id, video.status === status ? "new" : status);
|
||||
@@ -375,7 +375,7 @@ function VideoCard({
|
||||
view: FeedView;
|
||||
/** Measured width of this card/row, from VirtualFeed. 0 until the first measure. */
|
||||
width: number;
|
||||
onState: (id: string, status: string) => void;
|
||||
onState: (id: string, status: VideoStatus) => void;
|
||||
onResetState?: (id: string) => void;
|
||||
onToggleSave: (id: string, saved: boolean) => void;
|
||||
onOpen?: (v: Video, startAt?: number | null) => void;
|
||||
|
||||
Reference in New Issue
Block a user