Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active contests cards on home page #10468

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const NewProposalPage = lazy(() => import('views/pages/new_proposal/index'));
const DiscussionsPage = lazy(
() => import('views/pages/discussions/DiscussionsPage'),
);
const CommunityHomePage = lazy(
() => import('../views/pages/CommunityHome/CommunityHomePage'),
);
const ViewThreadPage = lazy(
() => import('../views/pages/view_thread/ViewThreadPage'),
);
Expand Down Expand Up @@ -317,6 +320,13 @@ const CommonDomainRoutes = ({
// GOVERNANCE END

// DISCUSSIONS
<Route
key="/:scope/community-home"
path="/:scope/community-home"
element={withLayout(CommunityHomePage, {
scoped: true,
})}
/>,
<Route
key="/:scope/discussions"
path="/:scope/discussions"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export const DiscussionSection = ({
location,
);

const matchesCommunityHomeRoute = matchRoutes(
[{ path: ':scope/community-home' }],
location,
);

const matchesArchivedRoute = matchRoutes(
[{ path: '/archived' }, { path: ':scope/archived' }],
location,
Expand Down Expand Up @@ -113,6 +118,31 @@ export const DiscussionSection = ({
localStorage[`${app.activeChainId()}-discussions-toggle-tree`],
);
const discussionsGroupData: SectionGroupAttrs[] = [
{
title: 'Community Home',
containsChildren: false,
hasDefaultToggle: false,
isVisible: true,
isUpdated: true,
isActive: !!matchesCommunityHomeRoute,
onClick: (e, toggle: boolean) => {
e.preventDefault();
resetSidebarState();
handleRedirectClicks(
navigate,
e,
`/community-home`,
communityId,
() => {
setDiscussionsToggleTree(
`children.CommunityHome.toggledState`,
toggle,
);
},
);
},
displayData: null,
},
{
title: 'All',
containsChildren: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@import '../../../../../styles/shared';

.ActiveContestCard {
border-radius: 6px;
padding: 16px;
border: 1px solid $neutral-100;
background: $white;
display: flex;
flex-direction: column;

&:hover {
box-shadow: $elevation-2;
}

.contest-banner {
border-radius: 6px;
height: 160px;

.banner-image {
border-radius: 6px;
width: 100%;
height: 100%;
object-fit: cover;
}
}

.contest-content {
padding-block: 4px;
flex: 1;
display: flex;
flex-direction: column;

.contest-header {
display: flex;
align-items: center;

gap: 8px;
margin-bottom: 8px;
position: relative;

.contest-title {
@include multiline-text-ellipsis(1);
}

.contest-icon-container {
position: absolute;
background: $white;
border-radius: 50%;
right: 8px;
top: -20px;
width: 30px;
height: 30px;

.contest-icon {
width: 100%;
height: 100%;

&.common-icon {
padding: 2px;
}
}
}
}

.contest-timing {
margin-bottom: 16px;
}

.prizes-section {
margin-bottom: 16px;

.prize-list {
margin-top: 8px;

.prize-row {
display: flex;
justify-content: space-between;

.label {
color: $neutral-600;
}
}
}
}

.contest-actions {
display: flex;
gap: 16px;
margin-bottom: 16px;
}

.cta-button-container {
display: flex;
align-items: center;
height: 40px;
margin-top: auto;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import clsx from 'clsx';
import moment from 'moment';
import React from 'react';

import commonLogo from 'assets/img/branding/common.svg';
import farcasterUrl from 'assets/img/farcaster.svg';
import { navigateToCommunity, useCommonNavigate } from 'navigation/helpers';
import { useGetContestBalanceQuery } from 'state/api/contests';
import { Skeleton } from 'views/components/Skeleton';
import { CWCommunityAvatar } from 'views/components/component_kit/cw_community_avatar';
import { capDecimals } from 'views/modals/ManageCommunityStakeModal/utils';

import { CWText } from '../../../../components/component_kit/cw_text';
import { CWButton } from '../../../../components/component_kit/new_designs/CWButton/CWButton';
import { CWThreadAction } from '../../../../components/component_kit/new_designs/cw_thread_action';
import { Contest } from '../../../CommunityManagement/Contests/ContestsList';
import ContestCountdown from '../../../CommunityManagement/Contests/ContestsList/ContestCountdown';

import './ActiveContestCard.scss';

interface ActiveContestCardProps {
contest: Contest;
community: {
name: string;
iconUrl: string;
chainNodeUrl: string;
ethChainId: number;
};
}

const ActiveContestCard = ({ contest, community }: ActiveContestCardProps) => {
const navigate = useCommonNavigate();
const finishDate = moment(contest.contests?.[0].end_time).toISOString();

const { data: contestBalance, isLoading: isContestBalanceLoading } =
useGetContestBalanceQuery({
contestAddress: contest.contest_address || '',
chainRpc: community.chainNodeUrl,
ethChainId: community.ethChainId,
isOneOff: !!contest.funding_token_address,
apiEnabled: Boolean(
contest.contest_address &&
community.chainNodeUrl &&
community.ethChainId,
),
});

const prizes =
contestBalance && contest.payout_structure
? contest.payout_structure.map(
(percentage) =>
(contestBalance * (percentage / 100)) /
Math.pow(10, contest.decimals || 18),
)
: [];

const handleGoToContest = () => {
const path = contest.is_farcaster_contest
? `/contests/${contest.contest_address}`
: `/discussions/${contest.topics?.[0]?.name}`;

navigateToCommunity({
navigate,
path,
chain: contest.community_id || '',
});
};

const handleLeaderboardClick = () => {
const path = contest.is_farcaster_contest
? `/contests/${contest.contest_address}`
: `/discussions?featured=mostLikes&contest=${contest.contest_address}`;

navigateToCommunity({
navigate,
path,
chain: contest.community_id || '',
});
};

return (
<div className="ActiveContestCard">
<div className="contest-banner">
<img
src={contest.image_url}
alt="Contest banner"
className="banner-image"
/>
</div>

<div className="contest-content">
<div className="contest-header">
<CWCommunityAvatar
onClick={() => {
navigateToCommunity({
navigate,
path: '',
chain: contest.community_id || '',
});
}}
community={{
name: community.name,
iconUrl: community.iconUrl,
}}
/>

<CWText type="h3" fontWeight="medium" className="contest-title">
{contest.name}
<div className="contest-icon-container">
<img
className={clsx(
'contest-icon',
!contest.is_farcaster_contest && 'common-icon',
)}
src={contest.is_farcaster_contest ? farcasterUrl : commonLogo}
/>
</div>
</CWText>
</div>

<div className="contest-timing">
<ContestCountdown finishTime={finishDate} isActive />
</div>

<div className="prizes-section">
<CWText type="b2" fontWeight="medium">
Current Prizes
</CWText>
<div className="prize-list">
{isContestBalanceLoading ? (
<>
<Skeleton width="100%" height="20px" />
<Skeleton width="100%" height="20px" />
<Skeleton width="100%" height="20px" />
</>
) : prizes.length > 0 ? (
prizes?.map((prize, index) => (
<div className="prize-row" key={index}>
<CWText className="label">
{moment.localeData().ordinal(index + 1)} Prize
</CWText>
<CWText fontWeight="bold">
{capDecimals(String(prize))} {contest.ticker}
</CWText>
</div>
))
) : (
<CWText type="b2">No prizes available</CWText>
)}
</div>
</div>

<div className="contest-actions">
<CWThreadAction
action="leaderboard"
label="Leaderboard"
onClick={handleLeaderboardClick}
/>
</div>

<div className="cta-button-container">
<CWButton
buttonHeight="sm"
buttonWidth="full"
label="Go to contest"
buttonType="secondary"
buttonAlt="green"
className="cta-button"
onClick={handleGoToContest}
/>
</div>
</div>
</div>
);
};

export default ActiveContestCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ActiveContestCard from './ActiveContestCard';

export default ActiveContestCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@import '../../../../styles/shared';

.ActiveContestList {
margin: 16px 0;

.content {
display: grid;
grid-gap: 28px;
grid-template-columns: 1fr 1fr;
justify-content: center;
margin: 24px 0;

@include extraSmall {
grid-template-columns: 1fr;
}
}

.empty-contests {
margin: 24px auto;
display: flex;
justify-content: center;
text-align: center;
}
}
Loading
Loading