@acmekit/dashboard 2.13.6 → 2.13.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acmekit/dashboard",
3
- "version": "2.13.6",
3
+ "version": "2.13.7",
4
4
  "scripts": {
5
5
  "generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts",
6
6
  "dev": "../../../node_modules/.bin/vite",
@@ -39,10 +39,10 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@acmekit/admin-shared": "2.13.6",
43
- "@acmekit/icons": "2.13.6",
44
- "@acmekit/js-sdk": "2.13.6",
45
- "@acmekit/ui": "4.1.6",
42
+ "@acmekit/admin-shared": "2.13.7",
43
+ "@acmekit/icons": "2.13.7",
44
+ "@acmekit/js-sdk": "2.13.7",
45
+ "@acmekit/ui": "4.1.7",
46
46
  "@ariakit/react": "^0.4.15",
47
47
  "@babel/runtime": "^7.26.10",
48
48
  "@dnd-kit/core": "^6.1.0",
@@ -80,10 +80,10 @@
80
80
  "zod": "3.25.76"
81
81
  },
82
82
  "devDependencies": {
83
- "@acmekit/admin-shared": "2.13.6",
84
- "@acmekit/admin-vite-plugin": "2.13.6",
85
- "@acmekit/types": "2.13.6",
86
- "@acmekit/ui-preset": "2.13.6"
83
+ "@acmekit/admin-shared": "2.13.7",
84
+ "@acmekit/admin-vite-plugin": "2.13.7",
85
+ "@acmekit/types": "2.13.7",
86
+ "@acmekit/ui-preset": "2.13.7"
87
87
  },
88
88
  "packageManager": "yarn@3.2.1"
89
89
  }
@@ -1,11 +1,12 @@
1
1
  import { ArrowUturnLeft, MinusMini } from "@acmekit/icons"
2
2
  import { clx, Divider, IconButton, Text } from "@acmekit/ui"
3
3
  import { Collapsible as RadixCollapsible } from "radix-ui"
4
- import { useEffect, useState } from "react"
4
+ import { Fragment, useEffect, useMemo, useState } from "react"
5
5
  import { useTranslation } from "react-i18next"
6
6
  import { Link, useLocation } from "react-router-dom"
7
7
 
8
8
  import { useExtension } from "../../../providers/extension-provider"
9
+ import { useFeatureFlag } from "../../../providers/feature-flag-provider"
9
10
  import { INavItem, NavItem } from "../nav-item"
10
11
  import { Shell } from "../shell"
11
12
  import { UserMenu } from "../user-menu"
@@ -18,6 +19,42 @@ export const SettingsLayout = () => {
18
19
  )
19
20
  }
20
21
 
22
+ const useSettingRoutes = (): INavItem[] => {
23
+ const isTranslationsEnabled = useFeatureFlag("translation")
24
+ const { t } = useTranslation()
25
+
26
+ return useMemo(
27
+ () => [
28
+ { label: t("store.domain"), to: "/settings/store" },
29
+ { label: t("users.domain"), to: "/settings/users" },
30
+ ...(isTranslationsEnabled
31
+ ? [{ label: t("translations.domain"), to: "/settings/translations" }]
32
+ : []),
33
+ ],
34
+ [t, isTranslationsEnabled]
35
+ )
36
+ }
37
+
38
+ const useDeveloperRoutes = (): INavItem[] => {
39
+ const { t } = useTranslation()
40
+ return useMemo(
41
+ () => [
42
+ { label: t("apiKeyManagement.domain.publishable"), to: "/settings/publishable-api-keys" },
43
+ { label: t("apiKeyManagement.domain.secret"), to: "/settings/secret-api-keys" },
44
+ { label: t("workflowExecutions.domain"), to: "/settings/workflows" },
45
+ ],
46
+ [t]
47
+ )
48
+ }
49
+
50
+ const useMyAccountRoutes = (): INavItem[] => {
51
+ const { t } = useTranslation()
52
+ return useMemo(
53
+ () => [{ label: t("profile.domain"), to: "/settings/profile" }],
54
+ [t]
55
+ )
56
+ }
57
+
21
58
  /**
22
59
  * Ensure that the `from` prop is not another settings route, to avoid
23
60
  * the user getting stuck in a navigation loop.
@@ -26,7 +63,6 @@ const getSafeFromValue = (from: string) => {
26
63
  if (from.startsWith("/settings")) {
27
64
  return "/"
28
65
  }
29
-
30
66
  return from
31
67
  }
32
68
 
@@ -34,6 +70,9 @@ const SettingsSidebar = () => {
34
70
  const { getMenu } = useExtension()
35
71
  const extensionRoutes = getMenu("settingsExtensions")
36
72
  const { t } = useTranslation()
73
+ const routes = useSettingRoutes()
74
+ const developerRoutes = useDeveloperRoutes()
75
+ const myAccountRoutes = useMyAccountRoutes()
37
76
 
38
77
  return (
39
78
  <aside className="relative flex flex-1 flex-col justify-between overflow-y-auto">
@@ -45,11 +84,34 @@ const SettingsSidebar = () => {
45
84
  </div>
46
85
  <div className="flex flex-1 flex-col">
47
86
  <div className="flex flex-1 flex-col overflow-y-auto">
87
+ <RadixCollapsibleSection
88
+ label={t("app.nav.settings.general")}
89
+ items={routes}
90
+ />
91
+ <div className="flex items-center justify-center px-3">
92
+ <Divider variant="dashed" />
93
+ </div>
94
+ <RadixCollapsibleSection
95
+ label={t("app.nav.settings.developer")}
96
+ items={developerRoutes}
97
+ />
98
+ <div className="flex items-center justify-center px-3">
99
+ <Divider variant="dashed" />
100
+ </div>
101
+ <RadixCollapsibleSection
102
+ label={t("app.nav.settings.myAccount")}
103
+ items={myAccountRoutes}
104
+ />
48
105
  {extensionRoutes.length > 0 ? (
49
- <RadixCollapsibleSection
50
- label={t("app.nav.common.extensions")}
51
- items={extensionRoutes}
52
- />
106
+ <Fragment>
107
+ <div className="flex items-center justify-center px-3">
108
+ <Divider variant="dashed" />
109
+ </div>
110
+ <RadixCollapsibleSection
111
+ label={t("app.nav.common.extensions")}
112
+ items={extensionRoutes}
113
+ />
114
+ </Fragment>
53
115
  ) : null}
54
116
  </div>
55
117
  <div className="bg-ui-bg-subtle sticky bottom-0">
@@ -18,6 +18,230 @@ function mergeSettingsRouteChildren(
18
18
  .flatMap((r) => r.children ?? [])
19
19
  }
20
20
 
21
+ /** Default framework settings routes (profile, store, users, api-keys, workflows, translations). */
22
+ const defaultSettingsRouteChildren: RouteObject[] = [
23
+ {
24
+ path: "profile",
25
+ errorElement: <ErrorBoundary />,
26
+ lazy: () => import("../../routes/profile/profile-detail"),
27
+ handle: { breadcrumb: () => t("profile.domain") },
28
+ children: [
29
+ {
30
+ path: "edit",
31
+ lazy: () => import("../../routes/profile/profile-edit"),
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ path: "store",
37
+ errorElement: <ErrorBoundary />,
38
+ lazy: () => import("../../routes/store/store-detail"),
39
+ handle: { breadcrumb: () => t("store.domain") },
40
+ children: [
41
+ { path: "edit", lazy: () => import("../../routes/store/store-edit") },
42
+ {
43
+ path: "metadata/edit",
44
+ lazy: () => import("../../routes/store/store-metadata"),
45
+ },
46
+ ],
47
+ },
48
+ {
49
+ path: "users",
50
+ errorElement: <ErrorBoundary />,
51
+ element: <Outlet />,
52
+ handle: { breadcrumb: () => t("users.domain") },
53
+ children: [
54
+ {
55
+ path: "",
56
+ lazy: () => import("../../routes/users/user-list"),
57
+ children: [
58
+ {
59
+ path: "invite",
60
+ lazy: () => import("../../routes/users/user-invite"),
61
+ },
62
+ ],
63
+ },
64
+ {
65
+ path: ":id",
66
+ lazy: async () => {
67
+ const { Component, Breadcrumb, loader } = await import(
68
+ "../../routes/users/user-detail"
69
+ )
70
+ return {
71
+ Component,
72
+ loader,
73
+ handle: {
74
+ breadcrumb: (match: unknown) => (
75
+ <Breadcrumb {...(match as object)} />
76
+ ),
77
+ },
78
+ }
79
+ },
80
+ children: [
81
+ { path: "edit", lazy: () => import("../../routes/users/user-edit") },
82
+ {
83
+ path: "metadata/edit",
84
+ lazy: () => import("../../routes/users/user-metadata"),
85
+ },
86
+ ],
87
+ },
88
+ ],
89
+ },
90
+ {
91
+ path: "publishable-api-keys",
92
+ element: <Outlet />,
93
+ handle: { breadcrumb: () => t("apiKeyManagement.domain.publishable") },
94
+ children: [
95
+ {
96
+ path: "",
97
+ element: <Outlet />,
98
+ children: [
99
+ {
100
+ path: "",
101
+ lazy: () =>
102
+ import("../../routes/api-key-management/api-key-management-list"),
103
+ children: [
104
+ {
105
+ path: "create",
106
+ lazy: () =>
107
+ import(
108
+ "../../routes/api-key-management/api-key-management-create"
109
+ ),
110
+ },
111
+ ],
112
+ },
113
+ ],
114
+ },
115
+ {
116
+ path: ":id",
117
+ lazy: async () => {
118
+ const { Component, Breadcrumb, loader } = await import(
119
+ "../../routes/api-key-management/api-key-management-detail"
120
+ )
121
+ return {
122
+ Component,
123
+ loader,
124
+ handle: {
125
+ breadcrumb: (match: unknown) => (
126
+ <Breadcrumb {...(match as object)} />
127
+ ),
128
+ },
129
+ }
130
+ },
131
+ children: [
132
+ {
133
+ path: "edit",
134
+ lazy: () =>
135
+ import("../../routes/api-key-management/api-key-management-edit"),
136
+ },
137
+ ],
138
+ },
139
+ ],
140
+ },
141
+ {
142
+ path: "secret-api-keys",
143
+ element: <Outlet />,
144
+ handle: { breadcrumb: () => t("apiKeyManagement.domain.secret") },
145
+ children: [
146
+ {
147
+ path: "",
148
+ element: <Outlet />,
149
+ children: [
150
+ {
151
+ path: "",
152
+ lazy: () =>
153
+ import("../../routes/api-key-management/api-key-management-list"),
154
+ children: [
155
+ {
156
+ path: "create",
157
+ lazy: () =>
158
+ import(
159
+ "../../routes/api-key-management/api-key-management-create"
160
+ ),
161
+ },
162
+ ],
163
+ },
164
+ ],
165
+ },
166
+ {
167
+ path: ":id",
168
+ lazy: async () => {
169
+ const { Component, Breadcrumb, loader } = await import(
170
+ "../../routes/api-key-management/api-key-management-detail"
171
+ )
172
+ return {
173
+ Component,
174
+ loader,
175
+ handle: {
176
+ breadcrumb: (match: unknown) => (
177
+ <Breadcrumb {...(match as object)} />
178
+ ),
179
+ },
180
+ }
181
+ },
182
+ children: [
183
+ {
184
+ path: "edit",
185
+ lazy: () =>
186
+ import("../../routes/api-key-management/api-key-management-edit"),
187
+ },
188
+ ],
189
+ },
190
+ ],
191
+ },
192
+ {
193
+ path: "workflows",
194
+ errorElement: <ErrorBoundary />,
195
+ element: <Outlet />,
196
+ handle: { breadcrumb: () => t("workflowExecutions.domain") },
197
+ children: [
198
+ {
199
+ path: "",
200
+ lazy: () =>
201
+ import("../../routes/workflow-executions/workflow-execution-list"),
202
+ },
203
+ {
204
+ path: ":id",
205
+ lazy: async () => {
206
+ const { Component, Breadcrumb, loader } = await import(
207
+ "../../routes/workflow-executions/workflow-execution-detail"
208
+ )
209
+ return {
210
+ Component,
211
+ loader,
212
+ handle: {
213
+ breadcrumb: (match: unknown) => (
214
+ <Breadcrumb {...(match as object)} />
215
+ ),
216
+ },
217
+ }
218
+ },
219
+ },
220
+ ],
221
+ },
222
+ {
223
+ path: "translations",
224
+ errorElement: <ErrorBoundary />,
225
+ handle: { breadcrumb: () => t("translations.domain") },
226
+ children: [
227
+ {
228
+ path: "",
229
+ lazy: () => import("../../routes/translations/translation-list"),
230
+ children: [
231
+ {
232
+ path: "settings",
233
+ lazy: () => import("../../routes/translations/settings"),
234
+ },
235
+ ],
236
+ },
237
+ {
238
+ path: "edit",
239
+ lazy: () => import("../../routes/translations/translations-edit"),
240
+ },
241
+ ],
242
+ },
243
+ ]
244
+
21
245
  export function getRouteMap({
22
246
  settingsRoutes,
23
247
  coreRoutes,
@@ -55,6 +279,7 @@ export function getRouteMap({
55
279
  errorElement: <ErrorBoundary />,
56
280
  lazy: () => import("../../routes/settings"),
57
281
  },
282
+ ...defaultSettingsRouteChildren,
58
283
  ...settingsPluginChildren,
59
284
  ],
60
285
  },
@@ -23,7 +23,7 @@ export const Login = () => {
23
23
  const navigate = useNavigate()
24
24
  const { getWidgets } = useExtension()
25
25
 
26
- const from = location.state?.from?.pathname || "/orders"
26
+ const from = location.state?.from?.pathname || "/"
27
27
 
28
28
  const form = useForm<z.infer<typeof LoginSchema>>({
29
29
  resolver: zodResolver(LoginSchema),
@@ -1,159 +0,0 @@
1
- import {
2
- queryKeysFactory
3
- } from "./chunk-QYOO4QR6.mjs";
4
- import {
5
- sdk
6
- } from "./chunk-4VYJHIB3.mjs";
7
-
8
- // src/hooks/api/cloud.tsx
9
- import {
10
- useMutation,
11
- useQuery
12
- } from "@tanstack/react-query";
13
- var cloudQueryKeys = {
14
- all: ["cloud"],
15
- auth: () => [...cloudQueryKeys.all, "auth"]
16
- };
17
- var useCloudAuthEnabled = (options) => {
18
- return useQuery({
19
- queryKey: cloudQueryKeys.auth(),
20
- queryFn: async () => {
21
- return await sdk.client.fetch("/cloud/auth");
22
- },
23
- ...options
24
- });
25
- };
26
- var useCreateCloudAuthUser = (options) => {
27
- return useMutation({
28
- mutationFn: async () => {
29
- await sdk.client.fetch("/cloud/auth/users", {
30
- method: "POST"
31
- });
32
- },
33
- ...options
34
- });
35
- };
36
-
37
- // src/hooks/api/feature-flags.tsx
38
- import { useQuery as useQuery2 } from "@tanstack/react-query";
39
- var useFeatureFlags = () => {
40
- return useQuery2({
41
- queryKey: ["admin", "feature-flags"],
42
- queryFn: async () => {
43
- const response = await sdk.client.fetch(
44
- "/admin/feature-flags",
45
- {
46
- method: "GET"
47
- }
48
- );
49
- return response.feature_flags;
50
- },
51
- staleTime: 5 * 60 * 1e3,
52
- // Cache for 5 minutes
53
- cacheTime: 10 * 60 * 1e3
54
- // Keep in cache for 10 minutes
55
- });
56
- };
57
-
58
- // src/hooks/api/locales.tsx
59
- import { useQuery as useQuery3 } from "@tanstack/react-query";
60
- var LOCALES_QUERY_KEY = "locales";
61
- var localesQueryKeys = queryKeysFactory(LOCALES_QUERY_KEY);
62
-
63
- // src/hooks/api/notification.tsx
64
- import { useQuery as useQuery4 } from "@tanstack/react-query";
65
- var NOTIFICATION_QUERY_KEY = "notification";
66
- var notificationQueryKeys = queryKeysFactory(NOTIFICATION_QUERY_KEY);
67
- var useNotifications = (query, options) => {
68
- const { data, ...rest } = useQuery4({
69
- queryFn: () => sdk.admin.notification.list(query),
70
- queryKey: notificationQueryKeys.list(query),
71
- ...options
72
- });
73
- return { ...data, ...rest };
74
- };
75
-
76
- // src/hooks/api/plugins.tsx
77
- import { useQuery as useQuery5 } from "@tanstack/react-query";
78
- var PLUGINS_QUERY_KEY = "plugins";
79
- var pluginsQueryKeys = queryKeysFactory(PLUGINS_QUERY_KEY);
80
-
81
- // src/hooks/api/translations.tsx
82
- import {
83
- useInfiniteQuery,
84
- useMutation as useMutation2,
85
- useQuery as useQuery6
86
- } from "@tanstack/react-query";
87
- var TRANSLATIONS_QUERY_KEY = "translations";
88
- var translationsQueryKeys = queryKeysFactory(TRANSLATIONS_QUERY_KEY);
89
- var TRANSLATION_SETTINGS_QUERY_KEY = "translation_settings";
90
- var translationSettingsQueryKeys = queryKeysFactory(
91
- TRANSLATION_SETTINGS_QUERY_KEY
92
- );
93
- var TRANSLATION_STATISTICS_QUERY_KEY = "translation_statistics";
94
- var translationStatisticsQueryKeys = queryKeysFactory(
95
- TRANSLATION_STATISTICS_QUERY_KEY
96
- );
97
- var TRANSLATION_ENTITIES_QUERY_KEY = "translation_entities";
98
- var translationEntitiesQueryKeys = queryKeysFactory(
99
- TRANSLATION_ENTITIES_QUERY_KEY
100
- );
101
-
102
- // src/hooks/api/users.tsx
103
- import {
104
- useMutation as useMutation3,
105
- useQuery as useQuery7
106
- } from "@tanstack/react-query";
107
- var USERS_QUERY_KEY = "users";
108
- var usersQueryKeys = {
109
- ...queryKeysFactory(USERS_QUERY_KEY),
110
- me: () => [USERS_QUERY_KEY, "me"]
111
- };
112
- var useMe = (query, options) => {
113
- const { data, ...rest } = useQuery7({
114
- queryFn: () => sdk.admin.user.me(query),
115
- queryKey: usersQueryKeys.me(),
116
- ...options
117
- });
118
- return {
119
- ...data,
120
- ...rest
121
- };
122
- };
123
-
124
- // src/hooks/api/views.tsx
125
- import {
126
- useMutation as useMutation4,
127
- useQuery as useQuery8
128
- } from "@tanstack/react-query";
129
- var VIEWS_QUERY_KEY = "views";
130
- var _viewsKeys = queryKeysFactory(VIEWS_QUERY_KEY);
131
- _viewsKeys.columns = function(entity) {
132
- return [this.all, "columns", entity];
133
- };
134
- _viewsKeys.active = function(entity) {
135
- return [this.detail(entity), "active"];
136
- };
137
- _viewsKeys.configurations = function(entity, query) {
138
- const key = [this.all, "configurations", entity];
139
- if (query !== void 0) {
140
- key.push(query);
141
- }
142
- return key;
143
- };
144
-
145
- // src/hooks/api/workflow-executions.tsx
146
- import { useQuery as useQuery9 } from "@tanstack/react-query";
147
- var WORKFLOW_EXECUTIONS_QUERY_KEY = "workflow_executions";
148
- var workflowExecutionsQueryKeys = queryKeysFactory(
149
- WORKFLOW_EXECUTIONS_QUERY_KEY
150
- );
151
-
152
- export {
153
- useFeatureFlags,
154
- useMe,
155
- useCloudAuthEnabled,
156
- useCreateCloudAuthUser,
157
- notificationQueryKeys,
158
- useNotifications
159
- };
@@ -1,291 +0,0 @@
1
- import {
2
- useCloudAuthEnabled,
3
- useCreateCloudAuthUser
4
- } from "./chunk-NQEMGMWU.mjs";
5
- import {
6
- useExtension
7
- } from "./chunk-C5P5PL3E.mjs";
8
- import {
9
- isFetchError
10
- } from "./chunk-QYOO4QR6.mjs";
11
- import {
12
- AvatarBox
13
- } from "./chunk-JSJZMTQG.mjs";
14
- import {
15
- Form,
16
- sdk,
17
- useSignInWithEmailPass
18
- } from "./chunk-4VYJHIB3.mjs";
19
- import "./chunk-QZ7TP4HQ.mjs";
20
-
21
- // src/routes/login/login.tsx
22
- import { zodResolver } from "@hookform/resolvers/zod";
23
- import { Alert, Button as Button2, Heading, Hint, Input, Text } from "@acmekit/ui";
24
- import { useForm } from "react-hook-form";
25
- import { Trans, useTranslation as useTranslation2 } from "react-i18next";
26
- import { Link, useLocation, useNavigate as useNavigate2 } from "react-router-dom";
27
- import * as z from "zod";
28
-
29
- // src/routes/login/components/cloud-auth-login.tsx
30
- import { Spinner } from "@acmekit/icons";
31
- import { Button, toast } from "@acmekit/ui";
32
- import { useCallback, useEffect, useRef, useState } from "react";
33
- import { useTranslation } from "react-i18next";
34
- import { decodeToken } from "react-jwt";
35
- import { useNavigate, useSearchParams } from "react-router-dom";
36
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
37
- var CLOUD_AUTH_PROVIDER = "cloud";
38
- var CloudAuthLogin = () => {
39
- const { t } = useTranslation();
40
- const [searchParams] = useSearchParams();
41
- const { data: cloudAuth } = useCloudAuthEnabled();
42
- const isAutoLogin = searchParams.get("auth_provider") === CLOUD_AUTH_PROVIDER && searchParams.get("auto") === "true";
43
- const isCallback = searchParams.get("auth_provider") === CLOUD_AUTH_PROVIDER && (searchParams.has("code") || searchParams.has("error"));
44
- const { handleLogin, isLoginPending } = useHandleLogin(isAutoLogin);
45
- const { handleCallback, isCallbackPending } = useAuthCallback(searchParams);
46
- const actionInitiated = useRef(false);
47
- useEffect(() => {
48
- if (actionInitiated.current) {
49
- return;
50
- }
51
- if (isAutoLogin) {
52
- actionInitiated.current = true;
53
- handleLogin();
54
- } else if (isCallback) {
55
- actionInitiated.current = true;
56
- handleCallback();
57
- }
58
- }, [isAutoLogin, isCallback, handleLogin, handleCallback]);
59
- if (isAutoLogin || isCallback) {
60
- return /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle fixed inset-0 z-50 flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, { className: "text-ui-fg-subtle animate-spin" }) });
61
- }
62
- if (!cloudAuth?.enabled) {
63
- return null;
64
- }
65
- return /* @__PURE__ */ jsxs(Fragment, { children: [
66
- /* @__PURE__ */ jsx("hr", { className: "bg-ui-border-base my-4" }),
67
- /* @__PURE__ */ jsx(
68
- Button,
69
- {
70
- variant: "secondary",
71
- onClick: handleLogin,
72
- className: "w-full",
73
- disabled: isLoginPending || isCallbackPending,
74
- isLoading: isLoginPending || isCallbackPending,
75
- children: t("auth.login.cloud")
76
- }
77
- )
78
- ] });
79
- };
80
- var useHandleLogin = (isAutoLogin) => {
81
- const { t } = useTranslation();
82
- const navigate = useNavigate();
83
- const [isPending, setIsPending] = useState(false);
84
- const handleLogin = useCallback(async () => {
85
- setIsPending(true);
86
- try {
87
- const result = await sdk.auth.login("user", CLOUD_AUTH_PROVIDER, {
88
- // setting callback_url in case the admin is on a different domain, or the backend URL is set to just "/" which won't work for the callback
89
- callback_url: `${window.location.origin}${window.location.pathname}?auth_provider=${CLOUD_AUTH_PROVIDER}`
90
- });
91
- if (typeof result === "object" && result.location) {
92
- window.location.href = result.location;
93
- return;
94
- }
95
- throw new Error("Unexpected login response");
96
- } catch {
97
- toast.error(t("auth.login.authenticationFailed"));
98
- if (isAutoLogin) {
99
- navigate("/login");
100
- }
101
- }
102
- setIsPending(false);
103
- }, [t, navigate, isAutoLogin]);
104
- return { handleLogin, isLoginPending: isPending };
105
- };
106
- var useAuthCallback = (searchParams) => {
107
- const { t } = useTranslation();
108
- const navigate = useNavigate();
109
- const { mutateAsync: createCloudAuthUser } = useCreateCloudAuthUser();
110
- const [isPending, setIsPending] = useState(false);
111
- const handleCallback = useCallback(async () => {
112
- setIsPending(true);
113
- try {
114
- let token;
115
- try {
116
- const query = Object.fromEntries(searchParams);
117
- delete query.auth_provider;
118
- token = await sdk.auth.callback("user", CLOUD_AUTH_PROVIDER, query);
119
- } catch (error) {
120
- throw new Error("Authentication callback failed");
121
- }
122
- const decodedToken = decodeToken(token);
123
- if (!decodedToken?.actor_id) {
124
- await createCloudAuthUser();
125
- const refreshedToken = await sdk.auth.refresh({
126
- Authorization: `Bearer ${token}`
127
- // passing it manually in case the auth type is session
128
- });
129
- if (!refreshedToken) {
130
- throw new Error("Failed to refresh token after user creation");
131
- }
132
- }
133
- navigate("/");
134
- } catch (error) {
135
- toast.error(t("auth.login.authenticationFailed"));
136
- navigate("/login");
137
- }
138
- setIsPending(false);
139
- }, [searchParams, t, createCloudAuthUser, navigate]);
140
- return { handleCallback, isCallbackPending: isPending };
141
- };
142
-
143
- // src/routes/login/login.tsx
144
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
145
- var LoginSchema = z.object({
146
- email: z.string().email(),
147
- password: z.string()
148
- });
149
- var Login = () => {
150
- const { t } = useTranslation2();
151
- const location = useLocation();
152
- const navigate = useNavigate2();
153
- const { getWidgets } = useExtension();
154
- const from = location.state?.from?.pathname || "/orders";
155
- const form = useForm({
156
- resolver: zodResolver(LoginSchema),
157
- defaultValues: {
158
- email: "",
159
- password: ""
160
- }
161
- });
162
- const { mutateAsync, isPending } = useSignInWithEmailPass();
163
- const handleSubmit = form.handleSubmit(async ({ email, password }) => {
164
- await mutateAsync(
165
- {
166
- email,
167
- password
168
- },
169
- {
170
- onError: (error) => {
171
- if (isFetchError(error)) {
172
- if (error.status === 401) {
173
- form.setError("email", {
174
- type: "manual",
175
- message: error.message
176
- });
177
- return;
178
- }
179
- }
180
- form.setError("root.serverError", {
181
- type: "manual",
182
- message: error.message
183
- });
184
- },
185
- onSuccess: () => {
186
- navigate(from, { replace: true });
187
- }
188
- }
189
- );
190
- });
191
- const serverError = form.formState.errors?.root?.serverError?.message;
192
- const validationError = form.formState.errors.email?.message || form.formState.errors.password?.message;
193
- return /* @__PURE__ */ jsx2("div", { className: "bg-ui-bg-subtle flex min-h-dvh w-dvw items-center justify-center", children: /* @__PURE__ */ jsxs2("div", { className: "m-4 flex w-full max-w-[280px] flex-col items-center", children: [
194
- /* @__PURE__ */ jsx2(AvatarBox, {}),
195
- /* @__PURE__ */ jsxs2("div", { className: "mb-4 flex flex-col items-center", children: [
196
- /* @__PURE__ */ jsx2(Heading, { children: t("login.title") }),
197
- /* @__PURE__ */ jsx2(Text, { size: "small", className: "text-ui-fg-subtle text-center", children: t("login.hint") })
198
- ] }),
199
- /* @__PURE__ */ jsxs2("div", { className: "flex w-full flex-col gap-y-3", children: [
200
- getWidgets("login.before").map((Component, i) => {
201
- return /* @__PURE__ */ jsx2(Component, {}, i);
202
- }),
203
- /* @__PURE__ */ jsx2(Form, { ...form, children: /* @__PURE__ */ jsxs2(
204
- "form",
205
- {
206
- onSubmit: handleSubmit,
207
- className: "flex w-full flex-col gap-y-6",
208
- children: [
209
- /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-y-1", children: [
210
- /* @__PURE__ */ jsx2(
211
- Form.Field,
212
- {
213
- control: form.control,
214
- name: "email",
215
- render: ({ field }) => {
216
- return /* @__PURE__ */ jsx2(Form.Item, { children: /* @__PURE__ */ jsx2(Form.Control, { children: /* @__PURE__ */ jsx2(
217
- Input,
218
- {
219
- autoComplete: "email",
220
- ...field,
221
- className: "bg-ui-bg-field-component",
222
- placeholder: t("fields.email")
223
- }
224
- ) }) });
225
- }
226
- }
227
- ),
228
- /* @__PURE__ */ jsx2(
229
- Form.Field,
230
- {
231
- control: form.control,
232
- name: "password",
233
- render: ({ field }) => {
234
- return /* @__PURE__ */ jsxs2(Form.Item, { children: [
235
- /* @__PURE__ */ jsx2(Form.Label, {}),
236
- /* @__PURE__ */ jsx2(Form.Control, { children: /* @__PURE__ */ jsx2(
237
- Input,
238
- {
239
- type: "password",
240
- autoComplete: "current-password",
241
- ...field,
242
- className: "bg-ui-bg-field-component",
243
- placeholder: t("fields.password")
244
- }
245
- ) })
246
- ] });
247
- }
248
- }
249
- )
250
- ] }),
251
- validationError && /* @__PURE__ */ jsx2("div", { className: "text-center", children: /* @__PURE__ */ jsx2(Hint, { className: "inline-flex", variant: "error", children: validationError }) }),
252
- serverError && /* @__PURE__ */ jsx2(
253
- Alert,
254
- {
255
- className: "bg-ui-bg-base items-center p-2",
256
- dismissible: true,
257
- variant: "error",
258
- children: serverError
259
- }
260
- ),
261
- /* @__PURE__ */ jsx2(Button2, { className: "w-full", type: "submit", isLoading: isPending, children: t("actions.continueWithEmail") })
262
- ]
263
- }
264
- ) }),
265
- [...getWidgets("login.after"), CloudAuthLogin].map(
266
- (Component, i) => {
267
- return /* @__PURE__ */ jsx2(Component, {}, i);
268
- }
269
- )
270
- ] }),
271
- /* @__PURE__ */ jsx2("span", { className: "text-ui-fg-muted txt-small my-6", children: /* @__PURE__ */ jsx2(
272
- Trans,
273
- {
274
- i18nKey: "login.forgotPassword",
275
- components: [
276
- /* @__PURE__ */ jsx2(
277
- Link,
278
- {
279
- to: "/reset-password",
280
- className: "text-ui-fg-interactive transition-fg hover:text-ui-fg-interactive-hover focus-visible:text-ui-fg-interactive-hover font-medium outline-none"
281
- },
282
- "reset-password-link"
283
- )
284
- ]
285
- }
286
- ) })
287
- ] }) });
288
- };
289
- export {
290
- Login as Component
291
- };