fix: small fixes
This commit is contained in:
parent
e1ca45f1f1
commit
c9de506c56
|
@ -1,51 +1,62 @@
|
|||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useContext } from "react";
|
||||
import { useNotification } from "@refinedev/core";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useCallback, useContext } from "react";
|
||||
import { PinningProcess } from "~/data/pinning";
|
||||
import { PinningContext } from "~/providers/PinningProvider";
|
||||
|
||||
// TODO: Adapt to real API
|
||||
|
||||
export const usePinning = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const context = useContext(PinningContext);
|
||||
const { open } = useNotification();
|
||||
|
||||
const { mutate } = useMutation({
|
||||
mutationKey: ["pin-progress"],
|
||||
mutationFn: async (variables: { cid: string, type: "pin" | "unpin" }) => {
|
||||
const { cid, type } = variables;
|
||||
switch (type) {
|
||||
case "pin": {
|
||||
const response = await PinningProcess.pin(cid);
|
||||
const { mutate: pinMutation } = useMutation({
|
||||
mutationKey: ["pin-mutation"],
|
||||
mutationFn: async (variables: { cid: string }) => {
|
||||
const { cid } = variables;
|
||||
const response = await PinningProcess.pin(cid);
|
||||
|
||||
if (!response.success) {
|
||||
open?.({
|
||||
type: "destructive",
|
||||
message: "Erorr pinning " + cid,
|
||||
description: response.message,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "unpin": {
|
||||
const response = await PinningProcess.unpin(cid);
|
||||
|
||||
if (!response.success) {
|
||||
open?.({
|
||||
type: "destructive",
|
||||
message: "Erorr removing " + cid,
|
||||
description: response.message,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (!response.success) {
|
||||
open?.({
|
||||
type: "error",
|
||||
message: `Error pinning ${cid}`,
|
||||
description: response.message,
|
||||
});
|
||||
}
|
||||
|
||||
context.queryClient.invalidateQueries({ queryKey: ["pin-progress"] })
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: ["pin-progress"] });
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: unpinMutation } = useMutation({
|
||||
mutationKey: ["unpin-mutation"],
|
||||
mutationFn: async (variables: { cid: string }) => {
|
||||
const { cid } = variables;
|
||||
const response = await PinningProcess.unpin(cid);
|
||||
|
||||
if (!response.success) {
|
||||
open?.({
|
||||
type: "error",
|
||||
message: `Error removing ${cid}`,
|
||||
description: response.message,
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: ["pin-progress"] });
|
||||
},
|
||||
});
|
||||
|
||||
const bulkPin = useCallback(
|
||||
(cids: string[]) => {
|
||||
for (const cid of cids) {
|
||||
pinMutation({ cid });
|
||||
}
|
||||
},
|
||||
[pinMutation],
|
||||
);
|
||||
|
||||
return {
|
||||
...context.query,
|
||||
mutate
|
||||
pin: pinMutation,
|
||||
unpin: unpinMutation,
|
||||
bulkPin,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {
|
||||
QueryClient,
|
||||
UseQueryResult,
|
||||
type QueryClient,
|
||||
type UseQueryResult,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import { createContext, useContext } from "react";
|
||||
import { PinningProcess, PinningStatus } from "~/data/pinning";
|
||||
import { PinningProcess, type PinningStatus } from "~/data/pinning";
|
||||
|
||||
export interface IPinningData {
|
||||
cid: string;
|
||||
|
|
113
app/root.tsx
113
app/root.tsx
|
@ -1,79 +1,82 @@
|
|||
import {Links, Meta, Outlet, Scripts, ScrollRestoration,} from "@remix-run/react";
|
||||
import {
|
||||
Links,
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
ScrollRestoration,
|
||||
} from "@remix-run/react";
|
||||
|
||||
import stylesheet from "./tailwind.css?url";
|
||||
import type {LinksFunction} from "@remix-run/node";
|
||||
import type { LinksFunction } from "@remix-run/node";
|
||||
|
||||
// Supports weights 200-800
|
||||
import '@fontsource-variable/manrope';
|
||||
import {Refine} from "@refinedev/core";
|
||||
import "@fontsource-variable/manrope";
|
||||
import { Refine } from "@refinedev/core";
|
||||
import routerProvider from "@refinedev/remix-router";
|
||||
import {notificationProvider} from "~/data/notification-provider";
|
||||
import {SdkContextProvider, useSdk} from "~/components/lib/sdk-context";
|
||||
import {Toaster} from "~/components/ui/toaster";
|
||||
import {getProviders} from "~/data/providers.js";
|
||||
import {Sdk} from "@lumeweb/portal-sdk";
|
||||
import { notificationProvider } from "~/data/notification-provider";
|
||||
import { SdkContextProvider, useSdk } from "~/components/lib/sdk-context";
|
||||
import { Toaster } from "~/components/ui/toaster";
|
||||
import { getProviders } from "~/data/providers.js";
|
||||
import { Sdk } from "@lumeweb/portal-sdk";
|
||||
import resources from "~/data/resources.js";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import {useMemo} from "react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export const links: LinksFunction = () => [
|
||||
{rel: "stylesheet", href: stylesheet},
|
||||
{ rel: "stylesheet", href: stylesheet },
|
||||
];
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export function Layout({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<Meta/>
|
||||
<Links/>
|
||||
</head>
|
||||
<body className="overflow-hidden">
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
<body className="overflow-hidden">
|
||||
{children}
|
||||
<Toaster/>
|
||||
<ScrollRestoration/>
|
||||
<Scripts/>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
<Toaster />
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
const sdk = useSdk();
|
||||
const providers = useMemo(() => getProviders(sdk as Sdk), [sdk]);
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Refine
|
||||
authProvider={providers.auth}
|
||||
routerProvider={routerProvider}
|
||||
notificationProvider={notificationProvider}
|
||||
dataProvider={{
|
||||
default: providers.default,
|
||||
files: providers.files
|
||||
}}
|
||||
resources={resources}
|
||||
options={{disableTelemetry: true}}
|
||||
>
|
||||
<SdkContextProvider sdk={sdk}>
|
||||
<Outlet/>
|
||||
</SdkContextProvider>
|
||||
</Refine>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
const sdk = useSdk();
|
||||
const providers = useMemo(() => getProviders(sdk as Sdk), [sdk]);
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Refine
|
||||
authProvider={providers.auth}
|
||||
routerProvider={routerProvider}
|
||||
notificationProvider={notificationProvider}
|
||||
dataProvider={{
|
||||
default: providers.default,
|
||||
files: providers.files,
|
||||
}}
|
||||
resources={resources}
|
||||
options={{ disableTelemetry: true }}>
|
||||
<Outlet />
|
||||
</Refine>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Root() {
|
||||
const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL)
|
||||
return (
|
||||
<SdkContextProvider sdk={sdk}>
|
||||
<App/>
|
||||
</SdkContextProvider>
|
||||
);
|
||||
const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL);
|
||||
return (
|
||||
<SdkContextProvider sdk={sdk}>
|
||||
<App />
|
||||
</SdkContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function HydrateFallback() {
|
||||
return <p>Loading...</p>;
|
||||
return <p>Loading...</p>;
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ import { getZodConstraint, parseWithZod } from "@conform-to/zod";
|
|||
import { DialogClose } from "@radix-ui/react-dialog";
|
||||
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||
import {
|
||||
Authenticated,
|
||||
type BaseKey,
|
||||
useGetIdentity,
|
||||
useUpdate,
|
||||
useUpdatePassword,
|
||||
Authenticated,
|
||||
type BaseKey,
|
||||
useGetIdentity,
|
||||
useUpdate,
|
||||
useUpdatePassword,
|
||||
} from "@refinedev/core";
|
||||
import { useMemo, useState } from "react";
|
||||
import { z } from "zod";
|
||||
|
@ -41,7 +41,7 @@ import { Input } from "~/components/ui/input";
|
|||
import { UsageCard } from "~/components/usage-card";
|
||||
|
||||
import QRImg from "~/images/QR.png";
|
||||
import type {UpdatePasswordFormRequest} from "~/data/auth-provider";
|
||||
import type { UpdatePasswordFormRequest } from "~/data/auth-provider";
|
||||
|
||||
export default function MyAccount() {
|
||||
const { data: identity } = useGetIdentity<{ email: string }>();
|
||||
|
@ -54,167 +54,175 @@ export default function MyAccount() {
|
|||
});
|
||||
|
||||
return (
|
||||
<Authenticated key="account" v3LegacyAuthProviderCompatible>
|
||||
<GeneralLayout>
|
||||
<h1 className="text-lg font-bold mb-4">My Account</h1>
|
||||
<Dialog
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setModal({
|
||||
changeEmail: false,
|
||||
changePassword: false,
|
||||
setupTwoFactor: false,
|
||||
changeAvatar: false,
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<UsageCard
|
||||
label="Usage"
|
||||
currentUsage={2}
|
||||
monthlyUsage={10}
|
||||
icon={<CloudIcon className="text-ring" />}
|
||||
button={
|
||||
<Button variant="accent" className="gap-x-2 h-12">
|
||||
<AddIcon />
|
||||
Upgrade to Premium
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<h2 className="font-bold my-8">Account Management</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard>
|
||||
<ManagementCardAvatar
|
||||
button={
|
||||
<DialogTrigger asChild className="absolute bottom-0 right-0 z-50">
|
||||
<Button
|
||||
onClick={() => setModal({ ...openModal, changeAvatar: true })}
|
||||
variant="outline"
|
||||
className=" flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2">
|
||||
<EditIcon />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
}
|
||||
/>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Email Address</ManagementCardTitle>
|
||||
<ManagementCardContent className="text-ring font-semibold">
|
||||
{identity?.email}
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() => setModal({ ...openModal, changeEmail: true })}>
|
||||
<AddIcon />
|
||||
Change Email Address
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Account Type</ManagementCardTitle>
|
||||
<ManagementCardContent className="text-ring font-semibold flex gap-x-2">
|
||||
Lite Premium Account
|
||||
<CrownIcon />
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2">
|
||||
<Authenticated key="account" v3LegacyAuthProviderCompatible>
|
||||
<GeneralLayout>
|
||||
<h1 className="text-lg font-bold mb-4">My Account</h1>
|
||||
<Dialog
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setModal({
|
||||
changeEmail: false,
|
||||
changePassword: false,
|
||||
setupTwoFactor: false,
|
||||
changeAvatar: false,
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<UsageCard
|
||||
label="Usage"
|
||||
currentUsage={2}
|
||||
monthlyUsage={10}
|
||||
icon={<CloudIcon className="text-ring" />}
|
||||
button={
|
||||
<Button variant="accent" className="gap-x-2 h-12">
|
||||
<AddIcon />
|
||||
Upgrade to Premium
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<h2 className="font-bold my-8">Security</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Password</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
<PasswordDots className="mt-6" />
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, changePassword: true })
|
||||
}>
|
||||
}
|
||||
/>
|
||||
<h2 className="font-bold my-8">Account Management</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard>
|
||||
<ManagementCardAvatar
|
||||
button={
|
||||
<DialogTrigger
|
||||
asChild
|
||||
className="absolute bottom-0 right-0 z-50">
|
||||
<Button
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, changeAvatar: true })
|
||||
}
|
||||
variant="outline"
|
||||
className=" flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2">
|
||||
<EditIcon />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
}
|
||||
/>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Email Address</ManagementCardTitle>
|
||||
<ManagementCardContent className="text-ring font-semibold">
|
||||
{identity?.email}
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, changeEmail: true })
|
||||
}>
|
||||
<AddIcon />
|
||||
Change Email Address
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Account Type</ManagementCardTitle>
|
||||
<ManagementCardContent className="text-ring font-semibold flex gap-x-2">
|
||||
Lite Premium Account
|
||||
<CrownIcon />
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2">
|
||||
<AddIcon />
|
||||
Change Password
|
||||
Upgrade to Premium
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Two-Factor Authentication</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Improve security by enabling 2FA.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, setupTwoFactor: true })
|
||||
}>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<h2 className="font-bold my-8">Security</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Password</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
<PasswordDots className="mt-6" />
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, changePassword: true })
|
||||
}>
|
||||
<AddIcon />
|
||||
Change Password
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>
|
||||
Two-Factor Authentication
|
||||
</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Improve security by enabling 2FA.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
className="h-12 gap-x-2"
|
||||
onClick={() =>
|
||||
setModal({ ...openModal, setupTwoFactor: true })
|
||||
}>
|
||||
<AddIcon />
|
||||
Enable Two-Factor Authorization
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<h2 className="font-bold my-8">More</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard variant="accent">
|
||||
<ManagementCardTitle>Invite a Friend</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Get 1 GB per friend invited for free (max 5 GB).
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button variant="accent" className="h-12 gap-x-2">
|
||||
<AddIcon />
|
||||
Enable Two-Factor Authorization
|
||||
Send Invitation
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<h2 className="font-bold my-8">More</h2>
|
||||
<div className="grid grid-cols-3 gap-x-8">
|
||||
<ManagementCard variant="accent">
|
||||
<ManagementCardTitle>Invite a Friend</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Get 1 GB per friend invited for free (max 5 GB).
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button variant="accent" className="h-12 gap-x-2">
|
||||
<AddIcon />
|
||||
Send Invitation
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Read our Resources</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Navigate helpful articles or get assistance.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2">
|
||||
<AddIcon />
|
||||
Open Support Centre
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Delete Account</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Once initiated, this action cannot be undone.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2" variant="destructive">
|
||||
<AddIcon />
|
||||
Delete my Account
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<DialogContent>
|
||||
{openModal.changeAvatar && <ChangeAvatarForm />}
|
||||
{openModal.changeEmail && (
|
||||
<ChangeEmailForm currentValue={identity?.email || ""} />
|
||||
)}
|
||||
{openModal.changePassword && <ChangePasswordForm />}
|
||||
{openModal.setupTwoFactor && <SetupTwoFactorDialog />}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</GeneralLayout>
|
||||
</Authenticated>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Read our Resources</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Navigate helpful articles or get assistance.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2">
|
||||
<AddIcon />
|
||||
Open Support Centre
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
<ManagementCard>
|
||||
<ManagementCardTitle>Delete Account</ManagementCardTitle>
|
||||
<ManagementCardContent>
|
||||
Once initiated, this action cannot be undone.
|
||||
</ManagementCardContent>
|
||||
<ManagementCardFooter>
|
||||
<Button className="h-12 gap-x-2" variant="destructive">
|
||||
<AddIcon />
|
||||
Delete my Account
|
||||
</Button>
|
||||
</ManagementCardFooter>
|
||||
</ManagementCard>
|
||||
</div>
|
||||
<DialogContent>
|
||||
{openModal.changeAvatar && <ChangeAvatarForm />}
|
||||
{openModal.changeEmail && (
|
||||
<ChangeEmailForm currentValue={identity?.email || ""} />
|
||||
)}
|
||||
{openModal.changePassword && <ChangePasswordForm />}
|
||||
{openModal.setupTwoFactor && <SetupTwoFactorDialog />}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</GeneralLayout>
|
||||
</Authenticated>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -252,7 +260,7 @@ const ChangeEmailForm = ({ currentValue }: { currentValue: string }) => {
|
|||
console.log(identity);
|
||||
updateEmail({
|
||||
resource: "account",
|
||||
id: "",
|
||||
id: "",
|
||||
values: {
|
||||
email: data.email.toString(),
|
||||
password: data.password.toString(),
|
||||
|
@ -313,7 +321,8 @@ const ChangePasswordSchema = z
|
|||
});
|
||||
|
||||
const ChangePasswordForm = () => {
|
||||
const { mutate: updatePassword } = useUpdatePassword<UpdatePasswordFormRequest>();
|
||||
const { mutate: updatePassword } =
|
||||
useUpdatePassword<UpdatePasswordFormRequest>();
|
||||
const [form, fields] = useForm({
|
||||
id: "login",
|
||||
constraint: getZodConstraint(ChangePasswordSchema),
|
||||
|
@ -327,8 +336,8 @@ const ChangePasswordForm = () => {
|
|||
const data = Object.fromEntries(new FormData(e.currentTarget).entries());
|
||||
|
||||
updatePassword({
|
||||
currentPassword: data.currentPassword.toString(),
|
||||
password: data.newPassword.toString(),
|
||||
currentPassword: data.currentPassword.toString(),
|
||||
password: data.newPassword.toString(),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -14,6 +14,10 @@ import {
|
|||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import { Field } from "~/components/forms";
|
||||
import { z } from "zod";
|
||||
import { getFormProps, useForm } from "@conform-to/react";
|
||||
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
|
||||
import { usePinning } from "~/hooks/usePinning";
|
||||
|
||||
export default function FileManager() {
|
||||
return (
|
||||
|
@ -72,25 +76,55 @@ export default function FileManager() {
|
|||
dataProviderName="files"
|
||||
/>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pin Content</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form action="" className="w-full flex flex-col gap-y-4">
|
||||
<Field
|
||||
inputProps={{
|
||||
name: "cids",
|
||||
placeholder: "Comma separated CIDs",
|
||||
}}
|
||||
labelProps={{ htmlFor: "cids", children: "Content to Pin" }}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Pin Content
|
||||
</Button>
|
||||
</form>
|
||||
<PinFilesForm />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</GeneralLayout>
|
||||
</Authenticated>
|
||||
);
|
||||
}
|
||||
|
||||
const PinFilesSchema = z.object({
|
||||
cids: z.string().transform((value) => value.split(",")),
|
||||
});
|
||||
|
||||
const PinFilesForm = () => {
|
||||
const { bulkPin } = usePinning();
|
||||
const [form, fields] = useForm({
|
||||
id: "pin-files",
|
||||
constraint: getZodConstraint(PinFilesSchema),
|
||||
onValidate({ formData }) {
|
||||
return parseWithZod(formData, { schema: PinFilesSchema });
|
||||
},
|
||||
shouldValidate: "onSubmit",
|
||||
onSubmit(e, { submission }) {
|
||||
if (submission?.status === "success") {
|
||||
const value = submission.value;
|
||||
|
||||
bulkPin(value.cids);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pin Content</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form {...getFormProps(form)} className="w-full flex flex-col gap-y-4">
|
||||
<Field
|
||||
inputProps={{
|
||||
name: fields.cids.name,
|
||||
placeholder: "Comma separated CIDs",
|
||||
}}
|
||||
labelProps={{ htmlFor: "cids", children: "Content to Pin" }}
|
||||
errors={fields.cids.errors}
|
||||
/>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Pin Content
|
||||
</Button>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue