Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { WaveSmallLeaderboardItemOutcomes } from '@/components/waves/small-leaderboard/WaveSmallLeaderboardItemOutcomes';
import { ApiWaveOutcomeCredit } from '@/generated/models/ApiWaveOutcomeCredit';
import { ApiWaveOutcomeType } from '@/generated/models/ApiWaveOutcomeType';

const mockUseWaveRankReward = jest.fn();

jest.mock('@/hooks/waves/useWaveRankReward', () => ({
useWaveRankReward: (args: any) => mockUseWaveRankReward(args),
}));

describe('WaveSmallLeaderboardItemOutcomes', () => {
const drop: any = { rank: 1 };
const wave: any = {
outcomes: [
{ credit: ApiWaveOutcomeCredit.Cic, distribution: [{ amount: 1 }] },
{ credit: ApiWaveOutcomeCredit.Rep, distribution: [{ amount: 2 }] },
{ type: ApiWaveOutcomeType.Manual, distribution: [{ amount: 1, description: 'Award' }] },
],
};
const drop: any = { rank: 1, wave: { id: 'w1' } };

beforeEach(() => {
mockUseWaveRankReward.mockReset();
});

it('renders button when outcomes exist', () => {
render(<WaveSmallLeaderboardItemOutcomes drop={drop} wave={wave} />);
mockUseWaveRankReward.mockReturnValue({
nicTotal: 10,
repTotal: 20,
manualOutcomes: ['Award'],
isLoading: false
});

render(<WaveSmallLeaderboardItemOutcomes drop={drop} />);
expect(screen.getByRole('button')).toBeInTheDocument();
expect(screen.getByText('Outcome:')).toBeInTheDocument();
});

it('hides when no outcomes', () => {
const waveEmpty = { outcomes: [] } as any;
const { container } = render(<WaveSmallLeaderboardItemOutcomes drop={drop} wave={waveEmpty} />);
it('hides when no outcomes and not loading', () => {
mockUseWaveRankReward.mockReturnValue({
nicTotal: 0,
repTotal: 0,
manualOutcomes: [],
isLoading: false
});

const { container } = render(<WaveSmallLeaderboardItemOutcomes drop={drop} />);
expect(container.firstChild).toBeNull();
});

it('shows loading state', () => {
mockUseWaveRankReward.mockReturnValue({
nicTotal: 0,
repTotal: 0,
manualOutcomes: [],
isLoading: true
});
const { container } = render(<WaveSmallLeaderboardItemOutcomes drop={drop} />);
expect(container.querySelector('.tw-animate-pulse')).toBeInTheDocument();
});
});
1 change: 1 addition & 0 deletions components/react-query-wrapper/ReactQueryWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export enum QueryKey {
WAVE_DECISIONS = "WAVE_DECISIONS",
WAVE_OUTCOMES = "WAVE_OUTCOMES",
WAVE_OUTCOME_DISTRIBUTION = "WAVE_OUTCOME_DISTRIBUTION",
WAVE_OUTCOME_DISTRIBUTION_PAGE = "WAVE_OUTCOME_DISTRIBUTION_PAGE",
}

interface InitProfileRatersParamsAndData {
Expand Down
2 changes: 1 addition & 1 deletion components/waves/drop/SingleWaveDropInfoAuthorSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const SingleWaveDropInfoAuthorSection: React.FC<
</div>
</div>
{wave && drop && (
<WaveSmallLeaderboardItemOutcomes drop={drop} wave={wave} />
<WaveSmallLeaderboardItemOutcomes drop={drop} />
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ interface WaveLeaderboardDropFooterProps {

export const WaveLeaderboardDropFooter: React.FC<
WaveLeaderboardDropFooterProps
> = ({ drop, wave }) => {
return <WaveSmallLeaderboardItemOutcomes drop={drop} wave={wave} />;
> = ({ drop }) => {
return <WaveSmallLeaderboardItemOutcomes drop={drop} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface WaveSmallLeaderboardDefaultDropProps {

export const WaveSmallLeaderboardDefaultDrop: React.FC<
WaveSmallLeaderboardDefaultDropProps
> = ({ drop, wave, onDropClick }) => {
> = ({ drop, onDropClick }) => {
const getCICColor = (cic: number): string => {
const cicType = cicToType(cic);
switch (cicType) {
Expand Down Expand Up @@ -129,7 +129,7 @@ export const WaveSmallLeaderboardDefaultDrop: React.FC<
/>
</div>
<div className="tw-mt-3">
<WaveSmallLeaderboardItemOutcomes drop={drop} wave={wave} />
<WaveSmallLeaderboardItemOutcomes drop={drop} />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,97 +5,17 @@ import { Tooltip } from "react-tooltip";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAddressCard, faStar } from "@fortawesome/free-regular-svg-icons";
import { faAward } from "@fortawesome/free-solid-svg-icons";

import { ApiWave } from "@/generated/models/ApiWave";
import { ApiWaveOutcomeCredit } from "@/generated/models/ApiWaveOutcomeCredit";
import { ApiWaveOutcomeType } from "@/generated/models/ApiWaveOutcomeType";
import { ApiDrop } from "@/generated/models/ApiDrop";
import { useWaveRankReward } from "@/hooks/waves/useWaveRankReward";

interface WaveSmallLeaderboardItemOutcomesProps {
readonly drop: ApiDrop;
readonly wave: ApiWave;
readonly isMobile?: boolean;
}

interface OutcomeSummary {
nicTotal: number;
repTotal: number;
manualOutcomes: string[];
}

const calculateNIC = ({
drop,
wave,
}: {
drop: ApiDrop;
wave: ApiWave;
}): number => {
const rank = drop.rank;
if (!rank) return 0;
const outcomes = wave.outcomes;
const nicOutcomes = outcomes.filter(
(outcome) => outcome.credit === ApiWaveOutcomeCredit.Cic
);
const nic = nicOutcomes.reduce((acc, outcome) => {
return acc + (outcome.distribution?.[rank - 1]?.amount ?? 0);
}, 0);
return nic;
};

const calculateRep = ({
drop,
wave,
}: {
drop: ApiDrop;
wave: ApiWave;
}): number => {
const rank = drop.rank;
if (!rank) return 0;
const outcomes = wave.outcomes;
const repOutcomes = outcomes.filter(
(outcome) => outcome.credit === ApiWaveOutcomeCredit.Rep
);
const rep = repOutcomes.reduce((acc, outcome) => {
return acc + (outcome.distribution?.[rank - 1]?.amount ?? 0);
}, 0);
return rep;
};

const calculateManualOutcomes = ({
drop,
wave,
}: {
drop: ApiDrop;
wave: ApiWave;
}): string[] => {
const rank = drop.rank;
if (!rank) return [];
const outcomes = wave.outcomes;
const manualOutcomes = outcomes.filter(
(outcome) => outcome.type === ApiWaveOutcomeType.Manual
);
return manualOutcomes
.filter((outcome) => !!outcome.distribution?.[rank - 1]?.amount)
.map((outcome) => outcome.distribution?.[rank - 1]?.description ?? "");
};

const calculateOutcomeSummary = ({
drop,
wave,
}: {
drop: ApiDrop;
wave: ApiWave;
}): OutcomeSummary => {
return {
nicTotal: calculateNIC({ drop, wave }),
repTotal: calculateRep({ drop, wave }),
manualOutcomes: calculateManualOutcomes({ drop, wave }),
};
};

export const WaveSmallLeaderboardItemOutcomes: React.FC<
WaveSmallLeaderboardItemOutcomesProps
> = ({ drop, wave, isMobile = false }) => {
> = ({ drop, isMobile = false }) => {
const [isTouch, setIsTouch] = useState(false);
const [isOpen, setIsOpen] = useState(false);

Expand All @@ -110,17 +30,24 @@ export const WaveSmallLeaderboardItemOutcomes: React.FC<
}
};

const { nicTotal, repTotal, manualOutcomes } = calculateOutcomeSummary({
drop,
wave,
const { nicTotal, repTotal, manualOutcomes, isLoading } = useWaveRankReward({
waveId: drop.wave.id,
rank: drop.rank,
});
Comment thread
simo6529 marked this conversation as resolved.

const totalOutcomes =
(nicTotal ? 1 : 0) + (repTotal ? 1 : 0) + manualOutcomes.length;

if (totalOutcomes === 0) {
if (totalOutcomes === 0 && !isLoading) {
return null;
}

if (isLoading) {
return (
<div className={`tw-animate-pulse tw-h-6 tw-w-16 tw-bg-iron-800 tw-rounded-lg`} />
)
}

const tooltipContent = (
<div className="tw-p-3 tw-space-y-3 tw-min-w-[200px]">
<div className="tw-space-y-2">
Expand Down Expand Up @@ -184,11 +111,9 @@ export const WaveSmallLeaderboardItemOutcomes: React.FC<
<>
<button
onClick={handleClick}
className={`tw-border-0 tw-rounded-lg tw-flex tw-items-center ${
isMobile ? "tw-gap-4" : "tw-gap-2"
} tw-min-w-6 tw-py-1.5 tw-px-2 tw-bg-iron-800 tw-ring-1 tw-ring-iron-700 ${
isTouch ? "tw-cursor-pointer" : ""
}`}
className={`tw-border-0 tw-rounded-lg tw-flex tw-items-center ${isMobile ? "tw-gap-4" : "tw-gap-2"
} tw-min-w-6 tw-py-1.5 tw-px-2 tw-bg-iron-800 tw-ring-1 tw-ring-iron-700 ${isTouch ? "tw-cursor-pointer" : ""
}`}
data-tooltip-id={`wave-outcomes-${drop.id}`}>
<span className="tw-text-xs tw-font-medium tw-text-iron-200">
Outcome:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ interface WaveSmallLeaderboardTopThreeDropProps {

export const WaveSmallLeaderboardTopThreeDrop: React.FC<
WaveSmallLeaderboardTopThreeDropProps
> = ({ drop, wave, onDropClick }) => {
const getPFPColor = (rank: number | null): string | null => {
return null;
};
> = ({ drop, onDropClick }) => {

const getRankTextColor = (rank: number | null): string | null => {
if (rank === 1) return "tw-text-[#E8D48A]";
Expand Down Expand Up @@ -67,32 +64,28 @@ export const WaveSmallLeaderboardTopThreeDrop: React.FC<
className="tw-@container tw-rounded-xl tw-bg-iron-900 tw-p-4 tw-relative desktop-hover:hover:tw-bg-iron-800/80 tw-transition-all tw-duration-300 tw-ease-out"
style={{
border: "1px solid transparent",
boxShadow: `inset 2px 0 0 ${
drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)?.replace("tw-text-", "").trim()
boxShadow: `inset 2px 0 0 ${drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)?.replace("tw-text-", "").trim()
: "#60606C"
},
inset 0 1px 0 ${drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
}20,
inset -1px 0 0 ${drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
}20,
inset 0 -1px 0 ${drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
},
inset 0 1px 0 ${
drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
}20,
inset -1px 0 0 ${
drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
}20,
inset 0 -1px 0 ${
drop.rank && drop.rank <= 3
? getRankTextColor(drop.rank)
?.replace("tw-text-", "")
.trim()
: "#60606C"
}20`,
}20`,
transition: "box-shadow 0.2s ease, background-color 0.2s ease",
}}
>
Expand Down Expand Up @@ -168,7 +161,7 @@ export const WaveSmallLeaderboardTopThreeDrop: React.FC<
/>
</div>
<div className="tw-mt-3">
<WaveSmallLeaderboardItemOutcomes drop={drop} wave={wave} />
<WaveSmallLeaderboardItemOutcomes drop={drop} />
</div>
</div>
</div>
Expand Down
Loading