fix: small fixes
This commit is contained in:
parent
e1ca45f1f1
commit
c9de506c56
|
@ -1,51 +1,62 @@
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useNotification } from "@refinedev/core";
|
||||||
import { useContext } from "react";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { useCallback, useContext } from "react";
|
||||||
import { PinningProcess } from "~/data/pinning";
|
import { PinningProcess } from "~/data/pinning";
|
||||||
import { PinningContext } from "~/providers/PinningProvider";
|
import { PinningContext } from "~/providers/PinningProvider";
|
||||||
|
|
||||||
// TODO: Adapt to real API
|
|
||||||
|
|
||||||
export const usePinning = () => {
|
export const usePinning = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const context = useContext(PinningContext);
|
const context = useContext(PinningContext);
|
||||||
|
const { open } = useNotification();
|
||||||
|
|
||||||
const { mutate } = useMutation({
|
const { mutate: pinMutation } = useMutation({
|
||||||
mutationKey: ["pin-progress"],
|
mutationKey: ["pin-mutation"],
|
||||||
mutationFn: async (variables: { cid: string, type: "pin" | "unpin" }) => {
|
mutationFn: async (variables: { cid: string }) => {
|
||||||
const { cid, type } = variables;
|
const { cid } = variables;
|
||||||
switch (type) {
|
|
||||||
case "pin": {
|
|
||||||
const response = await PinningProcess.pin(cid);
|
const response = await PinningProcess.pin(cid);
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
open?.({
|
open?.({
|
||||||
type: "destructive",
|
type: "error",
|
||||||
message: "Erorr pinning " + cid,
|
message: `Error pinning ${cid}`,
|
||||||
description: response.message,
|
description: response.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
queryClient.invalidateQueries({ queryKey: ["pin-progress"] });
|
||||||
case "unpin": {
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { mutate: unpinMutation } = useMutation({
|
||||||
|
mutationKey: ["unpin-mutation"],
|
||||||
|
mutationFn: async (variables: { cid: string }) => {
|
||||||
|
const { cid } = variables;
|
||||||
const response = await PinningProcess.unpin(cid);
|
const response = await PinningProcess.unpin(cid);
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
open?.({
|
open?.({
|
||||||
type: "destructive",
|
type: "error",
|
||||||
message: "Erorr removing " + cid,
|
message: `Error removing ${cid}`,
|
||||||
description: response.message,
|
description: response.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["pin-progress"] });
|
||||||
break;
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.queryClient.invalidateQueries({ queryKey: ["pin-progress"] })
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const bulkPin = useCallback(
|
||||||
|
(cids: string[]) => {
|
||||||
|
for (const cid of cids) {
|
||||||
|
pinMutation({ cid });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[pinMutation],
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...context.query,
|
...context.query,
|
||||||
mutate
|
pin: pinMutation,
|
||||||
|
unpin: unpinMutation,
|
||||||
|
bulkPin,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {
|
import {
|
||||||
QueryClient,
|
type QueryClient,
|
||||||
UseQueryResult,
|
type UseQueryResult,
|
||||||
useQuery,
|
useQuery,
|
||||||
useQueryClient,
|
useQueryClient,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
import { createContext, useContext } from "react";
|
import { createContext, useContext } from "react";
|
||||||
import { PinningProcess, PinningStatus } from "~/data/pinning";
|
import { PinningProcess, type PinningStatus } from "~/data/pinning";
|
||||||
|
|
||||||
export interface IPinningData {
|
export interface IPinningData {
|
||||||
cid: string;
|
cid: string;
|
||||||
|
|
57
app/root.tsx
57
app/root.tsx
|
@ -1,41 +1,47 @@
|
||||||
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 stylesheet from "./tailwind.css?url";
|
||||||
import type {LinksFunction} from "@remix-run/node";
|
import type { LinksFunction } from "@remix-run/node";
|
||||||
|
|
||||||
// Supports weights 200-800
|
// Supports weights 200-800
|
||||||
import '@fontsource-variable/manrope';
|
import "@fontsource-variable/manrope";
|
||||||
import {Refine} from "@refinedev/core";
|
import { Refine } from "@refinedev/core";
|
||||||
import routerProvider from "@refinedev/remix-router";
|
import routerProvider from "@refinedev/remix-router";
|
||||||
import {notificationProvider} from "~/data/notification-provider";
|
import { notificationProvider } from "~/data/notification-provider";
|
||||||
import {SdkContextProvider, useSdk} from "~/components/lib/sdk-context";
|
import { SdkContextProvider, useSdk } from "~/components/lib/sdk-context";
|
||||||
import {Toaster} from "~/components/ui/toaster";
|
import { Toaster } from "~/components/ui/toaster";
|
||||||
import {getProviders} from "~/data/providers.js";
|
import { getProviders } from "~/data/providers.js";
|
||||||
import {Sdk} from "@lumeweb/portal-sdk";
|
import { Sdk } from "@lumeweb/portal-sdk";
|
||||||
import resources from "~/data/resources.js";
|
import resources from "~/data/resources.js";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import {useMemo} from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
export const links: LinksFunction = () => [
|
export const links: LinksFunction = () => [
|
||||||
{rel: "stylesheet", href: stylesheet},
|
{ rel: "stylesheet", href: stylesheet },
|
||||||
];
|
];
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
export function Layout({children}: { children: React.ReactNode }) {
|
export function Layout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charSet="utf-8"/>
|
<meta charSet="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<Meta/>
|
<Meta />
|
||||||
<Links/>
|
<Links />
|
||||||
</head>
|
</head>
|
||||||
<body className="overflow-hidden">
|
<body className="overflow-hidden">
|
||||||
{children}
|
{children}
|
||||||
<Toaster/>
|
<Toaster />
|
||||||
<ScrollRestoration/>
|
<ScrollRestoration />
|
||||||
<Scripts/>
|
<Scripts />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
@ -52,24 +58,21 @@ function App() {
|
||||||
notificationProvider={notificationProvider}
|
notificationProvider={notificationProvider}
|
||||||
dataProvider={{
|
dataProvider={{
|
||||||
default: providers.default,
|
default: providers.default,
|
||||||
files: providers.files
|
files: providers.files,
|
||||||
}}
|
}}
|
||||||
resources={resources}
|
resources={resources}
|
||||||
options={{disableTelemetry: true}}
|
options={{ disableTelemetry: true }}>
|
||||||
>
|
<Outlet />
|
||||||
<SdkContextProvider sdk={sdk}>
|
|
||||||
<Outlet/>
|
|
||||||
</SdkContextProvider>
|
|
||||||
</Refine>
|
</Refine>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Root() {
|
export default function Root() {
|
||||||
const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL)
|
const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL);
|
||||||
return (
|
return (
|
||||||
<SdkContextProvider sdk={sdk}>
|
<SdkContextProvider sdk={sdk}>
|
||||||
<App/>
|
<App />
|
||||||
</SdkContextProvider>
|
</SdkContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import { Input } from "~/components/ui/input";
|
||||||
import { UsageCard } from "~/components/usage-card";
|
import { UsageCard } from "~/components/usage-card";
|
||||||
|
|
||||||
import QRImg from "~/images/QR.png";
|
import QRImg from "~/images/QR.png";
|
||||||
import type {UpdatePasswordFormRequest} from "~/data/auth-provider";
|
import type { UpdatePasswordFormRequest } from "~/data/auth-provider";
|
||||||
|
|
||||||
export default function MyAccount() {
|
export default function MyAccount() {
|
||||||
const { data: identity } = useGetIdentity<{ email: string }>();
|
const { data: identity } = useGetIdentity<{ email: string }>();
|
||||||
|
@ -85,9 +85,13 @@ export default function MyAccount() {
|
||||||
<ManagementCard>
|
<ManagementCard>
|
||||||
<ManagementCardAvatar
|
<ManagementCardAvatar
|
||||||
button={
|
button={
|
||||||
<DialogTrigger asChild className="absolute bottom-0 right-0 z-50">
|
<DialogTrigger
|
||||||
|
asChild
|
||||||
|
className="absolute bottom-0 right-0 z-50">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setModal({ ...openModal, changeAvatar: true })}
|
onClick={() =>
|
||||||
|
setModal({ ...openModal, changeAvatar: true })
|
||||||
|
}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className=" flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2">
|
className=" flex items-center w-10 h-10 p-0 border-white rounded-full justiyf-center hover:bg-secondary-2">
|
||||||
<EditIcon />
|
<EditIcon />
|
||||||
|
@ -105,7 +109,9 @@ export default function MyAccount() {
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
className="h-12 gap-x-2"
|
className="h-12 gap-x-2"
|
||||||
onClick={() => setModal({ ...openModal, changeEmail: true })}>
|
onClick={() =>
|
||||||
|
setModal({ ...openModal, changeEmail: true })
|
||||||
|
}>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
Change Email Address
|
Change Email Address
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -147,7 +153,9 @@ export default function MyAccount() {
|
||||||
</ManagementCardFooter>
|
</ManagementCardFooter>
|
||||||
</ManagementCard>
|
</ManagementCard>
|
||||||
<ManagementCard>
|
<ManagementCard>
|
||||||
<ManagementCardTitle>Two-Factor Authentication</ManagementCardTitle>
|
<ManagementCardTitle>
|
||||||
|
Two-Factor Authentication
|
||||||
|
</ManagementCardTitle>
|
||||||
<ManagementCardContent>
|
<ManagementCardContent>
|
||||||
Improve security by enabling 2FA.
|
Improve security by enabling 2FA.
|
||||||
</ManagementCardContent>
|
</ManagementCardContent>
|
||||||
|
@ -313,7 +321,8 @@ const ChangePasswordSchema = z
|
||||||
});
|
});
|
||||||
|
|
||||||
const ChangePasswordForm = () => {
|
const ChangePasswordForm = () => {
|
||||||
const { mutate: updatePassword } = useUpdatePassword<UpdatePasswordFormRequest>();
|
const { mutate: updatePassword } =
|
||||||
|
useUpdatePassword<UpdatePasswordFormRequest>();
|
||||||
const [form, fields] = useForm({
|
const [form, fields] = useForm({
|
||||||
id: "login",
|
id: "login",
|
||||||
constraint: getZodConstraint(ChangePasswordSchema),
|
constraint: getZodConstraint(ChangePasswordSchema),
|
||||||
|
|
|
@ -14,6 +14,10 @@ import {
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "~/components/ui/dialog";
|
} from "~/components/ui/dialog";
|
||||||
import { Field } from "~/components/forms";
|
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() {
|
export default function FileManager() {
|
||||||
return (
|
return (
|
||||||
|
@ -72,25 +76,55 @@ export default function FileManager() {
|
||||||
dataProviderName="files"
|
dataProviderName="files"
|
||||||
/>
|
/>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<PinFilesForm />
|
||||||
<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>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</GeneralLayout>
|
</GeneralLayout>
|
||||||
</Authenticated>
|
</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