@proveanything/smartlinks-auth-ui 0.5.6 → 0.5.7

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/index.js CHANGED
@@ -11513,15 +11513,18 @@ class AuthAPI {
11513
11513
  return smartlinks__namespace.authKit.verifyMagicLink(this.clientId, token);
11514
11514
  }
11515
11515
  // ============= WhatsApp =============
11516
- async sendWhatsApp(redirectUrl, phoneNumber, reply, prefillMessage) {
11516
+ async sendWhatsApp(redirectUrl, phoneNumber, reply, prefillMessage, contactData) {
11517
11517
  // phoneNumber is optional — backend extracts it from the inbound WhatsApp webhook.
11518
11518
  // `reply`, when provided, is sent back to the user via WhatsApp on successful verification.
11519
11519
  // `prefillMessage` customizes the message body pre-filled in the wa.me link.
11520
+ // `contactData` is upserted onto the contact when the backend creates/links it,
11521
+ // so the returned session.user is fully formed (name, email, custom fields, etc.).
11520
11522
  return smartlinks__namespace.authKit.sendWhatsApp(this.clientId, {
11521
11523
  phoneNumber: phoneNumber ?? '',
11522
11524
  redirectUrl,
11523
11525
  ...(reply ? { reply } : {}),
11524
11526
  ...(prefillMessage ? { prefillMessage } : {}),
11527
+ ...(contactData ? { contactData } : {}),
11525
11528
  });
11526
11529
  }
11527
11530
  async exchangeWhatsAppSession(token, sessionKey) {
@@ -14291,8 +14294,17 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14291
14294
  });
14292
14295
  // Resolve outbound prefill message: per-call prop wins, then AuthKit default.
14293
14296
  const prefillMessage = whatsappPrefillMessage ?? config?.whatsappPrefillMessage;
14294
- const result = await api.sendWhatsApp(getRedirectUrl(), undefined, reply, prefillMessage);
14295
- whatsappSendRef.current = { token: result.token, sessionKey: result.sessionKey };
14297
+ // Pass collected signup details as contactData so the backend creates the
14298
+ // contact with name/customFields already attached and returns a fully
14299
+ // formed session.user — no follow-up updateProfile call needed.
14300
+ const trimmedName = displayName?.trim() || undefined;
14301
+ const contactData = trimmedName ? { name: trimmedName } : undefined;
14302
+ const result = await api.sendWhatsApp(getRedirectUrl(), undefined, reply, prefillMessage, contactData);
14303
+ whatsappSendRef.current = {
14304
+ token: result.token,
14305
+ sessionKey: result.sessionKey,
14306
+ displayName: trimmedName,
14307
+ };
14296
14308
  return result;
14297
14309
  }
14298
14310
  catch (err) {
@@ -14311,9 +14323,9 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
14311
14323
  const target = status.redirectUrl || getRedirectUrl();
14312
14324
  setAuthSuccess(true);
14313
14325
  setSuccessMessage('WhatsApp verified! Signing you in…');
14314
- // Exchange the verified WhatsApp proof for a real Auth Kit session token,
14315
- // so the user is fully logged in (not just verified) and any same-tab
14316
- // continuation flows (claim, bid, etc.) pick up an authenticated session.
14326
+ // Exchange the verified WhatsApp proof for a real Auth Kit session token.
14327
+ // The backend has already created/updated the contact using contactData
14328
+ // sent at sendWhatsApp time, so session.user is fully formed.
14317
14329
  const send = whatsappSendRef.current;
14318
14330
  if (send?.sessionKey) {
14319
14331
  try {
@@ -14656,6 +14668,32 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14656
14668
  const [profile, setProfile] = React.useState(null);
14657
14669
  const [error, setError] = React.useState();
14658
14670
  const [success, setSuccess] = React.useState();
14671
+ const [resolvedClientId, setResolvedClientId] = React.useState(clientId);
14672
+ // Keep prop in sync
14673
+ React.useEffect(() => {
14674
+ if (clientId)
14675
+ setResolvedClientId(clientId);
14676
+ }, [clientId]);
14677
+ // If no clientId was provided, try to resolve the collection's default Auth Kit.
14678
+ // This supports "portal mode" where the host app only knows the collectionId.
14679
+ React.useEffect(() => {
14680
+ if (clientId || !collectionId)
14681
+ return;
14682
+ let cancelled = false;
14683
+ (async () => {
14684
+ try {
14685
+ const collection = await smartlinks__namespace.collection.get(collectionId);
14686
+ const defaultId = collection?.defaultAuthKitId;
14687
+ if (!cancelled && defaultId)
14688
+ setResolvedClientId(defaultId);
14689
+ }
14690
+ catch {
14691
+ // Non-fatal — handlers will surface a friendly error if still missing
14692
+ }
14693
+ })();
14694
+ return () => { cancelled = true; };
14695
+ }, [clientId, collectionId]);
14696
+ const NO_CLIENT_ID_MSG = 'This account section is not connected to an Auth Kit yet. Pass a clientId prop, or set a default Auth Kit on the collection in the admin console.';
14659
14697
  // Schema state — now uses SDK type directly
14660
14698
  const [schema, setSchema] = React.useState(null);
14661
14699
  const [schemaLoading, setSchemaLoading] = React.useState(false);
@@ -14727,26 +14765,29 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14727
14765
  setLoading(true);
14728
14766
  setError(undefined);
14729
14767
  try {
14768
+ // Pull contact first so we can fall back to fields the auth user object
14769
+ // may not carry (e.g. WhatsApp phone numbers, displayName, email).
14770
+ let contactData = auth.contact;
14771
+ if (collectionId && !contactData) {
14772
+ try {
14773
+ contactData = (await auth.getContact?.()) || null;
14774
+ }
14775
+ catch { /* non-fatal */ }
14776
+ }
14777
+ const contactAny = contactData;
14730
14778
  const profileData = {
14731
14779
  uid: auth.user?.uid || '',
14732
- email: auth.user?.email,
14733
- displayName: auth.user?.displayName,
14734
- phoneNumber: auth.user?.phoneNumber,
14780
+ email: auth.user?.email || contactAny?.email,
14781
+ displayName: auth.user?.displayName || contactAny?.displayName || contactAny?.name,
14782
+ phoneNumber: auth.user?.phoneNumber || contactAny?.phone || contactAny?.phoneNumber,
14735
14783
  photoURL: auth.user?.photoURL,
14736
14784
  emailVerified: true,
14737
14785
  accountData: auth.accountData || {},
14738
14786
  };
14739
14787
  setProfile(profileData);
14740
14788
  setDisplayName(profileData.displayName || '');
14741
- // Load contact custom fields if collectionId provided
14742
- if (collectionId && auth.contact) {
14743
- setCustomFieldValues(auth.contact.customFields || {});
14744
- }
14745
- else if (collectionId) {
14746
- const contact = await auth.getContact?.();
14747
- if (contact?.customFields) {
14748
- setCustomFieldValues(contact.customFields);
14749
- }
14789
+ if (collectionId && contactData?.customFields) {
14790
+ setCustomFieldValues(contactData.customFields);
14750
14791
  }
14751
14792
  }
14752
14793
  catch (err) {
@@ -14778,15 +14819,15 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14778
14819
  const editableCustomFields = getEditableFields(schema, customFieldValues).filter(f => !['email', 'displayName', 'phone', 'phoneNumber'].includes(f.key));
14779
14820
  const handleUpdateProfile = async (e) => {
14780
14821
  e.preventDefault();
14781
- if (!clientId) {
14782
- setError('Client ID is required');
14822
+ if (!resolvedClientId) {
14823
+ setError(NO_CLIENT_ID_MSG);
14783
14824
  return;
14784
14825
  }
14785
14826
  setLoading(true);
14786
14827
  setError(undefined);
14787
14828
  setSuccess(undefined);
14788
14829
  try {
14789
- await smartlinks__namespace.authKit.updateProfile(clientId, { displayName });
14830
+ await smartlinks__namespace.authKit.updateProfile(resolvedClientId, { displayName });
14790
14831
  setSuccess('Profile updated successfully!');
14791
14832
  setEditingSection(null);
14792
14833
  if (profile) {
@@ -14825,8 +14866,8 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14825
14866
  };
14826
14867
  const handleChangeEmail = async (e) => {
14827
14868
  e.preventDefault();
14828
- if (!clientId) {
14829
- setError('Client ID is required');
14869
+ if (!resolvedClientId) {
14870
+ setError(NO_CLIENT_ID_MSG);
14830
14871
  return;
14831
14872
  }
14832
14873
  setLoading(true);
@@ -14834,7 +14875,7 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14834
14875
  setSuccess(undefined);
14835
14876
  try {
14836
14877
  const redirectUrl = window.location.href;
14837
- await smartlinks__namespace.authKit.changeEmail(clientId, newEmail, emailPassword, redirectUrl);
14878
+ await smartlinks__namespace.authKit.changeEmail(resolvedClientId, newEmail, emailPassword, redirectUrl);
14838
14879
  setSuccess('Email change requested. Please check your new email for verification.');
14839
14880
  setEditingSection(null);
14840
14881
  setNewEmail('');
@@ -14850,8 +14891,8 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14850
14891
  };
14851
14892
  const handleChangePassword = async (e) => {
14852
14893
  e.preventDefault();
14853
- if (!clientId) {
14854
- setError('Client ID is required');
14894
+ if (!resolvedClientId) {
14895
+ setError(NO_CLIENT_ID_MSG);
14855
14896
  return;
14856
14897
  }
14857
14898
  if (newPassword !== confirmPassword) {
@@ -14866,7 +14907,7 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14866
14907
  setError(undefined);
14867
14908
  setSuccess(undefined);
14868
14909
  try {
14869
- await smartlinks__namespace.authKit.changePassword(clientId, currentPassword, newPassword);
14910
+ await smartlinks__namespace.authKit.changePassword(resolvedClientId, currentPassword, newPassword);
14870
14911
  setSuccess('Password changed successfully!');
14871
14912
  setEditingSection(null);
14872
14913
  setCurrentPassword('');
@@ -14882,14 +14923,14 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14882
14923
  }
14883
14924
  };
14884
14925
  const handleSendPhoneCode = async () => {
14885
- if (!clientId) {
14886
- setError('Client ID is required');
14926
+ if (!resolvedClientId) {
14927
+ setError(NO_CLIENT_ID_MSG);
14887
14928
  return;
14888
14929
  }
14889
14930
  setLoading(true);
14890
14931
  setError(undefined);
14891
14932
  try {
14892
- await smartlinks__namespace.authKit.sendPhoneCode(clientId, newPhone);
14933
+ await smartlinks__namespace.authKit.sendPhoneCode(resolvedClientId, newPhone);
14893
14934
  setPhoneCodeSent(true);
14894
14935
  setSuccess('Verification code sent to your phone');
14895
14936
  }
@@ -14903,15 +14944,15 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14903
14944
  };
14904
14945
  const handleUpdatePhone = async (e) => {
14905
14946
  e.preventDefault();
14906
- if (!clientId) {
14907
- setError('Client ID is required');
14947
+ if (!resolvedClientId) {
14948
+ setError(NO_CLIENT_ID_MSG);
14908
14949
  return;
14909
14950
  }
14910
14951
  setLoading(true);
14911
14952
  setError(undefined);
14912
14953
  setSuccess(undefined);
14913
14954
  try {
14914
- await smartlinks__namespace.authKit.updatePhone(clientId, newPhone, phoneCode);
14955
+ await smartlinks__namespace.authKit.updatePhone(resolvedClientId, newPhone, phoneCode);
14915
14956
  setSuccess('Phone number updated successfully!');
14916
14957
  setEditingSection(null);
14917
14958
  setNewPhone('');
@@ -14928,8 +14969,8 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14928
14969
  }
14929
14970
  };
14930
14971
  const handleDeleteAccount = async () => {
14931
- if (!clientId) {
14932
- setError('Client ID is required');
14972
+ if (!resolvedClientId) {
14973
+ setError(NO_CLIENT_ID_MSG);
14933
14974
  return;
14934
14975
  }
14935
14976
  if (deleteConfirmText !== 'DELETE') {
@@ -14943,7 +14984,7 @@ const AccountManagement = ({ apiEndpoint, clientId, collectionId, onError, class
14943
14984
  setLoading(true);
14944
14985
  setError(undefined);
14945
14986
  try {
14946
- await smartlinks__namespace.authKit.deleteAccount(clientId, deletePassword, deleteConfirmText);
14987
+ await smartlinks__namespace.authKit.deleteAccount(resolvedClientId, deletePassword, deleteConfirmText);
14947
14988
  setSuccess('Account deleted successfully');
14948
14989
  await auth.logout();
14949
14990
  }