Skip to content

Commit 742dba1

Browse files
authored
Add changing call status by date (#25)
* feat: update data and add logic for call status * feat: refactor and apply logic to component * chore: remove comment * chore: formatting
1 parent 773f80b commit 742dba1

File tree

2 files changed

+115
-108
lines changed

2 files changed

+115
-108
lines changed

components/BeamCalls.tsx

Lines changed: 99 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ExternalLink, FileText, ListChecks, Play, Presentation } from 'lucide-r
33
import { Card, CardContent, CardFooter } from '@/components/ui/primitives';
44
import { Button } from '@/components/ui/Button';
55
import Link from 'next/link';
6-
import { BeamCall, beamCallsData } from '@/data/beam-calls';
6+
import { BeamCall, beamCallsData, determineBeamCallStatus } from '@/data/beam-calls';
77

88
// Helper function to extract YouTube video ID from URL
99
function getYoutubeVideoId(url: string): string | null {
@@ -33,101 +33,107 @@ export function BeamCalls() {
3333
return (
3434
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
3535
{beamCallsData.map((call) => (
36-
<Card
37-
key={call.id}
38-
className={`bg-white border-slate-200 overflow-hidden ${call.status === 'unscheduled' ? 'filter brightness-100 opacity-25' : ''}`}
39-
>
40-
<div className="relative">
41-
{call.youtubeUrl !== '#' && getYoutubeVideoId(call.youtubeUrl) ? (
42-
<div className="w-full h-48">
43-
<iframe
44-
src={`https://www.youtube.com/embed/${getYoutubeVideoId(call.youtubeUrl)}`}
45-
title={call.title}
46-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
47-
allowFullScreen
48-
className="w-full h-full"
49-
/>
50-
</div>
51-
) : (
52-
<>
53-
<Image
54-
src={call.thumbnail || '/placeholder.svg?height=180&width=320'}
55-
alt={call.title}
56-
width={320}
57-
height={180}
58-
className="w-full h-48 object-cover"
59-
/>
60-
{call.youtubeUrl !== '#' && (
61-
<div className="absolute inset-0 bg-black bg-opacity-30 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
62-
<Link href={call.youtubeUrl} target="_blank">
63-
<Button
64-
size="icon"
65-
variant="secondary"
66-
className="rounded-full bg-white bg-opacity-90 h-12 w-12"
67-
>
68-
<Play className="h-6 w-6 text-red-600" />
69-
</Button>
70-
</Link>
71-
</div>
72-
)}
73-
</>
74-
)}
36+
<BeamCallCard key={call.id} call={call} />
37+
))}
38+
</div>
39+
);
40+
}
41+
42+
function BeamCallCard({ call }: { call: BeamCall }) {
43+
const status = determineBeamCallStatus(call.date);
44+
45+
return (
46+
<Card
47+
key={call.id}
48+
className={`bg-white border-slate-200 overflow-hidden ${status === 'unscheduled' ? 'filter brightness-100 opacity-25' : ''}`}
49+
>
50+
<div className="relative">
51+
{call.youtubeUrl !== '#' && getYoutubeVideoId(call.youtubeUrl) ? (
52+
<div className="w-full h-48">
53+
<iframe
54+
src={`https://www.youtube.com/embed/${getYoutubeVideoId(call.youtubeUrl)}`}
55+
title={call.title}
56+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
57+
allowFullScreen
58+
className="w-full h-full"
59+
/>
7560
</div>
76-
<CardContent className="pt-4">
77-
{call.youtubeUrl !== '#' ? (
78-
<Link
79-
href={call.youtubeUrl}
80-
target="_blank"
81-
className="font-semibold text-lg mb-1 text-slate-900 hover:text-blue-600"
82-
>
83-
{call.title}
84-
</Link>
85-
) : (
86-
<div className="flex items-center">
87-
<p className="font-semibold text-lg mb-1 text-slate-900">{call.title}</p>
88-
{call.status === 'upcoming' && (
89-
<span className="ml-2 text-xs bg-red-500 text-white rounded-md px-2 py-1">
90-
Soon!
91-
</span>
92-
)}
93-
</div>
94-
)}
95-
<p className="text-xs text-slate-500 mb-2">{call.date}</p>
96-
<p className="text-sm text-slate-600">{call.summary}</p>
97-
{call.resources && call.resources.length > 0 && (
98-
<div className="mt-4 space-y-2">
99-
<p className="text-sm font-medium text-slate-700">Resources:</p>
100-
<div className="flex flex-wrap gap-2">
101-
{call.resources.map((resource, index) => (
102-
<Link
103-
key={index}
104-
href={resource.url}
105-
target="_blank"
106-
className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium text-slate-700 bg-slate-100 rounded-full hover:bg-slate-200"
107-
>
108-
{getResourceIcon(resource.type)}
109-
{resource.title}
110-
</Link>
111-
))}
112-
</div>
61+
) : (
62+
<>
63+
<Image
64+
src={call.thumbnail || '/placeholder.svg?height=180&width=320'}
65+
alt={call.title}
66+
width={320}
67+
height={180}
68+
className="w-full h-48 object-cover"
69+
/>
70+
{call.youtubeUrl !== '#' && (
71+
<div className="absolute inset-0 bg-black bg-opacity-30 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
72+
<Link href={call.youtubeUrl} target="_blank">
73+
<Button
74+
size="icon"
75+
variant="secondary"
76+
className="rounded-full bg-white bg-opacity-90 h-12 w-12"
77+
>
78+
<Play className="h-6 w-6 text-red-600" />
79+
</Button>
80+
</Link>
11381
</div>
11482
)}
115-
</CardContent>
116-
<CardFooter className="pt-0">
117-
{call.youtubeUrl !== '#' ? (
118-
<Link
119-
href={call.youtubeUrl}
120-
className="text-sm font-medium text-slate-700 hover:text-slate-900 flex items-center gap-1"
121-
target="_blank"
122-
>
123-
Watch on YouTube <ExternalLink className="h-3.5 w-3.5" />
124-
</Link>
125-
) : (
126-
<p className="text-sm text-slate-400">Recording not yet available.</p>
83+
</>
84+
)}
85+
</div>
86+
<CardContent className="pt-4">
87+
{call.youtubeUrl !== '#' ? (
88+
<Link
89+
href={call.youtubeUrl}
90+
target="_blank"
91+
className="font-semibold text-lg mb-1 text-slate-900 hover:text-blue-600"
92+
>
93+
{call.title}
94+
</Link>
95+
) : (
96+
<div className="flex items-center">
97+
<p className="font-semibold text-lg mb-1 text-slate-900">{call.title}</p>
98+
{status === 'upcoming' && (
99+
<span className="ml-2 text-xs bg-red-500 text-white rounded-md px-2 py-1">Soon!</span>
127100
)}
128-
</CardFooter>
129-
</Card>
130-
))}
131-
</div>
101+
</div>
102+
)}
103+
<p className="text-xs text-slate-500 mb-2">{call.date}</p>
104+
<p className="text-sm text-slate-600">{call.summary}</p>
105+
{call.resources && call.resources.length > 0 && (
106+
<div className="mt-4 space-y-2">
107+
<p className="text-sm font-medium text-slate-700">Resources:</p>
108+
<div className="flex flex-wrap gap-2">
109+
{call.resources.map((resource, index) => (
110+
<Link
111+
key={index}
112+
href={resource.url}
113+
target="_blank"
114+
className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium text-slate-700 bg-slate-100 rounded-full hover:bg-slate-200"
115+
>
116+
{getResourceIcon(resource.type)}
117+
{resource.title}
118+
</Link>
119+
))}
120+
</div>
121+
</div>
122+
)}
123+
</CardContent>
124+
<CardFooter className="pt-0">
125+
{call.youtubeUrl !== '#' ? (
126+
<Link
127+
href={call.youtubeUrl}
128+
className="text-sm font-medium text-slate-700 hover:text-slate-900 flex items-center gap-1"
129+
target="_blank"
130+
>
131+
Watch on YouTube <ExternalLink className="h-3.5 w-3.5" />
132+
</Link>
133+
) : (
134+
<p className="text-sm text-slate-400">Recording not yet available.</p>
135+
)}
136+
</CardFooter>
137+
</Card>
132138
);
133139
}

data/beam-calls.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
export type BeamCallStatus = 'completed' | 'upcoming' | 'scheduled' | 'unscheduled';
2+
13
export interface BeamCall {
24
id: string;
35
title: string;
4-
status: 'completed' | 'upcoming' | 'unscheduled';
56
date: string;
67
summary: string;
7-
thumbnail: string;
8+
thumbnail: string | null;
89
youtubeUrl: string;
910
resources?: {
1011
title: string;
@@ -13,11 +14,23 @@ export interface BeamCall {
1314
}[];
1415
}
1516

17+
export function determineBeamCallStatus(date: string): BeamCallStatus {
18+
if (date === 'TBD') return 'unscheduled';
19+
20+
const callDate = new Date(date);
21+
const today = new Date();
22+
const oneMonthFromNow = new Date();
23+
oneMonthFromNow.setMonth(today.getMonth() + 1);
24+
25+
if (callDate < today) return 'completed';
26+
if (callDate <= oneMonthFromNow) return 'upcoming';
27+
return 'scheduled';
28+
}
29+
1630
export const beamCallsData: BeamCall[] = [
1731
{
1832
id: 'call-1',
1933
title: 'Beam Call #1: Social Layer Updates',
20-
status: 'completed',
2134
date: 'February 14, 2025',
2235
summary:
2336
'The kickoff call covering social layer progress, funding structures, legal updates, introductions of research specialists and client teams, and coordinator presentations',
@@ -39,7 +52,6 @@ export const beamCallsData: BeamCall[] = [
3952
{
4053
id: 'call-2',
4154
title: 'Beam Call #2: Post-Quantum Security',
42-
status: 'completed',
4355
date: 'February 28, 2025',
4456
summary:
4557
'Technical updates on post-quantum cryptography solutions, featuring technical presentations from researchers on signature schemes, hash functions, minimal zkVMs, and formal verification.',
@@ -81,7 +93,6 @@ export const beamCallsData: BeamCall[] = [
8193
{
8294
id: 'call-3',
8395
title: 'Beam Call #3: P2P Networking',
84-
status: 'completed',
8596
date: 'April 4, 2025',
8697
summary: 'Discussion on the latest developments in peer-to-peer networking.',
8798
thumbnail: null,
@@ -142,7 +153,6 @@ export const beamCallsData: BeamCall[] = [
142153
{
143154
id: 'call-4',
144155
title: 'Beam Call #4: Exit Queue',
145-
status: 'completed',
146156
date: 'April 18, 2025',
147157
summary:
148158
'Discussion of Ethereum validator exit mechanisms and proposals to improve exit queue flexibility while maintaining protocol security.',
@@ -169,7 +179,6 @@ export const beamCallsData: BeamCall[] = [
169179
{
170180
id: 'call-5',
171181
title: 'Beam Call #5: APS (Attester-Proposer Separation)',
172-
status: 'completed',
173182
date: 'May 2, 2025',
174183
summary:
175184
'Exploration of the Attester-Proposer Separation (APS) concept, its benefits, and potential applications for the Beam Chain.',
@@ -191,7 +200,6 @@ export const beamCallsData: BeamCall[] = [
191200
{
192201
id: 'call-6',
193202
title: 'Beam Call #6: 3SF (Finality)',
194-
status: 'upcoming',
195203
date: 'May 16, 2025',
196204
summary:
197205
'Discussion on the finality of the 3SF protocol, including its implementation and implications on the network.',
@@ -213,7 +221,6 @@ export const beamCallsData: BeamCall[] = [
213221
{
214222
id: 'call-7',
215223
title: 'Beam Call #7: Rainbow Staking',
216-
status: 'upcoming',
217224
date: 'May 30, 2025',
218225
summary:
219226
'Introduction to Rainbow Staking, a novel staking mechanism designed to enhance network security and decentralization.',
@@ -223,7 +230,6 @@ export const beamCallsData: BeamCall[] = [
223230
{
224231
id: 'call-8',
225232
title: 'Beam Call #8: PQ Sub-Spec',
226-
status: 'unscheduled',
227233
date: 'TBD',
228234
summary:
229235
'In-depth discussion on the Post-Quantum (PQ) sub-specification, focusing on its cryptographic aspects and integration into the Beam Chain.',
@@ -233,7 +239,6 @@ export const beamCallsData: BeamCall[] = [
233239
{
234240
id: 'call-9',
235241
title: 'Beam Call #9: P2P Sub-Spec',
236-
status: 'unscheduled',
237242
date: 'TBD',
238243
summary:
239244
'Examination of the Peer-to-Peer (P2P) sub-specification, covering its role in facilitating decentralized communication within the Beam Chain.',
@@ -243,7 +248,6 @@ export const beamCallsData: BeamCall[] = [
243248
{
244249
id: 'call-10',
245250
title: 'Beam Call #10: APS Sub-Spec',
246-
status: 'unscheduled',
247251
date: 'TBD',
248252
summary:
249253
'Exploring the Attester-Proposer Separation (APS) sub-specification, its benefits, and potential applications in the Beam Chain.',
@@ -253,7 +257,6 @@ export const beamCallsData: BeamCall[] = [
253257
{
254258
id: 'call-11',
255259
title: 'Beam Call #11: 3SF Sub-Spec',
256-
status: 'unscheduled',
257260
date: 'TBD',
258261
summary:
259262
"Delving into the 3SF sub-specification, including its technical details and implications for the network's finality.",
@@ -263,7 +266,6 @@ export const beamCallsData: BeamCall[] = [
263266
{
264267
id: 'call-12',
265268
title: 'Beam Call #12: Beam Spec (Part 1)',
266-
status: 'unscheduled',
267269
date: 'TBD',
268270
summary:
269271
'First part of the Beam specification discussion, covering the overall architecture and core components of the Beam Chain.',
@@ -273,7 +275,6 @@ export const beamCallsData: BeamCall[] = [
273275
{
274276
id: 'call-13',
275277
title: 'Beam Call #13: Beam Spec (Part 2)',
276-
status: 'upcoming',
277278
date: 'December 26, 2025',
278279
summary:
279280
"Second part of the Beam specification discussion, focusing on the protocol's advanced features, security considerations, and future development plans.",

0 commit comments

Comments
 (0)