mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
Merge pull request #386 from BEDOLAGA-DEV/dev
fix: batch frontend fixes matching backend changes
This commit is contained in:
@@ -7,7 +7,7 @@ import { brandingApi, type TelegramWidgetConfig } from '../api/branding';
|
|||||||
import { authApi } from '../api/auth';
|
import { authApi } from '../api/auth';
|
||||||
import { useAuthStore } from '../store/auth';
|
import { useAuthStore } from '../store/auth';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { consumeCampaignSlug } from '../utils/campaign';
|
import { getPendingCampaignSlug } from '../utils/campaign';
|
||||||
import { copyToClipboard } from '../utils/clipboard';
|
import { copyToClipboard } from '../utils/clipboard';
|
||||||
|
|
||||||
interface TelegramLoginButtonProps {
|
interface TelegramLoginButtonProps {
|
||||||
@@ -253,7 +253,7 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
// bot users where referrals don't apply. Leaving it in localStorage allows
|
// bot users where referrals don't apply. Leaving it in localStorage allows
|
||||||
// other auth methods (OIDC, widget) to pick it up if the user switches paths.
|
// other auth methods (OIDC, widget) to pick it up if the user switches paths.
|
||||||
if (!codesConsumedRef.current) {
|
if (!codesConsumedRef.current) {
|
||||||
capturedCampaignRef.current = consumeCampaignSlug();
|
capturedCampaignRef.current = getPendingCampaignSlug();
|
||||||
codesConsumedRef.current = true;
|
codesConsumedRef.current = true;
|
||||||
}
|
}
|
||||||
const capturedCampaign = capturedCampaignRef.current;
|
const capturedCampaign = capturedCampaignRef.current;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ function injectYandexMetrika(counterId: string) {
|
|||||||
ym(${counterId}, "init", {
|
ym(${counterId}, "init", {
|
||||||
clickmap:true,
|
clickmap:true,
|
||||||
trackLinks:true,
|
trackLinks:true,
|
||||||
accurateTrackBounce:true
|
accurateTrackBounce:true,
|
||||||
|
webvisor:true
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
|
|||||||
@@ -677,6 +677,8 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"not_found": "Promo code not found",
|
"not_found": "Promo code not found",
|
||||||
"expired": "Promo code has expired",
|
"expired": "Promo code has expired",
|
||||||
|
"inactive": "Promo code is deactivated",
|
||||||
|
"not_yet_valid": "Promo code is not yet active",
|
||||||
"used": "Promo code has already been used",
|
"used": "Promo code has already been used",
|
||||||
"already_used_by_user": "You have already used this promo code",
|
"already_used_by_user": "You have already used this promo code",
|
||||||
"user_not_found": "User not found",
|
"user_not_found": "User not found",
|
||||||
|
|||||||
@@ -524,6 +524,8 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"not_found": "کد تخفیف یافت نشد",
|
"not_found": "کد تخفیف یافت نشد",
|
||||||
"expired": "کد تخفیف منقضی شده",
|
"expired": "کد تخفیف منقضی شده",
|
||||||
|
"inactive": "کد تخفیف غیرفعال شده",
|
||||||
|
"not_yet_valid": "کد تخفیف هنوز فعال نشده",
|
||||||
"used": "کد تخفیف قبلاً استفاده شده",
|
"used": "کد تخفیف قبلاً استفاده شده",
|
||||||
"already_used_by_user": "شما قبلاً از این کد استفاده کردهاید",
|
"already_used_by_user": "شما قبلاً از این کد استفاده کردهاید",
|
||||||
"user_not_found": "کاربر یافت نشد",
|
"user_not_found": "کاربر یافت نشد",
|
||||||
|
|||||||
@@ -705,6 +705,8 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"not_found": "Промокод не найден",
|
"not_found": "Промокод не найден",
|
||||||
"expired": "Срок действия промокода истёк",
|
"expired": "Срок действия промокода истёк",
|
||||||
|
"inactive": "Промокод деактивирован",
|
||||||
|
"not_yet_valid": "Промокод ещё не начал действовать",
|
||||||
"used": "Промокод уже использован",
|
"used": "Промокод уже использован",
|
||||||
"already_used_by_user": "Вы уже использовали этот промокод",
|
"already_used_by_user": "Вы уже использовали этот промокод",
|
||||||
"user_not_found": "Пользователь не найден",
|
"user_not_found": "Пользователь не найден",
|
||||||
|
|||||||
@@ -524,6 +524,8 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"not_found": "优惠码不存在",
|
"not_found": "优惠码不存在",
|
||||||
"expired": "优惠码已过期",
|
"expired": "优惠码已过期",
|
||||||
|
"inactive": "优惠码已停用",
|
||||||
|
"not_yet_valid": "优惠码尚未生效",
|
||||||
"used": "优惠码已被使用",
|
"used": "优惠码已被使用",
|
||||||
"already_used_by_user": "您已使用过此优惠码",
|
"already_used_by_user": "您已使用过此优惠码",
|
||||||
"user_not_found": "用户不存在",
|
"user_not_found": "用户不存在",
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ const ChevronRightIcon = () => (
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Settings that require SALES_MODE=tariffs to be visible
|
||||||
|
const TARIFF_MODE_SETTINGS = ['MULTI_TARIFF_ENABLED', 'MAX_ACTIVE_SUBSCRIPTIONS'];
|
||||||
|
|
||||||
export default function AdminSettings() {
|
export default function AdminSettings() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -85,9 +88,6 @@ export default function AdminSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings that require SALES_MODE=tariffs to be visible
|
|
||||||
const TARIFF_MODE_SETTINGS = ['MULTI_TARIFF_ENABLED', 'MAX_ACTIVE_SUBSCRIPTIONS'];
|
|
||||||
|
|
||||||
// Check if tariffs mode is active
|
// Check if tariffs mode is active
|
||||||
const isTariffsMode = useMemo(() => {
|
const isTariffsMode = useMemo(() => {
|
||||||
if (!allSettings || !Array.isArray(allSettings)) return false;
|
if (!allSettings || !Array.isArray(allSettings)) return false;
|
||||||
|
|||||||
@@ -177,13 +177,18 @@ export default function Balance() {
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||||
const errorDetail = axiosError.response?.data?.detail || 'server_error';
|
const errorDetail = axiosError.response?.data?.detail || 'server_error';
|
||||||
const errorKey = errorDetail.toLowerCase().includes('not found')
|
const detail = errorDetail.toLowerCase();
|
||||||
|
const errorKey = detail.includes('not found')
|
||||||
? 'not_found'
|
? 'not_found'
|
||||||
: errorDetail.toLowerCase().includes('expired')
|
: detail.includes('deactivated')
|
||||||
|
? 'inactive'
|
||||||
|
: detail.includes('not yet active')
|
||||||
|
? 'not_yet_valid'
|
||||||
|
: detail.includes('expired')
|
||||||
? 'expired'
|
? 'expired'
|
||||||
: errorDetail.toLowerCase().includes('fully used')
|
: detail.includes('fully used')
|
||||||
? 'used'
|
? 'used'
|
||||||
: errorDetail.toLowerCase().includes('already used')
|
: detail.includes('already used')
|
||||||
? 'already_used_by_user'
|
? 'already_used_by_user'
|
||||||
: 'server_error';
|
: 'server_error';
|
||||||
setPromocodeError(t(`balance.promocode.errors.${errorKey}`));
|
setPromocodeError(t(`balance.promocode.errors.${errorKey}`));
|
||||||
|
|||||||
@@ -873,7 +873,7 @@ export default function SubscriptionPurchase() {
|
|||||||
const dailyPrice =
|
const dailyPrice =
|
||||||
tariff.daily_price_kopeks ?? tariff.price_per_day_kopeks ?? 0;
|
tariff.daily_price_kopeks ?? tariff.price_per_day_kopeks ?? 0;
|
||||||
const originalDailyPrice = tariff.original_daily_price_kopeks || 0;
|
const originalDailyPrice = tariff.original_daily_price_kopeks || 0;
|
||||||
if (dailyPrice > 0) {
|
if (dailyPrice > 0 || originalDailyPrice > 0) {
|
||||||
const promoDaily = applyPromoDiscount(
|
const promoDaily = applyPromoDiscount(
|
||||||
dailyPrice,
|
dailyPrice,
|
||||||
originalDailyPrice > dailyPrice ? originalDailyPrice : undefined,
|
originalDailyPrice > dailyPrice ? originalDailyPrice : undefined,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { authApi } from '../api/auth';
|
import { authApi } from '../api/auth';
|
||||||
import { useAuthStore } from '../store/auth';
|
import { useAuthStore } from '../store/auth';
|
||||||
import { useShallow } from 'zustand/shallow';
|
import { useShallow } from 'zustand/shallow';
|
||||||
import { consumeCampaignSlug } from '../utils/campaign';
|
import { consumeCampaignSlug, getPendingCampaignSlug } from '../utils/campaign';
|
||||||
import { tokenStorage } from '../utils/token';
|
import { tokenStorage } from '../utils/token';
|
||||||
import LanguageSwitcher from '../components/LanguageSwitcher';
|
import LanguageSwitcher from '../components/LanguageSwitcher';
|
||||||
|
|
||||||
@@ -39,8 +39,9 @@ export default function VerifyEmail() {
|
|||||||
|
|
||||||
const verify = async () => {
|
const verify = async () => {
|
||||||
try {
|
try {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const response = await authApi.verifyEmail(token, campaignSlug);
|
const response = await authApi.verifyEmail(token, campaignSlug);
|
||||||
|
consumeCampaignSlug();
|
||||||
// Save tokens and log user in
|
// Save tokens and log user in
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
setTokens(response.access_token, response.refresh_token);
|
setTokens(response.access_token, response.refresh_token);
|
||||||
|
|||||||
@@ -3,8 +3,16 @@ import { persist } from 'zustand/middleware';
|
|||||||
import type { CampaignBonusInfo, RegisterResponse, User } from '../types';
|
import type { CampaignBonusInfo, RegisterResponse, User } from '../types';
|
||||||
import { authApi } from '../api/auth';
|
import { authApi } from '../api/auth';
|
||||||
import { apiClient } from '../api/client';
|
import { apiClient } from '../api/client';
|
||||||
import { captureCampaignFromUrl, consumeCampaignSlug } from '../utils/campaign';
|
import {
|
||||||
import { captureReferralFromUrl, consumeReferralCode } from '../utils/referral';
|
captureCampaignFromUrl,
|
||||||
|
consumeCampaignSlug,
|
||||||
|
getPendingCampaignSlug,
|
||||||
|
} from '../utils/campaign';
|
||||||
|
import {
|
||||||
|
captureReferralFromUrl,
|
||||||
|
consumeReferralCode,
|
||||||
|
getPendingReferralCode,
|
||||||
|
} from '../utils/referral';
|
||||||
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
|
import { tokenStorage, isTokenValid, tokenRefreshManager } from '../utils/token';
|
||||||
import { usePermissionStore } from './permissions';
|
import { usePermissionStore } from './permissions';
|
||||||
|
|
||||||
@@ -241,9 +249,12 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithTelegram: async (initData) => {
|
loginWithTelegram: async (initData) => {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const referralCode = consumeReferralCode();
|
const referralCode = getPendingReferralCode();
|
||||||
const response = await authApi.loginTelegram(initData, campaignSlug, referralCode);
|
const response = await authApi.loginTelegram(initData, campaignSlug, referralCode);
|
||||||
|
// Clear only after successful auth — retry keeps the slugs
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
accessToken: response.access_token,
|
accessToken: response.access_token,
|
||||||
@@ -256,9 +267,11 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithTelegramWidget: async (data) => {
|
loginWithTelegramWidget: async (data) => {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const referralCode = consumeReferralCode();
|
const referralCode = getPendingReferralCode();
|
||||||
const response = await authApi.loginTelegramWidget(data, campaignSlug, referralCode);
|
const response = await authApi.loginTelegramWidget(data, campaignSlug, referralCode);
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
accessToken: response.access_token,
|
accessToken: response.access_token,
|
||||||
@@ -271,9 +284,11 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithTelegramOIDC: async (idToken) => {
|
loginWithTelegramOIDC: async (idToken) => {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const referralCode = consumeReferralCode();
|
const referralCode = getPendingReferralCode();
|
||||||
const response = await authApi.loginTelegramOIDC(idToken, campaignSlug, referralCode);
|
const response = await authApi.loginTelegramOIDC(idToken, campaignSlug, referralCode);
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
accessToken: response.access_token,
|
accessToken: response.access_token,
|
||||||
@@ -286,9 +301,11 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithEmail: async (email, password) => {
|
loginWithEmail: async (email, password) => {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const referralCode = consumeReferralCode();
|
const referralCode = getPendingReferralCode();
|
||||||
const response = await authApi.loginEmail(email, password, campaignSlug, referralCode);
|
const response = await authApi.loginEmail(email, password, campaignSlug, referralCode);
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
accessToken: response.access_token,
|
accessToken: response.access_token,
|
||||||
@@ -301,8 +318,8 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithOAuth: async (provider, code, state, deviceId) => {
|
loginWithOAuth: async (provider, code, state, deviceId) => {
|
||||||
const campaignSlug = consumeCampaignSlug();
|
const campaignSlug = getPendingCampaignSlug();
|
||||||
const referralCode = consumeReferralCode();
|
const referralCode = getPendingReferralCode();
|
||||||
const response = await authApi.oauthCallback(
|
const response = await authApi.oauthCallback(
|
||||||
provider,
|
provider,
|
||||||
code,
|
code,
|
||||||
@@ -311,6 +328,8 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
campaignSlug,
|
campaignSlug,
|
||||||
referralCode,
|
referralCode,
|
||||||
);
|
);
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
accessToken: response.access_token,
|
accessToken: response.access_token,
|
||||||
@@ -339,7 +358,7 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
registerWithEmail: async (email, password, firstName, referralCode) => {
|
registerWithEmail: async (email, password, firstName, referralCode) => {
|
||||||
const code = referralCode || consumeReferralCode() || undefined;
|
const code = referralCode || getPendingReferralCode() || undefined;
|
||||||
const response = await authApi.registerEmailStandalone({
|
const response = await authApi.registerEmailStandalone({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
@@ -347,6 +366,7 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
language: navigator.language.split('-')[0] || 'ru',
|
language: navigator.language.split('-')[0] || 'ru',
|
||||||
referral_code: code,
|
referral_code: code,
|
||||||
});
|
});
|
||||||
|
consumeReferralCode();
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user