@lukoweb/apitogo-module-user-panel 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/account-paths.ts +42 -42
- package/src/components/AccountLayout.tsx +119 -119
- package/src/hooks/useAccountSettings.ts +93 -93
- package/src/index.tsx +14 -14
- package/src/pages/DefaultDashboardPage.tsx +126 -126
- package/src/pages/DefaultPlansPage.tsx +62 -62
- package/src/pages/DefaultProfilePage.tsx +79 -79
- package/src/pages/SettingsPage.tsx +279 -279
- package/src/renderModuleElement.tsx +18 -18
- package/src/userPanelModule.tsx +152 -152
- package/src/utils/dev-portal-api.ts +125 -125
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukoweb/apitogo-module-user-panel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.tsx"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/react": "19.2.14",
|
|
16
16
|
"@types/react-dom": "19.2.3",
|
|
17
|
-
"@lukoweb/apitogo": "0.2.
|
|
17
|
+
"@lukoweb/apitogo": "0.2.24",
|
|
18
18
|
"react": "19.2.4",
|
|
19
19
|
"react-dom": "19.2.4",
|
|
20
20
|
"react-router": "7.13.1",
|
package/src/account-paths.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
/** Default account area paths (match dev-portal billing plugin). */
|
|
2
|
-
export const DEFAULT_ACCOUNT_BASE_PATH = "/account";
|
|
3
|
-
|
|
4
|
-
export type AccountNavPaths = {
|
|
5
|
-
overview: string;
|
|
6
|
-
apiKeys: string;
|
|
7
|
-
usage: string;
|
|
8
|
-
billing: string;
|
|
9
|
-
settings: string;
|
|
10
|
-
docs: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function buildAccountNavPaths(
|
|
14
|
-
basePath = DEFAULT_ACCOUNT_BASE_PATH,
|
|
15
|
-
docsPath = "/introduction",
|
|
16
|
-
): AccountNavPaths {
|
|
17
|
-
const base = basePath.replace(/\/+$/, "") || DEFAULT_ACCOUNT_BASE_PATH;
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
overview: `${base}/dashboard`,
|
|
21
|
-
apiKeys: `${base}/credentials`,
|
|
22
|
-
usage: `${base}/usage`,
|
|
23
|
-
billing: `${base}/subscriptions`,
|
|
24
|
-
settings: `${base}/profile`,
|
|
25
|
-
docs: docsPath,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function toAccountChildPath(basePath: string, fullPath: string): string {
|
|
30
|
-
const base = basePath.replace(/\/+$/, "");
|
|
31
|
-
const normalized = fullPath.replace(/\/+$/, "") || fullPath;
|
|
32
|
-
|
|
33
|
-
if (normalized === base) {
|
|
34
|
-
return "";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (normalized.startsWith(`${base}/`)) {
|
|
38
|
-
return normalized.slice(base.length + 1);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return normalized.replace(/^\/+/, "");
|
|
42
|
-
}
|
|
1
|
+
/** Default account area paths (match dev-portal billing plugin). */
|
|
2
|
+
export const DEFAULT_ACCOUNT_BASE_PATH = "/account";
|
|
3
|
+
|
|
4
|
+
export type AccountNavPaths = {
|
|
5
|
+
overview: string;
|
|
6
|
+
apiKeys: string;
|
|
7
|
+
usage: string;
|
|
8
|
+
billing: string;
|
|
9
|
+
settings: string;
|
|
10
|
+
docs: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function buildAccountNavPaths(
|
|
14
|
+
basePath = DEFAULT_ACCOUNT_BASE_PATH,
|
|
15
|
+
docsPath = "/introduction",
|
|
16
|
+
): AccountNavPaths {
|
|
17
|
+
const base = basePath.replace(/\/+$/, "") || DEFAULT_ACCOUNT_BASE_PATH;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
overview: `${base}/dashboard`,
|
|
21
|
+
apiKeys: `${base}/credentials`,
|
|
22
|
+
usage: `${base}/usage`,
|
|
23
|
+
billing: `${base}/subscriptions`,
|
|
24
|
+
settings: `${base}/profile`,
|
|
25
|
+
docs: docsPath,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function toAccountChildPath(basePath: string, fullPath: string): string {
|
|
30
|
+
const base = basePath.replace(/\/+$/, "");
|
|
31
|
+
const normalized = fullPath.replace(/\/+$/, "") || fullPath;
|
|
32
|
+
|
|
33
|
+
if (normalized === base) {
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (normalized.startsWith(`${base}/`)) {
|
|
38
|
+
return normalized.slice(base.length + 1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return normalized.replace(/^\/+/, "");
|
|
42
|
+
}
|
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
import { cn } from "@lukoweb/apitogo";
|
|
2
|
-
import { useAuth } from "@lukoweb/apitogo/hooks";
|
|
3
|
-
import {
|
|
4
|
-
BookOpenIcon,
|
|
5
|
-
CreditCardIcon,
|
|
6
|
-
KeyRoundIcon,
|
|
7
|
-
LayoutGridIcon,
|
|
8
|
-
LogOutIcon,
|
|
9
|
-
SettingsIcon,
|
|
10
|
-
BarChart3Icon,
|
|
11
|
-
} from "@lukoweb/apitogo/icons";
|
|
12
|
-
import { Link, NavLink, Outlet } from "@lukoweb/apitogo/router";
|
|
13
|
-
import type { ReactNode } from "react";
|
|
14
|
-
import {
|
|
15
|
-
buildAccountNavPaths,
|
|
16
|
-
DEFAULT_ACCOUNT_BASE_PATH,
|
|
17
|
-
} from "../account-paths.js";
|
|
18
|
-
|
|
19
|
-
type AccountNavItem = {
|
|
20
|
-
label: string;
|
|
21
|
-
to: string;
|
|
22
|
-
icon: typeof LayoutGridIcon;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type AccountLayoutProps = {
|
|
26
|
-
basePath?: string;
|
|
27
|
-
docsPath?: string;
|
|
28
|
-
children?: ReactNode;
|
|
29
|
-
/** When true, show API keys / Usage / Billing (billing plugin routes). */
|
|
30
|
-
includeBillingNav?: boolean;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function AccountLayout({
|
|
34
|
-
basePath = DEFAULT_ACCOUNT_BASE_PATH,
|
|
35
|
-
docsPath = "/introduction",
|
|
36
|
-
children,
|
|
37
|
-
includeBillingNav = false,
|
|
38
|
-
}: AccountLayoutProps) {
|
|
39
|
-
const auth = useAuth();
|
|
40
|
-
const paths = buildAccountNavPaths(basePath, docsPath);
|
|
41
|
-
|
|
42
|
-
const navItems: AccountNavItem[] = [
|
|
43
|
-
{ label: "Overview", to: paths.overview, icon: LayoutGridIcon },
|
|
44
|
-
...(includeBillingNav
|
|
45
|
-
? [
|
|
46
|
-
{ label: "API keys", to: paths.apiKeys, icon: KeyRoundIcon },
|
|
47
|
-
{ label: "Usage", to: paths.usage, icon: BarChart3Icon },
|
|
48
|
-
{ label: "Billing", to: paths.billing, icon: CreditCardIcon },
|
|
49
|
-
]
|
|
50
|
-
: []),
|
|
51
|
-
{ label: "Settings", to: paths.settings, icon: SettingsIcon },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
const renderNavLink = (item: AccountNavItem, compact = false) => (
|
|
55
|
-
<NavLink
|
|
56
|
-
key={item.to}
|
|
57
|
-
to={item.to}
|
|
58
|
-
end={item.to === paths.overview}
|
|
59
|
-
className={({ isActive }) =>
|
|
60
|
-
cn(
|
|
61
|
-
compact
|
|
62
|
-
? "inline-flex shrink-0 items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors"
|
|
63
|
-
: "flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
|
64
|
-
isActive
|
|
65
|
-
? "bg-primary/14 font-semibold text-primary"
|
|
66
|
-
: "text-muted-foreground hover:bg-muted/80 hover:text-foreground",
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
>
|
|
70
|
-
<item.icon
|
|
71
|
-
size={compact ? 18 : 20}
|
|
72
|
-
strokeWidth={1.8}
|
|
73
|
-
className="shrink-0 opacity-80"
|
|
74
|
-
/>
|
|
75
|
-
{item.label}
|
|
76
|
-
</NavLink>
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<div className="flex min-h-[calc(100dvh-var(--header-height))] flex-col bg-muted md:flex-row">
|
|
81
|
-
<nav
|
|
82
|
-
aria-label="Account"
|
|
83
|
-
className="flex gap-1 overflow-x-auto border-b border-border bg-card px-3 py-2 md:hidden"
|
|
84
|
-
>
|
|
85
|
-
{navItems.map((item) => renderNavLink(item, true))}
|
|
86
|
-
</nav>
|
|
87
|
-
|
|
88
|
-
<aside className="hidden w-[236px] shrink-0 flex-col justify-between border-r border-border bg-card px-3 py-4 md:flex">
|
|
89
|
-
<nav className="flex flex-col gap-1">
|
|
90
|
-
{navItems.map((item) => renderNavLink(item))}
|
|
91
|
-
</nav>
|
|
92
|
-
|
|
93
|
-
<div className="flex flex-col gap-1 border-t border-border pt-3">
|
|
94
|
-
<Link
|
|
95
|
-
to={paths.docs}
|
|
96
|
-
className="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground"
|
|
97
|
-
>
|
|
98
|
-
<BookOpenIcon size={20} strokeWidth={1.8} className="shrink-0" />
|
|
99
|
-
Documentation
|
|
100
|
-
</Link>
|
|
101
|
-
{auth.isAuthEnabled ? (
|
|
102
|
-
<button
|
|
103
|
-
type="button"
|
|
104
|
-
className="flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground"
|
|
105
|
-
onClick={() => {
|
|
106
|
-
void auth.logout();
|
|
107
|
-
}}
|
|
108
|
-
>
|
|
109
|
-
<LogOutIcon size={20} strokeWidth={1.8} className="shrink-0" />
|
|
110
|
-
Log out
|
|
111
|
-
</button>
|
|
112
|
-
) : null}
|
|
113
|
-
</div>
|
|
114
|
-
</aside>
|
|
115
|
-
|
|
116
|
-
<main className="min-w-0 flex-1">{children ?? <Outlet />}</main>
|
|
117
|
-
</div>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
1
|
+
import { cn } from "@lukoweb/apitogo";
|
|
2
|
+
import { useAuth } from "@lukoweb/apitogo/hooks";
|
|
3
|
+
import {
|
|
4
|
+
BookOpenIcon,
|
|
5
|
+
CreditCardIcon,
|
|
6
|
+
KeyRoundIcon,
|
|
7
|
+
LayoutGridIcon,
|
|
8
|
+
LogOutIcon,
|
|
9
|
+
SettingsIcon,
|
|
10
|
+
BarChart3Icon,
|
|
11
|
+
} from "@lukoweb/apitogo/icons";
|
|
12
|
+
import { Link, NavLink, Outlet } from "@lukoweb/apitogo/router";
|
|
13
|
+
import type { ReactNode } from "react";
|
|
14
|
+
import {
|
|
15
|
+
buildAccountNavPaths,
|
|
16
|
+
DEFAULT_ACCOUNT_BASE_PATH,
|
|
17
|
+
} from "../account-paths.js";
|
|
18
|
+
|
|
19
|
+
type AccountNavItem = {
|
|
20
|
+
label: string;
|
|
21
|
+
to: string;
|
|
22
|
+
icon: typeof LayoutGridIcon;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type AccountLayoutProps = {
|
|
26
|
+
basePath?: string;
|
|
27
|
+
docsPath?: string;
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
/** When true, show API keys / Usage / Billing (billing plugin routes). */
|
|
30
|
+
includeBillingNav?: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function AccountLayout({
|
|
34
|
+
basePath = DEFAULT_ACCOUNT_BASE_PATH,
|
|
35
|
+
docsPath = "/introduction",
|
|
36
|
+
children,
|
|
37
|
+
includeBillingNav = false,
|
|
38
|
+
}: AccountLayoutProps) {
|
|
39
|
+
const auth = useAuth();
|
|
40
|
+
const paths = buildAccountNavPaths(basePath, docsPath);
|
|
41
|
+
|
|
42
|
+
const navItems: AccountNavItem[] = [
|
|
43
|
+
{ label: "Overview", to: paths.overview, icon: LayoutGridIcon },
|
|
44
|
+
...(includeBillingNav
|
|
45
|
+
? [
|
|
46
|
+
{ label: "API keys", to: paths.apiKeys, icon: KeyRoundIcon },
|
|
47
|
+
{ label: "Usage", to: paths.usage, icon: BarChart3Icon },
|
|
48
|
+
{ label: "Billing", to: paths.billing, icon: CreditCardIcon },
|
|
49
|
+
]
|
|
50
|
+
: []),
|
|
51
|
+
{ label: "Settings", to: paths.settings, icon: SettingsIcon },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const renderNavLink = (item: AccountNavItem, compact = false) => (
|
|
55
|
+
<NavLink
|
|
56
|
+
key={item.to}
|
|
57
|
+
to={item.to}
|
|
58
|
+
end={item.to === paths.overview}
|
|
59
|
+
className={({ isActive }) =>
|
|
60
|
+
cn(
|
|
61
|
+
compact
|
|
62
|
+
? "inline-flex shrink-0 items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors"
|
|
63
|
+
: "flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
|
64
|
+
isActive
|
|
65
|
+
? "bg-primary/14 font-semibold text-primary"
|
|
66
|
+
: "text-muted-foreground hover:bg-muted/80 hover:text-foreground",
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
>
|
|
70
|
+
<item.icon
|
|
71
|
+
size={compact ? 18 : 20}
|
|
72
|
+
strokeWidth={1.8}
|
|
73
|
+
className="shrink-0 opacity-80"
|
|
74
|
+
/>
|
|
75
|
+
{item.label}
|
|
76
|
+
</NavLink>
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div className="flex min-h-[calc(100dvh-var(--header-height))] flex-col bg-muted md:flex-row">
|
|
81
|
+
<nav
|
|
82
|
+
aria-label="Account"
|
|
83
|
+
className="flex gap-1 overflow-x-auto border-b border-border bg-card px-3 py-2 md:hidden"
|
|
84
|
+
>
|
|
85
|
+
{navItems.map((item) => renderNavLink(item, true))}
|
|
86
|
+
</nav>
|
|
87
|
+
|
|
88
|
+
<aside className="hidden w-[236px] shrink-0 flex-col justify-between border-r border-border bg-card px-3 py-4 md:flex">
|
|
89
|
+
<nav className="flex flex-col gap-1">
|
|
90
|
+
{navItems.map((item) => renderNavLink(item))}
|
|
91
|
+
</nav>
|
|
92
|
+
|
|
93
|
+
<div className="flex flex-col gap-1 border-t border-border pt-3">
|
|
94
|
+
<Link
|
|
95
|
+
to={paths.docs}
|
|
96
|
+
className="flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground"
|
|
97
|
+
>
|
|
98
|
+
<BookOpenIcon size={20} strokeWidth={1.8} className="shrink-0" />
|
|
99
|
+
Documentation
|
|
100
|
+
</Link>
|
|
101
|
+
{auth.isAuthEnabled ? (
|
|
102
|
+
<button
|
|
103
|
+
type="button"
|
|
104
|
+
className="flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-medium text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground"
|
|
105
|
+
onClick={() => {
|
|
106
|
+
void auth.logout();
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
<LogOutIcon size={20} strokeWidth={1.8} className="shrink-0" />
|
|
110
|
+
Log out
|
|
111
|
+
</button>
|
|
112
|
+
) : null}
|
|
113
|
+
</div>
|
|
114
|
+
</aside>
|
|
115
|
+
|
|
116
|
+
<main className="min-w-0 flex-1">{children ?? <Outlet />}</main>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import { useAuth, useZudoku } from "@lukoweb/apitogo/hooks";
|
|
2
|
-
import {
|
|
3
|
-
useMutation,
|
|
4
|
-
useQuery,
|
|
5
|
-
useQueryClient,
|
|
6
|
-
} from "@lukoweb/apitogo/react-query";
|
|
7
|
-
import {
|
|
8
|
-
changeAccountPassword,
|
|
9
|
-
deleteAccount,
|
|
10
|
-
fetchAccountMe,
|
|
11
|
-
resolveDevPortalApiBaseUrl,
|
|
12
|
-
updateAccountProfile,
|
|
13
|
-
} from "../utils/dev-portal-api.js";
|
|
14
|
-
|
|
15
|
-
export function useAccountMe() {
|
|
16
|
-
const auth = useAuth();
|
|
17
|
-
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
18
|
-
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
return useQuery({
|
|
22
|
-
queryKey: ["account-me", apiBaseUrl],
|
|
23
|
-
enabled: auth.isAuthenticated && Boolean(apiBaseUrl),
|
|
24
|
-
queryFn: () => fetchAccountMe(apiBaseUrl!),
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function useUpdateAccountProfile() {
|
|
29
|
-
const auth = useAuth();
|
|
30
|
-
const { authentication } = useZudoku();
|
|
31
|
-
const queryClient = useQueryClient();
|
|
32
|
-
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
33
|
-
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
return useMutation({
|
|
37
|
-
mutationFn: (displayName: string) => {
|
|
38
|
-
if (!apiBaseUrl) {
|
|
39
|
-
throw new Error("Dev portal API is not configured.");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return updateAccountProfile(apiBaseUrl, displayName);
|
|
43
|
-
},
|
|
44
|
-
onSuccess: async () => {
|
|
45
|
-
await queryClient.invalidateQueries({ queryKey: ["account-me"] });
|
|
46
|
-
await queryClient.invalidateQueries({ queryKey: ["dev-portal-me"] });
|
|
47
|
-
await authentication?.refreshUserProfile?.();
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function useChangeAccountPassword() {
|
|
53
|
-
const auth = useAuth();
|
|
54
|
-
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
55
|
-
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
return useMutation({
|
|
59
|
-
mutationFn: ({
|
|
60
|
-
currentPassword,
|
|
61
|
-
newPassword,
|
|
62
|
-
}: {
|
|
63
|
-
currentPassword: string;
|
|
64
|
-
newPassword: string;
|
|
65
|
-
}) => {
|
|
66
|
-
if (!apiBaseUrl) {
|
|
67
|
-
throw new Error("Dev portal API is not configured.");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return changeAccountPassword(apiBaseUrl, currentPassword, newPassword);
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function useDeleteAccount() {
|
|
76
|
-
const auth = useAuth();
|
|
77
|
-
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
78
|
-
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
return useMutation({
|
|
82
|
-
mutationFn: (password?: string) => {
|
|
83
|
-
if (!apiBaseUrl) {
|
|
84
|
-
throw new Error("Dev portal API is not configured.");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return deleteAccount(apiBaseUrl, password);
|
|
88
|
-
},
|
|
89
|
-
onSuccess: async () => {
|
|
90
|
-
await auth.logout();
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
1
|
+
import { useAuth, useZudoku } from "@lukoweb/apitogo/hooks";
|
|
2
|
+
import {
|
|
3
|
+
useMutation,
|
|
4
|
+
useQuery,
|
|
5
|
+
useQueryClient,
|
|
6
|
+
} from "@lukoweb/apitogo/react-query";
|
|
7
|
+
import {
|
|
8
|
+
changeAccountPassword,
|
|
9
|
+
deleteAccount,
|
|
10
|
+
fetchAccountMe,
|
|
11
|
+
resolveDevPortalApiBaseUrl,
|
|
12
|
+
updateAccountProfile,
|
|
13
|
+
} from "../utils/dev-portal-api.js";
|
|
14
|
+
|
|
15
|
+
export function useAccountMe() {
|
|
16
|
+
const auth = useAuth();
|
|
17
|
+
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
18
|
+
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return useQuery({
|
|
22
|
+
queryKey: ["account-me", apiBaseUrl],
|
|
23
|
+
enabled: auth.isAuthenticated && Boolean(apiBaseUrl),
|
|
24
|
+
queryFn: () => fetchAccountMe(apiBaseUrl!),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useUpdateAccountProfile() {
|
|
29
|
+
const auth = useAuth();
|
|
30
|
+
const { authentication } = useZudoku();
|
|
31
|
+
const queryClient = useQueryClient();
|
|
32
|
+
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
33
|
+
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return useMutation({
|
|
37
|
+
mutationFn: (displayName: string) => {
|
|
38
|
+
if (!apiBaseUrl) {
|
|
39
|
+
throw new Error("Dev portal API is not configured.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return updateAccountProfile(apiBaseUrl, displayName);
|
|
43
|
+
},
|
|
44
|
+
onSuccess: async () => {
|
|
45
|
+
await queryClient.invalidateQueries({ queryKey: ["account-me"] });
|
|
46
|
+
await queryClient.invalidateQueries({ queryKey: ["dev-portal-me"] });
|
|
47
|
+
await authentication?.refreshUserProfile?.();
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useChangeAccountPassword() {
|
|
53
|
+
const auth = useAuth();
|
|
54
|
+
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
55
|
+
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return useMutation({
|
|
59
|
+
mutationFn: ({
|
|
60
|
+
currentPassword,
|
|
61
|
+
newPassword,
|
|
62
|
+
}: {
|
|
63
|
+
currentPassword: string;
|
|
64
|
+
newPassword: string;
|
|
65
|
+
}) => {
|
|
66
|
+
if (!apiBaseUrl) {
|
|
67
|
+
throw new Error("Dev portal API is not configured.");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return changeAccountPassword(apiBaseUrl, currentPassword, newPassword);
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function useDeleteAccount() {
|
|
76
|
+
const auth = useAuth();
|
|
77
|
+
const apiBaseUrl = resolveDevPortalApiBaseUrl(
|
|
78
|
+
auth.providerData as { type: "dev-portal"; apiBaseUrl: string } | null,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return useMutation({
|
|
82
|
+
mutationFn: (password?: string) => {
|
|
83
|
+
if (!apiBaseUrl) {
|
|
84
|
+
throw new Error("Dev portal API is not configured.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return deleteAccount(apiBaseUrl, password);
|
|
88
|
+
},
|
|
89
|
+
onSuccess: async () => {
|
|
90
|
+
await auth.logout();
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export { userPanelModule } from "./userPanelModule.js";
|
|
2
|
-
export type { UserPanelModuleOptions } from "./userPanelModule.js";
|
|
3
|
-
export { AccountLayout } from "./components/AccountLayout.js";
|
|
4
|
-
export type { AccountLayoutProps } from "./components/AccountLayout.js";
|
|
5
|
-
export {
|
|
6
|
-
buildAccountNavPaths,
|
|
7
|
-
DEFAULT_ACCOUNT_BASE_PATH,
|
|
8
|
-
toAccountChildPath,
|
|
9
|
-
} from "./account-paths.js";
|
|
10
|
-
export type { AccountNavPaths } from "./account-paths.js";
|
|
11
|
-
export { DefaultDashboardPage } from "./pages/DefaultDashboardPage.js";
|
|
12
|
-
export { SettingsPage } from "./pages/SettingsPage.js";
|
|
13
|
-
export { DefaultProfilePage } from "./pages/DefaultProfilePage.js";
|
|
14
|
-
export { DefaultPlansPage } from "./pages/DefaultPlansPage.js";
|
|
1
|
+
export { userPanelModule } from "./userPanelModule.js";
|
|
2
|
+
export type { UserPanelModuleOptions } from "./userPanelModule.js";
|
|
3
|
+
export { AccountLayout } from "./components/AccountLayout.js";
|
|
4
|
+
export type { AccountLayoutProps } from "./components/AccountLayout.js";
|
|
5
|
+
export {
|
|
6
|
+
buildAccountNavPaths,
|
|
7
|
+
DEFAULT_ACCOUNT_BASE_PATH,
|
|
8
|
+
toAccountChildPath,
|
|
9
|
+
} from "./account-paths.js";
|
|
10
|
+
export type { AccountNavPaths } from "./account-paths.js";
|
|
11
|
+
export { DefaultDashboardPage } from "./pages/DefaultDashboardPage.js";
|
|
12
|
+
export { SettingsPage } from "./pages/SettingsPage.js";
|
|
13
|
+
export { DefaultProfilePage } from "./pages/DefaultProfilePage.js";
|
|
14
|
+
export { DefaultPlansPage } from "./pages/DefaultPlansPage.js";
|