mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
Add a chill little banner to tell users if there is an issue with the extension
This commit is contained in:
parent
ac8b9066d1
commit
fe14f61525
3 changed files with 106 additions and 5 deletions
|
@ -6,7 +6,6 @@ import { TMDBContentTypes } from "@/backend/metadata/types/tmdb";
|
||||||
import { ThiccContainer } from "@/components/layout/ThinContainer";
|
import { ThiccContainer } from "@/components/layout/ThinContainer";
|
||||||
import { MediaCard } from "@/components/media/MediaCard";
|
import { MediaCard } from "@/components/media/MediaCard";
|
||||||
import { MediaGrid } from "@/components/media/MediaGrid";
|
import { MediaGrid } from "@/components/media/MediaGrid";
|
||||||
import { Divider } from "@/components/utils/Divider";
|
|
||||||
import { Heading1, Paragraph } from "@/components/utils/Text";
|
import { Heading1, Paragraph } from "@/components/utils/Text";
|
||||||
import { MediaItem } from "@/utils/mediaTypes";
|
import { MediaItem } from "@/utils/mediaTypes";
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,60 @@
|
||||||
import { ReactNode } from "react";
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
|
||||||
|
import { extensionInfo } from "@/backend/extension/messaging";
|
||||||
import { useBannerSize, useBannerStore } from "@/stores/banner";
|
import { useBannerSize, useBannerStore } from "@/stores/banner";
|
||||||
import { BannerLocation } from "@/stores/banner/BannerLocation";
|
import { ExtensionBanner } from "@/stores/banner/BannerLocation";
|
||||||
|
|
||||||
|
export type ExtensionStatus =
|
||||||
|
| "unknown"
|
||||||
|
| "failed"
|
||||||
|
| "disallowed"
|
||||||
|
| "noperms"
|
||||||
|
| "outdated"
|
||||||
|
| "success";
|
||||||
|
|
||||||
|
async function getExtensionState(): Promise<ExtensionStatus> {
|
||||||
|
const info = await extensionInfo();
|
||||||
|
if (!info) return "unknown"; // cant talk to extension
|
||||||
|
if (!info.success) return "failed"; // extension failed to respond
|
||||||
|
if (!info.allowed) return "disallowed"; // extension is not enabled on this page
|
||||||
|
if (!info.hasPermission) return "noperms"; // extension has no perms to do it's tasks
|
||||||
|
if (!isAllowedExtensionVersion(info.version)) return "outdated"; // extension is too old
|
||||||
|
return "success"; // no problems
|
||||||
|
}
|
||||||
|
|
||||||
export function Layout(props: { children: ReactNode }) {
|
export function Layout(props: { children: ReactNode }) {
|
||||||
const bannerSize = useBannerSize();
|
const bannerSize = useBannerSize();
|
||||||
const location = useBannerStore((s) => s.location);
|
const location = useBannerStore((s) => s.location);
|
||||||
|
const [extensionState, setExtensionState] =
|
||||||
|
useState<ExtensionStatus>("unknown");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let isMounted = true;
|
||||||
|
|
||||||
|
getExtensionState().then((state) => {
|
||||||
|
if (isMounted) {
|
||||||
|
setExtensionState(state);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMounted = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<p className="flex items-center justify-center h-screen">Loading...</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="fixed inset-x-0 z-[1000]">
|
<div className="fixed inset-x-0 z-[1000]">
|
||||||
<BannerLocation />
|
<ExtensionBanner extensionState={extensionState} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -2,20 +2,23 @@ import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
|
import { ExtensionStatus } from "@/setup/Layout";
|
||||||
import { useBannerStore, useRegisterBanner } from "@/stores/banner";
|
import { useBannerStore, useRegisterBanner } from "@/stores/banner";
|
||||||
|
|
||||||
export function Banner(props: {
|
export function Banner(props: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
type: "error";
|
type: "error" | "info"; // Add "info" type
|
||||||
id: string;
|
id: string;
|
||||||
}) {
|
}) {
|
||||||
const [ref] = useRegisterBanner<HTMLDivElement>(props.id);
|
const [ref] = useRegisterBanner<HTMLDivElement>(props.id);
|
||||||
const hideBanner = useBannerStore((s) => s.hideBanner);
|
const hideBanner = useBannerStore((s) => s.hideBanner);
|
||||||
const styles = {
|
const styles = {
|
||||||
error: "bg-[#C93957] text-white",
|
error: "bg-[#C93957] text-white",
|
||||||
|
info: "bg-[#126FD3] text-white", // Add "info" style
|
||||||
};
|
};
|
||||||
const icons = {
|
const icons = {
|
||||||
error: Icons.CIRCLE_EXCLAMATION,
|
error: Icons.CIRCLE_EXCLAMATION,
|
||||||
|
info: Icons.CIRCLE_EXCLAMATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -41,6 +44,61 @@ export function Banner(props: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This jawn is for advertising the extension for le
|
||||||
|
export function ExtensionBanner(props: {
|
||||||
|
location?: string;
|
||||||
|
extensionState: ExtensionStatus;
|
||||||
|
}) {
|
||||||
|
const setLocation = useBannerStore((s) => s.setLocation);
|
||||||
|
const currentLocation = useBannerStore((s) => s.location);
|
||||||
|
const extensionPage =
|
||||||
|
"https://chromewebstore.google.com/detail/movie-web-extension/hoffoikpiofojilgpofjhnkkamfnnhmm";
|
||||||
|
const loc = props.location ?? null;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!loc) return;
|
||||||
|
setLocation(loc);
|
||||||
|
return () => {
|
||||||
|
setLocation(null);
|
||||||
|
};
|
||||||
|
}, [setLocation, loc]);
|
||||||
|
|
||||||
|
if (currentLocation !== loc) return null;
|
||||||
|
|
||||||
|
// Show the banner with a 40% chance
|
||||||
|
if (Math.random() < 0.4) {
|
||||||
|
let bannerText = "";
|
||||||
|
switch (props.extensionState) {
|
||||||
|
case "noperms":
|
||||||
|
bannerText =
|
||||||
|
"You don't have the necessary permissions to use the extension.";
|
||||||
|
break;
|
||||||
|
case "outdated":
|
||||||
|
bannerText =
|
||||||
|
"Your extension is outdated. Please update it for better performance.";
|
||||||
|
break;
|
||||||
|
case "disallowed":
|
||||||
|
bannerText = "The extension is not enabled on this page.";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bannerText =
|
||||||
|
"You don't have the extension! Download it here for better quality.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => window.open(extensionPage, "_blank")}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
<Banner id="extension" type="info">
|
||||||
|
{bannerText}
|
||||||
|
</Banner>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function BannerLocation(props: { location?: string }) {
|
export function BannerLocation(props: { location?: string }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isOnline = useBannerStore((s) => s.isOnline);
|
const isOnline = useBannerStore((s) => s.isOnline);
|
||||||
|
|
Loading…
Reference in a new issue