"use client"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { useLocalStorage } from "@app/hooks/useLocalStorage"; import { cn } from "@app/lib/cn"; import { type ProductUpdate, productUpdatesQueries } from "@app/lib/queries"; import { useQueries } from "@tanstack/react-query"; import { ArrowRight, BellIcon, ChevronRightIcon, RocketIcon, XIcon } from "lucide-react"; import { useTranslations } from "next-intl"; import { Transition, TransitionChild } from "@headlessui/react"; import * as React from "react"; export default function ProductUpdates({ isCollapsed }: { isCollapsed?: boolean; }) { const data = useQueries({ queries: [ productUpdatesQueries.list, productUpdatesQueries.latestVersion ], combine(result) { if (result[0].isLoading || result[1].isLoading) return null; return { updates: result[0].data?.data ?? [], latestVersion: result[1].data }; } }); const { env } = useEnvContext(); const t = useTranslations(); const [showMoreUpdatesText, setShowMoreUpdatesText] = React.useState(false); // we need to delay the initial React.useEffect(() => { const timeout = setTimeout(() => setShowMoreUpdatesText(true), 600); return () => clearTimeout(timeout); }, []); const [ignoredVersionUpdate, setIgnoredVersionUpdate] = useLocalStorage< string | null >("ignored-version", null); if (!data) return null; const showNewVersionPopup = Boolean( data?.latestVersion?.data && ignoredVersionUpdate !== data.latestVersion.data?.pangolin.latestVersion && env.app.version !== data.latestVersion.data?.pangolin.latestVersion ); return (
<>
{data.updates.length > 0 && ( <> {showNewVersionPopup ? t("productUpdateMoreInfo", { noOfUpdates: data.updates.length }) : t("productUpdateInfo", { noOfUpdates: data.updates.length })} )} 0} />
{ setIgnoredVersionUpdate( data.latestVersion?.data?.pangolin.latestVersion ?? null ); }} show={showNewVersionPopup} />
); } type ProductUpdatesPopupProps = { updates: ProductUpdate[]; show: boolean }; function ProductUpdatesPopup({ updates, show }: ProductUpdatesPopupProps) { const [open, setOpen] = React.useState(false); const t = useTranslations(); // we need to delay the initial opening state to have an animation on `appear` React.useEffect(() => { if (show) { requestAnimationFrame(() => setOpen(true)); } }, [show]); return (

{t("productUpdateWhatsNew")}

{updates[0].contents}
); } type NewVersionAvailableProps = { onClose: () => void; show: boolean; version: | Awaited< ReturnType< NonNullable< typeof productUpdatesQueries.latestVersion.queryFn > > >["data"] | undefined; }; function NewVersionAvailable({ version, show, onClose }: NewVersionAvailableProps) { const t = useTranslations(); const [open, setOpen] = React.useState(false); // we need to delay the initial opening state to have an animation on `appear` React.useEffect(() => { if (show) { requestAnimationFrame(() => setOpen(true)); } }, [show]); return (
{version && ( <>

{t("pangolinUpdateAvailable")}

{t("pangolinUpdateAvailableInfo", { version: version.pangolin.latestVersion })} {t("pangolinUpdateAvailableReleaseNotes")}
)}
); }