Skip to content

Commit

Permalink
🩹 Date Inconsistencies – Events Component (#2147)
Browse files Browse the repository at this point in the history
* time added and conversion to UTC

* refactor time processing and updating the schema with extra fields

* removing console logs

* deployment linting test...

* linting tests (snooze)

* remove the step field

* testing if utc-field is the linting issue...

* revert to previous implementation with a ts-ignore... :(

* TinaCMS content update

* TinaCMS content update

* updating as per Josh's comments and removing end time

* TinaCMS content update

Co-authored-by: Brady Stroud <[email protected]>

* TinaCMS content update

Co-authored-by: Brady Stroud <[email protected]>

* adding comments to calculations and fixing a bool name

* added a dummy field to help indicate to the users what's going on

* TinaCMS content update

Co-authored-by: Brady Stroud <[email protected]>

* TinaCMS content update

Co-authored-by: Brady Stroud <[email protected]>

* updating descriptions

* tina-lock

* changing the start time text

* TinaCMS content update

---------

Co-authored-by: tina-cloud-app[bot] <58178390+tina-cloud-app[bot]@users.noreply.github.com>
Co-authored-by: Brady Stroud <[email protected]>
  • Loading branch information
3 people authored Sep 11, 2024
1 parent 6643a11 commit 464a1b4
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 116 deletions.
2 changes: 0 additions & 2 deletions components/DocumentationNavigation/DocsNavigationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ const NavLevel = ({
)

const selected = path == slug || (slug == '/docs' && path == "/docs/")
console.log(categoryData.items)
console.log(router.asPath)
const childSelected = hasNestedSlug(categoryData.items, router.asPath)

React.useEffect(() => {
Expand Down
52 changes: 0 additions & 52 deletions components/blocks/Events.template.ts

This file was deleted.

142 changes: 142 additions & 0 deletions components/blocks/Events.template.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import type { Template } from 'tinacms'
import { NumberField, NumberFieldPlugin, NumberInput, TextField, wrapFieldsWithMeta } from 'tinacms'
import React from 'react'

const formatTimezoneOption = (value, prefix = "+") => {
return { value: value, label: `GMT ${prefix}${Math.floor(value)}:${value % 1 ? "3" : "0"}0` }
}

const positiveTimezoneList = Array.from(Array(29).keys()).map(value => formatTimezoneOption(value / 2)).reverse()
const negativeTimezoneList = Array.from(Array(24).keys()).map(value =>
{
const tempOption = formatTimezoneOption((value / 2) + 0.5, '-')
return {value: tempOption.value * -1, label: tempOption.label}
})

const timeFormat = Intl.DateTimeFormat('en-US', {
year: "numeric",
month: "short",
day: "numeric",
timeZone: "UTC"
});

const timezoneValidation = (value, data) => {
if (value > 23 || value < 0) {
return "The time should be between 0 (00:00) and 23 (23:00)"
}
if (value && value % 1 != 0) {
return "Only whole numbers should be used."
}
}

export const eventsTemplate: Template = {
label: 'Events',
name: 'events',
ui: {
previewSrc: '/img/blocks/events.png',
},
fields: [
{ name: 'title', label: 'Title', type: 'string' },
{
name: 'cardItems',
label: 'Card Items',
type: 'object',
list: true,
ui: {
itemProps: (item) => ({
key: item.id,
label: item.headline,
}),
},
// https://tina.io/docs/reference/toolkit/fields/date/#datetimepickerprops and https://tina.io/docs/reference/toolkit/fields/number/
// @ts-ignore: type error as utc, options and step fields aren't formally recognised but valid as per docs (linked above)
fields: [
{ name: 'headline', label: 'Headline', type: 'string' },
{
name: 'startDate',
label: 'Start Date',
type: 'datetime',
description:
'Enter date in the timezone of the event.',
ui: {
utc: true,
format: (value, name, field) => value && timeFormat.format(new Date(Date.parse(value)))
},
},
{
name: 'startTime',
label: 'Start Time',
type: 'number',
description:
"Enter start time in the timezone of the event. (e.g. if the event starts at 9:00am, enter '9')",
ui: {
step: 1,
validate: timezoneValidation
},
},
{
name: 'endDate',
label: 'End Date',
type: 'datetime',
description:
'Note this field is not mandatory. Leave blank for a 1 day event. Enter date in the timezone of the event.',
ui: {
utc: true,
format: (value, name, field) => value && timeFormat.format(new Date(Date.parse(value)))
},
},
{
//Note the below is just a UI aspect for clarity on how a new event can be specified
name: 'endTime',
label: 'End Time',
type: 'string',
description:
'This is locked to midnight on the end date of the event.',
ui: {
format: (value) => "11:59pm",
component: (props) => {
return <div className="mb-4 relative">
<div className="z-50 absolute cursor-not-allowed w-full h-full top-0 left-0"/>
<div className="opacity-50">
{TextField(props)}
</div>
</div>
}
},
},
{
name: 'timezone',
label: 'Timezone',
type: 'number',
description:
'Please select the timezone the event is being held in. GMT and UTC are analagous.',
ui: {
parse: (value) => Number(value),
component: 'select',
options: [
...positiveTimezoneList,
...negativeTimezoneList
]
}
},
{ name: 'location', label: 'Location', type: 'string' },
{ name: 'image', label: 'Image', type: 'image' },
{ name: 'link', label: 'URL', type: 'string' },
{
name: 'markerLAT',
label: 'Marker Latitude',
type: 'number',
description:
'Note this field corresponds to the Latitude position of the marker on the globe.',
},
{
name: 'markerLONG',
label: 'Marker Longitude',
type: 'number',
description:
'Note this field corresponds to the Longitude position of the marker on the globe.',
},
],
},
],
}
86 changes: 32 additions & 54 deletions components/blocks/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,66 +21,39 @@ const Card = ({ cardItem, onHover }) => {
}
}

const calculateDaysUntilEvent = (date) => {
const eventDate = new Date(date)
const currentDate = new Date()
eventDate.setHours(0, 0, 0, 0)
currentDate.setHours(0, 0, 0, 0)

const timeDifference = eventDate.getTime() - currentDate.getTime()
const daysDifference = Math.ceil(timeDifference / (1000 * 60 * 60 * 24))
return daysDifference
}

const isDateInRange = (startDate, endDate) => {
const start = new Date(startDate)
const end = new Date(endDate)
const current = new Date()
start.setHours(0, 0, 0, 0)
end.setHours(0, 0, 0, 0)
current.setHours(0, 0, 0, 0)

return current >= start && current <= end
}

const formatStartDate = (date) => {
const d = new Date(date)
return `${d.getDate()}${getOrdinalSuffix(d.getDate())} ${format(d, 'MMM')}`
}

const formatDateRange = (start, end) => {
const startDate = new Date(start)
const endDate = new Date(end)
if (startDate.getMonth() === endDate.getMonth()) {
return `${startDate.getDate()}${getOrdinalSuffix(
startDate.getDate()
)} - ${endDate.getDate()}${getOrdinalSuffix(endDate.getDate())} ${format(
endDate,
'MMM'
)}`
}
return `${startDate.getDate()}${getOrdinalSuffix(
startDate.getDate()
)} ${format(startDate, 'MMM')} - ${endDate.getDate()}${getOrdinalSuffix(
endDate.getDate()
)} ${format(endDate, 'MMM')}`
const dateFormat = (start, end?): string => {
//Gets the start date in the event time, which is "UTC" from how it's stored
const startDay = `${new Date(start).getUTCDate() + getOrdinalSuffix(new Date(start).getUTCDate())}`
const startMonth = format(new Date(start), 'MMM')
//Gets the end date in the event time, which is "UTC" from how it's stored
const endDateAndHyphen = end ? ` - ${new Date(end).getUTCDate() + getOrdinalSuffix(new Date(end).getUTCDate())}` : ''
const endMonth = end ? format(new Date(end), 'MMM') : ''
//Formats the dates into a single string
return `${startDay} ${startMonth == endMonth ? '' : startMonth}${endDateAndHyphen} ${endMonth ?? startMonth}`
}

const displayDate = () => {
if (cardItem.startDate && cardItem.endDate) {
return formatDateRange(cardItem.startDate, cardItem.endDate)
} else if (cardItem.startDate) {
return formatStartDate(cardItem.startDate)
if (cardItem.startDate) {
return dateFormat(cardItem.startDate, cardItem.endDate)
}
return ''
}

const daysUntilEvent = calculateDaysUntilEvent(cardItem.startDate)
const isPastEvent = daysUntilEvent < 0
//Gets the accurate start date-time in UTC, by applying the offset and event start time.
//Note that getting UTC minutes is actually getting the time in the event timezone, based on how the values are being stored.
const startDateUTC = new Date(Date.parse(cardItem.startDate))
startDateUTC.setUTCMinutes(startDateUTC.getUTCMinutes() + (cardItem.timezone * -60) + ((cardItem.startTime) * 60))
//Gets the provided end date at midnight in UTC, or for one day events the start date is re-used.
const endDateUTC = new Date(Date.parse(cardItem.endDate ?? cardItem.startDate))
endDateUTC.setUTCMinutes(endDateUTC.getUTCMinutes() + (cardItem.timezone * -60) + (24 * 60))
//Calculate the hours until the event/event end by subtracting start and end dates (in UTC) against the current local time (in UTC).
const hoursUntilEvent = Math.ceil((startDateUTC.getTime() - (new Date()).getTime()) / 36e5)
const hoursUntilEventEnd = Math.ceil((endDateUTC.getTime() - (new Date()).getTime()) / 36e5)

const isLiveOrPastEvent = hoursUntilEvent < 0
const isLiveEvent =
cardItem.startDate &&
cardItem.endDate &&
isDateInRange(cardItem.startDate, cardItem.endDate)
hoursUntilEvent <= 0 &&
hoursUntilEventEnd > 0

return (
<div
Expand Down Expand Up @@ -108,11 +81,16 @@ const Card = ({ cardItem, onHover }) => {
<p className="mr-2">{displayDate()}</p>
{isLiveEvent ? (
<span className="bg-teal-100 px-2 rounded text-sm text-teal-700 shadow-lg opacity-60">LIVE</span>
) : isPastEvent ? (
) : isLiveOrPastEvent ? (
<span className="bg-slate-200 px-2 rounded text-sm text-gray-700 shadow-lg opacity-60">DONE</span>
) : (
<span className="bg-teal-100 px-2 rounded text-sm text-teal-700 shadow-lg opacity-60">
{daysUntilEvent} DAY{daysUntilEvent > 1 ? 'S' : ''} TO GO
{
hoursUntilEvent >= 24 ?
`${Math.floor(hoursUntilEvent / 24)} DAY${hoursUntilEvent >= 48 ? 'S' : ''} TO GO`
:
`${hoursUntilEvent} HOUR${hoursUntilEvent > 1 ? 'S' : ''} TO GO`
}
</span>
)}
</div>
Expand Down
20 changes: 13 additions & 7 deletions content/blocksPages/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@
"cardItems": [
{
"headline": "NDC Porto",
"startDate": "2024-10-13T13:00:00.000Z",
"endDate": "2024-10-17T13:00:00.000Z",
"startDate": "2024-10-14T00:00:00.000Z",
"startTime": 9,
"endDate": "2024-10-18T00:00:00.000Z",
"timezone": 1,
"location": "Porto, Portugal",
"image": "https://res.cloudinary.com/forestry-demo/image/upload/v1724215794/e95ddece6811979e4a83e932c4116680_nslaox.jpg",
"link": "https://ndcporto.com/",
Expand All @@ -145,8 +147,9 @@
},
{
"headline": "CPH Dev Fest",
"startDate": "2024-08-25T14:00:00.000Z",
"endDate": "2024-08-29T14:00:00.000Z",
"startDate": "2024-08-26T00:00:00.000Z",
"endDate": "2024-08-30T00:00:00.000Z",
"timezone": 2,
"location": "Copenhagen, Denmark",
"image": "https://res.cloudinary.com/forestry-demo/image/upload/v1724215863/704853_s2w9sg.jpg",
"link": "https://cphdevfest.com/",
Expand All @@ -155,8 +158,10 @@
},
{
"headline": "NDC Oslo",
"startDate": "2024-05-18T14:00:00.000Z",
"endDate": "2024-05-22T14:00:00.000Z",
"startDate": "2024-05-19T00:00:00.000Z",
"startTime": 9,
"endDate": "2024-05-23T00:00:00.000Z",
"timezone": 2,
"location": "Oslo, Norway",
"image": "https://res.cloudinary.com/forestry-demo/image/upload/v1724215929/Norway_Oslo_Houses_Marinas_Bay_569380_1920x1080_ocqvvo.jpg",
"link": "https://ndcoslo.com/",
Expand All @@ -165,7 +170,8 @@
},
{
"headline": "/serverless/DAYS ANZ",
"startDate": "2024-05-20T14:00:00.000Z",
"startDate": "2024-05-21T00:00:00.000Z",
"timezone": 10,
"location": "Sydney, Australia",
"image": "https://res.cloudinary.com/forestry-demo/image/upload/v1724215959/716104_jwhkyu.jpg",
"link": "https://anz.serverlessdays.io/sydney/",
Expand Down
Binary file added public/img/blocks/events.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tina/tina-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tsconfig.tsbuildinfo

Large diffs are not rendered by default.

0 comments on commit 464a1b4

Please sign in to comment.