From 04c38429fd3dec67997a7df581d2612b9dc12286 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 15:57:17 -0400 Subject: [PATCH 01/24] fix: disable refine telemetry --- app/root.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/root.tsx b/app/root.tsx index 96d1531..a825abd 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -50,6 +50,7 @@ export default function App() { { name: 'files' }, { name: 'users' } ]} + options={{disableTelemetry: true}} > From 90f14b63e56d528d185c74f02c8c3c5794eb2f82 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 16:36:17 -0400 Subject: [PATCH 02/24] build: add patch-package to package.json --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a7c61fc..0ddced1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "dev": "remix vite:dev", "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", "preview": "vite preview", - "typecheck": "tsc" + "typecheck": "tsc", + "patch-package": "patch-package", + "postinstall": "patch-package" }, "dependencies": { "@conform-to/react": "^1.0.2", From d1e059fd71e287273e90a59ec64e51406240654a Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 16:48:29 -0400 Subject: [PATCH 03/24] fix: need to merge tus metadata to file meta --- app/components/lib/uppy.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/components/lib/uppy.ts b/app/components/lib/uppy.ts index 3dc123c..d07ab95 100644 --- a/app/components/lib/uppy.ts +++ b/app/components/lib/uppy.ts @@ -98,8 +98,13 @@ export function useUppy({ const file = uppyInstance.current?.getFile(fileID) as UppyFile // @ts-ignore if (file.uploader === "tus") { + const options = await sdk.protocols!().get(PROTOCOL_S5).getSdk().getTusOptions(file.data as File) uppyInstance.current?.setFileState(fileID, { - tus: await sdk.protocols!().get(PROTOCOL_S5).getSdk().getTusOptions(file.data as File) + tus: options, + meta: { + ...options.metadata, + ...file.meta, + } }) } } From ba374a851c277aa0d24a9263542493237f6d0f7c Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 17:23:38 -0400 Subject: [PATCH 04/24] dep: update portal-sdk --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 0ddced1..d93440a 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240318183202", + "@lumeweb/portal-sdk": "0.0.0-20240318212259", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", @@ -45,7 +45,6 @@ "react-dom": "^18.2.0", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", - "universal-cookie": "^7.1.0", "zod": "^3.22.4" }, "devDependencies": { From 7293cb0b5a5d572acd6b482fbfd11969e2bd0134 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 17:25:49 -0400 Subject: [PATCH 05/24] refactor: switch to pulling the cookie from the account service after ping as ping now returns it in the response --- app/data/auth-provider.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/data/auth-provider.ts b/app/data/auth-provider.ts index 55188b6..7a96734 100644 --- a/app/data/auth-provider.ts +++ b/app/data/auth-provider.ts @@ -8,7 +8,6 @@ import type { // @ts-ignore } from "@refinedev/core/dist/interfaces/bindings/auth" import {Sdk} from "@lumeweb/portal-sdk"; -import Cookies from 'universal-cookie'; import type {AccountInfoResponse} from "@lumeweb/portal-sdk"; export type AuthFormRequest = { @@ -91,15 +90,16 @@ export class PortalAuthProvider implements RequiredAuthProvider { } async check(params?: any): Promise { - this.maybeSetupAuth(); - const ret = await this._sdk.account().ping(); + if(ret){ + this.maybeSetupAuth(); + } + return {authenticated: ret, redirectTo: ret ? undefined : "/login"}; } async onError(error: any): Promise { - const cookies = new Cookies(); return {logout: true}; } @@ -144,10 +144,9 @@ export class PortalAuthProvider implements RequiredAuthProvider { } maybeSetupAuth(): void { - const cookies = new Cookies(); - const jwtCookie = cookies.get('auth_token'); - if (jwtCookie) { - this._sdk.setAuthToken(jwtCookie); + const jwt = this._sdk.account().jwtToken + if (jwt) { + this._sdk.setAuthToken(jwt); } } } From 9a9357bfc08b21091652fdfead98b354960a24e0 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 18:06:49 -0400 Subject: [PATCH 06/24] dep: update portal-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d93440a..bfd74eb 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240318212259", + "@lumeweb/portal-sdk": "0.0.0-20240318220522", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", From 48f29a1338ae811d2c9599b7e49cee8fd6c0e922 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 18:20:24 -0400 Subject: [PATCH 07/24] refactor: set parallelUploads to 10 --- app/components/lib/uppy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/lib/uppy.ts b/app/components/lib/uppy.ts index d07ab95..9a433ce 100644 --- a/app/components/lib/uppy.ts +++ b/app/components/lib/uppy.ts @@ -150,7 +150,7 @@ export function useUppy({ }) if (useTus) { - uppy.use(Tus, { endpoint: endpoint, limit: 6 }) + uppy.use(Tus, { endpoint: endpoint, limit: 6, parallelUploads: 10 }) uppy.addPreProcessor(tusPreprocessor) } From c12c980b17aaaf9344b4da7241f2dd5149283ec6 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 18:32:12 -0400 Subject: [PATCH 08/24] dep: update portal-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bfd74eb..459138f 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240318220522", + "@lumeweb/portal-sdk": "0.0.0-20240318223121", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", From 0a51f3e76d96d1d0d848239cba1a310152108d40 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 18:42:53 -0400 Subject: [PATCH 09/24] dep: update portal-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 459138f..6e19023 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240318223121", + "@lumeweb/portal-sdk": "0.0.0-20240318224232", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", From 1ff5f205b2c4829a571021139fa7e3abf48518cb Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Mon, 18 Mar 2024 18:51:41 -0400 Subject: [PATCH 10/24] feat: add callback and emit to track hashing progress --- app/components/lib/uppy.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/components/lib/uppy.ts b/app/components/lib/uppy.ts index 9a433ce..bda8c9a 100644 --- a/app/components/lib/uppy.ts +++ b/app/components/lib/uppy.ts @@ -8,7 +8,7 @@ import DropTarget, {type DropTargetOptions} from "./uppy-dropzone" import {useSdk} from "~/components/lib/sdk-context.js"; import UppyFileUpload from "~/components/lib/uppy-file-upload.js"; import {PROTOCOL_S5, Sdk} from "@lumeweb/portal-sdk"; -import {S5Client} from "@lumeweb/s5-js"; +import {S5Client, HashProgressEvent} from "@lumeweb/s5-js"; const LISTENING_EVENTS = [ "upload", @@ -98,7 +98,18 @@ export function useUppy({ const file = uppyInstance.current?.getFile(fileID) as UppyFile // @ts-ignore if (file.uploader === "tus") { - const options = await sdk.protocols!().get(PROTOCOL_S5).getSdk().getTusOptions(file.data as File) + const hashProgressCb = (event: HashProgressEvent) => { + uppyInstance.current?.emit("preprocess-progress", file, { + uploadStarted: false, + bytesUploaded: 0, + preprocess: { + mode: "determinate", + message: "Hashing file...", + value: Math.round((event.total / event.total) * 100) + } + }) + } + const options = await sdk.protocols!().get(PROTOCOL_S5).getSdk().getTusOptions(file.data as File, {}, {onHashProgress: hashProgressCb}) uppyInstance.current?.setFileState(fileID, { tus: options, meta: { From 482fd966cc7f47b93256cab8c3ca8a57b1b141e6 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 07:17:15 -0400 Subject: [PATCH 11/24] chore: remove unused property --- app/components/general-layout.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/general-layout.tsx b/app/components/general-layout.tsx index add18d6..be666f0 100644 --- a/app/components/general-layout.tsx +++ b/app/components/general-layout.tsx @@ -160,7 +160,6 @@ const UploadFileForm = () => { removeFile, cancelAll, } = useUppy({ - uploader: "tus", endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT, }); From 2e918e780229447837c019b09efc474a71af942b Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 07:18:31 -0400 Subject: [PATCH 12/24] refactor: we don't need to pass the endpoint, the sdk handles it --- app/components/general-layout.tsx | 4 +--- app/components/lib/uppy.ts | 10 +++------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/app/components/general-layout.tsx b/app/components/general-layout.tsx index be666f0..01025de 100644 --- a/app/components/general-layout.tsx +++ b/app/components/general-layout.tsx @@ -159,9 +159,7 @@ const UploadFileForm = () => { state, removeFile, cancelAll, - } = useUppy({ - endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT, - }); + } = useUppy(); console.log({ state, files: getFiles() }); diff --git a/app/components/lib/uppy.ts b/app/components/lib/uppy.ts index bda8c9a..5fb54bc 100644 --- a/app/components/lib/uppy.ts +++ b/app/components/lib/uppy.ts @@ -19,11 +19,7 @@ const LISTENING_EVENTS = [ "files-added" ] as const -export function useUppy({ - endpoint -}: { - endpoint: string -}) { +export function useUppy() { const sdk = useSdk() const [uploadLimit, setUploadLimit] = useState(0) @@ -161,7 +157,7 @@ export function useUppy({ }) if (useTus) { - uppy.use(Tus, { endpoint: endpoint, limit: 6, parallelUploads: 10 }) + uppy.use(Tus, { limit: 6, parallelUploads: 10 }) uppy.addPreProcessor(tusPreprocessor) } @@ -211,7 +207,7 @@ export function useUppy({ }) } setState("idle") - }, [targetRef, endpoint, uploadLimit]) + }, [targetRef, uploadLimit]) useEffect(() => { return () => { From ff5e5dec14186daa4be1bd81e9d0bf2e683164c1 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 07:20:11 -0400 Subject: [PATCH 13/24] refactor: major refactor of the providers and resources to be more dynamic and flexible --- app/data/account-provider.ts | 11 ++ app/data/auth-provider.ts | 216 ++++++++++++++--------------------- app/data/file-provider.ts | 5 +- app/data/providers.ts | 31 +++++ app/data/resources.ts | 18 +++ app/data/sdk-provider.ts | 6 + app/root.tsx | 29 ++--- vite-env.d.ts | 9 ++ 8 files changed, 177 insertions(+), 148 deletions(-) create mode 100644 app/data/account-provider.ts create mode 100644 app/data/providers.ts create mode 100644 app/data/resources.ts create mode 100644 app/data/sdk-provider.ts create mode 100644 vite-env.d.ts diff --git a/app/data/account-provider.ts b/app/data/account-provider.ts new file mode 100644 index 0000000..5028718 --- /dev/null +++ b/app/data/account-provider.ts @@ -0,0 +1,11 @@ +import type { DataProvider } from "@refinedev/core"; +import {SdkProvider} from "~/data/sdk-provider.js"; + +export const accountProvider: SdkProvider = { + getList: () => { throw Error("Not Implemented") }, + getOne: () => { throw Error("Not Implemented") }, + update: () => { throw Error("Not Implemented") }, + create: () => { throw Error("Not Implemented") }, + deleteOne: () => { throw Error("Not Implemented") }, + getApiUrl: () => "", +} diff --git a/app/data/auth-provider.ts b/app/data/auth-provider.ts index 7a96734..f7c211d 100644 --- a/app/data/auth-provider.ts +++ b/app/data/auth-provider.ts @@ -31,134 +31,94 @@ export type Identity = { email: string; } -export class PortalAuthProvider implements RequiredAuthProvider { - constructor(apiUrl: string) { - this._sdk = Sdk.create(apiUrl); - - const methods: Array = [ - 'login', - 'logout', - 'check', - 'onError', - 'register', - 'forgotPassword', - 'updatePassword', - 'getPermissions', - 'getIdentity', - ]; - - methods.forEach((method) => { - this[method] = this[method]?.bind(this) as any; - }); - } - - private _sdk: Sdk; - - get sdk(): Sdk { - return this._sdk; - } - - public static create(apiUrl: string): AuthProvider { - return new PortalAuthProvider(apiUrl); - } - - async login(params: AuthFormRequest): Promise { - const ret = await this._sdk.account().login({ - email: params.email, - password: params.password, - }) - - let redirectTo: string | undefined; - - if (ret) { - redirectTo = params.redirectTo; - if (!redirectTo) { - redirectTo = ret ? "/dashboard" : "/login"; - } - this._sdk.setAuthToken(this._sdk.account().jwtToken); - } - - return { - success: ret, - redirectTo, - }; - } - - async logout(params: any): Promise { - let ret = await this._sdk.account().logout(); - return {success: ret, redirectTo: "/login"}; - } - - async check(params?: any): Promise { - const ret = await this._sdk.account().ping(); - - if(ret){ - this.maybeSetupAuth(); - } - - return {authenticated: ret, redirectTo: ret ? undefined : "/login"}; - } - - async onError(error: any): Promise { - return {logout: true}; - } - - async register(params: RegisterFormRequest): Promise { - const ret = await this._sdk.account().register({ - email: params.email, - password: params.password, - first_name: params.firstName, - last_name: params.lastName, - }); - return {success: ret, redirectTo: ret ? "/dashboard" : undefined}; - } - - async forgotPassword(params: any): Promise { - return {success: true}; - } - - async updatePassword(params: any): Promise { - return {success: true}; - } - - async getPermissions(params?: Record): Promise { - return {success: true}; - } - - async getIdentity(params?: Identity): Promise { - this.maybeSetupAuth(); - const ret = await this._sdk.account().info(); - - if (!ret) { - return {identity: null}; - } - - const acct = ret as AccountInfoResponse; - - return { - id: acct.id, - firstName: acct.first_name, - lastName: acct.last_name, - email: acct.email, - }; - } - - maybeSetupAuth(): void { - const jwt = this._sdk.account().jwtToken +export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { + const maybeSetupAuth = (): void => { + const jwt = sdk.account().jwtToken; if (jwt) { - this._sdk.setAuthToken(jwt); + sdk.setAuthToken(jwt); } - } -} + }; -export interface RequiredAuthProvider extends AuthProvider { - login: AuthProvider['login']; - logout: AuthProvider['logout']; - check: AuthProvider['check']; - onError: AuthProvider['onError']; - register: AuthProvider['register']; - forgotPassword: AuthProvider['forgotPassword']; - updatePassword: AuthProvider['updatePassword']; - getPermissions: AuthProvider['getPermissions']; - getIdentity: AuthProvider['getIdentity']; -} + return { + async login(params: AuthFormRequest): Promise { + const ret = await sdk.account().login({ + email: params.email, + password: params.password, + }); + + let redirectTo: string | undefined; + + if (ret) { + redirectTo = params.redirectTo; + if (!redirectTo) { + redirectTo = ret ? "/dashboard" : "/login"; + } + sdk.setAuthToken(sdk.account().jwtToken); + } + + return { + success: ret, + redirectTo, + }; + }, + + async logout(params: any): Promise { + let ret = await sdk.account().logout(); + return { success: ret, redirectTo: "/login" }; + }, + + async check(params?: any): Promise { + const ret = await sdk.account().ping(); + + if (ret) { + maybeSetupAuth(); + } + + return { authenticated: ret, redirectTo: ret ? undefined : "/login" }; + }, + + async onError(error: any): Promise { + return { logout: true }; + }, + + async register(params: RegisterFormRequest): Promise { + const ret = await sdk.account().register({ + email: params.email, + password: params.password, + first_name: params.firstName, + last_name: params.lastName, + }); + return { success: ret, redirectTo: ret ? "/dashboard" : undefined }; + }, + + async forgotPassword(params: any): Promise { + return { success: true }; + }, + + async updatePassword(params: any): Promise { + return { success: true }; + }, + + async getPermissions(params?: Record): Promise { + return { success: true }; + }, + + async getIdentity(params?: Identity): Promise { + maybeSetupAuth(); + const ret = await sdk.account().info(); + + if (!ret) { + return { identity: null }; + } + + const acct = ret as AccountInfoResponse; + + return { + id: acct.id, + firstName: acct.first_name, + lastName: acct.last_name, + email: acct.email, + }; + }, + }; +}; diff --git a/app/data/file-provider.ts b/app/data/file-provider.ts index 004d6b1..4d89673 100644 --- a/app/data/file-provider.ts +++ b/app/data/file-provider.ts @@ -1,10 +1,11 @@ import type { DataProvider } from "@refinedev/core"; +import {SdkProvider} from "~/data/sdk-provider.js"; -export const defaultProvider: DataProvider = { +export const fileProvider: SdkProvider = { getList: () => { throw Error("Not Implemented") }, getOne: () => { throw Error("Not Implemented") }, update: () => { throw Error("Not Implemented") }, create: () => { throw Error("Not Implemented") }, deleteOne: () => { throw Error("Not Implemented") }, getApiUrl: () => "", -} \ No newline at end of file +} diff --git a/app/data/providers.ts b/app/data/providers.ts new file mode 100644 index 0000000..ee47b55 --- /dev/null +++ b/app/data/providers.ts @@ -0,0 +1,31 @@ +import type {AuthProvider, DataProvider} from "@refinedev/core"; +import {fileProvider} from "~/data/file-provider.js"; +import {Sdk} from "@lumeweb/portal-sdk"; +import {accountProvider} from "~/data/account-provider.js"; +import type {SdkProvider} from "~/data/sdk-provider.js"; +import {createPortalAuthProvider} from "~/data/auth-provider.js"; + +interface DataProviders { + default: SdkProvider; + auth: AuthProvider; + + [key: string]: SdkProvider | AuthProvider; +} + +let providers: DataProviders; + +export function getProviders(sdk: Sdk) { + if (providers) { + return providers; + } + + accountProvider.sdk = sdk; + fileProvider.sdk = sdk; + providers = { + default: accountProvider, + auth: createPortalAuthProvider(sdk), + files: fileProvider, + }; + + return providers; +} diff --git a/app/data/resources.ts b/app/data/resources.ts new file mode 100644 index 0000000..d36d69e --- /dev/null +++ b/app/data/resources.ts @@ -0,0 +1,18 @@ +import type {ResourceProps} from "@refinedev/core"; + +const resources: ResourceProps[] = [ + { + name: 'account', + meta: { + dataProviderName: 'default', + } + }, + { + name: 'file', + meta: { + dataProviderName: 'files', + } + } +]; + +export default resources; diff --git a/app/data/sdk-provider.ts b/app/data/sdk-provider.ts new file mode 100644 index 0000000..c5fbcea --- /dev/null +++ b/app/data/sdk-provider.ts @@ -0,0 +1,6 @@ +import {DataProvider} from "@refinedev/core"; +import {Sdk} from "@lumeweb/portal-sdk"; + +export interface SdkProvider extends DataProvider { + sdk?: Sdk; +} diff --git a/app/root.tsx b/app/root.tsx index a825abd..f44d8b2 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,21 +1,16 @@ -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 {PortalAuthProvider} from "~/data/auth-provider.js"; import routerProvider from "@refinedev/remix-router"; -import { defaultProvider } from "./data/file-provider"; import {SdkContextProvider} from "~/components/lib/sdk-context.js"; +import {getProviders} from "~/data/providers.js"; +import {Sdk} from "@lumeweb/portal-sdk"; +import resources from "~/data/resources.js"; export const links: LinksFunction = () => [ { rel: "stylesheet", href: stylesheet }, @@ -40,19 +35,17 @@ export function Layout({children}: { children: React.ReactNode }) { } export default function App() { - const auth = PortalAuthProvider.create("https://alpha.pinner.xyz") + const sdk = Sdk.create(import.meta.env.VITE_PORTAL_URL) + const providers = getProviders(sdk); return ( - + diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 0000000..5f868a8 --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_PORTAL_API_URL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} From 9fed7a26439e50c592a2dbf3f164f54e14e5741b Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 08:53:49 -0400 Subject: [PATCH 14/24] dep: update portal-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e19023..e846320 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240318224232", + "@lumeweb/portal-sdk": "0.0.0-20240319120038", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", From ddf9a0ddeadf349d4365d5e2569b8727ea5701c3 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 08:54:10 -0400 Subject: [PATCH 15/24] feat: initial update email support --- app/data/account-provider.ts | 58 +++++++++++++++++++++++++++++++----- app/routes/account.tsx | 4 +-- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/app/data/account-provider.ts b/app/data/account-provider.ts index 5028718..67fbc43 100644 --- a/app/data/account-provider.ts +++ b/app/data/account-provider.ts @@ -1,11 +1,53 @@ -import type { DataProvider } from "@refinedev/core"; +import type {DataProvider, UpdateParams, UpdateResponse, HttpError} from "@refinedev/core"; import {SdkProvider} from "~/data/sdk-provider.js"; -export const accountProvider: SdkProvider = { - getList: () => { throw Error("Not Implemented") }, - getOne: () => { throw Error("Not Implemented") }, - update: () => { throw Error("Not Implemented") }, - create: () => { throw Error("Not Implemented") }, - deleteOne: () => { throw Error("Not Implemented") }, - getApiUrl: () => "", +type AccountParams = { + email?: string; + password?: string; +} + +type AccountData = AccountParams; + +export const accountProvider: SdkProvider = { + getList: () => { + throw Error("Not Implemented") + }, + getOne: () => { + throw Error("Not Implemented") + }, + // @ts-ignore + async update( + params: UpdateParams, + ): Promise> { + if (params.variables.email && params.variables.password) { + const ret = accountProvider.sdk?.account().updateEmail(params.variables.email, params.variables.password); + + if (ret) { + if (ret instanceof Error) { + return Promise.reject(ret) + } + } else { + return Promise.reject(); + } + + return { + data: + { + email: params.variables.email, + }, + }; + } + + // Return an empty response if params.variables is undefined + return { + data: {} as AccountParams, + }; + }, + create: () => { + throw Error("Not Implemented") + }, + deleteOne: () => { + throw Error("Not Implemented") + }, + getApiUrl: () => "", } diff --git a/app/routes/account.tsx b/app/routes/account.tsx index 41a4717..b9cd815 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -222,8 +222,8 @@ const ChangeEmailForm = ({ const data = Object.fromEntries(new FormData(e.currentTarget).entries()); console.log(identity); updateEmail({ - resource: "users", - id: identity?.id || "", + resource: "account", + id: "", values: { email: data.email.toString(), }, From 3502732e76e66619a16f5cac040e6c31b33c9ee9 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 08:59:10 -0400 Subject: [PATCH 16/24] fix: pass password to updateEmail --- app/routes/account.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/routes/account.tsx b/app/routes/account.tsx index b9cd815..1f82f46 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -226,6 +226,7 @@ const ChangeEmailForm = ({ id: "", values: { email: data.email.toString(), + password: data.password.toString(), }, }); }, From 2dccaca132ddf6d49e6393a5db7b1e1b9bf10f95 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 09:12:21 -0400 Subject: [PATCH 17/24] fix: missing await --- app/data/account-provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/data/account-provider.ts b/app/data/account-provider.ts index 67fbc43..154abd2 100644 --- a/app/data/account-provider.ts +++ b/app/data/account-provider.ts @@ -20,7 +20,7 @@ export const accountProvider: SdkProvider = { params: UpdateParams, ): Promise> { if (params.variables.email && params.variables.password) { - const ret = accountProvider.sdk?.account().updateEmail(params.variables.email, params.variables.password); + const ret = await accountProvider.sdk?.account().updateEmail(params.variables.email, params.variables.password); if (ret) { if (ret instanceof Error) { From 8ca46c6f1813b423876e22a12a00f79212cca41e Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:07:38 -0400 Subject: [PATCH 18/24] dep: update portal-sdk --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e846320..7541186 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "@conform-to/react": "^1.0.2", "@conform-to/zod": "^1.0.2", "@fontsource-variable/manrope": "^5.0.19", - "@lumeweb/portal-sdk": "0.0.0-20240319120038", + "@lumeweb/portal-sdk": "0.0.0-20240319140708", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", From b65bd12c8abbf53b675ff8ab3f60b95cec70017e Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:12:13 -0400 Subject: [PATCH 19/24] feat: implement updatePassword --- app/data/auth-provider.ts | 41 ++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/app/data/auth-provider.ts b/app/data/auth-provider.ts index f7c211d..9145763 100644 --- a/app/data/auth-provider.ts +++ b/app/data/auth-provider.ts @@ -31,6 +31,11 @@ export type Identity = { email: string; } +export type UpdatePasswordFormRequest = { + currentPassword: string; + newPassword: string; +} + export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { const maybeSetupAuth = (): void => { const jwt = sdk.account().jwtToken; @@ -64,7 +69,7 @@ export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { async logout(params: any): Promise { let ret = await sdk.account().logout(); - return { success: ret, redirectTo: "/login" }; + return {success: ret, redirectTo: "/login"}; }, async check(params?: any): Promise { @@ -74,11 +79,11 @@ export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { maybeSetupAuth(); } - return { authenticated: ret, redirectTo: ret ? undefined : "/login" }; + return {authenticated: ret, redirectTo: ret ? undefined : "/login"}; }, async onError(error: any): Promise { - return { logout: true }; + return {logout: true}; }, async register(params: RegisterFormRequest): Promise { @@ -88,19 +93,37 @@ export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { first_name: params.firstName, last_name: params.lastName, }); - return { success: ret, redirectTo: ret ? "/dashboard" : undefined }; + return {success: ret, redirectTo: ret ? "/dashboard" : undefined}; }, async forgotPassword(params: any): Promise { - return { success: true }; + return {success: true}; }, - async updatePassword(params: any): Promise { - return { success: true }; + async updatePassword(params: UpdatePasswordFormRequest): Promise { + maybeSetupAuth(); + const ret = await sdk.account().updatePassword(params.currentPassword, params.newPassword); + + if (ret) { + if (ret instanceof Error) { + return { + success: false, + error: ret + } + } + + return { + success: true + } + } else { + return { + success: false + } + } }, async getPermissions(params?: Record): Promise { - return { success: true }; + return {success: true}; }, async getIdentity(params?: Identity): Promise { @@ -108,7 +131,7 @@ export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { const ret = await sdk.account().info(); if (!ret) { - return { identity: null }; + return {identity: null}; } const acct = ret as AccountInfoResponse; From 03b1d761f07fd47fefba610e88ce1462d1ac82b8 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:16:22 -0400 Subject: [PATCH 20/24] fix: use ChangePasswordSchema --- app/routes/account.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/account.tsx b/app/routes/account.tsx index 1f82f46..5d4782a 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -295,7 +295,7 @@ const ChangePasswordForm = ({ const { mutate: updatePassword } = useUpdatePassword<{ password: string }>(); const [form, fields] = useForm({ id: "login", - constraint: getZodConstraint(ChangeEmailSchema), + constraint: getZodConstraint(ChangePasswordSchema), onValidate({ formData }) { return parseWithZod(formData, { schema: ChangePasswordSchema }); }, From 1dae0ba7713cd5e2df5e9d6271c052a9745ca643 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:23:03 -0400 Subject: [PATCH 21/24] refactor: have UpdatePasswordFormRequest extend UpdatePasswordFormTypes --- app/data/auth-provider.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/data/auth-provider.ts b/app/data/auth-provider.ts index 9145763..0f207b0 100644 --- a/app/data/auth-provider.ts +++ b/app/data/auth-provider.ts @@ -1,4 +1,4 @@ -import type {AuthProvider} from "@refinedev/core" +import type {AuthProvider, UpdatePasswordFormTypes} from "@refinedev/core" import type { AuthActionResponse, @@ -31,9 +31,8 @@ export type Identity = { email: string; } -export type UpdatePasswordFormRequest = { +export interface UpdatePasswordFormRequest extends UpdatePasswordFormTypes{ currentPassword: string; - newPassword: string; } export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { @@ -102,7 +101,7 @@ export const createPortalAuthProvider = (sdk: Sdk): AuthProvider => { async updatePassword(params: UpdatePasswordFormRequest): Promise { maybeSetupAuth(); - const ret = await sdk.account().updatePassword(params.currentPassword, params.newPassword); + const ret = await sdk.account().updatePassword(params.currentPassword, params.password as string); if (ret) { if (ret instanceof Error) { From 02cd490700df7eff8c2ad40a6a46c3150ed1ac63 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:25:44 -0400 Subject: [PATCH 22/24] fix: update password needs the correct data sent to the mutation --- app/routes/account.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/routes/account.tsx b/app/routes/account.tsx index 5d4782a..d404db7 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -29,6 +29,7 @@ import { Input } from "~/components/ui/input"; import { UsageCard } from "~/components/usage-card"; import QRImg from "~/images/QR.png"; +import {UpdatePasswordFormRequest} from "~/data/auth-provider.js"; export default function MyAccount() { const { data: identity } = useGetIdentity<{ email: string }>(); @@ -292,7 +293,7 @@ const ChangePasswordForm = ({ open: boolean; setOpen: (value: boolean) => void; }) => { - const { mutate: updatePassword } = useUpdatePassword<{ password: string }>(); + const { mutate: updatePassword } = useUpdatePassword(); const [form, fields] = useForm({ id: "login", constraint: getZodConstraint(ChangePasswordSchema), @@ -306,7 +307,8 @@ const ChangePasswordForm = ({ const data = Object.fromEntries(new FormData(e.currentTarget).entries()); updatePassword({ - password: data.newPassword.toString(), + currentPassword: data.currentPassword.toString(), + password: data.newPassword.toString(), }); }, }); From 847f7537a304e7ee1873d0eb02b961909cc56ab2 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 10:27:55 -0400 Subject: [PATCH 23/24] fix: don't validate as email --- app/routes/account.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/account.tsx b/app/routes/account.tsx index d404db7..437bb5a 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -271,7 +271,7 @@ const ChangeEmailForm = ({ const ChangePasswordSchema = z .object({ - currentPassword: z.string().email(), + currentPassword: z.string(), newPassword: z.string(), retypePassword: z.string(), }) From 8770e2463990f36f544dd3df9743aabb3e22599f Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Tue, 19 Mar 2024 11:10:02 -0400 Subject: [PATCH 24/24] fix: wrap page in Authenticated component --- app/routes/account.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/routes/account.tsx b/app/routes/account.tsx index 437bb5a..443e726 100644 --- a/app/routes/account.tsx +++ b/app/routes/account.tsx @@ -1,10 +1,11 @@ import { getFormProps, useForm } from "@conform-to/react"; import { getZodConstraint, parseWithZod } from "@conform-to/zod"; import { - BaseKey, - useGetIdentity, - useUpdate, - useUpdatePassword, + Authenticated, + BaseKey, + useGetIdentity, + useUpdate, + useUpdatePassword, } from "@refinedev/core"; import { useState } from "react"; import { z } from "zod"; @@ -41,7 +42,8 @@ export default function MyAccount() { }); return ( - + +

My Account

+
); }