From c9de506c565db301017a22e85856a9a462b42cba Mon Sep 17 00:00:00 2001 From: Juan Di Toro Date: Fri, 22 Mar 2024 18:53:39 +0100 Subject: [PATCH] fix: small fixes --- app/hooks/usePinning.ts | 83 ++++---- app/providers/PinningProvider.tsx | 6 +- app/root.tsx | 113 +++++----- app/routes/account.tsx | 337 +++++++++++++++--------------- app/routes/file-manager/index.tsx | 66 ++++-- 5 files changed, 331 insertions(+), 274 deletions(-) diff --git a/app/hooks/usePinning.ts b/app/hooks/usePinning.ts index 4547869..553c14f 100644 --- a/app/hooks/usePinning.ts +++ b/app/hooks/usePinning.ts @@ -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, }; }; diff --git a/app/providers/PinningProvider.tsx b/app/providers/PinningProvider.tsx index 660aa6c..afc7fd5 100644 --- a/app/providers/PinningProvider.tsx +++ b/app/providers/PinningProvider.tsx @@ -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; diff --git a/app/root.tsx b/app/root.tsx index 5b3d319..12d5da3 100644 --- a/app/root.tsx +++ b/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 ( - - - - - - - - +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + {children} - - - - - - ); + + + + + + ); } function App() { - const sdk = useSdk(); - const providers = useMemo(() => getProviders(sdk as Sdk), [sdk]); - return ( - - - - - - - - ); + const sdk = useSdk(); + const providers = useMemo(() => getProviders(sdk as Sdk), [sdk]); + return ( + + + + + + ); } export default function Root() { - const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL) - return ( - - - - ); + const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL); + return ( + + + + ); } export function HydrateFallback() { - return

Loading...

; + return

Loading...

; } diff --git a/app/routes/account.tsx b/app/routes/account.tsx index 4795ce3..9fdf752 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -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 ( - - -

My Account

- { - if (!open) { - setModal({ - changeEmail: false, - changePassword: false, - setupTwoFactor: false, - changeAvatar: false, - }); - } - }}> - } - button={ - - } - /> -

Account Management

-
- - - - - } - /> - - - Email Address - - {identity?.email} - - - - - - - - - Account Type - - Lite Premium Account - - - - - - -
-

Security

-
- - Password - - - - - - + + } + /> + + + Email Address + + {identity?.email} + + + + + + + + + Account Type + + Lite Premium Account + + + + - - - - - Two-Factor Authentication - - Improve security by enabling 2FA. - - - -
+

Security

+
+ + Password + + + + + + + + + + + + Two-Factor Authentication + + + Improve security by enabling 2FA. + + + + + + + +
+

More

+
+ + Invite a Friend + + Get 1 GB per friend invited for free (max 5 GB). + + + - - - -
-

More

-
- - Invite a Friend - - Get 1 GB per friend invited for free (max 5 GB). - - - - - - - Read our Resources - - Navigate helpful articles or get assistance. - - - - - - - Delete Account - - Once initiated, this action cannot be undone. - - - - - -
- - {openModal.changeAvatar && } - {openModal.changeEmail && ( - - )} - {openModal.changePassword && } - {openModal.setupTwoFactor && } - -
-
-
+ + + + Read our Resources + + Navigate helpful articles or get assistance. + + + + + + + Delete Account + + Once initiated, this action cannot be undone. + + + + + + + + {openModal.changeAvatar && } + {openModal.changeEmail && ( + + )} + {openModal.changePassword && } + {openModal.setupTwoFactor && } + + + + ); } @@ -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(); + const { mutate: updatePassword } = + useUpdatePassword(); 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(), }); }, }); diff --git a/app/routes/file-manager/index.tsx b/app/routes/file-manager/index.tsx index d01478c..12752af 100644 --- a/app/routes/file-manager/index.tsx +++ b/app/routes/file-manager/index.tsx @@ -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" /> - - Pin Content - -
- - - - +
); } + +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 ( + <> + + Pin Content + +
+ + + + + + ); +};