Skip to content

Commit

Permalink
Merge pull request #183 from poap-xyz/release/v1.11.0
Browse files Browse the repository at this point in the history
Release v1.11.0
  • Loading branch information
jm42 authored Apr 17, 2024
2 parents 1c99b34 + bfb8baa commit 03ec8b5
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 33 deletions.
17 changes: 16 additions & 1 deletion netlify/edge-functions/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function getEventId(requestUrl) {
}

async function getEventInfo(eventId) {
const response = await axios.get(`${FAMILY_API_URL}/event/${eventId}?metrics=true&fresh=true`)
const response = await axios.get(`${FAMILY_API_URL}/event/${eventId}?description=true&metrics=true&fresh=true`)
const event = response.data
if (
typeof event !== 'object' ||
Expand Down Expand Up @@ -64,6 +64,17 @@ function escapeHtml(str) {
.replaceAll("'", ''')
}

function truncate(str, n = 90) {
const p = str.split('\n').shift()
if (p && p.length <= n) {
return p
}
if (str.length > n) {
return `${str.substring(0, n)}...`
}
return str
}

export default async function handler(request, context) {
const eventId = getEventId(request.url)
const queryString = getQueryString(request.url)
Expand Down Expand Up @@ -98,6 +109,10 @@ export default async function handler(request, context) {
`${eventInfo.event.city && eventInfo.event.country
? ` ${eventInfo.event.city}, ${eventInfo.event.country}`
: ''
}` +
`${eventInfo.description && typeof eventInfo.description === 'string'
? ` ${truncate(eventInfo.description)}`
: ''
}`
)
const image = eventInfo.event.image_url
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poap-xyz/poap-family",
"version": "1.10.3",
"version": "1.11.0",
"author": {
"name": "POAP",
"url": "https://poap.xyz"
Expand Down
48 changes: 35 additions & 13 deletions src/components/EventInfo.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
import { useState } from 'react'
import { FastArrowLeft, FastArrowRight } from 'iconoir-react'
import Ilustration from '../images/Illustration_Cities_BuenosAires.png'
import Card from './Card'
import Stats from './Stats'
import TokenImageZoom from './TokenImageZoom'
import EventButtons from './EventButtons'
import ExternalLink from './ExternalLink'
import { formatDate } from '../utils/date'
import linkify from '../utils/linkify'
import '../styles/event-info.css'

function EventInfo({ event, stats = {}, highlightStat, buttons = [], children }) {
const [extraOpen, setExtraOpen] = useState(false)

return (
<Card style={{ backgroundImage: `url(${Ilustration})`, backgroundPosition: '-3rem -8rem' }}>
<div className="event-info">
<div className="event-image">
<TokenImageZoom event={event} zoomSize={512} size={128} />
<div className="event-info-header">
{event.description && (
<div className={`event-info-extra ${extraOpen ? 'open' : 'close'}`}>
<div className="event-info-extra-card">
{extraOpen && (
<div className="event-info-extra-content">
{event.description.split('\n').map((p, i) => <p key={i}>{linkify(p, ExternalLink)}</p>)}
</div>
)}
<button onClick={() => setExtraOpen((prev) => !prev)} className="event-info-extra-button">
{extraOpen ? <FastArrowLeft /> : <FastArrowRight />}
</button>
</div>
</div>
<div className="event-data">
<h1>{event.name}</h1>
<div className="event-date">{formatDate(event.start_date)}</div>
{event.city && event.country && <div className="place">{event.city}, {event.country}</div>}
<Stats stats={stats} highlight={highlightStat} />
<EventButtons event={event} buttons={buttons} viewInGallery={true} />
{children}
)}
<Card style={{ backgroundImage: `url(${Ilustration})`, backgroundPosition: '-3rem -8rem' }}>
<div className="event-info">
<div className="event-image">
<TokenImageZoom event={event} zoomSize={512} size={128} />
</div>
<div className="event-data">
<h1>{event.name}</h1>
<div className="event-date">{formatDate(event.start_date)}</div>
{event.city && event.country && <div className="place">{event.city}, {event.country}</div>}
<Stats stats={stats} highlight={highlightStat} />
<EventButtons event={event} buttons={buttons} viewInGallery={true} />
{children}
</div>
</div>
</div>
</Card>
</Card>
</div>
)
}

Expand Down
13 changes: 13 additions & 0 deletions src/components/ExternalLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { OpenNewWindow } from 'iconoir-react'
import '../styles/external-link.css'

function ExternalLink({ href, children }) {
return (
<a href={href} target="_blank" rel="noopener noreferrer" className="external-link">
{children ?? href}
<OpenNewWindow className="external-link-icon" />
</a>
)
}

export default ExternalLink
2 changes: 1 addition & 1 deletion src/components/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function Search() {
})
setErrorById(null)
setEventById(null)
fetchEvent(eventId, controller.signal).then(
fetchEvent(eventId, /*includeDescription*/false, controller.signal).then(
(result) => {
setLoadingById({ eventId: null, state: false, controller: null })
if (result) {
Expand Down
12 changes: 7 additions & 5 deletions src/loaders/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import axios from 'axios'
import { FAMILY_API_KEY, FAMILY_API_URL } from '../models/api'
import { encodeExpiryDates, Event } from '../models/event'

async function getEventAndOwners(eventId, abortSignal, includeMetrics = true, fresh = true) {
async function getEventAndOwners(eventId, abortSignal, includeDescription = false, includeMetrics = true, fresh = true) {
if (!FAMILY_API_KEY) {
return null
}
const response = await fetch(
`${FAMILY_API_URL}/event/${eventId}?metrics=${encodeURIComponent(includeMetrics)}` +
`${FAMILY_API_URL}/event/${eventId}?` +
`description=${encodeURIComponent(includeDescription)}&` +
`metrics=${encodeURIComponent(includeMetrics)}` +
`${fresh ? '&fresh=true' : ''}`,
{
signal: abortSignal instanceof AbortSignal ? abortSignal : undefined,
Expand All @@ -33,7 +35,7 @@ async function getEventAndOwners(eventId, abortSignal, includeMetrics = true, fr
}
if (!includeMetrics) {
return {
event: Event(body.event),
event: Event(body.event, includeDescription),
owners: body.owners,
ts: body.ts,
}
Expand All @@ -48,7 +50,7 @@ async function getEventAndOwners(eventId, abortSignal, includeMetrics = true, fr
!('ts' in body.metrics) || (typeof body.metrics.ts !== 'number' && body.metrics.ts !== null)
) {
return {
event: Event(body.event),
event: Event(body.event, includeDescription),
owners: body.owners,
ts: body.ts,
metrics: {
Expand All @@ -62,7 +64,7 @@ async function getEventAndOwners(eventId, abortSignal, includeMetrics = true, fr
}
}
return {
event: Event(body.event),
event: Event(body.event, includeDescription),
owners: body.owners,
ts: body.ts,
metrics: {
Expand Down
15 changes: 11 additions & 4 deletions src/loaders/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async function fetchEventsOrErrors(eventIds, limit = 100) {
return [eventsMap, errorsMap]
}

async function fetchEvent(eventId, abortSignal) {
async function fetchEvent(eventId, includeDescription, abortSignal) {
const response = await fetch(`${POAP_API_URL}/events/id/${eventId}`, {
signal: abortSignal instanceof AbortSignal ? abortSignal : null,
headers: {
Expand All @@ -141,15 +141,22 @@ async function fetchEvent(eventId, abortSignal) {
throw new Error(`Fetch event '${eventId}' response was not success`)
}
return Event(
await response.json()
await response.json(),
includeDescription
)
}

async function eventLoader({ params, request }) {
const force = new URL(request.url).searchParams.get('force')
if (!force) {
try {
const eventAndOwners = await getEventAndOwners(params.eventId, /*abortSignal*/undefined, /*includeMetrics*/true, /*fresh*/true)
const eventAndOwners = await getEventAndOwners(
params.eventId,
/*abortSignal*/undefined,
/*includeDescription*/true,
/*includeMetrics*/true,
/*fresh*/true
)
if (eventAndOwners) {
return {
event: eventAndOwners.event,
Expand All @@ -162,7 +169,7 @@ async function eventLoader({ params, request }) {
console.error(err)
}
}
const event = await fetchEvent(params.eventId)
const event = await fetchEvent(params.eventId, /*includeDescription*/true)
if (!event) {
throw new Response('', {
status: 404,
Expand Down
3 changes: 2 additions & 1 deletion src/models/event.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
function Event(event) {
function Event(event, includeDescription) {
return {
id: event.id,
name: event.name,
description: includeDescription ? event.description : undefined,
image_url: event.image_url,
original_url: event.original_url
?? event.drop_image?.gateways?.reduce(
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Event.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ function Event() {
return (
<Page>
<div className="event">
<div className="event-header">
<div className="event-header-info">
<EventInfo
event={event}
stats={{
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Events.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function Events() {
}
removeErrors(eventId)
setLoading((alsoLoading) => ({ ...alsoLoading, [eventId]: LOADING_OWNERS }))
return getEventAndOwners(eventId, abortSignal, /*includeMetrics*/true, /*fresh*/true).then(
return getEventAndOwners(eventId, abortSignal, /*includeDescription*/false, /*includeMetrics*/true, /*fresh*/true).then(
(eventAndOwners) => {
removeLoading(eventId)
setOwners((prevOwners) => ({ ...prevOwners, [eventId]: eventAndOwners.owners }))
Expand Down
77 changes: 72 additions & 5 deletions src/styles/event-info.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
.event-header {
width: 100%;
.event-info-header {
position: relative;
overflow-x: auto;
left: 0;
right: 0;
}

.event-info {
Expand All @@ -17,3 +13,74 @@
.event-info .event-buttons {
margin-top: .4rem;
}

.event-info-extra {
position: absolute;
top: 4rem;
left: calc(100% - 4rem);
bottom: 4rem;
min-width: 4rem;
background-color: white;
}

.event-info-extra-card {
position: relative;
width: 100%;
height: 100%;
border: .1rem solid black;
border-top-right-radius: 1.2rem;
border-bottom-right-radius: 1.2rem;
background-color: white;
overflow: hidden;
}

.event-info-extra-card::before {
content: "";
position: absolute;
top: .8rem;
left: -.6rem;
height: 100%;
width: 100%;
border-radius: 3.2rem;
background-color: gray;
opacity: .25;
z-index: -1;
}

.event-info-extra-button {
border-width: 0;
background-color: lightgray;
cursor: pointer;
outline: 0;
}

.event-info-extra.open .event-info-extra-button {
position: absolute;
top: 0;
bottom: 0;
left: 2.7rem;
}

.event-info-extra.close .event-info-extra-button {
position: absolute;
top: 0;
right: 0;
bottom: 0;
border-top-right-radius: 1.2rem;
border-bottom-right-radius: 1.2rem;
}

.event-info-extra-content {
padding: 1rem .5rem 1rem 0;
margin: 0 .5rem 0 5rem;
height: 100%;
max-width: 100rem;
overflow-y: scroll;
overflow-x: hidden;
}

.event-info-extra-content p {
margin-top: 1rem;
margin-bottom: 1rem;
word-wrap: break-word;
}
6 changes: 6 additions & 0 deletions src/styles/event.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
overflow: scroll;
}

.event-header-info {
width: 100%;
display: flex;
overflow-x: auto;
}

.event .caching, .event .caching-error, .event .cached {
font-size: 11px;
display: inline-block;
Expand Down
5 changes: 5 additions & 0 deletions src/styles/external-link.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.external-link-icon {
width: 10px;
height: 10px;
margin-left: 3px;
}
44 changes: 44 additions & 0 deletions src/utils/linkify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { POAP_SCAN_URL } from '../models/poap'

const regexp =
/[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi;

export default function linkify(text, Anchor) {
const texts = []
const urls = []

let cursor = 0
let match

while ((match = regexp.exec(text))) {
if (!text) {
break
}
const matchedText = match[0]

texts.push(text.slice(cursor, match.index))
urls.push(matchedText)

cursor = match.index + matchedText.length
}

texts.push(text.slice(cursor, text.length))

const results = []

for (let i = 0; i < texts.length; i++) {
results.push(texts[i])

if (urls[i]) {
const href = /^https?:\/\//i.test(urls[i])
? urls[i]
: /\.eth$/i.test(urls[i])
? `${POAP_SCAN_URL}/${urls[i]}`
: `https://${urls[i]}`

results.push(Anchor({ href, key: `${i}-${href}`, children: urls[i] }));
}
}

return results.filter((x) => x)
}

0 comments on commit 03ec8b5

Please sign in to comment.