@proveanything/smartlinks-auth-ui 0.1.0 → 0.1.1

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
@@ -399,6 +399,8 @@ const AuthUIPreview = ({ customization, enabledProviders = ['email', 'google', '
399
399
  return (jsxRuntime.jsxs(AuthContainer, { theme: theme, className: className, config: customization, children: [showEmail && (jsxRuntime.jsxs("div", { className: "auth-form", children: [jsxRuntime.jsxs("div", { className: "auth-form-group", children: [jsxRuntime.jsx("label", { className: "auth-label", children: "Email" }), jsxRuntime.jsx("input", { type: "email", className: "auth-input", placeholder: "Enter your email", disabled: true })] }), jsxRuntime.jsxs("div", { className: "auth-form-group", children: [jsxRuntime.jsx("label", { className: "auth-label", children: "Password" }), jsxRuntime.jsx("input", { type: "password", className: "auth-input", placeholder: "Enter your password", disabled: true })] }), jsxRuntime.jsx("button", { className: "auth-button auth-button-primary", disabled: true, children: "Sign In" }), jsxRuntime.jsx("div", { style: { textAlign: 'center', marginTop: '1rem' }, children: jsxRuntime.jsx("button", { className: "auth-link", disabled: true, children: "Forgot password?" }) }), jsxRuntime.jsxs("div", { style: { textAlign: 'center', marginTop: '0.5rem', fontSize: '0.875rem', color: 'var(--auth-text-muted, #6B7280)' }, children: ["Don't have an account?", ' ', jsxRuntime.jsx("button", { className: "auth-link", disabled: true, children: "Sign up" })] })] })), hasProviders && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [showEmail && (jsxRuntime.jsx("div", { className: "auth-or-divider", children: jsxRuntime.jsx("span", { children: "or continue with" }) })), jsxRuntime.jsxs("div", { className: "auth-provider-buttons", children: [showGoogle && (jsxRuntime.jsxs("button", { className: "auth-provider-button", disabled: true, children: [jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", children: [jsxRuntime.jsx("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z", fill: "#4285F4" }), jsxRuntime.jsx("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.183l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332C2.438 15.983 5.482 18 9 18z", fill: "#34A853" }), jsxRuntime.jsx("path", { d: "M3.964 10.707c-.18-.54-.282-1.117-.282-1.707 0-.593.102-1.167.282-1.707V4.961H.957C.347 6.175 0 7.548 0 9s.348 2.825.957 4.039l3.007-2.332z", fill: "#FBBC05" }), jsxRuntime.jsx("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0 5.482 0 2.438 2.017.957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z", fill: "#EA4335" })] }), jsxRuntime.jsx("span", { children: "Google" })] })), showPhone && (jsxRuntime.jsxs("button", { className: "auth-provider-button", disabled: true, children: [jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntime.jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }), jsxRuntime.jsx("span", { children: "Phone" })] }))] })] }))] }));
400
400
  };
401
401
 
402
+ // Default Smartlinks Google OAuth Client ID (public - safe to expose)
403
+ const DEFAULT_GOOGLE_CLIENT_ID = '696509063554-jdlbjl8vsjt7cr0vgkjkjf3ffnvi3a70.apps.googleusercontent.com';
402
404
  const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], redirectUrl, theme = 'light', className, customization, skipConfigFetch = false, }) => {
403
405
  const [mode, setMode] = react.useState('login');
404
406
  const [loading, setLoading] = react.useState(false);
@@ -691,19 +693,94 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
691
693
  }
692
694
  };
693
695
  const handleGoogleLogin = async () => {
696
+ // Use custom client ID from config, or fall back to default Smartlinks client ID
697
+ const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
698
+ // Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
699
+ const oauthFlow = config?.googleOAuthFlow || 'oneTap';
694
700
  setLoading(true);
695
701
  setError(undefined);
696
702
  try {
697
- // In a real implementation, this would open Google OAuth flow
698
- // For now, this is a placeholder that the consuming app would implement
699
- throw new Error('Google OAuth flow must be implemented in your application');
703
+ const google = window.google;
704
+ if (!google) {
705
+ throw new Error('Google Identity Services not loaded. Please check your internet connection.');
706
+ }
707
+ if (oauthFlow === 'popup') {
708
+ // Use OAuth2 popup flow (works in iframes but requires popup permission)
709
+ if (!google.accounts.oauth2) {
710
+ throw new Error('Google OAuth2 not available');
711
+ }
712
+ const client = google.accounts.oauth2.initTokenClient({
713
+ client_id: googleClientId,
714
+ scope: 'openid email profile',
715
+ callback: async (response) => {
716
+ try {
717
+ if (response.error) {
718
+ throw new Error(response.error_description || response.error);
719
+ }
720
+ const accessToken = response.access_token;
721
+ // Send access token to backend
722
+ const authResponse = await api.loginWithGoogle(accessToken);
723
+ auth.login(authResponse.token, authResponse.user, authResponse.accountData);
724
+ setAuthSuccess(true);
725
+ setSuccessMessage('Google login successful!');
726
+ onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
727
+ if (redirectUrl) {
728
+ setTimeout(() => {
729
+ window.location.href = redirectUrl;
730
+ }, 2000);
731
+ }
732
+ setLoading(false);
733
+ }
734
+ catch (err) {
735
+ const errorMessage = err instanceof Error ? err.message : 'Google login failed';
736
+ setError(errorMessage);
737
+ onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
738
+ setLoading(false);
739
+ }
740
+ },
741
+ });
742
+ client.requestAccessToken();
743
+ }
744
+ else {
745
+ // Use One Tap / Sign-In button flow (smoother UX but doesn't work in iframes)
746
+ google.accounts.id.initialize({
747
+ client_id: googleClientId,
748
+ callback: async (response) => {
749
+ try {
750
+ const idToken = response.credential;
751
+ const authResponse = await api.loginWithGoogle(idToken);
752
+ auth.login(authResponse.token, authResponse.user, authResponse.accountData);
753
+ setAuthSuccess(true);
754
+ setSuccessMessage('Google login successful!');
755
+ onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
756
+ if (redirectUrl) {
757
+ setTimeout(() => {
758
+ window.location.href = redirectUrl;
759
+ }, 2000);
760
+ }
761
+ setLoading(false);
762
+ }
763
+ catch (err) {
764
+ const errorMessage = err instanceof Error ? err.message : 'Google login failed';
765
+ setError(errorMessage);
766
+ onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
767
+ setLoading(false);
768
+ }
769
+ },
770
+ auto_select: false,
771
+ cancel_on_tap_outside: true,
772
+ });
773
+ google.accounts.id.prompt((notification) => {
774
+ if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
775
+ setLoading(false);
776
+ }
777
+ });
778
+ }
700
779
  }
701
780
  catch (err) {
702
781
  const errorMessage = err instanceof Error ? err.message : 'Google login failed';
703
782
  setError(errorMessage);
704
783
  onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
705
- }
706
- finally {
707
784
  setLoading(false);
708
785
  }
709
786
  };