/** * Renders the header of a playlist's page, with its cover, title, description, * visibility, owner, dates and categories. * * @module */ import { Link } from "react-router"; import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { API_URL } from "../../config/api.ts"; import { VALIDATION } from "../../../shared/validation.ts"; import type { Wire } from "../../../shared/api.ts"; import type { Playlist, PlaylistWithDumps, UpdatePlaylistRequest, } from "../../../shared/playlist.ts"; import { expectOk } from "../../utils/shared/api.ts"; import { deserializePlaylist } from "../../utils/shared/deserialize.ts"; import { imageProps, playlistImageUrl } from "../../utils/shared/urls.ts"; import { IMAGE_SIZES } from "../../config/imageSizes.ts"; import { relativeTime } from "../../utils/shared/relativeTime.ts"; import { useAuth } from "../../hooks/auth/useAuth.ts"; import { Markdown } from "../editor/Markdown.tsx"; import { InlineEdit } from "../form/InlineEdit.tsx"; import { FollowPlaylistButton } from "../social/FollowButton.tsx"; import { Tooltip } from "../shared/Tooltip.tsx"; import { CategoryChips } from "../category/CategoryChips.tsx"; import { userPath } from "../../../shared/paths.ts"; /** Passed to {@link PlaylistHeader} by `PlaylistDetail`. */ export interface PlaylistHeaderProps { playlist: PlaylistWithDumps; /** * Given to those who may edit it, with `onSaved`: it adds an "Edit" button, * which opens `PlaylistEditForm`. */ onEdit?: () => void; /** * Called with the playlist as the server has it once its title or * description is edited in place, which it lets its editors do. */ onSaved?: (playlist: Playlist) => void; } /** * Renders the playlist's details, with a follow button for anyone but its * owner. Its editors change the title and the description in place, saved to * `PUT /api/playlists/:playlistId`, and the rest in `PlaylistEditForm`, which * takes the header's place while it is open. */ export function PlaylistHeader( { playlist, onEdit, onSaved }: PlaylistHeaderProps, ): React.JSX.Element { const { user, mediaToken, authFetch } = useAuth(); const save = async (changes: UpdatePlaylistRequest) => { const updated = await expectOk>( await authFetch(`${API_URL}/api/playlists/${playlist.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(changes), }), ); onSaved?.(deserializePlaylist(updated)); }; return ( <> {playlist.imageMime && ( )}
save({ title })} required maxLength={VALIDATION.PLAYLIST_TITLE_MAX} fieldClassName="playlist-detail-title" >

{playlist.title}

{user?.id !== playlist.userId && ( )} {onEdit && ( )}
{(playlist.description || onSaved) && ( save({ description: description || null })} kind="markdown" maxLength={VALIDATION.PLAYLIST_DESCRIPTION_MAX} placeholder={t`Add a description…`} > {playlist.description ? ( {playlist.description} ) : (

Add a description…

)}
)}
{playlist.isPublic ? public : private} {playlist.ownerUsername && ( @{playlist.ownerUsername} )} {playlist.updatedAt && ( edited {relativeTime(playlist.updatedAt)} )}
); }