feat(template): show template in templates view
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="skeleton"
|
||||||
|
className={cn("bg-accent animate-pulse rounded-md", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Skeleton }
|
||||||
@@ -49,7 +49,7 @@ class Requests {
|
|||||||
return data.data;
|
return data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async get<T>(url: string, props: GetProps<T>): Promise<T | void> {
|
async get<T>(url: string, props: GetProps<T>): Promise<T | null> {
|
||||||
// Call before
|
// Call before
|
||||||
props.before?.();
|
props.before?.();
|
||||||
|
|
||||||
@@ -78,6 +78,7 @@ class Requests {
|
|||||||
// Show notification, and call error callback
|
// Show notification, and call error callback
|
||||||
toast.error(err.message);
|
toast.error(err.message);
|
||||||
props.error?.(err);
|
props.error?.(err);
|
||||||
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
props.finally?.();
|
props.finally?.();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,50 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import Authorised from "@/layouts/Authorised";
|
import Authorised from "@/layouts/Authorised";
|
||||||
|
import requests from "@/lib/requests";
|
||||||
|
import { useQuery, type UseQueryResult } from "@tanstack/react-query";
|
||||||
import { createFileRoute, Link } from "@tanstack/react-router";
|
import { createFileRoute, Link } from "@tanstack/react-router";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
|
import type { Template } from "@/types/api";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
|
||||||
export const Route = createFileRoute("/templates/")({
|
export const Route = createFileRoute("/templates/")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function RenderTemplates({ templates }: { templates: UseQueryResult<null | Template[], Error> }) {
|
||||||
|
// Render loading
|
||||||
|
if (templates.isPending) {
|
||||||
|
const skelets = new Array(5).fill(null);
|
||||||
|
return skelets.map((_, i) => <Skeleton className="h-10" key={i} />);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render error
|
||||||
|
if (templates.isError) {
|
||||||
|
return <div className="text-danger font-bold">Error: {templates.error.message}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render null
|
||||||
|
if (templates.data === null) {
|
||||||
|
return <div className="text-primary">No templates found</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return templates.data.map((template, i) => (
|
||||||
|
<div className="flex gap-2 items-center" key={i}>
|
||||||
|
<p className="text-lg">{template.name}</p>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
|
const templates = useQuery({
|
||||||
|
queryKey: ["user_templates"],
|
||||||
|
queryFn: () => requests.get<Template[]>("/templates", {}),
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Authorised>
|
<Authorised>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<h1 className="text-2xl font-bold text-primary">0 Templates</h1>
|
<h1 className="text-2xl font-bold text-primary">{templates.data?.length} Templates</h1>
|
||||||
|
|
||||||
<Link to="/templates/create">
|
<Link to="/templates/create">
|
||||||
<Button icon={<Plus />} variant="secondary">
|
<Button icon={<Plus />} variant="secondary">
|
||||||
@@ -19,6 +52,10 @@ function RouteComponent() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-2 mt-4">
|
||||||
|
<RenderTemplates templates={templates} />
|
||||||
|
</div>
|
||||||
</Authorised>
|
</Authorised>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tw-animate-css";
|
@import "tw-animate-css";
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.625rem;
|
--radius: 0.625rem;
|
||||||
--background: oklch(1 0 0);
|
--background: oklch(1 0 0);
|
||||||
@@ -38,40 +36,6 @@
|
|||||||
--sidebar-ring: oklch(0.708 0 0);
|
--sidebar-ring: oklch(0.708 0 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
|
||||||
--background: oklch(0.145 0 0);
|
|
||||||
--foreground: oklch(0.985 0 0);
|
|
||||||
--card: oklch(0.205 0 0);
|
|
||||||
--card-foreground: oklch(0.985 0 0);
|
|
||||||
--popover: oklch(0.205 0 0);
|
|
||||||
--popover-foreground: oklch(0.985 0 0);
|
|
||||||
--primary: oklch(0.922 0 0);
|
|
||||||
--primary-foreground: oklch(0.205 0 0);
|
|
||||||
--secondary: oklch(0.269 0 0);
|
|
||||||
--secondary-foreground: oklch(0.985 0 0);
|
|
||||||
--muted: oklch(0.269 0 0);
|
|
||||||
--muted-foreground: oklch(0.708 0 0);
|
|
||||||
--accent: oklch(0.269 0 0);
|
|
||||||
--accent-foreground: oklch(0.985 0 0);
|
|
||||||
--destructive: oklch(0.704 0.191 22.216);
|
|
||||||
--border: oklch(1 0 0 / 10%);
|
|
||||||
--input: oklch(1 0 0 / 15%);
|
|
||||||
--ring: oklch(0.556 0 0);
|
|
||||||
--chart-1: oklch(0.488 0.243 264.376);
|
|
||||||
--chart-2: oklch(0.696 0.17 162.48);
|
|
||||||
--chart-3: oklch(0.769 0.188 70.08);
|
|
||||||
--chart-4: oklch(0.627 0.265 303.9);
|
|
||||||
--chart-5: oklch(0.645 0.246 16.439);
|
|
||||||
--sidebar: oklch(0.205 0 0);
|
|
||||||
--sidebar-foreground: oklch(0.985 0 0);
|
|
||||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
||||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
||||||
--sidebar-accent: oklch(0.269 0 0);
|
|
||||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
||||||
--sidebar-border: oklch(1 0 0 / 10%);
|
|
||||||
--sidebar-ring: oklch(0.556 0 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
|
|||||||
@@ -18,3 +18,12 @@ export interface TokenUserInfo {
|
|||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------- Templates --------
|
||||||
|
export interface Template {
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
name: string;
|
||||||
|
template: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user