@oneblink/apps-react 4.0.0-beta.1 → 4.0.0-beta.11

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.
Files changed (146) hide show
  1. package/README.md +2 -8
  2. package/dist/OneBlinkAutoSaveForm.d.ts +25 -5
  3. package/dist/OneBlinkAutoSaveForm.js +12 -0
  4. package/dist/OneBlinkAutoSaveForm.js.map +1 -1
  5. package/dist/OneBlinkForm.d.ts +558 -8
  6. package/dist/OneBlinkForm.js +546 -0
  7. package/dist/OneBlinkForm.js.map +1 -1
  8. package/dist/OneBlinkFormBase.d.ts +52 -7
  9. package/dist/OneBlinkFormBase.js +4 -1
  10. package/dist/OneBlinkFormBase.js.map +1 -1
  11. package/dist/OneBlinkReadOnlyForm.d.ts +83 -6
  12. package/dist/OneBlinkReadOnlyForm.js +80 -1
  13. package/dist/OneBlinkReadOnlyForm.js.map +1 -1
  14. package/dist/PaymentReceipt.d.ts +59 -0
  15. package/dist/PaymentReceipt.js +49 -0
  16. package/dist/PaymentReceipt.js.map +1 -1
  17. package/dist/components/formStore/FormStoreTableProvider.js +23 -1
  18. package/dist/components/formStore/FormStoreTableProvider.js.map +1 -1
  19. package/dist/components/formStore/OneBlinkFormStoreClearFiltersButton.d.ts +5 -0
  20. package/dist/components/formStore/OneBlinkFormStoreClearFiltersButton.js +5 -0
  21. package/dist/components/formStore/OneBlinkFormStoreClearFiltersButton.js.map +1 -1
  22. package/dist/components/formStore/OneBlinkFormStoreColumnsButton.d.ts +5 -0
  23. package/dist/components/formStore/OneBlinkFormStoreColumnsButton.js +5 -0
  24. package/dist/components/formStore/OneBlinkFormStoreColumnsButton.js.map +1 -1
  25. package/dist/components/formStore/OneBlinkFormStoreDownloadButton.d.ts +5 -0
  26. package/dist/components/formStore/OneBlinkFormStoreDownloadButton.js +5 -0
  27. package/dist/components/formStore/OneBlinkFormStoreDownloadButton.js.map +1 -1
  28. package/dist/components/formStore/OneBlinkFormStoreProvider.d.ts +5 -0
  29. package/dist/components/formStore/OneBlinkFormStoreProvider.js +5 -0
  30. package/dist/components/formStore/OneBlinkFormStoreProvider.js.map +1 -1
  31. package/dist/components/formStore/OneBlinkFormStoreRefreshButton.d.ts +5 -0
  32. package/dist/components/formStore/OneBlinkFormStoreRefreshButton.js +5 -0
  33. package/dist/components/formStore/OneBlinkFormStoreRefreshButton.js.map +1 -1
  34. package/dist/components/formStore/OneBlinkFormStoreTable.d.ts +4 -0
  35. package/dist/components/formStore/OneBlinkFormStoreTable.js +4 -0
  36. package/dist/components/formStore/OneBlinkFormStoreTable.js.map +1 -1
  37. package/dist/components/pickers/V4CompatibleDatePicker.d.ts +5 -0
  38. package/dist/components/pickers/V4CompatibleDatePicker.js +5 -0
  39. package/dist/components/pickers/V4CompatibleDatePicker.js.map +1 -1
  40. package/dist/components/pickers/V4CompatibleDateTimePicker.d.ts +5 -0
  41. package/dist/components/pickers/V4CompatibleDateTimePicker.js +5 -0
  42. package/dist/components/pickers/V4CompatibleDateTimePicker.js.map +1 -1
  43. package/dist/components/pickers/V4CompatibleTimePicker.d.ts +5 -0
  44. package/dist/components/pickers/V4CompatibleTimePicker.js +5 -0
  45. package/dist/components/pickers/V4CompatibleTimePicker.js.map +1 -1
  46. package/dist/components/renderer/LookupButton.js +2 -2
  47. package/dist/components/renderer/LookupButton.js.map +1 -1
  48. package/dist/components/renderer/LookupNotification.js +47 -25
  49. package/dist/components/renderer/LookupNotification.js.map +1 -1
  50. package/dist/components/renderer/OneBlinkFormElements.d.ts +3 -3
  51. package/dist/components/renderer/OneBlinkFormElements.js.map +1 -1
  52. package/dist/components/renderer/PageFormElements.d.ts +3 -3
  53. package/dist/components/renderer/PageFormElements.js.map +1 -1
  54. package/dist/components/renderer/ProgressBar.d.ts +7 -3
  55. package/dist/components/renderer/ProgressBar.js +5 -0
  56. package/dist/components/renderer/ProgressBar.js.map +1 -1
  57. package/dist/form-elements/FormElementBarcodeScanner.js +2 -2
  58. package/dist/form-elements/FormElementBarcodeScanner.js.map +1 -1
  59. package/dist/form-elements/FormElementCalculation.js.map +1 -1
  60. package/dist/form-elements/FormElementForm.d.ts +4 -4
  61. package/dist/form-elements/FormElementForm.js.map +1 -1
  62. package/dist/form-elements/FormElementRepeatableSet.d.ts +4 -4
  63. package/dist/form-elements/FormElementRepeatableSet.js.map +1 -1
  64. package/dist/form-elements/FormElementSummary.js.map +1 -1
  65. package/dist/hooks/useAuth.d.ts +81 -6
  66. package/dist/hooks/useAuth.js +54 -0
  67. package/dist/hooks/useAuth.js.map +1 -1
  68. package/dist/hooks/useBooleanState.d.ts +42 -5
  69. package/dist/hooks/useBooleanState.js +36 -0
  70. package/dist/hooks/useBooleanState.js.map +1 -1
  71. package/dist/hooks/useClickOutsideElement.d.ts +40 -0
  72. package/dist/hooks/useClickOutsideElement.js +40 -0
  73. package/dist/hooks/useClickOutsideElement.js.map +1 -1
  74. package/dist/hooks/useConditionalLogic.d.ts +2 -3
  75. package/dist/hooks/useConditionalLogic.js.map +1 -1
  76. package/dist/hooks/useDrafts.d.ts +82 -0
  77. package/dist/hooks/useDrafts.js +204 -0
  78. package/dist/hooks/useDrafts.js.map +1 -0
  79. package/dist/hooks/useFormSubmissionAutoSaveState.d.ts +18 -5
  80. package/dist/hooks/useFormSubmissionAutoSaveState.js +10 -0
  81. package/dist/hooks/useFormSubmissionAutoSaveState.js.map +1 -1
  82. package/dist/hooks/useFormSubmissionModelContext.d.ts +4 -4
  83. package/dist/hooks/useFormSubmissionModelContext.js.map +1 -1
  84. package/dist/hooks/useFormSubmissionState.d.ts +45 -5
  85. package/dist/hooks/useFormSubmissionState.js +37 -0
  86. package/dist/hooks/useFormSubmissionState.js.map +1 -1
  87. package/dist/hooks/useFormValidation.d.ts +3 -3
  88. package/dist/hooks/useFormValidation.js.map +1 -1
  89. package/dist/hooks/useInjectPages.d.ts +2 -3
  90. package/dist/hooks/useInjectPages.js.map +1 -1
  91. package/dist/hooks/useIsMounted.d.ts +20 -0
  92. package/dist/hooks/useIsMounted.js +19 -0
  93. package/dist/hooks/useIsMounted.js.map +1 -1
  94. package/dist/hooks/useIsOffline.d.ts +54 -0
  95. package/dist/hooks/useIsOffline.js +54 -0
  96. package/dist/hooks/useIsOffline.js.map +1 -1
  97. package/dist/hooks/useLoadDataState.d.ts +46 -3
  98. package/dist/hooks/useLoadDataState.js +41 -0
  99. package/dist/hooks/useLoadDataState.js.map +1 -1
  100. package/dist/hooks/useLogin.d.ts +400 -13
  101. package/dist/hooks/useLogin.js +300 -0
  102. package/dist/hooks/useLogin.js.map +1 -1
  103. package/dist/hooks/useLookupNotification.d.ts +6 -2
  104. package/dist/hooks/useLookupNotification.js +29 -3
  105. package/dist/hooks/useLookupNotification.js.map +1 -1
  106. package/dist/hooks/useLookups.d.ts +3 -3
  107. package/dist/hooks/useLookups.js.map +1 -1
  108. package/dist/hooks/useNullableState.d.ts +46 -1
  109. package/dist/hooks/useNullableState.js +42 -1
  110. package/dist/hooks/useNullableState.js.map +1 -1
  111. package/dist/hooks/usePendingSubmissions.d.ts +103 -0
  112. package/dist/hooks/usePendingSubmissions.js +195 -0
  113. package/dist/hooks/usePendingSubmissions.js.map +1 -0
  114. package/dist/hooks/useSignUp.d.ts +5 -0
  115. package/dist/hooks/useSignUp.js +5 -0
  116. package/dist/hooks/useSignUp.js.map +1 -1
  117. package/dist/index.d.ts +7 -4
  118. package/dist/index.js +5 -2
  119. package/dist/index.js.map +1 -1
  120. package/dist/services/checkBsbsAreInvalid.d.ts +2 -3
  121. package/dist/services/checkBsbsAreInvalid.js.map +1 -1
  122. package/dist/services/checkIfAttachmentsExist.d.ts +2 -3
  123. package/dist/services/checkIfAttachmentsExist.js.map +1 -1
  124. package/dist/services/checkIfBsbsAreValidating.d.ts +2 -3
  125. package/dist/services/checkIfBsbsAreValidating.js.map +1 -1
  126. package/dist/services/cleanFormSubmissionModel.d.ts +4 -4
  127. package/dist/services/cleanFormSubmissionModel.js +2 -1
  128. package/dist/services/cleanFormSubmissionModel.js.map +1 -1
  129. package/dist/services/form-validation.d.ts +3 -3
  130. package/dist/services/form-validation.js.map +1 -1
  131. package/dist/services/generate-default-data.d.ts +2 -3
  132. package/dist/services/generate-default-data.js +3 -1
  133. package/dist/services/generate-default-data.js.map +1 -1
  134. package/dist/services/generateFreshdeskDependentFieldElements.js.map +1 -1
  135. package/dist/services/getDateRangeConfiguration.d.ts +2 -3
  136. package/dist/services/getDateRangeConfiguration.js.map +1 -1
  137. package/dist/services/getRepeatableSetEntriesConfiguration.d.ts +2 -3
  138. package/dist/services/getRepeatableSetEntriesConfiguration.js.map +1 -1
  139. package/dist/styles/receipt.scss +1 -1
  140. package/dist/styles/repeatable-set.scss +2 -2
  141. package/dist/typedoc.d.ts +2 -0
  142. package/dist/typedoc.js +3 -0
  143. package/dist/typedoc.js.map +1 -0
  144. package/dist/types/form.d.ts +5 -6
  145. package/dist/types/form.js.map +1 -1
  146. package/package.json +10 -4
@@ -2,6 +2,305 @@ import * as React from 'react';
2
2
  import { authService, Sentry } from '@oneblink/apps';
3
3
  import useIsMounted from './useIsMounted';
4
4
  import useBooleanState from './useBooleanState';
5
+ /**
6
+ * This function is a react hook to help writing your own login screen.
7
+ *
8
+ * ## Example
9
+ *
10
+ * ```jsx
11
+ * import * as React from 'react'
12
+ * import { useHistory } from 'react-router-dom'
13
+ * import { useLogin } from '@oneblink/apps-react'
14
+ *
15
+ * function App() {
16
+ * const history = useHistory()
17
+ *
18
+ * const [username, setUsername] = React.useState('')
19
+ * const [password, setPassword] = React.useState('')
20
+ * const [newPasswordConfirmed, setNewPasswordConfirmed] = React.useState('')
21
+ * const [newPassword, setNewPassword] = React.useState('')
22
+ * const [code, setCode] = React.useState('')
23
+ *
24
+ * const onLogin = React.useCallback(() => {
25
+ * history.push('/')
26
+ * }, [history])
27
+ *
28
+ * const {
29
+ * // Login
30
+ * loginWithGoogle,
31
+ * loginWithUsernamePassword,
32
+ * isLoggingIn,
33
+ * // Reset Temp Password
34
+ * isPasswordTemporary,
35
+ * isResettingTemporaryPassword,
36
+ * resetTemporaryPassword,
37
+ * // MFA Password
38
+ * isMfaCodeRequired,
39
+ * isSubmittingMfaCode,
40
+ * submitMfaCode,
41
+ * // Login Errors
42
+ * loginError,
43
+ * clearLoginError,
44
+ * // Showing Forgot Password
45
+ * isShowingForgotPassword,
46
+ * showForgotPassword,
47
+ * hideForgotPassword,
48
+ * // Sending Forgot Password Code
49
+ * isSendingForgotPasswordCode,
50
+ * sendForgotPasswordCode,
51
+ * // Resetting Forgotten Password
52
+ * hasSentForgotPasswordCode,
53
+ * isResettingForgottenPassword,
54
+ * resetForgottenPassword,
55
+ * // Forgot Password Errors
56
+ * forgotPasswordError,
57
+ * clearForgotPasswordError,
58
+ * // Validation
59
+ * usernameValidation,
60
+ * passwordValidation,
61
+ * codeValidation,
62
+ * newPasswordValidation,
63
+ * newPasswordConfirmedValidation,
64
+ * } = useLogin({
65
+ * username,
66
+ * password,
67
+ * newPassword,
68
+ * newPasswordConfirmed,
69
+ * code,
70
+ * onLogin,
71
+ * })
72
+ *
73
+ * if (hasSentForgotPasswordCode) {
74
+ * return (
75
+ * <form
76
+ * onSubmit={(e) => {
77
+ * e.preventDefault()
78
+ * resetForgottenPassword()
79
+ * }}
80
+ * >
81
+ * <p>We have sent you a password reset code via email. Enter it below to reset your password.</p>
82
+ *
83
+ * <input
84
+ * type="password"
85
+ * placeholder="Code"
86
+ * value={code}
87
+ * onChange={(e) => setCode(e.target.value)}
88
+ * />
89
+ *
90
+ * <input
91
+ * type="password"
92
+ * placeholder="New Password"
93
+ * value={newPassword}
94
+ * onChange={(e) => setNewPassword(e.target.value)}
95
+ * />
96
+ *
97
+ * <input
98
+ * type="password"
99
+ * placeholder="Confirm Password"
100
+ * value={newPassword}
101
+ * onChange={(e) => setNewPasswordConfirmed(e.target.value)}
102
+ * />
103
+ *
104
+ * <button
105
+ * type="submit"
106
+ * disabled={isResettingForgottenPassword || codeValidation.isInvalid || newPasswordValidation.isInvalid || newPasswordConfirmedValidation.isInvalid}
107
+ * >
108
+ * Change Password
109
+ * </button>
110
+ *
111
+ * <p>Password Requirements</p>
112
+ * <p>Contains a lowercase letter: {validation.hasLowercaseLetter ? 'Yes' : 'No'}</p>
113
+ * <p>Contains an upper case letter: {validation.hasUpperCaseLetter ? 'Yes' : 'No'}</p>
114
+ * <p>Contains a number: {validation.hasNumber ? 'Yes' : 'No'}</p>
115
+ * <p>Contains a special character: {validation.hasSpecialCharacter ? 'Yes' : 'No'}</p>
116
+ * <p>Contains at least 8 characters: {validation.hasMinLength ? 'Yes' : 'No'}</p>
117
+ *
118
+ * {forgotPasswordError && (
119
+ * <p>{forgotPasswordError.message}</p>
120
+ * <button type="button" onClick={clearForgotPasswordError}>Clear Error</button>
121
+ * )}
122
+ * </form>
123
+ * )
124
+ * }
125
+ *
126
+ * if (isShowingForgotPassword) {
127
+ * return (
128
+ * <form
129
+ * onSubmit={(e) => {
130
+ * e.preventDefault()
131
+ * sendForgotPasswordCode()
132
+ * }}
133
+ * >
134
+ * <p>Enter your email address and we will send you a code to reset your password.</p>
135
+ *
136
+ * <input
137
+ * type="email"
138
+ * placeholder="Email Address"
139
+ * value={username}
140
+ * onChange={(e) => setUsername(e.target.value)}
141
+ * />
142
+ *
143
+ * <p>
144
+ * <a onClick={hideForgotPassword}>Remembered your password?</a>
145
+ * </p>
146
+ *
147
+ * <button
148
+ * type="submit"
149
+ * disabled={isSendingForgotPasswordCode || usernameValidation.isInvalid}
150
+ * >
151
+ * Reset Password
152
+ * </button>
153
+ *
154
+ * {forgotPasswordError && (
155
+ * <p>{forgotPasswordError.message}</p>
156
+ * <button type="button" onClick={clearForgotPasswordError}>Clear Error</button>
157
+ * )}
158
+ * </form>
159
+ * )
160
+ * }
161
+ *
162
+ * if (isPasswordTemporary) {
163
+ * return (
164
+ * <form
165
+ * onSubmit={(e) => {
166
+ * e.preventDefault()
167
+ * resetTemporaryPassword()
168
+ * }}
169
+ * >
170
+ * <p>The password you entered was only temporary and must be reset for security purposes. Please enter your new password below to continue.</p>
171
+ *
172
+ * <input
173
+ * type="password"
174
+ * placeholder="New Password"
175
+ * value={newPassword}
176
+ * onChange={(e) => setNewPassword(e.target.value)}
177
+ * />
178
+ *
179
+ * <input
180
+ * type="password"
181
+ * placeholder="Confirm Password"
182
+ * value={newPassword}
183
+ * onChange={(e) => setNewPasswordConfirmed(e.target.value)}
184
+ * />
185
+ *
186
+ * <button
187
+ * type="submit"
188
+ * disabled={isResettingTemporaryPassword || newPasswordValidation.isInvalid || newPasswordConfirmedValidation.isInvalid}
189
+ * >
190
+ * Change Password &amp; Sign In
191
+ * </button>
192
+ *
193
+ * <p>Password Requirements</p>
194
+ * <p>Contains a lowercase letter: {validation.hasLowercaseLetter ? 'Yes' : 'No'}</p>
195
+ * <p>Contains an upper case letter: {validation.hasUpperCaseLetter ? 'Yes' : 'No'}</p>
196
+ * <p>Contains a number: {validation.hasNumber ? 'Yes' : 'No'}</p>
197
+ * <p>Contains a special character: {validation.hasSpecialCharacter ? 'Yes' : 'No'}</p>
198
+ * <p>Contains at least 8 characters: {validation.hasMinLength ? 'Yes' : 'No'}</p>
199
+ *
200
+ * {loginError && (
201
+ * <p>{loginError.message}</p>
202
+ * <button type="button" onClick={clearLoginError}>Clear Error</button>
203
+ * )}
204
+ * </form>
205
+ * )
206
+ * }
207
+ *
208
+ * if (isMfaCodeRequired) {
209
+ * return (
210
+ * <form
211
+ * onSubmit={(e) => {
212
+ * e.preventDefault()
213
+ * submitMfaCode()
214
+ * }}
215
+ * >
216
+ * <p>Enter the 6-digit code found in your authenticator app.</p>
217
+ *
218
+ * <input
219
+ * type="password"
220
+ * placeholder="Code"
221
+ * value={code}
222
+ * onChange={(e) => setCode(e.target.value)}
223
+ * />
224
+ *
225
+ * <button
226
+ * type="submit"
227
+ * disabled={isSubmittingMfaCode || codeValidation.isInvalid}
228
+ * >
229
+ * Sign In
230
+ * </button>
231
+ *
232
+ * {loginError && (
233
+ * <p>{loginError.message}</p>
234
+ * <button type="button" onClick={clearLoginError}>Clear Error</button>
235
+ * )}
236
+ * </form>
237
+ * )
238
+ * }
239
+ *
240
+ * return (
241
+ * <form
242
+ * onSubmit={(e) => {
243
+ * e.preventDefault()
244
+ * loginWithUsernamePassword()
245
+ * }}
246
+ * >
247
+ * <p>Sign in with your email address and password.</p>
248
+ * <input
249
+ * type="email"
250
+ * placeholder="Email Address"
251
+ * value={username}
252
+ * onChange={(e) => setUsername(e.target.value)}
253
+ * />
254
+ *
255
+ * <input
256
+ * type="password"
257
+ * placeholder="New Password"
258
+ * value={newPassword}
259
+ * onChange={(e) => setNewPassword(e.target.value)}
260
+ * />
261
+ *
262
+ * <p>
263
+ * <a onClick={showForgotPassword}>Forgot your password?</a>
264
+ * </p>
265
+ *
266
+ * <button
267
+ * type="submit"
268
+ * disabled={isLoggingIn || usernameValidation.isInvalid || passwordValidation.isInvalid}
269
+ * >
270
+ * {children}
271
+ * </button>
272
+ *
273
+ * <p>or</p>
274
+ *
275
+ * <button
276
+ * type="button"
277
+ * onClick={loginWithGoogle}
278
+ * >
279
+ * <img
280
+ * alt="Google"
281
+ * src="google-sign-in.png"
282
+ * />
283
+ * <span>Sign in with Google</span>
284
+ * </button>
285
+ *
286
+ * {loginError && (
287
+ * <p>{loginError.message}</p>
288
+ * <button type="button" onClick={clearLoginError}>Clear Error</button>
289
+ * )}
290
+ * </form>
291
+ * )
292
+ * }
293
+ *
294
+ * const root = document.getElementById('root')
295
+ * if (root) {
296
+ * ReactDOM.render(<App />, root)
297
+ * }
298
+ * ```
299
+ *
300
+ * @param options
301
+ * @returns
302
+ * @group Hooks
303
+ */
5
304
  export default function useLogin({ username, password, newPassword, newPasswordConfirmed, code, }) {
6
305
  const isMounted = useIsMounted();
7
306
  // Validation
@@ -298,6 +597,7 @@ export default function useLogin({ username, password, newPassword, newPasswordC
298
597
  }, []);
299
598
  return {
300
599
  // Login
600
+ /** Open redirect user to the Google sign in */
301
601
  loginWithGoogle,
302
602
  loginWithUsernamePassword,
303
603
  isLoggingIn,
@@ -1 +1 @@
1
- {"version":3,"file":"useLogin.js","sourceRoot":"","sources":["../../src/hooks/useLogin.ts"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { authService, Sentry } from '@oneblink/apps'\n\nimport useIsMounted from './useIsMounted'\nimport useBooleanState from './useBooleanState'\n\nexport default function useLogin({\n username,\n password,\n newPassword,\n newPasswordConfirmed,\n code,\n}: {\n username: string\n password: string\n newPassword: string\n newPasswordConfirmed: string\n code: string\n}) {\n const isMounted = useIsMounted()\n\n // Validation\n const usernameValidation = React.useMemo(() => {\n return {\n isInvalid: !username.trim(),\n }\n }, [username])\n\n const passwordValidation = React.useMemo(() => {\n return {\n isInvalid: !password.trim(),\n }\n }, [password])\n\n const codeValidation = React.useMemo(() => {\n return {\n isInvalid: !code.trim(),\n }\n }, [code])\n\n const newPasswordValidation = React.useMemo(() => {\n const validation = {\n hasLowercaseLetter: /[a-z]+/.test(newPassword),\n hasUpperCaseLetter: /[A-Z]+/.test(newPassword),\n hasNumber: /\\d+/.test(newPassword),\n hasSpecialCharacter: /[\\^$*.[\\]{}()?|\\-\"!@#%&/,><':;|_~`]+/.test(\n newPassword,\n ),\n hasMinLength: newPassword.length >= 8,\n isInvalid: true,\n }\n validation.isInvalid =\n !validation.hasLowercaseLetter ||\n !validation.hasUpperCaseLetter ||\n !validation.hasNumber ||\n !validation.hasSpecialCharacter ||\n !validation.hasMinLength\n return validation\n }, [newPassword])\n\n const newPasswordConfirmedValidation = React.useMemo(() => {\n return {\n isInvalid: newPassword !== newPasswordConfirmed,\n }\n }, [newPassword, newPasswordConfirmed])\n\n // Login, Reset Password, MFA\n const [\n {\n isResettingTemporaryPassword,\n isLoggingIn,\n loginError,\n loginAttemptResponse,\n isSubmittingMfaCode,\n },\n setLoginState,\n ] = React.useState<{\n isResettingTemporaryPassword: boolean\n isLoggingIn: boolean\n loginError: null | Error\n loginAttemptResponse: authService.LoginAttemptResponse | undefined\n isSubmittingMfaCode: boolean\n }>({\n isResettingTemporaryPassword: false,\n isLoggingIn: false,\n loginError: null,\n loginAttemptResponse: undefined,\n isSubmittingMfaCode: false,\n })\n const clearLoginError = React.useCallback(\n () =>\n setLoginState((current) => ({\n ...current,\n loginError: null,\n })),\n [],\n )\n const loginWithUsernamePassword = React.useCallback(async () => {\n if (usernameValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid email address'),\n }))\n return\n }\n if (passwordValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid password'),\n }))\n return\n }\n\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: true,\n loginError: null,\n }))\n\n try {\n const newLoginAttemptResponse = await authService.loginUsernamePassword(\n username,\n password,\n )\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: false,\n loginAttemptResponse: newLoginAttemptResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: false,\n loginError: error as Error,\n }))\n }\n }\n }, [\n isMounted,\n password,\n passwordValidation.isInvalid,\n username,\n usernameValidation.isInvalid,\n ])\n\n const resetTemporaryPassword = React.useCallback(async () => {\n const resetTemporaryPasswordCallback =\n loginAttemptResponse?.resetPasswordCallback\n if (!resetTemporaryPasswordCallback) {\n return\n }\n\n if (newPasswordValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid password'),\n }))\n return\n }\n\n if (newPasswordConfirmedValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please confirm your new password'),\n }))\n return\n }\n\n setLoginState((current) => ({\n ...current,\n isResettingPassword: true,\n loginError: null,\n }))\n\n try {\n const resetPasswordResponse = await resetTemporaryPasswordCallback(\n newPassword,\n )\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isResettingTemporaryPassword: false,\n loginAttemptResponse: resetPasswordResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((current) => ({\n ...current,\n isResettingPassword: false,\n loginError: error as Error,\n }))\n }\n }\n }, [\n isMounted,\n loginAttemptResponse?.resetPasswordCallback,\n newPassword,\n newPasswordConfirmedValidation.isInvalid,\n newPasswordValidation.isInvalid,\n ])\n\n const submitMfaCode = React.useCallback(async () => {\n const mfaCodeCallback = loginAttemptResponse?.mfaCodeCallback\n if (!mfaCodeCallback) {\n return\n }\n\n setLoginState((current) => ({\n ...current,\n isSubmittingMfaCode: true,\n loginError: null,\n }))\n\n try {\n const mfaResponse = await mfaCodeCallback(code)\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isSubmittingMfaCode: false,\n loginAttemptResponse: mfaResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((current) => ({\n ...current,\n isSubmittingMfaCode: false,\n loginError: error as Error,\n }))\n }\n }\n }, [code, isMounted, loginAttemptResponse?.mfaCodeCallback])\n\n // Forgot Password\n const [isShowingForgotPassword, showForgotPassword, hideForgotPassword] =\n useBooleanState(false)\n const [\n {\n resetForgottenPasswordCallback,\n isSendingForgotPasswordCode,\n isResettingForgottenPassword,\n forgotPasswordError,\n },\n setForgotPasswordState,\n ] = React.useState<{\n isSendingForgotPasswordCode: boolean\n forgotPasswordError: null | Error\n resetForgottenPasswordCallback:\n | null\n | ((code: string, newPassword: string) => void)\n isResettingForgottenPassword: boolean\n }>({\n isSendingForgotPasswordCode: false,\n forgotPasswordError: null,\n resetForgottenPasswordCallback: null,\n isResettingForgottenPassword: false,\n })\n const clearForgotPasswordError = React.useCallback(\n () =>\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: null,\n })),\n [],\n )\n const sendForgotPasswordCode = React.useCallback(async () => {\n if (usernameValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please enter a valid email address'),\n }))\n return\n }\n\n setForgotPasswordState({\n isSendingForgotPasswordCode: true,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n\n try {\n const newResetForgottenPasswordCallback =\n await authService.forgotPassword(username)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: newResetForgottenPasswordCallback,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: error as Error,\n isResettingForgottenPassword: false,\n })\n }\n }\n }, [isMounted, username, usernameValidation.isInvalid])\n\n const resetForgottenPassword = React.useCallback(async () => {\n if (!resetForgottenPasswordCallback) {\n return\n }\n\n if (codeValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error(\n 'Please enter the code that was sent to your email address',\n ),\n }))\n }\n if (newPasswordValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please enter a valid password'),\n }))\n return\n }\n if (newPasswordConfirmedValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please confirm your new password'),\n }))\n return\n }\n\n setForgotPasswordState((current) => ({\n ...current,\n isChangingPassword: true,\n forgotPasswordError: null,\n }))\n\n try {\n await resetForgottenPasswordCallback(code, newPassword)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n hideForgotPassword()\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setForgotPasswordState((current) => ({\n ...current,\n isChangingPassword: false,\n forgotPasswordError: error as Error,\n }))\n }\n }\n }, [\n resetForgottenPasswordCallback,\n codeValidation.isInvalid,\n newPasswordValidation.isInvalid,\n newPasswordConfirmedValidation.isInvalid,\n code,\n newPassword,\n isMounted,\n hideForgotPassword,\n ])\n\n const loginWithGoogle = React.useCallback(() => {\n authService.loginHostedUI('Google')\n }, [])\n\n return {\n // Login\n loginWithGoogle,\n loginWithUsernamePassword,\n isLoggingIn,\n loginError,\n clearLoginError,\n // Reset Temp Password\n isPasswordTemporary: !!loginAttemptResponse?.resetPasswordCallback,\n isResettingTemporaryPassword,\n resetTemporaryPassword,\n // MFA Code\n isMfaCodeRequired: !!loginAttemptResponse?.mfaCodeCallback,\n isSubmittingMfaCode,\n submitMfaCode,\n // Showing Forgot Password\n isShowingForgotPassword,\n showForgotPassword,\n hideForgotPassword,\n forgotPasswordError,\n clearForgotPasswordError,\n // Sending Forgot Password Code\n isSendingForgotPasswordCode,\n sendForgotPasswordCode,\n // Resetting Forgotten Password\n hasSentForgotPasswordCode: !!resetForgottenPasswordCallback,\n isResettingForgottenPassword,\n resetForgottenPassword,\n // Validation\n usernameValidation,\n passwordValidation,\n codeValidation,\n newPasswordValidation,\n newPasswordConfirmedValidation,\n }\n}\n"]}
1
+ {"version":3,"file":"useLogin.js","sourceRoot":"","sources":["../../src/hooks/useLogin.ts"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { authService, Sentry } from '@oneblink/apps'\n\nimport useIsMounted from './useIsMounted'\nimport useBooleanState from './useBooleanState'\n\n/**\n * This function is a react hook to help writing your own login screen.\n *\n * ## Example\n *\n * ```jsx\n * import * as React from 'react'\n * import { useHistory } from 'react-router-dom'\n * import { useLogin } from '@oneblink/apps-react'\n *\n * function App() {\n * const history = useHistory()\n *\n * const [username, setUsername] = React.useState('')\n * const [password, setPassword] = React.useState('')\n * const [newPasswordConfirmed, setNewPasswordConfirmed] = React.useState('')\n * const [newPassword, setNewPassword] = React.useState('')\n * const [code, setCode] = React.useState('')\n *\n * const onLogin = React.useCallback(() => {\n * history.push('/')\n * }, [history])\n *\n * const {\n * // Login\n * loginWithGoogle,\n * loginWithUsernamePassword,\n * isLoggingIn,\n * // Reset Temp Password\n * isPasswordTemporary,\n * isResettingTemporaryPassword,\n * resetTemporaryPassword,\n * // MFA Password\n * isMfaCodeRequired,\n * isSubmittingMfaCode,\n * submitMfaCode,\n * // Login Errors\n * loginError,\n * clearLoginError,\n * // Showing Forgot Password\n * isShowingForgotPassword,\n * showForgotPassword,\n * hideForgotPassword,\n * // Sending Forgot Password Code\n * isSendingForgotPasswordCode,\n * sendForgotPasswordCode,\n * // Resetting Forgotten Password\n * hasSentForgotPasswordCode,\n * isResettingForgottenPassword,\n * resetForgottenPassword,\n * // Forgot Password Errors\n * forgotPasswordError,\n * clearForgotPasswordError,\n * // Validation\n * usernameValidation,\n * passwordValidation,\n * codeValidation,\n * newPasswordValidation,\n * newPasswordConfirmedValidation,\n * } = useLogin({\n * username,\n * password,\n * newPassword,\n * newPasswordConfirmed,\n * code,\n * onLogin,\n * })\n *\n * if (hasSentForgotPasswordCode) {\n * return (\n * <form\n * onSubmit={(e) => {\n * e.preventDefault()\n * resetForgottenPassword()\n * }}\n * >\n * <p>We have sent you a password reset code via email. Enter it below to reset your password.</p>\n *\n * <input\n * type=\"password\"\n * placeholder=\"Code\"\n * value={code}\n * onChange={(e) => setCode(e.target.value)}\n * />\n *\n * <input\n * type=\"password\"\n * placeholder=\"New Password\"\n * value={newPassword}\n * onChange={(e) => setNewPassword(e.target.value)}\n * />\n *\n * <input\n * type=\"password\"\n * placeholder=\"Confirm Password\"\n * value={newPassword}\n * onChange={(e) => setNewPasswordConfirmed(e.target.value)}\n * />\n *\n * <button\n * type=\"submit\"\n * disabled={isResettingForgottenPassword || codeValidation.isInvalid || newPasswordValidation.isInvalid || newPasswordConfirmedValidation.isInvalid}\n * >\n * Change Password\n * </button>\n *\n * <p>Password Requirements</p>\n * <p>Contains a lowercase letter: {validation.hasLowercaseLetter ? 'Yes' : 'No'}</p>\n * <p>Contains an upper case letter: {validation.hasUpperCaseLetter ? 'Yes' : 'No'}</p>\n * <p>Contains a number: {validation.hasNumber ? 'Yes' : 'No'}</p>\n * <p>Contains a special character: {validation.hasSpecialCharacter ? 'Yes' : 'No'}</p>\n * <p>Contains at least 8 characters: {validation.hasMinLength ? 'Yes' : 'No'}</p>\n *\n * {forgotPasswordError && (\n * <p>{forgotPasswordError.message}</p>\n * <button type=\"button\" onClick={clearForgotPasswordError}>Clear Error</button>\n * )}\n * </form>\n * )\n * }\n *\n * if (isShowingForgotPassword) {\n * return (\n * <form\n * onSubmit={(e) => {\n * e.preventDefault()\n * sendForgotPasswordCode()\n * }}\n * >\n * <p>Enter your email address and we will send you a code to reset your password.</p>\n *\n * <input\n * type=\"email\"\n * placeholder=\"Email Address\"\n * value={username}\n * onChange={(e) => setUsername(e.target.value)}\n * />\n *\n * <p>\n * <a onClick={hideForgotPassword}>Remembered your password?</a>\n * </p>\n *\n * <button\n * type=\"submit\"\n * disabled={isSendingForgotPasswordCode || usernameValidation.isInvalid}\n * >\n * Reset Password\n * </button>\n *\n * {forgotPasswordError && (\n * <p>{forgotPasswordError.message}</p>\n * <button type=\"button\" onClick={clearForgotPasswordError}>Clear Error</button>\n * )}\n * </form>\n * )\n * }\n *\n * if (isPasswordTemporary) {\n * return (\n * <form\n * onSubmit={(e) => {\n * e.preventDefault()\n * resetTemporaryPassword()\n * }}\n * >\n * <p>The password you entered was only temporary and must be reset for security purposes. Please enter your new password below to continue.</p>\n *\n * <input\n * type=\"password\"\n * placeholder=\"New Password\"\n * value={newPassword}\n * onChange={(e) => setNewPassword(e.target.value)}\n * />\n *\n * <input\n * type=\"password\"\n * placeholder=\"Confirm Password\"\n * value={newPassword}\n * onChange={(e) => setNewPasswordConfirmed(e.target.value)}\n * />\n *\n * <button\n * type=\"submit\"\n * disabled={isResettingTemporaryPassword || newPasswordValidation.isInvalid || newPasswordConfirmedValidation.isInvalid}\n * >\n * Change Password &amp; Sign In\n * </button>\n *\n * <p>Password Requirements</p>\n * <p>Contains a lowercase letter: {validation.hasLowercaseLetter ? 'Yes' : 'No'}</p>\n * <p>Contains an upper case letter: {validation.hasUpperCaseLetter ? 'Yes' : 'No'}</p>\n * <p>Contains a number: {validation.hasNumber ? 'Yes' : 'No'}</p>\n * <p>Contains a special character: {validation.hasSpecialCharacter ? 'Yes' : 'No'}</p>\n * <p>Contains at least 8 characters: {validation.hasMinLength ? 'Yes' : 'No'}</p>\n *\n * {loginError && (\n * <p>{loginError.message}</p>\n * <button type=\"button\" onClick={clearLoginError}>Clear Error</button>\n * )}\n * </form>\n * )\n * }\n *\n * if (isMfaCodeRequired) {\n * return (\n * <form\n * onSubmit={(e) => {\n * e.preventDefault()\n * submitMfaCode()\n * }}\n * >\n * <p>Enter the 6-digit code found in your authenticator app.</p>\n *\n * <input\n * type=\"password\"\n * placeholder=\"Code\"\n * value={code}\n * onChange={(e) => setCode(e.target.value)}\n * />\n *\n * <button\n * type=\"submit\"\n * disabled={isSubmittingMfaCode || codeValidation.isInvalid}\n * >\n * Sign In\n * </button>\n *\n * {loginError && (\n * <p>{loginError.message}</p>\n * <button type=\"button\" onClick={clearLoginError}>Clear Error</button>\n * )}\n * </form>\n * )\n * }\n *\n * return (\n * <form\n * onSubmit={(e) => {\n * e.preventDefault()\n * loginWithUsernamePassword()\n * }}\n * >\n * <p>Sign in with your email address and password.</p>\n * <input\n * type=\"email\"\n * placeholder=\"Email Address\"\n * value={username}\n * onChange={(e) => setUsername(e.target.value)}\n * />\n *\n * <input\n * type=\"password\"\n * placeholder=\"New Password\"\n * value={newPassword}\n * onChange={(e) => setNewPassword(e.target.value)}\n * />\n *\n * <p>\n * <a onClick={showForgotPassword}>Forgot your password?</a>\n * </p>\n *\n * <button\n * type=\"submit\"\n * disabled={isLoggingIn || usernameValidation.isInvalid || passwordValidation.isInvalid}\n * >\n * {children}\n * </button>\n *\n * <p>or</p>\n *\n * <button\n * type=\"button\"\n * onClick={loginWithGoogle}\n * >\n * <img\n * alt=\"Google\"\n * src=\"google-sign-in.png\"\n * />\n * <span>Sign in with Google</span>\n * </button>\n *\n * {loginError && (\n * <p>{loginError.message}</p>\n * <button type=\"button\" onClick={clearLoginError}>Clear Error</button>\n * )}\n * </form>\n * )\n * }\n *\n * const root = document.getElementById('root')\n * if (root) {\n * ReactDOM.render(<App />, root)\n * }\n * ```\n *\n * @param options\n * @returns\n * @group Hooks\n */\nexport default function useLogin({\n username,\n password,\n newPassword,\n newPasswordConfirmed,\n code,\n}: {\n /** The email address entered by the user. */\n username: string\n /** The password entered by the user. */\n password: string\n /** The new password entered by the user if changing their password. */\n newPassword: string\n /**\n * The new password repeated by the user if changing their password to ensure\n * they do type it in wrong.\n */\n newPasswordConfirmed: string\n /**\n * The code sent to the user after requesting a password reset by starting the\n * \"forgot password\" process.\n */\n code: string\n}): UseLoginValue {\n const isMounted = useIsMounted()\n\n // Validation\n const usernameValidation = React.useMemo(() => {\n return {\n isInvalid: !username.trim(),\n }\n }, [username])\n\n const passwordValidation = React.useMemo(() => {\n return {\n isInvalid: !password.trim(),\n }\n }, [password])\n\n const codeValidation = React.useMemo(() => {\n return {\n isInvalid: !code.trim(),\n }\n }, [code])\n\n const newPasswordValidation = React.useMemo(() => {\n const validation = {\n hasLowercaseLetter: /[a-z]+/.test(newPassword),\n hasUpperCaseLetter: /[A-Z]+/.test(newPassword),\n hasNumber: /\\d+/.test(newPassword),\n hasSpecialCharacter: /[\\^$*.[\\]{}()?|\\-\"!@#%&/,><':;|_~`]+/.test(\n newPassword,\n ),\n hasMinLength: newPassword.length >= 8,\n isInvalid: true,\n }\n validation.isInvalid =\n !validation.hasLowercaseLetter ||\n !validation.hasUpperCaseLetter ||\n !validation.hasNumber ||\n !validation.hasSpecialCharacter ||\n !validation.hasMinLength\n return validation\n }, [newPassword])\n\n const newPasswordConfirmedValidation = React.useMemo(() => {\n return {\n isInvalid: newPassword !== newPasswordConfirmed,\n }\n }, [newPassword, newPasswordConfirmed])\n\n // Login, Reset Password, MFA\n const [\n {\n isResettingTemporaryPassword,\n isLoggingIn,\n loginError,\n loginAttemptResponse,\n isSubmittingMfaCode,\n },\n setLoginState,\n ] = React.useState<{\n isResettingTemporaryPassword: boolean\n isLoggingIn: boolean\n loginError: null | Error\n loginAttemptResponse: authService.LoginAttemptResponse | undefined\n isSubmittingMfaCode: boolean\n }>({\n isResettingTemporaryPassword: false,\n isLoggingIn: false,\n loginError: null,\n loginAttemptResponse: undefined,\n isSubmittingMfaCode: false,\n })\n const clearLoginError = React.useCallback(\n () =>\n setLoginState((current) => ({\n ...current,\n loginError: null,\n })),\n [],\n )\n const loginWithUsernamePassword = React.useCallback(async () => {\n if (usernameValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid email address'),\n }))\n return\n }\n if (passwordValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid password'),\n }))\n return\n }\n\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: true,\n loginError: null,\n }))\n\n try {\n const newLoginAttemptResponse = await authService.loginUsernamePassword(\n username,\n password,\n )\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: false,\n loginAttemptResponse: newLoginAttemptResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isLoggingIn: false,\n loginError: error as Error,\n }))\n }\n }\n }, [\n isMounted,\n password,\n passwordValidation.isInvalid,\n username,\n usernameValidation.isInvalid,\n ])\n\n const resetTemporaryPassword = React.useCallback(async () => {\n const resetTemporaryPasswordCallback =\n loginAttemptResponse?.resetPasswordCallback\n if (!resetTemporaryPasswordCallback) {\n return\n }\n\n if (newPasswordValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please enter a valid password'),\n }))\n return\n }\n\n if (newPasswordConfirmedValidation.isInvalid) {\n setLoginState((current) => ({\n ...current,\n loginError: new Error('Please confirm your new password'),\n }))\n return\n }\n\n setLoginState((current) => ({\n ...current,\n isResettingPassword: true,\n loginError: null,\n }))\n\n try {\n const resetPasswordResponse = await resetTemporaryPasswordCallback(\n newPassword,\n )\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isResettingTemporaryPassword: false,\n loginAttemptResponse: resetPasswordResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((current) => ({\n ...current,\n isResettingPassword: false,\n loginError: error as Error,\n }))\n }\n }\n }, [\n isMounted,\n loginAttemptResponse?.resetPasswordCallback,\n newPassword,\n newPasswordConfirmedValidation.isInvalid,\n newPasswordValidation.isInvalid,\n ])\n\n const submitMfaCode = React.useCallback(async () => {\n const mfaCodeCallback = loginAttemptResponse?.mfaCodeCallback\n if (!mfaCodeCallback) {\n return\n }\n\n setLoginState((current) => ({\n ...current,\n isSubmittingMfaCode: true,\n loginError: null,\n }))\n\n try {\n const mfaResponse = await mfaCodeCallback(code)\n if (isMounted.current) {\n setLoginState((currentState) => ({\n ...currentState,\n isSubmittingMfaCode: false,\n loginAttemptResponse: mfaResponse,\n }))\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setLoginState((current) => ({\n ...current,\n isSubmittingMfaCode: false,\n loginError: error as Error,\n }))\n }\n }\n }, [code, isMounted, loginAttemptResponse?.mfaCodeCallback])\n\n // Forgot Password\n const [isShowingForgotPassword, showForgotPassword, hideForgotPassword] =\n useBooleanState(false)\n const [\n {\n resetForgottenPasswordCallback,\n isSendingForgotPasswordCode,\n isResettingForgottenPassword,\n forgotPasswordError,\n },\n setForgotPasswordState,\n ] = React.useState<{\n isSendingForgotPasswordCode: boolean\n forgotPasswordError: null | Error\n resetForgottenPasswordCallback:\n | null\n | ((code: string, newPassword: string) => void)\n isResettingForgottenPassword: boolean\n }>({\n isSendingForgotPasswordCode: false,\n forgotPasswordError: null,\n resetForgottenPasswordCallback: null,\n isResettingForgottenPassword: false,\n })\n const clearForgotPasswordError = React.useCallback(\n () =>\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: null,\n })),\n [],\n )\n const sendForgotPasswordCode = React.useCallback(async () => {\n if (usernameValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please enter a valid email address'),\n }))\n return\n }\n\n setForgotPasswordState({\n isSendingForgotPasswordCode: true,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n\n try {\n const newResetForgottenPasswordCallback =\n await authService.forgotPassword(username)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: newResetForgottenPasswordCallback,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: error as Error,\n isResettingForgottenPassword: false,\n })\n }\n }\n }, [isMounted, username, usernameValidation.isInvalid])\n\n const resetForgottenPassword = React.useCallback(async () => {\n if (!resetForgottenPasswordCallback) {\n return\n }\n\n if (codeValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error(\n 'Please enter the code that was sent to your email address',\n ),\n }))\n }\n if (newPasswordValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please enter a valid password'),\n }))\n return\n }\n if (newPasswordConfirmedValidation.isInvalid) {\n setForgotPasswordState((current) => ({\n ...current,\n forgotPasswordError: new Error('Please confirm your new password'),\n }))\n return\n }\n\n setForgotPasswordState((current) => ({\n ...current,\n isChangingPassword: true,\n forgotPasswordError: null,\n }))\n\n try {\n await resetForgottenPasswordCallback(code, newPassword)\n if (isMounted.current) {\n setForgotPasswordState({\n isSendingForgotPasswordCode: false,\n resetForgottenPasswordCallback: null,\n forgotPasswordError: null,\n isResettingForgottenPassword: false,\n })\n hideForgotPassword()\n }\n } catch (error) {\n Sentry.captureException(error)\n if (isMounted.current) {\n setForgotPasswordState((current) => ({\n ...current,\n isChangingPassword: false,\n forgotPasswordError: error as Error,\n }))\n }\n }\n }, [\n resetForgottenPasswordCallback,\n codeValidation.isInvalid,\n newPasswordValidation.isInvalid,\n newPasswordConfirmedValidation.isInvalid,\n code,\n newPassword,\n isMounted,\n hideForgotPassword,\n ])\n\n const loginWithGoogle = React.useCallback(() => {\n authService.loginHostedUI('Google')\n }, [])\n\n return {\n // Login\n /** Open redirect user to the Google sign in */\n loginWithGoogle,\n loginWithUsernamePassword,\n isLoggingIn,\n loginError,\n clearLoginError,\n // Reset Temp Password\n isPasswordTemporary: !!loginAttemptResponse?.resetPasswordCallback,\n isResettingTemporaryPassword,\n resetTemporaryPassword,\n // MFA Code\n isMfaCodeRequired: !!loginAttemptResponse?.mfaCodeCallback,\n isSubmittingMfaCode,\n submitMfaCode,\n // Showing Forgot Password\n isShowingForgotPassword,\n showForgotPassword,\n hideForgotPassword,\n forgotPasswordError,\n clearForgotPasswordError,\n // Sending Forgot Password Code\n isSendingForgotPasswordCode,\n sendForgotPasswordCode,\n // Resetting Forgotten Password\n hasSentForgotPasswordCode: !!resetForgottenPasswordCallback,\n isResettingForgottenPassword,\n resetForgottenPassword,\n // Validation\n usernameValidation,\n passwordValidation,\n codeValidation,\n newPasswordValidation,\n newPasswordConfirmedValidation,\n }\n}\n\nexport interface UseLoginValue {\n /** Open redirect user to the Google sign-in page. */\n loginWithGoogle: () => void\n /**\n * Attempt to use the `username` and `password` arguments to create a session.\n * Will call `onLogin()` if successful, otherwise will set `loginError`.\n */\n loginWithUsernamePassword: () => void\n /** `true` while processing `loginWithUsernamePassword()`. */\n isLoggingIn: boolean\n /**\n * `true` if the user logged in using a temporary password. Prompt the user\n * for a new password and call `resetTemporaryPassword()`.\n */\n isPasswordTemporary: boolean\n /**\n * Attempt to use `newPassword` and `newPasswordConfirmed` arguments to reset\n * the user's password and create a session. Will call `onLogin()` if\n * successful, otherwise will set `loginError`.\n */\n resetTemporaryPassword: () => void\n /**\n * Set if an error occurs while processing `loginWithUsernamePassword()` or\n * `resetTemporaryPassword()`.\n */\n loginError: Error | null\n /** Set `loginError` back to `null`. */\n clearLoginError: () => void\n /** `true` while processing `resetTemporaryPassword()`. */\n isResettingTemporaryPassword: boolean\n /** `true` when showing the forgot password flow. */\n isShowingForgotPassword: boolean\n /** Set `isShowingForgotPassword` to `true`. */\n showForgotPassword: () => void\n /** Set `isShowingForgotPassword` to `false`. */\n hideForgotPassword: () => void\n /**\n * Attempt to use the `username` argument to start the forgot password\n * process. This will send the user an email with a code to enter. A failed\n * request will set `forgotPasswordError`.\n */\n sendForgotPasswordCode: () => void\n /** `true` while processing `sendForgotPasswordCode()`. */\n isSendingForgotPasswordCode: boolean\n /** `true` if the forgot password code has been successfully sent to the user. */\n hasSentForgotPasswordCode: boolean\n /**\n * Attempt to use the `code`, `newPassword`, and `newPasswordConfirmed`\n * arguments to reset the user's password. A failed request will set\n * `forgotPasswordError`.\n */\n resetForgottenPassword: () => void\n /** `true` while processing `resetForgottenPassword()`. */\n isResettingForgottenPassword: boolean\n /**\n * Set if an error occurs while processing `sendForgotPasswordCode()` or\n * `resetForgottenPassword()`.\n */\n forgotPasswordError: Error | null\n /** Set `forgotPasswordError` back to `null`. */\n clearForgotPasswordError: () => void\n usernameValidation: {\n /** `true` if the `username` argument is invalid. */\n isInvalid: boolean\n }\n passwordValidation: {\n /** `true` if the `password` argument is invalid. */\n isInvalid: boolean\n }\n codeValidation: {\n /** `true` if the `code` argument is invalid. */\n isInvalid: boolean\n }\n newPasswordValidation: {\n /** `true` if the `newPassword` argument is invalid. */\n isInvalid: boolean\n /**\n * `true` if the `newPassword` argument has a lowercase letter (required to\n * be valid).\n */\n hasLowercaseLetter: boolean\n /**\n * `true` if the `newPassword` argument has an uppercase letter (required to\n * be valid).\n */\n hasUpperCaseLetter: boolean\n /** `true` if the `newPassword` argument has a number (required to be valid). */\n hasNumber: boolean\n /**\n * `true` if the `newPassword` argument has a special character (required to\n * be valid).\n */\n hasSpecialCharacter: boolean\n /**\n * `true` if the `newPassword` argument has at least the minimum number of\n * characters (required to be valid).\n */\n hasMinLength: boolean\n }\n newPasswordConfirmedValidation: {\n /**\n * `true` if the `newPasswordConfirmed` argument is invalid (must match the\n * `newPassword` argument).\n */\n isInvalid: boolean\n }\n /**\n * `true` if the user logged in using MFA and a code is required to finish the\n * login attempt. Prompt the user for a code and call `submitMfaCode()`.\n */\n isMfaCodeRequired: boolean\n /** `true` while processing `submitMfaCode()`. */\n isSubmittingMfaCode: boolean\n /**\n * Attempt to use `code` argument to submit the MFA code and create a session.\n * Will call `onLogin()` if successful, otherwise will set `loginError`.\n */\n submitMfaCode: () => void\n}\n"]}
@@ -2,8 +2,12 @@ import * as React from 'react';
2
2
  type LookupNotificationContextValue = {
3
3
  isLookup: boolean;
4
4
  isDisabled: boolean;
5
- onLookup: (value: unknown) => Promise<void>;
5
+ onLookup: (value: unknown, abortSignal: AbortSignal) => Promise<void>;
6
6
  };
7
7
  export declare const LookupNotificationContext: React.Context<LookupNotificationContextValue>;
8
- export default function useLookupNotification(): LookupNotificationContextValue;
8
+ export default function useLookupNotification(value: unknown): {
9
+ onLookup: () => void;
10
+ isLookup: boolean;
11
+ isDisabled: boolean;
12
+ };
9
13
  export {};
@@ -2,10 +2,36 @@ import * as React from 'react';
2
2
  const defaultContext = {
3
3
  isLookup: false,
4
4
  isDisabled: false,
5
- onLookup: async () => { },
5
+ onLookup: async () => undefined,
6
6
  };
7
7
  export const LookupNotificationContext = React.createContext(defaultContext);
8
- export default function useLookupNotification() {
9
- return React.useContext(LookupNotificationContext);
8
+ export default function useLookupNotification(value) {
9
+ const { onLookup, ...state } = React.useContext(LookupNotificationContext);
10
+ // We use a number to trigger the lookup function so that we can have
11
+ // the effect below run every time the onLookup function is called.
12
+ // We need it in an useEffect so that we can pass an abort controller
13
+ // and have it aborted if the user clicks the lookup button again.
14
+ const [lookupCount, setLookupCount] = React.useState(0);
15
+ React.useEffect(() => {
16
+ if (lookupCount === 0) {
17
+ return;
18
+ }
19
+ const abortController = new AbortController();
20
+ onLookup(value, abortController.signal);
21
+ return () => {
22
+ abortController.abort();
23
+ };
24
+ // Wants to use "onLookup" and "value" as dependencies,
25
+ // however, these will change on any change made on any
26
+ // element. Checking if "lookupCount" has changed is enough
27
+ // to trigger a lookup when the correct dependencies change
28
+ // eslint-disable-next-line react-hooks/exhaustive-deps
29
+ }, [lookupCount]);
30
+ return {
31
+ ...state,
32
+ onLookup: React.useCallback(() => {
33
+ setLookupCount((currentLookupCount) => currentLookupCount + 1);
34
+ }, []),
35
+ };
10
36
  }
11
37
  //# sourceMappingURL=useLookupNotification.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLookupNotification.js","sourceRoot":"","sources":["../../src/hooks/useLookupNotification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,cAAc,GAAG;IACrB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,KAAK;IACjB,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;CACzB,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GACpC,KAAK,CAAC,aAAa,CAAiC,cAAc,CAAC,CAAA;AAErE,MAAM,CAAC,OAAO,UAAU,qBAAqB;IAC3C,OAAO,KAAK,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAA;AACpD,CAAC","sourcesContent":["import * as React from 'react'\n\ntype LookupNotificationContextValue = {\n isLookup: boolean\n isDisabled: boolean\n onLookup: (value: unknown) => Promise<void>\n}\n\nconst defaultContext = {\n isLookup: false,\n isDisabled: false,\n onLookup: async () => {},\n}\n\nexport const LookupNotificationContext =\n React.createContext<LookupNotificationContextValue>(defaultContext)\n\nexport default function useLookupNotification() {\n return React.useContext(LookupNotificationContext)\n}\n"]}
1
+ {"version":3,"file":"useLookupNotification.js","sourceRoot":"","sources":["../../src/hooks/useLookupNotification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,MAAM,cAAc,GAAG;IACrB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,KAAK;IACjB,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;CAChC,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GACpC,KAAK,CAAC,aAAa,CAAiC,cAAc,CAAC,CAAA;AAErE,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,KAAc;IAC1D,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAA;IAE1E,qEAAqE;IACrE,mEAAmE;IACnE,qEAAqE;IACrE,kEAAkE;IAClE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,WAAW,KAAK,CAAC,EAAE;YACrB,OAAM;SACP;QACD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAC7C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,CAAA;QACvC,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,KAAK,EAAE,CAAA;QACzB,CAAC,CAAA;QACD,uDAAuD;QACvD,uDAAuD;QACvD,2DAA2D;QAC3D,2DAA2D;QAC3D,uDAAuD;IACzD,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEjB,OAAO;QACL,GAAG,KAAK;QACR,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;YAC/B,cAAc,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,GAAG,CAAC,CAAC,CAAA;QAChE,CAAC,EAAE,EAAE,CAAC;KACP,CAAA;AACH,CAAC","sourcesContent":["import * as React from 'react'\n\ntype LookupNotificationContextValue = {\n isLookup: boolean\n isDisabled: boolean\n onLookup: (value: unknown, abortSignal: AbortSignal) => Promise<void>\n}\n\nconst defaultContext = {\n isLookup: false,\n isDisabled: false,\n onLookup: async () => undefined,\n}\n\nexport const LookupNotificationContext =\n React.createContext<LookupNotificationContextValue>(defaultContext)\n\nexport default function useLookupNotification(value: unknown) {\n const { onLookup, ...state } = React.useContext(LookupNotificationContext)\n\n // We use a number to trigger the lookup function so that we can have\n // the effect below run every time the onLookup function is called.\n // We need it in an useEffect so that we can pass an abort controller\n // and have it aborted if the user clicks the lookup button again.\n const [lookupCount, setLookupCount] = React.useState(0)\n\n React.useEffect(() => {\n if (lookupCount === 0) {\n return\n }\n const abortController = new AbortController()\n onLookup(value, abortController.signal)\n return () => {\n abortController.abort()\n }\n // Wants to use \"onLookup\" and \"value\" as dependencies,\n // however, these will change on any change made on any\n // element. Checking if \"lookupCount\" has changed is enough\n // to trigger a lookup when the correct dependencies change\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [lookupCount])\n\n return {\n ...state,\n onLookup: React.useCallback(() => {\n setLookupCount((currentLookupCount) => currentLookupCount + 1)\n }, []),\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { FormTypes } from '@oneblink/types';
2
- import { FormSubmissionModel, SetFormSubmission } from '../types/form';
1
+ import { FormTypes, SubmissionTypes } from '@oneblink/types';
2
+ import { SetFormSubmission } from '../types/form';
3
3
  export default function useLookups(formId: number, setFormSubmission: SetFormSubmission): {
4
- handlePagesLookupResult: (element: FormTypes.LookupFormElement, elementLookupData: FormTypes.PageElement[], dataLookupResult?: FormSubmissionModel) => void;
4
+ handlePagesLookupResult: (element: FormTypes.LookupFormElement, elementLookupData: FormTypes.PageElement[], dataLookupResult?: SubmissionTypes.S3SubmissionData['submission']) => void;
5
5
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useLookups.js","sourceRoot":"","sources":["../../src/hooks/useLookups.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAExD,OAAO,mBAAmB,MAAM,mCAAmC,CAAA;AAInE,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,MAAc,EACd,iBAAoC;IAEpC,MAAM,uBAAuB,GAAG,KAAK,CAAC,WAAW,CAC/C,CACE,OAAoC,EACpC,iBAA0C,EAC1C,gBAAsC,EACtC,EAAE;QACF,MAAM,eAAe,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC;YACJ,mBAAmB,EAAE,OAAO,CAAC,EAAE;SAChC,CAAC,CAAC,CAAA;QACH,iBAAiB,CAAC,CAAC,qBAAqB,EAAE,EAAE;YAC1C,MAAM,UAAU,GAAmB;gBACjC,GAAG,qBAAqB,CAAC,UAAU;gBACnC,WAAW,EAAE,IAAI;aAClB,CAAA;YACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,WAAW,EAAE;gBACjD,UAAU,CAAC,QAAQ,GAAG;oBACpB;wBACE,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE;wBACrB,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE,QAAQ;wBACf,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,QAAQ;wBACnD,iBAAiB,EAAE,KAAK;wBACxB,sCAAsC,EAAE,KAAK;qBAC9C;oBACD,GAAG,eAAe;iBACnB,CAAA;aACF;iBAAM;gBACL,MAAM,WAAW,GACf,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CACjD,CAAC,WAAkC,EAAE,EAAE;oBACrC,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,EAAE;wBAC/B,OAAO,mBAAmB,CAAC,eAAe,CACxC,WAAW,CAAC,QAAQ,EACpB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAC7B,CAAA;qBACF;gBACH,CAAC,CACF,CAAA;gBACH,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE;oBACtB,OAAO,qBAAqB,CAAA;iBAC7B;gBACD,UAAU,CAAC,QAAQ;oBACjB,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAC9C,CACE,mBAA4C,EAC5C,WAAkC,EAClC,KAAa,EACb,EAAE;wBACF,uFAAuF;wBACvF,IAAI,WAAW,CAAC,mBAAmB,KAAK,OAAO,CAAC,EAAE,EAAE;4BAClD,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;yBACtC;wBACD,IAAI,KAAK,KAAK,WAAW,EAAE;4BACzB,mBAAmB,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAA;yBAC7C;wBACD,OAAO,mBAAmB,CAAA;oBAC5B,CAAC,EACD,EAAE,CACH,CAAA;aACJ;YAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,QAAQ,EAAE;gBAC1D,GAAG,qBAAqB,CAAC,UAAU;gBACnC,GAAG,gBAAgB;aACpB,CAAC,CAAA;YACF,OAAO;gBACL,UAAU;gBACV,UAAU;gBACV,kBAAkB,EAAE,qBAAqB,CAAC,kBAAkB;aAC7D,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAC5B,CAAA;IAED,OAAO;QACL,uBAAuB;KACxB,CAAA;AACH,CAAC","sourcesContent":["import * as React from 'react'\nimport { formElementsService } from '@oneblink/sdk-core'\n\nimport generateDefaultData from '../services/generate-default-data'\nimport { FormTypes } from '@oneblink/types'\nimport { FormSubmissionModel, SetFormSubmission } from '../types/form'\n\nexport default function useLookups(\n formId: number,\n setFormSubmission: SetFormSubmission,\n) {\n const handlePagesLookupResult = React.useCallback(\n (\n element: FormTypes.LookupFormElement,\n elementLookupData: FormTypes.PageElement[],\n dataLookupResult?: FormSubmissionModel,\n ) => {\n const newPageElements = elementLookupData.map((e) => ({\n ...e,\n injectedByElementId: element.id,\n }))\n setFormSubmission((currentFormSubmission) => {\n const definition: FormTypes.Form = {\n ...currentFormSubmission.definition,\n isMultiPage: true,\n }\n if (!currentFormSubmission.definition.isMultiPage) {\n definition.elements = [\n {\n id: formId.toString(),\n type: 'page',\n label: 'Page 1',\n elements: currentFormSubmission.definition.elements,\n conditionallyShow: false,\n requiresAllConditionallyShowPredicates: false,\n },\n ...newPageElements,\n ]\n } else {\n const indexOfPage =\n currentFormSubmission.definition.elements.findIndex(\n (pageElement: FormTypes.FormElement) => {\n if (pageElement.type === 'page') {\n return formElementsService.findFormElement(\n pageElement.elements,\n (el) => el.id === element.id,\n )\n }\n },\n )\n if (indexOfPage === -1) {\n return currentFormSubmission\n }\n definition.elements =\n currentFormSubmission.definition.elements.reduce(\n (\n partialPageElements: FormTypes.FormElement[],\n pageElement: FormTypes.FormElement,\n index: number,\n ) => {\n // @ts-expect-error Sorry typescript, we need to add a property you don't approve of :(\n if (pageElement.injectedByElementId !== element.id) {\n partialPageElements.push(pageElement)\n }\n if (index === indexOfPage) {\n partialPageElements.push(...newPageElements)\n }\n return partialPageElements\n },\n [],\n )\n }\n\n const submission = generateDefaultData(definition.elements, {\n ...currentFormSubmission.submission,\n ...dataLookupResult,\n })\n return {\n submission,\n definition,\n lastElementUpdated: currentFormSubmission.lastElementUpdated,\n }\n })\n },\n [formId, setFormSubmission],\n )\n\n return {\n handlePagesLookupResult,\n }\n}\n"]}
1
+ {"version":3,"file":"useLookups.js","sourceRoot":"","sources":["../../src/hooks/useLookups.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAExD,OAAO,mBAAmB,MAAM,mCAAmC,CAAA;AAInE,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,MAAc,EACd,iBAAoC;IAEpC,MAAM,uBAAuB,GAAG,KAAK,CAAC,WAAW,CAC/C,CACE,OAAoC,EACpC,iBAA0C,EAC1C,gBAAiE,EACjE,EAAE;QACF,MAAM,eAAe,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC;YACJ,mBAAmB,EAAE,OAAO,CAAC,EAAE;SAChC,CAAC,CAAC,CAAA;QACH,iBAAiB,CAAC,CAAC,qBAAqB,EAAE,EAAE;YAC1C,MAAM,UAAU,GAAmB;gBACjC,GAAG,qBAAqB,CAAC,UAAU;gBACnC,WAAW,EAAE,IAAI;aAClB,CAAA;YACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,WAAW,EAAE;gBACjD,UAAU,CAAC,QAAQ,GAAG;oBACpB;wBACE,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE;wBACrB,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE,QAAQ;wBACf,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,QAAQ;wBACnD,iBAAiB,EAAE,KAAK;wBACxB,sCAAsC,EAAE,KAAK;qBAC9C;oBACD,GAAG,eAAe;iBACnB,CAAA;aACF;iBAAM;gBACL,MAAM,WAAW,GACf,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CACjD,CAAC,WAAkC,EAAE,EAAE;oBACrC,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,EAAE;wBAC/B,OAAO,mBAAmB,CAAC,eAAe,CACxC,WAAW,CAAC,QAAQ,EACpB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAC7B,CAAA;qBACF;gBACH,CAAC,CACF,CAAA;gBACH,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE;oBACtB,OAAO,qBAAqB,CAAA;iBAC7B;gBACD,UAAU,CAAC,QAAQ;oBACjB,qBAAqB,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAC9C,CACE,mBAA4C,EAC5C,WAAkC,EAClC,KAAa,EACb,EAAE;wBACF,uFAAuF;wBACvF,IAAI,WAAW,CAAC,mBAAmB,KAAK,OAAO,CAAC,EAAE,EAAE;4BAClD,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;yBACtC;wBACD,IAAI,KAAK,KAAK,WAAW,EAAE;4BACzB,mBAAmB,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAA;yBAC7C;wBACD,OAAO,mBAAmB,CAAA;oBAC5B,CAAC,EACD,EAAE,CACH,CAAA;aACJ;YAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,QAAQ,EAAE;gBAC1D,GAAG,qBAAqB,CAAC,UAAU;gBACnC,GAAG,gBAAgB;aACpB,CAAC,CAAA;YACF,OAAO;gBACL,UAAU;gBACV,UAAU;gBACV,kBAAkB,EAAE,qBAAqB,CAAC,kBAAkB;aAC7D,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,EACD,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAC5B,CAAA;IAED,OAAO;QACL,uBAAuB;KACxB,CAAA;AACH,CAAC","sourcesContent":["import * as React from 'react'\nimport { formElementsService } from '@oneblink/sdk-core'\n\nimport generateDefaultData from '../services/generate-default-data'\nimport { FormTypes, SubmissionTypes } from '@oneblink/types'\nimport { SetFormSubmission } from '../types/form'\n\nexport default function useLookups(\n formId: number,\n setFormSubmission: SetFormSubmission,\n) {\n const handlePagesLookupResult = React.useCallback(\n (\n element: FormTypes.LookupFormElement,\n elementLookupData: FormTypes.PageElement[],\n dataLookupResult?: SubmissionTypes.S3SubmissionData['submission'],\n ) => {\n const newPageElements = elementLookupData.map((e) => ({\n ...e,\n injectedByElementId: element.id,\n }))\n setFormSubmission((currentFormSubmission) => {\n const definition: FormTypes.Form = {\n ...currentFormSubmission.definition,\n isMultiPage: true,\n }\n if (!currentFormSubmission.definition.isMultiPage) {\n definition.elements = [\n {\n id: formId.toString(),\n type: 'page',\n label: 'Page 1',\n elements: currentFormSubmission.definition.elements,\n conditionallyShow: false,\n requiresAllConditionallyShowPredicates: false,\n },\n ...newPageElements,\n ]\n } else {\n const indexOfPage =\n currentFormSubmission.definition.elements.findIndex(\n (pageElement: FormTypes.FormElement) => {\n if (pageElement.type === 'page') {\n return formElementsService.findFormElement(\n pageElement.elements,\n (el) => el.id === element.id,\n )\n }\n },\n )\n if (indexOfPage === -1) {\n return currentFormSubmission\n }\n definition.elements =\n currentFormSubmission.definition.elements.reduce(\n (\n partialPageElements: FormTypes.FormElement[],\n pageElement: FormTypes.FormElement,\n index: number,\n ) => {\n // @ts-expect-error Sorry typescript, we need to add a property you don't approve of :(\n if (pageElement.injectedByElementId !== element.id) {\n partialPageElements.push(pageElement)\n }\n if (index === indexOfPage) {\n partialPageElements.push(...newPageElements)\n }\n return partialPageElements\n },\n [],\n )\n }\n\n const submission = generateDefaultData(definition.elements, {\n ...currentFormSubmission.submission,\n ...dataLookupResult,\n })\n return {\n submission,\n definition,\n lastElementUpdated: currentFormSubmission.lastElementUpdated,\n }\n })\n },\n [formId, setFormSubmission],\n )\n\n return {\n handlePagesLookupResult,\n }\n}\n"]}
@@ -1,2 +1,47 @@
1
1
  import * as React from 'react';
2
- export default function useNullableState<T>(defaultValue: T | null): [T | null, React.Dispatch<React.SetStateAction<T | null>>, () => void];
2
+ /**
3
+ * This function is a react hook for state of type of your choosing. It comes
4
+ * with two memoized functions, one for setting state and one for clearing it.
5
+ *
6
+ * The items returned in the array can be destructured and named whatever you
7
+ * like:
8
+ *
9
+ * ```js
10
+ * import { useNullableState } from '@oneblink/apps-react'
11
+ *
12
+ * const startingProfile = {
13
+ * name: 'Forest Gump',
14
+ * profession: 'Military, Athlete, Other',
15
+ * }
16
+ *
17
+ * const [userProfile, setUserProfile, unsetUserProfile] =
18
+ * useBooleanState(startingProfile)
19
+ * ```
20
+ *
21
+ * `setUserProfile` can then be called with an object of type `T` like:
22
+ *
23
+ * ```js
24
+ * setUserProfile({
25
+ * name: 'Walter White',
26
+ * profession: 'Chemistry Teacher (Secondary School), Other',
27
+ * })
28
+ * ```
29
+ *
30
+ * And `unsetUserProfile` can be called like:
31
+ *
32
+ * ```js
33
+ * unsetUserProfile()
34
+ * ```
35
+ *
36
+ * @typeParam T The type of the state
37
+ * @param defaultValue
38
+ * @returns
39
+ * @group Hooks
40
+ */
41
+ export default function useNullableState<T>(
42
+ /** The starting state for the hook. */
43
+ defaultValue: T | null): [
44
+ state: T | null,
45
+ setState: React.Dispatch<React.SetStateAction<T | null>>,
46
+ clearState: () => void
47
+ ];
@@ -1,5 +1,46 @@
1
1
  import * as React from 'react';
2
- export default function useNullableState(defaultValue) {
2
+ /**
3
+ * This function is a react hook for state of type of your choosing. It comes
4
+ * with two memoized functions, one for setting state and one for clearing it.
5
+ *
6
+ * The items returned in the array can be destructured and named whatever you
7
+ * like:
8
+ *
9
+ * ```js
10
+ * import { useNullableState } from '@oneblink/apps-react'
11
+ *
12
+ * const startingProfile = {
13
+ * name: 'Forest Gump',
14
+ * profession: 'Military, Athlete, Other',
15
+ * }
16
+ *
17
+ * const [userProfile, setUserProfile, unsetUserProfile] =
18
+ * useBooleanState(startingProfile)
19
+ * ```
20
+ *
21
+ * `setUserProfile` can then be called with an object of type `T` like:
22
+ *
23
+ * ```js
24
+ * setUserProfile({
25
+ * name: 'Walter White',
26
+ * profession: 'Chemistry Teacher (Secondary School), Other',
27
+ * })
28
+ * ```
29
+ *
30
+ * And `unsetUserProfile` can be called like:
31
+ *
32
+ * ```js
33
+ * unsetUserProfile()
34
+ * ```
35
+ *
36
+ * @typeParam T The type of the state
37
+ * @param defaultValue
38
+ * @returns
39
+ * @group Hooks
40
+ */
41
+ export default function useNullableState(
42
+ /** The starting state for the hook. */
43
+ defaultValue) {
3
44
  const [state, setState] = React.useState(defaultValue);
4
45
  const unsetState = React.useCallback(() => setState(null), []);
5
46
  return [state, setState, unsetState];