The useSignUp hook provides functionality for user registration with support for verification flows including email and phone verification.

Import

import { useSignUp } from '@snipextt/wacht';

Usage

import { useSignUp } from '@snipextt/wacht';

function SignUpForm() {
  const { signUp, loading, signupAttempt, errors } = useSignUp();

  const handleSignUp = async (params) => {
    const result = await signUp.create({
      first_name: 'John',
      last_name: 'Doe',
      email: 'john@example.com',
      password: 'securePassword123',
      username: 'johndoe'
    });
    
    if (result.data && result.data.signup_attempts) {
      // Sign-up successful, may require verification
      console.log('Sign up successful');
    }
  };

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      const formData = new FormData(e.target);
      handleSignUp({
        first_name: formData.get('firstName'),
        last_name: formData.get('lastName'),
        email: formData.get('email'),
        password: formData.get('password'),
        username: formData.get('username')
      });
    }}>
      <input name="firstName" placeholder="First Name" required />
      <input name="lastName" placeholder="Last Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <input name="password" type="password" placeholder="Password" required />
      <input name="username" placeholder="Username" />
      <button type="submit" disabled={loading}>
        {loading ? 'Creating Account...' : 'Sign Up'}
      </button>
    </form>
  );
}

Properties

loading
boolean
Whether a sign-up operation is currently in progress. true during registration requests.
signupAttempt
SignupAttempt | null
The current sign-up attempt object containing verification requirements and status. null if no active attempt.
errors
ApiResult<unknown, ErrorInterface> | null
Any errors that occurred during the sign-up process. null if no errors.

Sign-Up Object

The signUp object provides methods for registration:

create()

Creates a new user account with the provided parameters.
params
SignUpParams
required
User registration data
const { signUp } = useSignUp();

const result = await signUp.create({
  first_name: 'John',
  last_name: 'Doe',
  email: 'john@example.com',
  password: 'securePassword123',
  username: 'johndoe',
  phone_number: '+1234567890'
});

prepareVerification()

Prepares verification for email or phone number.
params
SignupVerificationParams
required
Parameters for preparing verification
const { signUp } = useSignUp();

// Prepare email verification
await signUp.prepareVerification({
  strategy: 'email_otp',
  redirectUri: 'https://myapp.com/verify'
});

// Prepare phone verification
await signUp.prepareVerification({
  strategy: 'phone_otp',
  lastDigits: '1234'
});

completeVerification()

Completes verification with the provided code.
verificationCode
string
required
The verification code received via email or SMS
const { signUp } = useSignUp();

// Complete verification with OTP code
await signUp.completeVerification('123456');

Methods

discardSignupAttempt()

Clears the current sign-up attempt and any associated errors.
const { discardSignupAttempt } = useSignUp();

// Clear current attempt
discardSignupAttempt();

Sign-Up Parameters

The create method accepts the following parameters:
first_name
string
User’s first name
last_name
string
User’s last name
email
string
User’s email address
password
string
User’s password
username
string
User’s username (optional)
phone_number
string
User’s phone number (optional)

Examples

Complete Sign-Up Flow with Verification

function CompleteSignUpFlow() {
  const { signUp, signupAttempt, loading } = useSignUp();
  const [step, setStep] = useState('signup');

  const handleSignUp = async (userData) => {
    const result = await signUp.create(userData);
    
    if (result.data?.signup_attempts?.length) {
      const attempt = result.data.signup_attempts[0];
      
      if (attempt.current_step === 'verify_email') {
        setStep('email-verification');
      } else if (attempt.current_step === 'verify_phone') {
        setStep('phone-verification');
      }
    }
  };

  const handleEmailVerification = async (code) => {
    await signUp.completeVerification(code);
    setStep('complete');
  };

  if (step === 'email-verification') {
    return (
      <div>
        <h2>Verify Your Email</h2>
        <p>Please enter the verification code sent to your email.</p>
        <input 
          type="text" 
          placeholder="Enter 6-digit code"
          onBlur={(e) => handleEmailVerification(e.target.value)}
        />
      </div>
    );
  }

  if (step === 'complete') {
    return <div>Account created successfully!</div>;
  }

  return (
    <SignUpForm onSubmit={handleSignUp} />
  );
}

Sign-Up with Error Handling

function SignUpWithErrorHandling() {
  const { signUp, errors, loading } = useSignUp();

  const handleSignUp = async (userData) => {
    const result = await signUp.create(userData);
    
    if (result.errors) {
      // Handle specific error types
      result.errors.forEach(error => {
        if (error.code === 'email_already_exists') {
          console.error('Email already in use');
        } else if (error.code === 'weak_password') {
          console.error('Password is too weak');
        }
      });
    }
  };

  return (
    <div>
      {errors && (
        <div className="error-messages">
          {errors.errors?.map((error, index) => (
            <p key={index} className="error">
              {error.message}
            </p>
          ))}
        </div>
      )}
      
      <form onSubmit={(e) => {
        e.preventDefault();
        const formData = new FormData(e.target);
        handleSignUp({
          first_name: formData.get('firstName'),
          last_name: formData.get('lastName'),
          email: formData.get('email'),
          password: formData.get('password')
        });
      }}>
        {/* Form fields */}
        <button type="submit" disabled={loading}>
          {loading ? 'Creating Account...' : 'Sign Up'}
        </button>
      </form>
    </div>
  );
}

Conditional Verification

function ConditionalVerification() {
  const { signUp, signupAttempt } = useSignUp();

  const prepareEmailVerification = async () => {
    await signUp.prepareVerification({
      strategy: 'email_otp',
      redirectUri: window.location.origin + '/verify-email'
    });
  };

  const preparePhoneVerification = async () => {
    await signUp.prepareVerification({
      strategy: 'phone_otp',
      lastDigits: '1234' // Optional hint for phone verification
    });
  };

  if (signupAttempt?.current_step === 'verify_email') {
    return (
      <div>
        <h3>Email Verification Required</h3>
        <button onClick={prepareEmailVerification}>
          Send Email Verification
        </button>
      </div>
    );
  }

  if (signupAttempt?.current_step === 'verify_phone') {
    return (
      <div>
        <h3>Phone Verification Required</h3>
        <button onClick={preparePhoneVerification}>
          Send SMS Verification
        </button>
      </div>
    );
  }

  return <div>Signup completed successfully!</div>;
}

Verification Strategies

Email OTP Verification

// Prepare email verification
await signUp.prepareVerification({
  strategy: 'email_otp',
  redirectUri: 'https://myapp.com/verify-email'
});

// Complete with received code
await signUp.completeVerification('123456');

Phone OTP Verification

// Prepare phone verification
await signUp.prepareVerification({
  strategy: 'phone_otp',
  lastDigits: '1234' // Optional last digits hint
});

// Complete with received code
await signUp.completeVerification('123456');

Notes

  • Sign-up attempts are automatically tracked and managed
  • Verification codes are typically 6 digits
  • Email verification may include a redirect URI for seamless user experience
  • Phone verification supports last digits hints for user convenience
  • All operations return a consistent ApiResult format
  • The hook automatically manages loading states during API calls