feat(artifact): refresh button
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
CopyCheck,
|
CopyCheck,
|
||||||
ImageIcon,
|
ImageIcon,
|
||||||
OctagonAlert,
|
OctagonAlert,
|
||||||
|
RefreshCwIcon,
|
||||||
ScanSearch,
|
ScanSearch,
|
||||||
SquircleDashed,
|
SquircleDashed,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
@@ -13,7 +14,8 @@ import { useEffect, useState } from "react";
|
|||||||
import Enka from "#/enka_logo.png";
|
import Enka from "#/enka_logo.png";
|
||||||
import { SimpleTooltip } from "@/components/tooltip";
|
import { SimpleTooltip } from "@/components/tooltip";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { getCardStatus } from "@/lib/api";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
|
import { getCardStatus, revalidateCard } from "@/lib/api";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
||||||
@@ -21,6 +23,14 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [useWeb, setUseWeb] = useState(false);
|
const [useWeb, setUseWeb] = useState(false);
|
||||||
const [isCached, setIsCached] = useState(true);
|
const [isCached, setIsCached] = useState(true);
|
||||||
|
const [t, setT] = useState(0);
|
||||||
|
|
||||||
|
async function refresh() {
|
||||||
|
setReady(false);
|
||||||
|
setIsCached(false);
|
||||||
|
if (!useWeb) await revalidateCard(sub);
|
||||||
|
setT(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: for update
|
// biome-ignore lint/correctness/useExhaustiveDependencies: for update
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -31,7 +41,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
|||||||
setIsCached(s.cached);
|
setIsCached(s.cached);
|
||||||
if (!s.cached) setError(s.error);
|
if (!s.cached) setError(s.error);
|
||||||
});
|
});
|
||||||
}, [sub, uid]);
|
}, [sub, uid, t]);
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full relative">
|
<div className="h-full w-full relative">
|
||||||
{!ready && !error && (isCached || useWeb) && (
|
{!ready && !error && (isCached || useWeb) && (
|
||||||
@@ -68,13 +78,16 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute left-1 z-45 opacity-70 md:opacity-50 hover:opacity-100 flex gap-1",
|
||||||
|
useWeb ? "-bottom-19" : "bottom-1",
|
||||||
|
)}
|
||||||
|
>
|
||||||
<SimpleTooltip text={useWeb ? "สลับเป็นรูปภาพ" : "สลับเป็น Enka"}>
|
<SimpleTooltip text={useWeb ? "สลับเป็นรูปภาพ" : "สลับเป็น Enka"}>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className={cn(
|
className="bg-[#222a]! backdrop-blur-sm"
|
||||||
"absolute left-1 z-45 bg-[#222a]! backdrop-blur-sm opacity-70 md:opacity-50 hover:opacity-100",
|
|
||||||
useWeb ? "-bottom-19" : "bottom-1",
|
|
||||||
)}
|
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setReady(false);
|
setReady(false);
|
||||||
@@ -89,9 +102,20 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</SimpleTooltip>
|
</SimpleTooltip>
|
||||||
|
<SimpleTooltip text="รีเฟรช">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={refresh}
|
||||||
|
disabled={!error && !ready}
|
||||||
|
>
|
||||||
|
{!error && !ready ? <Spinner /> : <RefreshCwIcon />}
|
||||||
|
</Button>
|
||||||
|
</SimpleTooltip>
|
||||||
|
</div>
|
||||||
{useWeb ? (
|
{useWeb ? (
|
||||||
<iframe
|
<iframe
|
||||||
src={`https://enka.network/u/${uid}`}
|
src={`https://enka.network/u/${uid}?t=${t}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full border-0 bg-card -mt-20 h-[calc(100%+5rem)]",
|
"w-full border-0 bg-card -mt-20 h-[calc(100%+5rem)]",
|
||||||
!ready && "grayscale blur-md brightness-50 pointer-events-none",
|
!ready && "grayscale blur-md brightness-50 pointer-events-none",
|
||||||
@@ -108,7 +132,7 @@ export function EnkaBrowser({ sub, uid }: { sub: string; uid: string }) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={`/api/card/${sub}`}
|
src={`/api/card/${sub}?t=${t}`}
|
||||||
alt={`Enka card for ${sub}`}
|
alt={`Enka card for ${sub}`}
|
||||||
fill
|
fill
|
||||||
objectFit="contain"
|
objectFit="contain"
|
||||||
|
|||||||
@@ -229,6 +229,12 @@ export async function random() {
|
|||||||
else throw "ไม่พบผู้ลงทะเบียนที่ยังไม่ตรวจสอบ";
|
else throw "ไม่พบผู้ลงทะเบียนที่ยังไม่ตรวจสอบ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function revalidateCard(sub: string) {
|
||||||
|
if (!(await adminCheck())) throw "Unauthorized";
|
||||||
|
await db.delete(cards).where(eq(cards.submission, sub));
|
||||||
|
revalidatePath(`/api/card/${sub}`);
|
||||||
|
}
|
||||||
|
|
||||||
export async function tlState(
|
export async function tlState(
|
||||||
data: Partial<typeof tierlistStates.$inferInsert>,
|
data: Partial<typeof tierlistStates.$inferInsert>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ const nextConfig: NextConfig = withBundleAnalyzer({
|
|||||||
hostname: "cards.enka.network",
|
hostname: "cards.enka.network",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
localPatterns: [
|
||||||
|
{ pathname: "/api/card/*" },
|
||||||
|
{
|
||||||
|
pathname: "/cdn/*",
|
||||||
|
},
|
||||||
|
],
|
||||||
minimumCacheTTL: 86400,
|
minimumCacheTTL: 86400,
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
|
|||||||
Reference in New Issue
Block a user