UNPKG

sanity-plugin-wistia-input

Version:
316 lines (315 loc) 12.6 kB
import { setIfMissing, set, definePlugin } from "sanity"; import { jsx, jsxs } from "react/jsx-runtime"; import { useState, useEffect, useCallback } from "react"; import { Box, Card, Text, Menu, Flex, Spinner, MenuItem, Tooltip, Heading, MenuButton, MenuDivider, Button, useToast, Dialog } from "@sanity/ui"; import { LockIcon, SearchIcon, ClipboardIcon, ResetIcon, EllipsisVerticalIcon, PlayIcon, DocumentVideoIcon, ChevronLeftIcon } from "@sanity/icons"; const wistiaMedia = { name: "wistiaMedia", type: "object", title: "Wistia media", fields: [ { type: "number", name: "id" }, { type: "string", name: "hashed_id" } ], preview: { select: { title: "id" }, prepare({ title }) { return { title: `Wistia video ID: ${title}` }; } } }, WistiaProjectsComponent = ({ onProjectClick, config }) => { const [wistiaProjects, setWistiaProjects] = useState([]), [loading, setLoading] = useState(!1), [error, setError] = useState(""), handleProjectClick = (projectId) => { onProjectClick(projectId); }; return useEffect(() => { setLoading(!0); const apiUrl = "https://api.wistia.com/v1/projects.json?sort_by=updated&sort_direction=0", headers = new Headers({ Authorization: `Bearer ${config.token}` }); fetch(apiUrl, { method: "GET", headers }).then((response) => (response.ok || (response?.status === 401 ? setError("401 Not authorised - check your API key permissions.") : setError(`${response?.status} error`)), setLoading(!1), response.json())).then((data) => setWistiaProjects(data)).catch((error2) => console.error(error2)); }, []), error ? /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsx(Card, { padding: [3, 3, 4], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsx(Text, { align: "center", children: error }) }) }) : /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsxs(Menu, { children: [ loading && /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsxs(Flex, { align: "center", direction: "column", gap: 3, height: "fill", justify: "center", children: [ /* @__PURE__ */ jsx(Spinner, { muted: !0 }), /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Loading projects from Wistia\u2026" }) ] }) }), wistiaProjects?.length ? wistiaProjects?.map((project) => /* @__PURE__ */ jsx( MenuItem, { style: { cursor: "pointer" }, onClick: () => handleProjectClick(project.id), children: /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", gap: 2, children: [ /* @__PURE__ */ jsxs(Text, { weight: "semibold", children: [ project.name, !project.public && /* @__PURE__ */ jsx( Tooltip, { content: /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "This project is private" }) }), fallbackPlacements: ["right", "left"], placement: "top", portal: !0, children: /* @__PURE__ */ jsx(LockIcon, { style: { marginLeft: 5 } }) } ) ] }), /* @__PURE__ */ jsx(Text, { muted: !0, children: project.mediaCount }) ] }) }) }, project.id )) : !loading && /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "No projects found." }) }) ] }) }); }, groupBy = (array, key) => array.reduce((rv, x) => ((rv[x[key]] = rv[x[key]] || []).push(x), rv), {}), wistiaMediasComponent = ({ onVideoClick, projectId, config }) => { const [wistiaMedias, setwistiaMedias] = useState({}), [loading, setLoading] = useState(!1), handleVideoClick = (media) => { onVideoClick(media); }; return useEffect(() => { if (projectId) { setLoading(!0); const apiUrl = `https://api.wistia.com/v1/medias.json?project_id=${projectId}&sort_by=name`, headers = new Headers({ Authorization: `Bearer ${config.token}` }); fetch(apiUrl, { method: "GET", headers }).then((response) => response.json()).then((data) => { setLoading(!1); let grouped = groupBy(data, "section"); return setwistiaMedias(grouped); }).catch((error) => console.error(error)); } }, []), /* @__PURE__ */ jsx(Box, { padding: 1, children: /* @__PURE__ */ jsxs(Menu, { children: [ !projectId && /* @__PURE__ */ jsx("div", { children: "Error loading project" }), loading && /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsxs(Flex, { align: "center", direction: "column", gap: 3, height: "fill", justify: "center", children: [ /* @__PURE__ */ jsx(Spinner, { muted: !0 }), /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: "Loading media from Wistia\u2026" }) ] }) }), Object.keys(wistiaMedias)?.length ? Object.keys(wistiaMedias)?.map((section, index) => /* @__PURE__ */ jsxs("div", { children: [ section !== "undefined" && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsx(Heading, { as: "h2", size: 1, children: section }) }), wistiaMedias[section].map((media) => /* @__PURE__ */ jsx( MenuItem, { paddingX: 3, paddingY: 2, style: { cursor: "pointer" }, onClick: () => handleVideoClick({ id: media.id, hashed_id: media.hashed_id }), children: /* @__PURE__ */ jsxs(Flex, { gap: 3, align: "center", children: [ /* @__PURE__ */ jsx("img", { src: media.thumbnail.url, width: "70", style: { borderRadius: 3 } }), /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", align: "left", children: media.name }), /* @__PURE__ */ jsx(Text, { size: 1, style: { marginLeft: "auto" }, muted: !0, children: new Date(media.duration * 1e3).toISOString().slice(11, 19) }) ] }) }, media.id )) ] }, projectId + index)) : !loading && /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsx(Text, { align: "center", muted: !0, size: 1, children: "No media found." }) }) ] }) }); }, playerUrl = (videoUrl) => { let params = new URLSearchParams(), wistiaSettings = { playbar: !0, playButton: !0, seo: !1, controlsVisibleOnLoad: !0, autoPlay: !1, doNotTrack: !0, preload: "none", volumeControl: !0, copyLinkAndThumbnailEnabled: !0, fullscreenButton: !0 }; for (let key in wistiaSettings) params.append(key, wistiaSettings[key]); return `${videoUrl}?${params.toString()}`; }; function Player({ videoUrl }) { return /* @__PURE__ */ jsx( "div", { style: { position: "relative", paddingTop: "56.25%", height: "0" }, children: /* @__PURE__ */ jsx( "iframe", { allow: "autoplay; fullscreen", style: { width: "100%", height: "100%", position: "absolute", top: "0", right: "0", bottom: "0", left: "0", border: "0", display: "block", borderRadius: "3px" }, src: playerUrl(videoUrl) || "" } ) } ); } function AssetMenu({ onAction }) { return /* @__PURE__ */ jsx( MenuButton, { button: /* @__PURE__ */ jsx(Button, { padding: 2, mode: "ghost", icon: EllipsisVerticalIcon, tone: "default" }), id: "asset-menu", menu: /* @__PURE__ */ jsxs(Menu, { children: [ /* @__PURE__ */ jsx( MenuItem, { text: "Replace media", icon: SearchIcon, onClick: () => { onAction({ type: "select" }); } } ), /* @__PURE__ */ jsx( MenuItem, { text: "Copy embed URL", icon: ClipboardIcon, onClick: () => { onAction({ type: "copyUrl" }); } } ), /* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx( MenuItem, { text: "Clear field", icon: ResetIcon, tone: "critical", onClick: () => { onAction({ type: "delete" }); } } ) ] }) } ); } const WistiaInputComponent = (props) => { const { value, onChange, config, schemaType } = props, [isModalOpen, setIsModalOpen] = useState(!1), [selectedProjectId, setSelectedProjectId] = useState(0), handleChange = useCallback( (newValue) => { setIsModalOpen(!1), onChange([ setIfMissing({ _type: schemaType.name }), set(newValue.hashed_id, ["hashed_id"]), set(newValue.id, ["id"]) ]); }, [onChange, schemaType] ), handleProjectClick = (projectId) => { setSelectedProjectId(projectId); }, handleAssetMenu = (action) => { switch (action?.type) { case "copyUrl": handleCopyURL(); break; case "delete": handleChange({}); break; case "select": setIsModalOpen(!0); break; } }, videoUrl = value?.hashed_id ? `https://fast.wistia.net/embed/iframe/${value.hashed_id}` : null, { push: pushToast } = useToast(), handleCopyURL = useCallback(() => { navigator.clipboard.writeText(videoUrl || ""), pushToast({ closable: !0, status: "success", title: "The URL is copied to the clipboard" }); }, [pushToast, videoUrl]), toggleModal = () => { setIsModalOpen(!isModalOpen); }; return config?.token?.length ? /* @__PURE__ */ jsxs("div", { style: { padding: 1 }, children: [ videoUrl ? /* @__PURE__ */ jsxs(Card, { radius: 2, shadow: 1, padding: 2, children: [ /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", gap: 2, marginBottom: 2, children: [ /* @__PURE__ */ jsxs(Text, { size: 1, weight: "semibold", cellPadding: 2, children: [ /* @__PURE__ */ jsx(PlayIcon, { style: { marginLeft: 3, marginRight: 3 } }), "Wistia video ID: ", value?.id ] }), /* @__PURE__ */ jsx(AssetMenu, { onAction: handleAssetMenu }) ] }), /* @__PURE__ */ jsx(Player, { videoUrl: videoUrl || "" }) ] }) : /* @__PURE__ */ jsx(Card, { tone: "inherit", border: !0, padding: [3, 5], style: { borderStyle: "dashed" }, children: /* @__PURE__ */ jsxs(Flex, { align: "center", direction: "column", gap: 4, children: [ /* @__PURE__ */ jsx(Text, { muted: !0, children: /* @__PURE__ */ jsx(DocumentVideoIcon, {}) }), /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Select a media from Wistia" }), /* @__PURE__ */ jsx(Button, { mode: "ghost", text: "Select media", onClick: toggleModal }) ] }) }), isModalOpen && /* @__PURE__ */ jsx( Dialog, { header: selectedProjectId ? "Select media" : "Select project", id: "wistia-projects", onClose: toggleModal, width: 1, children: selectedProjectId ? /* @__PURE__ */ jsxs("div", { children: [ /* @__PURE__ */ jsx(Card, { tone: "default", borderBottom: !0, padding: 4, children: /* @__PURE__ */ jsx( Button, { icon: ChevronLeftIcon, onClick: () => handleProjectClick(0), mode: "ghost", text: "Back to projects" } ) }), /* @__PURE__ */ jsx(wistiaMediasComponent, { config, projectId: selectedProjectId, onVideoClick: handleChange }) ] }) : /* @__PURE__ */ jsx(WistiaProjectsComponent, { config, onProjectClick: handleProjectClick }) } ) ] }) : /* @__PURE__ */ jsx(Card, { padding: [3, 3, 4], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsxs(Text, { align: "center", children: [ "Missing required API token in Sanity config.", " ", /* @__PURE__ */ jsx("a", { href: "https://wistia.com/support/developers/making-api-requests", children: "See Wistia documentation." }) ] }) }); }; function wistiaMediaRender(config) { return { components: { input: (props) => /* @__PURE__ */ jsx(WistiaInputComponent, { config, ...props }) } }; } const wistiaInput = definePlugin((config) => ({ name: "sanity-plugin-wistia-input", schema: { types: [ { ...wistiaMedia, ...wistiaMediaRender(config) } ] } })); export { wistiaInput }; //# sourceMappingURL=index.mjs.map