This commit is contained in:
mrjvs 2023-11-22 15:04:59 +01:00
commit f3146b9a00
3 changed files with 76 additions and 40 deletions

View File

@ -0,0 +1,68 @@
import { useRef, useState } from "react";
import { Button } from "@/components/Button";
import { Icon, Icons } from "@/components/Icon";
import { DisplayError } from "@/components/player/display/displayInterface";
export function ErrorCard(props: { error: DisplayError | string }) {
const [showErrorCard, setShowErrorCard] = useState(true);
const [hasCopied, setHasCopied] = useState(false);
const hasCopiedUnsetDebounce = useRef<ReturnType<typeof setTimeout> | null>(
null
);
const errorMessage =
typeof props.error === "string" ? props.error : props.error.message;
function copyError() {
if (!props.error || !navigator.clipboard) return;
navigator.clipboard.writeText(`\`\`\`${errorMessage}\`\`\``);
setHasCopied(true);
// Debounce unsetting the "has copied" label
if (hasCopiedUnsetDebounce.current)
clearTimeout(hasCopiedUnsetDebounce.current);
hasCopiedUnsetDebounce.current = setTimeout(() => setHasCopied(false), 2e3);
}
if (!showErrorCard) return null;
return (
// I didn't put a <Transition> here because it'd fade out, then jump height weirdly
<div className="w-full bg-errors-card p-6 rounded-lg">
<div className="flex justify-between items-center pb-2 border-b border-errors-border">
<span className="text-white font-medium">Error details</span>
<div className="flex justify-center items-center gap-3">
<Button
theme="secondary"
padding="p-2 md:px-4"
onClick={() => copyError()}
>
{hasCopied ? (
<>
<Icon icon={Icons.CHECKMARK} className="text-xs mr-3" />
Copied
</>
) : (
<>
<Icon icon={Icons.COPY} className="text-2xl mr-3" />
Copy
</>
)}
</Button>
<Button
theme="secondary"
padding="p-2 md:px-2"
onClick={() => setShowErrorCard(false)}
>
<Icon icon={Icons.X} className="text-2xl" />
</Button>
</div>
</div>
<div className="mt-4 h-60 overflow-y-auto text-left whitespace-pre pointer-events-auto select-text">
{errorMessage}
</div>
</div>
);
}

View File

@ -1,11 +1,13 @@
import { Button } from "@/components/Button";
import { Icon, Icons } from "@/components/Icon";
import { Icons } from "@/components/Icon";
import { IconPill } from "@/components/layout/IconPill";
import { Paragraph } from "@/components/text/Paragraph";
import { Title } from "@/components/text/Title";
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
import { usePlayerStore } from "@/stores/player/store";
import { ErrorCard } from "../errors/ErrorCard";
export function PlaybackErrorPart() {
const playbackError = usePlayerStore((s) => s.interface.error);
@ -31,25 +33,7 @@ export function PlaybackErrorPart() {
</ErrorContainer>
<ErrorContainer maxWidth="max-w-[45rem]">
{/* Error */}
{playbackError ? (
<div className="w-full bg-errors-card p-6 rounded-lg">
<div className="flex justify-between items-center pb-2 border-b border-errors-border">
<span className="text-white font-medium">Error details</span>
<div className="flex justify-center items-center gap-3">
<Button theme="secondary" padding="p-2 md:px-4">
<Icon icon={Icons.COPY} className="text-2xl mr-3" />
Copy
</Button>
<Button theme="secondary" padding="p-2 md:px-2">
<Icon icon={Icons.X} className="text-2xl" />
</Button>
</div>
</div>
<div className="mt-4 h-60 overflow-y-auto text-left whitespace-pre pointer-events-auto">
{playbackError.message}
</div>
</div>
) : null}
{playbackError ? <ErrorCard error={playbackError} /> : null}
</ErrorContainer>
</ErrorLayout>
);

View File

@ -1,13 +1,15 @@
import { useMemo } from "react";
import { Button } from "@/components/Button";
import { Icon, Icons } from "@/components/Icon";
import { Icons } from "@/components/Icon";
import { IconPill } from "@/components/layout/IconPill";
import { Paragraph } from "@/components/text/Paragraph";
import { Title } from "@/components/text/Title";
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
import { ErrorCard } from "../errors/ErrorCard";
export interface ScrapeErrorPartProps {
data: {
sources: Record<string, ScrapingSegment>;
@ -53,25 +55,7 @@ export function ScrapeErrorPart(props: ScrapeErrorPartProps) {
</ErrorContainer>
<ErrorContainer maxWidth="max-w-[45rem]">
{/* Error */}
{error ? (
<div className="w-full bg-errors-card p-6 rounded-lg">
<div className="flex justify-between items-center pb-2 border-b border-errors-border">
<span className="text-white font-medium">Error details</span>
<div className="flex justify-center items-center gap-3">
<Button theme="secondary" padding="p-2 md:px-4">
<Icon icon={Icons.COPY} className="text-2xl mr-3" />
Copy
</Button>
<Button theme="secondary" padding="p-2 md:px-2">
<Icon icon={Icons.X} className="text-2xl" />
</Button>
</div>
</div>
<div className="mt-4 h-60 overflow-y-auto text-left whitespace-pre pointer-events-auto">
{error}
</div>
</div>
) : null}
{error ? <ErrorCard error={error} /> : null}
</ErrorContainer>
</ErrorLayout>
);