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