Skip to content

Commit e17ed7e

Browse files
Merge pull request #25 from code4rena-dev/develop
Contest Tile Update
2 parents 56a5056 + 32c5be0 commit e17ed7e

9 files changed

+1465
-700
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@code4rena/components-library",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "Code4rena's official components library ",
55
"types": "./dist/lib.d.ts",
66
"exports": {
@@ -84,4 +84,4 @@
8484
"@babel/preset-react"
8585
]
8686
}
87-
}
87+
}
+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import React, { useCallback, useEffect, useState } from 'react';
2+
import clsx from "clsx";
3+
import { BountyTileData, ContestSchedule, ContestTileData, ContestTileProps, ContestTileVariant } from "./ContestTile.types";
4+
import { Status } from '../types';
5+
import { ContestStatus } from '../ContestStatus';
6+
import { Countdown } from './ContestTile';
7+
import { getDates } from '../../utils/time';
8+
9+
export default function CompactTemplate({
10+
variant,
11+
htmlId,
12+
title,
13+
sponsorImage,
14+
sponsorUrl,
15+
contestData,
16+
bountyData
17+
}: ContestTileProps) {
18+
const variantClasses = clsx({
19+
"compact--light": variant === ContestTileVariant.COMPACT_LIGHT,
20+
"compact--dark": variant === ContestTileVariant.COMPACT_DARK,
21+
});
22+
23+
const tileClasses = clsx({
24+
c4contesttile: true,
25+
compact: true
26+
});
27+
28+
return <div className={clsx("c4tilewrapper", variantClasses)}>
29+
<div id={htmlId ?? undefined} className={clsx(variantClasses, tileClasses)}>
30+
<div className="container--inner compact-content">
31+
{contestData && <IsContest
32+
title={title}
33+
contestData={contestData}
34+
sponsorUrl={sponsorUrl}
35+
sponsorImage={sponsorImage} />}
36+
{bountyData && <IsBounty
37+
title={title}
38+
bountyData={bountyData}
39+
sponsorUrl={sponsorUrl}
40+
sponsorImage={sponsorImage}
41+
/>}
42+
</div>
43+
</div>
44+
</div>
45+
}
46+
47+
48+
const IsContest = ({title, contestData, sponsorUrl, sponsorImage}: {
49+
title: string;
50+
contestData: ContestTileData;
51+
sponsorUrl: string | undefined;
52+
sponsorImage: string | undefined;
53+
}) => {
54+
const { startDate, endDate, amount, contestUrl, contestType } = contestData;
55+
const [contestTimelineObject, setContestTimelineObject] = useState<ContestSchedule | undefined>();
56+
57+
const updateContestTileStatus = useCallback(() => {
58+
if (contestData) {
59+
const { updateContestStatus } = contestData;
60+
if (updateContestStatus) {
61+
updateContestStatus();
62+
}
63+
64+
if (startDate && endDate) {
65+
const newTimelineObject = getDates(contestData.startDate, contestData.endDate);
66+
setContestTimelineObject(newTimelineObject);
67+
}
68+
}
69+
}, [contestData]);
70+
71+
useEffect(() => {
72+
if (contestData && startDate && endDate) {
73+
const newTimelineObject = getDates(startDate, endDate);
74+
setContestTimelineObject(newTimelineObject);
75+
}
76+
}, [contestData])
77+
78+
return (
79+
<div className="body--contest">
80+
<header>
81+
<div className="header--status">
82+
{contestData && contestTimelineObject && <span>
83+
<ContestStatus className={clsx('status', contestTimelineObject.contestStatus === Status.ENDED && 'ended')}
84+
status={contestTimelineObject.contestStatus} />
85+
{contestTimelineObject.contestStatus !== Status.ENDED && (
86+
<div className="timer">
87+
<Countdown
88+
start={startDate}
89+
end={endDate}
90+
updateContestStatus={updateContestTileStatus}
91+
text={contestTimelineObject.contestStatus === Status.UPCOMING ? 'Starts in ' : 'Ends in '}
92+
/>
93+
</div>
94+
)}
95+
</span>}
96+
<p className="type">{contestType}</p>
97+
</div>
98+
</header>
99+
<div className="content--wrapper">
100+
{sponsorUrl ? (
101+
<a
102+
href={sponsorUrl}
103+
target="_blank"
104+
rel="noreferrer noopener"
105+
className="logo"
106+
>
107+
<img
108+
alt="Sponsor logo"
109+
src={sponsorImage ?? "/"}
110+
width={88}
111+
height={88}
112+
/>
113+
</a>
114+
) : (
115+
<img
116+
alt="Sponsor logo"
117+
className="logo"
118+
src={sponsorImage ?? "/"}
119+
width={88}
120+
height={88}
121+
/>
122+
)}
123+
<div className="content">
124+
<h2 className="title">
125+
<a href={`${contestUrl}#top`}>{title}</a>
126+
</h2>
127+
</div>
128+
<p className="amount">{amount}</p>
129+
</div>
130+
</div>
131+
)}
132+
133+
const IsBounty = ({title, bountyData, sponsorUrl, sponsorImage}: {
134+
title: string;
135+
bountyData: BountyTileData;
136+
sponsorUrl: string | undefined;
137+
sponsorImage: string | undefined;
138+
}) => {
139+
const { amount, bountyUrl } = bountyData;
140+
141+
return (
142+
<div className="body--bounty">
143+
<header>
144+
{sponsorUrl ? (
145+
<a
146+
href={sponsorUrl}
147+
target="_blank"
148+
rel="noreferrer noopener"
149+
className="logo"
150+
>
151+
<img
152+
alt="Sponsor logo"
153+
src={sponsorImage ?? "/"}
154+
width={88}
155+
height={88}
156+
/>
157+
</a>
158+
) : (
159+
<img
160+
alt="Sponsor logo"
161+
className="logo"
162+
src={sponsorImage ?? "/"}
163+
width={88}
164+
height={88}
165+
/>
166+
)}
167+
<h2 className="title">
168+
<a href={bountyUrl ? `${bountyUrl}#top` : '#'}>{title}</a>
169+
</h2>
170+
<p className="type">Bug Bounty</p>
171+
</header>
172+
<div className="content--wrapper">
173+
<strong>Max Bounty</strong>
174+
<p className="amount">{amount}</p>
175+
</div>
176+
</div>
177+
)}

0 commit comments

Comments
 (0)