Skip to content

Commit e3ad9c5

Browse files
committed
switch to using real notion table
1 parent 21afb3c commit e3ad9c5

6 files changed

Lines changed: 258 additions & 39 deletions

File tree

devconnect/src/pages/argentina.tsx

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ import styles from './argentina.module.scss'
99
import Oblisk from '../../public/scroll-video/Oblisk_4K0125.webp'
1010
import cn from 'classnames'
1111
import NewSchedule from 'lib/components/event-schedule-new'
12+
import { formatResult } from 'lib/helpers/notion-normalizer'
13+
// import dateFns from 'date-fns'
14+
import moment from 'moment'
1215

13-
const Argentina = () => {
16+
const Argentina = (props: any) => {
1417
const { selectedEvent, selectedDay, setSelectedEvent, setSelectedDay } = useCalendarStore()
1518

19+
console.log(props.events)
20+
1621
return (
1722
<>
1823
<Header active />
@@ -37,8 +42,8 @@ const Argentina = () => {
3742
</div>
3843
<div className="flex flex-col gap-4 text-black">
3944
<div className="section my-1 mb-8">
40-
<div className="flex justify-between gap-4 items-end"></div>
4145
<NewSchedule
46+
events={props.events}
4247
selectedEvent={selectedEvent}
4348
selectedDay={selectedDay}
4449
setSelectedEvent={setSelectedEvent}
@@ -57,45 +62,104 @@ export async function getStaticProps({ locale }: { locale: string }) {
5762
const translationPath = locale === 'en' ? 'global.json' : locale + '/global.json'
5863
const translations = await client.queries.global_translations({ relativePath: translationPath })
5964

60-
// https://www.notion.so/ef-events/1f5638cdc41580be9117f4963f021d8b?v=1f5638cdc415816c9277000ccc6cda85&pvs=4
65+
//www.notion.so/ef-events/1f5638cdc41580be9117f4963f021d8b?v=1f5638cdc415816c9277000ccc6cda85&pvs=4
6166

6267
const notion = new Client({
6368
auth: process.env.NOTION_SECRET,
6469
})
6570

6671
const query = {
6772
database_id: '1f5638cdc41580be9117f4963f021d8b',
68-
sorts: [
69-
{
70-
property: '[HOST] Event Date',
71-
direction: 'ascending',
72-
},
73-
{
74-
property: '[WEB] Priority (sort)',
75-
direction: 'descending',
76-
},
77-
],
78-
filter: {
79-
and: [
80-
{
81-
property: '[HOST] Event Date',
82-
date: {
83-
is_not_empty: true,
84-
},
85-
},
86-
{
87-
property: '[WEB] Live',
88-
checkbox: {
89-
equals: true,
90-
},
91-
},
92-
],
93-
},
73+
// sorts: [
74+
// {
75+
// property: '[HOST] Event Date',
76+
// direction: 'ascending',
77+
// },
78+
// {
79+
// property: '[WEB] Priority (sort)',
80+
// direction: 'descending',
81+
// },
82+
// ],
83+
// filter: {
84+
// and: [
85+
// {
86+
// property: '[HOST] Event Date',
87+
// date: {
88+
// is_not_empty: true,
89+
// },
90+
// },
91+
// {
92+
// property: '[WEB] Live',
93+
// checkbox: {
94+
// equals: true,
95+
// },
96+
// },
97+
// ],
98+
// },
9499
}
95100

96-
const events = await notion.databases.query(query as any)
101+
const notionEvents = await notion.databases.query(query as any)
102+
103+
/*
104+
export interface Event {
105+
id: string;
106+
name: string;
107+
isFairEvent?: boolean;
108+
isCoreEvent?: boolean;
109+
description: string;
110+
organizer: string;
111+
difficulty: string;
112+
amountPeople?: string;
113+
location: {
114+
url: string;
115+
text: string;
116+
coordinates?: {
117+
lat: number;
118+
lng: number;
119+
};
120+
};
121+
timeblocks: {
122+
start: string;
123+
end: string;
124+
name?: string;
125+
location?: string;
126+
}[];
127+
priority: number;
128+
categories: string[];
129+
}
130+
131+
*/
132+
133+
// console.log(notionEvents)
134+
135+
const events = notionEvents.results
136+
.map(event => {
137+
const formattedEvent = formatResult(event)
138+
139+
const startDate = moment('2025-11-17T09:00:00Z').add(Math.floor(Math.random() * 6), 'days')
140+
141+
return {
142+
id: event.id,
143+
name: formattedEvent['Event name'],
144+
description: formattedEvent['Description'] || '',
145+
capacity: formattedEvent['Capacity'],
146+
size: formattedEvent['Size'],
147+
location: formattedEvent['Location'] || { text: 'TBD', url: '' },
148+
timeblocks: [
149+
{
150+
start: startDate.format('YYYY-MM-DDTHH:mm:ss[Z]'),
151+
end: startDate.clone().add(4, 'hours').format('YYYY-MM-DDTHH:mm:ss[Z]'),
152+
},
153+
],
154+
difficulty: 'Beginner',
155+
}
156+
})
157+
.sort((a, b) => moment(a.timeblocks[0].start).valueOf() - moment(b.timeblocks[0].start).valueOf())
97158

98-
console.log(events)
159+
// @ts-ignore
160+
events[0].isFairEvent = true
161+
// @ts-ignore
162+
events[1].isCoreEvent = true
99163

100164
return {
101165
props: {

devconnect/src/store/calendar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { create } from 'zustand'
2-
import { Event } from 'common/components/new-schedule-hehe/model'
2+
import { Event } from 'lib/components/event-schedule-new/model'
33

44
interface CalendarStore {
55
selectedEvent: Event | null

lib/components/event-schedule-new/day/event.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ const Event: React.FC<EventProps> = ({
7272
? "bg-yellow-300"
7373
: "bg-red-300";
7474

75-
const isCoworking = event.name.includes("Coworking");
76-
const isETHDay = event.name.includes("ETH Day");
75+
const isCoworking = event.isCoreEvent; // event.name.includes("Coworking");
76+
const isETHDay = event.isFairEvent; // event.name.includes("ETH Day");
7777

7878
const isCoreEvent = event.isCoreEvent || event.isFairEvent;
7979

lib/components/event-schedule-new/index.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type ScheduleProps = {
1717
selectedDay: string | null;
1818
setSelectedEvent: (event: EventType | null) => void;
1919
setSelectedDay: (day: string | null) => void;
20+
events: EventType[];
2021
};
2122

2223
// Utility function for tracking placed nodes in the grid
@@ -125,10 +126,12 @@ const NewScheduleIndex = ({
125126
selectedDay,
126127
setSelectedEvent,
127128
setSelectedDay,
129+
events,
128130
}: ScheduleProps) => {
129131
// const { selectedEvent, selectedDay, setSelectedEvent, setSelectedDay } = useCalendarStore()
130-
const eventRange = computeCalendarRange(dummyEvents);
131-
const [events] = useState<EventType[]>(dummyEvents);
132+
const eventRange = computeCalendarRange(events);
133+
// const [events] = useState<EventType[]>(dummyEvents);
134+
// const [events] = useState<EventType[]>(events);
132135
// Add state to track which date is being hovered
133136
const [hoveredDate, setHoveredDate] = useState<string | null>(null);
134137

@@ -259,7 +262,7 @@ const NewScheduleIndex = ({
259262
// gridColumn: `1 / span ${eventRange.length}`, // Span all columns
260263
// }}
261264
>
262-
<Timeline events={dummyEvents} />
265+
<Timeline events={events} />
263266
{/* {selectedDay && <MapComponent />} */}
264267
</div>
265268
</div>

lib/components/event-schedule-new/model.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export interface Event {
66
description: string;
77
organizer: string;
88
difficulty: string;
9-
lemonadeID: string;
109
amountPeople?: string;
1110
location: {
1211
url: string;
@@ -18,7 +17,7 @@ export interface Event {
1817
};
1918
timeblocks: {
2019
start: string;
21-
end: string;
20+
end: string;
2221
name?: string;
2322
location?: string;
2423
}[];

lib/helpers/notion-normalizer.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Notion fetch/format below
2+
export const notionDatabasePropertyResolver = (property: any, key: any) => {
3+
switch (property.type) {
4+
case "text":
5+
case "rich_text":
6+
case "title":
7+
// Extract url and url text from the Location column
8+
if (key === "Location" && property[property.type]) {
9+
let locationInfo = {} as any;
10+
11+
property[property.type].forEach((chunk: any) => {
12+
if (chunk.href) {
13+
locationInfo.url = chunk.href;
14+
locationInfo.text = chunk.plain_text;
15+
}
16+
});
17+
18+
return locationInfo;
19+
}
20+
21+
const dechunked = property[property.type]
22+
? property[property.type].reduce((acc: string, chunk: any) => {
23+
let textToAppend;
24+
25+
if (
26+
chunk.href &&
27+
property.type === "rich_text" &&
28+
key !== "URL" &&
29+
key !== "Stream URL"
30+
) {
31+
textToAppend = `<a href=${chunk.href} target="_blank" class="generic" rel="noopener noreferrer">${chunk.plain_text}</a>`;
32+
} else {
33+
textToAppend = chunk.plain_text;
34+
}
35+
36+
if (chunk.annotations) {
37+
let annotations = "placeholder";
38+
39+
if (chunk.annotations.bold) annotations = `<b>${annotations}</b>`;
40+
if (chunk.annotations.italic)
41+
annotations = `<i>${annotations}</i>`;
42+
if (chunk.annotations.strikethrough)
43+
annotations = `<s>${annotations}</s>`;
44+
if (chunk.annotations.underline)
45+
annotations = `<u>${annotations}</u>`;
46+
47+
textToAppend = annotations.replace("placeholder", textToAppend);
48+
}
49+
50+
return acc + textToAppend;
51+
}, "")
52+
: null;
53+
54+
return `${dechunked}`;
55+
56+
case "date":
57+
if (property.date) {
58+
return {
59+
startDate: property.date.start,
60+
endDate: property.date.end || property.date.start,
61+
};
62+
}
63+
64+
return null;
65+
66+
case "multi_select":
67+
if (property.multi_select) {
68+
return property.multi_select.map((value: any) => value.name);
69+
}
70+
71+
return null;
72+
case "select":
73+
return property.select && property.select.name;
74+
75+
case "number":
76+
return property.number;
77+
78+
case "checkbox":
79+
return property.checkbox;
80+
81+
default:
82+
return "default value no handler for: " + property.type;
83+
}
84+
};
85+
86+
export const formatResult = (result: any) => {
87+
const properties = {} as { [key: string]: any };
88+
89+
// Format the raw notion data into something more workable
90+
Object.entries(result.properties).forEach(([key, value]) => {
91+
if (typeof value === "undefined") return;
92+
93+
const val = notionDatabasePropertyResolver(value, key);
94+
95+
if (Array.isArray(val)) {
96+
properties[key] = val;
97+
} else if (typeof val === "object" && val !== null) {
98+
properties[key] = {
99+
...val,
100+
};
101+
} else {
102+
properties[key] = val;
103+
}
104+
});
105+
106+
return properties;
107+
};
108+
109+
// const formatResult = (result: any) => {
110+
// const properties = {} as { [key: string]: any };
111+
112+
// // Our schedules follow multiple formats, so we have to normalize before processing:
113+
// const normalizedNotionEventData = normalizeEvent(result.properties);
114+
115+
// // Format the raw notion data into something more workable
116+
// Object.entries(normalizedNotionEventData).forEach(([key, value]) => {
117+
// if (typeof value === "undefined") return;
118+
119+
// const val = notionDatabasePropertyResolver(value, key);
120+
121+
// if (Array.isArray(val)) {
122+
// properties[key] = val;
123+
// } else if (typeof val === "object" && val !== null) {
124+
// properties[key] = {
125+
// ...val,
126+
// };
127+
// } else {
128+
// properties[key] = val;
129+
// }
130+
// });
131+
132+
// // Insert a default value for time of day when unspecified
133+
// // if (!properties["Time of Day"]) properties["Time of Day"] = "All day";
134+
// // Prepend https to url if it's not an internal link (e.g. /cowork) and if https is not specified in case the event host forgot
135+
// // if (properties["URL"]) {
136+
// // const isInternal = properties["URL"].startsWith("/");
137+
// // const noHttp = !properties["URL"].startsWith("http");
138+
139+
// // if (noHttp && !isInternal) {
140+
// // properties["URL"] = `https://${properties["URL"]}`;
141+
// // }
142+
// // }
143+
144+
// // const isVirtualEvent =
145+
// // properties.Category && properties.Category.includes("Virtual Event");
146+
147+
// return {
148+
// ...properties,
149+
// ShortID: result.id.slice(0, 5),
150+
// // isVirtualEvent,
151+
// // ID: result.id,
152+
// };
153+
// };

0 commit comments

Comments
 (0)