@ttoss/react-auth-strapi 0.4.0 → 0.4.2

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/README.md CHANGED
@@ -123,6 +123,35 @@ The component automatically handles:
123
123
  - **Email confirmation**: Manages email verification process
124
124
  - **Error notifications**: Shows user-friendly error messages
125
125
 
126
+ #### Props
127
+
128
+ ```tsx
129
+ <Auth
130
+ initialScreen={{ value: 'signUp' }} // Optional: start on a specific screen
131
+ logo={<MyLogo />} // Optional: custom logo
132
+ layout={{
133
+ // Optional: layout configuration
134
+ fullScreen: true,
135
+ sideContent: <BrandingContent />,
136
+ sideContentPosition: 'left',
137
+ }}
138
+ />
139
+ ```
140
+
141
+ **initialScreen**: Set the initial authentication screen to display. Useful for:
142
+
143
+ - Deep linking to specific auth flows (e.g., `/auth/signup` → `{ value: 'signUp' }`)
144
+ - Redirecting users to password reset from email links
145
+ - Pre-selecting sign up vs sign in based on user context
146
+
147
+ Available screens:
148
+
149
+ - `{ value: 'signIn' }` - Sign in screen (default)
150
+ - `{ value: 'signUp' }` - Sign up screen
151
+ - `{ value: 'forgotPassword' }` - Forgot password screen
152
+ - `{ value: 'confirmSignUpCheckEmail' }` - Email confirmation reminder
153
+ - `{ value: 'confirmResetPassword', context: { email: string } }` - Password reset screen
154
+
126
155
  ### useAuth Hook
127
156
 
128
157
  Enhanced version of the core useAuth hook with Strapi-specific context:
@@ -162,6 +191,104 @@ sequenceDiagram
162
191
  A->>A: Restore authentication state
163
192
  ```
164
193
 
194
+ ## Password Reset Flow with Email Links
195
+
196
+ ### Email Template Configuration
197
+
198
+ When configuring the password reset email template in Strapi, use this URL format to enable deep linking:
199
+
200
+ ```html
201
+ <p>We received a request to reset your password.</p>
202
+ <p>If it was you, click the link below to create a new password:</p>
203
+ <p><%= URL %>/auth?initialScreen=confirmResetPassword&code=<%= TOKEN %></p>
204
+ <p>If it wasn't you, ignore this email. Your account will remain secure.</p>
205
+ <p>Thank you,</p>
206
+ <p>Team</p>
207
+ ```
208
+
209
+ ### React Router Integration
210
+
211
+ To handle password reset links from email, configure your route to parse URL parameters and pass them to the Auth component:
212
+
213
+ ```tsx
214
+ import { useSearchParams } from 'react-router-dom';
215
+ import { Auth, type AuthScreen } from '@ttoss/react-auth-strapi';
216
+
217
+ function AuthPage() {
218
+ const [searchParams] = useSearchParams();
219
+
220
+ // Parse URL parameters from email link
221
+ const initialScreenParam = searchParams.get('initialScreen');
222
+ const code = searchParams.get('code');
223
+
224
+ // Build the initialScreen object
225
+ let initialScreen: AuthScreen | undefined;
226
+
227
+ if (initialScreenParam === 'confirmResetPassword' && code) {
228
+ initialScreen = {
229
+ value: 'confirmResetPassword',
230
+ context: { code },
231
+ };
232
+ } else if (initialScreenParam) {
233
+ // Handle other screen types without context
234
+ initialScreen = { value: initialScreenParam };
235
+ }
236
+
237
+ return <Auth initialScreen={initialScreen} />;
238
+ }
239
+ ```
240
+
241
+ ### Route Configuration
242
+
243
+ ```tsx
244
+ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
245
+ import { AuthProvider } from '@ttoss/react-auth-strapi';
246
+ import { NotificationProvider } from '@ttoss/react-notifications';
247
+
248
+ function App() {
249
+ return (
250
+ <NotificationProvider>
251
+ <AuthProvider apiUrl="https://your-strapi-api.com/api">
252
+ <BrowserRouter>
253
+ <Routes>
254
+ <Route path="/auth" element={<AuthPage />} />
255
+ <Route path="/" element={<HomePage />} />
256
+ </Routes>
257
+ </BrowserRouter>
258
+ </AuthProvider>
259
+ </NotificationProvider>
260
+ );
261
+ }
262
+ ```
263
+
264
+ ### Complete Flow
265
+
266
+ ```mermaid
267
+ sequenceDiagram
268
+ participant U as User
269
+ participant E as Email
270
+ participant R as React Router
271
+ participant A as Auth Component
272
+ participant S as Strapi API
273
+
274
+ U->>A: Click "Forgot Password"
275
+ A->>S: POST /auth/forgot-password
276
+ S->>E: Send reset email with link
277
+ E-->>U: Email: /auth?initialScreen=confirmResetPassword&code=ABC123
278
+
279
+ Note over U,R: User clicks email link
280
+ U->>R: Navigate to /auth?initialScreen=...&code=...
281
+ R->>R: Parse searchParams
282
+ R->>A: <Auth initialScreen={{ value: 'confirmResetPassword', context: { code: 'ABC123' } }} />
283
+ A-->>U: Display Reset Password form with pre-filled code
284
+
285
+ U->>A: Enter new password
286
+ A->>S: POST /auth/reset-password { code, password }
287
+ S-->>A: Success
288
+ A->>A: setScreen({ value: 'signIn' })
289
+ A-->>U: Display Sign In screen with success notification
290
+ ```
291
+
165
292
  ## Error Handling
166
293
 
167
294
  The package integrates with `@ttoss/react-notifications` to display authentication errors:
package/dist/esm/index.js CHANGED
@@ -135,7 +135,7 @@ var Auth = /* @__PURE__ */__name(props => {
135
135
  const {
136
136
  screen,
137
137
  setScreen
138
- } = useAuthScreen();
138
+ } = useAuthScreen(props.initialScreen);
139
139
  const {
140
140
  addNotification
141
141
  } = useNotifications();
@@ -267,6 +267,12 @@ var Auth = /* @__PURE__ */__name(props => {
267
267
  });
268
268
  return;
269
269
  }
270
+ setScreen({
271
+ value: "confirmResetPassword",
272
+ context: {
273
+ email
274
+ }
275
+ });
270
276
  } catch {
271
277
  addNotification({
272
278
  title: "Network Error",
@@ -274,19 +280,63 @@ var Auth = /* @__PURE__ */__name(props => {
274
280
  type: "error"
275
281
  });
276
282
  }
277
- }, [addNotification, apiUrl]);
283
+ }, [addNotification, setScreen, apiUrl]);
284
+ const onForgotPasswordResetPassword = React2.useCallback(async ({
285
+ email: _email,
286
+ code,
287
+ newPassword
288
+ }) => {
289
+ try {
290
+ const response = await fetch(`${apiUrl}/auth/reset-password`, {
291
+ method: "POST",
292
+ headers: {
293
+ "Content-Type": "application/json"
294
+ },
295
+ body: JSON.stringify({
296
+ code,
297
+ password: newPassword,
298
+ passwordConfirmation: newPassword
299
+ })
300
+ });
301
+ const data = await response.json();
302
+ if (!response.ok) {
303
+ addNotification({
304
+ title: "Reset password failed",
305
+ message: data.error?.message || "An error occurred during password reset.",
306
+ type: "error"
307
+ });
308
+ return;
309
+ }
310
+ addNotification({
311
+ title: "Password reset successful",
312
+ message: "You can now sign in with your new password.",
313
+ type: "success"
314
+ });
315
+ setScreen({
316
+ value: "signIn"
317
+ });
318
+ } catch {
319
+ addNotification({
320
+ title: "Network Error",
321
+ message: "Unable to connect to the server. Please check your connection.",
322
+ type: "error"
323
+ });
324
+ }
325
+ }, [addNotification, setScreen, apiUrl]);
278
326
  const onConfirmSignUpCheckEmail = React2.useCallback(async () => {
279
327
  setScreen({
280
328
  value: "signIn"
281
329
  });
282
330
  }, [setScreen]);
283
331
  return /* @__PURE__ */React2.createElement(AuthCore, {
284
- ...props,
332
+ logo: props.logo,
333
+ layout: props.layout,
285
334
  screen,
286
335
  setScreen,
287
336
  onSignIn,
288
337
  onSignUp,
289
338
  onForgotPassword,
339
+ onForgotPasswordResetPassword,
290
340
  onConfirmSignUpCheckEmail
291
341
  });
292
342
  }, "Auth");
package/dist/index.d.cts CHANGED
@@ -1,9 +1,12 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _ttoss_react_auth_core from '@ttoss/react-auth-core';
3
- import { AuthProps } from '@ttoss/react-auth-core';
3
+ import { AuthProps, AuthScreen } from '@ttoss/react-auth-core';
4
+ export { AuthScreen } from '@ttoss/react-auth-core';
4
5
  import * as React from 'react';
5
6
 
6
- declare const Auth: (props: Pick<AuthProps, "logo" | "layout">) => react_jsx_runtime.JSX.Element;
7
+ declare const Auth: (props: Pick<AuthProps, "logo" | "layout"> & {
8
+ initialScreen?: AuthScreen;
9
+ }) => react_jsx_runtime.JSX.Element;
7
10
 
8
11
  declare const AuthProvider: (props: React.PropsWithChildren<{
9
12
  apiUrl: string;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _ttoss_react_auth_core from '@ttoss/react-auth-core';
3
- import { AuthProps } from '@ttoss/react-auth-core';
3
+ import { AuthProps, AuthScreen } from '@ttoss/react-auth-core';
4
+ export { AuthScreen } from '@ttoss/react-auth-core';
4
5
  import * as React from 'react';
5
6
 
6
- declare const Auth: (props: Pick<AuthProps, "logo" | "layout">) => react_jsx_runtime.JSX.Element;
7
+ declare const Auth: (props: Pick<AuthProps, "logo" | "layout"> & {
8
+ initialScreen?: AuthScreen;
9
+ }) => react_jsx_runtime.JSX.Element;
7
10
 
8
11
  declare const AuthProvider: (props: React.PropsWithChildren<{
9
12
  apiUrl: string;
package/dist/index.js CHANGED
@@ -179,7 +179,7 @@ var Auth = /* @__PURE__ */__name(props => {
179
179
  const {
180
180
  screen,
181
181
  setScreen
182
- } = (0, import_react_auth_core2.useAuthScreen)();
182
+ } = (0, import_react_auth_core2.useAuthScreen)(props.initialScreen);
183
183
  const {
184
184
  addNotification
185
185
  } = (0, import_react_notifications.useNotifications)();
@@ -311,6 +311,12 @@ var Auth = /* @__PURE__ */__name(props => {
311
311
  });
312
312
  return;
313
313
  }
314
+ setScreen({
315
+ value: "confirmResetPassword",
316
+ context: {
317
+ email
318
+ }
319
+ });
314
320
  } catch {
315
321
  addNotification({
316
322
  title: "Network Error",
@@ -318,19 +324,63 @@ var Auth = /* @__PURE__ */__name(props => {
318
324
  type: "error"
319
325
  });
320
326
  }
321
- }, [addNotification, apiUrl]);
327
+ }, [addNotification, setScreen, apiUrl]);
328
+ const onForgotPasswordResetPassword = React2.useCallback(async ({
329
+ email: _email,
330
+ code,
331
+ newPassword
332
+ }) => {
333
+ try {
334
+ const response = await fetch(`${apiUrl}/auth/reset-password`, {
335
+ method: "POST",
336
+ headers: {
337
+ "Content-Type": "application/json"
338
+ },
339
+ body: JSON.stringify({
340
+ code,
341
+ password: newPassword,
342
+ passwordConfirmation: newPassword
343
+ })
344
+ });
345
+ const data = await response.json();
346
+ if (!response.ok) {
347
+ addNotification({
348
+ title: "Reset password failed",
349
+ message: data.error?.message || "An error occurred during password reset.",
350
+ type: "error"
351
+ });
352
+ return;
353
+ }
354
+ addNotification({
355
+ title: "Password reset successful",
356
+ message: "You can now sign in with your new password.",
357
+ type: "success"
358
+ });
359
+ setScreen({
360
+ value: "signIn"
361
+ });
362
+ } catch {
363
+ addNotification({
364
+ title: "Network Error",
365
+ message: "Unable to connect to the server. Please check your connection.",
366
+ type: "error"
367
+ });
368
+ }
369
+ }, [addNotification, setScreen, apiUrl]);
322
370
  const onConfirmSignUpCheckEmail = React2.useCallback(async () => {
323
371
  setScreen({
324
372
  value: "signIn"
325
373
  });
326
374
  }, [setScreen]);
327
375
  return /* @__PURE__ */React2.createElement(import_react_auth_core2.Auth, {
328
- ...props,
376
+ logo: props.logo,
377
+ layout: props.layout,
329
378
  screen,
330
379
  setScreen,
331
380
  onSignIn,
332
381
  onSignUp,
333
382
  onForgotPassword,
383
+ onForgotPasswordResetPassword,
334
384
  onConfirmSignUpCheckEmail
335
385
  });
336
386
  }, "Auth");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/react-auth-strapi",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Authentication components and abstractions for React apps using Strapi.",
5
5
  "license": "MIT",
6
6
  "author": "ttoss",
@@ -26,19 +26,23 @@
26
26
  "sideEffects": false,
27
27
  "peerDependencies": {
28
28
  "react": ">=16.8.0",
29
- "@ttoss/react-auth-core": "^0.4.0",
30
29
  "@ttoss/react-i18n": "^2.1.0",
31
- "@ttoss/react-notifications": "^2.6.0"
30
+ "@ttoss/react-auth-core": "^0.4.2",
31
+ "@ttoss/react-notifications": "^2.6.1"
32
32
  },
33
33
  "devDependencies": {
34
+ "@jest/globals": "^29.7.0",
34
35
  "@types/react": "^19.2.14",
35
36
  "jest": "^30.2.0",
36
37
  "react": "^19.2.4",
37
38
  "tsup": "^8.5.1",
39
+ "@ttoss/config": "^1.36.0",
38
40
  "@ttoss/i18n-cli": "^0.7.39",
41
+ "@ttoss/react-auth-core": "^0.4.2",
39
42
  "@ttoss/react-i18n": "^2.1.0",
40
- "@ttoss/react-auth-core": "^0.4.0",
41
- "@ttoss/react-notifications": "^2.6.0"
43
+ "@ttoss/react-notifications": "^2.6.1",
44
+ "@ttoss/ui": "^6.7.0",
45
+ "@ttoss/test-utils": "^4.1.0"
42
46
  },
43
47
  "keywords": [
44
48
  "React",
@@ -53,6 +57,6 @@
53
57
  "scripts": {
54
58
  "build": "tsup",
55
59
  "i18n": "ttoss-i18n",
56
- "test": "echo jest --projects tests/unit"
60
+ "test": "jest --projects tests/unit"
57
61
  }
58
62
  }