hazo_auth 5.1.19 → 5.1.21
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/components/layouts/create_firm/hooks/use_create_firm_form.d.ts +6 -0
- package/dist/components/layouts/create_firm/hooks/use_create_firm_form.d.ts.map +1 -1
- package/dist/components/layouts/create_firm/hooks/use_create_firm_form.js +80 -2
- package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
- package/dist/components/layouts/create_firm/index.js +6 -1
- package/package.json +1 -1
|
@@ -27,6 +27,12 @@ export type UseCreateFirmFormResult = {
|
|
|
27
27
|
isSubmitDisabled: boolean;
|
|
28
28
|
handleFieldChange: (field: keyof CreateFirmFormValues, value: string) => void;
|
|
29
29
|
handleSubmit: (e: FormEvent) => Promise<void>;
|
|
30
|
+
/** Ref to attach to firm_name input for DOM value sync */
|
|
31
|
+
firmNameRef: React.RefObject<HTMLInputElement>;
|
|
32
|
+
/** Ref to attach to org_structure input for DOM value sync */
|
|
33
|
+
orgStructureRef: React.RefObject<HTMLInputElement>;
|
|
34
|
+
/** Sync React state from DOM values (call on autofill detection) */
|
|
35
|
+
syncFromDOM: () => void;
|
|
30
36
|
};
|
|
31
37
|
export declare function use_create_firm_form(options?: UseCreateFirmFormOptions): UseCreateFirmFormResult;
|
|
32
38
|
//# sourceMappingURL=use_create_firm_form.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_create_firm_form.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/create_firm/hooks/use_create_firm_form.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"use_create_firm_form.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/create_firm/hooks/use_create_firm_form.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqD,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,oBAAoB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9E,YAAY,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,0DAA0D;IAC1D,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC/C,8DAA8D;IAC9D,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACnD,oEAAoE;IACpE,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAGF,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,wBAA6B,GACrC,uBAAuB,CAmNzB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// file_description: hook for managing create firm form state and submission
|
|
2
2
|
"use client";
|
|
3
3
|
// section: imports
|
|
4
|
-
import { useState, useCallback } from "react";
|
|
4
|
+
import { useState, useCallback, useRef, useEffect, useMemo } from "react";
|
|
5
5
|
// section: hook
|
|
6
6
|
export function use_create_firm_form(options = {}) {
|
|
7
7
|
const { default_org_structure = "Headquarters", onSuccess, redirectRoute = "/", apiBasePath = "/api/hazo_auth", logger, } = options;
|
|
@@ -12,6 +12,62 @@ export function use_create_firm_form(options = {}) {
|
|
|
12
12
|
const [errors, setErrors] = useState({});
|
|
13
13
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
14
14
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
15
|
+
// Refs for DOM value sync (handles browser autocomplete, password managers, etc.)
|
|
16
|
+
const firmNameRef = useRef(null);
|
|
17
|
+
const orgStructureRef = useRef(null);
|
|
18
|
+
// Counter to force re-evaluation of isSubmitDisabled after sync
|
|
19
|
+
const [syncCounter, setSyncCounter] = useState(0);
|
|
20
|
+
// Sync React state from DOM values (call when autofill detected or on focus)
|
|
21
|
+
const syncFromDOM = useCallback(() => {
|
|
22
|
+
let didSync = false;
|
|
23
|
+
if (firmNameRef.current) {
|
|
24
|
+
const domValue = firmNameRef.current.value;
|
|
25
|
+
if (domValue !== values.firm_name) {
|
|
26
|
+
setValues((prev) => (Object.assign(Object.assign({}, prev), { firm_name: domValue })));
|
|
27
|
+
didSync = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (orgStructureRef.current) {
|
|
31
|
+
const domValue = orgStructureRef.current.value;
|
|
32
|
+
if (domValue !== values.org_structure) {
|
|
33
|
+
setValues((prev) => (Object.assign(Object.assign({}, prev), { org_structure: domValue })));
|
|
34
|
+
didSync = true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Force re-evaluation even if React state didn't change (DOM might have)
|
|
38
|
+
if (didSync) {
|
|
39
|
+
setSyncCounter((c) => c + 1);
|
|
40
|
+
}
|
|
41
|
+
}, [values.firm_name, values.org_structure]);
|
|
42
|
+
// Effect to detect browser autofill via animationstart event
|
|
43
|
+
// Chrome triggers animationstart on autofilled inputs if CSS animation is defined
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const handleAutofill = (e) => {
|
|
46
|
+
if (e.animationName === "onAutoFillStart") {
|
|
47
|
+
// Delay to allow browser to populate the value
|
|
48
|
+
setTimeout(syncFromDOM, 50);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const firmNameInput = firmNameRef.current;
|
|
52
|
+
const orgStructureInput = orgStructureRef.current;
|
|
53
|
+
firmNameInput === null || firmNameInput === void 0 ? void 0 : firmNameInput.addEventListener("animationstart", handleAutofill);
|
|
54
|
+
orgStructureInput === null || orgStructureInput === void 0 ? void 0 : orgStructureInput.addEventListener("animationstart", handleAutofill);
|
|
55
|
+
// Also sync on focus (catches form restoration, manual paste, etc.)
|
|
56
|
+
const handleFocus = () => {
|
|
57
|
+
// Small delay to let browser complete any pending value changes
|
|
58
|
+
setTimeout(syncFromDOM, 10);
|
|
59
|
+
};
|
|
60
|
+
firmNameInput === null || firmNameInput === void 0 ? void 0 : firmNameInput.addEventListener("focus", handleFocus);
|
|
61
|
+
orgStructureInput === null || orgStructureInput === void 0 ? void 0 : orgStructureInput.addEventListener("focus", handleFocus);
|
|
62
|
+
// Initial sync after mount (catches pre-populated values)
|
|
63
|
+
setTimeout(syncFromDOM, 100);
|
|
64
|
+
return () => {
|
|
65
|
+
firmNameInput === null || firmNameInput === void 0 ? void 0 : firmNameInput.removeEventListener("animationstart", handleAutofill);
|
|
66
|
+
orgStructureInput === null || orgStructureInput === void 0 ? void 0 : orgStructureInput.removeEventListener("animationstart", handleAutofill);
|
|
67
|
+
firmNameInput === null || firmNameInput === void 0 ? void 0 : firmNameInput.removeEventListener("focus", handleFocus);
|
|
68
|
+
orgStructureInput === null || orgStructureInput === void 0 ? void 0 : orgStructureInput.removeEventListener("focus", handleFocus);
|
|
69
|
+
};
|
|
70
|
+
}, [syncFromDOM]);
|
|
15
71
|
const handleFieldChange = useCallback((field, value) => {
|
|
16
72
|
setValues((prev) => (Object.assign(Object.assign({}, prev), { [field]: value })));
|
|
17
73
|
// Clear field error when user starts typing
|
|
@@ -86,7 +142,26 @@ export function use_create_firm_form(options = {}) {
|
|
|
86
142
|
setIsSubmitting(false);
|
|
87
143
|
}
|
|
88
144
|
}, [values, validateForm, onSuccess, redirectRoute, apiBasePath, logger]);
|
|
89
|
-
|
|
145
|
+
// Calculate disabled state using both React state AND refs as fallback
|
|
146
|
+
// This handles cases where DOM is populated but React state hasn't caught up
|
|
147
|
+
// (browser autocomplete, password managers, form restoration, etc.)
|
|
148
|
+
const isSubmitDisabled = useMemo(() => {
|
|
149
|
+
var _a, _b, _c, _d;
|
|
150
|
+
if (isSubmitting)
|
|
151
|
+
return true;
|
|
152
|
+
// Check React state first
|
|
153
|
+
const firmNameFromState = values.firm_name.trim();
|
|
154
|
+
const orgStructureFromState = values.org_structure.trim();
|
|
155
|
+
// Also check DOM refs as fallback (may have values React doesn't know about)
|
|
156
|
+
const firmNameFromDom = ((_b = (_a = firmNameRef.current) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.trim()) || "";
|
|
157
|
+
const orgStructureFromDom = ((_d = (_c = orgStructureRef.current) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.trim()) || "";
|
|
158
|
+
// Use whichever has a value (prefer state, fall back to DOM)
|
|
159
|
+
const effectiveFirmName = firmNameFromState || firmNameFromDom;
|
|
160
|
+
const effectiveOrgStructure = orgStructureFromState || orgStructureFromDom;
|
|
161
|
+
return !effectiveFirmName || !effectiveOrgStructure;
|
|
162
|
+
// syncCounter included to force re-evaluation after DOM sync
|
|
163
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
164
|
+
}, [isSubmitting, values.firm_name, values.org_structure, syncCounter]);
|
|
90
165
|
return {
|
|
91
166
|
values,
|
|
92
167
|
errors,
|
|
@@ -95,5 +170,8 @@ export function use_create_firm_form(options = {}) {
|
|
|
95
170
|
isSubmitDisabled,
|
|
96
171
|
handleFieldChange,
|
|
97
172
|
handleSubmit,
|
|
173
|
+
firmNameRef,
|
|
174
|
+
orgStructureRef,
|
|
175
|
+
syncFromDOM,
|
|
98
176
|
};
|
|
99
177
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,EACL,KAAK,sBAAsB,EAC5B,MAAM,uCAAuC,CAAC;AAQ/C,MAAM,MAAM,qBAAqB,GAAG;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oCAAoC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,2BAA2B;IAC3B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,SAAS,EACT,SAA8B,EAC9B,sBAAkC,EAClC,OAA4B,EAC5B,WAAuD,EACvD,eAA6B,EAC7B,qBAA8C,EAC9C,mBAA8C,EAC9C,yBAA6D,EAC7D,qBAAsC,EACtC,mBAAmC,EACnC,eAA4D,EAC5D,cAAoB,EACpB,WAAW,EACX,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE,qBAAqB,2CAoJvB;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -28,7 +28,12 @@ export default function CreateFirmLayout({ image_src, image_alt = "Create your f
|
|
|
28
28
|
cancelText: (button_colors === null || button_colors === void 0 ? void 0 : button_colors.cancelText) || "text-gray-700",
|
|
29
29
|
};
|
|
30
30
|
const renderFields = (formState) => {
|
|
31
|
-
|
|
31
|
+
// Handler that works with both onChange and onInput events
|
|
32
|
+
const handleInput = (field, e) => {
|
|
33
|
+
const value = e.target.value;
|
|
34
|
+
formState.handleFieldChange(field, value);
|
|
35
|
+
};
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsx(FormFieldWrapper, { fieldId: "firm_name", label: firm_name_label, input: _jsx(Input, { id: "firm_name", ref: formState.firmNameRef, type: "text", value: formState.values.firm_name, onChange: (e) => handleInput("firm_name", e), onInput: (e) => handleInput("firm_name", e), placeholder: firm_name_placeholder, "aria-label": firm_name_label, className: "cls_create_firm_layout_field_input hazo-autofill-detect", autoComplete: "organization" }), errorMessage: formState.errors.firm_name }), _jsx(FormFieldWrapper, { fieldId: "org_structure", label: org_structure_label, input: _jsx(Input, { id: "org_structure", ref: formState.orgStructureRef, type: "text", value: formState.values.org_structure, onChange: (e) => handleInput("org_structure", e), onInput: (e) => handleInput("org_structure", e), placeholder: org_structure_placeholder, "aria-label": org_structure_label, className: "cls_create_firm_layout_field_input hazo-autofill-detect" }), errorMessage: formState.errors.org_structure })] }));
|
|
32
37
|
};
|
|
33
38
|
// Show success message after firm creation
|
|
34
39
|
if (form.isSuccess) {
|
package/package.json
CHANGED