@abpjs/account 0.7.6
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/LICENSE +165 -0
- package/README.md +316 -0
- package/dist/components/LoginForm/LoginForm.d.ts +48 -0
- package/dist/components/LoginForm/image-placeholder.d.ts +1 -0
- package/dist/components/LoginForm/index.d.ts +2 -0
- package/dist/components/RegisterForm/RegisterForm.d.ts +50 -0
- package/dist/components/RegisterForm/index.d.ts +2 -0
- package/dist/components/TenantBox/TenantBox.d.ts +21 -0
- package/dist/components/TenantBox/index.d.ts +2 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/usePasswordFlow.d.ts +27 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +574 -0
- package/dist/index.mjs +552 -0
- package/dist/models/index.d.ts +42 -0
- package/dist/pages/LoginPage.d.ts +25 -0
- package/dist/pages/RegisterPage.d.ts +25 -0
- package/dist/pages/index.d.ts +2 -0
- package/dist/providers/AccountProvider.d.ts +40 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/routes/index.d.ts +24 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ACCOUNT_PATHS: () => ACCOUNT_PATHS,
|
|
24
|
+
ACCOUNT_ROUTES: () => ACCOUNT_ROUTES,
|
|
25
|
+
AccountProvider: () => AccountProvider,
|
|
26
|
+
DEFAULT_REDIRECT_URL: () => DEFAULT_REDIRECT_URL,
|
|
27
|
+
LoginForm: () => LoginForm,
|
|
28
|
+
LoginPage: () => LoginPage,
|
|
29
|
+
RegisterForm: () => RegisterForm,
|
|
30
|
+
RegisterPage: () => RegisterPage,
|
|
31
|
+
TenantBox: () => TenantBox,
|
|
32
|
+
useAccountContext: () => useAccountContext,
|
|
33
|
+
useAccountOptions: () => useAccountOptions,
|
|
34
|
+
usePasswordFlow: () => usePasswordFlow
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/providers/AccountProvider.tsx
|
|
39
|
+
var import_react = require("react");
|
|
40
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
|
+
var DEFAULT_OPTIONS = {
|
|
42
|
+
redirectUrl: "/"
|
|
43
|
+
};
|
|
44
|
+
var AccountContext = (0, import_react.createContext)(null);
|
|
45
|
+
function AccountProvider({ children, options }) {
|
|
46
|
+
const mergedOptions = (0, import_react.useMemo)(
|
|
47
|
+
() => ({
|
|
48
|
+
...DEFAULT_OPTIONS,
|
|
49
|
+
...options
|
|
50
|
+
}),
|
|
51
|
+
[options]
|
|
52
|
+
);
|
|
53
|
+
const value = (0, import_react.useMemo)(
|
|
54
|
+
() => ({
|
|
55
|
+
options: mergedOptions
|
|
56
|
+
}),
|
|
57
|
+
[mergedOptions]
|
|
58
|
+
);
|
|
59
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccountContext.Provider, { value, children });
|
|
60
|
+
}
|
|
61
|
+
function useAccountContext() {
|
|
62
|
+
const context = (0, import_react.useContext)(AccountContext);
|
|
63
|
+
if (!context) {
|
|
64
|
+
throw new Error("useAccountContext must be used within an AccountProvider");
|
|
65
|
+
}
|
|
66
|
+
return context;
|
|
67
|
+
}
|
|
68
|
+
function useAccountOptions() {
|
|
69
|
+
const context = (0, import_react.useContext)(AccountContext);
|
|
70
|
+
return context?.options ?? DEFAULT_OPTIONS;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/hooks/usePasswordFlow.ts
|
|
74
|
+
var import_react2 = require("react");
|
|
75
|
+
var import_core = require("@abpjs/core");
|
|
76
|
+
var import_react_router_dom = require("react-router-dom");
|
|
77
|
+
function usePasswordFlow() {
|
|
78
|
+
const { store, axiosInstance, applicationConfigurationService, userManager } = (0, import_core.useAbp)();
|
|
79
|
+
const config = (0, import_core.useConfig)();
|
|
80
|
+
const options = useAccountOptions();
|
|
81
|
+
const navigate = (0, import_react_router_dom.useNavigate)();
|
|
82
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
|
|
83
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
84
|
+
const getTokenEndpoint = (0, import_react2.useCallback)(() => {
|
|
85
|
+
const oAuthConfig = config.environment.oAuthConfig;
|
|
86
|
+
if (oAuthConfig?.authority) {
|
|
87
|
+
const authority = oAuthConfig.authority.replace(/\/+$/, "");
|
|
88
|
+
return `${authority}/connect/token`;
|
|
89
|
+
}
|
|
90
|
+
throw new Error("OAuth authority not configured");
|
|
91
|
+
}, [config.environment.oAuthConfig]);
|
|
92
|
+
const login = (0, import_react2.useCallback)(
|
|
93
|
+
async (username, password, flowOptions) => {
|
|
94
|
+
setIsLoading(true);
|
|
95
|
+
setError(null);
|
|
96
|
+
try {
|
|
97
|
+
const oAuthConfig = config.environment.oAuthConfig;
|
|
98
|
+
if (!oAuthConfig?.client_id) {
|
|
99
|
+
throw new Error("OAuth client_id not configured");
|
|
100
|
+
}
|
|
101
|
+
const tokenEndpoint = getTokenEndpoint();
|
|
102
|
+
const formData = new URLSearchParams();
|
|
103
|
+
formData.append("grant_type", "password");
|
|
104
|
+
formData.append("username", username);
|
|
105
|
+
formData.append("password", password);
|
|
106
|
+
formData.append("client_id", oAuthConfig.client_id);
|
|
107
|
+
if (oAuthConfig.scope) {
|
|
108
|
+
formData.append("scope", oAuthConfig.scope);
|
|
109
|
+
}
|
|
110
|
+
const response = await axiosInstance.post(
|
|
111
|
+
tokenEndpoint,
|
|
112
|
+
formData.toString(),
|
|
113
|
+
{
|
|
114
|
+
headers: {
|
|
115
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
const tokenData = response.data;
|
|
120
|
+
const storage = flowOptions?.remember ? localStorage : sessionStorage;
|
|
121
|
+
const storageKey = `oidc.user:${oAuthConfig.authority}:${oAuthConfig.client_id}`;
|
|
122
|
+
const userData = {
|
|
123
|
+
access_token: tokenData.access_token,
|
|
124
|
+
token_type: tokenData.token_type,
|
|
125
|
+
expires_at: Math.floor(Date.now() / 1e3) + tokenData.expires_in,
|
|
126
|
+
refresh_token: tokenData.refresh_token,
|
|
127
|
+
scope: tokenData.scope,
|
|
128
|
+
profile: {}
|
|
129
|
+
// Will be filled after config fetch
|
|
130
|
+
};
|
|
131
|
+
storage.setItem(storageKey, JSON.stringify(userData));
|
|
132
|
+
const oidcKey = `oidc.user:${oAuthConfig.authority}:${oAuthConfig.client_id}`;
|
|
133
|
+
storage.setItem(oidcKey, JSON.stringify(userData));
|
|
134
|
+
if (userManager) {
|
|
135
|
+
const loadedUser = await userManager.getUser();
|
|
136
|
+
if (loadedUser) {
|
|
137
|
+
userManager.events.load(loadedUser);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const appConfig = await applicationConfigurationService.getConfiguration();
|
|
141
|
+
store.dispatch(import_core.configActions.setApplicationConfiguration(appConfig));
|
|
142
|
+
const redirectUrl = window.history.state?.redirectUrl || options.redirectUrl;
|
|
143
|
+
navigate(redirectUrl);
|
|
144
|
+
setIsLoading(false);
|
|
145
|
+
return { success: true };
|
|
146
|
+
} catch (err) {
|
|
147
|
+
const errorMessage = err.response?.data?.error_description || err.response?.data?.error || err.message || "Login failed";
|
|
148
|
+
setError(errorMessage);
|
|
149
|
+
setIsLoading(false);
|
|
150
|
+
console.error("Password flow error:", errorMessage);
|
|
151
|
+
return { success: false, error: errorMessage };
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
[
|
|
155
|
+
config.environment.oAuthConfig,
|
|
156
|
+
getTokenEndpoint,
|
|
157
|
+
axiosInstance,
|
|
158
|
+
applicationConfigurationService,
|
|
159
|
+
store,
|
|
160
|
+
options.redirectUrl,
|
|
161
|
+
navigate,
|
|
162
|
+
userManager
|
|
163
|
+
]
|
|
164
|
+
);
|
|
165
|
+
const clearError = (0, import_react2.useCallback)(() => {
|
|
166
|
+
setError(null);
|
|
167
|
+
}, []);
|
|
168
|
+
return {
|
|
169
|
+
login,
|
|
170
|
+
isLoading,
|
|
171
|
+
error,
|
|
172
|
+
clearError
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/components/TenantBox/TenantBox.tsx
|
|
177
|
+
var import_react3 = require("react");
|
|
178
|
+
var import_react_hook_form = require("react-hook-form");
|
|
179
|
+
var import_core2 = require("@abpjs/core");
|
|
180
|
+
var import_theme_shared = require("@abpjs/theme-shared");
|
|
181
|
+
var import_react4 = require("@chakra-ui/react");
|
|
182
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
183
|
+
function TenantBox({ containerStyle }) {
|
|
184
|
+
const { t } = (0, import_core2.useLocalization)();
|
|
185
|
+
const [selected, setSelected] = (0, import_react3.useState)(null);
|
|
186
|
+
const [modalVisible, setModalVisible] = (0, import_react3.useState)(false);
|
|
187
|
+
const { register, handleSubmit, reset } = (0, import_react_hook_form.useForm)({
|
|
188
|
+
defaultValues: {
|
|
189
|
+
name: ""
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
const openModal = (0, import_react3.useCallback)(() => {
|
|
193
|
+
reset({ name: selected?.name || "" });
|
|
194
|
+
setModalVisible(true);
|
|
195
|
+
}, [selected, reset]);
|
|
196
|
+
const onSwitch = (0, import_react3.useCallback)(() => {
|
|
197
|
+
setSelected(null);
|
|
198
|
+
openModal();
|
|
199
|
+
}, [openModal]);
|
|
200
|
+
const onSave = (0, import_react3.useCallback)((data) => {
|
|
201
|
+
setSelected(data.name ? data : null);
|
|
202
|
+
setModalVisible(false);
|
|
203
|
+
}, []);
|
|
204
|
+
const onClose = (0, import_react3.useCallback)(() => {
|
|
205
|
+
setModalVisible(false);
|
|
206
|
+
}, []);
|
|
207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
208
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
209
|
+
import_react4.Box,
|
|
210
|
+
{
|
|
211
|
+
className: "tenant-switch-box",
|
|
212
|
+
bg: "gray.100",
|
|
213
|
+
mb: 5,
|
|
214
|
+
color: "black",
|
|
215
|
+
p: 2.5,
|
|
216
|
+
textAlign: "center",
|
|
217
|
+
borderRadius: "md",
|
|
218
|
+
style: containerStyle,
|
|
219
|
+
children: [
|
|
220
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react4.Text, { as: "span", color: "gray.600", children: [
|
|
221
|
+
t("AbpUiMultiTenancy::Tenant"),
|
|
222
|
+
":",
|
|
223
|
+
" "
|
|
224
|
+
] }),
|
|
225
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Text, { as: "strong", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Text, { as: "i", children: selected?.name || t("AbpUiMultiTenancy::NotSelected") }) }),
|
|
226
|
+
" (",
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
228
|
+
import_react4.Link,
|
|
229
|
+
{
|
|
230
|
+
id: "abp-tenant-switch-link",
|
|
231
|
+
color: "gray.700",
|
|
232
|
+
cursor: "pointer",
|
|
233
|
+
onClick: onSwitch,
|
|
234
|
+
_hover: { textDecoration: "underline" },
|
|
235
|
+
children: t("AbpUiMultiTenancy::Switch")
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
")"
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
),
|
|
242
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
243
|
+
import_theme_shared.Modal,
|
|
244
|
+
{
|
|
245
|
+
visible: modalVisible,
|
|
246
|
+
onVisibleChange: setModalVisible,
|
|
247
|
+
size: "md",
|
|
248
|
+
header: t("AbpUiMultiTenancy::SwitchTenant") || "Switch Tenant",
|
|
249
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
250
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_theme_shared.Button, { variant: "ghost", colorPalette: "gray", onClick: onClose, children: t("AbpTenantManagement::Cancel") }),
|
|
251
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_theme_shared.Button, { colorPalette: "blue", onClick: handleSubmit(onSave), children: [
|
|
252
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CheckIcon, {}),
|
|
253
|
+
t("AbpTenantManagement::Save")
|
|
254
|
+
] })
|
|
255
|
+
] }),
|
|
256
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleSubmit(onSave), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react4.VStack, { gap: 4, align: "stretch", children: [
|
|
257
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_theme_shared.FormField, { label: t("AbpUiMultiTenancy::Name"), htmlFor: "tenant-name", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Input, { id: "tenant-name", type: "text", ...register("name") }) }),
|
|
258
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Text, { fontSize: "sm", color: "gray.600", children: t("AbpUiMultiTenancy::SwitchTenantHint") })
|
|
259
|
+
] }) })
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
] });
|
|
263
|
+
}
|
|
264
|
+
function CheckIcon() {
|
|
265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
266
|
+
"svg",
|
|
267
|
+
{
|
|
268
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
269
|
+
width: "16",
|
|
270
|
+
height: "16",
|
|
271
|
+
viewBox: "0 0 24 24",
|
|
272
|
+
fill: "none",
|
|
273
|
+
stroke: "currentColor",
|
|
274
|
+
strokeWidth: "2",
|
|
275
|
+
strokeLinecap: "round",
|
|
276
|
+
strokeLinejoin: "round",
|
|
277
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "20 6 9 17 4 12" })
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/components/LoginForm/LoginForm.tsx
|
|
283
|
+
var import_react_hook_form2 = require("react-hook-form");
|
|
284
|
+
var import_zod = require("@hookform/resolvers/zod");
|
|
285
|
+
var import_zod2 = require("zod");
|
|
286
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
287
|
+
var import_core3 = require("@abpjs/core");
|
|
288
|
+
var import_theme_shared2 = require("@abpjs/theme-shared");
|
|
289
|
+
var import_react5 = require("@chakra-ui/react");
|
|
290
|
+
var import_react6 = require("@chakra-ui/react");
|
|
291
|
+
var import_lu = require("react-icons/lu");
|
|
292
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
293
|
+
var loginSchema = import_zod2.z.object({
|
|
294
|
+
username: import_zod2.z.string().min(1, "Username is required").max(255, "Username must be at most 255 characters"),
|
|
295
|
+
password: import_zod2.z.string().min(1, "Password is required").max(32, "Password must be at most 32 characters"),
|
|
296
|
+
remember: import_zod2.z.boolean().default(false)
|
|
297
|
+
});
|
|
298
|
+
function LoginForm({
|
|
299
|
+
showTenantBox = true,
|
|
300
|
+
showRegisterLink = true,
|
|
301
|
+
registerUrl = "/account/register",
|
|
302
|
+
onLoginSuccess,
|
|
303
|
+
onLoginError
|
|
304
|
+
}) {
|
|
305
|
+
const { t } = (0, import_core3.useLocalization)();
|
|
306
|
+
const { login, isLoading, error, clearError } = usePasswordFlow();
|
|
307
|
+
const {
|
|
308
|
+
register,
|
|
309
|
+
handleSubmit,
|
|
310
|
+
formState: { errors, isSubmitting }
|
|
311
|
+
} = (0, import_react_hook_form2.useForm)({
|
|
312
|
+
resolver: (0, import_zod.zodResolver)(loginSchema),
|
|
313
|
+
defaultValues: {
|
|
314
|
+
username: "",
|
|
315
|
+
password: "",
|
|
316
|
+
remember: false
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
const onSubmit = async (data) => {
|
|
320
|
+
clearError();
|
|
321
|
+
const result = await login(data.username, data.password, {
|
|
322
|
+
remember: data.remember
|
|
323
|
+
});
|
|
324
|
+
if (result.success) {
|
|
325
|
+
onLoginSuccess?.();
|
|
326
|
+
} else if (result.error) {
|
|
327
|
+
onLoginError?.(result.error);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
const isFormLoading = isLoading || isSubmitting;
|
|
331
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Flex, { height: "full", flex: "1", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Box, { flex: "1.5", py: { base: "24", md: "32" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Container, { maxW: "md", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react6.Stack, { gap: "8", children: [
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Show, { when: showTenantBox, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TenantBox, {}) }),
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Stack, { gap: { base: "2", md: "3" }, textAlign: "center", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Heading, { size: { base: "2xl", md: "3xl" }, children: t("AbpAccount::Login") }) }),
|
|
334
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_theme_shared2.Alert, { status: "error", children: error }),
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("form", { onSubmit: handleSubmit(onSubmit), noValidate: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react6.Stack, { gap: "6", children: [
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react6.Stack, { gap: "5", children: [
|
|
337
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react6.Field.Root, { invalid: !!errors.username, children: [
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Field.Label, { children: t("AbpAccount::UserNameOrEmailAddress") }),
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.InputGroup, { startElement: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lu.LuMail, {}), width: "full", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
340
|
+
import_react5.Input,
|
|
341
|
+
{
|
|
342
|
+
id: "login-input-user-name-or-email-address",
|
|
343
|
+
type: "text",
|
|
344
|
+
autoComplete: "username",
|
|
345
|
+
placeholder: "me@example.com",
|
|
346
|
+
...register("username")
|
|
347
|
+
}
|
|
348
|
+
) }),
|
|
349
|
+
errors.username && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Field.ErrorText, { children: errors.username.message })
|
|
350
|
+
] }),
|
|
351
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react6.Field.Root, { invalid: !!errors.password, children: [
|
|
352
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Field.Label, { children: t("AbpAccount::Password") }),
|
|
353
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.InputGroup, { startElement: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lu.LuLock, {}), width: "full", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
354
|
+
import_react5.Input,
|
|
355
|
+
{
|
|
356
|
+
id: "login-input-password",
|
|
357
|
+
type: "password",
|
|
358
|
+
autoComplete: "current-password",
|
|
359
|
+
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
360
|
+
...register("password")
|
|
361
|
+
}
|
|
362
|
+
) }),
|
|
363
|
+
errors.password && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Field.ErrorText, { children: errors.password.message })
|
|
364
|
+
] }),
|
|
365
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_theme_shared2.Checkbox, { id: "login-input-remember-me", ...register("remember"), children: t("AbpAccount::RememberMe") }),
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
367
|
+
import_theme_shared2.Button,
|
|
368
|
+
{
|
|
369
|
+
type: "submit",
|
|
370
|
+
colorPalette: "blue",
|
|
371
|
+
loading: isFormLoading,
|
|
372
|
+
loadingText: t("AbpAccount::Login"),
|
|
373
|
+
children: t("AbpAccount::Login")
|
|
374
|
+
}
|
|
375
|
+
),
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Link, { variant: "plain", children: t("AbpAccount::ForgotPassword") })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Show, { when: showRegisterLink, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Card.Root, { size: "sm", mt: "10", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Card.Body, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react5.HStack, { textStyle: "sm", children: [
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react6.Text, { children: t("AbpAccount::AreYouANewUser") }),
|
|
380
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react5.Link, { asChild: true, variant: "underline", fontWeight: "semibold", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_router_dom2.Link, { to: registerUrl, children: t("AbpAccount::Register") }) })
|
|
381
|
+
] }) }) }) })
|
|
382
|
+
] }) })
|
|
383
|
+
] }) }) }) });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/components/RegisterForm/RegisterForm.tsx
|
|
387
|
+
var import_react_hook_form3 = require("react-hook-form");
|
|
388
|
+
var import_zod3 = require("@hookform/resolvers/zod");
|
|
389
|
+
var import_zod4 = require("zod");
|
|
390
|
+
var import_react_router_dom3 = require("react-router-dom");
|
|
391
|
+
var import_core4 = require("@abpjs/core");
|
|
392
|
+
var import_theme_shared3 = require("@abpjs/theme-shared");
|
|
393
|
+
var import_react7 = require("@chakra-ui/react");
|
|
394
|
+
var import_react8 = require("@chakra-ui/react");
|
|
395
|
+
var import_lu2 = require("react-icons/lu");
|
|
396
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
397
|
+
var passwordValidation = {
|
|
398
|
+
hasLowercase: /[a-z]/,
|
|
399
|
+
hasUppercase: /[A-Z]/,
|
|
400
|
+
hasNumber: /[0-9]/,
|
|
401
|
+
hasSpecial: /[!@#$%^&*(),.?":{}|<>]/
|
|
402
|
+
};
|
|
403
|
+
var registerSchema = import_zod4.z.object({
|
|
404
|
+
username: import_zod4.z.string().min(1, "Username is required").max(255, "Username must be at most 255 characters"),
|
|
405
|
+
email: import_zod4.z.string().min(1, "Email is required").email("Please enter a valid email address"),
|
|
406
|
+
password: import_zod4.z.string().min(6, "Password must be at least 6 characters").max(32, "Password must be at most 32 characters").refine(
|
|
407
|
+
(val) => passwordValidation.hasLowercase.test(val),
|
|
408
|
+
"Password must contain at least one lowercase letter"
|
|
409
|
+
).refine(
|
|
410
|
+
(val) => passwordValidation.hasUppercase.test(val),
|
|
411
|
+
"Password must contain at least one uppercase letter"
|
|
412
|
+
).refine(
|
|
413
|
+
(val) => passwordValidation.hasNumber.test(val),
|
|
414
|
+
"Password must contain at least one number"
|
|
415
|
+
).refine(
|
|
416
|
+
(val) => passwordValidation.hasSpecial.test(val),
|
|
417
|
+
"Password must contain at least one special character"
|
|
418
|
+
)
|
|
419
|
+
});
|
|
420
|
+
function RegisterForm({
|
|
421
|
+
showTenantBox = true,
|
|
422
|
+
showLoginLink = true,
|
|
423
|
+
loginUrl = "/account/login",
|
|
424
|
+
onRegisterSuccess,
|
|
425
|
+
// Note: onRegisterError will be used when registration API is implemented
|
|
426
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
427
|
+
onRegisterError: _onRegisterError
|
|
428
|
+
}) {
|
|
429
|
+
const { t } = (0, import_core4.useLocalization)();
|
|
430
|
+
const {
|
|
431
|
+
register,
|
|
432
|
+
handleSubmit,
|
|
433
|
+
formState: { errors, isSubmitting }
|
|
434
|
+
} = (0, import_react_hook_form3.useForm)({
|
|
435
|
+
resolver: (0, import_zod3.zodResolver)(registerSchema),
|
|
436
|
+
defaultValues: {
|
|
437
|
+
username: "",
|
|
438
|
+
email: "",
|
|
439
|
+
password: ""
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
const onSubmit = async (data) => {
|
|
443
|
+
console.log("Register form submitted (no API call in v0.7.6):", data);
|
|
444
|
+
onRegisterSuccess?.();
|
|
445
|
+
};
|
|
446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Flex, { height: "full", flex: "1", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react7.Box, { flex: "1.5", py: { base: "24", md: "32" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Container, { maxW: "md", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Stack, { gap: "8", children: [
|
|
447
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react7.Show, { when: showTenantBox, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TenantBox, {}) }),
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Stack, { gap: { base: "2", md: "3" }, textAlign: "center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react7.Heading, { size: { base: "2xl", md: "3xl" }, children: t("AbpAccount::Register") }) }),
|
|
449
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("form", { onSubmit: handleSubmit(onSubmit), noValidate: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Stack, { gap: "6", children: [
|
|
450
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Stack, { gap: "5", children: [
|
|
451
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Field.Root, { invalid: !!errors.username, children: [
|
|
452
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.Label, { children: t("AbpAccount::UserName") }),
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.InputGroup, { startElement: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu2.LuUser, {}), width: "full", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
454
|
+
import_react7.Input,
|
|
455
|
+
{
|
|
456
|
+
id: "input-user-name",
|
|
457
|
+
type: "text",
|
|
458
|
+
autoFocus: true,
|
|
459
|
+
autoComplete: "username",
|
|
460
|
+
placeholder: "johndoe",
|
|
461
|
+
...register("username")
|
|
462
|
+
}
|
|
463
|
+
) }),
|
|
464
|
+
errors.username && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.ErrorText, { children: errors.username.message })
|
|
465
|
+
] }),
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Field.Root, { invalid: !!errors.email, children: [
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.Label, { children: t("AbpAccount::EmailAddress") }),
|
|
468
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.InputGroup, { startElement: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu2.LuMail, {}), width: "full", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
469
|
+
import_react7.Input,
|
|
470
|
+
{
|
|
471
|
+
id: "input-email-address",
|
|
472
|
+
type: "email",
|
|
473
|
+
autoComplete: "email",
|
|
474
|
+
placeholder: "me@example.com",
|
|
475
|
+
...register("email")
|
|
476
|
+
}
|
|
477
|
+
) }),
|
|
478
|
+
errors.email && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.ErrorText, { children: errors.email.message })
|
|
479
|
+
] }),
|
|
480
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react8.Field.Root, { invalid: !!errors.password, children: [
|
|
481
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.Label, { children: t("AbpAccount::Password") }),
|
|
482
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.InputGroup, { startElement: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu2.LuLock, {}), width: "full", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
483
|
+
import_react7.Input,
|
|
484
|
+
{
|
|
485
|
+
id: "input-password",
|
|
486
|
+
type: "password",
|
|
487
|
+
autoComplete: "new-password",
|
|
488
|
+
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
489
|
+
...register("password")
|
|
490
|
+
}
|
|
491
|
+
) }),
|
|
492
|
+
errors.password && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Field.ErrorText, { children: errors.password.message })
|
|
493
|
+
] }),
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
495
|
+
import_theme_shared3.Button,
|
|
496
|
+
{
|
|
497
|
+
type: "submit",
|
|
498
|
+
colorPalette: "blue",
|
|
499
|
+
loading: isSubmitting,
|
|
500
|
+
loadingText: t("AbpAccount::Register"),
|
|
501
|
+
children: t("AbpAccount::Register")
|
|
502
|
+
}
|
|
503
|
+
)
|
|
504
|
+
] }),
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react7.Show, { when: showLoginLink, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Card.Root, { size: "sm", mt: "10", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Card.Body, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react7.HStack, { textStyle: "sm", children: [
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react8.Text, { children: t("AbpAccount::AlreadyRegistered") }),
|
|
507
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react7.Link, { asChild: true, variant: "underline", fontWeight: "semibold", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_router_dom3.Link, { to: loginUrl, children: t("AbpAccount::Login") }) })
|
|
508
|
+
] }) }) }) })
|
|
509
|
+
] }) })
|
|
510
|
+
] }) }) }) });
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/pages/LoginPage.tsx
|
|
514
|
+
var import_react9 = require("@chakra-ui/react");
|
|
515
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
516
|
+
function LoginPage({
|
|
517
|
+
maxWidth = "container.sm",
|
|
518
|
+
...loginFormProps
|
|
519
|
+
}) {
|
|
520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react9.Container, { maxW: maxWidth, py: 10, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react9.Center, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LoginForm, { ...loginFormProps }) }) });
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/pages/RegisterPage.tsx
|
|
524
|
+
var import_react10 = require("@chakra-ui/react");
|
|
525
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
526
|
+
function RegisterPage({
|
|
527
|
+
maxWidth = "container.sm",
|
|
528
|
+
...registerFormProps
|
|
529
|
+
}) {
|
|
530
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react10.Container, { maxW: maxWidth, py: 10, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react10.Center, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RegisterForm, { ...registerFormProps }) }) });
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/routes/index.ts
|
|
534
|
+
var import_core5 = require("@abpjs/core");
|
|
535
|
+
var ACCOUNT_ROUTES = [
|
|
536
|
+
{
|
|
537
|
+
name: "Account",
|
|
538
|
+
path: "account",
|
|
539
|
+
invisible: true,
|
|
540
|
+
layout: import_core5.eLayoutType.application,
|
|
541
|
+
children: [
|
|
542
|
+
{
|
|
543
|
+
path: "login",
|
|
544
|
+
name: "Login",
|
|
545
|
+
order: 1
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
path: "register",
|
|
549
|
+
name: "Register",
|
|
550
|
+
order: 2
|
|
551
|
+
}
|
|
552
|
+
]
|
|
553
|
+
}
|
|
554
|
+
];
|
|
555
|
+
var DEFAULT_REDIRECT_URL = "/";
|
|
556
|
+
var ACCOUNT_PATHS = {
|
|
557
|
+
login: "/account/login",
|
|
558
|
+
register: "/account/register"
|
|
559
|
+
};
|
|
560
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
561
|
+
0 && (module.exports = {
|
|
562
|
+
ACCOUNT_PATHS,
|
|
563
|
+
ACCOUNT_ROUTES,
|
|
564
|
+
AccountProvider,
|
|
565
|
+
DEFAULT_REDIRECT_URL,
|
|
566
|
+
LoginForm,
|
|
567
|
+
LoginPage,
|
|
568
|
+
RegisterForm,
|
|
569
|
+
RegisterPage,
|
|
570
|
+
TenantBox,
|
|
571
|
+
useAccountContext,
|
|
572
|
+
useAccountOptions,
|
|
573
|
+
usePasswordFlow
|
|
574
|
+
});
|