feat: add referral code persistence across all auth methods

Mirrors campaign.ts localStorage pattern to capture ?ref= from URL and pass
referral_code to backend during Telegram Widget, OAuth, email login, and
Mini App authentication. Fixes redirect loop when email auth is disabled.
This commit is contained in:
Fringg
2026-02-18 23:59:32 +03:00
parent 271a005e87
commit 2b2ead837c
5 changed files with 129 additions and 15 deletions

View File

@@ -4,6 +4,7 @@ import type { CampaignBonusInfo, RegisterResponse, User } from '../types';
import { authApi } from '../api/auth';
import { apiClient } from '../api/client';
import { captureCampaignFromUrl, consumeCampaignSlug } from '../utils/campaign';
import { captureReferralFromUrl, consumeReferralCode } from '../utils/referral';
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
export interface TelegramWidgetData {
@@ -242,7 +243,8 @@ export const useAuthStore = create<AuthState>()(
loginWithTelegram: async (initData) => {
const campaignSlug = consumeCampaignSlug();
const response = await authApi.loginTelegram(initData, campaignSlug);
const referralCode = consumeReferralCode();
const response = await authApi.loginTelegram(initData, campaignSlug, referralCode);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
@@ -256,7 +258,8 @@ export const useAuthStore = create<AuthState>()(
loginWithTelegramWidget: async (data) => {
const campaignSlug = consumeCampaignSlug();
const response = await authApi.loginTelegramWidget(data, campaignSlug);
const referralCode = consumeReferralCode();
const response = await authApi.loginTelegramWidget(data, campaignSlug, referralCode);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
@@ -270,7 +273,8 @@ export const useAuthStore = create<AuthState>()(
loginWithEmail: async (email, password) => {
const campaignSlug = consumeCampaignSlug();
const response = await authApi.loginEmail(email, password, campaignSlug);
const referralCode = consumeReferralCode();
const response = await authApi.loginEmail(email, password, campaignSlug, referralCode);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
@@ -284,7 +288,14 @@ export const useAuthStore = create<AuthState>()(
loginWithOAuth: async (provider, code, state) => {
const campaignSlug = consumeCampaignSlug();
const response = await authApi.oauthCallback(provider, code, state, campaignSlug);
const referralCode = consumeReferralCode();
const response = await authApi.oauthCallback(
provider,
code,
state,
campaignSlug,
referralCode,
);
tokenStorage.setTokens(response.access_token, response.refresh_token);
set({
accessToken: response.access_token,
@@ -300,12 +311,13 @@ export const useAuthStore = create<AuthState>()(
// Registration now returns message, not tokens
// User must verify email before they can login
// Campaign slug stays in localStorage — consumed during verify_email step
const code = referralCode || consumeReferralCode() || undefined;
const response = await authApi.registerEmailStandalone({
email,
password,
first_name: firstName,
language: navigator.language.split('-')[0] || 'ru',
referral_code: referralCode,
referral_code: code,
});
return response;
},
@@ -321,8 +333,9 @@ export const useAuthStore = create<AuthState>()(
),
);
// Capture campaign slug from URL before auth initialization
// Capture campaign slug and referral code from URL before auth initialization
captureCampaignFromUrl();
captureReferralFromUrl();
// Initialize auth on app load
useAuthStore.getState().initialize();