Skip to content

Commit 3e6f99e

Browse files
authored
Merge pull request #76 from code4rena-dev/feat/rolling-triage
Contest Tile: Add support for Rolling Triage
2 parents 9f1fe7c + a319087 commit 3e6f99e

9 files changed

+712
-53
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/ContestStatus/ContestStatus.types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,21 @@ export interface ContestStatusProps {
1212
/** HTML element identifier */
1313
id?: string;
1414
}
15+
16+
export const AuditStatus = {
17+
Booking: "Booking",
18+
PreAudit: "Pre-Audit",
19+
Active: "Active",
20+
/** Paused: The audit is in between Rolling Triage cohorts */
21+
Paused: "Paused",
22+
Review: "Review",
23+
Judging: "Judging",
24+
PJQA: "Post-Judging QA",
25+
JudgingComplete: "Judging Complete",
26+
Awarding: "Awarding",
27+
Reporting: "Reporting",
28+
Completed: "Completed",
29+
LostDeal: "Lost Deal",
30+
} as const;
31+
// Take the AuditStatus object, and make a string literal type of the values
32+
export type AuditStatus = (typeof AuditStatus)[keyof typeof AuditStatus];

src/lib/ContestTile/CompactTemplate.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import clsx from "clsx";
33
import { BountyTileData, ContestSchedule, ContestTileData, ContestTileProps, ContestTileVariant } from "./ContestTile.types";
44
import { Status, TagSize, TagVariant } from '../types';
55
import { ContestStatus } from '../ContestStatus';
6-
import { Countdown } from './ContestTile';
7-
import { getDates } from '../../utils/time';
6+
import { ContestCountdown } from './ContestTile';
7+
import { getContestSchedule } from '../../utils/time';
88
import { Tag } from '../Tag';
99
import { Icon } from '../Icon';
1010
import wolfbotIcon from "../../../public/icons/wolfbot.svg";
@@ -28,7 +28,7 @@ export default function CompactTemplate({
2828
c4contesttile: true,
2929
compact: true
3030
});
31-
31+
3232
return <div className={clsx("c4tilewrapper", variantClasses)}>
3333
<div id={htmlId ?? undefined} className={clsx(variantClasses, tileClasses)}>
3434
<div className="container--inner compact-content">
@@ -82,15 +82,15 @@ const IsContest = ({title, isDarkTile = true, contestData, sponsorUrl, sponsorIm
8282
}
8383

8484
if (startDate && endDate) {
85-
const newTimelineObject = getDates(contestData.startDate, contestData.endDate);
85+
const newTimelineObject = getContestSchedule(contestData);
8686
setContestTimelineObject(newTimelineObject);
8787
}
8888
}
8989
}, [contestData]);
9090

9191
useEffect(() => {
9292
if (contestData && startDate && endDate) {
93-
const newTimelineObject = getDates(startDate, endDate);
93+
const newTimelineObject = getContestSchedule(contestData);
9494
setContestTimelineObject(newTimelineObject);
9595
}
9696
}, [contestData])
@@ -104,14 +104,12 @@ const IsContest = ({title, isDarkTile = true, contestData, sponsorUrl, sponsorIm
104104
status={contestTimelineObject.contestStatus} />
105105
{contestTimelineObject.contestStatus !== Status.ENDED && (
106106
<div className="timer">
107-
<Countdown
108-
start={startDate}
109-
end={endDate}
107+
<ContestCountdown
108+
schedule={contestTimelineObject}
110109
updateContestStatus={updateContestTileStatus}
111-
text={contestTimelineObject.contestStatus === Status.UPCOMING ? 'Starts in ' : 'Ends in '}
112110
/>
113111
</div>
114-
)}
112+
)}
115113
</span>}
116114
<p className="type">
117115
{contestType === "Audit + mitigation review"
@@ -208,7 +206,7 @@ const IsBounty = ({title, isDarkTile = true, bountyData, sponsorUrl, sponsorImag
208206
break;
209207
}
210208
}
211-
209+
212210
return (
213211
<div className="body--bounty">
214212
<header>

src/lib/ContestTile/ContestTile.stories.tsx

Lines changed: 176 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React, { Fragment } from "react";
2+
import { addDays, subDays } from "date-fns";
23
import { ContestTile } from "./ContestTile";
34
import { Meta, StoryObj } from "@storybook/react";
45
import { CodingLanguage, ContestEcosystem, ContestTileVariant } from "./ContestTile.types";
6+
import { AuditStatus } from "../types";
57

68
const meta: Meta<typeof ContestTile> = {
79
component: ContestTile,
@@ -36,6 +38,7 @@ const defaultArgs = {
3638
htmlId: "",
3739
contestData: {
3840
codeAccess: "public",
41+
cohorts: [],
3942
contestType: "Open Audit",
4043
isUserCertified: false,
4144
contestId: 321,
@@ -75,6 +78,25 @@ export const ContestTileUpcoming: Story = (args) => {
7578
</Fragment>
7679
};
7780

81+
export const ContestTileUpcomingRollingTriage: Story = (args) => {
82+
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
83+
84+
return <Fragment>
85+
<ContestTile
86+
{...args}
87+
variant={isDark ? ContestTileVariant.DARK : ContestTileVariant.LIGHT}
88+
startDate={new Date(args.contestData.startDate).toISOString()}
89+
endDate={new Date(args.contestData.endDate).toISOString()}
90+
/>
91+
<ContestTile
92+
{...args}
93+
variant={isDark ? ContestTileVariant.COMPACT_DARK : ContestTileVariant.COMPACT_LIGHT }
94+
startDate={new Date(args.contestData.startDate).toISOString()}
95+
endDate={new Date(args.contestData.endDate).toISOString()}
96+
/>
97+
</Fragment>
98+
};
99+
78100
export const ContestTileLive: Story = (args) => {
79101
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
80102

@@ -94,6 +116,61 @@ export const ContestTileLive: Story = (args) => {
94116
</Fragment>
95117
};
96118

119+
export const ContestTileLiveCohort1: Story = (args) => {
120+
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
121+
122+
return <Fragment>
123+
<ContestTile
124+
{...args}
125+
variant={isDark ? ContestTileVariant.DARK : ContestTileVariant.LIGHT}
126+
startDate={new Date(args.contestData.startDate).toISOString()}
127+
endDate={new Date(args.contestData.endDate).toISOString()}
128+
/>
129+
<ContestTile
130+
{...args}
131+
variant={isDark ? ContestTileVariant.COMPACT_DARK : ContestTileVariant.COMPACT_LIGHT }
132+
startDate={new Date(args.contestData.startDate).toISOString()}
133+
endDate={new Date(args.contestData.endDate).toISOString()}
134+
/>
135+
</Fragment>
136+
};
137+
export const ContestTileLivePreCohort2: Story = (args) => {
138+
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
139+
140+
return <Fragment>
141+
<ContestTile
142+
{...args}
143+
variant={isDark ? ContestTileVariant.DARK : ContestTileVariant.LIGHT}
144+
startDate={new Date(args.contestData.startDate).toISOString()}
145+
endDate={new Date(args.contestData.endDate).toISOString()}
146+
/>
147+
<ContestTile
148+
{...args}
149+
variant={isDark ? ContestTileVariant.COMPACT_DARK : ContestTileVariant.COMPACT_LIGHT }
150+
startDate={new Date(args.contestData.startDate).toISOString()}
151+
endDate={new Date(args.contestData.endDate).toISOString()}
152+
/>
153+
</Fragment>
154+
};
155+
export const ContestTileLiveAwaitingCohort3: Story = (args) => {
156+
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
157+
158+
return <Fragment>
159+
<ContestTile
160+
{...args}
161+
variant={isDark ? ContestTileVariant.DARK : ContestTileVariant.LIGHT}
162+
startDate={new Date(args.contestData.startDate).toISOString()}
163+
endDate={new Date(args.contestData.endDate).toISOString()}
164+
/>
165+
<ContestTile
166+
{...args}
167+
variant={isDark ? ContestTileVariant.COMPACT_DARK : ContestTileVariant.COMPACT_LIGHT }
168+
startDate={new Date(args.contestData.startDate).toISOString()}
169+
endDate={new Date(args.contestData.endDate).toISOString()}
170+
/>
171+
</Fragment>
172+
};
173+
97174
export const ContestTileEnded: Story = (args) => {
98175
const isDark = args.variant === ContestTileVariant.DARK || args.variant === ContestTileVariant.COMPACT_DARK;
99176

@@ -127,7 +204,11 @@ export const BountyTile: Story = (args) => {
127204
}
128205

129206
ContestTileUpcoming.parameters = parameters;
207+
ContestTileUpcomingRollingTriage.parameters = parameters;
130208
ContestTileLive.parameters = parameters;
209+
ContestTileLiveCohort1.parameters = parameters;
210+
ContestTileLivePreCohort2.parameters = parameters;
211+
ContestTileLiveAwaitingCohort3.parameters = parameters;
131212
ContestTileEnded.parameters = parameters;
132213
BountyTile.parameters = parameters;
133214

@@ -136,16 +217,107 @@ ContestTileUpcoming.args = {
136217
contestData: {
137218
...defaultArgs.contestData,
138219
startDate: "2030-07-12T18:00:00Z",
139-
endDate: "2030-07-21T18:00:00.000Z"
220+
endDate: "2030-07-21T18:00:00.000Z",
221+
status: AuditStatus.PreAudit,
222+
}
223+
};
224+
ContestTileUpcomingRollingTriage.args = {
225+
...defaultArgs,
226+
contestData: {
227+
...defaultArgs.contestData,
228+
cohorts: [{
229+
name: "cohort-1",
230+
pauseTime: addDays(Date.now(), 6).toISOString(),
231+
resumeTime: null
232+
}, {
233+
name: "cohort-2",
234+
pauseTime: addDays(Date.now(), 13).toISOString(),
235+
resumeTime: addDays(Date.now(), 9).toISOString(),
236+
}, {
237+
name: "cohort-3",
238+
pauseTime: null,
239+
resumeTime: addDays(Date.now(), 16).toISOString(),
240+
}],
241+
startDate: addDays(Date.now(), 3).toISOString(),
242+
endDate: addDays(Date.now(), 20).toISOString(),
243+
status: AuditStatus.PreAudit,
140244
}
141245
};
142246

247+
143248
ContestTileLive.args = {
144249
...defaultArgs,
145250
contestData: {
146251
...defaultArgs.contestData,
147252
startDate: "2023-07-12T18:00:00Z",
148-
endDate: "2030-07-21T18:00:00.000Z"
253+
endDate: "2030-07-21T18:00:00.000Z",
254+
status: AuditStatus.Active,
255+
}
256+
};
257+
ContestTileLiveCohort1.args = {
258+
...defaultArgs,
259+
contestData: {
260+
...defaultArgs.contestData,
261+
cohorts: [{
262+
name: "cohort-1",
263+
pauseTime: addDays(Date.now(), 4).toISOString(),
264+
resumeTime: null
265+
}, {
266+
name: "cohort-2",
267+
pauseTime: addDays(Date.now(), 11).toISOString(),
268+
resumeTime: addDays(Date.now(), 7).toISOString(),
269+
}, {
270+
name: "cohort-3",
271+
pauseTime: null,
272+
resumeTime: addDays(Date.now(), 14).toISOString(),
273+
}],
274+
startDate: subDays(Date.now(), 1).toISOString(),
275+
endDate: addDays(Date.now(), 18).toISOString(),
276+
status: AuditStatus.Active,
277+
}
278+
};
279+
ContestTileLivePreCohort2.args = {
280+
...defaultArgs,
281+
contestData: {
282+
...defaultArgs.contestData,
283+
cohorts: [{
284+
name: "cohort-1",
285+
pauseTime: subDays(Date.now(), 1).toISOString(),
286+
resumeTime: null
287+
}, {
288+
name: "cohort-2",
289+
pauseTime: addDays(Date.now(), 6).toISOString(),
290+
resumeTime: addDays(Date.now(), 2).toISOString(),
291+
}, {
292+
name: "cohort-3",
293+
pauseTime: null,
294+
resumeTime: addDays(Date.now(), 9).toISOString(),
295+
}],
296+
startDate: subDays(Date.now(), 6).toISOString(),
297+
endDate: addDays(Date.now(), 16).toISOString(),
298+
status: AuditStatus.Paused,
299+
}
300+
};
301+
ContestTileLiveAwaitingCohort3.args = {
302+
...defaultArgs,
303+
contestData: {
304+
...defaultArgs.contestData,
305+
cohorts: [{
306+
name: "cohort-1",
307+
pauseTime: subDays(Date.now(), 11).toISOString(),
308+
resumeTime: null
309+
}, {
310+
name: "cohort-2",
311+
pauseTime: subDays(Date.now(), 4).toISOString(),
312+
resumeTime: subDays(Date.now(), 8).toISOString(),
313+
}, {
314+
name: "cohort-3",
315+
pauseTime: null,
316+
resumeTime: subDays(Date.now(), 1).toISOString(),
317+
}],
318+
startDate: subDays(Date.now(), 16).toISOString(),
319+
endDate: addDays(Date.now(), 6).toISOString(),
320+
status: AuditStatus.Paused,
149321
}
150322
};
151323

@@ -154,7 +326,8 @@ ContestTileEnded.args = {
154326
contestData: {
155327
...defaultArgs.contestData,
156328
startDate: "2023-07-12T18:00:00Z",
157-
endDate: "2023-07-21T18:00:00Z"
329+
endDate: "2023-07-21T18:00:00Z",
330+
status: AuditStatus.Review,
158331
}
159332
};
160333

0 commit comments

Comments
 (0)