@ttoss/react-auth 2.1.0 → 2.2.0

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/esm/index.js CHANGED
@@ -928,10 +928,16 @@ var AuthLogic = () => {
928
928
  }) => {
929
929
  try {
930
930
  setLoading(true);
931
- await signIn({
931
+ const result = await signIn({
932
932
  username: email,
933
933
  password
934
934
  });
935
+ if (result.nextStep.signInStep === "RESET_PASSWORD") {
936
+ setNotifications({
937
+ type: "error",
938
+ message: `For your security, we have updated our system and you need to reset your password in 'forgot your password?' to proceed`
939
+ });
940
+ }
935
941
  } catch (error) {
936
942
  switch (error.code) {
937
943
  case "UserNotConfirmedException":
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@ttoss/react-auth",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "ttoss authentication module for React apps.",
5
+ "license": "MIT",
5
6
  "author": "ttoss",
6
7
  "contributors": [
7
8
  "Pedro Arantes <pedro@arantespp.com> (https://arantespp.com/contact)"
@@ -20,21 +21,20 @@
20
21
  },
21
22
  "files": [
22
23
  "dist",
23
- "i18n",
24
- "src"
24
+ "i18n"
25
25
  ],
26
26
  "sideEffects": false,
27
27
  "dependencies": {
28
28
  "@xstate/react": "^3.2.2",
29
29
  "xstate": "^4.38.3",
30
- "@ttoss/forms": "^0.26.0"
30
+ "@ttoss/forms": "^0.26.1"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "aws-amplify": "^6.0.0",
34
34
  "react": ">=16.8.0",
35
- "@ttoss/react-i18n": "^2.0.3",
36
- "@ttoss/ui": "^5.0.7",
37
- "@ttoss/react-notifications": "^1.24.57"
35
+ "@ttoss/react-notifications": "^1.24.58",
36
+ "@ttoss/react-i18n": "^2.0.4",
37
+ "@ttoss/ui": "^5.0.8"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@jest/globals": "^29.7.0",
@@ -43,13 +43,13 @@
43
43
  "jest": "^29.7.0",
44
44
  "react": "^18.3.1",
45
45
  "tsup": "^8.3.0",
46
- "@ttoss/config": "^1.34.0",
47
- "@ttoss/cloud-auth": "^0.12.21",
48
- "@ttoss/i18n-cli": "^0.7.21",
49
- "@ttoss/react-notifications": "^1.24.57",
50
- "@ttoss/react-i18n": "^2.0.3",
51
- "@ttoss/test-utils": "^2.1.16",
52
- "@ttoss/ui": "^5.0.7"
46
+ "@ttoss/i18n-cli": "^0.7.22",
47
+ "@ttoss/cloud-auth": "^0.12.22",
48
+ "@ttoss/react-i18n": "^2.0.4",
49
+ "@ttoss/config": "^1.34.1",
50
+ "@ttoss/react-notifications": "^1.24.58",
51
+ "@ttoss/test-utils": "^2.1.17",
52
+ "@ttoss/ui": "^5.0.8"
53
53
  },
54
54
  "keywords": [
55
55
  "React",
package/src/Auth.tsx DELETED
@@ -1,328 +0,0 @@
1
- import * as React from 'react';
2
- import { AuthConfirmSignUp } from './AuthConfirmSignUp';
3
- import { AuthForgotPassword } from './AuthForgotPassword';
4
- import { AuthForgotPasswordResetPassword } from './AuthForgotPasswordResetPassword';
5
- import { AuthFullScreen } from './AuthFullScreen';
6
- import { AuthSignIn } from './AuthSignIn';
7
- import { AuthSignUp } from './AuthSignUp';
8
- import { LogoContextProps, LogoProvider } from './AuthCard';
9
- import { assign, createMachine } from 'xstate';
10
- import {
11
- confirmResetPassword,
12
- confirmSignUp,
13
- resendSignUpCode,
14
- resetPassword,
15
- signIn,
16
- signUp,
17
- } from 'aws-amplify/auth';
18
- import { useAuth } from './AuthProvider';
19
- import { useMachine } from '@xstate/react';
20
- import { useNotifications } from '@ttoss/react-notifications';
21
- import type {
22
- OnConfirmSignUp,
23
- OnForgotPassword,
24
- OnForgotPasswordResetPassword,
25
- OnSignIn,
26
- OnSignUp,
27
- } from './types';
28
-
29
- type AuthState =
30
- | {
31
- value: 'signIn';
32
- context: { email?: string };
33
- }
34
- | {
35
- value: 'signUp';
36
- context: Record<string, never>;
37
- }
38
- | {
39
- value: 'signUpConfirm';
40
- context: { email: string };
41
- }
42
- | {
43
- value: 'signUpResendConfirmation';
44
- context: { email: string };
45
- }
46
- | {
47
- value: 'forgotPassword';
48
- context: Record<string, never>;
49
- }
50
- | {
51
- value: 'forgotPasswordResetPassword';
52
- context: { email: string };
53
- };
54
-
55
- type AuthEvent =
56
- | { type: 'SIGN_UP' }
57
- | { type: 'SIGN_UP_CONFIRM'; email: string }
58
- | { type: 'SIGN_UP_CONFIRMED'; email: string }
59
- | { type: 'SIGN_UP_RESEND_CONFIRMATION'; email: string }
60
- | { type: 'RETURN_TO_SIGN_IN' }
61
- | { type: 'FORGOT_PASSWORD' }
62
- | { type: 'FORGOT_PASSWORD_RESET_PASSWORD'; email: string }
63
- | { type: 'FORGOT_PASSWORD_CONFIRMED'; email: string };
64
-
65
- type AuthContext = { email?: string };
66
-
67
- const authMachine = createMachine<AuthContext, AuthEvent, AuthState>(
68
- {
69
- predictableActionArguments: true,
70
- initial: 'signIn',
71
- states: {
72
- signIn: {
73
- on: {
74
- SIGN_UP: { target: 'signUp' },
75
- SIGN_UP_RESEND_CONFIRMATION: {
76
- actions: ['assignEmail'],
77
- target: 'signUpConfirm',
78
- },
79
- FORGOT_PASSWORD: { target: 'forgotPassword' },
80
- },
81
- },
82
- signUp: {
83
- on: {
84
- SIGN_UP_CONFIRM: {
85
- actions: ['assignEmail'],
86
- target: 'signUpConfirm',
87
- },
88
- RETURN_TO_SIGN_IN: { target: 'signIn' },
89
- },
90
- },
91
- signUpConfirm: {
92
- on: {
93
- SIGN_UP_CONFIRMED: {
94
- actions: ['assignEmail'],
95
- target: 'signIn',
96
- },
97
- },
98
- },
99
- forgotPassword: {
100
- on: {
101
- RETURN_TO_SIGN_IN: { target: 'signIn' },
102
- SIGN_UP: { target: 'signUp' },
103
- FORGOT_PASSWORD_RESET_PASSWORD: {
104
- actions: ['assignEmail'],
105
- target: 'forgotPasswordResetPassword',
106
- },
107
- },
108
- },
109
- forgotPasswordResetPassword: {
110
- on: {
111
- FORGOT_PASSWORD_CONFIRMED: {
112
- actions: ['assignEmail'],
113
- target: 'signIn',
114
- },
115
- RETURN_TO_SIGN_IN: { target: 'signIn' },
116
- },
117
- },
118
- },
119
- },
120
- {
121
- actions: {
122
- assignEmail: assign({
123
- email: (_, event) => {
124
- if ('email' in event) {
125
- return event.email;
126
- }
127
-
128
- return undefined;
129
- },
130
- }),
131
- },
132
- }
133
- );
134
-
135
- const AuthLogic = () => {
136
- const { isAuthenticated } = useAuth();
137
-
138
- const [state, send] = useMachine(authMachine);
139
-
140
- const { setLoading, setNotifications } = useNotifications();
141
-
142
- const onSignIn = React.useCallback<OnSignIn>(
143
- async ({ email, password }) => {
144
- try {
145
- setLoading(true);
146
- await signIn({ username: email, password });
147
- // toast('Signed In');
148
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
149
- } catch (error: any) {
150
- switch (error.code) {
151
- case 'UserNotConfirmedException':
152
- await resendSignUpCode({ username: email });
153
- send({ type: 'SIGN_UP_RESEND_CONFIRMATION', email });
154
- break;
155
- default:
156
- // toast(JSON.stringify(error, null, 2));
157
- }
158
- setNotifications({ type: 'error', message: error.message });
159
- } finally {
160
- setLoading(false);
161
- }
162
- },
163
- [send, setLoading, setNotifications]
164
- );
165
-
166
- const onSignUp = React.useCallback<OnSignUp>(
167
- async ({ email, password }) => {
168
- try {
169
- setLoading(true);
170
- await signUp({
171
- username: email,
172
- password,
173
- options: {
174
- userAttributes: {
175
- email,
176
- },
177
- },
178
- });
179
- // toast('Signed Up');
180
- send({ type: 'SIGN_UP_CONFIRM', email });
181
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
- } catch (error: any) {
183
- setNotifications({ type: 'error', message: error.message });
184
- // toast(JSON.stringify(error, null, 2));
185
- } finally {
186
- setLoading(false);
187
- }
188
- },
189
- [send, setLoading, setNotifications]
190
- );
191
-
192
- const onConfirmSignUp = React.useCallback<OnConfirmSignUp>(
193
- async ({ email, code }) => {
194
- try {
195
- setLoading(true);
196
- await confirmSignUp({ confirmationCode: code, username: email });
197
- // toast('Confirmed Signed In');
198
- send({ type: 'SIGN_UP_CONFIRMED', email });
199
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
200
- } catch (error: any) {
201
- setNotifications({ type: 'error', message: error.message });
202
- // toast(JSON.stringify(error, null, 2));
203
- } finally {
204
- setLoading(false);
205
- }
206
- },
207
- [send, setLoading, setNotifications]
208
- );
209
-
210
- const onReturnToSignIn = React.useCallback(() => {
211
- send({ type: 'RETURN_TO_SIGN_IN' });
212
- }, [send]);
213
-
214
- const onForgotPassword = React.useCallback<OnForgotPassword>(
215
- async ({ email }) => {
216
- try {
217
- setLoading(true);
218
- await resetPassword({ username: email });
219
- // toast('Forgot Password');
220
- send({ type: 'FORGOT_PASSWORD_RESET_PASSWORD', email });
221
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
- } catch (error: any) {
223
- setNotifications({ type: 'error', message: error.message });
224
- // toast(JSON.stringify(error, null, 2));
225
- } finally {
226
- setLoading(false);
227
- }
228
- },
229
- [send, setLoading, setNotifications]
230
- );
231
-
232
- const onForgotPasswordResetPassword =
233
- React.useCallback<OnForgotPasswordResetPassword>(
234
- async ({ email, code, newPassword }) => {
235
- try {
236
- setLoading(true);
237
- await confirmResetPassword({
238
- confirmationCode: code,
239
- username: email,
240
- newPassword,
241
- });
242
- // toast('Forgot Password Reset Password');
243
- send({ type: 'FORGOT_PASSWORD_CONFIRMED', email });
244
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
- } catch (error: any) {
246
- setNotifications({ type: 'error', message: error.message });
247
- // toast(JSON.stringify(error, null, 2));
248
- } finally {
249
- setLoading(false);
250
- }
251
- },
252
- [send, setLoading, setNotifications]
253
- );
254
-
255
- if (isAuthenticated) {
256
- return null;
257
- }
258
-
259
- if (state.matches('signUp')) {
260
- return (
261
- <AuthSignUp onSignUp={onSignUp} onReturnToSignIn={onReturnToSignIn} />
262
- );
263
- }
264
-
265
- if (state.matches('signUpConfirm')) {
266
- return (
267
- <AuthConfirmSignUp
268
- onConfirmSignUp={onConfirmSignUp}
269
- email={state.context.email}
270
- />
271
- );
272
- }
273
-
274
- if (state.matches('forgotPassword')) {
275
- return (
276
- <AuthForgotPassword
277
- onForgotPassword={onForgotPassword}
278
- onCancel={onReturnToSignIn}
279
- onSignUp={() => {
280
- return send('SIGN_UP');
281
- }}
282
- />
283
- );
284
- }
285
-
286
- if (state.matches('forgotPasswordResetPassword')) {
287
- return (
288
- <AuthForgotPasswordResetPassword
289
- email={state.context.email}
290
- onForgotPasswordResetPassword={onForgotPasswordResetPassword}
291
- onCancel={onReturnToSignIn}
292
- />
293
- );
294
- }
295
-
296
- return (
297
- <AuthSignIn
298
- onSignIn={onSignIn}
299
- onSignUp={() => {
300
- return send('SIGN_UP');
301
- }}
302
- onForgotPassword={() => {
303
- return send('FORGOT_PASSWORD');
304
- }}
305
- defaultValues={{ email: state.context.email }}
306
- />
307
- );
308
- };
309
-
310
- type AuthProps = LogoContextProps & {
311
- fullScreen?: boolean;
312
- };
313
-
314
- export const Auth = ({ logo, fullScreen = true }: AuthProps) => {
315
- const withLogoNode = React.useMemo(() => {
316
- return (
317
- <LogoProvider logo={logo}>
318
- <AuthLogic />
319
- </LogoProvider>
320
- );
321
- }, [logo]);
322
-
323
- if (fullScreen) {
324
- return <AuthFullScreen>{withLogoNode}</AuthFullScreen>;
325
- }
326
-
327
- return withLogoNode;
328
- };
package/src/AuthCard.tsx DELETED
@@ -1,95 +0,0 @@
1
- import * as React from 'react';
2
- import { Box, Button, Flex, Heading } from '@ttoss/ui';
3
- import { useNotifications } from '@ttoss/react-notifications';
4
-
5
- export type LogoContextProps = {
6
- logo?: React.ReactNode;
7
- children?: React.ReactNode;
8
- };
9
-
10
- const LogoContext = React.createContext<LogoContextProps>({});
11
-
12
- export const LogoProvider = ({ children, ...values }: LogoContextProps) => {
13
- return <LogoContext.Provider value={values}>{children}</LogoContext.Provider>;
14
- };
15
-
16
- type AuthCardProps = {
17
- children: React.ReactNode;
18
- title: string;
19
- buttonLabel: string;
20
- extraButton?: React.ReactNode;
21
- isValidForm?: boolean;
22
- };
23
-
24
- export const AuthCard = ({
25
- children,
26
- title,
27
- buttonLabel,
28
- extraButton,
29
- isValidForm,
30
- }: AuthCardProps) => {
31
- const { logo } = React.useContext(LogoContext);
32
-
33
- const { isLoading } = useNotifications();
34
-
35
- return (
36
- <Box
37
- sx={{
38
- width: '100%',
39
- border: 'default',
40
- borderColor: 'primary',
41
- paddingX: '2xl',
42
- paddingY: '3xl',
43
- backgroundColor: 'surface',
44
- }}
45
- >
46
- {logo && (
47
- <Flex
48
- sx={{
49
- width: '100%',
50
- maxHeight: '90px',
51
- justifyContent: 'center',
52
- marginBottom: '2xl',
53
- }}
54
- >
55
- {logo}
56
- </Flex>
57
- )}
58
- <Flex sx={{ flexDirection: 'column' }}>
59
- <Heading
60
- as="h2"
61
- variant="h2"
62
- sx={{
63
- marginBottom: '2xl',
64
- }}
65
- >
66
- {title}
67
- </Heading>
68
-
69
- {children}
70
-
71
- <Flex
72
- sx={{
73
- flexDirection: 'column',
74
- width: '100%',
75
- gap: 'xl',
76
- marginTop: '2xl',
77
- }}
78
- >
79
- <Button
80
- type="submit"
81
- aria-label="submit-button"
82
- variant="accent"
83
- disabled={isLoading || !isValidForm}
84
- sx={{ textAlign: 'center', display: 'initial' }}
85
- loading={isLoading}
86
- >
87
- {buttonLabel}
88
- </Button>
89
-
90
- {extraButton}
91
- </Flex>
92
- </Flex>
93
- </Box>
94
- );
95
- };
@@ -1,73 +0,0 @@
1
- import { AuthCard } from './AuthCard';
2
- import { Form, FormFieldInput, useForm, yup, yupResolver } from '@ttoss/forms';
3
- import { useI18n } from '@ttoss/react-i18n';
4
- import type { OnConfirmSignUp } from './types';
5
-
6
- export type AuthConfirmSignUpProps = {
7
- email: string;
8
- onConfirmSignUp: OnConfirmSignUp;
9
- };
10
-
11
- export const AuthConfirmSignUp = ({
12
- email,
13
- onConfirmSignUp,
14
- }: AuthConfirmSignUpProps) => {
15
- const { intl } = useI18n();
16
-
17
- const schema = yup
18
- .object()
19
- .shape({
20
- code: yup
21
- .string()
22
- .required(
23
- intl.formatMessage({
24
- description: 'Required field.',
25
- defaultMessage: 'Required field',
26
- })
27
- )
28
- .max(
29
- 6,
30
- intl.formatMessage(
31
- {
32
- description: 'Minimum {value} characters.',
33
- defaultMessage: 'Minimum {value} characters',
34
- },
35
- { value: 6 }
36
- )
37
- ),
38
- })
39
- .required();
40
-
41
- const formMethods = useForm<yup.InferType<typeof schema>>({
42
- resolver: yupResolver(schema),
43
- });
44
-
45
- return (
46
- <Form
47
- {...formMethods}
48
- onSubmit={({ code }) => {
49
- return onConfirmSignUp({ code, email });
50
- }}
51
- >
52
- <AuthCard
53
- buttonLabel={intl.formatMessage({
54
- description: 'Confirm',
55
- defaultMessage: 'Confirm',
56
- })}
57
- isValidForm={formMethods.formState.isValid}
58
- title={intl.formatMessage({
59
- description: 'Confirmation',
60
- defaultMessage: 'Confirmation',
61
- })}
62
- >
63
- <FormFieldInput
64
- name="code"
65
- label={intl.formatMessage({
66
- description: 'Sign up confirmation code',
67
- defaultMessage: 'Code',
68
- })}
69
- />
70
- </AuthCard>
71
- </Form>
72
- );
73
- };
@@ -1,102 +0,0 @@
1
- import { AuthCard } from './AuthCard';
2
- import { Button, Link, Text } from '@ttoss/ui';
3
- import { Form, FormFieldInput, useForm, yup, yupResolver } from '@ttoss/forms';
4
- import { NotificationsBox } from '@ttoss/react-notifications';
5
- import { useI18n } from '@ttoss/react-i18n';
6
- import type { OnForgotPassword } from './types';
7
-
8
- export type AuthForgotPasswordProps = {
9
- onForgotPassword: OnForgotPassword;
10
- onCancel: () => void;
11
- onSignUp: () => void;
12
- };
13
-
14
- export const AuthForgotPassword = ({
15
- onForgotPassword,
16
- onCancel,
17
- onSignUp,
18
- }: AuthForgotPasswordProps) => {
19
- const { intl } = useI18n();
20
-
21
- const schema = yup
22
- .object()
23
- .shape({
24
- email: yup
25
- .string()
26
- .required(
27
- intl.formatMessage({
28
- description: 'Required field.',
29
- defaultMessage: 'Enter your email address',
30
- })
31
- )
32
- .email(
33
- intl.formatMessage({
34
- description: 'Please, insert a valid e-mail',
35
- defaultMessage: 'Please, insert a valid e-mail',
36
- })
37
- ),
38
- })
39
- .required();
40
-
41
- const formMethods = useForm<yup.InferType<typeof schema>>({
42
- resolver: yupResolver(schema),
43
- mode: 'onBlur',
44
- });
45
-
46
- return (
47
- <Form
48
- {...formMethods}
49
- sx={{
50
- maxWidth: '390px',
51
- }}
52
- onSubmit={({ email }) => {
53
- return onForgotPassword({ email });
54
- }}
55
- >
56
- <AuthCard
57
- buttonLabel={intl.formatMessage({
58
- description: 'Recover Password',
59
- defaultMessage: 'Recover Password',
60
- })}
61
- isValidForm={formMethods.formState.isValid}
62
- title={intl.formatMessage({
63
- description: 'Recovering Password',
64
- defaultMessage: 'Recovering Password',
65
- })}
66
- extraButton={
67
- <Button
68
- sx={{ textAlign: 'center', display: 'initial' }}
69
- variant="secondary"
70
- onClick={onCancel}
71
- >
72
- {intl.formatMessage({
73
- description: 'Cancel',
74
- defaultMessage: 'Cancel',
75
- })}
76
- </Button>
77
- }
78
- >
79
- <FormFieldInput
80
- name="email"
81
- label={intl.formatMessage({
82
- description: 'Registered Email',
83
- defaultMessage: 'Registered Email',
84
- })}
85
- />
86
-
87
- <NotificationsBox />
88
-
89
- <Text
90
- sx={{ marginTop: 'xl', cursor: 'pointer' }}
91
- as={Link}
92
- onClick={onSignUp}
93
- >
94
- {intl.formatMessage({
95
- description: 'Sign up now',
96
- defaultMessage: 'Sign up now',
97
- })}
98
- </Text>
99
- </AuthCard>
100
- </Form>
101
- );
102
- };