@arch-cadre/auth 0.0.1
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/dist/actions/basic.cjs +46 -0
- package/dist/actions/basic.d.ts +14 -0
- package/dist/actions/basic.mjs +32 -0
- package/dist/actions/email.cjs +209 -0
- package/dist/actions/email.d.ts +7 -0
- package/dist/actions/email.mjs +186 -0
- package/dist/actions/index.cjs +27 -0
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.mjs +2 -0
- package/dist/index.cjs +16 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +9 -0
- package/dist/intl.d.ts +13 -0
- package/dist/routes.cjs +46 -0
- package/dist/routes.d.ts +2 -0
- package/dist/routes.mjs +48 -0
- package/dist/types.cjs +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.mjs +0 -0
- package/dist/ui/forgot-password/components.cjs +91 -0
- package/dist/ui/forgot-password/components.d.ts +2 -0
- package/dist/ui/forgot-password/components.mjs +63 -0
- package/dist/ui/forgot-password/page.cjs +13 -0
- package/dist/ui/forgot-password/page.d.ts +2 -0
- package/dist/ui/forgot-password/page.mjs +5 -0
- package/dist/ui/layout.cjs +39 -0
- package/dist/ui/layout.d.ts +4 -0
- package/dist/ui/layout.mjs +18 -0
- package/dist/ui/reset-password/components.cjs +109 -0
- package/dist/ui/reset-password/components.d.ts +2 -0
- package/dist/ui/reset-password/components.mjs +84 -0
- package/dist/ui/reset-password/page.cjs +29 -0
- package/dist/ui/reset-password/page.d.ts +2 -0
- package/dist/ui/reset-password/page.mjs +21 -0
- package/dist/ui/reset-password/verify-email/components.cjs +106 -0
- package/dist/ui/reset-password/verify-email/components.d.ts +4 -0
- package/dist/ui/reset-password/verify-email/components.mjs +62 -0
- package/dist/ui/reset-password/verify-email/page.cjs +31 -0
- package/dist/ui/reset-password/verify-email/page.d.ts +2 -0
- package/dist/ui/reset-password/verify-email/page.mjs +21 -0
- package/dist/ui/signin/components.cjs +172 -0
- package/dist/ui/signin/components.d.ts +11 -0
- package/dist/ui/signin/components.mjs +134 -0
- package/dist/ui/signin/page.cjs +41 -0
- package/dist/ui/signin/page.d.ts +2 -0
- package/dist/ui/signin/page.mjs +39 -0
- package/dist/ui/signup/components.cjs +193 -0
- package/dist/ui/signup/components.d.ts +11 -0
- package/dist/ui/signup/components.mjs +150 -0
- package/dist/ui/signup/page.cjs +36 -0
- package/dist/ui/signup/page.d.ts +2 -0
- package/dist/ui/signup/page.mjs +34 -0
- package/dist/ui/verify-email/components.cjs +129 -0
- package/dist/ui/verify-email/components.d.ts +4 -0
- package/dist/ui/verify-email/components.mjs +76 -0
- package/dist/ui/verify-email/page.cjs +29 -0
- package/dist/ui/verify-email/page.d.ts +2 -0
- package/dist/ui/verify-email/page.mjs +21 -0
- package/dist/validation.cjs +43 -0
- package/dist/validation.d.ts +97 -0
- package/dist/validation.mjs +37 -0
- package/locales/en/global.json +35 -0
- package/manifest.json +11 -0
- package/package.json +57 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
3
|
+
import { Button } from "@arch-cadre/ui/components/button";
|
|
4
|
+
import {
|
|
5
|
+
Field,
|
|
6
|
+
FieldError,
|
|
7
|
+
FieldGroup
|
|
8
|
+
} from "@arch-cadre/ui/components/field";
|
|
9
|
+
import {
|
|
10
|
+
InputOTP,
|
|
11
|
+
InputOTPGroup,
|
|
12
|
+
InputOTPSlot
|
|
13
|
+
} from "@arch-cadre/ui/components/input-otp";
|
|
14
|
+
import { cn } from "@arch-cadre/ui/lib/utils";
|
|
15
|
+
import { Loader } from "@arch-cadre/ui/shared/loader";
|
|
16
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
17
|
+
import { AlertCircle } from "lucide-react";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { useState } from "react";
|
|
20
|
+
import { Controller, useForm } from "react-hook-form";
|
|
21
|
+
import { toast } from "sonner";
|
|
22
|
+
import { verifyPasswordResetEmailAction } from "../../../actions/index.mjs";
|
|
23
|
+
import { verifyEmailSchema } from "../../../validation.mjs";
|
|
24
|
+
export function PasswordResetEmailVerificationForm({ email = "" }) {
|
|
25
|
+
const [generalError, setGeneralError] = useState("");
|
|
26
|
+
const { t } = useTranslation();
|
|
27
|
+
const form = useForm({
|
|
28
|
+
resolver: zodResolver(verifyEmailSchema)
|
|
29
|
+
});
|
|
30
|
+
async function onSubmit(data) {
|
|
31
|
+
setGeneralError("");
|
|
32
|
+
try {
|
|
33
|
+
const response = await verifyPasswordResetEmailAction(data);
|
|
34
|
+
if (response.error) {
|
|
35
|
+
setGeneralError(
|
|
36
|
+
response.message || t("Verification failed. Please try again.")
|
|
37
|
+
);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
toast(response.message);
|
|
41
|
+
} catch (_error) {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ React.createElement("div", { className: cn("flex flex-col space-y-3") }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2 text-center" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-semibold" }, t("Verify your email address")), /* @__PURE__ */ React.createElement("p", { className: "text-muted-foreground" }, t("We sent an 6-digit code to {email}.", { email }))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-5" }, generalError && /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 p-3 bg-red-50 border border-red-200 rounded-lg" }, /* @__PURE__ */ React.createElement(AlertCircle, { className: "w-4 h-4 text-red-600 flex-shrink-0 mt-0.5" }), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-red-600" }, generalError)), /* @__PURE__ */ React.createElement("form", { onSubmit: form.handleSubmit(onSubmit), className: "grid gap-6" }, /* @__PURE__ */ React.createElement(FieldGroup, { className: "w-full mx-auto" }, /* @__PURE__ */ React.createElement(
|
|
45
|
+
Controller,
|
|
46
|
+
{
|
|
47
|
+
name: "code",
|
|
48
|
+
control: form.control,
|
|
49
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ React.createElement(Field, { className: "w-full", "data-invalid": fieldState.invalid }, /* @__PURE__ */ React.createElement(
|
|
50
|
+
InputOTP,
|
|
51
|
+
{
|
|
52
|
+
...field,
|
|
53
|
+
className: "mx-auto w-full",
|
|
54
|
+
maxLength: 6,
|
|
55
|
+
autoFocus: true,
|
|
56
|
+
inputMode: "text"
|
|
57
|
+
},
|
|
58
|
+
/* @__PURE__ */ React.createElement(InputOTPGroup, { className: "mx-auto" }, /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 0 }), /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 1 }), /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 2 }), /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 3 }), /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 4 }), /* @__PURE__ */ React.createElement(InputOTPSlot, { index: 5 }))
|
|
59
|
+
), fieldState.invalid && /* @__PURE__ */ React.createElement(FieldError, { errors: [fieldState.error] }))
|
|
60
|
+
}
|
|
61
|
+
)), /* @__PURE__ */ React.createElement(Button, { disabled: form.formState.isSubmitting, className: "w-full" }, form.formState.isSubmitting ? t("Please wait...") : t("Verify"), form.formState.isSubmitting && /* @__PURE__ */ React.createElement(Loader, { variant: "dark" })))));
|
|
62
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
module.exports = Page;
|
|
7
|
+
var _server = require("@arch-cadre/core/server");
|
|
8
|
+
var _navigation = require("next/navigation");
|
|
9
|
+
var React = _interopRequireWildcard(require("react"));
|
|
10
|
+
var _components = require("./components.cjs");
|
|
11
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
12
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
|
+
async function Page() {
|
|
14
|
+
const {
|
|
15
|
+
session,
|
|
16
|
+
user
|
|
17
|
+
} = await (0, _server.getCurrentPasswordResetSession)();
|
|
18
|
+
if (session === null || user === null) {
|
|
19
|
+
return (0, _navigation.redirect)("/forgot-password");
|
|
20
|
+
}
|
|
21
|
+
if (session.emailVerified) {
|
|
22
|
+
const security = await (0, _server.checkSecurity)(session, user);
|
|
23
|
+
if (!security.satisfied && security.redirect) {
|
|
24
|
+
return (0, _navigation.redirect)(security.redirect);
|
|
25
|
+
}
|
|
26
|
+
return (0, _navigation.redirect)("/reset-password");
|
|
27
|
+
}
|
|
28
|
+
return /* @__PURE__ */React.createElement(_components.PasswordResetEmailVerificationForm, {
|
|
29
|
+
email: session.email
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkSecurity,
|
|
3
|
+
getCurrentPasswordResetSession
|
|
4
|
+
} from "@arch-cadre/core/server";
|
|
5
|
+
import { redirect } from "next/navigation";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { PasswordResetEmailVerificationForm } from "./components.mjs";
|
|
8
|
+
export default async function Page() {
|
|
9
|
+
const { session, user } = await getCurrentPasswordResetSession();
|
|
10
|
+
if (session === null || user === null) {
|
|
11
|
+
return redirect("/forgot-password");
|
|
12
|
+
}
|
|
13
|
+
if (session.emailVerified) {
|
|
14
|
+
const security = await checkSecurity(session, user);
|
|
15
|
+
if (!security.satisfied && security.redirect) {
|
|
16
|
+
return redirect(security.redirect);
|
|
17
|
+
}
|
|
18
|
+
return redirect("/reset-password");
|
|
19
|
+
}
|
|
20
|
+
return /* @__PURE__ */ React.createElement(PasswordResetEmailVerificationForm, { email: session.email });
|
|
21
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.LoginForm = LoginForm;
|
|
8
|
+
exports.useLoginForm = useLoginForm;
|
|
9
|
+
var _intl = require("@arch-cadre/intl");
|
|
10
|
+
var _button = require("@arch-cadre/ui/components/button");
|
|
11
|
+
var _checkbox = require("@arch-cadre/ui/components/checkbox");
|
|
12
|
+
var _field = require("@arch-cadre/ui/components/field");
|
|
13
|
+
var _input = require("@arch-cadre/ui/components/input");
|
|
14
|
+
var _separator = require("@arch-cadre/ui/components/separator");
|
|
15
|
+
var _utils = require("@arch-cadre/ui/lib/utils");
|
|
16
|
+
var _loader = require("@arch-cadre/ui/shared/loader");
|
|
17
|
+
var _zod = require("@hookform/resolvers/zod");
|
|
18
|
+
var _lucideReact = require("lucide-react");
|
|
19
|
+
var _link = _interopRequireDefault(require("next/link"));
|
|
20
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
21
|
+
var React = _react;
|
|
22
|
+
var _reactHookForm = require("react-hook-form");
|
|
23
|
+
var _sonner = require("sonner");
|
|
24
|
+
var _index = require("../../actions/index.cjs");
|
|
25
|
+
var _validation = require("../../validation.cjs");
|
|
26
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
27
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
28
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
29
|
+
const LoginFormContext = (0, _react.createContext)(null);
|
|
30
|
+
function useLoginForm() {
|
|
31
|
+
const context = (0, _react.useContext)(LoginFormContext);
|
|
32
|
+
if (!context) {
|
|
33
|
+
throw new Error("useLoginForm must be used within a LoginForm");
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
|
37
|
+
function LoginForm({
|
|
38
|
+
extraButtons,
|
|
39
|
+
extraFields,
|
|
40
|
+
hasAllowedExtensions
|
|
41
|
+
}) {
|
|
42
|
+
const [generalError, setGeneralError] = (0, _react.useState)("");
|
|
43
|
+
const {
|
|
44
|
+
t
|
|
45
|
+
} = (0, _intl.useTranslation)();
|
|
46
|
+
const form = (0, _reactHookForm.useForm)({
|
|
47
|
+
resolver: (0, _zod.zodResolver)(_validation.loginSchema)
|
|
48
|
+
});
|
|
49
|
+
async function onSubmit(data) {
|
|
50
|
+
setGeneralError("");
|
|
51
|
+
try {
|
|
52
|
+
const response = await (0, _index.loginAction)(data);
|
|
53
|
+
if (response.error) {
|
|
54
|
+
setGeneralError(response.message || t("error_occurred"));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
(0, _sonner.toast)(response.message);
|
|
58
|
+
} catch (_error) {}
|
|
59
|
+
}
|
|
60
|
+
return /* @__PURE__ */React.createElement(LoginFormContext.Provider, {
|
|
61
|
+
value: {
|
|
62
|
+
form
|
|
63
|
+
}
|
|
64
|
+
}, /* @__PURE__ */React.createElement("div", {
|
|
65
|
+
className: (0, _utils.cn)("flex flex-col space-y-6")
|
|
66
|
+
}, /* @__PURE__ */React.createElement("div", {
|
|
67
|
+
className: "space-y-2 text-center"
|
|
68
|
+
}, /* @__PURE__ */React.createElement("h1", {
|
|
69
|
+
className: "text-3xl font-semibold"
|
|
70
|
+
}, t("Sign In")), /* @__PURE__ */React.createElement("p", {
|
|
71
|
+
className: "text-muted-foreground"
|
|
72
|
+
}, t("Sign in to access your dashboard, settings and projects."))), /* @__PURE__ */React.createElement("div", {
|
|
73
|
+
className: "grid gap-5"
|
|
74
|
+
}, hasAllowedExtensions && /* @__PURE__ */React.createElement(React.Fragment, null, /* @__PURE__ */React.createElement("div", {
|
|
75
|
+
className: "flex flex-col gap-2"
|
|
76
|
+
}, extraButtons), /* @__PURE__ */React.createElement("div", {
|
|
77
|
+
className: "flex items-center gap-2"
|
|
78
|
+
}, /* @__PURE__ */React.createElement(_separator.Separator, {
|
|
79
|
+
className: "flex-1"
|
|
80
|
+
}), /* @__PURE__ */React.createElement("span", {
|
|
81
|
+
className: "text-sm text-muted-foreground"
|
|
82
|
+
}, t("or sign in with email")), /* @__PURE__ */React.createElement(_separator.Separator, {
|
|
83
|
+
className: "flex-1"
|
|
84
|
+
}))), generalError && /* @__PURE__ */React.createElement("div", {
|
|
85
|
+
className: "flex gap-2 p-3 bg-red-50 border border-red-200 rounded-lg"
|
|
86
|
+
}, /* @__PURE__ */React.createElement(_lucideReact.AlertCircle, {
|
|
87
|
+
className: "w-4 h-4 text-red-600 flex-shrink-0 mt-0.5"
|
|
88
|
+
}), /* @__PURE__ */React.createElement("p", {
|
|
89
|
+
className: "text-sm text-red-600"
|
|
90
|
+
}, generalError)), /* @__PURE__ */React.createElement("form", {
|
|
91
|
+
onSubmit: form.handleSubmit(onSubmit),
|
|
92
|
+
className: "grid gap-6"
|
|
93
|
+
}, /* @__PURE__ */React.createElement(_field.FieldGroup, null, /* @__PURE__ */React.createElement(_reactHookForm.Controller, {
|
|
94
|
+
name: "email",
|
|
95
|
+
control: form.control,
|
|
96
|
+
render: ({
|
|
97
|
+
field,
|
|
98
|
+
fieldState
|
|
99
|
+
}) => /* @__PURE__ */React.createElement(_field.Field, {
|
|
100
|
+
"data-invalid": fieldState.invalid
|
|
101
|
+
}, /* @__PURE__ */React.createElement(_field.FieldLabel, {
|
|
102
|
+
htmlFor: "email"
|
|
103
|
+
}, t("Email address")), /* @__PURE__ */React.createElement(_input.Input, {
|
|
104
|
+
...field,
|
|
105
|
+
id: "email",
|
|
106
|
+
type: "email",
|
|
107
|
+
"aria-invalid": fieldState.invalid,
|
|
108
|
+
placeholder: t("Email address"),
|
|
109
|
+
autoComplete: "off"
|
|
110
|
+
}), fieldState.invalid && /* @__PURE__ */React.createElement(_field.FieldError, {
|
|
111
|
+
errors: [fieldState.error]
|
|
112
|
+
}))
|
|
113
|
+
}), /* @__PURE__ */React.createElement(_reactHookForm.Controller, {
|
|
114
|
+
name: "password",
|
|
115
|
+
control: form.control,
|
|
116
|
+
render: ({
|
|
117
|
+
field,
|
|
118
|
+
fieldState
|
|
119
|
+
}) => /* @__PURE__ */React.createElement(_field.Field, {
|
|
120
|
+
"data-invalid": fieldState.invalid
|
|
121
|
+
}, /* @__PURE__ */React.createElement("div", {
|
|
122
|
+
className: "flex items-center"
|
|
123
|
+
}, /* @__PURE__ */React.createElement(_field.FieldLabel, {
|
|
124
|
+
htmlFor: "password"
|
|
125
|
+
}, t("Password")), /* @__PURE__ */React.createElement(_link.default, {
|
|
126
|
+
href: "/forgot-password",
|
|
127
|
+
className: "ml-auto text-sm text-primary! underline-offset-4 hover:underline"
|
|
128
|
+
}, t("Forgot your password?"))), /* @__PURE__ */React.createElement(_input.Input, {
|
|
129
|
+
...field,
|
|
130
|
+
id: "password",
|
|
131
|
+
type: "password",
|
|
132
|
+
"aria-invalid": fieldState.invalid,
|
|
133
|
+
placeholder: "********",
|
|
134
|
+
autoComplete: "off"
|
|
135
|
+
}), fieldState.invalid && /* @__PURE__ */React.createElement(_field.FieldError, {
|
|
136
|
+
errors: [fieldState.error]
|
|
137
|
+
}))
|
|
138
|
+
}), extraFields, /* @__PURE__ */React.createElement(_reactHookForm.Controller, {
|
|
139
|
+
name: "remember",
|
|
140
|
+
control: form.control,
|
|
141
|
+
render: ({
|
|
142
|
+
field,
|
|
143
|
+
fieldState
|
|
144
|
+
}) => /* @__PURE__ */React.createElement(_field.Field, {
|
|
145
|
+
"data-invalid": fieldState.invalid,
|
|
146
|
+
className: "flex items-center space-x-2"
|
|
147
|
+
}, /* @__PURE__ */React.createElement("div", {
|
|
148
|
+
className: "flex items-center space-x-2"
|
|
149
|
+
}, /* @__PURE__ */React.createElement(_checkbox.Checkbox, {
|
|
150
|
+
id: "remember-me",
|
|
151
|
+
"aria-invalid": fieldState.invalid,
|
|
152
|
+
checked: field.value,
|
|
153
|
+
onCheckedChange: checked => field.onChange(checked)
|
|
154
|
+
}), /* @__PURE__ */React.createElement(_field.FieldLabel, {
|
|
155
|
+
htmlFor: "remember-me",
|
|
156
|
+
className: "text-sm text-muted-foreground"
|
|
157
|
+
}, t("Remember me"))), fieldState.invalid && /* @__PURE__ */React.createElement(_field.FieldError, {
|
|
158
|
+
errors: [fieldState.error]
|
|
159
|
+
}))
|
|
160
|
+
})), /* @__PURE__ */React.createElement(_button.Button, {
|
|
161
|
+
disabled: form.formState.isSubmitting,
|
|
162
|
+
className: "w-full"
|
|
163
|
+
}, form.formState.isSubmitting ? t("Please wait...") : t("Sign In"), form.formState.isSubmitting && /* @__PURE__ */React.createElement(_loader.Loader, {
|
|
164
|
+
variant: "dark"
|
|
165
|
+
}))), /* @__PURE__ */React.createElement("div", {
|
|
166
|
+
className: "text-center text-sm"
|
|
167
|
+
}, t("No account?"), " ", /* @__PURE__ */React.createElement(_link.default, {
|
|
168
|
+
key: "signup",
|
|
169
|
+
href: "/signup",
|
|
170
|
+
className: "underline underline-offset-4"
|
|
171
|
+
}, t("Sign Up"))))));
|
|
172
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { UseFormReturn } from "react-hook-form";
|
|
3
|
+
import { type LoginInput } from "../../validation";
|
|
4
|
+
export declare function useLoginForm(): {
|
|
5
|
+
form: UseFormReturn<LoginInput>;
|
|
6
|
+
};
|
|
7
|
+
export declare function LoginForm({ extraButtons, extraFields, hasAllowedExtensions, }: {
|
|
8
|
+
hasAllowedExtensions?: boolean;
|
|
9
|
+
extraButtons?: React.ReactNode;
|
|
10
|
+
extraFields?: React.ReactNode;
|
|
11
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
3
|
+
import { Button } from "@arch-cadre/ui/components/button";
|
|
4
|
+
import { Checkbox } from "@arch-cadre/ui/components/checkbox";
|
|
5
|
+
import {
|
|
6
|
+
Field,
|
|
7
|
+
FieldError,
|
|
8
|
+
FieldGroup,
|
|
9
|
+
FieldLabel
|
|
10
|
+
} from "@arch-cadre/ui/components/field";
|
|
11
|
+
import { Input } from "@arch-cadre/ui/components/input";
|
|
12
|
+
import { Separator } from "@arch-cadre/ui/components/separator";
|
|
13
|
+
import { cn } from "@arch-cadre/ui/lib/utils";
|
|
14
|
+
import { Loader } from "@arch-cadre/ui/shared/loader";
|
|
15
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
16
|
+
import { AlertCircle } from "lucide-react";
|
|
17
|
+
import Link from "next/link";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { createContext, useContext, useState } from "react";
|
|
20
|
+
import { Controller, useForm } from "react-hook-form";
|
|
21
|
+
import { toast } from "sonner";
|
|
22
|
+
import { loginAction } from "../../actions/index.mjs";
|
|
23
|
+
import { loginSchema } from "../../validation.mjs";
|
|
24
|
+
const LoginFormContext = createContext(null);
|
|
25
|
+
export function useLoginForm() {
|
|
26
|
+
const context = useContext(LoginFormContext);
|
|
27
|
+
if (!context) {
|
|
28
|
+
throw new Error("useLoginForm must be used within a LoginForm");
|
|
29
|
+
}
|
|
30
|
+
return context;
|
|
31
|
+
}
|
|
32
|
+
export function LoginForm({
|
|
33
|
+
extraButtons,
|
|
34
|
+
extraFields,
|
|
35
|
+
hasAllowedExtensions
|
|
36
|
+
}) {
|
|
37
|
+
const [generalError, setGeneralError] = useState("");
|
|
38
|
+
const { t } = useTranslation();
|
|
39
|
+
const form = useForm({
|
|
40
|
+
resolver: zodResolver(loginSchema)
|
|
41
|
+
});
|
|
42
|
+
async function onSubmit(data) {
|
|
43
|
+
setGeneralError("");
|
|
44
|
+
try {
|
|
45
|
+
const response = await loginAction(data);
|
|
46
|
+
if (response.error) {
|
|
47
|
+
setGeneralError(response.message || t("error_occurred"));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
toast(response.message);
|
|
51
|
+
} catch (_error) {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return /* @__PURE__ */ React.createElement(LoginFormContext.Provider, { value: { form } }, /* @__PURE__ */ React.createElement("div", { className: cn("flex flex-col space-y-6") }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2 text-center" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-semibold" }, t("Sign In")), /* @__PURE__ */ React.createElement("p", { className: "text-muted-foreground" }, t("Sign in to access your dashboard, settings and projects."))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-5" }, hasAllowedExtensions && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-2" }, extraButtons), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(Separator, { className: "flex-1" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm text-muted-foreground" }, t("or sign in with email")), /* @__PURE__ */ React.createElement(Separator, { className: "flex-1" }))), generalError && /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 p-3 bg-red-50 border border-red-200 rounded-lg" }, /* @__PURE__ */ React.createElement(AlertCircle, { className: "w-4 h-4 text-red-600 flex-shrink-0 mt-0.5" }), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-red-600" }, generalError)), /* @__PURE__ */ React.createElement("form", { onSubmit: form.handleSubmit(onSubmit), className: "grid gap-6" }, /* @__PURE__ */ React.createElement(FieldGroup, null, /* @__PURE__ */ React.createElement(
|
|
55
|
+
Controller,
|
|
56
|
+
{
|
|
57
|
+
name: "email",
|
|
58
|
+
control: form.control,
|
|
59
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ React.createElement(Field, { "data-invalid": fieldState.invalid }, /* @__PURE__ */ React.createElement(FieldLabel, { htmlFor: "email" }, t("Email address")), /* @__PURE__ */ React.createElement(
|
|
60
|
+
Input,
|
|
61
|
+
{
|
|
62
|
+
...field,
|
|
63
|
+
id: "email",
|
|
64
|
+
type: "email",
|
|
65
|
+
"aria-invalid": fieldState.invalid,
|
|
66
|
+
placeholder: t("Email address"),
|
|
67
|
+
autoComplete: "off"
|
|
68
|
+
}
|
|
69
|
+
), fieldState.invalid && /* @__PURE__ */ React.createElement(FieldError, { errors: [fieldState.error] }))
|
|
70
|
+
}
|
|
71
|
+
), /* @__PURE__ */ React.createElement(
|
|
72
|
+
Controller,
|
|
73
|
+
{
|
|
74
|
+
name: "password",
|
|
75
|
+
control: form.control,
|
|
76
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ React.createElement(Field, { "data-invalid": fieldState.invalid }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement(FieldLabel, { htmlFor: "password" }, t("Password")), /* @__PURE__ */ React.createElement(
|
|
77
|
+
Link,
|
|
78
|
+
{
|
|
79
|
+
href: "/forgot-password",
|
|
80
|
+
className: "ml-auto text-sm text-primary! underline-offset-4 hover:underline"
|
|
81
|
+
},
|
|
82
|
+
t("Forgot your password?")
|
|
83
|
+
)), /* @__PURE__ */ React.createElement(
|
|
84
|
+
Input,
|
|
85
|
+
{
|
|
86
|
+
...field,
|
|
87
|
+
id: "password",
|
|
88
|
+
type: "password",
|
|
89
|
+
"aria-invalid": fieldState.invalid,
|
|
90
|
+
placeholder: "********",
|
|
91
|
+
autoComplete: "off"
|
|
92
|
+
}
|
|
93
|
+
), fieldState.invalid && /* @__PURE__ */ React.createElement(FieldError, { errors: [fieldState.error] }))
|
|
94
|
+
}
|
|
95
|
+
), extraFields, /* @__PURE__ */ React.createElement(
|
|
96
|
+
Controller,
|
|
97
|
+
{
|
|
98
|
+
name: "remember",
|
|
99
|
+
control: form.control,
|
|
100
|
+
render: ({ field, fieldState }) => /* @__PURE__ */ React.createElement(
|
|
101
|
+
Field,
|
|
102
|
+
{
|
|
103
|
+
"data-invalid": fieldState.invalid,
|
|
104
|
+
className: "flex items-center space-x-2"
|
|
105
|
+
},
|
|
106
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center space-x-2" }, /* @__PURE__ */ React.createElement(
|
|
107
|
+
Checkbox,
|
|
108
|
+
{
|
|
109
|
+
id: "remember-me",
|
|
110
|
+
"aria-invalid": fieldState.invalid,
|
|
111
|
+
checked: field.value,
|
|
112
|
+
onCheckedChange: (checked) => field.onChange(checked)
|
|
113
|
+
}
|
|
114
|
+
), /* @__PURE__ */ React.createElement(
|
|
115
|
+
FieldLabel,
|
|
116
|
+
{
|
|
117
|
+
htmlFor: "remember-me",
|
|
118
|
+
className: "text-sm text-muted-foreground"
|
|
119
|
+
},
|
|
120
|
+
t("Remember me")
|
|
121
|
+
)),
|
|
122
|
+
fieldState.invalid && /* @__PURE__ */ React.createElement(FieldError, { errors: [fieldState.error] })
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
)), /* @__PURE__ */ React.createElement(Button, { disabled: form.formState.isSubmitting, className: "w-full" }, form.formState.isSubmitting ? t("Please wait...") : t("Sign In"), form.formState.isSubmitting && /* @__PURE__ */ React.createElement(Loader, { variant: "dark" }))), /* @__PURE__ */ React.createElement("div", { className: "text-center text-sm" }, t("No account?"), " ", /* @__PURE__ */ React.createElement(
|
|
126
|
+
Link,
|
|
127
|
+
{
|
|
128
|
+
key: "signup",
|
|
129
|
+
href: "/signup",
|
|
130
|
+
className: "underline underline-offset-4"
|
|
131
|
+
},
|
|
132
|
+
t("Sign Up")
|
|
133
|
+
)))));
|
|
134
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
module.exports = Page;
|
|
7
|
+
var _server = require("@arch-cadre/core/server");
|
|
8
|
+
var _modules = require("@arch-cadre/modules");
|
|
9
|
+
var _server2 = require("@arch-cadre/modules/server");
|
|
10
|
+
var _navigation = require("next/navigation");
|
|
11
|
+
var React = _interopRequireWildcard(require("react"));
|
|
12
|
+
var _components = require("./components.cjs");
|
|
13
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
|
+
async function Page() {
|
|
16
|
+
const {
|
|
17
|
+
session,
|
|
18
|
+
user
|
|
19
|
+
} = await (0, _server.getCurrentSession)();
|
|
20
|
+
if (session !== null && user !== null) {
|
|
21
|
+
const security = await (0, _server.checkSecurity)(session, user);
|
|
22
|
+
if (!security.satisfied && security.redirect) {
|
|
23
|
+
return (0, _navigation.redirect)(security.redirect);
|
|
24
|
+
}
|
|
25
|
+
return (0, _navigation.redirect)("/");
|
|
26
|
+
}
|
|
27
|
+
const hasAllowed = await (0, _server2.hasExtension)("auth", "signin:extra-buttons");
|
|
28
|
+
return /* @__PURE__ */React.createElement(_components.LoginForm, {
|
|
29
|
+
hasAllowedExtensions: hasAllowed,
|
|
30
|
+
extraButtons: /* @__PURE__ */React.createElement(_modules.ExtensionPoint, {
|
|
31
|
+
module: "auth",
|
|
32
|
+
point: "signin:extra-buttons",
|
|
33
|
+
className: "flex flex-col gap-2"
|
|
34
|
+
}),
|
|
35
|
+
extraFields: /* @__PURE__ */React.createElement(_modules.ExtensionPoint, {
|
|
36
|
+
module: "auth",
|
|
37
|
+
point: "signin:extra-fields",
|
|
38
|
+
className: "flex flex-col gap-4"
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { checkSecurity, getCurrentSession } from "@arch-cadre/core/server";
|
|
2
|
+
import { ExtensionPoint } from "@arch-cadre/modules";
|
|
3
|
+
import { hasExtension } from "@arch-cadre/modules/server";
|
|
4
|
+
import { redirect } from "next/navigation";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { LoginForm } from "./components.mjs";
|
|
7
|
+
export default async function Page() {
|
|
8
|
+
const { session, user } = await getCurrentSession();
|
|
9
|
+
if (session !== null && user !== null) {
|
|
10
|
+
const security = await checkSecurity(session, user);
|
|
11
|
+
if (!security.satisfied && security.redirect) {
|
|
12
|
+
return redirect(security.redirect);
|
|
13
|
+
}
|
|
14
|
+
return redirect("/");
|
|
15
|
+
}
|
|
16
|
+
const hasAllowed = await hasExtension("auth", "signin:extra-buttons");
|
|
17
|
+
return /* @__PURE__ */ React.createElement(
|
|
18
|
+
LoginForm,
|
|
19
|
+
{
|
|
20
|
+
hasAllowedExtensions: hasAllowed,
|
|
21
|
+
extraButtons: /* @__PURE__ */ React.createElement(
|
|
22
|
+
ExtensionPoint,
|
|
23
|
+
{
|
|
24
|
+
module: "auth",
|
|
25
|
+
point: "signin:extra-buttons",
|
|
26
|
+
className: "flex flex-col gap-2"
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
extraFields: /* @__PURE__ */ React.createElement(
|
|
30
|
+
ExtensionPoint,
|
|
31
|
+
{
|
|
32
|
+
module: "auth",
|
|
33
|
+
point: "signin:extra-fields",
|
|
34
|
+
className: "flex flex-col gap-4"
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|