@proveanything/smartlinks-auth-ui 0.4.0 → 0.4.3
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/SchemaFieldRenderer.d.ts +6 -3
- package/dist/components/SchemaFieldRenderer.d.ts.map +1 -1
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/context/AuthContext.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +278 -68
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +279 -71
- package/dist/index.js.map +1 -1
- package/dist/utils/errorHandling.d.ts +5 -4
- package/dist/utils/errorHandling.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { ContactSchemaResponse, ContactSchemaProperty, ContactUiSchemaEntry } from '@proveanything/smartlinks';
|
|
3
|
-
import { evaluateConditions } from '@proveanything/smartlinks';
|
|
2
|
+
import type { ContactSchemaResponse, ContactSchemaProperty, ContactUiSchemaEntry, FieldCondition } from '@proveanything/smartlinks';
|
|
4
3
|
export type { ContactSchemaResponse, ContactSchemaProperty, ContactUiSchemaEntry };
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Evaluate whether a field's conditions are satisfied given current form values.
|
|
6
|
+
* Local implementation matching SDK's evaluateConditions — avoids Vite ESM export issues.
|
|
7
|
+
*/
|
|
8
|
+
export declare const evaluateConditions: (conditions: FieldCondition[] | undefined, showWhen: "all" | "any" | undefined, fieldValues: Record<string, unknown>) => boolean;
|
|
6
9
|
/**
|
|
7
10
|
* Configuration for which fields to show during registration.
|
|
8
11
|
* Stored in AuthKit config.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaFieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/SchemaFieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SchemaFieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/SchemaFieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACf,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,CAAC;AAEnF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,cAAc,EAAE,GAAG,SAAS,EACxC,UAAU,KAAK,GAAG,KAAK,GAAG,SAAS,EACnC,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,OA0CF,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,sBAAsB,EAAE,OAAO,CAAC;IAChC,SAAS,EAAE,QAAQ,GAAG,kBAAkB,CAAC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,qBAAqB,CAAC;IAChC,EAAE,EAAE,oBAAoB,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,wBAAwB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA+OlE,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,qBAAqB,GAAG,IAAI,EACpC,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,aAAa,EAqBf,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,qBAAqB,GAAG,IAAI,EACpC,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,aAAa,EAIf,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,qBAAqB,GAAG,IAAI,EACpC,oBAAoB,uBAAuB,EAAE,EAC7C,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,aAAa,EA0Bf,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,aAAa,EAAE,EACvB,oBAAoB,uBAAuB,EAAE,KAC5C;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,eAAe,EAAE,aAAa,EAAE,CAAA;CAgB7D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAY5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;AA8I7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CAmCjD,CAAC;AAwEF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAK/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAY5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;AA8I7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CAmCjD,CAAC;AAwEF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAK/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA0sD5D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAOnG,OAAO,KAAK,EAAqC,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGvG,eAAO,MAAM,WAAW,6CAAyD,CAAC;AAGlF,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAOnG,OAAO,KAAK,EAAqC,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGvG,eAAO,MAAM,WAAW,6CAAyD,CAAC;AAGlF,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA81BpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { tokenStorage } from './utils/tokenStorage';
|
|
|
8
8
|
export { AuthUIPreview } from './components/AuthUIPreview';
|
|
9
9
|
export { getDefaultAuthKitId, setDefaultAuthKitId } from './utils/defaultAuthKit';
|
|
10
10
|
export { getFriendlyErrorMessage, isConflictError, isAuthError, isRateLimitError, isServerError, getErrorStatusCode, getErrorCode } from './utils/errorHandling';
|
|
11
|
-
export { SchemaFieldRenderer, getEditableFields, getRegistrationFields, sortFieldsByPlacement, resolveFields
|
|
11
|
+
export { SchemaFieldRenderer, evaluateConditions, getEditableFields, getRegistrationFields, sortFieldsByPlacement, resolveFields } from './components/SchemaFieldRenderer';
|
|
12
12
|
export type { ResolvedField, RegistrationFieldConfig } from './components/SchemaFieldRenderer';
|
|
13
13
|
export type { ContactSchemaResponse, ContactSchemaProperty, ContactUiSchemaEntry } from '@proveanything/smartlinks';
|
|
14
14
|
/** @deprecated Use ResolvedField instead */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EACL,eAAe,EAEf,gBAAgB,EAChB,cAAc,EAEd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,aAAa,GACd,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGlF,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,YAAY,EACb,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EACL,eAAe,EAEf,gBAAgB,EAChB,cAAc,EAEd,iBAAiB,EACjB,eAAe,EACf,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,aAAa,GACd,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAGlF,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,YAAY,EACb,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAC3K,YAAY,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAE/F,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACpH,4CAA4C;AAC5C,YAAY,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACrF,mFAAmF;AACnF,YAAY,EAAE,qBAAqB,IAAI,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAGxF,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,EACZ,aAAa,GACd,MAAM,wBAAwB,CAAC;AAGhC,mBAAmB,SAAS,CAAC;AAC7B,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG5E,OAAO,EAAE,gBAAgB,IAAI,cAAc,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import React, { useEffect, useState, useMemo, useRef, useCallback, createContext, useContext } from 'react';
|
|
3
3
|
import * as smartlinks from '@proveanything/smartlinks';
|
|
4
|
-
import {
|
|
5
|
-
export { evaluateConditions } from '@proveanything/smartlinks';
|
|
4
|
+
import { iframe, SmartlinksApiError } from '@proveanything/smartlinks';
|
|
6
5
|
import { post, getApiHeaders, isProxyEnabled } from '@proveanything/smartlinks/dist/http';
|
|
7
6
|
|
|
8
7
|
const AuthContainer = ({ children, theme = 'light', className = '', config, minimal = false, }) => {
|
|
@@ -60,6 +59,52 @@ const AuthContainer = ({ children, theme = 'light', className = '', config, mini
|
|
|
60
59
|
return (jsx("div", { className: containerClass, children: jsxs("div", { className: cardClass, style: !minimal && config?.branding?.buttonStyle === 'square' ? { borderRadius: '4px' } : undefined, children: [(logoUrl || title || subtitle) && (jsxs("div", { className: "auth-header", children: [logoUrl && (jsx("div", { className: "auth-logo", children: jsx("img", { src: logoUrl, alt: "Logo", style: { maxWidth: '200px', height: 'auto', objectFit: 'contain' } }) })), title && jsx("h1", { className: "auth-title", children: title }), subtitle && jsx("p", { className: "auth-subtitle", children: subtitle })] })), jsx("div", { className: "auth-content", children: children }), (config?.branding?.termsUrl || config?.branding?.privacyUrl) && (jsxs("div", { className: "auth-footer", children: [config.branding.termsUrl && jsx("a", { href: config.branding.termsUrl, target: "_blank", rel: "noopener noreferrer", children: "Terms" }), config.branding.termsUrl && config.branding.privacyUrl && jsx("span", { children: "\u2022" }), config.branding.privacyUrl && jsx("a", { href: config.branding.privacyUrl, target: "_blank", rel: "noopener noreferrer", children: "Privacy" })] }))] }) }));
|
|
61
60
|
};
|
|
62
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Evaluate whether a field's conditions are satisfied given current form values.
|
|
64
|
+
* Local implementation matching SDK's evaluateConditions — avoids Vite ESM export issues.
|
|
65
|
+
*/
|
|
66
|
+
const evaluateConditions = (conditions, showWhen, fieldValues) => {
|
|
67
|
+
if (!conditions || conditions.length === 0)
|
|
68
|
+
return true;
|
|
69
|
+
const results = conditions.map(condition => {
|
|
70
|
+
const value = fieldValues[condition.targetFieldId];
|
|
71
|
+
switch (condition.operator) {
|
|
72
|
+
case 'is_empty':
|
|
73
|
+
return value == null || value === '' || (Array.isArray(value) && value.length === 0);
|
|
74
|
+
case 'is_not_empty':
|
|
75
|
+
return value != null && value !== '' && !(Array.isArray(value) && value.length === 0);
|
|
76
|
+
case 'is_true':
|
|
77
|
+
return value === true;
|
|
78
|
+
case 'is_false':
|
|
79
|
+
return value === false;
|
|
80
|
+
case 'equals':
|
|
81
|
+
return value === condition.value;
|
|
82
|
+
case 'not_equals':
|
|
83
|
+
return value !== condition.value;
|
|
84
|
+
case 'contains':
|
|
85
|
+
return Array.isArray(value)
|
|
86
|
+
? value.includes(condition.value)
|
|
87
|
+
: typeof value === 'string' && value.includes(String(condition.value));
|
|
88
|
+
case 'not_contains':
|
|
89
|
+
return Array.isArray(value)
|
|
90
|
+
? !value.includes(condition.value)
|
|
91
|
+
: typeof value === 'string' && !value.includes(String(condition.value));
|
|
92
|
+
case 'greater_than':
|
|
93
|
+
return typeof value === 'number' && typeof condition.value === 'number'
|
|
94
|
+
? value > condition.value
|
|
95
|
+
: String(value) > String(condition.value);
|
|
96
|
+
case 'less_than':
|
|
97
|
+
return typeof value === 'number' && typeof condition.value === 'number'
|
|
98
|
+
? value < condition.value
|
|
99
|
+
: String(value) < String(condition.value);
|
|
100
|
+
default:
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return (showWhen ?? 'all') === 'any'
|
|
105
|
+
? results.some(Boolean)
|
|
106
|
+
: results.every(Boolean);
|
|
107
|
+
};
|
|
63
108
|
/**
|
|
64
109
|
* Renders a form field based on a ContactSchemaResponse property + uiSchema entry.
|
|
65
110
|
*/
|
|
@@ -130,10 +175,13 @@ const SchemaFieldRenderer = ({ field, value, onChange, disabled = false, error,
|
|
|
130
175
|
const resolveFields = (schema, formValues) => {
|
|
131
176
|
if (!schema)
|
|
132
177
|
return [];
|
|
133
|
-
const
|
|
134
|
-
|
|
178
|
+
const fieldOrder = schema.fieldOrder ?? [];
|
|
179
|
+
const properties = schema.schema?.properties ?? {};
|
|
180
|
+
const uiSchema = schema.uiSchema ?? {};
|
|
181
|
+
const requiredSet = new Set(schema.schema?.required || []);
|
|
182
|
+
return fieldOrder
|
|
135
183
|
.filter(fieldId => {
|
|
136
|
-
const prop =
|
|
184
|
+
const prop = properties[fieldId];
|
|
137
185
|
if (!prop)
|
|
138
186
|
return false;
|
|
139
187
|
// Evaluate conditional visibility
|
|
@@ -141,8 +189,8 @@ const resolveFields = (schema, formValues) => {
|
|
|
141
189
|
})
|
|
142
190
|
.map(fieldId => ({
|
|
143
191
|
key: fieldId,
|
|
144
|
-
property:
|
|
145
|
-
ui:
|
|
192
|
+
property: properties[fieldId],
|
|
193
|
+
ui: uiSchema[fieldId] || {},
|
|
146
194
|
required: requiredSet.has(fieldId),
|
|
147
195
|
}));
|
|
148
196
|
};
|
|
@@ -159,13 +207,16 @@ const getRegistrationFields = (schema, registrationConfig, formValues) => {
|
|
|
159
207
|
if (!schema || !registrationConfig.length)
|
|
160
208
|
return [];
|
|
161
209
|
const configMap = new Map(registrationConfig.map(c => [c.key, c]));
|
|
162
|
-
const
|
|
163
|
-
|
|
210
|
+
const fieldOrder = schema.fieldOrder ?? [];
|
|
211
|
+
const properties = schema.schema?.properties ?? {};
|
|
212
|
+
const uiSchema = schema.uiSchema ?? {};
|
|
213
|
+
const requiredSet = new Set(schema.schema?.required || []);
|
|
214
|
+
return fieldOrder
|
|
164
215
|
.filter(fieldId => {
|
|
165
216
|
const config = configMap.get(fieldId);
|
|
166
217
|
if (!config?.showDuringRegistration)
|
|
167
218
|
return false;
|
|
168
|
-
const prop =
|
|
219
|
+
const prop = properties[fieldId];
|
|
169
220
|
if (!prop)
|
|
170
221
|
return false;
|
|
171
222
|
return evaluateConditions(prop.conditions, prop.showWhen, formValues || {});
|
|
@@ -174,8 +225,8 @@ const getRegistrationFields = (schema, registrationConfig, formValues) => {
|
|
|
174
225
|
const config = configMap.get(fieldId);
|
|
175
226
|
return {
|
|
176
227
|
key: fieldId,
|
|
177
|
-
property:
|
|
178
|
-
ui:
|
|
228
|
+
property: properties[fieldId],
|
|
229
|
+
ui: uiSchema[fieldId] || {},
|
|
179
230
|
required: config.required ?? requiredSet.has(fieldId),
|
|
180
231
|
};
|
|
181
232
|
});
|
|
@@ -263,7 +314,7 @@ const EmailAuthForm = ({ mode, onSubmit, onModeSwitch, onForgotPassword, loading
|
|
|
263
314
|
if (newMode !== mode) {
|
|
264
315
|
onModeSwitch();
|
|
265
316
|
}
|
|
266
|
-
}, disabled: loading })), jsxs("div", { className: "auth-form-header", children: [jsx("h2", { className: "auth-form-title", children: title }), jsx("p", { className: "auth-form-subtitle", children: subtitle })] }), error && (jsxs("div", { className: "auth-error", role: "alert", children: [jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error] })), mode === 'register' && (jsxs("div", { className: "auth-form-group", children: [jsx("label", { htmlFor: "displayName", className: "auth-label", children: "Full Name" }), jsx("input", { type: "text", id: "displayName", className: "auth-input", value: formData.displayName || '', onChange: (e) => handleChange('displayName', e.target.value), required: mode === 'register', disabled: loading, placeholder: "John
|
|
317
|
+
}, disabled: loading })), jsxs("div", { className: "auth-form-header", children: [jsx("h2", { className: "auth-form-title", children: title }), jsx("p", { className: "auth-form-subtitle", children: subtitle })] }), error && (jsxs("div", { className: "auth-error", role: "alert", children: [jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error] })), mode === 'register' && (jsxs("div", { className: "auth-form-group", children: [jsx("label", { htmlFor: "displayName", className: "auth-label", children: "Full Name" }), jsx("input", { type: "text", id: "displayName", className: "auth-input", value: formData.displayName || '', onChange: (e) => handleChange('displayName', e.target.value), required: mode === 'register', disabled: loading, placeholder: "John Smith" })] })), jsxs("div", { className: "auth-form-group", children: [jsx("label", { htmlFor: "email", className: "auth-label", children: "Email address" }), jsx("input", { type: "email", id: "email", className: "auth-input", value: formData.email || '', onChange: (e) => handleChange('email', e.target.value), required: true, disabled: loading, placeholder: "you@example.com", autoComplete: "email" })] }), jsxs("div", { className: "auth-form-group", children: [jsx("label", { htmlFor: "password", className: "auth-label", children: "Password" }), jsx("input", { type: "password", id: "password", className: "auth-input", value: formData.password || '', onChange: (e) => handleChange('password', e.target.value), required: true, disabled: loading, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", autoComplete: mode === 'login' ? 'current-password' : 'new-password', minLength: 6 })] }), mode === 'register' && hasSchemaFields && schemaFields.inline.map(renderSchemaField), mode === 'register' && hasLegacyFields && additionalFields.map(renderLegacyField), mode === 'register' && hasSchemaFields && schemaFields.postCredentials.length > 0 && (jsxs(Fragment, { children: [jsx("div", { className: "auth-divider", style: { margin: '16px 0' }, children: jsx("span", { children: "Additional Information" }) }), schemaFields.postCredentials.map(renderSchemaField)] })), mode === 'login' && (jsx("div", { className: "auth-form-footer", children: jsx("button", { type: "button", className: "auth-link", onClick: onForgotPassword, disabled: loading, children: "Forgot password?" }) })), jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? (jsx("span", { className: "auth-spinner" })) : mode === 'login' ? ('Sign in') : ('Create account') }), signupProminence !== 'balanced' && (jsxs("div", { className: "auth-divider", children: [jsx("span", { children: mode === 'login' ? "Don't have an account?" : 'Already have an account?' }), jsx("button", { type: "button", className: "auth-link auth-link-bold", onClick: onModeSwitch, disabled: loading, children: mode === 'login' ? 'Sign up' : 'Sign in' })] }))] }));
|
|
267
318
|
};
|
|
268
319
|
|
|
269
320
|
const ProviderButtons = ({ enabledProviders, providerOrder, onEmailLogin, onGoogleLogin, onPhoneLogin, onMagicLinkLogin, loading, }) => {
|
|
@@ -11681,15 +11732,27 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
|
|
|
11681
11732
|
const headers = getApiHeaders();
|
|
11682
11733
|
const hasBearer = !!headers['Authorization'];
|
|
11683
11734
|
const hasSdkProxy = isProxyEnabled();
|
|
11735
|
+
console.log('[AuthContext] 🔍 Proxy mode init:', {
|
|
11736
|
+
hasBearer,
|
|
11737
|
+
hasSdkProxy,
|
|
11738
|
+
authHeader: headers['Authorization'] ? `${headers['Authorization'].substring(0, 20)}...` : '(none)',
|
|
11739
|
+
willCallGetAccount: hasBearer || hasSdkProxy,
|
|
11740
|
+
});
|
|
11684
11741
|
if (!hasBearer && !hasSdkProxy) {
|
|
11685
|
-
console.
|
|
11742
|
+
console.log('[AuthContext] ⏭️ Skipping getAccount - no bearer token and SDK proxy not enabled');
|
|
11686
11743
|
// Fall through to "no valid session" state
|
|
11687
11744
|
}
|
|
11688
11745
|
else {
|
|
11746
|
+
console.log('[AuthContext] 📡 Calling auth.getAccount() via', hasSdkProxy ? 'proxy' : 'bearer');
|
|
11689
11747
|
try {
|
|
11690
11748
|
const accountResponse = await smartlinks.auth.getAccount();
|
|
11691
11749
|
const accountAny = accountResponse;
|
|
11692
11750
|
const hasValidSession = accountAny?.uid && accountAny.uid.length > 0;
|
|
11751
|
+
console.log('[AuthContext] 📋 getAccount response:', {
|
|
11752
|
+
hasValidSession,
|
|
11753
|
+
uid: accountAny?.uid || '(none)',
|
|
11754
|
+
email: accountAny?.email || '(none)',
|
|
11755
|
+
});
|
|
11693
11756
|
if (hasValidSession && isMounted) {
|
|
11694
11757
|
const userFromAccount = {
|
|
11695
11758
|
uid: accountAny.uid,
|
|
@@ -11706,10 +11769,11 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
|
|
|
11706
11769
|
syncContactRef.current?.(userFromAccount, accountResponse);
|
|
11707
11770
|
}
|
|
11708
11771
|
else if (isMounted) {
|
|
11709
|
-
|
|
11772
|
+
console.log('[AuthContext] ℹ️ No valid session found via proxy');
|
|
11710
11773
|
}
|
|
11711
11774
|
}
|
|
11712
11775
|
catch (error) {
|
|
11776
|
+
console.warn('[AuthContext] ❌ getAccount() failed:', error);
|
|
11713
11777
|
// auth.getAccount() failed, awaiting login
|
|
11714
11778
|
}
|
|
11715
11779
|
} // end else (has credentials)
|
|
@@ -12218,7 +12282,6 @@ const useAuth = () => {
|
|
|
12218
12282
|
|
|
12219
12283
|
/**
|
|
12220
12284
|
* Friendly error messages for common HTTP status codes.
|
|
12221
|
-
* Maps status codes to context-specific user-friendly messages.
|
|
12222
12285
|
*/
|
|
12223
12286
|
const STATUS_MESSAGES = {
|
|
12224
12287
|
400: 'Invalid request. Please check your input and try again.',
|
|
@@ -12230,41 +12293,103 @@ const STATUS_MESSAGES = {
|
|
|
12230
12293
|
};
|
|
12231
12294
|
/**
|
|
12232
12295
|
* Context-specific error messages for different auth operations.
|
|
12233
|
-
* Use `errorCode` from the SDK when available, otherwise fall back to status code.
|
|
12234
12296
|
*/
|
|
12235
12297
|
const ERROR_CODE_MESSAGES = {
|
|
12236
|
-
//
|
|
12298
|
+
// 400 - Validation errors
|
|
12299
|
+
'MISSING_FIELDS': 'Email and password are required.',
|
|
12300
|
+
'MISSING_EMAIL': 'Email is required.',
|
|
12301
|
+
'MISSING_PASSWORD': 'Password is required.',
|
|
12302
|
+
'MISSING_TOKEN': 'Token is required.',
|
|
12303
|
+
'MISSING_PHONE_NUMBER': 'Phone number is required.',
|
|
12304
|
+
'MISSING_VERIFICATION_CODE': 'Phone number and verification code are required.',
|
|
12305
|
+
'MISSING_REDIRECT_URL': 'Redirect URL is required.',
|
|
12306
|
+
'MISSING_GOOGLE_TOKEN': 'Google token is required.',
|
|
12307
|
+
'INVALID_CLIENT_ID': 'Invalid client configuration.',
|
|
12308
|
+
'INVALID_REDIRECT_URL': 'Invalid redirect URL.',
|
|
12309
|
+
'INVALID_PHONE_NUMBER': 'Invalid phone number. Please check the format and try again.',
|
|
12310
|
+
'INVALID_GOOGLE_TOKEN': 'Invalid Google sign-in token.',
|
|
12311
|
+
'PASSWORD_TOO_SHORT': 'Password must be at least 8 characters long.',
|
|
12312
|
+
'PASSWORD_REQUIREMENTS_NOT_MET': 'New password must be at least 6 characters.',
|
|
12313
|
+
'EMAIL_ALREADY_VERIFIED': 'Your email is already verified.',
|
|
12314
|
+
'INVALID_CONFIRMATION': 'Please type DELETE to confirm account deletion.',
|
|
12315
|
+
// 401 - Authentication errors
|
|
12237
12316
|
'INVALID_CREDENTIALS': 'Invalid email or password.',
|
|
12238
|
-
'
|
|
12317
|
+
'INCORRECT_PASSWORD': 'Current password is incorrect.',
|
|
12318
|
+
'INVALID_VERIFICATION_CODE': 'Invalid or expired verification code. Please try again.',
|
|
12319
|
+
'INVALID_TOKEN': 'This link has expired or is invalid. Please request a new one.',
|
|
12320
|
+
'TOKEN_EXPIRED': 'This link has expired. Please request a new one.',
|
|
12321
|
+
'TOKEN_ALREADY_USED': 'This link has already been used. Please request a new one.',
|
|
12322
|
+
'UNAUTHORIZED': 'You must be logged in to perform this action.',
|
|
12323
|
+
'GOOGLE_TOKEN_AUDIENCE_MISMATCH': 'Google sign-in failed. Token was not issued for this application.',
|
|
12324
|
+
// 403 - Forbidden / verification required
|
|
12239
12325
|
'EMAIL_NOT_VERIFIED': 'Please verify your email before signing in.',
|
|
12240
|
-
'ACCOUNT_LOCKED': 'Your account has been locked. Please
|
|
12326
|
+
'ACCOUNT_LOCKED': 'Your account has been locked. Please verify your email to unlock.',
|
|
12327
|
+
'EMAIL_VERIFICATION_EXPIRED': 'Your verification deadline has passed and your account is locked. Please contact support.',
|
|
12328
|
+
// 404
|
|
12329
|
+
'USER_NOT_FOUND': 'Account not found. Please check your email or create a new account.',
|
|
12330
|
+
// 409 - Conflicts
|
|
12331
|
+
'EMAIL_ALREADY_EXISTS': 'This email is already registered.',
|
|
12332
|
+
'EMAIL_IN_USE': 'This email is already in use.',
|
|
12333
|
+
// 429 - Rate limiting
|
|
12334
|
+
'RATE_LIMIT_EXCEEDED': 'Too many requests. Please try again later.',
|
|
12335
|
+
'TOO_MANY_MAGIC_LINKS': 'Too many magic link requests. Please try again later.',
|
|
12336
|
+
'TOO_MANY_VERIFICATION_ATTEMPTS': 'Too many verification attempts. Please wait and try again.',
|
|
12337
|
+
'MAX_VERIFICATION_ATTEMPTS': 'Maximum verification attempts reached. Please try again later.',
|
|
12338
|
+
// 500 - Server errors
|
|
12339
|
+
'LOGIN_FAILED': 'Login failed. Please try again later.',
|
|
12340
|
+
'REGISTRATION_FAILED': 'Registration failed. Please try again later.',
|
|
12341
|
+
'GOOGLE_AUTH_NOT_CONFIGURED': 'Google sign-in is not available for this application.',
|
|
12342
|
+
'GOOGLE_AUTH_FAILED': 'Google sign-in failed. Please try again.',
|
|
12343
|
+
'GOOGLE_USERINFO_FAILED': 'Failed to retrieve your Google account information. Please try again.',
|
|
12344
|
+
'PHONE_VERIFICATION_FAILED': 'Phone verification failed. Please try again.',
|
|
12345
|
+
'SEND_VERIFICATION_CODE_FAILED': 'Failed to send verification code. Please try again.',
|
|
12346
|
+
'MAGIC_LINK_SEND_FAILED': 'Failed to send magic link. Please try again.',
|
|
12347
|
+
'MAGIC_LINK_VERIFICATION_FAILED': 'Magic link verification failed. Please try again.',
|
|
12348
|
+
'PASSWORD_RESET_FAILED': 'Failed to process password reset. Please try again.',
|
|
12349
|
+
'PASSWORD_RESET_COMPLETE_FAILED': 'Failed to reset password. Please try again.',
|
|
12350
|
+
'EMAIL_VERIFICATION_SEND_FAILED': 'Failed to send verification email. Please try again.',
|
|
12351
|
+
'EMAIL_VERIFICATION_FAILED': 'Email verification failed. Please try again.',
|
|
12352
|
+
// Account management 500s
|
|
12353
|
+
'UPDATE_PROFILE_FAILED': 'Failed to update profile. Please try again.',
|
|
12354
|
+
'CHANGE_PASSWORD_FAILED': 'Failed to change password. Please try again.',
|
|
12355
|
+
'CHANGE_EMAIL_FAILED': 'Failed to change email. Please try again.',
|
|
12356
|
+
'UPDATE_PHONE_FAILED': 'Failed to update phone number. Please try again.',
|
|
12357
|
+
'DELETE_ACCOUNT_FAILED': 'Failed to delete account. Please try again.',
|
|
12358
|
+
'CONFIG_FETCH_FAILED': 'Failed to load configuration. Please try again.',
|
|
12359
|
+
'INTERNAL_ERROR': 'An unexpected error occurred. Please try again.',
|
|
12360
|
+
// Legacy aliases (kept for backward compatibility)
|
|
12241
12361
|
'INVALID_CODE': 'Invalid verification code. Please check and try again.',
|
|
12242
12362
|
'CODE_EXPIRED': 'This code has expired. Please request a new one.',
|
|
12243
|
-
'INVALID_TOKEN': 'This link has expired or is invalid. Please request a new one.',
|
|
12244
|
-
'TOKEN_EXPIRED': 'This link has expired. Please request a new one.',
|
|
12245
12363
|
'PHONE_NOT_SUPPORTED': 'This phone number is not supported. Please try a different number.',
|
|
12246
12364
|
'INVALID_PHONE': 'Invalid phone number. Please check the format and try again.',
|
|
12247
12365
|
'PASSWORD_TOO_WEAK': 'Password is too weak. Please use at least 8 characters with a mix of letters and numbers.',
|
|
12248
12366
|
'RATE_LIMITED': 'Too many attempts. Please wait a moment and try again.',
|
|
12249
12367
|
};
|
|
12368
|
+
function isApiErrorLike(error) {
|
|
12369
|
+
if (error instanceof SmartlinksApiError)
|
|
12370
|
+
return true;
|
|
12371
|
+
if (error && typeof error === 'object' && 'statusCode' in error && 'message' in error) {
|
|
12372
|
+
const e = error;
|
|
12373
|
+
return typeof e.statusCode === 'number' && typeof e.message === 'string';
|
|
12374
|
+
}
|
|
12375
|
+
return false;
|
|
12376
|
+
}
|
|
12250
12377
|
/**
|
|
12251
12378
|
* Extracts a user-friendly error message from an error.
|
|
12252
12379
|
*
|
|
12253
12380
|
* Handles:
|
|
12254
|
-
* - SmartlinksApiError
|
|
12381
|
+
* - SmartlinksApiError (and duck-typed equivalents from proxy mode)
|
|
12255
12382
|
* - Standard Error: Uses message property
|
|
12256
12383
|
* - String: Passes through directly (for native bridge errors)
|
|
12257
12384
|
* - Unknown: Returns generic message
|
|
12258
|
-
*
|
|
12259
|
-
* @param error - The caught error (SmartlinksApiError, Error, string, or unknown)
|
|
12260
|
-
* @returns A user-friendly error message suitable for display
|
|
12261
12385
|
*/
|
|
12262
12386
|
function getFriendlyErrorMessage(error) {
|
|
12263
|
-
// Handle SmartlinksApiError
|
|
12264
|
-
if (error
|
|
12387
|
+
// Handle SmartlinksApiError or duck-typed API errors (proxy mode)
|
|
12388
|
+
if (isApiErrorLike(error)) {
|
|
12265
12389
|
// First, check for specific error code (most precise)
|
|
12266
|
-
|
|
12267
|
-
|
|
12390
|
+
const errorCode = error.errorCode || error.details?.errorCode || error.details?.error;
|
|
12391
|
+
if (errorCode && ERROR_CODE_MESSAGES[errorCode]) {
|
|
12392
|
+
return ERROR_CODE_MESSAGES[errorCode];
|
|
12268
12393
|
}
|
|
12269
12394
|
// Then, check status code for general category messages
|
|
12270
12395
|
if (error.statusCode >= 500) {
|
|
@@ -12276,8 +12401,12 @@ function getFriendlyErrorMessage(error) {
|
|
|
12276
12401
|
// Fall back to the server's message (already human-readable from backend)
|
|
12277
12402
|
return error.message;
|
|
12278
12403
|
}
|
|
12279
|
-
// Handle standard Error objects
|
|
12404
|
+
// Handle standard Error objects — check message for known patterns
|
|
12280
12405
|
if (error instanceof Error) {
|
|
12406
|
+
// Check if the message itself contains a known API error pattern
|
|
12407
|
+
if (/already (registered|exists)/i.test(error.message)) {
|
|
12408
|
+
return 'This email is already registered.';
|
|
12409
|
+
}
|
|
12281
12410
|
return error.message;
|
|
12282
12411
|
}
|
|
12283
12412
|
// Handle plain strings (e.g., from native bridge callbacks)
|
|
@@ -12291,41 +12420,57 @@ function getFriendlyErrorMessage(error) {
|
|
|
12291
12420
|
* Checks if an error represents a conflict (409) - typically duplicate registration.
|
|
12292
12421
|
*/
|
|
12293
12422
|
function isConflictError(error) {
|
|
12294
|
-
|
|
12423
|
+
if (isApiErrorLike(error))
|
|
12424
|
+
return error.statusCode === 409;
|
|
12425
|
+
// Also check error message for keyword match (resilient fallback)
|
|
12426
|
+
if (error instanceof Error && /already (registered|exists)/i.test(error.message))
|
|
12427
|
+
return true;
|
|
12428
|
+
return false;
|
|
12295
12429
|
}
|
|
12296
12430
|
/**
|
|
12297
12431
|
* Checks if an error represents invalid credentials (401).
|
|
12298
12432
|
*/
|
|
12299
12433
|
function isAuthError(error) {
|
|
12300
|
-
|
|
12434
|
+
if (error instanceof SmartlinksApiError)
|
|
12435
|
+
return error.isAuthError();
|
|
12436
|
+
if (isApiErrorLike(error))
|
|
12437
|
+
return error.statusCode === 401 || error.statusCode === 403;
|
|
12438
|
+
return false;
|
|
12301
12439
|
}
|
|
12302
12440
|
/**
|
|
12303
12441
|
* Checks if an error represents rate limiting (429).
|
|
12304
12442
|
*/
|
|
12305
12443
|
function isRateLimitError(error) {
|
|
12306
|
-
|
|
12444
|
+
if (error instanceof SmartlinksApiError)
|
|
12445
|
+
return error.isRateLimited();
|
|
12446
|
+
if (isApiErrorLike(error))
|
|
12447
|
+
return error.statusCode === 429;
|
|
12448
|
+
return false;
|
|
12307
12449
|
}
|
|
12308
12450
|
/**
|
|
12309
12451
|
* Checks if an error represents a server error (5xx).
|
|
12310
12452
|
*/
|
|
12311
12453
|
function isServerError(error) {
|
|
12312
|
-
|
|
12454
|
+
if (error instanceof SmartlinksApiError)
|
|
12455
|
+
return error.isServerError();
|
|
12456
|
+
if (isApiErrorLike(error))
|
|
12457
|
+
return error.statusCode >= 500;
|
|
12458
|
+
return false;
|
|
12313
12459
|
}
|
|
12314
12460
|
/**
|
|
12315
12461
|
* Gets the HTTP status code from an error, if available.
|
|
12316
12462
|
*/
|
|
12317
12463
|
function getErrorStatusCode(error) {
|
|
12318
|
-
if (error
|
|
12464
|
+
if (isApiErrorLike(error))
|
|
12319
12465
|
return error.statusCode;
|
|
12320
|
-
}
|
|
12321
12466
|
return undefined;
|
|
12322
12467
|
}
|
|
12323
12468
|
/**
|
|
12324
12469
|
* Gets the server-specific error code from an error, if available.
|
|
12325
12470
|
*/
|
|
12326
12471
|
function getErrorCode(error) {
|
|
12327
|
-
if (error
|
|
12328
|
-
return error.errorCode;
|
|
12472
|
+
if (isApiErrorLike(error)) {
|
|
12473
|
+
return error.errorCode || error.details?.errorCode || error.details?.error;
|
|
12329
12474
|
}
|
|
12330
12475
|
return undefined;
|
|
12331
12476
|
}
|
|
@@ -12555,6 +12700,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
12555
12700
|
const [sdkReady, setSdkReady] = useState(false); // Track SDK initialization state
|
|
12556
12701
|
const [contactSchema, setContactSchema] = useState(null); // Schema for registration fields
|
|
12557
12702
|
const [silentSignInChecked, setSilentSignInChecked] = useState(false); // Track if silent sign-in has been checked
|
|
12703
|
+
const [googleFallbackToPopup, setGoogleFallbackToPopup] = useState(false); // Show popup fallback when FedCM is blocked/dismissed
|
|
12558
12704
|
const log = useMemo(() => createLoggerWrapper(logger), [logger]);
|
|
12559
12705
|
const api = new AuthAPI(apiEndpoint, clientId, clientName, logger);
|
|
12560
12706
|
const auth = useAuth();
|
|
@@ -13147,6 +13293,22 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13147
13293
|
setLoading(false);
|
|
13148
13294
|
}
|
|
13149
13295
|
};
|
|
13296
|
+
// Retry Google login using popup flow (fallback when FedCM/OneTap is blocked)
|
|
13297
|
+
const handleGooglePopupFallback = () => {
|
|
13298
|
+
setGoogleFallbackToPopup(false);
|
|
13299
|
+
setError(undefined);
|
|
13300
|
+
// Temporarily override the flow to popup and call handleGoogleLogin
|
|
13301
|
+
const originalFlow = config?.googleOAuthFlow;
|
|
13302
|
+
if (config) {
|
|
13303
|
+
config.googleOAuthFlow = 'popup';
|
|
13304
|
+
}
|
|
13305
|
+
handleGoogleLogin().finally(() => {
|
|
13306
|
+
// Restore original flow setting
|
|
13307
|
+
if (config) {
|
|
13308
|
+
config.googleOAuthFlow = originalFlow;
|
|
13309
|
+
}
|
|
13310
|
+
});
|
|
13311
|
+
};
|
|
13150
13312
|
const handleGoogleLogin = async () => {
|
|
13151
13313
|
const hasCustomGoogleClientId = !!config?.googleClientId;
|
|
13152
13314
|
const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
|
|
@@ -13162,6 +13324,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13162
13324
|
const isWhitelisted = isWhitelistedGoogleDomain(config?.whitelistedGoogleDomains);
|
|
13163
13325
|
const googleProxyUrl = config?.googleOAuthProxyUrl
|
|
13164
13326
|
|| (!hasCustomGoogleClientId && !isWhitelisted ? DEFAULT_GOOGLE_PROXY_URL : undefined);
|
|
13327
|
+
setGoogleFallbackToPopup(false);
|
|
13165
13328
|
log.log('Google Auth initiated:', {
|
|
13166
13329
|
configuredFlow,
|
|
13167
13330
|
effectiveFlow: oauthFlow,
|
|
@@ -13472,14 +13635,26 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13472
13635
|
cancel_on_tap_outside: true,
|
|
13473
13636
|
use_fedcm_for_prompt: true, // Enable FedCM for future browser compatibility
|
|
13474
13637
|
});
|
|
13475
|
-
// Use timeout fallback
|
|
13476
|
-
// (isNotDisplayed/isSkippedMoment will stop working when FedCM becomes mandatory)
|
|
13638
|
+
// Use timeout fallback — if no prompt interaction after 5s, assume FedCM was blocked
|
|
13477
13639
|
const promptTimeout = setTimeout(() => {
|
|
13640
|
+
log.log('Google OneTap prompt timed out — FedCM may be blocked or unavailable');
|
|
13641
|
+
setGoogleFallbackToPopup(true);
|
|
13478
13642
|
setLoading(false);
|
|
13479
13643
|
}, 5000);
|
|
13480
|
-
google.accounts.id.prompt(() => {
|
|
13481
|
-
// Clear timeout if prompt interaction occurs
|
|
13644
|
+
google.accounts.id.prompt((notification) => {
|
|
13482
13645
|
clearTimeout(promptTimeout);
|
|
13646
|
+
// Check for FedCM/OneTap dismissal or blocking
|
|
13647
|
+
// notification may have getMomentType(), getDismissedReason(), getSkippedReason()
|
|
13648
|
+
const momentType = notification?.getMomentType?.();
|
|
13649
|
+
const dismissedReason = notification?.getDismissedReason?.();
|
|
13650
|
+
const skippedReason = notification?.getSkippedReason?.();
|
|
13651
|
+
log.log('Google OneTap prompt notification:', { momentType, dismissedReason, skippedReason });
|
|
13652
|
+
if (momentType === 'skipped' || momentType === 'dismissed') {
|
|
13653
|
+
// User dismissed the prompt, or browser blocked it (FedCM disabled)
|
|
13654
|
+
// Offer popup flow as alternative
|
|
13655
|
+
log.log('Google OneTap was dismissed/skipped, offering popup fallback');
|
|
13656
|
+
setGoogleFallbackToPopup(true);
|
|
13657
|
+
}
|
|
13483
13658
|
setLoading(false);
|
|
13484
13659
|
});
|
|
13485
13660
|
}
|
|
@@ -13802,33 +13977,68 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
13802
13977
|
fontSize: '0.875rem',
|
|
13803
13978
|
fontWeight: 500,
|
|
13804
13979
|
opacity: loading ? 0.6 : 1
|
|
13805
|
-
}, children: "Cancel" })] })] })) : (
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
color: 'var(--auth-text-color, #6B7280)',
|
|
13820
|
-
cursor: 'pointer',
|
|
13980
|
+
}, children: "Cancel" })] })] })) : (jsxs(Fragment, { children: [googleFallbackToPopup && (jsxs("div", { style: {
|
|
13981
|
+
marginBottom: '1rem',
|
|
13982
|
+
padding: '0.75rem 1rem',
|
|
13983
|
+
borderRadius: '0.5rem',
|
|
13984
|
+
backgroundColor: resolvedTheme === 'dark' ? 'rgba(59, 130, 246, 0.1)' : 'rgba(59, 130, 246, 0.05)',
|
|
13985
|
+
border: `1px solid ${resolvedTheme === 'dark' ? 'rgba(59, 130, 246, 0.3)' : 'rgba(59, 130, 246, 0.2)'}`,
|
|
13986
|
+
}, children: [jsx("p", { style: {
|
|
13987
|
+
fontSize: '0.8125rem',
|
|
13988
|
+
color: resolvedTheme === 'dark' ? '#93c5fd' : '#1e40af',
|
|
13989
|
+
marginBottom: '0.5rem',
|
|
13990
|
+
lineHeight: 1.4,
|
|
13991
|
+
}, children: "Google sign-in was blocked by your browser. You can try signing in via a popup window instead." }), jsxs("button", { onClick: handleGooglePopupFallback, disabled: loading, style: {
|
|
13992
|
+
width: '100%',
|
|
13993
|
+
padding: '0.5rem 1rem',
|
|
13821
13994
|
fontSize: '0.875rem',
|
|
13995
|
+
fontWeight: 500,
|
|
13996
|
+
color: '#fff',
|
|
13997
|
+
backgroundColor: '#4285F4',
|
|
13998
|
+
border: 'none',
|
|
13999
|
+
borderRadius: '0.375rem',
|
|
14000
|
+
cursor: loading ? 'not-allowed' : 'pointer',
|
|
14001
|
+
opacity: loading ? 0.6 : 1,
|
|
13822
14002
|
display: 'flex',
|
|
13823
14003
|
alignItems: 'center',
|
|
13824
|
-
|
|
13825
|
-
|
|
13826
|
-
|
|
13827
|
-
|
|
13828
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
14004
|
+
justifyContent: 'center',
|
|
14005
|
+
gap: '0.5rem',
|
|
14006
|
+
}, children: [jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", children: [jsx("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615Z", fill: "#4285F4" }), jsx("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18Z", fill: "#34A853" }), jsx("path", { d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.997 8.997 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332Z", fill: "#FBBC05" }), jsx("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58Z", fill: "#EA4335" })] }), "Sign in with Google"] }), jsx("button", { onClick: () => setGoogleFallbackToPopup(false), style: {
|
|
14007
|
+
marginTop: '0.375rem',
|
|
14008
|
+
width: '100%',
|
|
14009
|
+
padding: '0.25rem',
|
|
14010
|
+
fontSize: '0.75rem',
|
|
14011
|
+
color: resolvedTheme === 'dark' ? '#64748b' : '#9ca3af',
|
|
14012
|
+
backgroundColor: 'transparent',
|
|
14013
|
+
border: 'none',
|
|
14014
|
+
cursor: 'pointer',
|
|
14015
|
+
}, children: "Dismiss" })] })), (() => {
|
|
14016
|
+
const emailDisplayMode = config?.emailDisplayMode || 'form';
|
|
14017
|
+
const providerOrder = config?.providerOrder || (config?.enabledProviders || enabledProviders);
|
|
14018
|
+
const actualProviders = config?.enabledProviders || enabledProviders;
|
|
14019
|
+
// Button mode: show provider selection first, then email form if email is selected
|
|
14020
|
+
if (emailDisplayMode === 'button' && !showEmailForm) {
|
|
14021
|
+
return (jsx(ProviderButtons, { enabledProviders: actualProviders, providerOrder: providerOrder, onEmailLogin: () => setShowEmailForm(true), onGoogleLogin: handleGoogleLogin, onPhoneLogin: () => setMode('phone'), onMagicLinkLogin: () => setMode('magic-link'), loading: loading }));
|
|
14022
|
+
}
|
|
14023
|
+
// Form mode or email button was clicked: show email form with other providers
|
|
14024
|
+
return (jsxs(Fragment, { children: [emailDisplayMode === 'button' && showEmailForm && (jsx("button", { onClick: () => setShowEmailForm(false), style: {
|
|
14025
|
+
marginBottom: '1rem',
|
|
14026
|
+
padding: '0.5rem',
|
|
14027
|
+
background: 'none',
|
|
14028
|
+
border: 'none',
|
|
14029
|
+
color: 'var(--auth-text-color, #6B7280)',
|
|
14030
|
+
cursor: 'pointer',
|
|
14031
|
+
fontSize: '0.875rem',
|
|
14032
|
+
display: 'flex',
|
|
14033
|
+
alignItems: 'center',
|
|
14034
|
+
gap: '0.25rem'
|
|
14035
|
+
}, children: "\u2190 Back to options" })), jsx(EmailAuthForm, { mode: mode, onSubmit: handleEmailAuth, onModeSwitch: () => {
|
|
14036
|
+
setMode(mode === 'login' ? 'register' : 'login');
|
|
14037
|
+
setShowResendVerification(false);
|
|
14038
|
+
setShowRequestNewReset(false);
|
|
14039
|
+
setError(undefined);
|
|
14040
|
+
}, onForgotPassword: () => setMode('reset-password'), loading: loading, error: error, signupProminence: resolvedSignupProminence, schema: contactSchema, registrationFieldsConfig: config?.registrationFields, additionalFields: config?.signupAdditionalFields }), emailDisplayMode === 'form' && actualProviders.length > 1 && (jsx(ProviderButtons, { enabledProviders: actualProviders.filter((p) => p !== 'email'), providerOrder: providerOrder, onGoogleLogin: handleGoogleLogin, onPhoneLogin: () => setMode('phone'), onMagicLinkLogin: () => setMode('magic-link'), loading: loading }))] }));
|
|
14041
|
+
})()] })) })) : null }));
|
|
13832
14042
|
};
|
|
13833
14043
|
|
|
13834
14044
|
var SmartlinksAuthUI$1 = /*#__PURE__*/Object.freeze({
|
|
@@ -14897,5 +15107,5 @@ async function setDefaultAuthKitId(collectionId, authKitId) {
|
|
|
14897
15107
|
});
|
|
14898
15108
|
}
|
|
14899
15109
|
|
|
14900
|
-
export { AccountManagement, AuthProvider, AuthUIPreview, SmartlinksAuthUI as FirebaseAuthUI, ProtectedRoute, SchemaFieldRenderer, SmartlinksAuthUI, SmartlinksFrame, buildIframeSrc, getDefaultAuthKitId, getEditableFields, getErrorCode, getErrorStatusCode, getFriendlyErrorMessage, getRegistrationFields, isAdminFromRoles, isAuthError, isConflictError, isRateLimitError, isServerError, resolveFields, setDefaultAuthKitId, sortFieldsByPlacement, tokenStorage, useAdminDetection, useAuth, useIframeMessages, useIframeResize };
|
|
15110
|
+
export { AccountManagement, AuthProvider, AuthUIPreview, SmartlinksAuthUI as FirebaseAuthUI, ProtectedRoute, SchemaFieldRenderer, SmartlinksAuthUI, SmartlinksFrame, buildIframeSrc, evaluateConditions, getDefaultAuthKitId, getEditableFields, getErrorCode, getErrorStatusCode, getFriendlyErrorMessage, getRegistrationFields, isAdminFromRoles, isAuthError, isConflictError, isRateLimitError, isServerError, resolveFields, setDefaultAuthKitId, sortFieldsByPlacement, tokenStorage, useAdminDetection, useAuth, useIframeMessages, useIframeResize };
|
|
14901
15111
|
//# sourceMappingURL=index.esm.js.map
|