Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import React from 'react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import { GivebackImpactPanel } from './GivebackImpactPanel';
import { useContributionStatus } from '../hooks/useContributionStatus';
import { useContributionSponsors } from '../hooks/useContributionSponsors';
import { useGivebackContribution } from '../hooks/useGivebackContribution';
import { useContributionRewards } from '../hooks/useContributionRewards';
import { useContributionUserRewards } from '../hooks/useContributionUserRewards';
import { useClaimContributionReward } from '../hooks/useClaimContributionReward';
import { useContributionCausePicker } from '../hooks/useContributionCausePicker';
import { useContributionActions } from '../hooks/useContributionActions';
import { useLogContext } from '../../../contexts/LogContext';
import { useAuthContext } from '../../../contexts/AuthContext';
import { LogEvent } from '../../../lib/log';
import { ContributionRewardType, type ContributionRewardTier } from '../types';

jest.mock('../hooks/useContributionStatus');
jest.mock('../hooks/useContributionSponsors');
jest.mock('../hooks/useGivebackContribution');
jest.mock('../hooks/useContributionRewards');
jest.mock('../hooks/useContributionUserRewards');
jest.mock('../hooks/useClaimContributionReward');
jest.mock('../hooks/useContributionCausePicker');
jest.mock('../hooks/useContributionActions');
jest.mock('../../../contexts/LogContext');
jest.mock('../../../contexts/AuthContext');

// Resolve the reveal/count-up animations synchronously so assertions read final
// values, not mid-animation frames.
Expand All @@ -26,12 +28,6 @@ jest.mock('../useGivebackMotion', () => ({
useCountUp: (target: number) => target,
}));

const mockStatus = useContributionStatus as jest.MockedFunction<
typeof useContributionStatus
>;
const mockSponsors = useContributionSponsors as jest.MockedFunction<
typeof useContributionSponsors
>;
const mockContribution = useGivebackContribution as jest.MockedFunction<
typeof useGivebackContribution
>;
Expand All @@ -44,7 +40,14 @@ const mockUserRewards = useContributionUserRewards as jest.MockedFunction<
const mockClaim = useClaimContributionReward as jest.MockedFunction<
typeof useClaimContributionReward
>;
const mockCausePicker = useContributionCausePicker as jest.MockedFunction<
typeof useContributionCausePicker
>;
const mockActions = useContributionActions as jest.MockedFunction<
typeof useContributionActions
>;
const mockLog = useLogContext as jest.MockedFunction<typeof useLogContext>;
const mockAuth = useAuthContext as jest.MockedFunction<typeof useAuthContext>;
const logEvent = jest.fn();

const tiers: ContributionRewardTier[] = [
Expand Down Expand Up @@ -73,20 +76,6 @@ const tiers: ContributionRewardTier[] = [

beforeEach(() => {
jest.clearAllMocks();
mockStatus.mockReturnValue({
status: {
enabled: true,
eligible: true,
currentCyclePoints: 4000,
currentCycleTargetPoints: 10000,
lifetimePoints: 0,
lifetimeAmountCents: 0,
contributorsCount: 128,
userPoints: 40,
},
isPending: false,
});
mockSponsors.mockReturnValue({ sponsors: [], isPending: false });
mockContribution.mockReturnValue({
earnedPoints: 40,
nextReward: tiers[1],
Expand All @@ -102,36 +91,43 @@ beforeEach(() => {
claim: jest.fn().mockResolvedValue(undefined),
isPending: false,
});
mockCausePicker.mockReturnValue({
causes: [],
selectedCauseIds: [],
isPending: false,
});
mockActions.mockReturnValue({
actions: [],
categories: [],
rewardTiers: [],
claimedRewardIds: [],
isPending: false,
});
mockLog.mockReturnValue({ logEvent } as unknown as ReturnType<
typeof useLogContext
>);
});

it('renders the funding progress section with live totals', () => {
render(<GivebackImpactPanel onTakeAction={jest.fn()} />);

expect(screen.getByText('Funding progress')).toBeInTheDocument();
expect(screen.getByText('$4,000')).toBeInTheDocument();
expect(screen.getByText('128')).toBeInTheDocument();
mockAuth.mockReturnValue({ user: null } as unknown as ReturnType<
typeof useAuthContext
>);
});

it('renders the reward-ladder journey with the current level', () => {
render(<GivebackImpactPanel onTakeAction={jest.fn()} />);

expect(screen.getByText('Your journey')).toBeInTheDocument();
expect(screen.getByText(/for causes you love/)).toBeInTheDocument();
expect(screen.getByText('Sticker pack')).toBeInTheDocument();
expect(screen.getByText('One month of Plus')).toBeInTheDocument();
expect(screen.getByText('Hoodie')).toBeInTheDocument();
// $40 earned: the next milestone is the $100 tier.
expect(screen.getByText('Next up: One month of Plus')).toBeInTheDocument();
expect(screen.getByText('$60 to your next reward')).toBeInTheDocument();
expect(screen.getByText('$60 to go')).toBeInTheDocument();
});

it('offers a claim for an unlocked, unclaimed tier and logs it', async () => {
render(<GivebackImpactPanel onTakeAction={jest.fn()} />);

// The $25 tier is reached at $40 and not yet claimed.
const claimButton = screen.getByRole('button', { name: 'Claim' });
const claimButton = screen.getByRole('button', { name: /Claim reward/ });
expect(claimButton).toBeInTheDocument();
expect(screen.getByText(/ready to claim/)).toBeInTheDocument();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import type { ReactElement } from 'react';
import React from 'react';
import { FlexCol } from '../../../components/utilities';
import { GivebackCommunityGoalProgress } from './GivebackCommunityGoalProgress';
import { GivebackPersonalRoadmap } from './GivebackPersonalRoadmap';

interface GivebackImpactPanelProps {
onTakeAction: () => void;
}

// The Impact tab: the campaign's funding progress (community pot + sponsors)
// followed by the visitor's own reward-ladder journey. The leaderboard and live
// community feed from the design are intentionally skipped — the campaign starts
// from scratch, so the social-proof half stays funding + personal progress.
// The Impact tab: the visitor's own reward-ladder journey through the campaign.
export const GivebackImpactPanel = ({
onTakeAction,
}: GivebackImpactPanelProps): ReactElement => (
<FlexCol className="gap-12">
<GivebackCommunityGoalProgress />
<div className="border-t border-border-subtlest-tertiary pt-12">
<GivebackPersonalRoadmap onTakeAction={onTakeAction} />
</div>
<GivebackPersonalRoadmap onTakeAction={onTakeAction} />
</FlexCol>
);
Loading
Loading