diff --git a/src/app/banners/BannerManager.test.ts b/src/app/banners/BannerManager.test.ts index 29f48f398..e399db699 100644 --- a/src/app/banners/BannerManager.test.ts +++ b/src/app/banners/BannerManager.test.ts @@ -117,3 +117,162 @@ describe('BannerManager - showFreeBanner', () => { expect(result.showFreeBanner).toBe(false); }); }); + +describe('BannerManager - showSubscriptionBanner', () => { + const today = new Date('2025-06-01'); + + beforeAll(() => { + vi.useFakeTimers(); + vi.setSystemTime(today); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + const mockUser: UserSettings = { + userId: '1', + uuid: 'uuid-1', + email: 'test@example.com', + name: 'Test', + lastname: 'User', + username: 'testuser', + bridgeUser: '', + bucket: '', + backupsBucket: null, + root_folder_id: 1, + rootFolderId: 'folder', + rootFolderUuid: 'folder-uuid', + sharedWorkspace: false, + credit: 0, + mnemonic: '', + privateKey: '', + publicKey: '', + revocationKey: '', + keys: { + ecc: { publicKey: '', privateKey: '' }, + kyber: { publicKey: '', privateKey: '' }, + }, + teams: false, + appSumoDetails: null, + registerCompleted: true, + hasReferralsProgram: false, + createdAt: today, + avatar: null, + emailVerified: true, + }; + + const validPlanForSubscription: PlanState = { + isLoadingPlanLimit: false, + isLoadingPlanUsage: false, + isLoadingBusinessLimitAndUsage: false, + individualPlan: { + planId: 'price_1PNxYtFAOdcgaBMQzkimr6OU', + productId: 'product-id', + name: 'Plan', + simpleName: 'Pro', + paymentInterval: RenewalPeriod.Monthly, + price: 0, + monthlyPrice: 0, + currency: 'eur', + isTeam: false, + isLifetime: false, + renewalPeriod: RenewalPeriod.Monthly, + storageLimit: 0, + amountOfSeats: 1, + seats: { minimumSeats: 1, maximumSeats: 1 }, + }, + businessPlan: null, + planLimit: 0, + planUsage: 0, + usageDetails: null, + individualSubscription: { + type: 'subscription', + subscriptionId: 'sub-123', + amount: 999, + currency: 'eur', + interval: 'month', + nextPayment: Date.now(), + priceId: 'price_1PNxYtFAOdcgaBMQzkimr6OU', + }, + businessSubscription: null, + businessPlanLimit: 0, + businessPlanUsage: 0, + businessPlanUsageDetails: null, + }; + + const invalidPlan: PlanState = { + isLoadingPlanLimit: false, + isLoadingPlanUsage: false, + isLoadingBusinessLimitAndUsage: false, + individualPlan: { + planId: 'invalid-plan-id', + productId: 'product-id', + name: 'Plan', + simpleName: 'Free', + paymentInterval: RenewalPeriod.Monthly, + price: 0, + monthlyPrice: 0, + currency: 'eur', + isTeam: false, + isLifetime: false, + renewalPeriod: RenewalPeriod.Monthly, + storageLimit: 0, + amountOfSeats: 1, + seats: { minimumSeats: 1, maximumSeats: 1 }, + }, + businessPlan: null, + planLimit: 0, + planUsage: 0, + usageDetails: null, + individualSubscription: { type: 'free' }, + businessSubscription: null, + businessPlanLimit: 0, + businessPlanUsage: 0, + businessPlanUsageDetails: null, + }; + + const futureDate = new Date('2025-06-10'); + + beforeEach(() => { + vi.clearAllMocks(); + vi.resetModules(); + }); + + it('returns true when user has a valid subscription plan', () => { + (localStorageService.get as Mock).mockReturnValue(''); + + const manager = new BannerManager(mockUser, validPlanForSubscription, futureDate); + const result = manager.getBannersToShow(); + + expect(result.showSubscriptionBanner).toBe(true); + }); + + it('returns false when user does not have a valid subscription plan', () => { + (localStorageService.get as Mock).mockReturnValue(''); + + const manager = new BannerManager(mockUser, invalidPlan, futureDate); + const result = manager.getBannersToShow(); + + expect(result.showSubscriptionBanner).toBe(false); + }); + + it('returns true for different valid plan IDs', () => { + const planWithDifferentId: PlanState = { + ...validPlanForSubscription, + individualPlan: validPlanForSubscription.individualPlan + ? { + ...validPlanForSubscription.individualPlan, + planId: 'price_1OQ3MDFAOdcgaBMQ3he4Xqed', + } + : null, + }; + + (localStorageService.get as Mock).mockReturnValue(''); + + const manager = new BannerManager(mockUser, planWithDifferentId, futureDate); + const result = manager.getBannersToShow(); + + expect(result.showSubscriptionBanner).toBe(true); + }); +}); diff --git a/src/app/banners/BannerWrapper.tsx b/src/app/banners/BannerWrapper.tsx index 8ae72ffec..8fa714935 100644 --- a/src/app/banners/BannerWrapper.tsx +++ b/src/app/banners/BannerWrapper.tsx @@ -1,12 +1,12 @@ import { RootState } from '../store'; import { PlanState } from '../store/slices/plan'; import { useSelector } from 'react-redux'; - import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings'; import { BannerManager } from './BannerManager'; import { useEffect, useMemo, useState } from 'react'; import { userSelectors } from 'app/store/slices/user'; import FeaturesBanner from './FeaturesBanner'; +import newStorageService from 'app/drive/services/new-storage.service'; const OFFER_END_DAY = new Date('2026-01-26'); const TIMEOUT = 90000; @@ -15,17 +15,26 @@ const BannerWrapper = (): JSX.Element => { const user = useSelector((state: RootState) => state.user.user) as UserSettings; const plan = useSelector((state) => state.plan); const isNewAccount = useSelector((state: RootState) => userSelectors.hasSignedToday(state)); - const bannerManager = useMemo(() => new BannerManager(user, plan, OFFER_END_DAY), [user, plan, isNewAccount]); - const [bannersToShow, setBannersToShow] = useState({ showFreeBanner: false, showSubscriptionBanner: false }); const [showDelayedBanner, setShowDelayedBanner] = useState(false); + const [hasUploadedFirstFile, setHasUploadedFirstFile] = useState(false); useEffect(() => { - const timeout = setTimeout(() => setShowDelayedBanner(true), TIMEOUT); - return () => clearTimeout(timeout); + newStorageService.hasUploadedFiles().then(({ hasUploadedFiles }) => { + if (hasUploadedFiles) { + setHasUploadedFirstFile(true); + } + }); }, []); + useEffect(() => { + if (hasUploadedFirstFile) { + const timeout = setTimeout(() => setShowDelayedBanner(true), TIMEOUT); + return () => clearTimeout(timeout); + } + }, [hasUploadedFirstFile]); + useEffect(() => { const newBanners = bannerManager.getBannersToShow(); setBannersToShow(() => ({