Restructure layout and add widget
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
import { Section } from "./page";
|
||||
|
||||
export function SettingsAccountSection() {
|
||||
return <Section title="บัญชี">ask dreamgineer bruh</Section>;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
"use server";
|
||||
|
||||
import { exec } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { actionLog } from "@/lib/api";
|
||||
import { db } from "@/lib/db";
|
||||
import { settings } from "@/lib/db/schema";
|
||||
|
||||
export async function getEnka() {
|
||||
const [{ enka } = { enka: true }] = await db.select().from(settings).limit(1);
|
||||
return enka;
|
||||
}
|
||||
|
||||
export async function toggleEnka(state: boolean) {
|
||||
const last = await getEnka();
|
||||
if (last === state) return;
|
||||
await db
|
||||
.insert(settings)
|
||||
.values({ enka: state })
|
||||
.onConflictDoUpdate({ target: settings.id, set: { enka: state } });
|
||||
|
||||
actionLog("Changed a settings", { enka: state });
|
||||
revalidatePath("/admin/settings");
|
||||
revalidatePath("/artifact");
|
||||
}
|
||||
|
||||
export async function syncAmber() {
|
||||
const res = await promisify(exec)("bun util/sync 2>&1");
|
||||
actionLog("Triggered an Amber sync", { result: res.stdout });
|
||||
return res.stdout;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { SettingsAccountSection } from "./account";
|
||||
import { getEnka } from "./api";
|
||||
import { SettingsServicesSection } from "./services";
|
||||
|
||||
export default async function () {
|
||||
const enka = await getEnka();
|
||||
|
||||
return (
|
||||
<div className="grid gap-8 h-full w-full p-2 pl-0">
|
||||
<Tabs defaultValue="external">
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger value="external">บริการนอก</TabsTrigger>
|
||||
<TabsTrigger value="account">บัญชี</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="external">
|
||||
<SettingsServicesSection enka={enka} />
|
||||
</TabsContent>
|
||||
<TabsContent value="account">
|
||||
<SettingsAccountSection />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Section({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & { description?: string }) {
|
||||
return (
|
||||
<Card className={cn("h-full", className)} {...props}>
|
||||
<CardHeader>
|
||||
{title && <CardTitle className="text-2xl">{title}</CardTitle>}
|
||||
{description && <CardDescription>{description}</CardDescription>}
|
||||
</CardHeader>
|
||||
<CardContent className="h-full">{children}</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { FolderSync } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { syncAmber, toggleEnka } from "./api";
|
||||
import { Section } from "./page";
|
||||
|
||||
export function SettingsServicesSection({
|
||||
enka: enkaInitial,
|
||||
}: {
|
||||
enka: boolean;
|
||||
}) {
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
const [syncResult, setSyncResult] = useState("");
|
||||
const [enka, setEnka] = useState<boolean>();
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof enka !== "boolean") return setEnka(enkaInitial);
|
||||
toggleEnka(enka);
|
||||
}, [enka, enkaInitial]);
|
||||
|
||||
async function sync() {
|
||||
setSyncing(true);
|
||||
syncAmber()
|
||||
.then(setSyncResult)
|
||||
.finally(() => setSyncing(false));
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="บริการนอก">
|
||||
<div className="flex flex-col gap-2 h-full">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch checked={enka} onCheckedChange={setEnka} />
|
||||
เปิดใช้การดึงตัวละครใน Artifact
|
||||
</div>
|
||||
<Button disabled={syncing} onClick={sync} className="w-min">
|
||||
{syncing ? <Spinner /> : <FolderSync />}
|
||||
Sync Amber
|
||||
</Button>
|
||||
{syncResult && (
|
||||
<pre className="border bg-muted rounded h-full p-2">{syncResult}</pre>
|
||||
)}
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user