mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-15 17:09:51 +00:00
feat(ui): new Login UI using antd
This commit is contained in:
parent
b44b8d09b2
commit
2facb160aa
@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||||
</head>
|
</head>
|
||||||
|
16
ui/package-lock.json
generated
16
ui/package-lock.json
generated
@ -30,6 +30,7 @@
|
|||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
"antd": "^5.22.2",
|
"antd": "^5.22.2",
|
||||||
|
"antd-zod": "^6.0.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
@ -3819,6 +3820,18 @@
|
|||||||
"react-dom": ">=16.9.0"
|
"react-dom": ">=16.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/antd-zod": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/antd-zod/-/antd-zod-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-dv5XXR72UtWm1Sz2IhRV5Ho0t7FGZtQLUbEQMeryY6k3W/K9MrvT+e1mV9Ye9tBY+vUD5CksN9cgSAlqimVMXQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.merge": "^4.6.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"antd": "^5.20.5",
|
||||||
|
"zod": ">=3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/any-promise": {
|
"node_modules/any-promise": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz",
|
||||||
@ -5715,8 +5728,7 @@
|
|||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/loose-envify": {
|
"node_modules/loose-envify": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"@radix-ui/react-tooltip": "^1.1.2",
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"@tanstack/react-table": "^8.20.5",
|
"@tanstack/react-table": "^8.20.5",
|
||||||
"antd": "^5.22.2",
|
"antd": "^5.22.2",
|
||||||
|
"antd-zod": "^6.0.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
|
2
ui/public/logo.svg
Normal file
2
ui/public/logo.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.92591302712353 216.92591302712353" height="216.92591302712353" width="216.92591302712353"><g><svg /></g><g id="icon-0"><svg viewBox="0 0 216.92591302712353 216.92591302712353" height="216.92591302712353" width="216.92591302712353"><g><path d="M0 108.463c0-59.902 48.561-108.463 108.463-108.463 59.902 0 108.463 48.561 108.463 108.463 0 59.902-48.561 108.463-108.463 108.463-59.902 0-108.463-48.561-108.463-108.463zM108.463 211.779c57.06 0 103.316-46.256 103.316-103.316 0-57.06-46.256-103.316-103.316-103.316-57.06 0-103.316 46.256-103.316 103.316 0 57.06 46.256 103.316 103.316 103.316z" data-fill-palette-color="accent" fill="#f97317" stroke="transparent" /><ellipse rx="107.37832694842615" ry="107.37832694842615" cx="108.46295651356176" cy="108.46295651356176" fill="#f97317" stroke="transparent" stroke-width="0" fill-opacity="1" data-fill-palette-color="accent" /></g><g transform="matrix(1,0,0,1,64.03903745467258,44.049576960135155)"><svg viewBox="0 0 88.84783811777835 128.82675910685322" height="128.82675910685322" width="88.84783811777835"><g><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0" y="0" viewBox="4.99999928747888 13.445 56.29700142504224 81.6290007125211"
|
||||||
|
enable-background="new 0 0 100 100" xml:space="preserve" height="128.82675910685322" width="88.84783811777835" class="icon-dxe-0" data-fill-palette-color="quaternary" id="dxe-0"><path d="M58.482 47.222H55.667V35.963C55.667 23.527 45.587 13.445 33.148 13.445S10.63 23.528 10.63 35.963V47.222H7.815A2.813 2.813 0 0 0 5 50.037V92.259A2.813 2.813 0 0 0 7.815 95.074H58.482A2.813 2.813 0 0 0 61.297 92.259V50.037A2.815 2.815 0 0 0 58.482 47.222M35.963 72.039V86.63H30.333V72.039C27.062 70.876 24.703 67.784 24.703 64.111A8.445 8.445 0 0 1 41.591 64.111C41.593 67.784 39.234 70.876 35.963 72.039M47.222 47.222H19.074V35.963C19.074 28.203 25.388 21.889 33.148 21.889S47.222 28.203 47.222 35.963z" fill="#ffffff" data-fill-palette-color="quaternary" /></svg></g></svg></g></svg></g></svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,28 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216.92591302712353 216.92591302712353" height="216.92591302712353"
|
|
||||||
width="216.92591302712353">
|
|
||||||
<g><svg /></g>
|
|
||||||
<g id="icon-0"><svg viewBox="0 0 216.92591302712353 216.92591302712353" height="216.92591302712353"
|
|
||||||
width="216.92591302712353">
|
|
||||||
<g>
|
|
||||||
<path
|
|
||||||
d="M0 108.463c0-59.902 48.561-108.463 108.463-108.463 59.902 0 108.463 48.561 108.463 108.463 0 59.902-48.561 108.463-108.463 108.463-59.902 0-108.463-48.561-108.463-108.463zM108.463 211.779c57.06 0 103.316-46.256 103.316-103.316 0-57.06-46.256-103.316-103.316-103.316-57.06 0-103.316 46.256-103.316 103.316 0 57.06 46.256 103.316 103.316 103.316z"
|
|
||||||
data-fill-palette-color="accent" fill="#f97317" stroke="transparent" />
|
|
||||||
<ellipse rx="107.37832694842615" ry="107.37832694842615" cx="108.46295651356176" cy="108.46295651356176"
|
|
||||||
fill="#f97317" stroke="transparent" stroke-width="0" fill-opacity="1"
|
|
||||||
data-fill-palette-color="accent" />
|
|
||||||
</g>
|
|
||||||
<g transform="matrix(1,0,0,1,64.03903745467258,44.049576960135155)"><svg
|
|
||||||
viewBox="0 0 88.84783811777835 128.82675910685322" height="128.82675910685322"
|
|
||||||
width="88.84783811777835">
|
|
||||||
<g><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
|
|
||||||
x="0" y="0" viewBox="4.99999928747888 13.445 56.29700142504224 81.6290007125211"
|
|
||||||
enable-background="new 0 0 100 100" xml:space="preserve" height="128.82675910685322"
|
|
||||||
width="88.84783811777835" class="icon-dxe-0" data-fill-palette-color="quaternary"
|
|
||||||
id="dxe-0">
|
|
||||||
<path
|
|
||||||
d="M58.482 47.222H55.667V35.963C55.667 23.527 45.587 13.445 33.148 13.445S10.63 23.528 10.63 35.963V47.222H7.815A2.813 2.813 0 0 0 5 50.037V92.259A2.813 2.813 0 0 0 7.815 95.074H58.482A2.813 2.813 0 0 0 61.297 92.259V50.037A2.815 2.815 0 0 0 58.482 47.222M35.963 72.039V86.63H30.333V72.039C27.062 70.876 24.703 67.784 24.703 64.111A8.445 8.445 0 0 1 41.591 64.111C41.593 67.784 39.234 70.876 35.963 72.039M47.222 47.222H19.074V35.963C19.074 28.203 25.388 21.889 33.148 21.889S47.222 28.203 47.222 35.963z"
|
|
||||||
fill="#ffffff" data-fill-palette-color="quaternary" />
|
|
||||||
</svg></g>
|
|
||||||
</svg></g>
|
|
||||||
</svg></g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.5 KiB |
@ -1,8 +1,7 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { BookOpen } from "lucide-react";
|
import { Divider, Space, Typography } from "antd";
|
||||||
|
import { BookOpen as BookOpenIcon } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/components/ui/utils";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
|
||||||
import { version } from "@/domain/version";
|
import { version } from "@/domain/version";
|
||||||
|
|
||||||
type VersionProps = {
|
type VersionProps = {
|
||||||
@ -13,18 +12,18 @@ const Version = ({ className }: VersionProps) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("w-full flex pb-5 ", className)}>
|
<Space className={className} size={4}>
|
||||||
<div className="text-muted-foreground text-sm hover:text-stone-900 dark:hover:text-stone-200 flex">
|
<Typography.Link type="secondary" href="https://docs.certimate.me" target="_blank">
|
||||||
<a href="https://docs.certimate.me" target="_blank" className="flex items-center">
|
<div className="flex items-center justify-center space-x-1">
|
||||||
<BookOpen size={16} />
|
<BookOpenIcon size={16} />
|
||||||
<div className="ml-1">{t("common.menu.document")}</div>
|
<span>{t("common.menu.document")}</span>
|
||||||
</a>
|
</div>
|
||||||
<Separator orientation="vertical" className="mx-2" />
|
</Typography.Link>
|
||||||
<a href="https://github.com/usual2970/certimate/releases" target="_blank">
|
<Divider type="vertical" />
|
||||||
{version}
|
<Typography.Link type="secondary" href="https://github.com/usual2970/certimate/releases" target="_blank">
|
||||||
</a>
|
{version}
|
||||||
</div>
|
</Typography.Link>
|
||||||
</div>
|
</Space>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ export default function Dashboard() {
|
|||||||
<div className="flex h-full max-h-screen flex-col gap-2">
|
<div className="flex h-full max-h-screen flex-col gap-2">
|
||||||
<div className="flex h-14 items-center border-b dark:border-stone-500 px-4 lg:h-[60px] lg:px-6">
|
<div className="flex h-14 items-center border-b dark:border-stone-500 px-4 lg:h-[60px] lg:px-6">
|
||||||
<Link to="/" className="flex items-center gap-2 font-semibold">
|
<Link to="/" className="flex items-center gap-2 font-semibold">
|
||||||
<img src="/vite.svg" className="w-[36px] h-[36px]" />
|
<img src="/logo.svg" className="w-[36px] h-[36px]" />
|
||||||
<span className="dark:text-white">Certimate</span>
|
<span className="dark:text-white">Certimate</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -97,7 +97,7 @@ export default function Dashboard() {
|
|||||||
<SheetContent side="left" className="flex flex-col">
|
<SheetContent side="left" className="flex flex-col">
|
||||||
<nav className="grid gap-2 text-lg font-medium">
|
<nav className="grid gap-2 text-lg font-medium">
|
||||||
<Link to="/" className="flex items-center gap-2 text-lg font-semibold">
|
<Link to="/" className="flex items-center gap-2 text-lg font-semibold">
|
||||||
<img src="/vite.svg" className="w-[36px] h-[36px]" />
|
<img src="/logo.svg" className="w-[36px] h-[36px]" />
|
||||||
<span className="dark:text-white">Certimate</span>
|
<span className="dark:text-white">Certimate</span>
|
||||||
<span className="sr-only">Certimate</span>
|
<span className="sr-only">Certimate</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -4,7 +4,8 @@ import Version from "@/components/certimate/Version";
|
|||||||
import { getPocketBase } from "@/repository/pocketbase";
|
import { getPocketBase } from "@/repository/pocketbase";
|
||||||
|
|
||||||
const LoginLayout = () => {
|
const LoginLayout = () => {
|
||||||
if (getPocketBase().authStore.isValid && getPocketBase().authStore.isAdmin) {
|
const auth = getPocketBase().authStore;
|
||||||
|
if (auth.isValid && auth.isAdmin) {
|
||||||
return <Navigate to="/" />;
|
return <Navigate to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ const LoginLayout = () => {
|
|||||||
<div className="container">
|
<div className="container">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
|
|
||||||
<Version className="fixed right-0 bottom-0 justify-end pr-5" />
|
<Version className="fixed right-8 bottom-4" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -138,6 +138,7 @@ const AccessList = () => {
|
|||||||
title: t("access.action.delete"),
|
title: t("access.action.delete"),
|
||||||
content: t("access.action.delete.confirm"),
|
content: t("access.action.delete.confirm"),
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
|
// TODO: 有关联数据的不允许被删除
|
||||||
try {
|
try {
|
||||||
const res = await removeAccess(data);
|
const res = await removeAccess(data);
|
||||||
configContext.deleteAccess(res.id);
|
configContext.deleteAccess(res.id);
|
||||||
|
@ -11,11 +11,11 @@ import { list as listCertificate, type CertificateListReq } from "@/repository/c
|
|||||||
import { diffDays, getLeftDays } from "@/lib/time";
|
import { diffDays, getLeftDays } from "@/lib/time";
|
||||||
|
|
||||||
const CertificateList = () => {
|
const CertificateList = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
const tableColumns: TableProps<CertificateType>["columns"] = [
|
const tableColumns: TableProps<CertificateType>["columns"] = [
|
||||||
|
@ -1,90 +1,67 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Button, Card, Form, Input, notification } from "antd";
|
||||||
|
import { createSchemaFieldRule } from "antd-zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { getErrMessage } from "@/lib/error";
|
|
||||||
import { getPocketBase } from "@/repository/pocketbase";
|
import { getPocketBase } from "@/repository/pocketbase";
|
||||||
|
|
||||||
const formSchema = z.object({
|
|
||||||
username: z.string().email({
|
|
||||||
message: "login.username.errmsg.invalid",
|
|
||||||
}),
|
|
||||||
password: z.string().min(10, {
|
|
||||||
message: "login.password.errmsg.invalid",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
|
const navigage = useNavigate();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
resolver: zodResolver(formSchema),
|
|
||||||
defaultValues: {
|
const formSchema = z.object({
|
||||||
username: "",
|
username: z.string().email(t("login.username.errmsg.invalid")),
|
||||||
password: "",
|
password: z.string().min(10, t("login.password.errmsg.invalid")),
|
||||||
},
|
});
|
||||||
});
|
const formRule = createSchemaFieldRule(formSchema);
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
|
||||||
// 2. Define a submit handler.
|
|
||||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||||
|
setSubmitting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await getPocketBase().admins.authWithPassword(values.username, values.password);
|
await getPocketBase().admins.authWithPassword(values.username, values.password);
|
||||||
navigage("/");
|
navigage("/");
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
const message = getErrMessage(e);
|
notificationApi.error({ message: t("common.text.request_error"), description: <>{String(err)}</> });
|
||||||
form.setError("username", { message });
|
} finally {
|
||||||
form.setError("password", { message });
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigage = useNavigate();
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-[35em] border dark:border-stone-500 mx-auto mt-32 p-10 rounded-md shadow-md">
|
<>
|
||||||
<div className="flex justify-center mb-10">
|
{NotificationContextHolder}
|
||||||
<img src="/vite.svg" className="w-16" />
|
|
||||||
</div>
|
|
||||||
<Form {...form}>
|
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="username"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem>
|
|
||||||
<FormLabel>{t("login.username.label")}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder={t("login.username.placeholder")} {...field} />
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormMessage />
|
<Card className="mx-auto mt-32 p-10 max-w-[35em] border dark:border-stone-500 rounded-md shadow-md">
|
||||||
</FormItem>
|
<div className="flex items-center justify-center mb-10">
|
||||||
)}
|
<img src="/logo.svg" className="w-16" />
|
||||||
/>
|
</div>
|
||||||
|
|
||||||
<FormField
|
<Form form={form} disabled={submitting} layout="vertical" onFinish={onSubmit}>
|
||||||
control={form.control}
|
<Form.Item name="username" label={t("login.username.label")} rules={[formRule]}>
|
||||||
name="password"
|
<Input placeholder={t("login.username.placeholder")} />
|
||||||
render={({ field }) => (
|
</Form.Item>
|
||||||
<FormItem>
|
|
||||||
<FormLabel>{t("login.password.label")}</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder={t("login.password.placeholder")} {...field} type="password" />
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormMessage />
|
<Form.Item name="password" label={t("login.password.label")} rules={[formRule]}>
|
||||||
</FormItem>
|
<Input type="password" placeholder={t("login.password.placeholder")} />
|
||||||
)}
|
</Form.Item>
|
||||||
/>
|
|
||||||
<div className="flex justify-end">
|
<Form.Item>
|
||||||
<Button type="submit">{t("login.submit")}</Button>
|
<Button type="primary" htmlType="submit" block loading={submitting}>
|
||||||
</div>
|
{t("login.submit")}
|
||||||
</form>
|
</Button>
|
||||||
</Form>
|
</Form.Item>
|
||||||
</div>
|
</Form>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import { Workflow as WorkflowType } from "@/domain/workflow";
|
|||||||
import { list as listWorkflow, remove as removeWorkflow, save as saveWorkflow, type WorkflowListReq } from "@/repository/workflow";
|
import { list as listWorkflow, remove as removeWorkflow, save as saveWorkflow, type WorkflowListReq } from "@/repository/workflow";
|
||||||
|
|
||||||
const WorkflowList = () => {
|
const WorkflowList = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [modalApi, ModelContextHolder] = Modal.useModal();
|
const [modalApi, ModelContextHolder] = Modal.useModal();
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import PocketBase from "pocketbase";
|
import PocketBase from "pocketbase";
|
||||||
|
|
||||||
const apiDomain = import.meta.env.VITE_API_DOMAIN;
|
const apiDomain = import.meta.env.VITE_API_DOMAIN;
|
||||||
console.log(apiDomain);
|
console.log("VITE_API_DOMAIN:", apiDomain);
|
||||||
|
|
||||||
let pb: PocketBase;
|
let pb: PocketBase;
|
||||||
export const getPocketBase = () => {
|
export const getPocketBase = () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user