From ce1979da1b47e720fcc796f6752921d019640d95 Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Mon, 29 Mar 2021 05:17:55 +0300 Subject: [PATCH 01/72] add arrow to messagebox --- src/components/molecules/Chatbox/Chatbox.scss | 39 +++++++++++++- src/components/molecules/Chatbox/Chatbox.tsx | 51 ++++++++++++------- .../templates/Jazzbar/JazzTab/JazzTab.tsx | 2 + 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/components/molecules/Chatbox/Chatbox.scss b/src/components/molecules/Chatbox/Chatbox.scss index 3f453c8b6d..6cd53aa640 100644 --- a/src/components/molecules/Chatbox/Chatbox.scss +++ b/src/components/molecules/Chatbox/Chatbox.scss @@ -16,10 +16,10 @@ &__form { background-color: $black; - height: 74px; + height: 84px; padding: 10px; display: flex; - align-items: center; + flex-direction: column; } &__input { @@ -57,3 +57,38 @@ color: $white; } } + +.nav-chat-logo { + position: relative; + height: 60px; + text-align: center; + cursor: pointer; + display: flex; + align-items: center; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + transition: transform 400ms cubic-bezier(0.23, 1, 0.32, 1); + text-indent: 20px; + img { + height: 40px; + } + &:after { + content: ""; + height: 20px; + width: 20px; + background-image: url(/icons/nav-party-logo-icon.png); + background-size: 20px; + opacity: 0.4; + transform: rotate(0deg); + transition: transform 400ms cubic-bezier(0.23, 1, 0.32, 1); + } + &.clicked { + &:after { + transform: rotate(180deg); + } + } + &.slide { + transform: translateX(110px); + } +} diff --git a/src/components/molecules/Chatbox/Chatbox.tsx b/src/components/molecules/Chatbox/Chatbox.tsx index 26e9635c47..37dfa7d752 100644 --- a/src/components/molecules/Chatbox/Chatbox.tsx +++ b/src/components/molecules/Chatbox/Chatbox.tsx @@ -1,5 +1,6 @@ -import React, { useMemo, useState, useEffect } from "react"; +import React, { useMemo, useState, useEffect, useCallback } from "react"; import { useForm } from "react-hook-form"; + import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPaperPlane } from "@fortawesome/free-solid-svg-icons"; @@ -59,28 +60,42 @@ export const Chatbox: React.FC = ({ [messages, deleteMessage] ); + const [isEventScheduleVisible, setEventScheduleVisible] = useState(false); + const toggleEventSchedule = useCallback(() => { + setEventScheduleVisible(!isEventScheduleVisible); + }, [isEventScheduleVisible]); + return (
{renderedMessages}
+
- - + Schedule +
+
+ + +
); diff --git a/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx b/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx index 5fa737eddb..88dd489a10 100644 --- a/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx +++ b/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx @@ -66,6 +66,8 @@ const Jazz: React.FC = ({ setUserList, venue }) => { const jazzbarTables = venueToUse?.config?.tables ?? JAZZBAR_TABLES; + console.log(jazzbarTables); + const [seatedAtTable, setSeatedAtTable] = useState(""); const [isAudioEffectDisabled, setIsAudioEffectDisabled] = useState(false); From 05887d2fe6f75a5bcfcceb03e868ecbe459e31fc Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Fri, 2 Apr 2021 15:05:11 +0300 Subject: [PATCH 02/72] Schedule for demo --- .../molecules/EventDisplay/EventDisplay.scss | 5 + .../molecules/EventDisplay/EventDisplay.tsx | 92 +++++++-------- .../EventRoomDisplay/EventRoomDisplay.scss | 45 +++++++ .../EventRoomDisplay/EventRoomDisplay.tsx | 72 ++++++++++++ .../EventTimeSchedule/EventTimeSchedule.scss | 39 ++++++ .../EventTimeSchedule/EventTimeSchedule.tsx | 18 +++ .../molecules/EventTimeSchedule/index.ts | 1 + .../molecules/LiveSchedule/LiveSchedule.scss | 2 +- src/components/molecules/NavBar/NavBar.scss | 111 ++++++++++++++++-- .../SchedulePageModal/SchedulePageModal.tsx | 103 +++++++++++----- .../Admin/Venue/Details/VenueDetails.tsx | 2 + src/types/rooms.ts | 3 + src/utils/time.ts | 21 ++++ 13 files changed, 423 insertions(+), 91 deletions(-) create mode 100644 src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss create mode 100644 src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx create mode 100644 src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss create mode 100644 src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx create mode 100644 src/components/molecules/EventTimeSchedule/index.ts diff --git a/src/components/molecules/EventDisplay/EventDisplay.scss b/src/components/molecules/EventDisplay/EventDisplay.scss index a12bf596e0..c7eb0ad9d9 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.scss +++ b/src/components/molecules/EventDisplay/EventDisplay.scss @@ -69,6 +69,11 @@ $sand: #937c63; } } } + .bookmark-icon { + cursor: pointer; + width: 15px; + height: 20px; + } .events-list { overflow-y: auto; .event { diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index f75a535ef7..32ed900109 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -1,14 +1,16 @@ -import React, { useMemo } from "react"; +import React, { useState } from "react"; + +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; +import { faBookmark as regularBookmark } from "@fortawesome/free-regular-svg-icons"; + import classNames from "classnames"; import { AnyVenue, VenueEvent } from "types/venues"; -import { Room } from "types/rooms"; -import { formatHourAndMinute, getCurrentTimeInUTCSeconds } from "utils/time"; +import { getCurrentTimeInUTCSeconds, formatHour } from "utils/time"; import { WithId } from "utils/id"; -import { useRoom } from "hooks/useRoom"; - import "./EventDisplay.scss"; export interface EventDisplayProps { @@ -17,14 +19,7 @@ export interface EventDisplayProps { } export const EventDisplay: React.FC = ({ event, venue }) => { - const eventRoomTitle = event.room; - - const room = useMemo( - () => venue?.rooms?.find((room) => room.title === eventRoomTitle), - [venue, eventRoomTitle] - ); - - const buttonText = `${event.room ?? "Enter"} ${venue && `- ${venue.name}`}`; + const [isBookmarked, setBookmark] = useState(false); const isLiveEvent = event.start_utc_seconds < getCurrentTimeInUTCSeconds() && @@ -35,49 +30,42 @@ export const EventDisplay: React.FC = ({ event, venue }) => { "schedule-event-container--live": isLiveEvent, }); + const starHour = formatHour(event.start_utc_seconds); + const duration = Math.floor(event.duration_minutes / 60); + return ( -
-
-
- {formatHourAndMinute(event.start_utc_seconds)} -
-
- {formatHourAndMinute( - event.start_utc_seconds + event.duration_minutes * 60 - )} -
- {isLiveEvent && Live} -
+
4800 + ? 4800 - (Number(starHour) * 200 + 100) + : duration * 200 + }px`, + }} + >
{event.name}
-
- {event.description} -
-
- {event.room && room && venue ? ( - - {buttonText} - - ) : ( -
{buttonText}
- )} -
+
by {event.host}
+
+
{ + e.stopPropagation(); + setBookmark(!isBookmarked); + }} + > +
); }; - -interface EnterRoomButtonProps { - room: Room; - venue: WithId; -} - -const EnterRoomButton: React.FC = ({ - room, - venue, - children, -}) => { - const { enterRoom } = useRoom({ room, venueName: venue.name }); - - return
{children}
; -}; diff --git a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss new file mode 100644 index 0000000000..270df31c92 --- /dev/null +++ b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss @@ -0,0 +1,45 @@ +@import "scss/constants.scss"; + +$side-padding: 30px; + +$gradient: linear-gradient(-124deg, #e15ada 0%, #6f43ff 50%, #00f6d5 100%); + +$dark: #1a1d24; +$border-radius: 28px; +$large-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.34); +$login-max-width: 540px; +$modal-max-width: 540px; +$page-max-width: 1240px; + +$sand: #937c63; + +.event-room { + width: 100%; + padding: 5px; + margin-bottom: 30px; +} + +.schedule-event-info-title { + font-size: 0.8rem; + font-weight: 700; +} +.schedule-event-info-description { + font-size: 0.7rem; + opacity: 0.8; +} +.event-room-button-container { + display: flex; + text-align: center; + height: 40px; +} +.event-room-button { + width: 90%; + border-radius: 10px; + font-size: 0.7rem; + margin: 5px 0; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + background-color: rgba(255, 255, 255, 0.2); +} diff --git a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx new file mode 100644 index 0000000000..d282f1835d --- /dev/null +++ b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx @@ -0,0 +1,72 @@ +import React, { useMemo, useState } from "react"; +import classNames from "classnames"; + +import { AnyVenue, VenueEvent } from "types/venues"; + +import { WithId, WithVenueId } from "utils/id"; + +import { EventDisplay } from "components/molecules/EventDisplay/EventDisplay"; + +import "./EventRoomDisplay.scss"; + +export interface EventRoomDisplayProps { + title?: string; + events?: Array>; + venue?: WithId; +} + +export const EventRoomDisplay: React.FC = ({ + title, + events, + venue, +}) => { + const [isSelected, setIsSelected] = useState(false); + + const containerClasses = classNames("event-show-bar", { + "event-show-bar--selected": isSelected, + }); + + const eventsToShow = useMemo( + () => + events?.map((event, index) => ( + + )), + [events, venue] + ); + + return ( +
{ + e.stopPropagation(); + setIsSelected(!isSelected); + }} + > +
+
+
{title}
+
+ {events?.length} events +
+
+ {isSelected && ( +
{ + e.stopPropagation(); + }} + > + Add to calendar +
+ )} +
+
+
+
{eventsToShow}
+
+ ); +}; diff --git a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss new file mode 100644 index 0000000000..bc1c683fa2 --- /dev/null +++ b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss @@ -0,0 +1,39 @@ +@import "scss/constants.scss"; + +$side-padding: 30px; + +$gradient: linear-gradient(-124deg, #e15ada 0%, #6f43ff 50%, #00f6d5 100%); + +$dark: #1a1d24; +$border-radius: 28px; +$large-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.34); +$login-max-width: 540px; +$modal-max-width: 540px; +$page-max-width: 1240px; + +$sand: #937c63; + +.event-time-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100%; + z-index: -1; +} + +.event-time { + font-size: 1rem; + width: 200px; + display: flex; + justify-content: center; + align-items: center; + opacity: 0.5; + margin-bottom: 20px; +} +.event-time-line { + width: 1px; + background-color: white; + opacity: 0.5; + height: 100%; +} diff --git a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx new file mode 100644 index 0000000000..c299a88324 --- /dev/null +++ b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx @@ -0,0 +1,18 @@ +import React from "react"; + +import "./EventTimeSchedule.scss"; + +export interface EventTimeScheduleProps { + time: string; +} + +export const EventTimeSchedule: React.FC = ({ + time, +}) => { + return ( +
+
{time}
+
+
+ ); +}; diff --git a/src/components/molecules/EventTimeSchedule/index.ts b/src/components/molecules/EventTimeSchedule/index.ts new file mode 100644 index 0000000000..f21845b676 --- /dev/null +++ b/src/components/molecules/EventTimeSchedule/index.ts @@ -0,0 +1 @@ +export { EventTimeSchedule } from "./EventTimeSchedule"; diff --git a/src/components/molecules/LiveSchedule/LiveSchedule.scss b/src/components/molecules/LiveSchedule/LiveSchedule.scss index 4dab6aaaa2..509fe33383 100644 --- a/src/components/molecules/LiveSchedule/LiveSchedule.scss +++ b/src/components/molecules/LiveSchedule/LiveSchedule.scss @@ -31,7 +31,7 @@ background-color: rgba($black, 0.3); } &.schedule-event-container--live { - background-color: rgba($primary, 0.2); + background-color: rgba($primary); } .schedule-event-time { diff --git a/src/components/molecules/NavBar/NavBar.scss b/src/components/molecules/NavBar/NavBar.scss index 47100504cc..914ba1d8cc 100644 --- a/src/components/molecules/NavBar/NavBar.scss +++ b/src/components/molecules/NavBar/NavBar.scss @@ -298,11 +298,10 @@ $border-radius: 28px; left: 0; width: 100%; height: 620px; - display: flex; - flex-wrap: wrap; - padding: 60px 40px 0; + + padding: 60px 0; background-color: rgba($black, 0.9); - overflow: none; + overflow: auto; pointer-events: none; opacity: 0; @@ -316,10 +315,21 @@ $border-radius: 28px; opacity: 1; transform: translateY(0px); } + &::-webkit-scrollbar { + width: 8px; + background-color: rgba(0, 0, 0, 0); + } + .event-show-bar { + width: 100%; + &.event-show-bar--selected { + background-color: rgba(255, 255, 255, 0.2); + } + } .partyinfo-container { flex: 1; margin-right: 60px; + padding: 0 40px 0; .partyinfo-main { display: flex; align-items: center; @@ -358,25 +368,88 @@ $border-radius: 28px; } } + .schedule-time-container { + display: flex; + flex-direction: row; + width: 4800px; + position: absolute; + height: 800px; + } + + .current-time-line { + position: absolute; + width: 1px; + height: 760px; + margin-top: 40px; + background-color: $primary; + } .schedule-container { position: relative; flex: 2; .schedule-tabs { height: 50px; + padding: 0 40px 0; + } + + .schedule-time-line { + display: flex; + position: relative; + flex-direction: row; + width: 4800px; + padding: 0 20px 0; + } + .shcedule-time-line-room { + display: flex; + flex-direction: column; + width: 5%; margin-top: 30px; - position: fixed; + box-shadow: 10px 0 30px rgb(0 0 0 / 50%); + } + + .schedule-event-row { + width: 4800px; + display: flex; + flex-direction: row; + position: relative; + overflow-x: auto; + } + .schedule-time-line-container { + display: flex; + flex-direction: column; + height: calc(100% - 70px); + width: 95%; + margin-left: 200px; + padding-bottom: 40px; + overflow-y: scroll; + + // styling scrollbar + &::-webkit-scrollbar-track { + border-radius: 1px; + background-color: rgba(0, 0, 0, 0); + } + + &::-webkit-scrollbar { + background-color: rgba(0, 0, 0, 0); + } + + &::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba($white, 0.1); + } } .schedule-day-container { @include scrollbar; position: absolute; - width: 100%; + // width: 100%; top: 70px; + width: 85%; height: calc(100% - 70px); overflow-y: scroll; padding-bottom: 20px; .schedule-event-container { border-radius: $border-radius/2; + background-color: rgba(0, 0, 0, 0.3); } } } @@ -460,15 +533,27 @@ $border-radius: 28px; .schedule-event-container { display: flex; - align-items: flex-start; + align-items: center; padding: 12px; margin-bottom: 10px; + border-radius: 15px; + justify-content: space-between; + background-color: #ebebeb; + color: #4c494f; + z-index: 1; + max-width: 4800px; + position: absolute; + margin-top: 40px; + box-shadow: 0 5px 10px rgb(0 0 0 / 65%); - &:nth-child(odd) { - background-color: rgba($black, 0.3); + &:hover { + z-index: 1000; } + &.schedule-event-container--live { - background-color: rgba($primary, 0.2); + background-color: $primary; + + color: #ebebeb; } .schedule-event-time { @@ -496,13 +581,17 @@ $border-radius: 28px; } .schedule-event-time-soon { box-shadow: none; - background-color: rgba($primary, 0.5); } } .schedule-event-info { + .schedule-event-info--live { + background-color: $primary; + } .schedule-event-info-title { font-weight: 700; + text-overflow: ellipsis; + color: black; } .schedule-event-info-description { font-size: 0.9rem; diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 756349647f..9ed2925234 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -1,22 +1,36 @@ import React, { useState, useMemo, FC } from "react"; -import { startOfDay, addDays, isWithinInterval, endOfDay } from "date-fns"; +import { + startOfDay, + addDays, + isWithinInterval, + endOfDay, + eachHourOfInterval, +} from "date-fns"; import { range } from "lodash"; - -import { AnyVenue, VenueEvent } from "types/venues"; - -import { formatDate, formatDateToWeekday } from "utils/time"; -import { WithId, WithVenueId } from "utils/id"; -import { itemsToObjectByIdReducer } from "utils/reducers"; +import { Room } from "types/rooms"; + +import { VenueEvent } from "types/venues"; + +import { + formatDate, + formatDateToWeekday, + hoursOfTheDay, + getMinutes, + getCurrentTimeInUTCSeconds, +} from "utils/time"; +import { WithVenueId } from "utils/id"; import { isEventLiveOrFuture } from "utils/event"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; -import { EventDisplay } from "components/molecules/EventDisplay/EventDisplay"; +import { EventRoomDisplay } from "components/molecules/EventRoomDisplay/EventRoomDisplay"; +import { EventTimeSchedule } from "components/molecules/EventTimeSchedule/EventTimeSchedule"; type DatedEvents = Array<{ dateDay: Date; events: Array>; + rooms: Array; }>; const DAYS_AHEAD = 7; @@ -29,20 +43,16 @@ export const SchedulePageModal: FC = ({ isVisible, }) => { const venueId = useVenueId(); + const { parentVenue, currentVenue, - relatedVenues, relatedVenueEvents, } = useConnectRelatedVenues({ venueId, withEvents: true, }); - const relatedVenuesById: Partial< - Record> - > = relatedVenues.reduce(itemsToObjectByIdReducer, {}); - const orderedEvents: DatedEvents = useMemo(() => { const liveAndFutureEvents = relatedVenueEvents.filter(isEventLiveOrFuture); const hasEvents = liveAndFutureEvents.length > 0; @@ -65,14 +75,25 @@ export const SchedulePageModal: FC = ({ }) .sort((a, b) => a.start_utc_seconds - b.start_utc_seconds); + let roomsWithEvents: Array = []; + if (currentVenue?.rooms) { + roomsWithEvents = currentVenue?.rooms?.map((room) => { + const events = todaysEvents.filter( + (event) => event?.room === room?.title + ); + return { ...room, events }; + }); + } + return { dateDay: day, events: hasEvents ? todaysEvents : [], + rooms: hasEvents ? roomsWithEvents : [], }; }); return dates; - }, [relatedVenueEvents]); + }, [relatedVenueEvents, currentVenue]); const [date, setDate] = useState(0); @@ -93,18 +114,18 @@ export const SchedulePageModal: FC = ({ [date, orderedEvents] ); - const events = useMemo( + const eventRooms = useMemo( () => - orderedEvents[date]?.events.map((event, index) => ( - ( + )), - [currentVenue, date, orderedEvents, relatedVenuesById] + [date, orderedEvents, currentVenue] ); - const hasEvents = !!orderedEvents?.[date]?.events.length; // TODO: this was essentially used in the old logic, but the styles look @@ -127,6 +148,19 @@ export const SchedulePageModal: FC = ({ const descriptionText = hasParentVenue ? parentVenue?.config?.landingPageConfig.description : currentVenue?.config?.landingPageConfig.description; + const result = getMinutes(getCurrentTimeInUTCSeconds()); + + const hours = hoursOfTheDay( + eachHourOfInterval({ + start: startOfDay(new Date()), + end: endOfDay(new Date()), + }) + ); + const dailyHours = useMemo(() => { + return hours.map((date, index) => ( + + )); + }, [hours]); return (
@@ -149,12 +183,27 @@ export const SchedulePageModal: FC = ({
    {scheduleTabs}
-
- {events} - {!hasEvents && ( -
There are no events scheduled for this day.
- )} + +
+
+
{dailyHours}
+
+ {!hasEvents && ( +
There are no events scheduled for this day.
+ )} +
+ {eventRooms}
+ + {/*
+
{eventRooms}
+ +
*/}
diff --git a/src/pages/Admin/Venue/Details/VenueDetails.tsx b/src/pages/Admin/Venue/Details/VenueDetails.tsx index 8924426d41..229b44a313 100644 --- a/src/pages/Admin/Venue/Details/VenueDetails.tsx +++ b/src/pages/Admin/Venue/Details/VenueDetails.tsx @@ -162,6 +162,8 @@ const VenueDetails: React.FC = ({ venue }) => { closeEditingModal(); }; + console.log("ROOMS ", rooms); + return ( diff --git a/src/types/rooms.ts b/src/types/rooms.ts index e1e82a1e33..fe00072ce7 100644 --- a/src/types/rooms.ts +++ b/src/types/rooms.ts @@ -1,11 +1,14 @@ import { SoundConfigReference } from "./sounds"; +import { VenueEvent } from "types/venues"; +import { WithVenueId } from "utils/id"; export enum RoomTypes { unclickable = "UNCLICKABLE", } // @debt We should end up with 1 canonical room type export interface Room { + events?: Array>; type?: RoomTypes; zIndex?: number; title: string; diff --git a/src/utils/time.ts b/src/utils/time.ts index 63a11acc6f..1c5921db18 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -169,6 +169,20 @@ export const formatHourAndMinute = (utcSeconds: number) => { return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "HH:mm"); }; +export const formatHour = (utcSeconds: number) => { + const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); + const hh = String(date.getHours()).padStart(2, "0"); + return hh; +}; + +export const getMinutes = (utcSeconds: number) => { + const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); + const hh = date.getHours(); + const mm = date.getMinutes(); + const minutes = hh * 60 + mm; + return minutes; +}; + export const daysFromEndOfEvent = ( utcSeconds: number, durationMinutes: number @@ -239,3 +253,10 @@ export const normalizeTimestampToMilliseconds = (timestamp: number) => { ? timestamp : timestamp * ONE_SECOND_IN_MILLISECONDS; }; + +export const hoursOfTheDay = (hours: Date[]) => { + const hour = hours.map((date) => { + return format(date, "h a"); + }); + return hour; +}; From b3636b799da38faeecdc76e0031e799ed72a4983 Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Fri, 2 Apr 2021 15:15:02 +0300 Subject: [PATCH 03/72] Chatbox from staging --- src/components/molecules/Chatbox/Chatbox.scss | 39 +------------- src/components/molecules/Chatbox/Chatbox.tsx | 51 +++++++------------ .../templates/Jazzbar/JazzTab/JazzTab.tsx | 2 - .../Admin/Venue/Details/VenueDetails.tsx | 2 - 4 files changed, 20 insertions(+), 74 deletions(-) diff --git a/src/components/molecules/Chatbox/Chatbox.scss b/src/components/molecules/Chatbox/Chatbox.scss index 6cd53aa640..3f453c8b6d 100644 --- a/src/components/molecules/Chatbox/Chatbox.scss +++ b/src/components/molecules/Chatbox/Chatbox.scss @@ -16,10 +16,10 @@ &__form { background-color: $black; - height: 84px; + height: 74px; padding: 10px; display: flex; - flex-direction: column; + align-items: center; } &__input { @@ -57,38 +57,3 @@ color: $white; } } - -.nav-chat-logo { - position: relative; - height: 60px; - text-align: center; - cursor: pointer; - display: flex; - align-items: center; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - transition: transform 400ms cubic-bezier(0.23, 1, 0.32, 1); - text-indent: 20px; - img { - height: 40px; - } - &:after { - content: ""; - height: 20px; - width: 20px; - background-image: url(/icons/nav-party-logo-icon.png); - background-size: 20px; - opacity: 0.4; - transform: rotate(0deg); - transition: transform 400ms cubic-bezier(0.23, 1, 0.32, 1); - } - &.clicked { - &:after { - transform: rotate(180deg); - } - } - &.slide { - transform: translateX(110px); - } -} diff --git a/src/components/molecules/Chatbox/Chatbox.tsx b/src/components/molecules/Chatbox/Chatbox.tsx index 37dfa7d752..26e9635c47 100644 --- a/src/components/molecules/Chatbox/Chatbox.tsx +++ b/src/components/molecules/Chatbox/Chatbox.tsx @@ -1,6 +1,5 @@ -import React, { useMemo, useState, useEffect, useCallback } from "react"; +import React, { useMemo, useState, useEffect } from "react"; import { useForm } from "react-hook-form"; - import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPaperPlane } from "@fortawesome/free-solid-svg-icons"; @@ -60,42 +59,28 @@ export const Chatbox: React.FC = ({ [messages, deleteMessage] ); - const [isEventScheduleVisible, setEventScheduleVisible] = useState(false); - const toggleEventSchedule = useCallback(() => { - setEventScheduleVisible(!isEventScheduleVisible); - }, [isEventScheduleVisible]); - return (
{renderedMessages}
-
-
+
-
- - -
+ +
); diff --git a/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx b/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx index 88dd489a10..5fa737eddb 100644 --- a/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx +++ b/src/components/templates/Jazzbar/JazzTab/JazzTab.tsx @@ -66,8 +66,6 @@ const Jazz: React.FC = ({ setUserList, venue }) => { const jazzbarTables = venueToUse?.config?.tables ?? JAZZBAR_TABLES; - console.log(jazzbarTables); - const [seatedAtTable, setSeatedAtTable] = useState(""); const [isAudioEffectDisabled, setIsAudioEffectDisabled] = useState(false); diff --git a/src/pages/Admin/Venue/Details/VenueDetails.tsx b/src/pages/Admin/Venue/Details/VenueDetails.tsx index 229b44a313..8924426d41 100644 --- a/src/pages/Admin/Venue/Details/VenueDetails.tsx +++ b/src/pages/Admin/Venue/Details/VenueDetails.tsx @@ -162,8 +162,6 @@ const VenueDetails: React.FC = ({ venue }) => { closeEditingModal(); }; - console.log("ROOMS ", rooms); - return ( From 6b6c57b84baeaf9d6c92f62985d8517d0bc84a45 Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Fri, 2 Apr 2021 17:59:26 +0300 Subject: [PATCH 04/72] sticky rooms --- .../molecules/EventDisplay/EventDisplay.tsx | 12 +++- .../EventRoomDisplay/EventRoomDisplay.tsx | 4 ++ src/components/molecules/NavBar/NavBar.scss | 24 ++++---- .../SchedulePageModal/SchedulePageModal.tsx | 59 +++++++++++++------ 4 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index 32ed900109..9ae7585245 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import { format } from "date-fns"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; @@ -31,16 +32,21 @@ export const EventDisplay: React.FC = ({ event, venue }) => { }); const starHour = formatHour(event.start_utc_seconds); + const oneHourBehind = format( + new Date().setHours(new Date().getHours() - 1), + "HH" + ); const duration = Math.floor(event.duration_minutes / 60); + const beginnigToShow = Number(starHour) - Number(oneHourBehind); return (
4800 - ? 4800 - (Number(starHour) * 200 + 100) + beginnigToShow * 200 + 100 + duration * 200 > 4800 + ? 4800 - (Number(beginnigToShow) * 200 + 100) : duration * 200 }px`, }} diff --git a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx index d282f1835d..4ef186910d 100644 --- a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx +++ b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx @@ -38,6 +38,10 @@ export const EventRoomDisplay: React.FC = ({ [events, venue] ); + if (events?.length === 0) { + return <>; + } + return (
= ({ )), [date, orderedEvents, currentVenue] ); + + const roomsWithEvents = useMemo(() => { + let counter = 0; + + orderedEvents[date]?.rooms.map((room, index) => { + if (room.events?.length !== 0) { + counter++; + } + }); + return counter; + }, [date, orderedEvents]); + const hasEvents = !!orderedEvents?.[date]?.events.length; // TODO: this was essentially used in the old logic, but the styles look @@ -148,11 +160,11 @@ export const SchedulePageModal: FC = ({ const descriptionText = hasParentVenue ? parentVenue?.config?.landingPageConfig.description : currentVenue?.config?.landingPageConfig.description; - const result = getMinutes(getCurrentTimeInUTCSeconds()); + const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()) - 60; const hours = hoursOfTheDay( eachHourOfInterval({ - start: startOfDay(new Date()), + start: new Date().setHours(new Date().getHours() - 1), end: endOfDay(new Date()), }) ); @@ -179,27 +191,40 @@ export const SchedulePageModal: FC = ({

{descriptionText}

+
+
    {scheduleTabs}
+
-
    {scheduleTabs}
+ {hasEvents && ( +
+
+
+ {dailyHours} +
+
+
+ {eventRooms} +
+ )} -
+ {!hasEvents && (
-
{dailyHours}
-
- {!hasEvents && ( -
There are no events scheduled for this day.
- )} +
There are no events scheduled for this day.
- {eventRooms} -
- + )} {/*
{eventRooms}
From 5717560b63a4aee251af8226a8c8f9bd0d8c2d9f Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Fri, 2 Apr 2021 19:08:38 +0300 Subject: [PATCH 05/72] showing time --- .../molecules/EventDisplay/EventDisplay.tsx | 17 ++++++++++++++--- .../SchedulePageModal/SchedulePageModal.tsx | 17 ++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index 9ae7585245..c1b72b519d 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useMemo } from "react"; import { format } from "date-fns"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -9,7 +9,7 @@ import classNames from "classnames"; import { AnyVenue, VenueEvent } from "types/venues"; -import { getCurrentTimeInUTCSeconds, formatHour } from "utils/time"; +import { getCurrentTimeInUTCSeconds, formatHour, getMinutes } from "utils/time"; import { WithId } from "utils/id"; import "./EventDisplay.scss"; @@ -32,6 +32,7 @@ export const EventDisplay: React.FC = ({ event, venue }) => { }); const starHour = formatHour(event.start_utc_seconds); + const oneHourBehind = format( new Date().setHours(new Date().getHours() - 1), "HH" @@ -39,11 +40,21 @@ export const EventDisplay: React.FC = ({ event, venue }) => { const duration = Math.floor(event.duration_minutes / 60); const beginnigToShow = Number(starHour) - Number(oneHourBehind); + const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()); + + const timeToShow = useMemo(() => { + const minutesShowing = + currentMinutes >= 1020 ? 1020 : (new Date().getHours() - 1) * 60; + const startTime = getMinutes(event.start_utc_seconds); + + return startTime - minutesShowing; + }, [currentMinutes, event.start_utc_seconds]); + return (
4800 ? 4800 - (Number(beginnigToShow) * 200 + 100) diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 1e9bb80674..35499fb4ab 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -160,14 +160,25 @@ export const SchedulePageModal: FC = ({ const descriptionText = hasParentVenue ? parentVenue?.config?.landingPageConfig.description : currentVenue?.config?.landingPageConfig.description; - const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()) - 60; + + const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()); const hours = hoursOfTheDay( eachHourOfInterval({ - start: new Date().setHours(new Date().getHours() - 1), + start: new Date().setHours( + currentMinutes >= 1020 ? 17 : new Date().getHours() - 1 + ), end: endOfDay(new Date()), }) ); + + const timeToShow = useMemo(() => { + const minutesShowing = + currentMinutes >= 1020 ? 1020 : (new Date().getHours() - 1) * 60; + + return currentMinutes - minutesShowing; + }, [currentMinutes]); + const dailyHours = useMemo(() => { return hours.map((date, index) => ( @@ -211,7 +222,7 @@ export const SchedulePageModal: FC = ({
From 545575b2f312825646de008c5d7713c620a63a04 Mon Sep 17 00:00:00 2001 From: ivangachmov Date: Fri, 2 Apr 2021 19:20:57 +0300 Subject: [PATCH 06/72] merge --- src/components/molecules/EventDisplay/EventDisplay.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index c1b72b519d..1632292fc0 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -31,14 +31,14 @@ export const EventDisplay: React.FC = ({ event, venue }) => { "schedule-event-container--live": isLiveEvent, }); - const starHour = formatHour(event.start_utc_seconds); + const starEventHour = formatHour(event.start_utc_seconds); const oneHourBehind = format( new Date().setHours(new Date().getHours() - 1), "HH" ); const duration = Math.floor(event.duration_minutes / 60); - const beginnigToShow = Number(starHour) - Number(oneHourBehind); + const beginnigToShow = Number(starEventHour) - Number(oneHourBehind); const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()); From a6cd04b7351b3b004d58205991ae7fd7e65d4ead Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 4 May 2021 20:25:27 +0300 Subject: [PATCH 07/72] Remove unused/old schedule components --- .../EventRoomDisplay/EventRoomDisplay.scss | 45 ------ .../EventRoomDisplay/EventRoomDisplay.tsx | 76 ---------- .../EventTimeSchedule/EventTimeSchedule.scss | 39 ----- .../EventTimeSchedule/EventTimeSchedule.tsx | 18 --- .../molecules/EventTimeSchedule/index.ts | 1 - .../molecules/LiveSchedule/LiveSchedule.scss | 51 ------- .../molecules/LiveSchedule/LiveSchedule.tsx | 65 --------- .../molecules/LiveSchedule/index.ts | 1 - .../organisms/AppRouter/AppRouter.jsx | 2 - src/pages/Schedule/SchedulePage.scss | 28 ---- src/pages/Schedule/SchedulePage.tsx | 136 ------------------ 11 files changed, 462 deletions(-) delete mode 100644 src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss delete mode 100644 src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx delete mode 100644 src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss delete mode 100644 src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx delete mode 100644 src/components/molecules/EventTimeSchedule/index.ts delete mode 100644 src/components/molecules/LiveSchedule/LiveSchedule.scss delete mode 100644 src/components/molecules/LiveSchedule/LiveSchedule.tsx delete mode 100644 src/components/molecules/LiveSchedule/index.ts delete mode 100644 src/pages/Schedule/SchedulePage.scss delete mode 100644 src/pages/Schedule/SchedulePage.tsx diff --git a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss deleted file mode 100644 index 270df31c92..0000000000 --- a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.scss +++ /dev/null @@ -1,45 +0,0 @@ -@import "scss/constants.scss"; - -$side-padding: 30px; - -$gradient: linear-gradient(-124deg, #e15ada 0%, #6f43ff 50%, #00f6d5 100%); - -$dark: #1a1d24; -$border-radius: 28px; -$large-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.34); -$login-max-width: 540px; -$modal-max-width: 540px; -$page-max-width: 1240px; - -$sand: #937c63; - -.event-room { - width: 100%; - padding: 5px; - margin-bottom: 30px; -} - -.schedule-event-info-title { - font-size: 0.8rem; - font-weight: 700; -} -.schedule-event-info-description { - font-size: 0.7rem; - opacity: 0.8; -} -.event-room-button-container { - display: flex; - text-align: center; - height: 40px; -} -.event-room-button { - width: 90%; - border-radius: 10px; - font-size: 0.7rem; - margin: 5px 0; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - background-color: rgba(255, 255, 255, 0.2); -} diff --git a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx b/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx deleted file mode 100644 index 4ef186910d..0000000000 --- a/src/components/molecules/EventRoomDisplay/EventRoomDisplay.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useMemo, useState } from "react"; -import classNames from "classnames"; - -import { AnyVenue, VenueEvent } from "types/venues"; - -import { WithId, WithVenueId } from "utils/id"; - -import { EventDisplay } from "components/molecules/EventDisplay/EventDisplay"; - -import "./EventRoomDisplay.scss"; - -export interface EventRoomDisplayProps { - title?: string; - events?: Array>; - venue?: WithId; -} - -export const EventRoomDisplay: React.FC = ({ - title, - events, - venue, -}) => { - const [isSelected, setIsSelected] = useState(false); - - const containerClasses = classNames("event-show-bar", { - "event-show-bar--selected": isSelected, - }); - - const eventsToShow = useMemo( - () => - events?.map((event, index) => ( - - )), - [events, venue] - ); - - if (events?.length === 0) { - return <>; - } - - return ( -
{ - e.stopPropagation(); - setIsSelected(!isSelected); - }} - > -
-
-
{title}
-
- {events?.length} events -
-
- {isSelected && ( -
{ - e.stopPropagation(); - }} - > - Add to calendar -
- )} -
-
-
-
{eventsToShow}
-
- ); -}; diff --git a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss deleted file mode 100644 index bc1c683fa2..0000000000 --- a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.scss +++ /dev/null @@ -1,39 +0,0 @@ -@import "scss/constants.scss"; - -$side-padding: 30px; - -$gradient: linear-gradient(-124deg, #e15ada 0%, #6f43ff 50%, #00f6d5 100%); - -$dark: #1a1d24; -$border-radius: 28px; -$large-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.34); -$login-max-width: 540px; -$modal-max-width: 540px; -$page-max-width: 1240px; - -$sand: #937c63; - -.event-time-container { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 100%; - z-index: -1; -} - -.event-time { - font-size: 1rem; - width: 200px; - display: flex; - justify-content: center; - align-items: center; - opacity: 0.5; - margin-bottom: 20px; -} -.event-time-line { - width: 1px; - background-color: white; - opacity: 0.5; - height: 100%; -} diff --git a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx b/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx deleted file mode 100644 index c299a88324..0000000000 --- a/src/components/molecules/EventTimeSchedule/EventTimeSchedule.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -import "./EventTimeSchedule.scss"; - -export interface EventTimeScheduleProps { - time: string; -} - -export const EventTimeSchedule: React.FC = ({ - time, -}) => { - return ( -
-
{time}
-
-
- ); -}; diff --git a/src/components/molecules/EventTimeSchedule/index.ts b/src/components/molecules/EventTimeSchedule/index.ts deleted file mode 100644 index f21845b676..0000000000 --- a/src/components/molecules/EventTimeSchedule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { EventTimeSchedule } from "./EventTimeSchedule"; diff --git a/src/components/molecules/LiveSchedule/LiveSchedule.scss b/src/components/molecules/LiveSchedule/LiveSchedule.scss deleted file mode 100644 index 509fe33383..0000000000 --- a/src/components/molecules/LiveSchedule/LiveSchedule.scss +++ /dev/null @@ -1,51 +0,0 @@ -@import "scss/constants.scss"; - -.sidebar-container .schedule-container { - @include scrollbar; - height: calc(100% - #{$chat-input-height + $footer-height}); - flex-direction: column; - display: none; - overflow-y: scroll; - overflow-x: hidden; - - &.show { - display: flex; - } - - .schedule-tabs { - height: auto; - padding: 20px 12px; - li { - font-size: 0.9rem; - padding: 10px 6px; - } - } - - .schedule-event-container { - display: flex; - align-items: flex-start; - padding: 12px; - margin-bottom: 4px; - - &:nth-child(odd) { - background-color: rgba($black, 0.3); - } - &.schedule-event-container--live { - background-color: rgba($primary); - } - - .schedule-event-time { - width: 88px; - flex-shrink: 0; - } - } -} - -.schedule-event-empty { - width: 100%; - height: 100%; - flex-grow: 1; - display: flex; - align-items: center; - justify-content: center; -} diff --git a/src/components/molecules/LiveSchedule/LiveSchedule.tsx b/src/components/molecules/LiveSchedule/LiveSchedule.tsx deleted file mode 100644 index 676be11ccb..0000000000 --- a/src/components/molecules/LiveSchedule/LiveSchedule.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { FC, useCallback, useMemo } from "react"; - -import { VenueEvent } from "types/venues"; - -import { isEventLive } from "utils/event"; -import { venueSelector } from "utils/selectors"; -import { WithVenueId } from "utils/id"; - -import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; -import { useSelector } from "hooks/useSelector"; -import { useVenueId } from "hooks/useVenueId"; - -import { EventDisplay } from "../EventDisplay"; - -import "./LiveSchedule.scss"; -import { hasElements } from "utils/types"; - -const LiveSchedule: FC = () => { - const venueId = useVenueId(); - const currentVenue = useSelector(venueSelector); - useConnectRelatedVenues({ venueId }); - - const { relatedVenueEvents, relatedVenues } = useConnectRelatedVenues({ - venueId, - withEvents: true, - }); - - const relatedVenueFor = useCallback( - (event: WithVenueId) => - relatedVenues.find((venue) => venue.id === event.venueId) ?? currentVenue, - [currentVenue, relatedVenues] - ); - - const events = useMemo(() => { - return relatedVenueEvents && relatedVenueEvents.length - ? relatedVenueEvents.filter((event) => isEventLive(event)) - : []; - }, [relatedVenueEvents]); - - const hasEvents = hasElements(events); - - const renderedEvents = useMemo(() => { - if (!hasEvents) return null; - - return events.map((event, index) => ( - - )); - }, [events, hasEvents, relatedVenueFor]); - - if (!hasEvents) { - return
No live events for now
; - } - - return ( -
-
{renderedEvents}
-
- ); -}; - -export default LiveSchedule; diff --git a/src/components/molecules/LiveSchedule/index.ts b/src/components/molecules/LiveSchedule/index.ts deleted file mode 100644 index 9c9ba4f49d..0000000000 --- a/src/components/molecules/LiveSchedule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./LiveSchedule"; diff --git a/src/components/organisms/AppRouter/AppRouter.jsx b/src/components/organisms/AppRouter/AppRouter.jsx index 13a3fbff08..858ce8cd4f 100644 --- a/src/components/organisms/AppRouter/AppRouter.jsx +++ b/src/components/organisms/AppRouter/AppRouter.jsx @@ -32,7 +32,6 @@ import { DEFAULT_REDIRECT_URL, SPARKLEVERSE_HOMEPAGE_URL } from "settings"; import VenuePage from "pages/VenuePage"; import { venueLandingUrl } from "utils/url"; import { RoomsForm } from "pages/Admin/Venue/Rooms/RoomsForm"; -import { SchedulePage } from "pages/Schedule/SchedulePage"; import { VenueAdminPage } from "pages/Admin/Venue/VenueAdminPage"; const AppRouter = () => { @@ -74,7 +73,6 @@ const AppRouter = () => { - ( diff --git a/src/pages/Schedule/SchedulePage.scss b/src/pages/Schedule/SchedulePage.scss deleted file mode 100644 index f7c2a78999..0000000000 --- a/src/pages/Schedule/SchedulePage.scss +++ /dev/null @@ -1,28 +0,0 @@ -.schedule-page { - padding: 20px; - overflow: hidden; - height: 100%; - max-height: 100%; -} - -.schedule-container { - height: 100%; - max-height: 100%; -} - -.scheduling-table { - &table { - border-collapse: collapse; - } - - &table, - th, - td { - border: 1px solid blue; - } - - th, - td { - padding: 5px; - } -} diff --git a/src/pages/Schedule/SchedulePage.tsx b/src/pages/Schedule/SchedulePage.tsx deleted file mode 100644 index cf22de3bbf..0000000000 --- a/src/pages/Schedule/SchedulePage.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import Bugsnag from "@bugsnag/js"; -import React, { useState, useMemo } from "react"; -import WithNavigationBar from "components/organisms/WithNavigationBar"; -import firebase from "firebase/app"; -import { OnlineStatsData } from "types/OnlineStatsData"; -import { range } from "lodash"; -import { startOfDay, addDays, isWithinInterval, endOfDay } from "date-fns"; -import "./SchedulePage.scss"; -import { Link } from "react-router-dom"; -import { DEFAULT_VENUE } from "settings"; -import { venueInsideUrl } from "utils/url"; -import { useInterval } from "hooks/useInterval"; -import { FIVE_MINUTES_MS } from "utils/time"; - -type OpenVenues = OnlineStatsData["openVenues"]; -type OpenVenue = OpenVenues[number]; - -type VenueEvent = { - venue: OpenVenue["venue"]; - event: OpenVenue["currentEvents"][number]; -}; - -type DatedEvents = Array<{ - dateDay: Date; - events: Array; -}>; - -const DAYS_AHEAD = 100; - -export const SchedulePage = () => { - const [openVenues, setOpenVenues] = useState(); - - useInterval(() => { - firebase - .functions() - .httpsCallable("stats-getOnlineStats")() - .then((result) => { - const { openVenues } = result.data as OnlineStatsData; - - setOpenVenues(openVenues); - }) - .catch(Bugsnag.notify); - }, FIVE_MINUTES_MS); - - const orderedEvents: DatedEvents = useMemo(() => { - if (!openVenues) return []; - - const nowDay = startOfDay(new Date()); - - const allEvents = openVenues.reduce>( - (acc, ov) => [ - ...acc, - ...ov.currentEvents.map((event) => ({ venue: ov.venue, event })), - ], - [] - ); - - const dates: DatedEvents = range(0, DAYS_AHEAD).map((idx) => { - const day = addDays(nowDay, idx); - - return { - dateDay: day, - events: allEvents - .filter((ve) => - // some events will span multiple days. Pick events for which `day` is between the event start and end - isWithinInterval(day, { - start: startOfDay(new Date(ve.event.start_utc_seconds * 1000)), - end: endOfDay( - new Date( - (ve.event.start_utc_seconds + - ve.event.duration_minutes * 60) * - 1000 - ) - ), - }) - ) - .sort( - (a, b) => a.event.start_utc_seconds - b.event.start_utc_seconds - ), - }; - }); - - return dates; - }, [openVenues]); - - return ( - -
-

Sparkleverse Schedule

-
- {orderedEvents.map((event) => ( -
-

{event.dateDay.toDateString()}

- - - - - - - - - {event.events.map((dayEvent) => ( - - - - - - - - ))} -
StartsEndsTitleDescriptionLocation
- {new Date( - dayEvent.event.start_utc_seconds * 1000 - ).toString()} - - {new Date( - (dayEvent.event.start_utc_seconds + - dayEvent.event.duration_minutes * 60) * - 1000 - ).toString()} - {dayEvent.event.name}{dayEvent.event.description} - - {dayEvent.venue.name} - -
-
- ))} -
-
-
- ); -}; From 020e7e5460f58cda756b163fd73dd19241d8004c Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 4 May 2021 22:44:03 +0300 Subject: [PATCH 08/72] Base Schedule functionality --- src/components/molecules/NavBar/NavBar.scss | 306 ------------------ .../Schedule/Schedule.constants.scss | 5 + .../molecules/Schedule/Schedule.scss | 74 +++++ .../molecules/Schedule/Schedule.tsx | 140 ++++++++ src/components/molecules/Schedule/index.ts | 1 + .../ScheduleEvent/ScheduleEvent.scss | 80 +++++ .../molecules/ScheduleEvent/ScheduleEvent.tsx | 91 ++++++ .../molecules/ScheduleEvent/index.ts | 1 + .../ScheduleRoomEvents.scss | 4 + .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 34 ++ .../molecules/ScheduleRoomEvents/index.ts | 1 + .../ScheduleVenueDescription.scss | 43 +++ .../ScheduleVenueDescription.tsx | 42 +++ .../ScheduleVenueDescription/index.ts | 1 + .../SchedulePageModal/SchedulePageModal.scss | 110 +++---- .../SchedulePageModal/SchedulePageModal.tsx | 283 +++++----------- .../SchedulePageModal.utils.ts | 83 +++++ src/utils/time.ts | 40 ++- 18 files changed, 758 insertions(+), 581 deletions(-) create mode 100644 src/components/molecules/Schedule/Schedule.constants.scss create mode 100644 src/components/molecules/Schedule/Schedule.scss create mode 100644 src/components/molecules/Schedule/Schedule.tsx create mode 100644 src/components/molecules/Schedule/index.ts create mode 100644 src/components/molecules/ScheduleEvent/ScheduleEvent.scss create mode 100644 src/components/molecules/ScheduleEvent/ScheduleEvent.tsx create mode 100644 src/components/molecules/ScheduleEvent/index.ts create mode 100644 src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss create mode 100644 src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx create mode 100644 src/components/molecules/ScheduleRoomEvents/index.ts create mode 100644 src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss create mode 100644 src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx create mode 100644 src/components/molecules/ScheduleVenueDescription/index.ts create mode 100644 src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts diff --git a/src/components/molecules/NavBar/NavBar.scss b/src/components/molecules/NavBar/NavBar.scss index a99191afc2..85a4b6ffee 100644 --- a/src/components/molecules/NavBar/NavBar.scss +++ b/src/components/molecules/NavBar/NavBar.scss @@ -291,174 +291,6 @@ $border-radius: 28px; text-shadow: 0 2px 3px rgb(0 0 0 / 35%); } -.schedule-dropdown-body { - position: fixed; - z-index: z(navbar-schedule); - top: 0; - left: 0; - width: 100%; - height: 620px; - - padding: 60px 0; - background-color: rgba($black, 0.9); - overflow: auto; - - pointer-events: none; - opacity: 0; - transform: translateY(-800px); - backdrop-filter: blur(5px); - box-shadow: 0 20px 50px 0 rgba(0, 0, 0, 0.33); - transition: all 400ms $transition-function; - - &.show { - pointer-events: all; - opacity: 1; - transform: translateY(0px); - } - &::-webkit-scrollbar { - width: 8px; - background-color: rgba(0, 0, 0, 0); - } - .event-show-bar { - width: 100%; - &.event-show-bar--selected { - background-color: rgba(255, 255, 255, 0.2); - } - } - - .partyinfo-container { - position: sticky; - left: 0; - flex: 1; - margin-right: 60px; - padding: 0 40px 0; - .partyinfo-main { - display: flex; - align-items: center; - margin-top: 2rem; - margin-bottom: 1rem; - .partyinfo-pic { - flex-shrink: 0; - width: 92px; - height: 92px; - background-size: cover; - border-radius: 46px; - margin-right: 20px; - cursor: pointer; - transition: all 400ms $transition-function; - box-shadow: 0 8px 16px rgba($black, 0.3); - &:hover { - transform: scale(1.1); - } - &:active { - transform: scale(0.9); - } - } - .partyinfo-title { - h2 { - font-style: italic; - margin-bottom: 5px; - } - h3 { - font-weight: 400; - } - } - } - .partyinfo-desc { - font-size: 0.8rem; - opacity: 0.8; - } - } - - .schedule-time-container { - display: flex; - flex-direction: row; - // width: 4800px; - position: absolute; - height: 100%; - } - - .current-time-line { - position: absolute; - width: 1px; - height: calc(100% - 40px); - margin-top: 40px; - background-color: $primary; - } - .schedule-container { - position: relative; - flex: 2; - .schedule-tabs { - height: 50px; - } - - .schedule-time-line { - display: flex; - position: relative; - flex-direction: row; - // width: 4800px; - padding: 0 20px 0; - } - .shcedule-time-line-room { - display: flex; - flex-direction: column; - width: 15%; - padding-top: 30px; - box-shadow: 10px 0 30px rgb(0 0 0 / 50%); - z-index: 5; - background-color: black; - position: sticky; - left: 30px; - } - - .schedule-event-row { - display: flex; - flex-direction: row; - position: relative; - overflow-x: auto; - } - .schedule-time-line-container { - display: flex; - flex-direction: column; - height: calc(100% - 70px); - width: 85%; - margin-left: 200px; - padding-bottom: 40px; - overflow-y: scroll; - - // styling scrollbar - &::-webkit-scrollbar-track { - border-radius: 1px; - background-color: rgba(0, 0, 0, 0); - } - - &::-webkit-scrollbar { - background-color: rgba(0, 0, 0, 0); - } - - &::-webkit-scrollbar-thumb { - border-radius: 4px; - background-color: rgba($white, 0.1); - } - } - .schedule-day-container { - @include scrollbar; - position: absolute; - // width: 100%; - top: 70px; - width: 85%; - height: calc(100% - 70px); - overflow-y: scroll; - padding-bottom: 20px; - - .schedule-event-container { - border-radius: $border-radius/2; - background-color: rgba(0, 0, 0, 0.3); - } - } - } -} - .schedule-dropdown-backdrop { position: fixed; left: 0; @@ -513,144 +345,6 @@ $border-radius: 28px; } } -.schedule-container { - @include scrollbar; - - .schedule-tabs { - li { - display: inline; - cursor: pointer; - padding: 10px 18px; - margin-right: 10px; - border-radius: $border-radius; - &:hover { - background-color: rgba($black, 0.3); - } - &.active { - background-color: $primary; - text-shadow: 0 2px 4px rgba($black, 0.3); - box-shadow: 0 3px 6px rgba($black, 0.2); - font-weight: 500; - } - } - } - - .schedule-event-container { - display: flex; - align-items: center; - padding: 12px; - margin-bottom: 10px; - border-radius: 15px; - justify-content: space-between; - background-color: #ebebeb; - color: #4c494f; - z-index: 1; - max-width: 4800px; - position: absolute; - margin-top: 40px; - box-shadow: 0 5px 10px rgb(0 0 0 / 65%); - - &:hover { - z-index: 2; - } - - &.schedule-event-container--live { - background-color: $primary; - - color: #ebebeb; - } - - .schedule-event-time { - width: 100px; - flex-shrink: 0; - .schedule-event-time-start { - font-size: 0.9rem; - font-weight: 500; - } - .schedule-event-time-end { - font-size: 0.9rem; - opacity: 0.8; - } - .schedule-event-time-live, - .schedule-event-time-soon { - display: inline-block; - font-size: 0.8rem; - font-weight: 500; - margin-top: 10px; - background-color: $primary; - box-shadow: 0 0 20px rgba($white, 0.2); - padding: 4px 10px; - border-radius: $border-radius/2; - text-align: center; - } - .schedule-event-time-soon { - box-shadow: none; - background-color: rgba($primary, 0.5); - } - } - .schedule-event-info { - .schedule-event-info--live { - background-color: $primary; - } - .schedule-event-info-title { - font-weight: 700; - text-overflow: ellipsis; - color: black; - } - .schedule-event-info-description { - font-size: 0.9rem; - opacity: 0.8; - } - .schedule-event-info-room { - margin-top: 10px; - font-size: 0.9rem; - span.schedule-event-info-room-icon { - display: inline-block; - height: 15px; - width: 15px; - vertical-align: middle; - margin-left: 4px; - margin-right: 4px; - background-size: 90px 15px; - &.schedule-event-info-room-icon_conversation { - background-position: 0 0; - } - &.schedule-event-info-room-icon_auditorium { - background-position: -15px 0; - } - &.schedule-event-info-room-icon_art { - background-position: -30px 0; - } - &.schedule-event-info-room-icon_musicbar { - background-position: -45px 0; - } - &.schedule-event-info-room-icon_reception { - background-position: -60px 0; - } - &.schedule-event-info-room-icon_concert { - background-position: -75px 0; - } - } - a { - opacity: 0.8; - text-decoration: underline; - &:hover { - opacity: 1; - } - } - div { - opacity: 0.8; - text-decoration: underline; - cursor: pointer; - &:hover { - opacity: 1; - } - } - } - } - } -} - @media (max-width: 600px) { .schedule-text { display: none; diff --git a/src/components/molecules/Schedule/Schedule.constants.scss b/src/components/molecules/Schedule/Schedule.constants.scss new file mode 100644 index 0000000000..25882bcb44 --- /dev/null +++ b/src/components/molecules/Schedule/Schedule.constants.scss @@ -0,0 +1,5 @@ +$room-count: var(--room-count, 1); +$current-time--position: var(--current-time--position, -2); +$hours-count: var(--hours-count, 8); + +$hour-width: 200px; diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss new file mode 100644 index 0000000000..4cf18c2194 --- /dev/null +++ b/src/components/molecules/Schedule/Schedule.scss @@ -0,0 +1,74 @@ +@import "scss/constants.scss"; +@import "./Schedule.constants.scss"; + +.ScheduledEvents { + padding-top: 20px; + display: flex; + position: relative; + + &__rooms { + flex-basis: 215px; + flex-shrink: 0; + margin-top: 36px; + padding-right: 20px; + box-shadow: 10px 0 30px rgba(0, 0, 0, 0.5); + font-size: 0.8rem; + } + + &__room { + margin-bottom: 1rem; + height: 70px; + display: flex; + justify-content: center; + flex-flow: column; + } + + &__schedule { + @include scrollbar; + flex-grow: 1; + overflow-x: auto; + position: relative; + } + + &__room-title { + margin-bottom: 0; + font-weight: 600; + } + + &__timeline { + height: 36px; + font-size: 0.9rem; + opacity: 0.6; + white-space: nowrap; + } + + &__hour { + width: $hour-width; + text-align: center; + display: inline-block; + + &::after { + content: ""; + display: block; + height: calc((65px + 1rem) * #{$room-count}); + border-left: 1px solid white; + margin-left: 100px; + margin-top: 18px; + } + } + + &__user-schedule { + height: 70px; + margin-bottom: 1rem; + background-color: rgba(255, 255, 255, 0.2); + width: calc(#{$hours-count} * #{$hour-width} + #{$hour-width} / 2); + } + + &__current-time-line { + position: absolute; + width: 2px; + height: calc((65px + 1rem) * #{$room-count}); + left: calc(#{$current-time--position} * 1px); + background-color: $primary; + } +} diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx new file mode 100644 index 0000000000..23acec8a10 --- /dev/null +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -0,0 +1,140 @@ +import React, { useState } from "react"; +import classNames from "classnames"; +import { format } from "date-fns"; +import { range } from "lodash"; +import { useCss } from "react-use"; + +import { Room } from "types/rooms"; +import { VenueEvent } from "types/venues"; + +import { + ONE_SECOND_IN_MILLISECONDS, + ONE_HOUR_IN_SECONDS, + getSecondsFromStartOfDay, +} from "utils/time"; + +import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; + +import "./Schedule.scss"; + +export type RoomWithEvents = Room & { events: VenueEvent[] }; + +export interface ScheduleDay { + isToday: boolean; + weekday: string; + dayStartUtcSeconds: number; + rooms: RoomWithEvents[]; +} + +export interface ScheduleProps { + scheduleDay: ScheduleDay; +} + +const MAX_SCHEDULE_START_HOUR = 16; +const HOUR_WIDTH = 200; // px + +export const Schedule: React.FC = ({ scheduleDay }) => { + const getStartHour = (utcSeconds: number) => { + return utcSeconds >= scheduleDay.dayStartUtcSeconds + ? Number(format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "H")) + : 0; + }; + + const roomStartHour = (room: RoomWithEvents) => + room.events?.reduce( + (acc, event) => Math.min(acc, getStartHour(event.start_utc_seconds)), + MAX_SCHEDULE_START_HOUR + ) ?? MAX_SCHEDULE_START_HOUR; + + const scheduleStartHour = Math.min( + ...scheduleDay.rooms.map((room) => roomStartHour(room)), + MAX_SCHEDULE_START_HOUR + ); + + const hours = range(scheduleStartHour, 24).map( + (hour: number) => `${hour % 12 || 12} ${hour >= 12 ? "PM" : "AM"}` + ); + + const calcStartPosition = (startTimeUtcSeconds: number) => { + const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + + return Math.floor( + HOUR_WIDTH / 2 + + (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * + HOUR_WIDTH + ); + }; + + const containerVars = useCss({ + "--room-count": scheduleDay.rooms.length + 1, + "--current-time--position": calcStartPosition( + Math.floor(Date.now() / ONE_SECOND_IN_MILLISECONDS) + ), + "--hours-count": hours.length, + }); + + const containerClasses = classNames("ScheduledEvents", containerVars); + + const [usersEvents, setUsersEvents] = useState([]); + + const onEventBookmarked = (isBookmarked: boolean, event: VenueEvent) => { + console.log("is bookmarked", isBookmarked); + if (isBookmarked) { + setUsersEvents([...usersEvents, event]); + } else { + setUsersEvents(usersEvents.filter((e) => e.name !== event.name)); + } + }; + + return ( +
+
+
+

My Daily Schedule

+ + {usersEvents.length} events + +
+ {scheduleDay.rooms.map((room) => ( +
+

{room.title}

+ + {room.events?.length || 0} events + +
+ ))} +
+ +
+
+ {hours.map((hour: string) => ( + + {hour} + + ))} +
+ + {scheduleDay.isToday && ( +
+ )} + +
+ +
+ {scheduleDay.rooms.map((room) => ( + + ))} +
+
+ ); +}; diff --git a/src/components/molecules/Schedule/index.ts b/src/components/molecules/Schedule/index.ts new file mode 100644 index 0000000000..100acaf802 --- /dev/null +++ b/src/components/molecules/Schedule/index.ts @@ -0,0 +1 @@ +export { Schedule } from "./Schedule"; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss new file mode 100644 index 0000000000..adf8947a45 --- /dev/null +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -0,0 +1,80 @@ +.ScheduleEvent { + display: flex; + position: absolute; + border-radius: 18px; + padding: 0 4px 0 12px; + cursor: pointer; + height: 60px; + justify-content: space-between; + align-items: center; + background-color: #3f3d42; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.65); + margin-top: 0.25rem; + + &:hover { + background-color: #4c494f; + z-index: 1; + } + + &--users { + color: #4c494f; + background-color: #ebebeb; + + &:hover { + background-color: white; + } + + .ScheduleEvent__bookmark { + color: black; + } + } + + &--live { + background-color: #7c46fb; + color: white; + + &:hover { + background-color: #8755fb; + } + + .ScheduleEvent__bookmark { + color: white; + } + } + + &__info { + font-size: 0.8rem; + overflow: hidden; + } + + &__title { + white-space: pre-line; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + } + + &__description { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + margin-top: 2px; + font-size: 0.7rem; + } + + &__bookmark { + height: 100%; + display: flex; + justify-content: center; + align-items: center; + padding: 0.5rem; + + &:hover { + padding-top: 0.375rem; + } + } +} diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx new file mode 100644 index 0000000000..c0fb53b6be --- /dev/null +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -0,0 +1,91 @@ +import React, { useState } from "react"; +import classNames from "classnames"; + +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; +import { faBookmark as regularBookmark } from "@fortawesome/free-regular-svg-icons"; + +import { VenueEvent } from "types/venues"; +import { isTruthy } from "utils/types"; + +import { + getSecondsFromStartOfDay, + ONE_HOUR_IN_SECONDS, + isLiveEvent, +} from "utils/time"; + +import "./ScheduleEvent.scss"; + +export interface ScheduleEventProps { + event: VenueEvent; + scheduleStartHour: number; + onEventBookmarked: Function; + isUsers?: boolean; +} + +const HOUR_WIDTH = 200; // px + +export const ScheduleEvent: React.FC = ({ + event, + scheduleStartHour, + onEventBookmarked, + isUsers, +}) => { + const [isBookmarked, setBookmark] = useState(isTruthy(isUsers)); + + const containerClasses = classNames( + "ScheduleEvent", + { + "ScheduleEvent--live": isLiveEvent( + event.start_utc_seconds, + event.duration_minutes + ), + }, + { "ScheduleEvent--users": isTruthy(isUsers) } + ); + + const calcStartPosition = (startTimeUtcSeconds: number) => { + const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + + return ( + HOUR_WIDTH / 2 + + (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * + HOUR_WIDTH + ); + }; + + const eventWidth = (event.duration_minutes * 200) / 60; + + const bookmarkEvent = () => { + setBookmark(!isBookmarked); + onEventBookmarked(!isBookmarked, event); + }; + + return ( +
+
+
{event.name}
+
by {event.host}
+
+ +
{ + e.stopPropagation(); + bookmarkEvent(); + }} + > + +
+
+ ); +}; diff --git a/src/components/molecules/ScheduleEvent/index.ts b/src/components/molecules/ScheduleEvent/index.ts new file mode 100644 index 0000000000..4b20b69aaa --- /dev/null +++ b/src/components/molecules/ScheduleEvent/index.ts @@ -0,0 +1 @@ +export { ScheduleEvent } from "./ScheduleEvent"; diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss new file mode 100644 index 0000000000..d73d7c89e7 --- /dev/null +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss @@ -0,0 +1,4 @@ +.RoomEvents { + height: 70px; + margin-bottom: 1rem; +} diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx new file mode 100644 index 0000000000..2713a7302c --- /dev/null +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { VenueEvent } from "types/venues"; + +import { ScheduleEvent } from "../ScheduleEvent"; + +import "./ScheduleRoomEvents.scss"; + +export interface ScheduleRoomEventsProps { + events: VenueEvent[]; + scheduleStartHour: number; + onEventBookmarked: Function; + isUsers?: boolean; +} + +export const ScheduleRoomEvents: React.FC = ({ + events, + scheduleStartHour, + onEventBookmarked, + isUsers, +}) => { + return ( +
+ {events.map((event, index) => ( + + ))} +
+ ); +}; diff --git a/src/components/molecules/ScheduleRoomEvents/index.ts b/src/components/molecules/ScheduleRoomEvents/index.ts new file mode 100644 index 0000000000..d899c995e0 --- /dev/null +++ b/src/components/molecules/ScheduleRoomEvents/index.ts @@ -0,0 +1 @@ +export { ScheduleRoomEvents } from "./ScheduleRoomEvents"; diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss new file mode 100644 index 0000000000..c24831ad69 --- /dev/null +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss @@ -0,0 +1,43 @@ +@import "scss/constants.scss"; + +.ScheduleVenueDescription { + flex: 1; + padding-left: 20px; + + &__main { + display: flex; + align-items: center; + margin-top: 2rem; + margin-bottom: 1rem; + } + + &__pic { + flex-shrink: 0; + width: 92px; + height: 92px; + background-size: cover; + border-radius: 46px; + margin-right: 20px; + cursor: pointer; + transition: all 400ms $transition-function; + box-shadow: 0 8px 16px rgba($black, 0.3); + + &:hover { + transform: scale(1.1); + } + } + + &__desc { + font-size: 0.8rem; + opacity: 0.8; + } + + &__name { + font-style: italic; + margin-bottom: 5px; + } + + &__subtitle { + font-weight: 400; + } +} diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx new file mode 100644 index 0000000000..115fea7534 --- /dev/null +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -0,0 +1,42 @@ +import React, { FC, useMemo } from "react"; + +import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; +import { useVenueId } from "hooks/useVenueId"; + +import "./ScheduleVenueDescription.scss"; + +export const ScheduleVenueDescription: FC = () => { + const venueId = useVenueId(); + + const { parentVenue, currentVenue } = useConnectRelatedVenues({ + venueId, + }); + + // @debt: ideally this would find the top most parent of parents and use those details + const scheduleVenue = useMemo( + () => (parentVenue ? parentVenue : currentVenue), + [parentVenue, currentVenue] + ); + + return ( +
+
+
+
+

+ {scheduleVenue?.name} +

+

+ {scheduleVenue?.config?.landingPageConfig?.subtitle} +

+
+
+
+

{scheduleVenue?.config?.landingPageConfig?.description}

+
+
+ ); +}; diff --git a/src/components/molecules/ScheduleVenueDescription/index.ts b/src/components/molecules/ScheduleVenueDescription/index.ts new file mode 100644 index 0000000000..8250ae4631 --- /dev/null +++ b/src/components/molecules/ScheduleVenueDescription/index.ts @@ -0,0 +1 @@ +export { ScheduleVenueDescription } from "./ScheduleVenueDescription"; diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss index b056cd6dd4..347bf218d1 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss @@ -1,72 +1,60 @@ @import "scss/constants.scss"; -$side-padding: 30px; - -$gradient: linear-gradient(-124deg, #e15ada 0%, #6f43ff 50%, #00f6d5 100%); +.SchedulePageModal { + @include scrollbar; + position: fixed; + z-index: z(navbar-schedule); + top: 0; + left: 0; + width: 100%; + height: 620px; -$dark: #1a1d24; -$border-radius: 28px; -$large-shadow: box-shadow--large(0.34); -$login-max-width: 540px; -$modal-max-width: 540px; -$page-max-width: 1240px; + padding-top: $navbar-height; + padding-left: 20px; -$sand: #937c63; + background-color: rgba($black, 0.9); + overflow: auto; -.modal-content { - width: 100%; - max-width: $modal-max-width; - margin: 0 auto; - padding: 20px 0 0 0; - background-color: $black; - box-shadow: $large-shadow; - text-align: left; - border-radius: $border-radius; - overflow: hidden; + pointer-events: none; + opacity: 0; + transform: translateY(-800px); + backdrop-filter: blur(5px); + box-shadow: 0 20px 50px 0 rgba(0, 0, 0, 0.33); + transition: all 400ms $transition-function; - h3 { - margin-bottom: 1rem; - padding: 0 $side-padding; + &--show { + pointer-events: all; + opacity: 1; + transform: translateY(0px); } - .modal-tabs { + + &__weekdays { display: flex; - flex-wrap: nowrap; - width: 100%; - align-items: center; /* Align Items Vertically */ - justify-content: space-around; - margin-bottom: 2rem; - border-bottom: 1px solid rgba($white, 0.2); - overflow-x: auto; - overflow-y: hidden; - button { - background-color: transparent; - border: none; - display: block; - position: relative; - color: white; - text-align: center; - padding: 4px 10px; - opacity: 0.7; - font-weight: 400; - &:hover { - opacity: 1; - } - &.selected { - opacity: 1; - font-weight: bold; - color: yellow; - outline: none; - &:after { - content: ""; - position: absolute; - height: 2px; - border-radius: 4px; - width: 100%; - background-color: white; - left: 0; - bottom: -1px; - } - } + padding-left: 20px; + } + + &__weekday { + display: inline; + cursor: pointer; + padding: 8px 10px; + margin-right: 10px; + border-radius: 22px; // consider variable + opacity: 0.8; + + &--active { + opacity: 1; + background-color: $primary; + text-shadow: 0 2px 4px rgba($black, 0.3); + box-shadow: 0 3px 6px rgba($black, 0.2); + } + + &:hover { + opacity: 1; } } + + &__no-events { + padding: 40px; + padding-left: 20px; + } } diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 35499fb4ab..27dfb48662 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -1,37 +1,30 @@ -import React, { useState, useMemo, FC } from "react"; -import { - startOfDay, - addDays, - isWithinInterval, - endOfDay, - eachHourOfInterval, -} from "date-fns"; +import React, { + useState, + useMemo, + FC, + useEffect, + useCallback, + MouseEventHandler, +} from "react"; +import { startOfDay } from "date-fns"; import { range } from "lodash"; -import { Room } from "types/rooms"; +import classNames from "classnames"; -import { VenueEvent } from "types/venues"; +import { Room } from "types/rooms"; -import { - formatDate, - formatDateToWeekday, - hoursOfTheDay, - getMinutes, - getCurrentTimeInUTCSeconds, -} from "utils/time"; -import { WithVenueId } from "utils/id"; +import { formatDate } from "utils/time"; import { isEventLiveOrFuture } from "utils/event"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; -import { EventRoomDisplay } from "components/molecules/EventRoomDisplay/EventRoomDisplay"; -import { EventTimeSchedule } from "components/molecules/EventTimeSchedule/EventTimeSchedule"; +import { Schedule } from "components/molecules/Schedule"; +import { ScheduleDay } from "components/molecules/Schedule/Schedule"; +import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; -type DatedEvents = Array<{ - dateDay: Date; - events: Array>; - rooms: Array; -}>; +import { scheduleDayBuilder } from "./SchedulePageModal.utils"; + +import "./SchedulePageModal.scss"; const DAYS_AHEAD = 7; @@ -44,204 +37,82 @@ export const SchedulePageModal: FC = ({ }) => { const venueId = useVenueId(); - const { - parentVenue, - currentVenue, - relatedVenueEvents, - } = useConnectRelatedVenues({ + const { relatedVenueEvents, relatedVenues } = useConnectRelatedVenues({ venueId, withEvents: true, }); - const orderedEvents: DatedEvents = useMemo(() => { + const [relatedRooms, setRelatedRooms] = useState([]); + + useEffect(() => { + const rooms: Room[] = []; + relatedVenues + .map((venue) => venue.rooms || []) + .forEach((venueRooms) => rooms.push(...venueRooms)); + setRelatedRooms(rooms); + }, [relatedVenues]); + + const schedule: ScheduleDay[] = useMemo(() => { const liveAndFutureEvents = relatedVenueEvents.filter(isEventLiveOrFuture); - const hasEvents = liveAndFutureEvents.length > 0; - - const nowDay = startOfDay(new Date()); - - const dates: DatedEvents = range(0, DAYS_AHEAD).map((idx) => { - const day = addDays(nowDay, idx); - - const todaysEvents = liveAndFutureEvents - .filter((event) => { - return isWithinInterval(day, { - start: startOfDay(new Date(event.start_utc_seconds * 1000)), - end: endOfDay( - new Date( - (event.start_utc_seconds + event.duration_minutes * 60) * 1000 - ) - ), - }); - }) - .sort((a, b) => a.start_utc_seconds - b.start_utc_seconds); - - let roomsWithEvents: Array = []; - if (currentVenue?.rooms) { - roomsWithEvents = currentVenue?.rooms?.map((room) => { - const events = todaysEvents.filter( - (event) => event?.room === room?.title - ); - return { ...room, events }; - }); - } - - return { - dateDay: day, - events: hasEvents ? todaysEvents : [], - rooms: hasEvents ? roomsWithEvents : [], - }; - }); - - return dates; - }, [relatedVenueEvents, currentVenue]); - - const [date, setDate] = useState(0); - - const scheduleTabs = useMemo( + const today = startOfDay(Date.now()); + const buildScheduleEvent = scheduleDayBuilder( + today, + liveAndFutureEvents, + relatedRooms + ); + + return range(0, DAYS_AHEAD).map((dayIndex) => buildScheduleEvent(dayIndex)); + }, [relatedVenueEvents, relatedRooms]); + + const [selectedDayIndex, setSelectedDayIndex] = useState(0); + + const onWeekdayClick = useCallback( + (index: number): MouseEventHandler => (e) => { + e.stopPropagation(); + setSelectedDayIndex(index); + }, + [] + ); + + const weekdayClasses = useCallback( + (index) => + classNames("SchedulePageModal__weekday", { + "SchedulePageModal__weekday--active": index === selectedDayIndex, + }), + [selectedDayIndex] + ); + + const weekdays = useMemo( () => - orderedEvents.map((day, idx) => ( + schedule.map((day, index) => (
  • { - e.stopPropagation(); - setDate(idx); - }} + key={formatDate(day.dayStartUtcSeconds)} + className={weekdayClasses(index)} + onClick={onWeekdayClick(index)} > - {formatDateToWeekday(day.dateDay.getTime() / 1000)} + {day.isToday ? "Today" : day.weekday}
  • )), - [date, orderedEvents] + [schedule, weekdayClasses, onWeekdayClick] ); - const eventRooms = useMemo( + const containerClasses = useMemo( () => - orderedEvents[date]?.rooms.map((room, index) => ( - - )), - [date, orderedEvents, currentVenue] + classNames("SchedulePageModal", { "SchedulePageModal--show": isVisible }), + [isVisible] ); - const roomsWithEvents = useMemo(() => { - let counter = 0; - - orderedEvents[date]?.rooms.map((room, index) => { - if (room.events?.length !== 0) { - counter++; - } - }); - return counter; - }, [date, orderedEvents]); - - const hasEvents = !!orderedEvents?.[date]?.events.length; - - // TODO: this was essentially used in the old logic, but the styles look - // as though they will hide it anyway, so I think it's better without this? - // if (!isVisible) return
    ; - - // TODO: ideally this would find the top most parent of parents and use those details - const hasParentVenue = !!parentVenue; - - const partyinfoImage = hasParentVenue - ? parentVenue?.host?.icon - : currentVenue?.host?.icon; - - const titleText = hasParentVenue ? parentVenue?.name : currentVenue?.name; - - const subtitleText = hasParentVenue - ? parentVenue?.config?.landingPageConfig.subtitle - : currentVenue?.config?.landingPageConfig.subtitle; - - const descriptionText = hasParentVenue - ? parentVenue?.config?.landingPageConfig.description - : currentVenue?.config?.landingPageConfig.description; - - const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()); - - const hours = hoursOfTheDay( - eachHourOfInterval({ - start: new Date().setHours( - currentMinutes >= 1020 ? 17 : new Date().getHours() - 1 - ), - end: endOfDay(new Date()), - }) - ); - - const timeToShow = useMemo(() => { - const minutesShowing = - currentMinutes >= 1020 ? 1020 : (new Date().getHours() - 1) * 60; - - return currentMinutes - minutesShowing; - }, [currentMinutes]); + return ( +
    + - const dailyHours = useMemo(() => { - return hours.map((date, index) => ( - - )); - }, [hours]); +
      {weekdays}
    - return ( -
    -
    -
    -
    -
    -
    -

    {titleText}

    -

    {subtitleText}

    -
    -
    -
    -

    {descriptionText}

    -
    -
    -
      {scheduleTabs}
    -
    -
    - -
    - {hasEvents && ( -
    -
    -
    - {dailyHours} -
    -
    -
    - {eventRooms} -
    - )} - - {!hasEvents && ( -
    -
    There are no events scheduled for this day.
    -
    - )} - {/*
    -
    {eventRooms}
    - -
    */} -
    -
    + {schedule[selectedDayIndex].rooms.length > 0 ? ( + + ) : ( +
    No events scheduled
    + )}
    ); }; diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts b/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts new file mode 100644 index 0000000000..dd55ff06d9 --- /dev/null +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts @@ -0,0 +1,83 @@ +import { + addDays, + compareAsc, + differenceInMinutes, + endOfDay, + format, + isWithinInterval, + startOfDay, +} from "date-fns"; + +import { Room } from "types/rooms"; +import { VenueEvent } from "types/venues"; + +import { WithVenueId } from "utils/id"; +import { ONE_MINUTE_IN_SECONDS, ONE_SECOND_IN_MILLISECONDS } from "utils/time"; + +import { RoomWithEvents } from "components/molecules/Schedule/Schedule"; + +export const isEventThisDay = (date: Date) => { + return (event: VenueEvent) => { + return isWithinInterval(date, { + start: startOfDay(event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS), + end: endOfDay( + (event.start_utc_seconds + + event.duration_minutes * ONE_MINUTE_IN_SECONDS) * + ONE_SECOND_IN_MILLISECONDS + ), + }); + }; +}; + +export const adjustEventTiming = (date: Date) => { + return (event: WithVenueId) => { + const dates = [ + event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS, + (event.start_utc_seconds + + event.duration_minutes * ONE_MINUTE_IN_SECONDS) * + ONE_SECOND_IN_MILLISECONDS, + startOfDay(date), + endOfDay(date), + ].sort(compareAsc); + + const startUtcMilliseconds = + dates[1] instanceof Date ? dates[1].getTime() : dates[1]; + + return { + ...event, + start_utc_seconds: startUtcMilliseconds / ONE_SECOND_IN_MILLISECONDS, + duration_minutes: differenceInMinutes(dates[2], dates[1]), + }; + }; +}; + +export const extendRoomsWithDaysEvents = ( + rooms: Room[], + daysEvents: WithVenueId[] +): RoomWithEvents[] => { + return rooms.map((room) => { + const events = daysEvents.filter((event) => event?.room === room?.title); + return { ...room, events }; + }); +}; + +export const scheduleDayBuilder = ( + today: Date, + events: WithVenueId[], + rooms: Room[] +) => (dayIndex: number) => { + const day = addDays(today, dayIndex); + + const daysEvents = events + .filter(isEventThisDay(day)) + .map(adjustEventTiming(day)); + + const roomsWithEvents = extendRoomsWithDaysEvents(rooms, daysEvents); + + return { + isToday: dayIndex === 0, + weekday: format(day, "E"), + dayStartUtcSeconds: Math.floor(day.getTime() / ONE_SECOND_IN_MILLISECONDS), + rooms: roomsWithEvents.filter((room) => room.events.length > 0), + }; +}; diff --git a/src/utils/time.ts b/src/utils/time.ts index 1c5921db18..b07df966e3 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -1,9 +1,17 @@ -import { format, formatDuration, formatRelative } from "date-fns"; +import { + format, + formatDuration, + formatRelative, + getHours, + getMinutes as getLibMinutes, + getSeconds, +} from "date-fns"; import { VenueEvent } from "types/venues"; export const ONE_SECOND_IN_MILLISECONDS = 1000; export const ONE_MINUTE_IN_SECONDS = 60; +export const ONE_HOUR_IN_MINUTES = 60; export const ONE_HOUR_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 60; export const ONE_DAY_IN_SECONDS = ONE_HOUR_IN_SECONDS * 24; @@ -169,12 +177,14 @@ export const formatHourAndMinute = (utcSeconds: number) => { return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "HH:mm"); }; +// TODO: do we need it? export const formatHour = (utcSeconds: number) => { const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); const hh = String(date.getHours()).padStart(2, "0"); return hh; }; +// TODO: do we need it? export const getMinutes = (utcSeconds: number) => { const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); const hh = date.getHours(); @@ -183,6 +193,27 @@ export const getMinutes = (utcSeconds: number) => { return minutes; }; +export const getSecondsFromStartOfDay = (utcSeconds: number) => { + const utcMilliseconds = utcSeconds * ONE_SECOND_IN_MILLISECONDS; + + return ( + getHours(utcMilliseconds) * ONE_HOUR_IN_SECONDS + + getLibMinutes(utcMilliseconds) * ONE_MINUTE_IN_SECONDS + + getSeconds(utcMilliseconds) + ); +}; + +export const isLiveEvent = ( + startUtcSeconds: number, + minutesDuration: number +) => { + const now = getCurrentTimeInUTCSeconds(); + return ( + startUtcSeconds <= now && + now <= startUtcSeconds + minutesDuration * ONE_MINUTE_IN_SECONDS + ); +}; + export const daysFromEndOfEvent = ( utcSeconds: number, durationMinutes: number @@ -253,10 +284,3 @@ export const normalizeTimestampToMilliseconds = (timestamp: number) => { ? timestamp : timestamp * ONE_SECOND_IN_MILLISECONDS; }; - -export const hoursOfTheDay = (hours: Date[]) => { - const hour = hours.map((date) => { - return format(date, "h a"); - }); - return hour; -}; From d97a8288a1bde2079af08c7ead6928099ef7f9ba Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 5 May 2021 14:16:11 +0300 Subject: [PATCH 09/72] Save events to the database; refactor the code --- src/api/profile.ts | 36 ++++++ .../molecules/Schedule/Schedule.tsx | 113 ++++++++---------- .../molecules/Schedule/Schedule.types.ts | 19 +++ .../molecules/Schedule/Schedule.utils.ts | 16 +++ .../molecules/ScheduleEvent/ScheduleEvent.tsx | 109 ++++++++++------- .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 12 +- .../SchedulePageModal/SchedulePageModal.tsx | 14 ++- .../SchedulePageModal.utils.ts | 28 +++-- src/types/User.ts | 3 + src/types/venues.ts | 4 + 10 files changed, 228 insertions(+), 126 deletions(-) create mode 100644 src/components/molecules/Schedule/Schedule.types.ts create mode 100644 src/components/molecules/Schedule/Schedule.utils.ts diff --git a/src/api/profile.ts b/src/api/profile.ts index e7be0ec375..eb761a2824 100644 --- a/src/api/profile.ts +++ b/src/api/profile.ts @@ -48,3 +48,39 @@ export const makeUpdateUserGridLocation = ({ firestore.doc(doc).set(newData); }); }; + +export interface SaveEventToProfileProps { + venueId: string; + userId: string; + eventId: string; + removeMode?: boolean; +} + +export const saveEventToProfile = async ({ + venueId, + userId, + eventId, + removeMode = false, +}: SaveEventToProfileProps): Promise => { + const userProfileRef = firebase.firestore().collection("users").doc(userId); + + const modify = removeMode + ? firebase.firestore.FieldValue.arrayRemove + : firebase.firestore.FieldValue.arrayUnion; + + const newSavedEvents = { + [`myPersonalizedSchedule.${venueId}`]: modify(eventId), + }; + + return userProfileRef.update(newSavedEvents).catch((err) => { + Bugsnag.notify(err, (event) => { + event.addMetadata("context", { + location: "api/profile::saveEventToProfile", + venueId, + userId, + eventId, + removeMode, + }); + }); + }); +}; diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 23acec8a10..fefdddcaf3 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,90 +1,75 @@ -import React, { useState } from "react"; +import React, { useCallback, useMemo } from "react"; import classNames from "classnames"; import { format } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; -import { Room } from "types/rooms"; -import { VenueEvent } from "types/venues"; +import { ONE_SECOND_IN_MILLISECONDS } from "utils/time"; -import { - ONE_SECOND_IN_MILLISECONDS, - ONE_HOUR_IN_SECONDS, - getSecondsFromStartOfDay, -} from "utils/time"; +import { RoomWithEvents, ScheduleProps } from "./Schedule.types"; + +import { calcStartPosition } from "./Schedule.utils"; import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; import "./Schedule.scss"; -export type RoomWithEvents = Room & { events: VenueEvent[] }; - -export interface ScheduleDay { - isToday: boolean; - weekday: string; - dayStartUtcSeconds: number; - rooms: RoomWithEvents[]; -} - -export interface ScheduleProps { - scheduleDay: ScheduleDay; -} - const MAX_SCHEDULE_START_HOUR = 16; -const HOUR_WIDTH = 200; // px +const MAX_HOUR = 24; +const MIDDAY_HOUR = 12; export const Schedule: React.FC = ({ scheduleDay }) => { - const getStartHour = (utcSeconds: number) => { - return utcSeconds >= scheduleDay.dayStartUtcSeconds - ? Number(format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "H")) - : 0; - }; - - const roomStartHour = (room: RoomWithEvents) => - room.events?.reduce( - (acc, event) => Math.min(acc, getStartHour(event.start_utc_seconds)), - MAX_SCHEDULE_START_HOUR - ) ?? MAX_SCHEDULE_START_HOUR; - - const scheduleStartHour = Math.min( - ...scheduleDay.rooms.map((room) => roomStartHour(room)), - MAX_SCHEDULE_START_HOUR + const getStartHour = useCallback( + (utcSeconds: number) => { + return utcSeconds >= scheduleDay.dayStartUtcSeconds + ? Number(format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "H")) + : 0; + }, + [scheduleDay] ); - const hours = range(scheduleStartHour, 24).map( - (hour: number) => `${hour % 12 || 12} ${hour >= 12 ? "PM" : "AM"}` + const roomStartHour = useCallback( + (room: RoomWithEvents) => + room.events?.reduce( + (acc, event) => Math.min(acc, getStartHour(event.start_utc_seconds)), + MAX_SCHEDULE_START_HOUR + ) ?? MAX_SCHEDULE_START_HOUR, + [getStartHour] ); - const calcStartPosition = (startTimeUtcSeconds: number) => { - const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + const scheduleStartHour = useMemo( + () => + Math.min( + ...scheduleDay.rooms.map((room) => roomStartHour(room)), + MAX_SCHEDULE_START_HOUR + ), + [scheduleDay, roomStartHour] + ); - return Math.floor( - HOUR_WIDTH / 2 + - (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * - HOUR_WIDTH - ); - }; + const hours = useMemo( + () => + range(scheduleStartHour, MAX_HOUR).map( + (hour: number) => + `${hour % MIDDAY_HOUR || MIDDAY_HOUR} ${ + hour >= MIDDAY_HOUR ? "PM" : "AM" + }` + ), + [scheduleStartHour] + ); const containerVars = useCss({ "--room-count": scheduleDay.rooms.length + 1, "--current-time--position": calcStartPosition( - Math.floor(Date.now() / ONE_SECOND_IN_MILLISECONDS) + Math.floor(Date.now() / ONE_SECOND_IN_MILLISECONDS), + scheduleStartHour ), "--hours-count": hours.length, }); - const containerClasses = classNames("ScheduledEvents", containerVars); - - const [usersEvents, setUsersEvents] = useState([]); - - const onEventBookmarked = (isBookmarked: boolean, event: VenueEvent) => { - console.log("is bookmarked", isBookmarked); - if (isBookmarked) { - setUsersEvents([...usersEvents, event]); - } else { - setUsersEvents(usersEvents.filter((e) => e.name !== event.name)); - } - }; + const containerClasses = useMemo( + () => classNames("ScheduledEvents", containerVars), + [containerVars] + ); return (
    @@ -92,7 +77,7 @@ export const Schedule: React.FC = ({ scheduleDay }) => {

    My Daily Schedule

    - {usersEvents.length} events + {scheduleDay.personalEvents.length} events
    {scheduleDay.rooms.map((room) => ( @@ -120,10 +105,9 @@ export const Schedule: React.FC = ({ scheduleDay }) => {
    {scheduleDay.rooms.map((room) => ( @@ -131,7 +115,6 @@ export const Schedule: React.FC = ({ scheduleDay }) => { key={room.title} events={room.events} scheduleStartHour={scheduleStartHour} - onEventBookmarked={onEventBookmarked} /> ))}
    diff --git a/src/components/molecules/Schedule/Schedule.types.ts b/src/components/molecules/Schedule/Schedule.types.ts new file mode 100644 index 0000000000..51b6769265 --- /dev/null +++ b/src/components/molecules/Schedule/Schedule.types.ts @@ -0,0 +1,19 @@ +import { Room } from "types/rooms"; +import { PersonalizedVenueEvent } from "types/venues"; +import { WithVenueId } from "utils/id"; + +export type RoomWithEvents = Room & { + events: WithVenueId[]; +}; + +export interface ScheduleDay { + isToday: boolean; + weekday: string; + dayStartUtcSeconds: number; + rooms: RoomWithEvents[]; + personalEvents: WithVenueId[]; +} + +export interface ScheduleProps { + scheduleDay: ScheduleDay; +} diff --git a/src/components/molecules/Schedule/Schedule.utils.ts b/src/components/molecules/Schedule/Schedule.utils.ts new file mode 100644 index 0000000000..a09859eaa2 --- /dev/null +++ b/src/components/molecules/Schedule/Schedule.utils.ts @@ -0,0 +1,16 @@ +import { getSecondsFromStartOfDay, ONE_HOUR_IN_SECONDS } from "utils/time"; + +export const HOUR_WIDTH = 200; // px + +export const calcStartPosition = ( + startTimeUtcSeconds: number, + scheduleStartHour: number +) => { + const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + + return Math.floor( + HOUR_WIDTH / 2 + + (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * + HOUR_WIDTH + ); +}; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index c0fb53b6be..60216556e2 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -1,71 +1,97 @@ -import React, { useState } from "react"; +import React, { + MouseEventHandler, + useCallback, + useEffect, + useMemo, + useState, +} from "react"; import classNames from "classnames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; import { faBookmark as regularBookmark } from "@fortawesome/free-regular-svg-icons"; -import { VenueEvent } from "types/venues"; +import { PersonalizedVenueEvent } from "types/venues"; + +import { WithVenueId } from "utils/id"; import { isTruthy } from "utils/types"; -import { - getSecondsFromStartOfDay, - ONE_HOUR_IN_SECONDS, - isLiveEvent, -} from "utils/time"; +import { isLiveEvent, ONE_HOUR_IN_MINUTES } from "utils/time"; + +import { saveEventToProfile } from "api/profile"; +import { useUser } from "hooks/useUser"; + +import { calcStartPosition, HOUR_WIDTH } from "../Schedule/Schedule.utils"; import "./ScheduleEvent.scss"; export interface ScheduleEventProps { - event: VenueEvent; + event: WithVenueId; scheduleStartHour: number; - onEventBookmarked: Function; isUsers?: boolean; } -const HOUR_WIDTH = 200; // px - export const ScheduleEvent: React.FC = ({ event, scheduleStartHour, - onEventBookmarked, isUsers, }) => { - const [isBookmarked, setBookmark] = useState(isTruthy(isUsers)); - - const containerClasses = classNames( - "ScheduleEvent", - { - "ScheduleEvent--live": isLiveEvent( - event.start_utc_seconds, - event.duration_minutes + const [isBookmarked, setBookmark] = useState(event.isSaved); + + useEffect(() => { + setBookmark(event.isSaved); + }, [event.isSaved]); + + const { userId } = useUser(); + + const containerClasses = useMemo( + () => + classNames( + "ScheduleEvent", + { + "ScheduleEvent--live": isLiveEvent( + event.start_utc_seconds, + event.duration_minutes + ), + }, + { "ScheduleEvent--users": isTruthy(isUsers) } ), - }, - { "ScheduleEvent--users": isTruthy(isUsers) } + [event, isUsers] ); - const calcStartPosition = (startTimeUtcSeconds: number) => { - const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); - - return ( - HOUR_WIDTH / 2 + - (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * - HOUR_WIDTH - ); - }; + const eventWidth = useMemo( + () => (event.duration_minutes * HOUR_WIDTH) / ONE_HOUR_IN_MINUTES, + [event] + ); + const bookmarkEvent = useCallback(() => { + event.isSaved = !event.isSaved; - const eventWidth = (event.duration_minutes * 200) / 60; + if (userId && event.id) { + saveEventToProfile({ + venueId: event.venueId, + userId: userId, + removeMode: !event.isSaved, + eventId: event.id, + }); + } + }, [userId, event]); - const bookmarkEvent = () => { - setBookmark(!isBookmarked); - onEventBookmarked(!isBookmarked, event); - }; + const onBookmark: MouseEventHandler = useCallback( + (e) => { + e.stopPropagation(); + bookmarkEvent(); + }, + [bookmarkEvent] + ); return (
    @@ -74,16 +100,9 @@ export const ScheduleEvent: React.FC = ({
    by {event.host}
    -
    { - e.stopPropagation(); - bookmarkEvent(); - }} - > +
    diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index 2713a7302c..44c79c8011 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -1,32 +1,32 @@ import React from "react"; -import { VenueEvent } from "types/venues"; + +import { PersonalizedVenueEvent } from "types/venues"; + +import { WithVenueId } from "utils/id"; import { ScheduleEvent } from "../ScheduleEvent"; import "./ScheduleRoomEvents.scss"; export interface ScheduleRoomEventsProps { - events: VenueEvent[]; + events: WithVenueId[]; scheduleStartHour: number; - onEventBookmarked: Function; isUsers?: boolean; } export const ScheduleRoomEvents: React.FC = ({ events, scheduleStartHour, - onEventBookmarked, isUsers, }) => { return (
    {events.map((event, index) => ( ))}
    diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 27dfb48662..250c03dc29 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -17,11 +17,13 @@ import { isEventLiveOrFuture } from "utils/event"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; +import { useUser } from "hooks/useUser"; import { Schedule } from "components/molecules/Schedule"; -import { ScheduleDay } from "components/molecules/Schedule/Schedule"; import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; +import { ScheduleDay } from "components/molecules/Schedule/Schedule.types"; + import { scheduleDayBuilder } from "./SchedulePageModal.utils"; import "./SchedulePageModal.scss"; @@ -32,10 +34,15 @@ interface SchedulePageModalProps { isVisible?: boolean; } +export const emptyPersonalizedSchedule = {}; + export const SchedulePageModal: FC = ({ isVisible, }) => { const venueId = useVenueId(); + const { userWithId } = useUser(); + const userEventIds = + userWithId?.myPersonalizedSchedule ?? emptyPersonalizedSchedule; const { relatedVenueEvents, relatedVenues } = useConnectRelatedVenues({ venueId, @@ -58,11 +65,12 @@ export const SchedulePageModal: FC = ({ const buildScheduleEvent = scheduleDayBuilder( today, liveAndFutureEvents, - relatedRooms + relatedRooms, + userEventIds ); return range(0, DAYS_AHEAD).map((dayIndex) => buildScheduleEvent(dayIndex)); - }, [relatedVenueEvents, relatedRooms]); + }, [relatedVenueEvents, relatedRooms, userEventIds]); const [selectedDayIndex, setSelectedDayIndex] = useState(0); diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts b/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts index dd55ff06d9..44e457aa8b 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts @@ -9,12 +9,14 @@ import { } from "date-fns"; import { Room } from "types/rooms"; -import { VenueEvent } from "types/venues"; +import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; +import { MyPersonalizedSchedule } from "types/User"; import { WithVenueId } from "utils/id"; import { ONE_MINUTE_IN_SECONDS, ONE_SECOND_IN_MILLISECONDS } from "utils/time"; +import { isTruthy } from "utils/types"; -import { RoomWithEvents } from "components/molecules/Schedule/Schedule"; +import { RoomWithEvents } from "components/molecules/Schedule/Schedule.types"; export const isEventThisDay = (date: Date) => { return (event: VenueEvent) => { @@ -53,24 +55,35 @@ export const adjustEventTiming = (date: Date) => { export const extendRoomsWithDaysEvents = ( rooms: Room[], - daysEvents: WithVenueId[] + daysEvents: WithVenueId[] ): RoomWithEvents[] => { return rooms.map((room) => { - const events = daysEvents.filter((event) => event?.room === room?.title); + const events: WithVenueId[] = daysEvents.filter( + (event) => event?.room === room?.title + ); return { ...room, events }; }); }; +export const bookmarkPersonalizedEvents = ( + usersEvents: MyPersonalizedSchedule +) => (event: WithVenueId): WithVenueId => ({ + ...event, + isSaved: isTruthy(event.id && usersEvents[event.venueId]?.includes(event.id)), +}); + export const scheduleDayBuilder = ( today: Date, events: WithVenueId[], - rooms: Room[] + rooms: Room[], + usersEvents: MyPersonalizedSchedule ) => (dayIndex: number) => { const day = addDays(today, dayIndex); - const daysEvents = events + const daysEvents: WithVenueId[] = events .filter(isEventThisDay(day)) - .map(adjustEventTiming(day)); + .map(adjustEventTiming(day)) + .map(bookmarkPersonalizedEvents(usersEvents)); const roomsWithEvents = extendRoomsWithDaysEvents(rooms, daysEvents); @@ -79,5 +92,6 @@ export const scheduleDayBuilder = ( weekday: format(day, "E"), dayStartUtcSeconds: Math.floor(day.getTime() / ONE_SECOND_IN_MILLISECONDS), rooms: roomsWithEvents.filter((room) => room.events.length > 0), + personalEvents: daysEvents.filter((event) => event.isSaved), }; }; diff --git a/src/types/User.ts b/src/types/User.ts index 33763e8092..ead69cce4d 100644 --- a/src/types/User.ts +++ b/src/types/User.ts @@ -14,6 +14,8 @@ export type VideoState = { removedParticipantUids?: string[]; }; +export type MyPersonalizedSchedule = Record; + export interface User { drinkOfChoice?: string; favouriteRecord?: string; @@ -32,4 +34,5 @@ export interface User { kidsMode: boolean; anonMode: boolean; enteredVenueIds?: string[]; + myPersonalizedSchedule?: MyPersonalizedSchedule; } diff --git a/src/types/venues.ts b/src/types/venues.ts index 4291e9d890..40579e450b 100644 --- a/src/types/venues.ts +++ b/src/types/venues.ts @@ -298,6 +298,10 @@ export interface VenueEvent { id?: string; } +export interface PersonalizedVenueEvent extends VenueEvent { + isSaved: boolean; +} + export const isVenueWithRooms = (venue: AnyVenue): venue is PartyMapVenue => HAS_ROOMS_TEMPLATES.includes(venue.template); From b578f715f5b9f805484eae6c33171a726a9edfc4 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 5 May 2021 15:02:27 +0300 Subject: [PATCH 10/72] Use z-index helper --- src/components/molecules/ScheduleEvent/ScheduleEvent.scss | 4 +++- src/scss/constants.scss | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index adf8947a45..6b54348cf1 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -1,3 +1,5 @@ +@import "scss/constants.scss"; + .ScheduleEvent { display: flex; position: absolute; @@ -13,7 +15,7 @@ &:hover { background-color: #4c494f; - z-index: 1; + z-index: z(navbar__schedule-event--hover); } &--users { diff --git a/src/scss/constants.scss b/src/scss/constants.scss index 91603166a4..60fc47eb88 100644 --- a/src/scss/constants.scss +++ b/src/scss/constants.scss @@ -98,6 +98,7 @@ $z-layers: ( navbar-schedule-backdrop: $z-layer-live-schedule, navbar-schedule: $z-layer-live-schedule, navbar: $z-layer-navbar, + navbar__schedule-event--hover: 1, // Sidebars + similar sidebar-slide-btn: -1, sidebar: $z-layer-sidebar, From cc504ba83a67397c00bf04b883a3c20a08f03ec3 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 5 May 2021 15:11:51 +0300 Subject: [PATCH 11/72] Return EventDisplay to its staging state --- .../molecules/EventDisplay/EventDisplay.scss | 5 - .../molecules/EventDisplay/EventDisplay.tsx | 109 +++++++++--------- 2 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/components/molecules/EventDisplay/EventDisplay.scss b/src/components/molecules/EventDisplay/EventDisplay.scss index c7eb0ad9d9..a12bf596e0 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.scss +++ b/src/components/molecules/EventDisplay/EventDisplay.scss @@ -69,11 +69,6 @@ $sand: #937c63; } } } - .bookmark-icon { - cursor: pointer; - width: 15px; - height: 20px; - } .events-list { overflow-y: auto; .event { diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index 1632292fc0..f75a535ef7 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -1,17 +1,14 @@ -import React, { useState, useMemo } from "react"; -import { format } from "date-fns"; - -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; -import { faBookmark as regularBookmark } from "@fortawesome/free-regular-svg-icons"; - +import React, { useMemo } from "react"; import classNames from "classnames"; import { AnyVenue, VenueEvent } from "types/venues"; +import { Room } from "types/rooms"; -import { getCurrentTimeInUTCSeconds, formatHour, getMinutes } from "utils/time"; +import { formatHourAndMinute, getCurrentTimeInUTCSeconds } from "utils/time"; import { WithId } from "utils/id"; +import { useRoom } from "hooks/useRoom"; + import "./EventDisplay.scss"; export interface EventDisplayProps { @@ -20,7 +17,14 @@ export interface EventDisplayProps { } export const EventDisplay: React.FC = ({ event, venue }) => { - const [isBookmarked, setBookmark] = useState(false); + const eventRoomTitle = event.room; + + const room = useMemo( + () => venue?.rooms?.find((room) => room.title === eventRoomTitle), + [venue, eventRoomTitle] + ); + + const buttonText = `${event.room ?? "Enter"} ${venue && `- ${venue.name}`}`; const isLiveEvent = event.start_utc_seconds < getCurrentTimeInUTCSeconds() && @@ -31,58 +35,49 @@ export const EventDisplay: React.FC = ({ event, venue }) => { "schedule-event-container--live": isLiveEvent, }); - const starEventHour = formatHour(event.start_utc_seconds); - - const oneHourBehind = format( - new Date().setHours(new Date().getHours() - 1), - "HH" - ); - const duration = Math.floor(event.duration_minutes / 60); - const beginnigToShow = Number(starEventHour) - Number(oneHourBehind); - - const currentMinutes = getMinutes(getCurrentTimeInUTCSeconds()); - - const timeToShow = useMemo(() => { - const minutesShowing = - currentMinutes >= 1020 ? 1020 : (new Date().getHours() - 1) * 60; - const startTime = getMinutes(event.start_utc_seconds); - - return startTime - minutesShowing; - }, [currentMinutes, event.start_utc_seconds]); - return ( -
    4800 - ? 4800 - (Number(beginnigToShow) * 200 + 100) - : duration * 200 - }px`, - }} - > +
    +
    +
    + {formatHourAndMinute(event.start_utc_seconds)} +
    +
    + {formatHourAndMinute( + event.start_utc_seconds + event.duration_minutes * 60 + )} +
    + {isLiveEvent && Live} +
    {event.name}
    -
    by {event.host}
    -
    -
    { - e.stopPropagation(); - setBookmark(!isBookmarked); - }} - > - +
    + {event.description} +
    +
    + {event.room && room && venue ? ( + + {buttonText} + + ) : ( +
    {buttonText}
    + )} +
    ); }; + +interface EnterRoomButtonProps { + room: Room; + venue: WithId; +} + +const EnterRoomButton: React.FC = ({ + room, + venue, + children, +}) => { + const { enterRoom } = useRoom({ room, venueName: venue.name }); + + return
    {children}
    ; +}; From 32efd4933865e151ac1c91f8642b9ca568bdf7c8 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 09:02:18 +0300 Subject: [PATCH 12/72] Remove unused utils/time functions --- src/utils/time.ts | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/utils/time.ts b/src/utils/time.ts index b07df966e3..fe51851117 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -3,7 +3,7 @@ import { formatDuration, formatRelative, getHours, - getMinutes as getLibMinutes, + getMinutes, getSeconds, } from "date-fns"; @@ -177,28 +177,12 @@ export const formatHourAndMinute = (utcSeconds: number) => { return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "HH:mm"); }; -// TODO: do we need it? -export const formatHour = (utcSeconds: number) => { - const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); - const hh = String(date.getHours()).padStart(2, "0"); - return hh; -}; - -// TODO: do we need it? -export const getMinutes = (utcSeconds: number) => { - const date = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); - const hh = date.getHours(); - const mm = date.getMinutes(); - const minutes = hh * 60 + mm; - return minutes; -}; - export const getSecondsFromStartOfDay = (utcSeconds: number) => { const utcMilliseconds = utcSeconds * ONE_SECOND_IN_MILLISECONDS; return ( getHours(utcMilliseconds) * ONE_HOUR_IN_SECONDS + - getLibMinutes(utcMilliseconds) * ONE_MINUTE_IN_SECONDS + + getMinutes(utcMilliseconds) * ONE_MINUTE_IN_SECONDS + getSeconds(utcMilliseconds) ); }; From 4620ee606b4d082901e989fc6eac27f0e5b9a265 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 09:18:03 +0300 Subject: [PATCH 13/72] Improve utils/time functions --- src/utils/time.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/utils/time.ts b/src/utils/time.ts index fe51851117..5c53542474 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -1,10 +1,11 @@ import { + addMinutes, + differenceInSeconds, format, formatDuration, formatRelative, - getHours, - getMinutes, - getSeconds, + isWithinInterval, + startOfDay, } from "date-fns"; import { VenueEvent } from "types/venues"; @@ -180,22 +181,17 @@ export const formatHourAndMinute = (utcSeconds: number) => { export const getSecondsFromStartOfDay = (utcSeconds: number) => { const utcMilliseconds = utcSeconds * ONE_SECOND_IN_MILLISECONDS; - return ( - getHours(utcMilliseconds) * ONE_HOUR_IN_SECONDS + - getMinutes(utcMilliseconds) * ONE_MINUTE_IN_SECONDS + - getSeconds(utcMilliseconds) - ); + return differenceInSeconds(utcMilliseconds, startOfDay(utcMilliseconds)); }; export const isLiveEvent = ( startUtcSeconds: number, minutesDuration: number ) => { - const now = getCurrentTimeInUTCSeconds(); - return ( - startUtcSeconds <= now && - now <= startUtcSeconds + minutesDuration * ONE_MINUTE_IN_SECONDS - ); + const start = startUtcSeconds * ONE_SECOND_IN_MILLISECONDS; + const end = addMinutes(start, minutesDuration); + + return isWithinInterval(Date.now(), { start, end }); }; export const daysFromEndOfEvent = ( From 6c79ed94ad0acdbf8061bba26c4e73f7912ed2de Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 15:41:13 +0300 Subject: [PATCH 14/72] Refactor SchedulePageModal component --- .../SchedulePageModal/SchedulePageModal.tsx | 86 +++++++------------ .../{SchedulePageModal.utils.ts => utils.ts} | 0 2 files changed, 32 insertions(+), 54 deletions(-) rename src/components/organisms/SchedulePageModal/{SchedulePageModal.utils.ts => utils.ts} (100%) diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 250c03dc29..ffed58032f 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -1,18 +1,8 @@ -import React, { - useState, - useMemo, - FC, - useEffect, - useCallback, - MouseEventHandler, -} from "react"; -import { startOfDay } from "date-fns"; +import React, { useState, useMemo, FC, MouseEventHandler } from "react"; +import { startOfToday } from "date-fns"; import { range } from "lodash"; import classNames from "classnames"; -import { Room } from "types/rooms"; - -import { formatDate } from "utils/time"; import { isEventLiveOrFuture } from "utils/event"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; @@ -24,7 +14,7 @@ import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDesc import { ScheduleDay } from "components/molecules/Schedule/Schedule.types"; -import { scheduleDayBuilder } from "./SchedulePageModal.utils"; +import { scheduleDayBuilder } from "./utils"; import "./SchedulePageModal.scss"; @@ -49,19 +39,14 @@ export const SchedulePageModal: FC = ({ withEvents: true, }); - const [relatedRooms, setRelatedRooms] = useState([]); - - useEffect(() => { - const rooms: Room[] = []; - relatedVenues - .map((venue) => venue.rooms || []) - .forEach((venueRooms) => rooms.push(...venueRooms)); - setRelatedRooms(rooms); - }, [relatedVenues]); + const relatedRooms = useMemo( + () => relatedVenues.flatMap((venue) => venue.rooms ?? []), + [relatedVenues] + ); const schedule: ScheduleDay[] = useMemo(() => { const liveAndFutureEvents = relatedVenueEvents.filter(isEventLiveOrFuture); - const today = startOfDay(Date.now()); + const today = startOfToday(); const buildScheduleEvent = scheduleDayBuilder( today, liveAndFutureEvents, @@ -74,41 +59,34 @@ export const SchedulePageModal: FC = ({ const [selectedDayIndex, setSelectedDayIndex] = useState(0); - const onWeekdayClick = useCallback( - (index: number): MouseEventHandler => (e) => { - e.stopPropagation(); - setSelectedDayIndex(index); - }, - [] - ); - - const weekdayClasses = useCallback( - (index) => - classNames("SchedulePageModal__weekday", { - "SchedulePageModal__weekday--active": index === selectedDayIndex, - }), - [selectedDayIndex] - ); - const weekdays = useMemo( () => - schedule.map((day, index) => ( -
  • - {day.isToday ? "Today" : day.weekday} -
  • - )), - [schedule, weekdayClasses, onWeekdayClick] + schedule.map((day, index) => { + const classes = classNames("SchedulePageModal__weekday", { + "SchedulePageModal__weekday--active": index === selectedDayIndex, + }); + + const onWeekdayClick: MouseEventHandler = (e) => { + e.stopPropagation(); + setSelectedDayIndex(index); + }; + + return ( +
  • + {day.isToday ? "Today" : day.weekday} +
  • + ); + }), + [schedule, selectedDayIndex] ); - const containerClasses = useMemo( - () => - classNames("SchedulePageModal", { "SchedulePageModal--show": isVisible }), - [isVisible] - ); + const containerClasses = classNames("SchedulePageModal", { + "SchedulePageModal--show": isVisible, + }); return (
    diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts b/src/components/organisms/SchedulePageModal/utils.ts similarity index 100% rename from src/components/organisms/SchedulePageModal/SchedulePageModal.utils.ts rename to src/components/organisms/SchedulePageModal/utils.ts From a15ab358e3b11aaaec41eefed360048f25dae58d Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 17:07:45 +0300 Subject: [PATCH 15/72] Remove unused utils/time functions --- src/utils/time.ts | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/utils/time.ts b/src/utils/time.ts index 5c53542474..6ec27fc4c9 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -194,54 +194,11 @@ export const isLiveEvent = ( return isWithinInterval(Date.now(), { start, end }); }; -export const daysFromEndOfEvent = ( - utcSeconds: number, - durationMinutes: number -) => { - const dateNow = new Date(); - const dateOfFinish = new Date( - (utcSeconds + durationMinutes * 60) * ONE_SECOND_IN_MILLISECONDS - ); - const differenceInTime = dateOfFinish.getTime() - dateNow.getTime(); - const differenceInDays = - differenceInTime / (ONE_SECOND_IN_MILLISECONDS * 3600 * 24); - return Math.round(differenceInDays); -}; - -export const daysFromStartOfEvent = (utcSeconds: number) => { - const dateNow = new Date(); - const dateOfStart = new Date(utcSeconds * ONE_SECOND_IN_MILLISECONDS); - const differenceInTime = dateNow.getTime() - dateOfStart.getTime(); - const differenceInDays = - differenceInTime / (ONE_SECOND_IN_MILLISECONDS * 3600 * 24); - return Math.round(differenceInDays); -}; - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now // The static Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. export const getCurrentTimeInUTCSeconds = () => Date.now() / ONE_SECOND_IN_MILLISECONDS; -export const roundToNearestHour = (seconds: number) => { - const oneHour = 60 * 60; - return Math.floor(seconds / oneHour) * oneHour; -}; - -/** - * Format UTC seconds as a string representing weekday abbreviation. - * - * @example - * formatDateToWeekday(1618509600) - * // 'Thu' - * - * @param utcSeconds - * - * @see https://date-fns.org/docs/format - */ -export function formatDateToWeekday(utcSeconds: number) { - return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "E"); -} - /** * Format UTC seconds as a string representing relative date from now. * From c711c1dc8074d1f09d6bbc16b4694dc2729d849a Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 19:44:13 +0300 Subject: [PATCH 16/72] Use isEventLive function from utils/event instead of creating a duplicate in utils/time --- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 8 +++----- src/utils/event.ts | 14 +++++++------- src/utils/time.ts | 12 ------------ 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 60216556e2..882718b124 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -15,8 +15,9 @@ import { PersonalizedVenueEvent } from "types/venues"; import { WithVenueId } from "utils/id"; import { isTruthy } from "utils/types"; +import { isEventLive } from "utils/event"; -import { isLiveEvent, ONE_HOUR_IN_MINUTES } from "utils/time"; +import { ONE_HOUR_IN_MINUTES } from "utils/time"; import { saveEventToProfile } from "api/profile"; import { useUser } from "hooks/useUser"; @@ -49,10 +50,7 @@ export const ScheduleEvent: React.FC = ({ classNames( "ScheduleEvent", { - "ScheduleEvent--live": isLiveEvent( - event.start_utc_seconds, - event.duration_minutes - ), + "ScheduleEvent--live": isEventLive(event), }, { "ScheduleEvent--users": isTruthy(isUsers) } ), diff --git a/src/utils/event.ts b/src/utils/event.ts index 282a09da12..da50cb4b86 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -1,5 +1,8 @@ +import { addMinutes, isWithinInterval } from "date-fns"; + import { VenueEvent } from "types/venues"; -import { getCurrentTimeInUTCSeconds } from "./time"; + +import { getCurrentTimeInUTCSeconds, ONE_SECOND_IN_MILLISECONDS } from "./time"; export const getCurrentEvent = (roomEvents: VenueEvent[]) => { const currentTimeInUTCSeconds = getCurrentTimeInUTCSeconds(); @@ -12,13 +15,10 @@ export const getCurrentEvent = (roomEvents: VenueEvent[]) => { }; export const isEventLive = (event: VenueEvent) => { - const currentTimeInUTCSeconds = getCurrentTimeInUTCSeconds(); + const start = event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS; + const end = addMinutes(start, event.duration_minutes); - return ( - event.start_utc_seconds < currentTimeInUTCSeconds && - event.start_utc_seconds + event.duration_minutes * 60 > - currentTimeInUTCSeconds - ); + return isWithinInterval(Date.now(), { start, end }); }; export const isEventLiveOrFuture = (event: VenueEvent) => { diff --git a/src/utils/time.ts b/src/utils/time.ts index 6ec27fc4c9..bd984e343e 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -1,10 +1,8 @@ import { - addMinutes, differenceInSeconds, format, formatDuration, formatRelative, - isWithinInterval, startOfDay, } from "date-fns"; @@ -184,16 +182,6 @@ export const getSecondsFromStartOfDay = (utcSeconds: number) => { return differenceInSeconds(utcMilliseconds, startOfDay(utcMilliseconds)); }; -export const isLiveEvent = ( - startUtcSeconds: number, - minutesDuration: number -) => { - const start = startUtcSeconds * ONE_SECOND_IN_MILLISECONDS; - const end = addMinutes(start, minutesDuration); - - return isWithinInterval(Date.now(), { start, end }); -}; - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now // The static Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. export const getCurrentTimeInUTCSeconds = () => From 9fce282d69bf3236a3cad6381d0b990072e0c3c2 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 6 May 2021 19:49:14 +0300 Subject: [PATCH 17/72] Simplify SchedulePageModal logic --- .../SchedulePageModal/SchedulePageModal.tsx | 93 ++++++++++--------- .../organisms/SchedulePageModal/utils.ts | 85 +++++------------ src/utils/event.ts | 13 ++- 3 files changed, 84 insertions(+), 107 deletions(-) diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index ffed58032f..737f0885d8 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -1,10 +1,8 @@ import React, { useState, useMemo, FC, MouseEventHandler } from "react"; -import { startOfToday } from "date-fns"; +import { addDays, startOfToday, format, getUnixTime } from "date-fns"; import { range } from "lodash"; import classNames from "classnames"; -import { isEventLiveOrFuture } from "utils/event"; - import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; @@ -14,7 +12,11 @@ import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDesc import { ScheduleDay } from "components/molecules/Schedule/Schedule.types"; -import { scheduleDayBuilder } from "./utils"; +import { + extendRoomsWithDaysEvents, + isEventLaterThisDay, + prepareForSchedule, +} from "./utils"; import "./SchedulePageModal.scss"; @@ -44,45 +46,50 @@ export const SchedulePageModal: FC = ({ [relatedVenues] ); - const schedule: ScheduleDay[] = useMemo(() => { - const liveAndFutureEvents = relatedVenueEvents.filter(isEventLiveOrFuture); - const today = startOfToday(); - const buildScheduleEvent = scheduleDayBuilder( - today, - liveAndFutureEvents, - relatedRooms, - userEventIds - ); - - return range(0, DAYS_AHEAD).map((dayIndex) => buildScheduleEvent(dayIndex)); - }, [relatedVenueEvents, relatedRooms, userEventIds]); - const [selectedDayIndex, setSelectedDayIndex] = useState(0); - const weekdays = useMemo( - () => - schedule.map((day, index) => { - const classes = classNames("SchedulePageModal__weekday", { - "SchedulePageModal__weekday--active": index === selectedDayIndex, - }); - - const onWeekdayClick: MouseEventHandler = (e) => { - e.stopPropagation(); - setSelectedDayIndex(index); - }; - - return ( -
  • - {day.isToday ? "Today" : day.weekday} -
  • - ); - }), - [schedule, selectedDayIndex] - ); + const weekdays = useMemo(() => { + const today = startOfToday(); + + return range(0, DAYS_AHEAD).map((dayIndex) => { + const day = addDays(today, dayIndex); + const classes = classNames("SchedulePageModal__weekday", { + "SchedulePageModal__weekday--active": dayIndex === selectedDayIndex, + }); + + const onWeekdayClick: MouseEventHandler = (e) => { + e.stopPropagation(); + setSelectedDayIndex(dayIndex); + }; + + return ( +
  • + {dayIndex === 0 ? "Today" : format(day, "E")} +
  • + ); + }); + }, [selectedDayIndex]); + + const schedule: ScheduleDay = useMemo(() => { + const day = addDays(startOfToday(), selectedDayIndex); + const daysEvents = relatedVenueEvents + .filter(isEventLaterThisDay(selectedDayIndex === 0 ? Date.now() : day)) + .map(prepareForSchedule(day, userEventIds)); + + const roomsWithEvents = extendRoomsWithDaysEvents(relatedRooms, daysEvents); + + return { + isToday: selectedDayIndex === 0, + weekday: format(day, "E"), + dayStartUtcSeconds: getUnixTime(day), + rooms: roomsWithEvents.filter((room) => room.events.length > 0), + personalEvents: daysEvents.filter((event) => event.isSaved), + }; + }, [relatedVenueEvents, relatedRooms, userEventIds, selectedDayIndex]); const containerClasses = classNames("SchedulePageModal", { "SchedulePageModal--show": isVisible, @@ -94,8 +101,8 @@ export const SchedulePageModal: FC = ({
      {weekdays}
    - {schedule[selectedDayIndex].rooms.length > 0 ? ( - + {schedule.rooms.length > 0 ? ( + ) : (
    No events scheduled
    )} diff --git a/src/components/organisms/SchedulePageModal/utils.ts b/src/components/organisms/SchedulePageModal/utils.ts index 44e457aa8b..e42d9fe393 100644 --- a/src/components/organisms/SchedulePageModal/utils.ts +++ b/src/components/organisms/SchedulePageModal/utils.ts @@ -1,10 +1,10 @@ import { - addDays, - compareAsc, differenceInMinutes, endOfDay, - format, + getUnixTime, isWithinInterval, + max, + min, startOfDay, } from "date-fns"; @@ -13,45 +13,18 @@ import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; import { MyPersonalizedSchedule } from "types/User"; import { WithVenueId } from "utils/id"; -import { ONE_MINUTE_IN_SECONDS, ONE_SECOND_IN_MILLISECONDS } from "utils/time"; +import { eventEndTime, eventStartTime } from "utils/event"; import { isTruthy } from "utils/types"; import { RoomWithEvents } from "components/molecules/Schedule/Schedule.types"; -export const isEventThisDay = (date: Date) => { - return (event: VenueEvent) => { - return isWithinInterval(date, { - start: startOfDay(event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS), - end: endOfDay( - (event.start_utc_seconds + - event.duration_minutes * ONE_MINUTE_IN_SECONDS) * - ONE_SECOND_IN_MILLISECONDS - ), - }); - }; -}; - -export const adjustEventTiming = (date: Date) => { - return (event: WithVenueId) => { - const dates = [ - event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS, - (event.start_utc_seconds + - event.duration_minutes * ONE_MINUTE_IN_SECONDS) * - ONE_SECOND_IN_MILLISECONDS, - startOfDay(date), - endOfDay(date), - ].sort(compareAsc); - - const startUtcMilliseconds = - dates[1] instanceof Date ? dates[1].getTime() : dates[1]; - - return { - ...event, - start_utc_seconds: startUtcMilliseconds / ONE_SECOND_IN_MILLISECONDS, - duration_minutes: differenceInMinutes(dates[2], dates[1]), - }; - }; -}; +export const isEventLaterThisDay = (date: number | Date) => ( + event: VenueEvent +) => + isWithinInterval(date, { + start: startOfDay(eventStartTime(event)), + end: eventEndTime(event), + }); export const extendRoomsWithDaysEvents = ( rooms: Room[], @@ -65,33 +38,19 @@ export const extendRoomsWithDaysEvents = ( }); }; -export const bookmarkPersonalizedEvents = ( - usersEvents: MyPersonalizedSchedule -) => (event: WithVenueId): WithVenueId => ({ - ...event, - isSaved: isTruthy(event.id && usersEvents[event.venueId]?.includes(event.id)), -}); - -export const scheduleDayBuilder = ( - today: Date, - events: WithVenueId[], - rooms: Room[], +export const prepareForSchedule = ( + day: Date, usersEvents: MyPersonalizedSchedule -) => (dayIndex: number) => { - const day = addDays(today, dayIndex); - - const daysEvents: WithVenueId[] = events - .filter(isEventThisDay(day)) - .map(adjustEventTiming(day)) - .map(bookmarkPersonalizedEvents(usersEvents)); - - const roomsWithEvents = extendRoomsWithDaysEvents(rooms, daysEvents); +) => (event: WithVenueId): WithVenueId => { + const startOfEventToShow = max([eventStartTime(event), startOfDay(day)]); + const endOfEventToShow = min([eventEndTime(event), endOfDay(day)]); return { - isToday: dayIndex === 0, - weekday: format(day, "E"), - dayStartUtcSeconds: Math.floor(day.getTime() / ONE_SECOND_IN_MILLISECONDS), - rooms: roomsWithEvents.filter((room) => room.events.length > 0), - personalEvents: daysEvents.filter((event) => event.isSaved), + ...event, + start_utc_seconds: getUnixTime(startOfEventToShow), + duration_minutes: differenceInMinutes(endOfEventToShow, startOfEventToShow), + isSaved: isTruthy( + event.id && usersEvents[event.venueId]?.includes(event.id) + ), }; }; diff --git a/src/utils/event.ts b/src/utils/event.ts index da50cb4b86..0839709f5b 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -2,7 +2,11 @@ import { addMinutes, isWithinInterval } from "date-fns"; import { VenueEvent } from "types/venues"; -import { getCurrentTimeInUTCSeconds, ONE_SECOND_IN_MILLISECONDS } from "./time"; +import { + getCurrentTimeInUTCSeconds, + ONE_MINUTE_IN_SECONDS, + ONE_SECOND_IN_MILLISECONDS, +} from "./time"; export const getCurrentEvent = (roomEvents: VenueEvent[]) => { const currentTimeInUTCSeconds = getCurrentTimeInUTCSeconds(); @@ -42,3 +46,10 @@ export const eventHappeningNow = ( event.start_utc_seconds + event.duration_minutes > currentTimeInUTCSeconds ); }; + +export const eventStartTime = (event: VenueEvent) => + event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS; + +export const eventEndTime = (event: VenueEvent) => + (event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS) * + ONE_SECOND_IN_MILLISECONDS; From bd69d2a49d0f54d888d77dcdf4caf800774ef766 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 7 May 2021 12:13:14 +0300 Subject: [PATCH 18/72] Use unixTime functions instead of manual operations with ONE_SECOND_IN_MILLISECONDS --- .../molecules/Schedule/Schedule.tsx | 8 +++--- src/pages/Admin/VenueEventDetails.tsx | 10 +++---- src/utils/event.ts | 17 +++++------- src/utils/time.ts | 27 +++++++++---------- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index fefdddcaf3..b3d65d9ae7 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,11 +1,9 @@ import React, { useCallback, useMemo } from "react"; import classNames from "classnames"; -import { format } from "date-fns"; +import { format, fromUnixTime, getUnixTime } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; -import { ONE_SECOND_IN_MILLISECONDS } from "utils/time"; - import { RoomWithEvents, ScheduleProps } from "./Schedule.types"; import { calcStartPosition } from "./Schedule.utils"; @@ -22,7 +20,7 @@ export const Schedule: React.FC = ({ scheduleDay }) => { const getStartHour = useCallback( (utcSeconds: number) => { return utcSeconds >= scheduleDay.dayStartUtcSeconds - ? Number(format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "H")) + ? Number(format(fromUnixTime(utcSeconds), "H")) : 0; }, [scheduleDay] @@ -60,7 +58,7 @@ export const Schedule: React.FC = ({ scheduleDay }) => { const containerVars = useCss({ "--room-count": scheduleDay.rooms.length + 1, "--current-time--position": calcStartPosition( - Math.floor(Date.now() / ONE_SECOND_IN_MILLISECONDS), + Math.floor(getUnixTime(Date.now())), scheduleStartHour ), "--hours-count": hours.length, diff --git a/src/pages/Admin/VenueEventDetails.tsx b/src/pages/Admin/VenueEventDetails.tsx index 3444846efd..089872eff9 100644 --- a/src/pages/Admin/VenueEventDetails.tsx +++ b/src/pages/Admin/VenueEventDetails.tsx @@ -1,14 +1,10 @@ import React from "react"; -import { format } from "date-fns"; +import { format, fromUnixTime } from "date-fns"; import { VenueEvent } from "types/venues"; import { WithId } from "utils/id"; -import { - formatHourAndMinute, - ONE_MINUTE_IN_SECONDS, - ONE_SECOND_IN_MILLISECONDS, -} from "utils/time"; +import { formatHourAndMinute, ONE_MINUTE_IN_SECONDS } from "utils/time"; interface Props { venueEvent: WithId; @@ -31,7 +27,7 @@ const VenueEventDetails = ({ ONE_MINUTE_IN_SECONDS * venueEvent.duration_minutes ); const startDay = format( - venueEvent.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS, + fromUnixTime(venueEvent.start_utc_seconds), "EEEE LLLL do" ); diff --git a/src/utils/event.ts b/src/utils/event.ts index 0839709f5b..571cfc19b4 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -1,12 +1,8 @@ -import { addMinutes, isWithinInterval } from "date-fns"; +import { addMinutes, fromUnixTime, isWithinInterval } from "date-fns"; import { VenueEvent } from "types/venues"; -import { - getCurrentTimeInUTCSeconds, - ONE_MINUTE_IN_SECONDS, - ONE_SECOND_IN_MILLISECONDS, -} from "./time"; +import { getCurrentTimeInUTCSeconds, ONE_MINUTE_IN_SECONDS } from "./time"; export const getCurrentEvent = (roomEvents: VenueEvent[]) => { const currentTimeInUTCSeconds = getCurrentTimeInUTCSeconds(); @@ -19,7 +15,7 @@ export const getCurrentEvent = (roomEvents: VenueEvent[]) => { }; export const isEventLive = (event: VenueEvent) => { - const start = event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS; + const start = fromUnixTime(event.start_utc_seconds); const end = addMinutes(start, event.duration_minutes); return isWithinInterval(Date.now(), { start, end }); @@ -48,8 +44,9 @@ export const eventHappeningNow = ( }; export const eventStartTime = (event: VenueEvent) => - event.start_utc_seconds * ONE_SECOND_IN_MILLISECONDS; + fromUnixTime(event.start_utc_seconds); export const eventEndTime = (event: VenueEvent) => - (event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS) * - ONE_SECOND_IN_MILLISECONDS; + fromUnixTime( + event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS + ); diff --git a/src/utils/time.ts b/src/utils/time.ts index bd984e343e..015d5a9415 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -3,6 +3,8 @@ import { format, formatDuration, formatRelative, + fromUnixTime, + getUnixTime, startOfDay, } from "date-fns"; @@ -72,8 +74,7 @@ const formatMeasurementInString = (value: number, measureUnit: string) => { export const getTimeBeforeParty = (startUtcSeconds?: number) => { if (startUtcSeconds === undefined) return "???"; - const secondsBeforeParty = - startUtcSeconds - Date.now() / ONE_SECOND_IN_MILLISECONDS; + const secondsBeforeParty = startUtcSeconds - getUnixTime(Date.now()); if (secondsBeforeParty < 0) { return 0; @@ -108,8 +109,7 @@ export const getTimeBeforeParty = (startUtcSeconds?: number) => { }; export const canUserJoinTheEvent = (event: VenueEvent) => - event.start_utc_seconds - Date.now() / ONE_SECOND_IN_MILLISECONDS > - ONE_HOUR_IN_SECONDS; + event.start_utc_seconds - getUnixTime(Date.now()) > ONE_HOUR_IN_SECONDS; /** * Format UTC seconds as a string representing date. @@ -123,7 +123,7 @@ export const canUserJoinTheEvent = (event: VenueEvent) => * @see https://date-fns.org/docs/format */ export function formatDate(utcSeconds: number) { - return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "MMM do"); + return format(fromUnixTime(utcSeconds), "MMM do"); } export function oneHourAfterTimestamp(timestamp: number) { @@ -142,13 +142,11 @@ export function oneHourAfterTimestamp(timestamp: number) { * @see https://date-fns.org/docs/format */ export function formatUtcSeconds(utcSeconds?: number | null) { - return utcSeconds - ? format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "p") - : "(unknown)"; + return utcSeconds ? format(fromUnixTime(utcSeconds), "p") : "(unknown)"; } export function getHoursAgoInSeconds(hours: number) { - const nowInSec = Date.now() / ONE_SECOND_IN_MILLISECONDS; + const nowInSec = getUnixTime(Date.now()); return nowInSec - hours * ONE_HOUR_IN_SECONDS; } @@ -173,19 +171,18 @@ export function getDaysAgoInSeconds(days: number) { * @see https://date-fns.org/docs/format */ export const formatHourAndMinute = (utcSeconds: number) => { - return format(utcSeconds * ONE_SECOND_IN_MILLISECONDS, "HH:mm"); + return format(fromUnixTime(utcSeconds), "HH:mm"); }; export const getSecondsFromStartOfDay = (utcSeconds: number) => { - const utcMilliseconds = utcSeconds * ONE_SECOND_IN_MILLISECONDS; + const time = fromUnixTime(utcSeconds); - return differenceInSeconds(utcMilliseconds, startOfDay(utcMilliseconds)); + return differenceInSeconds(time, startOfDay(time)); }; // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now // The static Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. -export const getCurrentTimeInUTCSeconds = () => - Date.now() / ONE_SECOND_IN_MILLISECONDS; +export const getCurrentTimeInUTCSeconds = () => getUnixTime(Date.now()); /** * Format UTC seconds as a string representing relative date from now. @@ -199,7 +196,7 @@ export const getCurrentTimeInUTCSeconds = () => * @see https://date-fns.org/docs/formatRelative */ export const formatUtcSecondsRelativeToNow = (utcSeconds: number) => { - return formatRelative(utcSeconds * ONE_SECOND_IN_MILLISECONDS, Date.now()); + return formatRelative(fromUnixTime(utcSeconds), Date.now()); }; export const normalizeTimestampToMilliseconds = (timestamp: number) => { From 5461bb17ff72bc8a2ddc452452a2b5fe35d2376d Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 7 May 2021 13:45:39 +0300 Subject: [PATCH 19/72] Filter rooms building day schedule --- .../organisms/SchedulePageModal/SchedulePageModal.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 737f0885d8..114af9c300 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -80,13 +80,18 @@ export const SchedulePageModal: FC = ({ .filter(isEventLaterThisDay(selectedDayIndex === 0 ? Date.now() : day)) .map(prepareForSchedule(day, userEventIds)); - const roomsWithEvents = extendRoomsWithDaysEvents(relatedRooms, daysEvents); + const roomNamesInSchedule = new Set(daysEvents.map((event) => event.room)); + + const roomsWithEvents = extendRoomsWithDaysEvents( + relatedRooms.filter((room) => roomNamesInSchedule.has(room.title)), + daysEvents + ); return { isToday: selectedDayIndex === 0, weekday: format(day, "E"), dayStartUtcSeconds: getUnixTime(day), - rooms: roomsWithEvents.filter((room) => room.events.length > 0), + rooms: roomsWithEvents, personalEvents: daysEvents.filter((event) => event.isSaved), }; }, [relatedVenueEvents, relatedRooms, userEventIds, selectedDayIndex]); From b5f6424790abf0724aaae75f27e884345d8c59f5 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 7 May 2021 13:51:02 +0300 Subject: [PATCH 20/72] Rename day -> dayStart in the SchedulePageModal#schedule --- .../SchedulePageModal/SchedulePageModal.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 114af9c300..083b34149a 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -75,10 +75,12 @@ export const SchedulePageModal: FC = ({ }, [selectedDayIndex]); const schedule: ScheduleDay = useMemo(() => { - const day = addDays(startOfToday(), selectedDayIndex); + const dayStart = addDays(startOfToday(), selectedDayIndex); const daysEvents = relatedVenueEvents - .filter(isEventLaterThisDay(selectedDayIndex === 0 ? Date.now() : day)) - .map(prepareForSchedule(day, userEventIds)); + .filter( + isEventLaterThisDay(selectedDayIndex === 0 ? Date.now() : dayStart) + ) + .map(prepareForSchedule(dayStart, userEventIds)); const roomNamesInSchedule = new Set(daysEvents.map((event) => event.room)); @@ -89,8 +91,8 @@ export const SchedulePageModal: FC = ({ return { isToday: selectedDayIndex === 0, - weekday: format(day, "E"), - dayStartUtcSeconds: getUnixTime(day), + weekday: format(dayStart, "E"), + dayStartUtcSeconds: getUnixTime(dayStart), rooms: roomsWithEvents, personalEvents: daysEvents.filter((event) => event.isSaved), }; From 06620c6fb5ce10998508b5403d8b8cf907ed32d6 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 7 May 2021 19:38:17 +0300 Subject: [PATCH 21/72] Refactor styles --- .../Schedule/Schedule.constants.scss | 7 +-- .../molecules/Schedule/Schedule.scss | 56 +++++++++++++------ .../ScheduleEvent/ScheduleEvent.scss | 54 ++++++++++++------ .../ScheduleRoomEvents.scss | 6 +- .../ScheduleVenueDescription.scss | 24 +++++--- .../SchedulePageModal/SchedulePageModal.scss | 23 +++++--- 6 files changed, 111 insertions(+), 59 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.constants.scss b/src/components/molecules/Schedule/Schedule.constants.scss index 25882bcb44..4d0e39ace9 100644 --- a/src/components/molecules/Schedule/Schedule.constants.scss +++ b/src/components/molecules/Schedule/Schedule.constants.scss @@ -1,5 +1,4 @@ -$room-count: var(--room-count, 1); -$current-time--position: var(--current-time--position, -2); -$hours-count: var(--hours-count, 8); +$ScheduleEvents--padding: 20px; -$hour-width: 200px; +$room--margin-bottom: 1rem; +$room--height: 70px; diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss index 4cf18c2194..7885b48664 100644 --- a/src/components/molecules/Schedule/Schedule.scss +++ b/src/components/molecules/Schedule/Schedule.scss @@ -1,23 +1,43 @@ @import "scss/constants.scss"; @import "./Schedule.constants.scss"; +$room-count: var(--room-count, 1); +$current-time--position: var(--current-time--position, -2); +$hours-count: var(--hours-count, 8); + +$hour-width: 200px; +$half-hour-width: calc(#{$hour-width} / 2); + +$rooms-column--width: 215px; +$timeline--height: 36px; + +$time-line--margin-top: 18px; +$time-line--width: 1px; +$current-time-line--width: 2px; + +$time-line--height: calc( + (#{$room--height} + #{$room--margin-bottom}) * #{$room-count} +); + +$schedule--width: calc(#{$hours-count} * #{$hour-width} + #{$half-hour-width}); + .ScheduledEvents { - padding-top: 20px; + padding-top: $ScheduleEvents--padding; display: flex; position: relative; &__rooms { - flex-basis: 215px; + flex-basis: $rooms-column--width; flex-shrink: 0; - margin-top: 36px; - padding-right: 20px; - box-shadow: 10px 0 30px rgba(0, 0, 0, 0.5); + margin-top: $timeline--height; + padding-right: $ScheduleEvents--padding; + box-shadow: box-shadow--large(); font-size: 0.8rem; } &__room { - margin-bottom: 1rem; - height: 70px; + margin-bottom: $room--margin-bottom; + height: $room--height; display: flex; justify-content: center; flex-flow: column; @@ -36,8 +56,8 @@ } &__timeline { - height: 36px; - font-size: 0.9rem; + height: $timeline--height; + font-size: $font-size--small; opacity: 0.6; white-space: nowrap; } @@ -50,24 +70,24 @@ &::after { content: ""; display: block; - height: calc((65px + 1rem) * #{$room-count}); - border-left: 1px solid white; - margin-left: 100px; - margin-top: 18px; + height: $time-line--height; + border-left: #{$time-line--width} solid white; + margin-left: $half-hour-width; + margin-top: $time-line--margin-top; } } &__user-schedule { - height: 70px; - margin-bottom: 1rem; + height: $room--height; + margin-bottom: $room--margin-bottom; background-color: rgba(255, 255, 255, 0.2); - width: calc(#{$hours-count} * #{$hour-width} + #{$hour-width} / 2); + width: $schedule--width; } &__current-time-line { position: absolute; - width: 2px; - height: calc((65px + 1rem) * #{$room-count}); + width: $current-time-line--width; + height: $time-line--height; left: calc(#{$current-time--position} * 1px); background-color: $primary; } diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index 6b54348cf1..942b4f6524 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -1,46 +1,64 @@ @import "scss/constants.scss"; +$grey--regular: #3f3d42; +$grey--hover: #4c494f; +$grey--users: #4c494f; + +$purple--regular: #7c46fb; +$purple--hover: #7c46fb; + +$ScheduleEvent--margin-top: 0.25rem; +$ScheduleEvent--height: 3.75rem; +$ScheduleEvent--padding: 0 0.25rem 0 0.75rem; +$ScheduleEvent--border-radius: 18px; +$ScheduleEvent--box-shadow: 5px 10px rgba(0, 0, 0, 0.65); + +$bookmark--padding: 0.5rem; +$bookmark-hover--padding-top: 0.375rem; + +$description--margin-top: 2px; + .ScheduleEvent { display: flex; position: absolute; - border-radius: 18px; - padding: 0 4px 0 12px; + border-radius: $ScheduleEvent--border-radius; + padding: $ScheduleEvent--padding; cursor: pointer; - height: 60px; + height: $ScheduleEvent--height; justify-content: space-between; align-items: center; - background-color: #3f3d42; - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.65); - margin-top: 0.25rem; + background-color: $grey--regular; + box-shadow: $ScheduleEvent--box-shadow; + margin-top: $ScheduleEvent--margin-top; &:hover { - background-color: #4c494f; + background-color: $grey--hover; z-index: z(navbar__schedule-event--hover); } &--users { - color: #4c494f; - background-color: #ebebeb; + color: $grey--hover; + background-color: $grey--users; &:hover { - background-color: white; + background-color: $white; } .ScheduleEvent__bookmark { - color: black; + color: $black; } } &--live { - background-color: #7c46fb; - color: white; + background-color: $purple--regular; + color: $white; &:hover { - background-color: #8755fb; + background-color: $purple--hover; } .ScheduleEvent__bookmark { - color: white; + color: $white; } } @@ -64,7 +82,7 @@ overflow: hidden; text-overflow: ellipsis; display: block; - margin-top: 2px; + margin-top: $description--margin-top; font-size: 0.7rem; } @@ -73,10 +91,10 @@ display: flex; justify-content: center; align-items: center; - padding: 0.5rem; + padding: $bookmark--padding; &:hover { - padding-top: 0.375rem; + padding-top: $bookmark-hover--padding-top; } } } diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss index d73d7c89e7..db4c9867be 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss @@ -1,4 +1,6 @@ +@import "../Schedule/Schedule.constants.scss"; + .RoomEvents { - height: 70px; - margin-bottom: 1rem; + height: $room--height; + margin-bottom: $room--margin-bottom; } diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss index c24831ad69..1f27856509 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss @@ -1,23 +1,31 @@ @import "scss/constants.scss"; +@import "../Schedule/Schedule.constants.scss"; + +$image-size: 92px; + +$main--margin-top: 2rem; +$main--margin-bottom: 1rem; + +$name--margin-bottom: 5px; .ScheduleVenueDescription { flex: 1; - padding-left: 20px; + padding-left: $ScheduleEvents--padding; &__main { display: flex; align-items: center; - margin-top: 2rem; - margin-bottom: 1rem; + margin-top: $main--margin-top; + margin-bottom: $main--margin-bottom; } &__pic { flex-shrink: 0; - width: 92px; - height: 92px; + width: $image-size; + height: $image-size; background-size: cover; - border-radius: 46px; - margin-right: 20px; + border-radius: 50%; + margin-right: $ScheduleEvents--padding; cursor: pointer; transition: all 400ms $transition-function; box-shadow: 0 8px 16px rgba($black, 0.3); @@ -34,7 +42,7 @@ &__name { font-style: italic; - margin-bottom: 5px; + margin-bottom: $name--margin-bottom; } &__subtitle { diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss index 347bf218d1..eadf6fe67e 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss @@ -1,5 +1,11 @@ @import "scss/constants.scss"; +$SchedulePageModal--height: 620px; +$SchedulePageModal--padding: 20px; + +$weekday--padding: 8px 10px; +$weekday--margin-right: 10px; + .SchedulePageModal { @include scrollbar; position: fixed; @@ -7,17 +13,17 @@ top: 0; left: 0; width: 100%; - height: 620px; + height: $SchedulePageModal--height; padding-top: $navbar-height; - padding-left: 20px; + padding-left: $SchedulePageModal--padding; background-color: rgba($black, 0.9); overflow: auto; pointer-events: none; opacity: 0; - transform: translateY(-800px); + transform: translateY(-#{$SchedulePageModal--height}); backdrop-filter: blur(5px); box-shadow: 0 20px 50px 0 rgba(0, 0, 0, 0.33); transition: all 400ms $transition-function; @@ -30,15 +36,15 @@ &__weekdays { display: flex; - padding-left: 20px; + padding-left: $SchedulePageModal--padding; } &__weekday { display: inline; cursor: pointer; - padding: 8px 10px; - margin-right: 10px; - border-radius: 22px; // consider variable + padding: $weekday--padding; + margin-right: $weekday--margin-right; + border-radius: $border-radius--input; opacity: 0.8; &--active { @@ -54,7 +60,6 @@ } &__no-events { - padding: 40px; - padding-left: 20px; + padding: $SchedulePageModal--padding; } } From 97450fe8a6c8cff5135e9d09b572068adf69b71c Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 7 May 2021 19:52:20 +0300 Subject: [PATCH 22/72] Create types/schedule --- src/components/molecules/Schedule/Schedule.tsx | 7 ++++++- .../organisms/SchedulePageModal/SchedulePageModal.tsx | 4 ++-- src/components/organisms/SchedulePageModal/utils.ts | 4 +--- src/types/rooms.ts | 6 +++++- .../Schedule/Schedule.types.ts => types/schedule.ts} | 11 ++--------- 5 files changed, 16 insertions(+), 16 deletions(-) rename src/{components/molecules/Schedule/Schedule.types.ts => types/schedule.ts} (59%) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index b3d65d9ae7..9c8c822c4a 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -4,7 +4,8 @@ import { format, fromUnixTime, getUnixTime } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; -import { RoomWithEvents, ScheduleProps } from "./Schedule.types"; +import { ScheduleDay } from "types/schedule"; +import { RoomWithEvents } from "types/rooms"; import { calcStartPosition } from "./Schedule.utils"; @@ -12,6 +13,10 @@ import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; import "./Schedule.scss"; +export interface ScheduleProps { + scheduleDay: ScheduleDay; +} + const MAX_SCHEDULE_START_HOUR = 16; const MAX_HOUR = 24; const MIDDAY_HOUR = 12; diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 083b34149a..5208f8f273 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -3,6 +3,8 @@ import { addDays, startOfToday, format, getUnixTime } from "date-fns"; import { range } from "lodash"; import classNames from "classnames"; +import { ScheduleDay } from "types/schedule"; + import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; @@ -10,8 +12,6 @@ import { useUser } from "hooks/useUser"; import { Schedule } from "components/molecules/Schedule"; import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; -import { ScheduleDay } from "components/molecules/Schedule/Schedule.types"; - import { extendRoomsWithDaysEvents, isEventLaterThisDay, diff --git a/src/components/organisms/SchedulePageModal/utils.ts b/src/components/organisms/SchedulePageModal/utils.ts index e42d9fe393..ff689154cf 100644 --- a/src/components/organisms/SchedulePageModal/utils.ts +++ b/src/components/organisms/SchedulePageModal/utils.ts @@ -8,7 +8,7 @@ import { startOfDay, } from "date-fns"; -import { Room } from "types/rooms"; +import { Room, RoomWithEvents } from "types/rooms"; import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; import { MyPersonalizedSchedule } from "types/User"; @@ -16,8 +16,6 @@ import { WithVenueId } from "utils/id"; import { eventEndTime, eventStartTime } from "utils/event"; import { isTruthy } from "utils/types"; -import { RoomWithEvents } from "components/molecules/Schedule/Schedule.types"; - export const isEventLaterThisDay = (date: number | Date) => ( event: VenueEvent ) => diff --git a/src/types/rooms.ts b/src/types/rooms.ts index fe00072ce7..75f8b3db3d 100644 --- a/src/types/rooms.ts +++ b/src/types/rooms.ts @@ -1,6 +1,6 @@ import { SoundConfigReference } from "./sounds"; -import { VenueEvent } from "types/venues"; +import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; import { WithVenueId } from "utils/id"; export enum RoomTypes { unclickable = "UNCLICKABLE", @@ -44,3 +44,7 @@ export interface RoomData_v2 { template?: string; roomIndex?: number; } + +export type RoomWithEvents = Room & { + events: WithVenueId[]; +}; diff --git a/src/components/molecules/Schedule/Schedule.types.ts b/src/types/schedule.ts similarity index 59% rename from src/components/molecules/Schedule/Schedule.types.ts rename to src/types/schedule.ts index 51b6769265..0f719d5052 100644 --- a/src/components/molecules/Schedule/Schedule.types.ts +++ b/src/types/schedule.ts @@ -1,10 +1,7 @@ -import { Room } from "types/rooms"; import { PersonalizedVenueEvent } from "types/venues"; -import { WithVenueId } from "utils/id"; +import { RoomWithEvents } from "types/rooms"; -export type RoomWithEvents = Room & { - events: WithVenueId[]; -}; +import { WithVenueId } from "utils/id"; export interface ScheduleDay { isToday: boolean; @@ -13,7 +10,3 @@ export interface ScheduleDay { rooms: RoomWithEvents[]; personalEvents: WithVenueId[]; } - -export interface ScheduleProps { - scheduleDay: ScheduleDay; -} From eedc4abb3203238d964e4b7da4b8d18a0f3ceb29 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 12 May 2021 11:08:21 +0300 Subject: [PATCH 23/72] Rename function that updates saved personalized events --- src/api/profile.ts | 2 +- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/api/profile.ts b/src/api/profile.ts index eb761a2824..9e4e18e283 100644 --- a/src/api/profile.ts +++ b/src/api/profile.ts @@ -56,7 +56,7 @@ export interface SaveEventToProfileProps { removeMode?: boolean; } -export const saveEventToProfile = async ({ +export const updatePersonalisedSchedule = async ({ venueId, userId, eventId, diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 882718b124..0c2c0b0b35 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -19,7 +19,7 @@ import { isEventLive } from "utils/event"; import { ONE_HOUR_IN_MINUTES } from "utils/time"; -import { saveEventToProfile } from "api/profile"; +import { updatePersonalisedSchedule } from "api/profile"; import { useUser } from "hooks/useUser"; import { calcStartPosition, HOUR_WIDTH } from "../Schedule/Schedule.utils"; @@ -61,17 +61,17 @@ export const ScheduleEvent: React.FC = ({ () => (event.duration_minutes * HOUR_WIDTH) / ONE_HOUR_IN_MINUTES, [event] ); + const bookmarkEvent = useCallback(() => { - event.isSaved = !event.isSaved; + if (!userId || !event.id) return; - if (userId && event.id) { - saveEventToProfile({ - venueId: event.venueId, - userId: userId, - removeMode: !event.isSaved, - eventId: event.id, - }); - } + event.isSaved = !event.isSaved; + updatePersonalisedSchedule({ + venueId: event.venueId, + userId: userId, + removeMode: !event.isSaved, + eventId: event.id, + }); }, [userId, event]); const onBookmark: MouseEventHandler = useCallback( From 4b5062d7063d480be64ec88429bf24b77fd196ff Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 12 May 2021 12:08:02 +0300 Subject: [PATCH 24/72] Fix ScheduleEvent stylings --- src/components/molecules/ScheduleEvent/ScheduleEvent.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index 942b4f6524..f08bff0dc5 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -3,6 +3,7 @@ $grey--regular: #3f3d42; $grey--hover: #4c494f; $grey--users: #4c494f; +$grey--ligth: #ebebeb; $purple--regular: #7c46fb; $purple--hover: #7c46fb; @@ -11,7 +12,7 @@ $ScheduleEvent--margin-top: 0.25rem; $ScheduleEvent--height: 3.75rem; $ScheduleEvent--padding: 0 0.25rem 0 0.75rem; $ScheduleEvent--border-radius: 18px; -$ScheduleEvent--box-shadow: 5px 10px rgba(0, 0, 0, 0.65); +$ScheduleEvent--box-shadow: 0 5px 10px rgba(0, 0, 0, 0.65); $bookmark--padding: 0.5rem; $bookmark-hover--padding-top: 0.375rem; @@ -38,7 +39,7 @@ $description--margin-top: 2px; &--users { color: $grey--hover; - background-color: $grey--users; + background-color: $grey--ligth; &:hover { background-color: $white; From 3773b544eaa9b24083615b54b444167ca724eff2 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 12 May 2021 12:08:59 +0300 Subject: [PATCH 25/72] Refactor personalized schedule --- .../molecules/Schedule/Schedule.tsx | 119 +++++++++--------- .../molecules/Schedule/Schedule.utils.ts | 6 +- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 12 +- .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 10 +- .../SchedulePageModal/SchedulePageModal.tsx | 25 +++- src/types/schedule.ts | 12 -- src/utils/time.ts | 3 + 7 files changed, 96 insertions(+), 91 deletions(-) delete mode 100644 src/types/schedule.ts diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 9c8c822c4a..a3c8c43fe8 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,11 +1,15 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useMemo } from "react"; import classNames from "classnames"; -import { format, fromUnixTime, getUnixTime } from "date-fns"; +import { getHours, getUnixTime } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; -import { ScheduleDay } from "types/schedule"; import { RoomWithEvents } from "types/rooms"; +import { PersonalizedVenueEvent } from "types/venues"; + +import { eventStartTime } from "utils/event"; +import { WithVenueId } from "utils/id"; +import { MAX_HOUR, MIDDAY_HOUR } from "utils/time"; import { calcStartPosition } from "./Schedule.utils"; @@ -14,59 +18,69 @@ import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; import "./Schedule.scss"; export interface ScheduleProps { - scheduleDay: ScheduleDay; + rooms: RoomWithEvents[]; + personalEvents: WithVenueId[]; + isToday: boolean; } const MAX_SCHEDULE_START_HOUR = 16; -const MAX_HOUR = 24; -const MIDDAY_HOUR = 12; - -export const Schedule: React.FC = ({ scheduleDay }) => { - const getStartHour = useCallback( - (utcSeconds: number) => { - return utcSeconds >= scheduleDay.dayStartUtcSeconds - ? Number(format(fromUnixTime(utcSeconds), "H")) - : 0; - }, - [scheduleDay] - ); +const NUMBER_OF_PERSONAL_ROOMS = 1; - const roomStartHour = useCallback( - (room: RoomWithEvents) => - room.events?.reduce( - (acc, event) => Math.min(acc, getStartHour(event.start_utc_seconds)), - MAX_SCHEDULE_START_HOUR - ) ?? MAX_SCHEDULE_START_HOUR, - [getStartHour] +const getRoomStartHour = (room: RoomWithEvents) => + room.events.reduce( + (acc, event) => Math.min(acc, getHours(eventStartTime(event))), + MAX_SCHEDULE_START_HOUR ); +export const Schedule: React.FC = ({ + rooms, + personalEvents, + isToday, +}) => { const scheduleStartHour = useMemo( () => Math.min( - ...scheduleDay.rooms.map((room) => roomStartHour(room)), + ...rooms.map((room) => getRoomStartHour(room)), MAX_SCHEDULE_START_HOUR ), - [scheduleDay, roomStartHour] + [rooms] + ); + + const currentTimePosition = calcStartPosition( + Math.floor(getUnixTime(Date.now())), + scheduleStartHour ); - const hours = useMemo( + const roomCells = useMemo( () => - range(scheduleStartHour, MAX_HOUR).map( - (hour: number) => - `${hour % MIDDAY_HOUR || MIDDAY_HOUR} ${ - hour >= MIDDAY_HOUR ? "PM" : "AM" - }` - ), + rooms.map((room) => ( +
    +

    {room.title}

    + + {room.events.length} events + +
    + )), + [rooms] + ); + + const hoursRow = useMemo( + () => + range(scheduleStartHour, MAX_HOUR).map((hour: number) => { + return ( + + {hour % MIDDAY_HOUR || MIDDAY_HOUR}{" "} + {hour >= MIDDAY_HOUR ? "PM" : "AM"} + + ); + }), [scheduleStartHour] ); const containerVars = useCss({ - "--room-count": scheduleDay.rooms.length + 1, - "--current-time--position": calcStartPosition( - Math.floor(getUnixTime(Date.now())), - scheduleStartHour - ), - "--hours-count": hours.length, + "--room-count": rooms.length + NUMBER_OF_PERSONAL_ROOMS, + "--current-time--position": currentTimePosition, + "--hours-count": hoursRow.length, }); const containerClasses = useMemo( @@ -80,40 +94,25 @@ export const Schedule: React.FC = ({ scheduleDay }) => {

    My Daily Schedule

    - {scheduleDay.personalEvents.length} events + {personalEvents.length} events
    - {scheduleDay.rooms.map((room) => ( -
    -

    {room.title}

    - - {room.events?.length || 0} events - -
    - ))} + {roomCells}
    -
    - {hours.map((hour: string) => ( - - {hour} - - ))} -
    +
    {hoursRow}
    - {scheduleDay.isToday && ( -
    - )} + {isToday &&
    }
    - {scheduleDay.rooms.map((room) => ( + {rooms.map((room) => ( ; scheduleStartHour: number; - isUsers?: boolean; + isPersonalizedEvent?: boolean; } export const ScheduleEvent: React.FC = ({ event, scheduleStartHour, - isUsers, + isPersonalizedEvent, }) => { const [isBookmarked, setBookmark] = useState(event.isSaved); @@ -52,13 +52,13 @@ export const ScheduleEvent: React.FC = ({ { "ScheduleEvent--live": isEventLive(event), }, - { "ScheduleEvent--users": isTruthy(isUsers) } + { "ScheduleEvent--users": isTruthy(isPersonalizedEvent) } ), - [event, isUsers] + [event, isPersonalizedEvent] ); const eventWidth = useMemo( - () => (event.duration_minutes * HOUR_WIDTH) / ONE_HOUR_IN_MINUTES, + () => (event.duration_minutes * HOUR_WIDTH_PX) / ONE_HOUR_IN_MINUTES, [event] ); diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index 44c79c8011..1c3909091b 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -11,20 +11,20 @@ import "./ScheduleRoomEvents.scss"; export interface ScheduleRoomEventsProps { events: WithVenueId[]; scheduleStartHour: number; - isUsers?: boolean; + isPersonalizedRoom?: boolean; } export const ScheduleRoomEvents: React.FC = ({ events, scheduleStartHour, - isUsers, + isPersonalizedRoom, }) => { return (
    - {events.map((event, index) => ( + {events.map((event) => ( diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 5208f8f273..ec49d885b1 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -3,12 +3,15 @@ import { addDays, startOfToday, format, getUnixTime } from "date-fns"; import { range } from "lodash"; import classNames from "classnames"; -import { ScheduleDay } from "types/schedule"; - import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; +import { PersonalizedVenueEvent } from "types/venues"; +import { RoomWithEvents } from "types/rooms"; + +import { WithVenueId } from "utils/id"; + import { Schedule } from "components/molecules/Schedule"; import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; @@ -20,12 +23,20 @@ import { import "./SchedulePageModal.scss"; -const DAYS_AHEAD = 7; +const SCHEDULE_SHOW_DAYS_AHEAD = 7; interface SchedulePageModalProps { isVisible?: boolean; } +export interface ScheduleDay { + isToday: boolean; + weekday: string; + dayStartUtcSeconds: number; + rooms: RoomWithEvents[]; + personalEvents: WithVenueId[]; +} + export const emptyPersonalizedSchedule = {}; export const SchedulePageModal: FC = ({ @@ -51,7 +62,7 @@ export const SchedulePageModal: FC = ({ const weekdays = useMemo(() => { const today = startOfToday(); - return range(0, DAYS_AHEAD).map((dayIndex) => { + return range(0, SCHEDULE_SHOW_DAYS_AHEAD).map((dayIndex) => { const day = addDays(today, dayIndex); const classes = classNames("SchedulePageModal__weekday", { "SchedulePageModal__weekday--active": dayIndex === selectedDayIndex, @@ -109,7 +120,11 @@ export const SchedulePageModal: FC = ({
      {weekdays}
    {schedule.rooms.length > 0 ? ( - + ) : (
    No events scheduled
    )} diff --git a/src/types/schedule.ts b/src/types/schedule.ts deleted file mode 100644 index 0f719d5052..0000000000 --- a/src/types/schedule.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PersonalizedVenueEvent } from "types/venues"; -import { RoomWithEvents } from "types/rooms"; - -import { WithVenueId } from "utils/id"; - -export interface ScheduleDay { - isToday: boolean; - weekday: string; - dayStartUtcSeconds: number; - rooms: RoomWithEvents[]; - personalEvents: WithVenueId[]; -} diff --git a/src/utils/time.ts b/src/utils/time.ts index 015d5a9415..34e54fbc50 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -23,6 +23,9 @@ export const ONE_HOUR_IN_MILLISECONDS = export const SECONDS_TIMESTAMP_MAX_VALUE = 9999999999; +export const MAX_HOUR = 24; +export const MIDDAY_HOUR = 12; + /** * Convert totalSeconds to a Duration object (days, hours, minutes, seconds). * From ad87fa8ede434fc3f42dfffda2da249c15b4511b Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Wed, 12 May 2021 17:04:35 +0300 Subject: [PATCH 26/72] Renew style variables usage --- src/components/molecules/Schedule/Schedule.scss | 2 +- .../organisms/SchedulePageModal/SchedulePageModal.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss index 7885b48664..29b5600968 100644 --- a/src/components/molecules/Schedule/Schedule.scss +++ b/src/components/molecules/Schedule/Schedule.scss @@ -57,7 +57,7 @@ $schedule--width: calc(#{$hours-count} * #{$hour-width} + #{$half-hour-width}); &__timeline { height: $timeline--height; - font-size: $font-size--small; + font-size: $font-size--md; opacity: 0.6; white-space: nowrap; } diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss index eadf6fe67e..6dfb1d4e78 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss @@ -44,7 +44,7 @@ $weekday--margin-right: 10px; cursor: pointer; padding: $weekday--padding; margin-right: $weekday--margin-right; - border-radius: $border-radius--input; + border-radius: $border-radius--xl; opacity: 0.8; &--active { From 6872d59cb55422994182f249d9f9c0d18cba94f8 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 15:58:14 +0300 Subject: [PATCH 27/72] Configure venue driven schedule --- .../molecules/Schedule/Schedule.tsx | 47 ++++++++-------- .../SchedulePageModal/SchedulePageModal.tsx | 55 ++++++++++++------- .../organisms/SchedulePageModal/utils.ts | 6 ++ src/types/venues.ts | 13 +++++ 4 files changed, 78 insertions(+), 43 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index a3c8c43fe8..8817070170 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -4,12 +4,11 @@ import { getHours, getUnixTime } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; -import { RoomWithEvents } from "types/rooms"; -import { PersonalizedVenueEvent } from "types/venues"; +import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; -import { eventStartTime } from "utils/event"; import { WithVenueId } from "utils/id"; import { MAX_HOUR, MIDDAY_HOUR } from "utils/time"; +import { eventStartTime } from "utils/event"; import { calcStartPosition } from "./Schedule.utils"; @@ -18,7 +17,7 @@ import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; import "./Schedule.scss"; export interface ScheduleProps { - rooms: RoomWithEvents[]; + locatedEvents: LocatedEvents[]; personalEvents: WithVenueId[]; isToday: boolean; } @@ -26,24 +25,23 @@ export interface ScheduleProps { const MAX_SCHEDULE_START_HOUR = 16; const NUMBER_OF_PERSONAL_ROOMS = 1; -const getRoomStartHour = (room: RoomWithEvents) => - room.events.reduce( - (acc, event) => Math.min(acc, getHours(eventStartTime(event))), - MAX_SCHEDULE_START_HOUR - ); - export const Schedule: React.FC = ({ - rooms, + locatedEvents, personalEvents, isToday, }) => { const scheduleStartHour = useMemo( () => Math.min( - ...rooms.map((room) => getRoomStartHour(room)), + ...locatedEvents.map(({ events }) => + events.reduce( + (acc, event) => Math.min(acc, getHours(eventStartTime(event))), + MAX_SCHEDULE_START_HOUR + ) + ), MAX_SCHEDULE_START_HOUR ), - [rooms] + [locatedEvents] ); const currentTimePosition = calcStartPosition( @@ -53,15 +51,20 @@ export const Schedule: React.FC = ({ const roomCells = useMemo( () => - rooms.map((room) => ( -
    -

    {room.title}

    + locatedEvents?.map(({ location, events }) => ( +
    +

    + {location.roomTitle || location.venueTitle || location.venueId} +

    - {room.events.length} events + {events.length} events
    )), - [rooms] + [locatedEvents] ); const hoursRow = useMemo( @@ -78,7 +81,7 @@ export const Schedule: React.FC = ({ ); const containerVars = useCss({ - "--room-count": rooms.length + NUMBER_OF_PERSONAL_ROOMS, + "--room-count": locatedEvents.length + NUMBER_OF_PERSONAL_ROOMS, "--current-time--position": currentTimePosition, "--hours-count": hoursRow.length, }); @@ -112,10 +115,10 @@ export const Schedule: React.FC = ({ scheduleStartHour={scheduleStartHour} />
    - {rooms.map((room) => ( + {locatedEvents.map(({ location, events }) => ( ))} diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index ec49d885b1..252553f4f0 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -1,14 +1,23 @@ -import React, { useState, useMemo, FC, MouseEventHandler } from "react"; +import React, { + useState, + useMemo, + FC, + MouseEventHandler, + useCallback, +} from "react"; import { addDays, startOfToday, format, getUnixTime } from "date-fns"; -import { range } from "lodash"; +import { chain, range } from "lodash"; import classNames from "classnames"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; -import { PersonalizedVenueEvent } from "types/venues"; -import { RoomWithEvents } from "types/rooms"; +import { + PersonalizedVenueEvent, + VenueLocation, + LocatedEvents, +} from "types/venues"; import { WithVenueId } from "utils/id"; @@ -16,7 +25,8 @@ import { Schedule } from "components/molecules/Schedule"; import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; import { - extendRoomsWithDaysEvents, + buildLocationString, + extractLocation, isEventLaterThisDay, prepareForSchedule, } from "./utils"; @@ -33,7 +43,7 @@ export interface ScheduleDay { isToday: boolean; weekday: string; dayStartUtcSeconds: number; - rooms: RoomWithEvents[]; + locatedEvents: LocatedEvents[]; personalEvents: WithVenueId[]; } @@ -52,11 +62,6 @@ export const SchedulePageModal: FC = ({ withEvents: true, }); - const relatedRooms = useMemo( - () => relatedVenues.flatMap((venue) => venue.rooms ?? []), - [relatedVenues] - ); - const [selectedDayIndex, setSelectedDayIndex] = useState(0); const weekdays = useMemo(() => { @@ -85,6 +90,16 @@ export const SchedulePageModal: FC = ({ }); }, [selectedDayIndex]); + const getLocaion = useCallback( + (locString: string): VenueLocation => { + const [venueId, roomTitle = ""] = extractLocation(locString); + const venueTitle = + relatedVenues.find((venue) => venue.id === venueId)?.name || ""; + return { venueId, roomTitle, venueTitle }; + }, + [relatedVenues] + ); + const schedule: ScheduleDay = useMemo(() => { const dayStart = addDays(startOfToday(), selectedDayIndex); const daysEvents = relatedVenueEvents @@ -93,21 +108,19 @@ export const SchedulePageModal: FC = ({ ) .map(prepareForSchedule(dayStart, userEventIds)); - const roomNamesInSchedule = new Set(daysEvents.map((event) => event.room)); - - const roomsWithEvents = extendRoomsWithDaysEvents( - relatedRooms.filter((room) => roomNamesInSchedule.has(room.title)), - daysEvents - ); + const locatedEvents: LocatedEvents[] = chain(daysEvents) + .groupBy(buildLocationString) + .map((value, key) => ({ location: getLocaion(key), events: value })) + .value(); return { + locatedEvents, isToday: selectedDayIndex === 0, weekday: format(dayStart, "E"), dayStartUtcSeconds: getUnixTime(dayStart), - rooms: roomsWithEvents, personalEvents: daysEvents.filter((event) => event.isSaved), }; - }, [relatedVenueEvents, relatedRooms, userEventIds, selectedDayIndex]); + }, [relatedVenueEvents, userEventIds, selectedDayIndex, getLocaion]); const containerClasses = classNames("SchedulePageModal", { "SchedulePageModal--show": isVisible, @@ -119,9 +132,9 @@ export const SchedulePageModal: FC = ({
      {weekdays}
    - {schedule.rooms.length > 0 ? ( + {schedule.locatedEvents.length > 0 ? ( diff --git a/src/components/organisms/SchedulePageModal/utils.ts b/src/components/organisms/SchedulePageModal/utils.ts index ff689154cf..54217c6ce1 100644 --- a/src/components/organisms/SchedulePageModal/utils.ts +++ b/src/components/organisms/SchedulePageModal/utils.ts @@ -52,3 +52,9 @@ export const prepareForSchedule = ( ), }; }; + +export const buildLocationString = (event: WithVenueId) => + `${event.venueId}#${event.room}`; + +export const extractLocation = (locationStr: string) => + locationStr.split("#", 2); diff --git a/src/types/venues.ts b/src/types/venues.ts index 85fc7465da..8cc0368f1e 100644 --- a/src/types/venues.ts +++ b/src/types/venues.ts @@ -2,6 +2,8 @@ import { CSSProperties } from "react"; import { HAS_ROOMS_TEMPLATES } from "settings"; +import { WithVenueId } from "utils/id"; + import { EntranceStepConfig } from "./EntranceStep"; import { Poster } from "./posters"; import { Quotation } from "./Quotation"; @@ -311,6 +313,17 @@ export interface VenueEvent { id?: string; } +export interface VenueLocation { + venueId: string; + roomTitle: string; + venueTitle?: string; +} + +export interface LocatedEvents { + location: VenueLocation; + events: WithVenueId[]; +} + export interface PersonalizedVenueEvent extends VenueEvent { isSaved: boolean; } From 7bccbd028b48f3f9efb8beef30e9e86635010392 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 19:43:15 +0300 Subject: [PATCH 28/72] Remove isBookmarked useState --- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index e6aebaa690..84577cf273 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -1,10 +1,4 @@ -import React, { - MouseEventHandler, - useCallback, - useEffect, - useMemo, - useState, -} from "react"; +import React, { MouseEventHandler, useCallback, useMemo } from "react"; import classNames from "classnames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -37,12 +31,6 @@ export const ScheduleEvent: React.FC = ({ scheduleStartHour, isPersonalizedEvent, }) => { - const [isBookmarked, setBookmark] = useState(event.isSaved); - - useEffect(() => { - setBookmark(event.isSaved); - }, [event.isSaved]); - const { userId } = useUser(); const containerClasses = useMemo( @@ -100,7 +88,7 @@ export const ScheduleEvent: React.FC = ({
    From f9a5a03fd4b27519a1be12954168717088125af5 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 19:50:21 +0300 Subject: [PATCH 29/72] Make MyPersonalizedSchedule interface Partial --- src/types/User.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/types/User.ts b/src/types/User.ts index ead69cce4d..c9f152f8ba 100644 --- a/src/types/User.ts +++ b/src/types/User.ts @@ -14,7 +14,8 @@ export type VideoState = { removedParticipantUids?: string[]; }; -export type MyPersonalizedSchedule = Record; +// the structure is { [key: venueId] : eventId[] } +export type MyPersonalizedSchedule = Partial>; export interface User { drinkOfChoice?: string; From e8e72acdc973897264de5681a7be2ff8c65bd991 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 20:14:16 +0300 Subject: [PATCH 30/72] Document deprecated EventDisplay component --- src/components/molecules/EventDisplay/EventDisplay.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/molecules/EventDisplay/EventDisplay.tsx b/src/components/molecules/EventDisplay/EventDisplay.tsx index f75a535ef7..865dfcc11d 100644 --- a/src/components/molecules/EventDisplay/EventDisplay.tsx +++ b/src/components/molecules/EventDisplay/EventDisplay.tsx @@ -16,6 +16,13 @@ export interface EventDisplayProps { venue?: WithId; } +/** + * @dept the componnet is used in the OnlineStats and VenuePreview (Playa) which are to be removed as part of the Playa cleanup work. + * + * @see https://github.com/sparkletown/sparkle/pull/833 + * + * @deprecated since https://github.com/sparkletown/sparkle/pull/1302 is merged; the component is replaced by ScheduleEvent + */ export const EventDisplay: React.FC = ({ event, venue }) => { const eventRoomTitle = event.room; From e5721d0ad131b92d8d01a936e71f0f3a351d9ef1 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 23:28:32 +0300 Subject: [PATCH 31/72] Move schedule constants to settings --- src/components/molecules/Schedule/Schedule.scss | 2 +- src/components/molecules/Schedule/Schedule.tsx | 16 ++++++++++------ .../molecules/Schedule/Schedule.utils.ts | 8 ++++---- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 8 ++++++-- .../SchedulePageModal/SchedulePageModal.tsx | 4 ++-- src/settings.ts | 7 +++++++ 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss index 29b5600968..947b9c3568 100644 --- a/src/components/molecules/Schedule/Schedule.scss +++ b/src/components/molecules/Schedule/Schedule.scss @@ -5,7 +5,7 @@ $room-count: var(--room-count, 1); $current-time--position: var(--current-time--position, -2); $hours-count: var(--hours-count, 8); -$hour-width: 200px; +$hour-width: var(--hour-width, 200px); $half-hour-width: calc(#{$hour-width} / 2); $rooms-column--width: 215px; diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 8817070170..6ad618da91 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -4,6 +4,12 @@ import { getHours, getUnixTime } from "date-fns"; import { range } from "lodash"; import { useCss } from "react-use"; +import { + SCHEDULE_HOUR_COLUMN_WIDTH_PX, + SCHEDULE_MAX_START_HOUR, + SCHEDULE_NUMBER_OF_PERSONAL_ROOMS, +} from "settings"; + import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; import { WithVenueId } from "utils/id"; @@ -22,9 +28,6 @@ export interface ScheduleProps { isToday: boolean; } -const MAX_SCHEDULE_START_HOUR = 16; -const NUMBER_OF_PERSONAL_ROOMS = 1; - export const Schedule: React.FC = ({ locatedEvents, personalEvents, @@ -36,10 +39,10 @@ export const Schedule: React.FC = ({ ...locatedEvents.map(({ events }) => events.reduce( (acc, event) => Math.min(acc, getHours(eventStartTime(event))), - MAX_SCHEDULE_START_HOUR + SCHEDULE_MAX_START_HOUR ) ), - MAX_SCHEDULE_START_HOUR + SCHEDULE_MAX_START_HOUR ), [locatedEvents] ); @@ -81,9 +84,10 @@ export const Schedule: React.FC = ({ ); const containerVars = useCss({ - "--room-count": locatedEvents.length + NUMBER_OF_PERSONAL_ROOMS, + "--room-count": locatedEvents.length + SCHEDULE_NUMBER_OF_PERSONAL_ROOMS, "--current-time--position": currentTimePosition, "--hours-count": hoursRow.length, + "--hour-width": `${SCHEDULE_HOUR_COLUMN_WIDTH_PX}px`, }); const containerClasses = useMemo( diff --git a/src/components/molecules/Schedule/Schedule.utils.ts b/src/components/molecules/Schedule/Schedule.utils.ts index 8c06722cd1..807b6eba12 100644 --- a/src/components/molecules/Schedule/Schedule.utils.ts +++ b/src/components/molecules/Schedule/Schedule.utils.ts @@ -1,6 +1,6 @@ -import { getSecondsFromStartOfDay, ONE_HOUR_IN_SECONDS } from "utils/time"; +import { SCHEDULE_HOUR_COLUMN_WIDTH_PX } from "settings"; -export const HOUR_WIDTH_PX = 200; +import { getSecondsFromStartOfDay, ONE_HOUR_IN_SECONDS } from "utils/time"; export const calcStartPosition = ( startTimeUtcSeconds: number, @@ -9,8 +9,8 @@ export const calcStartPosition = ( const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); return Math.floor( - HOUR_WIDTH_PX / 2 + + SCHEDULE_HOUR_COLUMN_WIDTH_PX / 2 + (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * - HOUR_WIDTH_PX + SCHEDULE_HOUR_COLUMN_WIDTH_PX ); }; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 84577cf273..533820c308 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -5,6 +5,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; import { faBookmark as regularBookmark } from "@fortawesome/free-regular-svg-icons"; +import { SCHEDULE_HOUR_COLUMN_WIDTH_PX } from "settings"; + import { PersonalizedVenueEvent } from "types/venues"; import { WithVenueId } from "utils/id"; @@ -16,7 +18,7 @@ import { ONE_HOUR_IN_MINUTES } from "utils/time"; import { updatePersonalisedSchedule } from "api/profile"; import { useUser } from "hooks/useUser"; -import { calcStartPosition, HOUR_WIDTH_PX } from "../Schedule/Schedule.utils"; +import { calcStartPosition } from "../Schedule/Schedule.utils"; import "./ScheduleEvent.scss"; @@ -46,7 +48,9 @@ export const ScheduleEvent: React.FC = ({ ); const eventWidth = useMemo( - () => (event.duration_minutes * HOUR_WIDTH_PX) / ONE_HOUR_IN_MINUTES, + () => + (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / + ONE_HOUR_IN_MINUTES, [event] ); diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 252553f4f0..c885f8aaa1 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -9,6 +9,8 @@ import { addDays, startOfToday, format, getUnixTime } from "date-fns"; import { chain, range } from "lodash"; import classNames from "classnames"; +import { SCHEDULE_SHOW_DAYS_AHEAD } from "settings"; + import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; @@ -33,8 +35,6 @@ import { import "./SchedulePageModal.scss"; -const SCHEDULE_SHOW_DAYS_AHEAD = 7; - interface SchedulePageModalProps { isVisible?: boolean; } diff --git a/src/settings.ts b/src/settings.ts index 8d4f5801b6..4e34326913 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -566,3 +566,10 @@ export const POSTERPAGE_MAX_VIDEO_PARTICIPANTS = 10; export const SEARCH_DEBOUNCE_TIME = 200; // ms export const DEFAULT_DISPLAYED_POSTER_PREVIEW_COUNT = 12; + +// SCHEDULE +// @debt probably would be better to adjust max hour based on user's display size +export const SCHEDULE_MAX_START_HOUR = 16; +export const SCHEDULE_NUMBER_OF_PERSONAL_ROOMS = 1; +export const SCHEDULE_HOUR_COLUMN_WIDTH_PX = 200; +export const SCHEDULE_SHOW_DAYS_AHEAD = 7; From ec6f178b8e074584901f9e51acfb0107b4190770 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Thu, 13 May 2021 23:40:56 +0300 Subject: [PATCH 32/72] Use memo where requested --- .../molecules/Schedule/Schedule.tsx | 20 ++++++++++++------- .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 14 +++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 6ad618da91..14f61b52ef 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -95,6 +95,18 @@ export const Schedule: React.FC = ({ [containerVars] ); + const rowsWithTheEvents = useMemo( + () => + locatedEvents.map(({ location, events }) => ( + + )), + [locatedEvents, scheduleStartHour] + ); + return (
    @@ -119,13 +131,7 @@ export const Schedule: React.FC = ({ scheduleStartHour={scheduleStartHour} />
    - {locatedEvents.map(({ location, events }) => ( - - ))} + {rowsWithTheEvents}
    ); diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index 1c3909091b..3a2952d763 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { PersonalizedVenueEvent } from "types/venues"; @@ -19,16 +19,18 @@ export const ScheduleRoomEvents: React.FC = ({ scheduleStartHour, isPersonalizedRoom, }) => { - return ( -
    - {events.map((event) => ( + const eventBlocks = useMemo( + () => + events.map((event) => ( - ))} -
    + )), + [events, isPersonalizedRoom, scheduleStartHour] ); + + return
    {eventBlocks}
    ; }; From 90fcd9db53a724b9e0e2b13aea8197fea206279c Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 00:09:32 +0300 Subject: [PATCH 33/72] Use eachOfInterval to show schedule hour labels --- .../molecules/Schedule/Schedule.tsx | 39 +++++++++++++------ .../SchedulePageModal/SchedulePageModal.tsx | 9 ++++- src/utils/time.ts | 3 -- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 14f61b52ef..8d6c9b0a24 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,7 +1,13 @@ import React, { useMemo } from "react"; import classNames from "classnames"; -import { getHours, getUnixTime } from "date-fns"; -import { range } from "lodash"; +import { + eachHourOfInterval, + endOfDay, + format, + getHours, + getUnixTime, + setHours, +} from "date-fns"; import { useCss } from "react-use"; import { @@ -13,7 +19,6 @@ import { import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; import { WithVenueId } from "utils/id"; -import { MAX_HOUR, MIDDAY_HOUR } from "utils/time"; import { eventStartTime } from "utils/event"; import { calcStartPosition } from "./Schedule.utils"; @@ -25,12 +30,14 @@ import "./Schedule.scss"; export interface ScheduleProps { locatedEvents: LocatedEvents[]; personalEvents: WithVenueId[]; + scheduleDate: Date; isToday: boolean; } export const Schedule: React.FC = ({ locatedEvents, personalEvents, + scheduleDate, isToday, }) => { const scheduleStartHour = useMemo( @@ -47,6 +54,11 @@ export const Schedule: React.FC = ({ [locatedEvents] ); + const scheduleStartDateTime = useMemo( + () => setHours(scheduleDate, scheduleStartHour), + [scheduleStartHour, scheduleDate] + ); + const currentTimePosition = calcStartPosition( Math.floor(getUnixTime(Date.now())), scheduleStartHour @@ -72,15 +84,18 @@ export const Schedule: React.FC = ({ const hoursRow = useMemo( () => - range(scheduleStartHour, MAX_HOUR).map((hour: number) => { - return ( - - {hour % MIDDAY_HOUR || MIDDAY_HOUR}{" "} - {hour >= MIDDAY_HOUR ? "PM" : "AM"} - - ); - }), - [scheduleStartHour] + eachHourOfInterval({ + start: scheduleStartDateTime, + end: endOfDay(scheduleStartDateTime), + }).map((scheduleHour) => ( + + {format(scheduleHour, "h a")} + + )), + [scheduleStartDateTime] ); const containerVars = useCss({ diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index c885f8aaa1..0e7def2421 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -5,7 +5,13 @@ import React, { MouseEventHandler, useCallback, } from "react"; -import { addDays, startOfToday, format, getUnixTime } from "date-fns"; +import { + addDays, + startOfToday, + format, + getUnixTime, + fromUnixTime, +} from "date-fns"; import { chain, range } from "lodash"; import classNames from "classnames"; @@ -137,6 +143,7 @@ export const SchedulePageModal: FC = ({ locatedEvents={schedule.locatedEvents} personalEvents={schedule.personalEvents} isToday={schedule.isToday} + scheduleDate={fromUnixTime(schedule.dayStartUtcSeconds)} /> ) : (
    No events scheduled
    diff --git a/src/utils/time.ts b/src/utils/time.ts index 34e54fbc50..015d5a9415 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -23,9 +23,6 @@ export const ONE_HOUR_IN_MILLISECONDS = export const SECONDS_TIMESTAMP_MAX_VALUE = 9999999999; -export const MAX_HOUR = 24; -export const MIDDAY_HOUR = 12; - /** * Convert totalSeconds to a Duration object (days, hours, minutes, seconds). * From f746cd4994e52ebca9c3f2873491ae671934016e Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 00:26:47 +0300 Subject: [PATCH 34/72] Separate adding and removing events (personalized schedule) --- src/api/profile.ts | 33 +++++++++++++------ .../molecules/ScheduleEvent/ScheduleEvent.tsx | 14 ++++---- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/api/profile.ts b/src/api/profile.ts index 9e4e18e283..4f19589242 100644 --- a/src/api/profile.ts +++ b/src/api/profile.ts @@ -1,6 +1,10 @@ import Bugsnag from "@bugsnag/js"; import firebase from "firebase/app"; +import { VenueEvent } from "types/venues"; + +import { WithVenueId } from "utils/id"; + export interface MakeUpdateUserGridLocationProps { venueId: string; userUid: string; @@ -49,19 +53,29 @@ export const makeUpdateUserGridLocation = ({ }); }; -export interface SaveEventToProfileProps { - venueId: string; +export interface UpdatePersonalizedScheduleProps { + event: WithVenueId; userId: string; - eventId: string; removeMode?: boolean; } -export const updatePersonalisedSchedule = async ({ - venueId, +export const addEventToPersonalizedSchedule = ({ + event, + userId, +}: Omit): Promise => + updatePersonalizedSchedule({ event, userId }); + +export const removeEventFromPersonalizedSchedule = ({ + event, + userId, +}: Omit): Promise => + updatePersonalizedSchedule({ event, userId, removeMode: true }); + +export const updatePersonalizedSchedule = async ({ + event, userId, - eventId, removeMode = false, -}: SaveEventToProfileProps): Promise => { +}: UpdatePersonalizedScheduleProps): Promise => { const userProfileRef = firebase.firestore().collection("users").doc(userId); const modify = removeMode @@ -69,16 +83,15 @@ export const updatePersonalisedSchedule = async ({ : firebase.firestore.FieldValue.arrayUnion; const newSavedEvents = { - [`myPersonalizedSchedule.${venueId}`]: modify(eventId), + [`myPersonalizedSchedule.${event.venueId}`]: modify(event.id), }; return userProfileRef.update(newSavedEvents).catch((err) => { Bugsnag.notify(err, (event) => { event.addMetadata("context", { location: "api/profile::saveEventToProfile", - venueId, userId, - eventId, + event, removeMode, }); }); diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 533820c308..ebea44e63d 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -15,7 +15,10 @@ import { isEventLive } from "utils/event"; import { ONE_HOUR_IN_MINUTES } from "utils/time"; -import { updatePersonalisedSchedule } from "api/profile"; +import { + addEventToPersonalizedSchedule, + removeEventFromPersonalizedSchedule, +} from "api/profile"; import { useUser } from "hooks/useUser"; import { calcStartPosition } from "../Schedule/Schedule.utils"; @@ -58,12 +61,9 @@ export const ScheduleEvent: React.FC = ({ if (!userId || !event.id) return; event.isSaved = !event.isSaved; - updatePersonalisedSchedule({ - venueId: event.venueId, - userId: userId, - removeMode: !event.isSaved, - eventId: event.id, - }); + event.isSaved + ? addEventToPersonalizedSchedule({ event, userId }) + : removeEventFromPersonalizedSchedule({ event, userId }); }, [userId, event]); const onBookmark: MouseEventHandler = useCallback( From 9f5cb16ef2b454cef9eaf486e2b3a35218bea171 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 00:33:33 +0300 Subject: [PATCH 35/72] Rename old class name ScheduledEvents -> Schedule --- .../Schedule/Schedule.constants.scss | 2 +- .../molecules/Schedule/Schedule.scss | 6 ++-- .../molecules/Schedule/Schedule.tsx | 31 ++++++++----------- .../ScheduleVenueDescription.scss | 4 +-- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.constants.scss b/src/components/molecules/Schedule/Schedule.constants.scss index 4d0e39ace9..6dce9c84a8 100644 --- a/src/components/molecules/Schedule/Schedule.constants.scss +++ b/src/components/molecules/Schedule/Schedule.constants.scss @@ -1,4 +1,4 @@ -$ScheduleEvents--padding: 20px; +$Schedule--padding: 20px; $room--margin-bottom: 1rem; $room--height: 70px; diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss index 947b9c3568..0b0a8100df 100644 --- a/src/components/molecules/Schedule/Schedule.scss +++ b/src/components/molecules/Schedule/Schedule.scss @@ -21,8 +21,8 @@ $time-line--height: calc( $schedule--width: calc(#{$hours-count} * #{$hour-width} + #{$half-hour-width}); -.ScheduledEvents { - padding-top: $ScheduleEvents--padding; +.Schedule { + padding-top: $Schedule--padding; display: flex; position: relative; @@ -30,7 +30,7 @@ $schedule--width: calc(#{$hours-count} * #{$hour-width} + #{$half-hour-width}); flex-basis: $rooms-column--width; flex-shrink: 0; margin-top: $timeline--height; - padding-right: $ScheduleEvents--padding; + padding-right: $Schedule--padding; box-shadow: box-shadow--large(); font-size: 0.8rem; } diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 8d6c9b0a24..91bc2b896f 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -69,14 +69,12 @@ export const Schedule: React.FC = ({ locatedEvents?.map(({ location, events }) => (
    -

    +

    {location.roomTitle || location.venueTitle || location.venueId}

    - - {events.length} events - + {events.length} events
    )), [locatedEvents] @@ -88,10 +86,7 @@ export const Schedule: React.FC = ({ start: scheduleStartDateTime, end: endOfDay(scheduleStartDateTime), }).map((scheduleHour) => ( - + {format(scheduleHour, "h a")} )), @@ -106,7 +101,7 @@ export const Schedule: React.FC = ({ }); const containerClasses = useMemo( - () => classNames("ScheduledEvents", containerVars), + () => classNames("Schedule", containerVars), [containerVars] ); @@ -124,22 +119,22 @@ export const Schedule: React.FC = ({ return (
    -
    -
    -

    My Daily Schedule

    - +
    +
    +

    My Daily Schedule

    + {personalEvents.length} events
    {roomCells}
    -
    -
    {hoursRow}
    +
    +
    {hoursRow}
    - {isToday &&
    } + {isToday &&
    } -
    +
    Date: Fri, 14 May 2021 00:40:36 +0300 Subject: [PATCH 36/72] Move no-events message to Schedule component --- .../molecules/Schedule/Schedule.scss | 4 ++ .../molecules/Schedule/Schedule.tsx | 56 +++++++++++-------- .../SchedulePageModal/SchedulePageModal.scss | 4 -- .../SchedulePageModal/SchedulePageModal.tsx | 18 ++---- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.scss b/src/components/molecules/Schedule/Schedule.scss index 0b0a8100df..315bc0e641 100644 --- a/src/components/molecules/Schedule/Schedule.scss +++ b/src/components/molecules/Schedule/Schedule.scss @@ -91,4 +91,8 @@ $schedule--width: calc(#{$hours-count} * #{$hour-width} + #{$half-hour-width}); left: calc(#{$current-time--position} * 1px); background-color: $primary; } + + &__no-events { + padding: $Schedule--padding; + } } diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 91bc2b896f..cb1aa6f93f 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -40,6 +40,8 @@ export const Schedule: React.FC = ({ scheduleDate, isToday, }) => { + const hasEvents = locatedEvents.length > 0; + const scheduleStartHour = useMemo( () => Math.min( @@ -119,30 +121,36 @@ export const Schedule: React.FC = ({ return (
    -
    -
    -

    My Daily Schedule

    - - {personalEvents.length} events - -
    - {roomCells} -
    - -
    -
    {hoursRow}
    - - {isToday &&
    } - -
    - -
    - {rowsWithTheEvents} -
    + {hasEvents ? ( + <> +
    +
    +

    My Daily Schedule

    + + {personalEvents.length} events + +
    + {roomCells} +
    + +
    +
    {hoursRow}
    + + {isToday &&
    } + +
    + +
    + {rowsWithTheEvents} +
    + + ) : ( +
    No events scheduled
    + )}
    ); }; diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss index 6dfb1d4e78..5ad4b7232f 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.scss @@ -58,8 +58,4 @@ $weekday--margin-right: 10px; opacity: 1; } } - - &__no-events { - padding: $SchedulePageModal--padding; - } } diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 0e7def2421..850db6ae50 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -135,19 +135,13 @@ export const SchedulePageModal: FC = ({ return (
    -
      {weekdays}
    - - {schedule.locatedEvents.length > 0 ? ( - - ) : ( -
    No events scheduled
    - )} +
    ); }; From 28b4cc25e369c09ac8ce1a6b2e3f4ee709068144 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 01:11:33 +0300 Subject: [PATCH 37/72] Refactor Schedule components --- .../molecules/Schedule/Schedule.tsx | 20 +++++------ .../molecules/Schedule/Schedule.utils.ts | 9 ++--- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 35 +++++++------------ .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 6 ++-- .../SchedulePageModal/SchedulePageModal.tsx | 4 +-- .../organisms/SchedulePageModal/utils.ts | 6 ++-- src/types/rooms.ts | 4 ++- src/types/venues.ts | 4 +-- 8 files changed, 38 insertions(+), 50 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index cb1aa6f93f..6632c3192b 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -18,18 +18,17 @@ import { import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; -import { WithVenueId } from "utils/id"; import { eventStartTime } from "utils/event"; -import { calcStartPosition } from "./Schedule.utils"; +import { ScheduleRoomEvents } from "components/molecules/ScheduleRoomEvents"; -import { ScheduleRoomEvents } from "../ScheduleRoomEvents"; +import { calcStartPosition } from "./Schedule.utils"; import "./Schedule.scss"; export interface ScheduleProps { locatedEvents: LocatedEvents[]; - personalEvents: WithVenueId[]; + personalEvents: PersonalizedVenueEvent[]; scheduleDate: Date; isToday: boolean; } @@ -70,7 +69,7 @@ export const Schedule: React.FC = ({ () => locatedEvents?.map(({ location, events }) => (

    @@ -102,16 +101,13 @@ export const Schedule: React.FC = ({ "--hour-width": `${SCHEDULE_HOUR_COLUMN_WIDTH_PX}px`, }); - const containerClasses = useMemo( - () => classNames("Schedule", containerVars), - [containerVars] - ); + const containerClasses = classNames("Schedule", containerVars); const rowsWithTheEvents = useMemo( () => locatedEvents.map(({ location, events }) => ( @@ -130,13 +126,14 @@ export const Schedule: React.FC = ({ {personalEvents.length} events

    + {roomCells}
    {hoursRow}
    - {isToday &&
    } + {isToday &&
    }
    = ({ scheduleStartHour={scheduleStartHour} />
    + {rowsWithTheEvents}
    diff --git a/src/components/molecules/Schedule/Schedule.utils.ts b/src/components/molecules/Schedule/Schedule.utils.ts index 807b6eba12..811ce2858a 100644 --- a/src/components/molecules/Schedule/Schedule.utils.ts +++ b/src/components/molecules/Schedule/Schedule.utils.ts @@ -6,11 +6,12 @@ export const calcStartPosition = ( startTimeUtcSeconds: number, scheduleStartHour: number ) => { - const startTimeTodaySeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + const startTimeSeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + const hoursToSkip = + startTimeSeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour; + const halfHourWidth = SCHEDULE_HOUR_COLUMN_WIDTH_PX / 2; return Math.floor( - SCHEDULE_HOUR_COLUMN_WIDTH_PX / 2 + - (startTimeTodaySeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour) * - SCHEDULE_HOUR_COLUMN_WIDTH_PX + halfHourWidth + hoursToSkip * SCHEDULE_HOUR_COLUMN_WIDTH_PX ); }; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index ebea44e63d..36d41cb19d 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -1,4 +1,4 @@ -import React, { MouseEventHandler, useCallback, useMemo } from "react"; +import React, { MouseEventHandler, useCallback } from "react"; import classNames from "classnames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -9,8 +9,6 @@ import { SCHEDULE_HOUR_COLUMN_WIDTH_PX } from "settings"; import { PersonalizedVenueEvent } from "types/venues"; -import { WithVenueId } from "utils/id"; -import { isTruthy } from "utils/types"; import { isEventLive } from "utils/event"; import { ONE_HOUR_IN_MINUTES } from "utils/time"; @@ -21,12 +19,12 @@ import { } from "api/profile"; import { useUser } from "hooks/useUser"; -import { calcStartPosition } from "../Schedule/Schedule.utils"; +import { calcStartPosition } from "components/molecules/Schedule/Schedule.utils"; import "./ScheduleEvent.scss"; export interface ScheduleEventProps { - event: WithVenueId; + event: PersonalizedVenueEvent; scheduleStartHour: number; isPersonalizedEvent?: boolean; } @@ -34,28 +32,21 @@ export interface ScheduleEventProps { export const ScheduleEvent: React.FC = ({ event, scheduleStartHour, - isPersonalizedEvent, + isPersonalizedEvent = false, }) => { const { userId } = useUser(); - const containerClasses = useMemo( - () => - classNames( - "ScheduleEvent", - { - "ScheduleEvent--live": isEventLive(event), - }, - { "ScheduleEvent--users": isTruthy(isPersonalizedEvent) } - ), - [event, isPersonalizedEvent] + const containerClasses = classNames( + "ScheduleEvent", + { + "ScheduleEvent--live": isEventLive(event), + }, + { "ScheduleEvent--users": isPersonalizedEvent } ); - const eventWidth = useMemo( - () => - (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / - ONE_HOUR_IN_MINUTES, - [event] - ); + const eventWidth = + (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / + ONE_HOUR_IN_MINUTES; const bookmarkEvent = useCallback(() => { if (!userId || !event.id) return; diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index 3a2952d763..999c61d43d 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -2,14 +2,12 @@ import React, { useMemo } from "react"; import { PersonalizedVenueEvent } from "types/venues"; -import { WithVenueId } from "utils/id"; - -import { ScheduleEvent } from "../ScheduleEvent"; +import { ScheduleEvent } from "components/molecules/ScheduleEvent"; import "./ScheduleRoomEvents.scss"; export interface ScheduleRoomEventsProps { - events: WithVenueId[]; + events: PersonalizedVenueEvent[]; scheduleStartHour: number; isPersonalizedRoom?: boolean; } diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 850db6ae50..592079f29a 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -27,8 +27,6 @@ import { LocatedEvents, } from "types/venues"; -import { WithVenueId } from "utils/id"; - import { Schedule } from "components/molecules/Schedule"; import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDescription"; @@ -50,7 +48,7 @@ export interface ScheduleDay { weekday: string; dayStartUtcSeconds: number; locatedEvents: LocatedEvents[]; - personalEvents: WithVenueId[]; + personalEvents: PersonalizedVenueEvent[]; } export const emptyPersonalizedSchedule = {}; diff --git a/src/components/organisms/SchedulePageModal/utils.ts b/src/components/organisms/SchedulePageModal/utils.ts index 54217c6ce1..0d33fe21ae 100644 --- a/src/components/organisms/SchedulePageModal/utils.ts +++ b/src/components/organisms/SchedulePageModal/utils.ts @@ -26,10 +26,10 @@ export const isEventLaterThisDay = (date: number | Date) => ( export const extendRoomsWithDaysEvents = ( rooms: Room[], - daysEvents: WithVenueId[] + daysEvents: PersonalizedVenueEvent[] ): RoomWithEvents[] => { return rooms.map((room) => { - const events: WithVenueId[] = daysEvents.filter( + const events: PersonalizedVenueEvent[] = daysEvents.filter( (event) => event?.room === room?.title ); return { ...room, events }; @@ -39,7 +39,7 @@ export const extendRoomsWithDaysEvents = ( export const prepareForSchedule = ( day: Date, usersEvents: MyPersonalizedSchedule -) => (event: WithVenueId): WithVenueId => { +) => (event: WithVenueId): PersonalizedVenueEvent => { const startOfEventToShow = max([eventStartTime(event), startOfDay(day)]); const endOfEventToShow = min([eventEndTime(event), endOfDay(day)]); diff --git a/src/types/rooms.ts b/src/types/rooms.ts index 75f8b3db3d..926c28a35a 100644 --- a/src/types/rooms.ts +++ b/src/types/rooms.ts @@ -1,7 +1,9 @@ import { SoundConfigReference } from "./sounds"; import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; + import { WithVenueId } from "utils/id"; + export enum RoomTypes { unclickable = "UNCLICKABLE", } @@ -46,5 +48,5 @@ export interface RoomData_v2 { } export type RoomWithEvents = Room & { - events: WithVenueId[]; + events: PersonalizedVenueEvent[]; }; diff --git a/src/types/venues.ts b/src/types/venues.ts index 8cc0368f1e..0f7d7811ae 100644 --- a/src/types/venues.ts +++ b/src/types/venues.ts @@ -321,10 +321,10 @@ export interface VenueLocation { export interface LocatedEvents { location: VenueLocation; - events: WithVenueId[]; + events: PersonalizedVenueEvent[]; } -export interface PersonalizedVenueEvent extends VenueEvent { +export interface PersonalizedVenueEvent extends WithVenueId { isSaved: boolean; } From f92a651bc30b9abecf965f21fadaa5b3455c676d Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 10:14:56 +0300 Subject: [PATCH 38/72] Keep event objects immutable --- src/components/molecules/ScheduleEvent/ScheduleEvent.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 36d41cb19d..6375668c76 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -51,10 +51,9 @@ export const ScheduleEvent: React.FC = ({ const bookmarkEvent = useCallback(() => { if (!userId || !event.id) return; - event.isSaved = !event.isSaved; event.isSaved - ? addEventToPersonalizedSchedule({ event, userId }) - : removeEventFromPersonalizedSchedule({ event, userId }); + ? removeEventFromPersonalizedSchedule({ event, userId }) + : addEventToPersonalizedSchedule({ event, userId }); }, [userId, event]); const onBookmark: MouseEventHandler = useCallback( From a04cf8f20c6703da519ad40002b3a827cef794eb Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 10:28:32 +0300 Subject: [PATCH 39/72] Replace inlined style object by useCss hook --- .../ScheduleEvent/ScheduleEvent.scss | 2 ++ .../molecules/ScheduleEvent/ScheduleEvent.tsx | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index f08bff0dc5..4b5e9e01d1 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -31,6 +31,8 @@ $description--margin-top: 2px; background-color: $grey--regular; box-shadow: $ScheduleEvent--box-shadow; margin-top: $ScheduleEvent--margin-top; + margin-left: var(--event--margin-left); + width: var(--event--width); &:hover { background-color: $grey--hover; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 6375668c76..c75ae0dd2c 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -1,5 +1,6 @@ import React, { MouseEventHandler, useCallback } from "react"; import classNames from "classnames"; +import { useCss } from "react-use"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBookmark as solidBookmark } from "@fortawesome/free-solid-svg-icons"; @@ -36,18 +37,27 @@ export const ScheduleEvent: React.FC = ({ }) => { const { userId } = useUser(); + const eventWidth = + (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / + ONE_HOUR_IN_MINUTES; + + const containerCssVars = useCss({ + "--event--margin-left": `${calcStartPosition( + event.start_utc_seconds, + scheduleStartHour + )}px`, + "--event--width": `${eventWidth}px`, + }); + const containerClasses = classNames( "ScheduleEvent", { "ScheduleEvent--live": isEventLive(event), }, - { "ScheduleEvent--users": isPersonalizedEvent } + { "ScheduleEvent--users": isPersonalizedEvent }, + containerCssVars ); - const eventWidth = - (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / - ONE_HOUR_IN_MINUTES; - const bookmarkEvent = useCallback(() => { if (!userId || !event.id) return; @@ -65,16 +75,7 @@ export const ScheduleEvent: React.FC = ({ ); return ( -
    +
    {event.name}
    by {event.host}
    From e926cc4dc30d47004d32f0718cefc4d5ae2d5c04 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 10:32:36 +0300 Subject: [PATCH 40/72] Merge bookmarkEvent functions --- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index c75ae0dd2c..c57289a573 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -58,20 +58,16 @@ export const ScheduleEvent: React.FC = ({ containerCssVars ); - const bookmarkEvent = useCallback(() => { - if (!userId || !event.id) return; - - event.isSaved - ? removeEventFromPersonalizedSchedule({ event, userId }) - : addEventToPersonalizedSchedule({ event, userId }); - }, [userId, event]); - - const onBookmark: MouseEventHandler = useCallback( + const bookmarkEvent: MouseEventHandler = useCallback( (e) => { e.stopPropagation(); - bookmarkEvent(); + if (!userId || !event.id) return; + + event.isSaved + ? removeEventFromPersonalizedSchedule({ event, userId }) + : addEventToPersonalizedSchedule({ event, userId }); }, - [bookmarkEvent] + [userId, event] ); return ( @@ -81,7 +77,7 @@ export const ScheduleEvent: React.FC = ({
    by {event.host}
    -
    +
    From f347b80591af26bab121b4fe09c75aaa16731294 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 10:39:29 +0300 Subject: [PATCH 41/72] Renamve ScheduleRoomEvents container class name --- .../molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss | 2 +- .../molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss index db4c9867be..6be7bfd3d4 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.scss @@ -1,6 +1,6 @@ @import "../Schedule/Schedule.constants.scss"; -.RoomEvents { +.ScheduleRoomEvents { height: $room--height; margin-bottom: $room--margin-bottom; } diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index 999c61d43d..ecdcfd24ac 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -30,5 +30,5 @@ export const ScheduleRoomEvents: React.FC = ({ [events, isPersonalizedRoom, scheduleStartHour] ); - return
    {eventBlocks}
    ; + return
    {eventBlocks}
    ; }; From 1b5374ae01d1701cc5bb11046467daa7dd154bfd Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 10:43:20 +0300 Subject: [PATCH 42/72] Remove the code that is related to extending room approach --- src/components/organisms/SchedulePageModal/utils.ts | 13 ------------- src/types/rooms.ts | 5 +---- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/components/organisms/SchedulePageModal/utils.ts b/src/components/organisms/SchedulePageModal/utils.ts index 0d33fe21ae..994c970c4d 100644 --- a/src/components/organisms/SchedulePageModal/utils.ts +++ b/src/components/organisms/SchedulePageModal/utils.ts @@ -8,7 +8,6 @@ import { startOfDay, } from "date-fns"; -import { Room, RoomWithEvents } from "types/rooms"; import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; import { MyPersonalizedSchedule } from "types/User"; @@ -24,18 +23,6 @@ export const isEventLaterThisDay = (date: number | Date) => ( end: eventEndTime(event), }); -export const extendRoomsWithDaysEvents = ( - rooms: Room[], - daysEvents: PersonalizedVenueEvent[] -): RoomWithEvents[] => { - return rooms.map((room) => { - const events: PersonalizedVenueEvent[] = daysEvents.filter( - (event) => event?.room === room?.title - ); - return { ...room, events }; - }); -}; - export const prepareForSchedule = ( day: Date, usersEvents: MyPersonalizedSchedule diff --git a/src/types/rooms.ts b/src/types/rooms.ts index 926c28a35a..79d132a4a7 100644 --- a/src/types/rooms.ts +++ b/src/types/rooms.ts @@ -1,8 +1,6 @@ import { SoundConfigReference } from "./sounds"; -import { PersonalizedVenueEvent, VenueEvent } from "types/venues"; - -import { WithVenueId } from "utils/id"; +import { PersonalizedVenueEvent } from "types/venues"; export enum RoomTypes { unclickable = "UNCLICKABLE", @@ -10,7 +8,6 @@ export enum RoomTypes { // @debt We should end up with 1 canonical room type export interface Room { - events?: Array>; type?: RoomTypes; zIndex?: number; title: string; From 2e96d5d6814d82592fe51522eca732f8711fa8fd Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 11:21:10 +0300 Subject: [PATCH 43/72] Refactor utils/time and utils/event --- .../EventPaymentButton/EventPaymentButton.tsx | 16 ++++++++------- src/pages/VenuePage/VenuePage.tsx | 5 +++-- src/utils/event.ts | 20 ++++++++++++------- src/utils/time.ts | 10 ++++------ 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx index e6cfc498a5..69d00d763e 100644 --- a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx +++ b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx @@ -1,16 +1,12 @@ import React from "react"; import "firebase/functions"; +import { Link } from "react-router-dom"; import { VenueEvent } from "types/venues"; -import "./EventPaymentButton.scss"; -import useConnectUserPurchaseHistory from "hooks/useConnectUserPurchaseHistory"; -import { Link } from "react-router-dom"; import { hasUserBoughtTicketForEvent } from "utils/hasUserBoughtTicket"; import { isUserAMember } from "utils/isUserAMember"; -import { canUserJoinTheEvent } from "utils/time"; -import { useUser } from "hooks/useUser"; -import { useSelector } from "hooks/useSelector"; +import { moreThanHourLeftBeforeEventStarts } from "utils/event"; import { WithId } from "utils/id"; import { venueEntranceUrl } from "utils/url"; import { @@ -18,6 +14,12 @@ import { userPurchaseHistorySelector, } from "utils/selectors"; +import { useUser } from "hooks/useUser"; +import { useSelector } from "hooks/useSelector"; +import useConnectUserPurchaseHistory from "hooks/useConnectUserPurchaseHistory"; + +import "./EventPaymentButton.scss"; + interface PropsType { event: WithId; venueId: string; @@ -57,7 +59,7 @@ const EventPaymentButton: React.FunctionComponent = ({ diff --git a/src/pages/VenuePage/VenuePage.tsx b/src/pages/VenuePage/VenuePage.tsx index e990bbeef7..e73f9842d9 100644 --- a/src/pages/VenuePage/VenuePage.tsx +++ b/src/pages/VenuePage/VenuePage.tsx @@ -15,7 +15,7 @@ import { isUserPurchaseHistoryRequestedSelector, userPurchaseHistorySelector, } from "utils/selectors"; -import { canUserJoinTheEvent, ONE_MINUTE_IN_SECONDS } from "utils/time"; +import { ONE_MINUTE_IN_SECONDS } from "utils/time"; import { clearLocationData, setLocationData, @@ -26,6 +26,7 @@ import { venueEntranceUrl } from "utils/url"; import { showZendeskWidget } from "utils/zendesk"; import { isCompleteProfile, updateProfileEnteredVenueIds } from "utils/profile"; import { isTruthy } from "utils/types"; +import { moreThanHourLeftBeforeEventStarts } from "utils/event"; import { useConnectCurrentEvent } from "hooks/useConnectCurrentEvent"; import { useConnectUserPurchaseHistory } from "hooks/useConnectUserPurchaseHistory"; @@ -212,7 +213,7 @@ const VenuePage: React.FC = () => { return <>Forbidden; } - if (!canUserJoinTheEvent(event)) { + if (!moreThanHourLeftBeforeEventStarts(event)) { return ( { const currentTimeInUTCSeconds = getCurrentTimeInUTCSeconds(); @@ -15,8 +20,8 @@ export const getCurrentEvent = (roomEvents: VenueEvent[]) => { }; export const isEventLive = (event: VenueEvent) => { - const start = fromUnixTime(event.start_utc_seconds); - const end = addMinutes(start, event.duration_minutes); + const start = eventStartTime(event); + const end = eventEndTime(event); return isWithinInterval(Date.now(), { start, end }); }; @@ -47,6 +52,7 @@ export const eventStartTime = (event: VenueEvent) => fromUnixTime(event.start_utc_seconds); export const eventEndTime = (event: VenueEvent) => - fromUnixTime( - event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS - ); + addMinutes(eventStartTime(event), event.duration_minutes); + +export const moreThanHourLeftBeforeEventStarts = (event: VenueEvent) => + differenceInHours(eventStartTime(event), Date.now()) > 0; diff --git a/src/utils/time.ts b/src/utils/time.ts index 015d5a9415..240614e2fc 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -8,8 +8,6 @@ import { startOfDay, } from "date-fns"; -import { VenueEvent } from "types/venues"; - export const ONE_SECOND_IN_MILLISECONDS = 1000; export const ONE_MINUTE_IN_SECONDS = 60; export const ONE_HOUR_IN_MINUTES = 60; @@ -74,7 +72,10 @@ const formatMeasurementInString = (value: number, measureUnit: string) => { export const getTimeBeforeParty = (startUtcSeconds?: number) => { if (startUtcSeconds === undefined) return "???"; - const secondsBeforeParty = startUtcSeconds - getUnixTime(Date.now()); + const secondsBeforeParty = differenceInSeconds( + fromUnixTime(startUtcSeconds), + Date.now() + ); if (secondsBeforeParty < 0) { return 0; @@ -108,9 +109,6 @@ export const getTimeBeforeParty = (startUtcSeconds?: number) => { return `${numberOfDaysInString} ${numberOfHoursInString} ${numberOfMinutesInString}`; }; -export const canUserJoinTheEvent = (event: VenueEvent) => - event.start_utc_seconds - getUnixTime(Date.now()) > ONE_HOUR_IN_SECONDS; - /** * Format UTC seconds as a string representing date. * From 3f5f7e701281da3c406bfc6fdc5bcf4aaf2a22e3 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 11:26:53 +0300 Subject: [PATCH 44/72] Put venueId as props to ScheduleVenueDescription --- .../ScheduleVenueDescription.tsx | 9 ++++++--- .../organisms/SchedulePageModal/SchedulePageModal.tsx | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index 115fea7534..63f28f29d3 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -1,13 +1,16 @@ import React, { FC, useMemo } from "react"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; -import { useVenueId } from "hooks/useVenueId"; import "./ScheduleVenueDescription.scss"; -export const ScheduleVenueDescription: FC = () => { - const venueId = useVenueId(); +export interface ScheduleVenueDescriptionProps { + venueId: string; +} +export const ScheduleVenueDescription: FC = ({ + venueId, +}) => { const { parentVenue, currentVenue } = useConnectRelatedVenues({ venueId, }); diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx index 592079f29a..0dfe0922f4 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx @@ -132,7 +132,7 @@ export const SchedulePageModal: FC = ({ return (
    - + {venueId && }
      {weekdays}
    Date: Fri, 14 May 2021 11:27:24 +0300 Subject: [PATCH 45/72] Refactor VenueEventDetails --- src/pages/Admin/VenueEventDetails.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/Admin/VenueEventDetails.tsx b/src/pages/Admin/VenueEventDetails.tsx index 089872eff9..14ac6c21ec 100644 --- a/src/pages/Admin/VenueEventDetails.tsx +++ b/src/pages/Admin/VenueEventDetails.tsx @@ -1,12 +1,13 @@ import React from "react"; -import { format, fromUnixTime } from "date-fns"; +import { format } from "date-fns"; import { VenueEvent } from "types/venues"; import { WithId } from "utils/id"; import { formatHourAndMinute, ONE_MINUTE_IN_SECONDS } from "utils/time"; +import { eventStartTime } from "utils/event"; -interface Props { +export interface VenueEventDetailsProps { venueEvent: WithId; setEditedEvent: Function | undefined; setShowCreateEventModal: Function; @@ -20,16 +21,13 @@ const VenueEventDetails = ({ setShowCreateEventModal, setShowDeleteEventModal, className, -}: Props) => { +}: VenueEventDetailsProps) => { const startTime = formatHourAndMinute(venueEvent.start_utc_seconds); const endTime = formatHourAndMinute( venueEvent.start_utc_seconds + ONE_MINUTE_IN_SECONDS * venueEvent.duration_minutes ); - const startDay = format( - fromUnixTime(venueEvent.start_utc_seconds), - "EEEE LLLL do" - ); + const startDay = format(eventStartTime(venueEvent), "EEEE LLLL do"); return (
    From e3803174b3455512104c73a78f74d8fba8962b1c Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 11:52:54 +0300 Subject: [PATCH 46/72] Remove RoomWithEvents type --- src/types/rooms.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/types/rooms.ts b/src/types/rooms.ts index 79d132a4a7..e1e82a1e33 100644 --- a/src/types/rooms.ts +++ b/src/types/rooms.ts @@ -1,7 +1,5 @@ import { SoundConfigReference } from "./sounds"; -import { PersonalizedVenueEvent } from "types/venues"; - export enum RoomTypes { unclickable = "UNCLICKABLE", } @@ -43,7 +41,3 @@ export interface RoomData_v2 { template?: string; roomIndex?: number; } - -export type RoomWithEvents = Room & { - events: PersonalizedVenueEvent[]; -}; From c43d2e62ac168a24b772c8660337e702281d062f Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 12:51:27 +0300 Subject: [PATCH 47/72] Use default venue image --- .../molecules/NavSearchBar/NavSearchBar.tsx | 4 ++-- .../ScheduleVenueDescription.scss | 1 + .../ScheduleVenueDescription.tsx | 20 +++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/components/molecules/NavSearchBar/NavSearchBar.tsx b/src/components/molecules/NavSearchBar/NavSearchBar.tsx index 427e06ed65..6e050d9052 100644 --- a/src/components/molecules/NavSearchBar/NavSearchBar.tsx +++ b/src/components/molecules/NavSearchBar/NavSearchBar.tsx @@ -3,7 +3,7 @@ import classNames from "classnames"; import { faSearch } from "@fortawesome/free-solid-svg-icons"; -import { DEFAULT_PARTY_NAME } from "settings"; +import { DEFAULT_PARTY_NAME, DEFAULT_VENUE_LOGO } from "settings"; import { VenueEvent } from "types/venues"; import { Room, RoomTypes } from "types/rooms"; @@ -115,7 +115,7 @@ const NavSearchBar = () => { description={`Event - ${uppercaseFirstChar( formatUtcSecondsRelativeToNow(event.start_utc_seconds) )}`} - image={imageUrl} + image={imageUrl ?? DEFAULT_VENUE_LOGO} /> ); }); diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss index c19f9cb49f..c0ed410df0 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.scss @@ -29,6 +29,7 @@ $name--margin-bottom: 5px; cursor: pointer; transition: all 400ms $transition-function; box-shadow: 0 8px 16px rgba($black, 0.3); + background-image: var(--venue-picture--background-image); &:hover { transform: scale(1.1); diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index 63f28f29d3..1532735925 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -1,4 +1,8 @@ import React, { FC, useMemo } from "react"; +import { useCss } from "react-use"; +import classNames from "classnames"; + +import { DEFAULT_VENUE_LOGO } from "settings"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; @@ -21,13 +25,21 @@ export const ScheduleVenueDescription: FC = ({ [parentVenue, currentVenue] ); + const venuePictureCssVars = useCss({ + "--venue-picture--background-image": `url(${ + scheduleVenue?.host?.icon ?? DEFAULT_VENUE_LOGO + })`, + }); + + const venuePictureClasses = classNames( + "ScheduleVenueDescription__pic", + venuePictureCssVars + ); + return (
    -
    +

    {scheduleVenue?.name} From 78137c7abb88cf26011ddff5462a8ae520d78df4 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 13:04:15 +0300 Subject: [PATCH 48/72] Rename SchedulePageModal -> NavBarSchedule --- src/components/molecules/NavBar/NavBar.tsx | 4 ++-- .../NavBarSchedule.scss} | 14 +++++++------- .../NavBarSchedule.tsx} | 18 ++++++++---------- .../utils.ts | 0 src/components/templates/ArtPiece/ArtPiece.tsx | 4 ++-- src/components/templates/Playa/Playa.tsx | 4 ++-- src/pages/Account/SplashPage.tsx | 4 ++-- 7 files changed, 23 insertions(+), 25 deletions(-) rename src/components/organisms/{SchedulePageModal/SchedulePageModal.scss => NavBarSchedule/NavBarSchedule.scss} (78%) rename src/components/organisms/{SchedulePageModal/SchedulePageModal.tsx => NavBarSchedule/NavBarSchedule.tsx} (88%) rename src/components/organisms/{SchedulePageModal => NavBarSchedule}/utils.ts (100%) diff --git a/src/components/molecules/NavBar/NavBar.tsx b/src/components/molecules/NavBar/NavBar.tsx index 8794aa7b37..ce3a1820f4 100644 --- a/src/components/molecules/NavBar/NavBar.tsx +++ b/src/components/molecules/NavBar/NavBar.tsx @@ -29,7 +29,7 @@ import { useFirestoreConnect } from "hooks/useFirestoreConnect"; import { GiftTicketModal } from "components/organisms/GiftTicketModal/GiftTicketModal"; import { ProfilePopoverContent } from "components/organisms/ProfileModal"; import { RadioModal } from "components/organisms/RadioModal/RadioModal"; -import { SchedulePageModal } from "components/organisms/SchedulePageModal/SchedulePageModal"; +import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; import NavSearchBar from "components/molecules/NavSearchBar"; import UpcomingTickets from "components/molecules/UpcomingTickets"; @@ -315,7 +315,7 @@ const NavBar: React.FC = ({ }`} onClick={hideEventSchedule} > - +

    {/* @debt Remove back button from Navbar */} diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss b/src/components/organisms/NavBarSchedule/NavBarSchedule.scss similarity index 78% rename from src/components/organisms/SchedulePageModal/SchedulePageModal.scss rename to src/components/organisms/NavBarSchedule/NavBarSchedule.scss index 5ad4b7232f..faf4818d4f 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.scss +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.scss @@ -1,29 +1,29 @@ @import "scss/constants.scss"; -$SchedulePageModal--height: 620px; -$SchedulePageModal--padding: 20px; +$NavBarSchedule--height: 620px; +$NavBarSchedule--padding: 20px; $weekday--padding: 8px 10px; $weekday--margin-right: 10px; -.SchedulePageModal { +.NavBarSchedule { @include scrollbar; position: fixed; z-index: z(navbar-schedule); top: 0; left: 0; width: 100%; - height: $SchedulePageModal--height; + height: $NavBarSchedule--height; padding-top: $navbar-height; - padding-left: $SchedulePageModal--padding; + padding-left: $NavBarSchedule--padding; background-color: rgba($black, 0.9); overflow: auto; pointer-events: none; opacity: 0; - transform: translateY(-#{$SchedulePageModal--height}); + transform: translateY(-#{$NavBarSchedule--height}); backdrop-filter: blur(5px); box-shadow: 0 20px 50px 0 rgba(0, 0, 0, 0.33); transition: all 400ms $transition-function; @@ -36,7 +36,7 @@ $weekday--margin-right: 10px; &__weekdays { display: flex; - padding-left: $SchedulePageModal--padding; + padding-left: $NavBarSchedule--padding; } &__weekday { diff --git a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx similarity index 88% rename from src/components/organisms/SchedulePageModal/SchedulePageModal.tsx rename to src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index 0dfe0922f4..2d813c13b6 100644 --- a/src/components/organisms/SchedulePageModal/SchedulePageModal.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -37,9 +37,9 @@ import { prepareForSchedule, } from "./utils"; -import "./SchedulePageModal.scss"; +import "./NavBarSchedule.scss"; -interface SchedulePageModalProps { +interface NavBarScheduleProps { isVisible?: boolean; } @@ -53,9 +53,7 @@ export interface ScheduleDay { export const emptyPersonalizedSchedule = {}; -export const SchedulePageModal: FC = ({ - isVisible, -}) => { +export const NavBarSchedule: FC = ({ isVisible }) => { const venueId = useVenueId(); const { userWithId } = useUser(); const userEventIds = @@ -73,8 +71,8 @@ export const SchedulePageModal: FC = ({ return range(0, SCHEDULE_SHOW_DAYS_AHEAD).map((dayIndex) => { const day = addDays(today, dayIndex); - const classes = classNames("SchedulePageModal__weekday", { - "SchedulePageModal__weekday--active": dayIndex === selectedDayIndex, + const classes = classNames("NavBarSchedule__weekday", { + "NavBarSchedule__weekday--active": dayIndex === selectedDayIndex, }); const onWeekdayClick: MouseEventHandler = (e) => { @@ -126,14 +124,14 @@ export const SchedulePageModal: FC = ({ }; }, [relatedVenueEvents, userEventIds, selectedDayIndex, getLocaion]); - const containerClasses = classNames("SchedulePageModal", { - "SchedulePageModal--show": isVisible, + const containerClasses = classNames("NavBarSchedule", { + "NavBarSchedule--show": isVisible, }); return (
    {venueId && } -
      {weekdays}
    +
      {weekdays}
    { dialogClassName="custom-dialog" > - + diff --git a/src/components/templates/Playa/Playa.tsx b/src/components/templates/Playa/Playa.tsx index 6189908fe1..5d2d3267db 100644 --- a/src/components/templates/Playa/Playa.tsx +++ b/src/components/templates/Playa/Playa.tsx @@ -54,7 +54,7 @@ import { useUser } from "hooks/useUser"; import { useFirestoreConnect } from "hooks/useFirestoreConnect"; import { DustStorm } from "components/organisms/DustStorm/DustStorm"; -import { SchedulePageModal } from "components/organisms/SchedulePageModal/SchedulePageModal"; +import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; import CreateEditPopUp from "components/molecules/CreateEditPopUp/CreateEditPopUp"; import { DonatePopUp } from "components/molecules/DonatePopUp/DonatePopUp"; @@ -1056,7 +1056,7 @@ const Playa = () => { dialogClassName="custom-dialog" > - + diff --git a/src/pages/Account/SplashPage.tsx b/src/pages/Account/SplashPage.tsx index 3a160e3fbe..64e8e4b0f1 100644 --- a/src/pages/Account/SplashPage.tsx +++ b/src/pages/Account/SplashPage.tsx @@ -7,7 +7,7 @@ import { venueInsideUrl } from "utils/url"; import { useUser } from "hooks/useUser"; import { useQuery } from "hooks/useQuery"; import { Modal } from "react-bootstrap"; -import { SchedulePageModal } from "components/organisms/SchedulePageModal/SchedulePageModal"; +import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; export interface ProfileFormData { partyName: string; @@ -66,7 +66,7 @@ const SplashPage = () => { dialogClassName="custom-dialog" > - + From d55f4a890d70697cc65f57345c7afcbf06034d5f Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 13:10:51 +0300 Subject: [PATCH 49/72] Move isEventLaterThisDay to utils/event --- .../organisms/NavBarSchedule/NavBarSchedule.tsx | 2 +- src/components/organisms/NavBarSchedule/utils.ts | 9 --------- src/utils/event.ts | 9 +++++++++ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index 2d813c13b6..55ea94781e 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -33,9 +33,9 @@ import { ScheduleVenueDescription } from "components/molecules/ScheduleVenueDesc import { buildLocationString, extractLocation, - isEventLaterThisDay, prepareForSchedule, } from "./utils"; +import { isEventLaterThisDay } from "utils/event"; import "./NavBarSchedule.scss"; diff --git a/src/components/organisms/NavBarSchedule/utils.ts b/src/components/organisms/NavBarSchedule/utils.ts index 994c970c4d..4b8bc68946 100644 --- a/src/components/organisms/NavBarSchedule/utils.ts +++ b/src/components/organisms/NavBarSchedule/utils.ts @@ -2,7 +2,6 @@ import { differenceInMinutes, endOfDay, getUnixTime, - isWithinInterval, max, min, startOfDay, @@ -15,14 +14,6 @@ import { WithVenueId } from "utils/id"; import { eventEndTime, eventStartTime } from "utils/event"; import { isTruthy } from "utils/types"; -export const isEventLaterThisDay = (date: number | Date) => ( - event: VenueEvent -) => - isWithinInterval(date, { - start: startOfDay(eventStartTime(event)), - end: eventEndTime(event), - }); - export const prepareForSchedule = ( day: Date, usersEvents: MyPersonalizedSchedule diff --git a/src/utils/event.ts b/src/utils/event.ts index a83898ead8..2ca49c5520 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -3,6 +3,7 @@ import { differenceInHours, fromUnixTime, isWithinInterval, + startOfDay, } from "date-fns"; import { VenueEvent } from "types/venues"; @@ -56,3 +57,11 @@ export const eventEndTime = (event: VenueEvent) => export const moreThanHourLeftBeforeEventStarts = (event: VenueEvent) => differenceInHours(eventStartTime(event), Date.now()) > 0; + +export const isEventLaterThisDay = (date: number | Date) => ( + event: VenueEvent +) => + isWithinInterval(date, { + start: startOfDay(eventStartTime(event)), + end: eventEndTime(event), + }); From a4704bef7c4b62e779ef2331555165f9aafe77d1 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Fri, 14 May 2021 13:25:55 +0300 Subject: [PATCH 50/72] Fix undefined room titles --- src/components/organisms/NavBarSchedule/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/organisms/NavBarSchedule/utils.ts b/src/components/organisms/NavBarSchedule/utils.ts index 4b8bc68946..0de6b9c7f6 100644 --- a/src/components/organisms/NavBarSchedule/utils.ts +++ b/src/components/organisms/NavBarSchedule/utils.ts @@ -32,7 +32,7 @@ export const prepareForSchedule = ( }; export const buildLocationString = (event: WithVenueId) => - `${event.venueId}#${event.room}`; + `${event.venueId}#${event.room ?? ""}`; export const extractLocation = (locationStr: string) => locationStr.split("#", 2); From d58d8064fc749ea46f015b5c9a1c5f960daee0dd Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 19:39:40 +0300 Subject: [PATCH 51/72] Close schedule modal only on click outside schedule area --- src/components/molecules/NavBar/NavBar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/NavBar/NavBar.tsx b/src/components/molecules/NavBar/NavBar.tsx index ce3a1820f4..101bc6a974 100644 --- a/src/components/molecules/NavBar/NavBar.tsx +++ b/src/components/molecules/NavBar/NavBar.tsx @@ -141,7 +141,9 @@ const NavBar: React.FC = ({ const toggleEventSchedule = useCallback(() => { setEventScheduleVisible(!isEventScheduleVisible); }, [isEventScheduleVisible]); - const hideEventSchedule = useCallback(() => { + const hideEventSchedule = useCallback((e) => { + if (e.target.closest(".NavBarSchedule")) return; + setEventScheduleVisible(false); }, []); From 84c633a2848faab78da90654662b3d1b8aba1942 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 20:58:51 +0300 Subject: [PATCH 52/72] Fixes in the Schedule --- .../molecules/Schedule/Schedule.tsx | 28 +++++++++++++------ .../ScheduleEvent/ScheduleEvent.scss | 2 +- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 8 +++--- .../ScheduleRoomEvents/ScheduleRoomEvents.tsx | 8 +++--- src/settings.ts | 4 ++- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 6632c3192b..0ff22224ce 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import classNames from "classnames"; import { eachHourOfInterval, @@ -11,15 +11,17 @@ import { import { useCss } from "react-use"; import { + SCHEDULE_CURRENT_TIMELINE_MS, SCHEDULE_HOUR_COLUMN_WIDTH_PX, SCHEDULE_MAX_START_HOUR, - SCHEDULE_NUMBER_OF_PERSONAL_ROOMS, } from "settings"; import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; import { eventStartTime } from "utils/event"; +import { useInterval } from "hooks/useInterval"; + import { ScheduleRoomEvents } from "components/molecules/ScheduleRoomEvents"; import { calcStartPosition } from "./Schedule.utils"; @@ -60,11 +62,6 @@ export const Schedule: React.FC = ({ [scheduleStartHour, scheduleDate] ); - const currentTimePosition = calcStartPosition( - Math.floor(getUnixTime(Date.now())), - scheduleStartHour - ); - const roomCells = useMemo( () => locatedEvents?.map(({ location, events }) => ( @@ -94,8 +91,21 @@ export const Schedule: React.FC = ({ [scheduleStartDateTime] ); + const calcCurrentTimePosition = useCallback( + () => calcStartPosition(getUnixTime(Date.now()), scheduleStartHour), + [scheduleStartHour] + ); + + const [currentTimePosition, setCurrentTimePosition] = useState( + calcCurrentTimePosition() + ); + + useInterval(() => { + setCurrentTimePosition(calcCurrentTimePosition()); + }, SCHEDULE_CURRENT_TIMELINE_MS); + const containerVars = useCss({ - "--room-count": locatedEvents.length + SCHEDULE_NUMBER_OF_PERSONAL_ROOMS, + "--room-count": locatedEvents.length + 1, // +1 is needed for the 1st personalized line of the schedule "--current-time--position": currentTimePosition, "--hours-count": hoursRow.length, "--hour-width": `${SCHEDULE_HOUR_COLUMN_WIDTH_PX}px`, @@ -137,7 +147,7 @@ export const Schedule: React.FC = ({
    diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index 4b5e9e01d1..d869021486 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -80,7 +80,7 @@ $description--margin-top: 2px; font-weight: bold; } - &__description { + &__host { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index c57289a573..a1374e44fa 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -27,13 +27,13 @@ import "./ScheduleEvent.scss"; export interface ScheduleEventProps { event: PersonalizedVenueEvent; scheduleStartHour: number; - isPersonalizedEvent?: boolean; + personalizedEvent?: boolean; } export const ScheduleEvent: React.FC = ({ event, scheduleStartHour, - isPersonalizedEvent = false, + personalizedEvent: isPersonaliezedEvent = false, }) => { const { userId } = useUser(); @@ -53,8 +53,8 @@ export const ScheduleEvent: React.FC = ({ "ScheduleEvent", { "ScheduleEvent--live": isEventLive(event), + "ScheduleEvent--users": isPersonaliezedEvent, }, - { "ScheduleEvent--users": isPersonalizedEvent }, containerCssVars ); @@ -74,7 +74,7 @@ export const ScheduleEvent: React.FC = ({
    {event.name}
    -
    by {event.host}
    +
    by {event.host}
    diff --git a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx index ecdcfd24ac..48bc57258b 100644 --- a/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx +++ b/src/components/molecules/ScheduleRoomEvents/ScheduleRoomEvents.tsx @@ -9,25 +9,25 @@ import "./ScheduleRoomEvents.scss"; export interface ScheduleRoomEventsProps { events: PersonalizedVenueEvent[]; scheduleStartHour: number; - isPersonalizedRoom?: boolean; + personalizedRoom?: boolean; } export const ScheduleRoomEvents: React.FC = ({ events, scheduleStartHour, - isPersonalizedRoom, + personalizedRoom, }) => { const eventBlocks = useMemo( () => events.map((event) => ( )), - [events, isPersonalizedRoom, scheduleStartHour] + [events, personalizedRoom, scheduleStartHour] ); return
    {eventBlocks}
    ; diff --git a/src/settings.ts b/src/settings.ts index 4e34326913..1848805782 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -92,6 +92,9 @@ export const LOCATION_INCREMENT_MS = LOCATION_INCREMENT_SECONDS * 1000; // How often to refresh daypart logic export const PLAYA_BG_DAYPART_MS = 60 * 1000; // 1 min +// How often to refresh current time line in the schedule +export const SCHEDULE_CURRENT_TIMELINE_MS = 60 * 1000; // 1 min + export const ROOM_IMAGE_WIDTH_PX = 300; export const MAX_IMAGE_FILE_SIZE_BYTES = 1024 * 2000; export const MAX_IMAGE_FILE_SIZE_TEXT = "2MB"; @@ -570,6 +573,5 @@ export const DEFAULT_DISPLAYED_POSTER_PREVIEW_COUNT = 12; // SCHEDULE // @debt probably would be better to adjust max hour based on user's display size export const SCHEDULE_MAX_START_HOUR = 16; -export const SCHEDULE_NUMBER_OF_PERSONAL_ROOMS = 1; export const SCHEDULE_HOUR_COLUMN_WIDTH_PX = 200; export const SCHEDULE_SHOW_DAYS_AHEAD = 7; From f6812cfaa6a054cfddecaa3b9eadaa9459f9f5bd Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 20:59:45 +0300 Subject: [PATCH 53/72] Introduce line-clamp @mixin --- .../molecules/OnlineStats/OnlineStats.scss | 12 ++---------- .../molecules/ScheduleEvent/ScheduleEvent.scss | 6 +----- .../molecules/VenueInfoEvents/VenueInfoEvents.scss | 6 +----- src/scss/constants.scss | 13 +++++++++++++ 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/components/molecules/OnlineStats/OnlineStats.scss b/src/components/molecules/OnlineStats/OnlineStats.scss index 8ca0915597..74ed9e375b 100644 --- a/src/components/molecules/OnlineStats/OnlineStats.scss +++ b/src/components/molecules/OnlineStats/OnlineStats.scss @@ -99,14 +99,10 @@ .venue-address { display: block; + @include line-clamp-with-overflow(3); font-size: 0.8rem; opacity: 0.8; margin-bottom: 4px; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; } .whatson-container { @@ -125,14 +121,10 @@ font-weight: 500; } .whatson-description-container-description { + @include line-clamp-with-overflow(2); font-size: 0.8rem; opacity: 0.8; margin-bottom: 4px; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; } .centered-flex { .btn { diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index d869021486..9a54cee386 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -71,12 +71,8 @@ $description--margin-top: 2px; } &__title { + @include line-clamp-with-overflow(2); white-space: pre-line; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; font-weight: bold; } diff --git a/src/components/molecules/VenueInfoEvents/VenueInfoEvents.scss b/src/components/molecules/VenueInfoEvents/VenueInfoEvents.scss index 7cbd4bad9d..4de88543fb 100644 --- a/src/components/molecules/VenueInfoEvents/VenueInfoEvents.scss +++ b/src/components/molecules/VenueInfoEvents/VenueInfoEvents.scss @@ -59,12 +59,8 @@ font-weight: 500; } .whatson-description-container-description { + @include line-clamp-with-overflow(2); font-size: 0.8rem; opacity: 0.8; margin-bottom: 4px; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; } diff --git a/src/scss/constants.scss b/src/scss/constants.scss index c654799df5..49c27f0339 100644 --- a/src/scss/constants.scss +++ b/src/scss/constants.scss @@ -192,3 +192,16 @@ $z-layers: ( background-color: rgba($white, 0.5); } } + +@mixin line-clamp($line-count: 1) { + display: -webkit-box; + -webkit-line-clamp: $line-count; + -webkit-box-orient: vertical; + line-clamp: $line-count; +} + +@mixin line-clamp-with-overflow($line-count: 1) { + @include line-clamp($line-count); + overflow: hidden; + text-overflow: ellipsis; +} From 749fd0a6fa7f0a96ff40eceeca4bdaf34e138d62 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 21:00:29 +0300 Subject: [PATCH 54/72] Rename moreThanHourLeftBeforeEventStarts -> isEventStartingSoon --- .../molecules/EventPaymentButton/EventPaymentButton.tsx | 4 ++-- src/pages/VenuePage/VenuePage.tsx | 4 ++-- src/utils/event.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx index 69d00d763e..63066fc393 100644 --- a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx +++ b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx @@ -6,7 +6,7 @@ import { VenueEvent } from "types/venues"; import { hasUserBoughtTicketForEvent } from "utils/hasUserBoughtTicket"; import { isUserAMember } from "utils/isUserAMember"; -import { moreThanHourLeftBeforeEventStarts } from "utils/event"; +import { isEventStartingSoon } from "utils/event"; import { WithId } from "utils/id"; import { venueEntranceUrl } from "utils/url"; import { @@ -59,7 +59,7 @@ const EventPaymentButton: React.FunctionComponent = ({ diff --git a/src/pages/VenuePage/VenuePage.tsx b/src/pages/VenuePage/VenuePage.tsx index e73f9842d9..3da727ebad 100644 --- a/src/pages/VenuePage/VenuePage.tsx +++ b/src/pages/VenuePage/VenuePage.tsx @@ -26,7 +26,7 @@ import { venueEntranceUrl } from "utils/url"; import { showZendeskWidget } from "utils/zendesk"; import { isCompleteProfile, updateProfileEnteredVenueIds } from "utils/profile"; import { isTruthy } from "utils/types"; -import { moreThanHourLeftBeforeEventStarts } from "utils/event"; +import { isEventStartingSoon } from "utils/event"; import { useConnectCurrentEvent } from "hooks/useConnectCurrentEvent"; import { useConnectUserPurchaseHistory } from "hooks/useConnectUserPurchaseHistory"; @@ -213,7 +213,7 @@ const VenuePage: React.FC = () => { return <>Forbidden; } - if (!moreThanHourLeftBeforeEventStarts(event)) { + if (!isEventStartingSoon(event)) { return ( export const eventEndTime = (event: VenueEvent) => addMinutes(eventStartTime(event), event.duration_minutes); -export const moreThanHourLeftBeforeEventStarts = (event: VenueEvent) => +export const isEventStartingSoon = (event: VenueEvent) => differenceInHours(eventStartTime(event), Date.now()) > 0; export const isEventLaterThisDay = (date: number | Date) => ( From 665b77b03c0d0cf316ef4813f7f2f6ddd4ffd785 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 22:02:33 +0300 Subject: [PATCH 55/72] Mark all utils/time constants as deprecated and add @dept comments to the places where they were used --- .../molecules/OnlineStats/OnlineStats.tsx | 1 + .../molecules/Schedule/Schedule.utils.ts | 1 + .../molecules/ScheduleEvent/ScheduleEvent.tsx | 1 + .../molecules/UserReactions/UserReactions.tsx | 6 +- .../organisms/DustStorm/DustStorm.tsx | 1 + .../components/RoomModal/RoomModal.tsx | 9 +-- src/pages/Admin/VenueEventDetails.tsx | 11 ++-- .../VenueLandingPage/VenueLandingPage.tsx | 62 ++++++++++--------- src/pages/VenuePage/VenuePage.tsx | 12 ++-- src/settings.ts | 1 + src/utils/time.ts | 27 +++++++- 11 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/components/molecules/OnlineStats/OnlineStats.tsx b/src/components/molecules/OnlineStats/OnlineStats.tsx index 10ac9062c4..d0aad8f5b9 100644 --- a/src/components/molecules/OnlineStats/OnlineStats.tsx +++ b/src/components/molecules/OnlineStats/OnlineStats.tsx @@ -78,6 +78,7 @@ const OnlineStats: React.FC = () => { const venueName = venue?.name; const { openUserProfileModal } = useProfileModalControls(); + // @debt FIVE_MINUTES_MS is deprecated; create needed constant in settings useInterval(() => { firebase .functions() diff --git a/src/components/molecules/Schedule/Schedule.utils.ts b/src/components/molecules/Schedule/Schedule.utils.ts index 811ce2858a..5c945b8b21 100644 --- a/src/components/molecules/Schedule/Schedule.utils.ts +++ b/src/components/molecules/Schedule/Schedule.utils.ts @@ -7,6 +7,7 @@ export const calcStartPosition = ( scheduleStartHour: number ) => { const startTimeSeconds = getSecondsFromStartOfDay(startTimeUtcSeconds); + // @debt ONE_HOUR_IN_SECONDS is deprecated; use utils/time or date-fns function instead const hoursToSkip = startTimeSeconds / ONE_HOUR_IN_SECONDS - scheduleStartHour; const halfHourWidth = SCHEDULE_HOUR_COLUMN_WIDTH_PX / 2; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index a1374e44fa..6b9d10b227 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -37,6 +37,7 @@ export const ScheduleEvent: React.FC = ({ }) => { const { userId } = useUser(); + // @debt ONE_HOUR_IN_MINUTES is deprectated; refactor to use utils/time or date-fns functions const eventWidth = (event.duration_minutes * SCHEDULE_HOUR_COLUMN_WIDTH_PX) / ONE_HOUR_IN_MINUTES; diff --git a/src/components/molecules/UserReactions/UserReactions.tsx b/src/components/molecules/UserReactions/UserReactions.tsx index 4a832c2eda..fd89ca5c39 100644 --- a/src/components/molecules/UserReactions/UserReactions.tsx +++ b/src/components/molecules/UserReactions/UserReactions.tsx @@ -1,6 +1,7 @@ import React, { useMemo } from "react"; import { useCss } from "react-use"; import classNames from "classnames"; +import { getSeconds } from "date-fns"; import { REACTION_TIMEOUT } from "settings"; @@ -11,16 +12,13 @@ import { } from "types/reactions"; import { uniqueEmojiReactionsDataMapReducer } from "utils/reactions"; -import { ONE_SECOND_IN_MILLISECONDS } from "utils/time"; import { useReactions } from "hooks/reactions"; import { useSelector } from "hooks/useSelector"; import "./UserReactions.scss"; -const REACTION_TIMEOUT_CSS = `${ - REACTION_TIMEOUT / ONE_SECOND_IN_MILLISECONDS -}s`; +const REACTION_TIMEOUT_CSS = `${getSeconds(REACTION_TIMEOUT)}s`; export interface UserReactionsProps { userId: string; diff --git a/src/components/organisms/DustStorm/DustStorm.tsx b/src/components/organisms/DustStorm/DustStorm.tsx index 9ee4f86cf6..f22fe8f550 100644 --- a/src/components/organisms/DustStorm/DustStorm.tsx +++ b/src/components/organisms/DustStorm/DustStorm.tsx @@ -58,6 +58,7 @@ export const DustStorm = () => { [] ); + // @debt FIVE_MINUTES_MS is deprecated; create needed constant in settings useInterval(() => { firebase .functions() diff --git a/src/components/templates/PartyMap/components/RoomModal/RoomModal.tsx b/src/components/templates/PartyMap/components/RoomModal/RoomModal.tsx index 123725f4c6..156ee335b0 100644 --- a/src/components/templates/PartyMap/components/RoomModal/RoomModal.tsx +++ b/src/components/templates/PartyMap/components/RoomModal/RoomModal.tsx @@ -1,12 +1,12 @@ import React, { useMemo } from "react"; import { Modal } from "react-bootstrap"; +import { isBefore } from "date-fns"; import { Room } from "types/rooms"; import { AnyVenue } from "types/venues"; -import { getCurrentEvent } from "utils/event"; +import { eventEndTime, getCurrentEvent } from "utils/event"; import { venueEventsSelector } from "utils/selectors"; -import { getCurrentTimeInUTCSeconds, ONE_MINUTE_IN_SECONDS } from "utils/time"; import { useCustomSound } from "hooks/sounds"; import { useSelector } from "hooks/useSelector"; @@ -61,10 +61,7 @@ export const RoomModalContent: React.FC = ({ return venueEvents.filter( (event) => - event.room === room.title && - event.start_utc_seconds + - event.duration_minutes * ONE_MINUTE_IN_SECONDS > - getCurrentTimeInUTCSeconds() + event.room === room.title && isBefore(Date.now(), eventEndTime(event)) ); }, [room, venueEvents]); diff --git a/src/pages/Admin/VenueEventDetails.tsx b/src/pages/Admin/VenueEventDetails.tsx index 14ac6c21ec..05579f3645 100644 --- a/src/pages/Admin/VenueEventDetails.tsx +++ b/src/pages/Admin/VenueEventDetails.tsx @@ -1,11 +1,11 @@ import React from "react"; -import { format } from "date-fns"; +import { format, getUnixTime } from "date-fns"; import { VenueEvent } from "types/venues"; import { WithId } from "utils/id"; -import { formatHourAndMinute, ONE_MINUTE_IN_SECONDS } from "utils/time"; -import { eventStartTime } from "utils/event"; +import { formatHourAndMinute } from "utils/time"; +import { eventEndTime, eventStartTime } from "utils/event"; export interface VenueEventDetailsProps { venueEvent: WithId; @@ -23,10 +23,7 @@ const VenueEventDetails = ({ className, }: VenueEventDetailsProps) => { const startTime = formatHourAndMinute(venueEvent.start_utc_seconds); - const endTime = formatHourAndMinute( - venueEvent.start_utc_seconds + - ONE_MINUTE_IN_SECONDS * venueEvent.duration_minutes - ); + const endTime = formatHourAndMinute(getUnixTime(eventEndTime(venueEvent))); const startDay = format(eventStartTime(venueEvent), "EEEE LLLL do"); return ( diff --git a/src/pages/VenueLandingPage/VenueLandingPage.tsx b/src/pages/VenueLandingPage/VenueLandingPage.tsx index dd374e9406..26b9488461 100644 --- a/src/pages/VenueLandingPage/VenueLandingPage.tsx +++ b/src/pages/VenueLandingPage/VenueLandingPage.tsx @@ -1,44 +1,50 @@ +import React, { useEffect, useState } from "react"; import { faCheckCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { VenueEvent } from "types/venues"; - -import CountDown from "components/molecules/CountDown"; -import EventPaymentButton from "components/molecules/EventPaymentButton"; -import InformationCard from "components/molecules/InformationCard"; -import SecretPasswordForm from "components/molecules/SecretPasswordForm"; -import AuthenticationModal from "components/organisms/AuthenticationModal"; -import PaymentModal from "components/organisms/PaymentModal"; -import WithNavigationBar from "components/organisms/WithNavigationBar"; import dayjs from "dayjs"; import advancedFormat from "dayjs/plugin/advancedFormat"; -import useConnectCurrentVenue from "hooks/useConnectCurrentVenue"; -import { useSelector } from "hooks/useSelector"; -import { useUser } from "hooks/useUser"; -import { updateTheme } from "pages/VenuePage/helpers"; -import React, { useEffect, useState } from "react"; -import { useFirestoreConnect } from "hooks/useFirestoreConnect"; -import { useVenueId } from "hooks/useVenueId"; +import { isAfter } from "date-fns"; +import { + DEFAULT_VENUE_BANNER, + DEFAULT_VENUE_LOGO, + IFRAME_ALLOW, +} from "settings"; + +import { VenueEvent } from "types/venues"; import { Firestore } from "types/Firestore"; +import { VenueAccessMode } from "types/VenueAcccess"; + import { hasUserBoughtTicketForEvent } from "utils/hasUserBoughtTicket"; import { WithId } from "utils/id"; import { isUserAMember } from "utils/isUserAMember"; -import { getTimeBeforeParty, ONE_MINUTE_IN_SECONDS } from "utils/time"; -import "./VenueLandingPage.scss"; +import { getTimeBeforeParty } from "utils/time"; import { venueEntranceUrl, venueInsideUrl } from "utils/url"; import { currentVenueSelectorData, userPurchaseHistorySelector, } from "utils/selectors"; -import { - DEFAULT_VENUE_BANNER, - DEFAULT_VENUE_LOGO, - IFRAME_ALLOW, -} from "settings"; -import { AuthOptions } from "components/organisms/AuthenticationModal/AuthenticationModal"; +import { eventEndTime } from "utils/event"; import { showZendeskWidget } from "utils/zendesk"; -import { VenueAccessMode } from "types/VenueAcccess"; + +import useConnectCurrentVenue from "hooks/useConnectCurrentVenue"; +import { useSelector } from "hooks/useSelector"; +import { useUser } from "hooks/useUser"; +import { useFirestoreConnect } from "hooks/useFirestoreConnect"; +import { useVenueId } from "hooks/useVenueId"; + +import { updateTheme } from "pages/VenuePage/helpers"; + +import AuthenticationModal from "components/organisms/AuthenticationModal"; +import PaymentModal from "components/organisms/PaymentModal"; +import WithNavigationBar from "components/organisms/WithNavigationBar"; +import { AuthOptions } from "components/organisms/AuthenticationModal/AuthenticationModal"; +import CountDown from "components/molecules/CountDown"; +import EventPaymentButton from "components/molecules/EventPaymentButton"; +import InformationCard from "components/molecules/InformationCard"; +import SecretPasswordForm from "components/molecules/SecretPasswordForm"; + +import "./VenueLandingPage.scss"; export interface VenueLandingPageProps { venue: Firestore["data"]["currentVenue"]; @@ -96,9 +102,7 @@ export const VenueLandingPage: React.FunctionComponent = const { user } = useUser(); const futureOrOngoingVenueEvents = venueEvents?.filter( - (event) => - event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS > - new Date().getTime() / 1000 && event.price > 0 + (event) => isAfter(eventEndTime(event), Date.now()) && event.price > 0 ); venue && updateTheme(venue); diff --git a/src/pages/VenuePage/VenuePage.tsx b/src/pages/VenuePage/VenuePage.tsx index 3da727ebad..01f5afaa23 100644 --- a/src/pages/VenuePage/VenuePage.tsx +++ b/src/pages/VenuePage/VenuePage.tsx @@ -1,5 +1,6 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect } from "react"; import { Redirect, useHistory } from "react-router-dom"; +import { isBefore } from "date-fns"; import { LOC_UPDATE_FREQ_MS } from "settings"; @@ -15,7 +16,6 @@ import { isUserPurchaseHistoryRequestedSelector, userPurchaseHistorySelector, } from "utils/selectors"; -import { ONE_MINUTE_IN_SECONDS } from "utils/time"; import { clearLocationData, setLocationData, @@ -26,7 +26,7 @@ import { venueEntranceUrl } from "utils/url"; import { showZendeskWidget } from "utils/zendesk"; import { isCompleteProfile, updateProfileEnteredVenueIds } from "utils/profile"; import { isTruthy } from "utils/types"; -import { isEventStartingSoon } from "utils/event"; +import { eventEndTime, isEventStartingSoon } from "utils/event"; import { useConnectCurrentEvent } from "hooks/useConnectCurrentEvent"; import { useConnectUserPurchaseHistory } from "hooks/useConnectUserPurchaseHistory"; @@ -60,7 +60,6 @@ const VenuePage: React.FC = () => { const mixpanel = useMixpanel(); const history = useHistory(); - const [currentTimestamp] = useState(Date.now() / 1000); // const [isAccessDenied, setIsAccessDenied] = useState(false); const { user, profile } = useUser(); @@ -88,10 +87,7 @@ const VenuePage: React.FC = () => { const hasUserBoughtTicket = event && hasUserBoughtTicketForEvent(userPurchaseHistory, event.id); - const isEventFinished = - event && - currentTimestamp > - event.start_utc_seconds + event.duration_minutes * ONE_MINUTE_IN_SECONDS; + const isEventFinished = event && isBefore(eventEndTime(event), Date.now()); const isUserVenueOwner = userId && venue?.owners?.includes(userId); const isMember = diff --git a/src/settings.ts b/src/settings.ts index 1848805782..ed92e8a79e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -82,6 +82,7 @@ export const DUST_STORM_TEXT_2 = // How often to refresh events schedule export const REFETCH_SCHEDULE_MS = 10 * 60 * 1000; // 10 mins +// @debt FIVE_MINUTES_MS is deprecated; use utils/time or date-fns functions instead // How often to update location for counting export const LOC_UPDATE_FREQ_MS = FIVE_MINUTES_MS; diff --git a/src/utils/time.ts b/src/utils/time.ts index 240614e2fc..8de560dcd4 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -8,17 +8,41 @@ import { startOfDay, } from "date-fns"; +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_SECOND_IN_MILLISECONDS = 1000; +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_MINUTE_IN_SECONDS = 60; +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_HOUR_IN_MINUTES = 60; +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_HOUR_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 60; +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_DAY_IN_SECONDS = ONE_HOUR_IN_SECONDS * 24; +/** + * @deprecated in favor of using date-fns functions + */ export const FIVE_MINUTES_MS = 5 * ONE_MINUTE_IN_SECONDS * ONE_SECOND_IN_MILLISECONDS; + +/** + * @deprecated in favor of using date-fns functions + */ export const ONE_HOUR_IN_MILLISECONDS = ONE_SECOND_IN_MILLISECONDS * ONE_HOUR_IN_SECONDS; - +/** + * @deprecated in favor of using date-fns functions + */ export const SECONDS_TIMESTAMP_MAX_VALUE = 9999999999; /** @@ -197,6 +221,7 @@ export const formatUtcSecondsRelativeToNow = (utcSeconds: number) => { return formatRelative(fromUnixTime(utcSeconds), Date.now()); }; +// @debt get rid of ONE_SECOND_IN_MILLISECONDS and use date-fns function export const normalizeTimestampToMilliseconds = (timestamp: number) => { const isTimestampInMilliSeconds = timestamp > SECONDS_TIMESTAMP_MAX_VALUE; From 0b6bf111b31f1e972b1bfda52fc0c80e89d7f36d Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 22:15:08 +0300 Subject: [PATCH 56/72] Add default venue name constant to settings --- .../ScheduleVenueDescription/ScheduleVenueDescription.tsx | 4 ++-- src/settings.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index 1532735925..ca6ab69f82 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -2,7 +2,7 @@ import React, { FC, useMemo } from "react"; import { useCss } from "react-use"; import classNames from "classnames"; -import { DEFAULT_VENUE_LOGO } from "settings"; +import { DEFAULT_VENUE_LOGO, DEFAULT_VENUE_NAME } from "settings"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; @@ -42,7 +42,7 @@ export const ScheduleVenueDescription: FC = ({

    - {scheduleVenue?.name} + {scheduleVenue?.name ?? DEFAULT_VENUE_NAME}

    {scheduleVenue?.config?.landingPageConfig?.subtitle} diff --git a/src/settings.ts b/src/settings.ts index ed92e8a79e..4c8e7962d8 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -43,6 +43,7 @@ export const SPARKLE_ICON = "/sparkle-icon.png"; export const DEFAULT_MAP_BACKGROUND = "/maps/Sparkle_Field_Background.jpg"; export const DEFAULT_VENUE_BANNER = "/assets/Sparkle_Banner_Default.jpg"; export const DEFAULT_VENUE_LOGO = "/assets/Sparkle_SquareLogo_Default.jpg"; +export const DEFAULT_VENUE_NAME = "Sparkle"; // @debt de-duplicate DEFAULT_PROFILE_IMAGE, DEFAULT_AVATAR_IMAGE, DEFAULT_PROFILE_PIC. Are they all used for the same concept? export const DEFAULT_PROFILE_IMAGE = "/anonymous-profile-icon.jpeg"; export const DEFAULT_AVATAR_IMAGE = sparkleNavLogo; From 81778da4a0078c447351d7fdabae1ee2096508e5 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 22:21:14 +0300 Subject: [PATCH 57/72] Remove stopPropagation events in clickable Schedule areas --- .../molecules/ScheduleEvent/ScheduleEvent.tsx | 18 +++++++----------- .../NavBarSchedule/NavBarSchedule.tsx | 3 +-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 6b9d10b227..5b23af7cd6 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -59,17 +59,13 @@ export const ScheduleEvent: React.FC = ({ containerCssVars ); - const bookmarkEvent: MouseEventHandler = useCallback( - (e) => { - e.stopPropagation(); - if (!userId || !event.id) return; - - event.isSaved - ? removeEventFromPersonalizedSchedule({ event, userId }) - : addEventToPersonalizedSchedule({ event, userId }); - }, - [userId, event] - ); + const bookmarkEvent: MouseEventHandler = useCallback(() => { + if (!userId || !event.id) return; + + event.isSaved + ? removeEventFromPersonalizedSchedule({ event, userId }) + : addEventToPersonalizedSchedule({ event, userId }); + }, [userId, event]); return (
    diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index 55ea94781e..b38b9b6252 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -75,8 +75,7 @@ export const NavBarSchedule: FC = ({ isVisible }) => { "NavBarSchedule__weekday--active": dayIndex === selectedDayIndex, }); - const onWeekdayClick: MouseEventHandler = (e) => { - e.stopPropagation(); + const onWeekdayClick: MouseEventHandler = () => { setSelectedDayIndex(dayIndex); }; From 8b3d9276bd1f4310e0163db00adbe61602133e32 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Mon, 17 May 2021 23:44:02 +0300 Subject: [PATCH 58/72] Refactor getTimeBeforeParty --- .../molecules/Schedule/Schedule.tsx | 5 +- src/pages/Admin/VenueEventDetails.tsx | 6 +- src/utils/formatMeasurement.ts | 7 +++ src/utils/time.ts | 56 ++++--------------- 4 files changed, 28 insertions(+), 46 deletions(-) create mode 100644 src/utils/formatMeasurement.ts diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 0ff22224ce..ebd9eeb7af 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -19,6 +19,7 @@ import { import { PersonalizedVenueEvent, LocatedEvents } from "types/venues"; import { eventStartTime } from "utils/event"; +import { formatMeasurement } from "utils/formatMeasurement"; import { useInterval } from "hooks/useInterval"; @@ -72,7 +73,9 @@ export const Schedule: React.FC = ({

    {location.roomTitle || location.venueTitle || location.venueId}

    - {events.length} events + + {formatMeasurement(events.length, "event")} +
    )), [locatedEvents] diff --git a/src/pages/Admin/VenueEventDetails.tsx b/src/pages/Admin/VenueEventDetails.tsx index 05579f3645..aa717fbd0e 100644 --- a/src/pages/Admin/VenueEventDetails.tsx +++ b/src/pages/Admin/VenueEventDetails.tsx @@ -4,7 +4,7 @@ import { format, getUnixTime } from "date-fns"; import { VenueEvent } from "types/venues"; import { WithId } from "utils/id"; -import { formatHourAndMinute } from "utils/time"; +import { formatHourAndMinute, getTimeBeforeParty } from "utils/time"; import { eventEndTime, eventStartTime } from "utils/event"; export interface VenueEventDetailsProps { @@ -25,6 +25,7 @@ const VenueEventDetails = ({ const startTime = formatHourAndMinute(venueEvent.start_utc_seconds); const endTime = formatHourAndMinute(getUnixTime(eventEndTime(venueEvent))); const startDay = format(eventStartTime(venueEvent), "EEEE LLLL do"); + console.log("here"); return (
    @@ -42,6 +43,9 @@ const VenueEventDetails = ({
    {venueEvent.description} +
    + {getTimeBeforeParty(venueEvent.start_utc_seconds)} + {venueEvent.descriptions?.map((description, index) => (

    {description}

    ))} diff --git a/src/utils/formatMeasurement.ts b/src/utils/formatMeasurement.ts new file mode 100644 index 0000000000..efa53d2586 --- /dev/null +++ b/src/utils/formatMeasurement.ts @@ -0,0 +1,7 @@ +export const formatMeasurement = (value: number, measureUnit: string) => { + const baseFormatted = `${value} ${measureUnit}`; + + if (value === 0) return ""; + if (value === 1) return baseFormatted; + if (value > 1) return `${baseFormatted}s`; +}; diff --git a/src/utils/time.ts b/src/utils/time.ts index 8de560dcd4..712776127a 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -5,6 +5,8 @@ import { formatRelative, fromUnixTime, getUnixTime, + intervalToDuration, + isBefore, startOfDay, } from "date-fns"; @@ -84,53 +86,19 @@ export const secondsToDuration = (totalSeconds: number): Duration => { export const formatSecondsAsDuration = (seconds: number): string => formatDuration(secondsToDuration(seconds)); -const formatMeasurementInString = (value: number, measureUnit: string) => { - const baseFormatted = `${value} ${measureUnit}`; +export const getTimeBeforeParty = (startUtcSeconds: number) => { + const eventStartDate = fromUnixTime(startUtcSeconds); + const now = Date.now(); - if (value === 0) return ""; - if (value === 1) return baseFormatted; - if (value > 1) return `${baseFormatted}s`; -}; - -// @debt quality test this -export const getTimeBeforeParty = (startUtcSeconds?: number) => { - if (startUtcSeconds === undefined) return "???"; - - const secondsBeforeParty = differenceInSeconds( - fromUnixTime(startUtcSeconds), - Date.now() - ); - - if (secondsBeforeParty < 0) { - return 0; - } - - const numberOfCompleteDaysBeforeParty = Math.floor( - secondsBeforeParty / ONE_DAY_IN_SECONDS - ); + if (isBefore(eventStartDate, now)) return 0; - const numberOfCompleteHours = Math.floor( - (secondsBeforeParty % ONE_DAY_IN_SECONDS) / ONE_HOUR_IN_SECONDS + return formatDuration( + intervalToDuration({ + start: Date.now(), + end: eventStartDate, + }), + { format: ["days", "hours", "minutes"] } ); - - const numberOfMinutes = Math.floor( - (secondsBeforeParty % ONE_HOUR_IN_SECONDS) / ONE_MINUTE_IN_SECONDS - ); - - const numberOfDaysInString = formatMeasurementInString( - numberOfCompleteDaysBeforeParty, - "day" - ); - const numberOfHoursInString = formatMeasurementInString( - numberOfCompleteHours, - "hour" - ); - const numberOfMinutesInString = formatMeasurementInString( - numberOfMinutes, - "minute" - ); - - return `${numberOfDaysInString} ${numberOfHoursInString} ${numberOfMinutesInString}`; }; /** From 799902a40ba07362f18780b48b286cb984dadd28 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 00:03:55 +0300 Subject: [PATCH 59/72] Refactor isEventWithinDate() --- .../NavBarSchedule/NavBarSchedule.tsx | 6 ++-- src/utils/event.ts | 29 ++++++++++++------- src/utils/time.ts | 4 ++- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index b38b9b6252..e19578d655 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -35,7 +35,7 @@ import { extractLocation, prepareForSchedule, } from "./utils"; -import { isEventLaterThisDay } from "utils/event"; +import { isEventWithinDate } from "utils/event"; import "./NavBarSchedule.scss"; @@ -104,9 +104,7 @@ export const NavBarSchedule: FC = ({ isVisible }) => { const schedule: ScheduleDay = useMemo(() => { const dayStart = addDays(startOfToday(), selectedDayIndex); const daysEvents = relatedVenueEvents - .filter( - isEventLaterThisDay(selectedDayIndex === 0 ? Date.now() : dayStart) - ) + .filter(isEventWithinDate(selectedDayIndex === 0 ? Date.now() : dayStart)) .map(prepareForSchedule(dayStart, userEventIds)); const locatedEvents: LocatedEvents[] = chain(daysEvents) diff --git a/src/utils/event.ts b/src/utils/event.ts index 1facc5b547..d84a3a4264 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -1,6 +1,8 @@ import { addMinutes, + areIntervalsOverlapping, differenceInHours, + endOfDay, fromUnixTime, isWithinInterval, startOfDay, @@ -21,10 +23,7 @@ export const getCurrentEvent = (roomEvents: VenueEvent[]) => { }; export const isEventLive = (event: VenueEvent) => { - const start = eventStartTime(event); - const end = eventEndTime(event); - - return isWithinInterval(Date.now(), { start, end }); + return isWithinInterval(Date.now(), getEventInterval(event)); }; export const isEventLiveOrFuture = (event: VenueEvent) => { @@ -58,10 +57,20 @@ export const eventEndTime = (event: VenueEvent) => export const isEventStartingSoon = (event: VenueEvent) => differenceInHours(eventStartTime(event), Date.now()) > 0; -export const isEventLaterThisDay = (date: number | Date) => ( +export const getEventInterval = (event: VenueEvent) => ({ + start: eventStartTime(event), + end: eventEndTime(event), +}); + +export const isEventWithinDate = (checkDate: number | Date) => ( event: VenueEvent -) => - isWithinInterval(date, { - start: startOfDay(eventStartTime(event)), - end: eventEndTime(event), - }); +) => { + const checkDateInterval = { + start: startOfDay(checkDate), + end: endOfDay(checkDate), + }; + + const eventInterval = getEventInterval(event); + + return areIntervalsOverlapping(checkDateInterval, eventInterval); +}; diff --git a/src/utils/time.ts b/src/utils/time.ts index 712776127a..74f7b955d1 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -86,7 +86,9 @@ export const secondsToDuration = (totalSeconds: number): Duration => { export const formatSecondsAsDuration = (seconds: number): string => formatDuration(secondsToDuration(seconds)); -export const getTimeBeforeParty = (startUtcSeconds: number) => { +export const getTimeBeforeParty = (startUtcSeconds?: number) => { + if (startUtcSeconds === undefined) return "???"; + const eventStartDate = fromUnixTime(startUtcSeconds); const now = Date.now(); From 6d26a6f4f896aa3cc48d0eafadb84c9807e4c24d Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 00:17:41 +0300 Subject: [PATCH 60/72] Remove weekday property from ScheduleDay --- src/components/organisms/NavBarSchedule/NavBarSchedule.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index e19578d655..f600a114a0 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -45,7 +45,6 @@ interface NavBarScheduleProps { export interface ScheduleDay { isToday: boolean; - weekday: string; dayStartUtcSeconds: number; locatedEvents: LocatedEvents[]; personalEvents: PersonalizedVenueEvent[]; @@ -115,7 +114,6 @@ export const NavBarSchedule: FC = ({ isVisible }) => { return { locatedEvents, isToday: selectedDayIndex === 0, - weekday: format(dayStart, "E"), dayStartUtcSeconds: getUnixTime(dayStart), personalEvents: daysEvents.filter((event) => event.isSaved), }; From 03d78303b9d16dfcdfde3ed631a87b04eec082ea Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:25:13 +0300 Subject: [PATCH 61/72] Add a few comments --- src/components/molecules/Schedule/Schedule.tsx | 2 ++ src/scss/constants.scss | 1 + 2 files changed, 3 insertions(+) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index ebd9eeb7af..fcda168ecd 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -63,6 +63,7 @@ export const Schedule: React.FC = ({ [scheduleStartHour, scheduleDate] ); + // pairs (venueId, roomTitle) are unique because they are grouped earlier (see NavBarSchedule#schedule) const roomCells = useMemo( () => locatedEvents?.map(({ location, events }) => ( @@ -116,6 +117,7 @@ export const Schedule: React.FC = ({ const containerClasses = classNames("Schedule", containerVars); + // pairs (venueId, roomTitle) are unique because they are grouped earlier (see NavBarSchedule#schedule) const rowsWithTheEvents = useMemo( () => locatedEvents.map(({ location, events }) => ( diff --git a/src/scss/constants.scss b/src/scss/constants.scss index 49c27f0339..01e4d0f10a 100644 --- a/src/scss/constants.scss +++ b/src/scss/constants.scss @@ -193,6 +193,7 @@ $z-layers: ( } } +// @debt replace this with `line-clamp` property once it's supported in autoprefixer; see https://github.com/postcss/autoprefixer/issues/1322 @mixin line-clamp($line-count: 1) { display: -webkit-box; -webkit-line-clamp: $line-count; From 367c7e8b948dc58e9e7ffa10620e0010075640dc Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:32:07 +0300 Subject: [PATCH 62/72] Leave NavBarSchedule in NavBar only --- .../organisms/AppRouter/AppRouter.jsx | 2 +- .../templates/ArtPiece/ArtPiece.tsx | 42 +++++++------------ src/components/templates/ArtPiece/index.ts | 5 --- src/components/templates/Playa/Playa.tsx | 12 ------ src/pages/Account/SplashPage.tsx | 42 ++++--------------- 5 files changed, 24 insertions(+), 79 deletions(-) diff --git a/src/components/organisms/AppRouter/AppRouter.jsx b/src/components/organisms/AppRouter/AppRouter.jsx index 858ce8cd4f..63cc72ecde 100644 --- a/src/components/organisms/AppRouter/AppRouter.jsx +++ b/src/components/organisms/AppRouter/AppRouter.jsx @@ -6,7 +6,7 @@ import { Redirect, } from "react-router-dom"; -import SplashPage from "pages/Account/SplashPage"; +import { SplashPage } from "pages/Account/SplashPage"; import Step1 from "pages/Account/Step1"; import Step2 from "pages/Account/Step2"; import Step3 from "pages/Account/Step3"; diff --git a/src/components/templates/ArtPiece/ArtPiece.tsx b/src/components/templates/ArtPiece/ArtPiece.tsx index ba54446e02..fafef0ed71 100644 --- a/src/components/templates/ArtPiece/ArtPiece.tsx +++ b/src/components/templates/ArtPiece/ArtPiece.tsx @@ -1,23 +1,25 @@ -import React, { useState } from "react"; -import "./ArtPiece.scss"; -import { InformationLeftColumn } from "components/organisms/InformationLeftColumn"; +import React from "react"; + +import { IFRAME_ALLOW } from "settings"; + +import { VideoAspectRatio } from "types/VideoAspectRatio"; + +import { ConvertToEmbeddableUrl } from "utils/ConvertToEmbeddableUrl"; +import { currentVenueSelectorData } from "utils/selectors"; + import { useSelector } from "hooks/useSelector"; -import InformationCard from "components/molecules/InformationCard"; -import WithNavigationBar from "components/organisms/WithNavigationBar"; + import Room from "components/organisms/Room"; +import WithNavigationBar from "components/organisms/WithNavigationBar"; +import { InformationLeftColumn } from "components/organisms/InformationLeftColumn"; +import InformationCard from "components/molecules/InformationCard"; import SparkleFairiesPopUp from "components/molecules/SparkleFairiesPopUp/SparkleFairiesPopUp"; -import { Modal } from "react-bootstrap"; -import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; -import { ConvertToEmbeddableUrl } from "utils/ConvertToEmbeddableUrl"; -import { currentVenueSelectorData } from "utils/selectors"; -import { IFRAME_ALLOW } from "settings"; -import { VideoAspectRatio } from "types/VideoAspectRatio"; + +import "./ArtPiece.scss"; export const ArtPiece = () => { const venue = useSelector(currentVenueSelectorData); - const [showEventSchedule, setShowEventSchedule] = useState(false); - if (!venue) return <>Loading...; const iframeUrl = ConvertToEmbeddableUrl(venue.iframeUrl); @@ -67,20 +69,6 @@ export const ArtPiece = () => {

    )} - setShowEventSchedule(false)} - dialogClassName="custom-dialog" - > - - - - ); }; - -/** - * @deprecated use named export instead - */ -export default ArtPiece; diff --git a/src/components/templates/ArtPiece/index.ts b/src/components/templates/ArtPiece/index.ts index 2aec203679..adc3f09d46 100644 --- a/src/components/templates/ArtPiece/index.ts +++ b/src/components/templates/ArtPiece/index.ts @@ -1,6 +1 @@ export { ArtPiece } from "./ArtPiece"; - -/** - * @deprecated use named export instead - */ -export { default } from "./ArtPiece"; diff --git a/src/components/templates/Playa/Playa.tsx b/src/components/templates/Playa/Playa.tsx index 5d2d3267db..ef7176af5e 100644 --- a/src/components/templates/Playa/Playa.tsx +++ b/src/components/templates/Playa/Playa.tsx @@ -54,7 +54,6 @@ import { useUser } from "hooks/useUser"; import { useFirestoreConnect } from "hooks/useFirestoreConnect"; import { DustStorm } from "components/organisms/DustStorm/DustStorm"; -import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; import CreateEditPopUp from "components/molecules/CreateEditPopUp/CreateEditPopUp"; import { DonatePopUp } from "components/molecules/DonatePopUp/DonatePopUp"; @@ -130,7 +129,6 @@ const minZoom = () => (window.innerWidth - 2 * PLAYA_MARGIN_X) / PLAYA_WIDTH; const Playa = () => { useFirestoreConnect("venues"); const [showModal, setShowModal] = useState(false); - const [showEventSchedule, setShowEventSchedule] = useState(false); const [selectedVenue, setSelectedVenue] = useState>(); const [zoom, setZoom] = useState(minZoom()); const [centerX, setCenterX] = useState(GATE_X); @@ -1050,15 +1048,6 @@ const Playa = () => { /> )} - setShowEventSchedule(false)} - dialogClassName="custom-dialog" - > - - - - ); }, [ @@ -1079,7 +1068,6 @@ const Playa = () => { isUserVenueOwner, dustStorm, changeDustStorm, - showEventSchedule, inVideoChat, videoChatHeight, mapContainer, diff --git a/src/pages/Account/SplashPage.tsx b/src/pages/Account/SplashPage.tsx index 64e8e4b0f1..ec3c7a3baa 100644 --- a/src/pages/Account/SplashPage.tsx +++ b/src/pages/Account/SplashPage.tsx @@ -1,37 +1,28 @@ -import React, { useCallback } from "react"; +import React from "react"; import { useHistory } from "react-router-dom"; -import "firebase/storage"; -import "./Account.scss"; + import { PLAYA_IMAGE, PLAYA_VENUE_NAME, PLAYA_VENUE_ID } from "settings"; + import { venueInsideUrl } from "utils/url"; + import { useUser } from "hooks/useUser"; -import { useQuery } from "hooks/useQuery"; -import { Modal } from "react-bootstrap"; -import { NavBarSchedule } from "components/organisms/NavBarSchedule/NavBarSchedule"; + +import "firebase/storage"; +import "./Account.scss"; export interface ProfileFormData { partyName: string; pictureUrl: string; } -const SplashPage = () => { +export const SplashPage = () => { const history = useHistory(); const { user } = useUser(); - const queryParams = useQuery(); - const showSchedule = !!queryParams.get("schedule"); const onSubmit = () => { history.push(user ? venueInsideUrl(PLAYA_VENUE_ID) : "/enter/step1"); }; - const onHideSchedule = useCallback(() => { - history.replace(history.location.pathname); - }, [history]); - - const onShowSchedulePress = useCallback(() => { - history.replace({ search: "schedule=true" }); - }, [history]); - return ( <>
    @@ -52,25 +43,8 @@ const SplashPage = () => { > Enter the burn -
    - - - - - ); }; - -export default SplashPage; From 41bfff843417a7b10e7bfe90c7750ee4027118ff Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:34:41 +0300 Subject: [PATCH 63/72] Move DEFAULT_VENUE_NAME to ScheduleVenueDescription --- .../ScheduleVenueDescription/ScheduleVenueDescription.tsx | 3 ++- src/settings.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index ca6ab69f82..f23ed83d6d 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -2,12 +2,13 @@ import React, { FC, useMemo } from "react"; import { useCss } from "react-use"; import classNames from "classnames"; -import { DEFAULT_VENUE_LOGO, DEFAULT_VENUE_NAME } from "settings"; +import { DEFAULT_VENUE_LOGO } from "settings"; import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import "./ScheduleVenueDescription.scss"; +const DEFAULT_VENUE_NAME = "Sparkle"; export interface ScheduleVenueDescriptionProps { venueId: string; } diff --git a/src/settings.ts b/src/settings.ts index 4c8e7962d8..ed92e8a79e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -43,7 +43,6 @@ export const SPARKLE_ICON = "/sparkle-icon.png"; export const DEFAULT_MAP_BACKGROUND = "/maps/Sparkle_Field_Background.jpg"; export const DEFAULT_VENUE_BANNER = "/assets/Sparkle_Banner_Default.jpg"; export const DEFAULT_VENUE_LOGO = "/assets/Sparkle_SquareLogo_Default.jpg"; -export const DEFAULT_VENUE_NAME = "Sparkle"; // @debt de-duplicate DEFAULT_PROFILE_IMAGE, DEFAULT_AVATAR_IMAGE, DEFAULT_PROFILE_PIC. Are they all used for the same concept? export const DEFAULT_PROFILE_IMAGE = "/anonymous-profile-icon.jpeg"; export const DEFAULT_AVATAR_IMAGE = sparkleNavLogo; From ca1b2af01733aab889bb0631cda18841b82c80c2 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:37:22 +0300 Subject: [PATCH 64/72] Reverse isEventStartingSoon logic --- .../molecules/EventPaymentButton/EventPaymentButton.tsx | 2 +- src/pages/VenuePage/VenuePage.tsx | 2 +- src/utils/event.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx index 63066fc393..a99394d3fb 100644 --- a/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx +++ b/src/components/molecules/EventPaymentButton/EventPaymentButton.tsx @@ -59,7 +59,7 @@ const EventPaymentButton: React.FunctionComponent = ({ diff --git a/src/pages/VenuePage/VenuePage.tsx b/src/pages/VenuePage/VenuePage.tsx index 01f5afaa23..8fece8f107 100644 --- a/src/pages/VenuePage/VenuePage.tsx +++ b/src/pages/VenuePage/VenuePage.tsx @@ -209,7 +209,7 @@ const VenuePage: React.FC = () => { return <>Forbidden; } - if (!isEventStartingSoon(event)) { + if (isEventStartingSoon(event)) { return ( addMinutes(eventStartTime(event), event.duration_minutes); export const isEventStartingSoon = (event: VenueEvent) => - differenceInHours(eventStartTime(event), Date.now()) > 0; + differenceInHours(eventStartTime(event), Date.now()) <= 0; export const getEventInterval = (event: VenueEvent) => ({ start: eventStartTime(event), From 1bc21ee7f27af654f05153ea0a2a463d476cce1e Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:49:49 +0300 Subject: [PATCH 65/72] Add comment about NavBarSchedule class name --- src/components/organisms/NavBarSchedule/NavBarSchedule.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index f600a114a0..610c1ce9ea 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -119,6 +119,7 @@ export const NavBarSchedule: FC = ({ isVisible }) => { }; }, [relatedVenueEvents, userEventIds, selectedDayIndex, getLocaion]); + // if .NavBarSchedule is changed, we need to update the class name in NavBar#hideEventSchedule event handler as well const containerClasses = classNames("NavBarSchedule", { "NavBarSchedule--show": isVisible, }); From bbb1862c171ac2cbb4b922d6b03f6a25b98dcc8f Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 11:52:49 +0300 Subject: [PATCH 66/72] Fix typo isPersonalizedEvent --- src/components/molecules/ScheduleEvent/ScheduleEvent.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx index 5b23af7cd6..fbfb230851 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.tsx @@ -33,7 +33,7 @@ export interface ScheduleEventProps { export const ScheduleEvent: React.FC = ({ event, scheduleStartHour, - personalizedEvent: isPersonaliezedEvent = false, + personalizedEvent: isPersonalizedEvent = false, }) => { const { userId } = useUser(); @@ -54,7 +54,7 @@ export const ScheduleEvent: React.FC = ({ "ScheduleEvent", { "ScheduleEvent--live": isEventLive(event), - "ScheduleEvent--users": isPersonaliezedEvent, + "ScheduleEvent--users": isPersonalizedEvent, }, containerCssVars ); From 61c8d31c7eecfeae9b1debbdc10b22f31a630afe Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 12:35:09 +0300 Subject: [PATCH 67/72] Refactor Schedule related components --- src/api/profile.ts | 2 ++ .../ScheduleEvent/ScheduleEvent.scss | 4 ++-- .../ScheduleVenueDescription.tsx | 3 +-- .../NavBarSchedule/NavBarSchedule.tsx | 20 ++++++++++--------- src/pages/Admin/VenueEventDetails.tsx | 5 +---- src/utils/event.ts | 4 ++-- src/utils/formatMeasurement.ts | 4 +--- src/utils/time.ts | 14 ++++++++----- 8 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/api/profile.ts b/src/api/profile.ts index 4f19589242..f44271135e 100644 --- a/src/api/profile.ts +++ b/src/api/profile.ts @@ -94,6 +94,8 @@ export const updatePersonalizedSchedule = async ({ event, removeMode, }); + + throw err; }); }); }; diff --git a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss index 9a54cee386..4fd3500196 100644 --- a/src/components/molecules/ScheduleEvent/ScheduleEvent.scss +++ b/src/components/molecules/ScheduleEvent/ScheduleEvent.scss @@ -3,7 +3,7 @@ $grey--regular: #3f3d42; $grey--hover: #4c494f; $grey--users: #4c494f; -$grey--ligth: #ebebeb; +$grey--light: #ebebeb; $purple--regular: #7c46fb; $purple--hover: #7c46fb; @@ -41,7 +41,7 @@ $description--margin-top: 2px; &--users { color: $grey--hover; - background-color: $grey--ligth; + background-color: $grey--light; &:hover { background-color: $white; diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index f23ed83d6d..67990a6426 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -8,7 +8,6 @@ import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; import "./ScheduleVenueDescription.scss"; -const DEFAULT_VENUE_NAME = "Sparkle"; export interface ScheduleVenueDescriptionProps { venueId: string; } @@ -43,7 +42,7 @@ export const ScheduleVenueDescription: FC = ({

    - {scheduleVenue?.name ?? DEFAULT_VENUE_NAME} + {scheduleVenue?.name ?? "Sparkle"}

    {scheduleVenue?.config?.landingPageConfig?.subtitle} diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index 610c1ce9ea..a4dcfb1434 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -12,7 +12,7 @@ import { getUnixTime, fromUnixTime, } from "date-fns"; -import { chain, range } from "lodash"; +import { groupBy, range } from "lodash"; import classNames from "classnames"; import { SCHEDULE_SHOW_DAYS_AHEAD } from "settings"; @@ -90,11 +90,11 @@ export const NavBarSchedule: FC = ({ isVisible }) => { }); }, [selectedDayIndex]); - const getLocaion = useCallback( + const getEventLocation = useCallback( (locString: string): VenueLocation => { const [venueId, roomTitle = ""] = extractLocation(locString); - const venueTitle = - relatedVenues.find((venue) => venue.id === venueId)?.name || ""; + const venueTitle = relatedVenues.find((venue) => venue.id === venueId) + ?.name; return { venueId, roomTitle, venueTitle }; }, [relatedVenues] @@ -106,10 +106,12 @@ export const NavBarSchedule: FC = ({ isVisible }) => { .filter(isEventWithinDate(selectedDayIndex === 0 ? Date.now() : dayStart)) .map(prepareForSchedule(dayStart, userEventIds)); - const locatedEvents: LocatedEvents[] = chain(daysEvents) - .groupBy(buildLocationString) - .map((value, key) => ({ location: getLocaion(key), events: value })) - .value(); + const locatedEvents: LocatedEvents[] = Object.entries( + groupBy(daysEvents, buildLocationString) + ).map(([group, events]) => ({ + events, + location: getEventLocation(group), + })); return { locatedEvents, @@ -117,7 +119,7 @@ export const NavBarSchedule: FC = ({ isVisible }) => { dayStartUtcSeconds: getUnixTime(dayStart), personalEvents: daysEvents.filter((event) => event.isSaved), }; - }, [relatedVenueEvents, userEventIds, selectedDayIndex, getLocaion]); + }, [relatedVenueEvents, userEventIds, selectedDayIndex, getEventLocation]); // if .NavBarSchedule is changed, we need to update the class name in NavBar#hideEventSchedule event handler as well const containerClasses = classNames("NavBarSchedule", { diff --git a/src/pages/Admin/VenueEventDetails.tsx b/src/pages/Admin/VenueEventDetails.tsx index aa717fbd0e..336ef3010f 100644 --- a/src/pages/Admin/VenueEventDetails.tsx +++ b/src/pages/Admin/VenueEventDetails.tsx @@ -4,7 +4,7 @@ import { format, getUnixTime } from "date-fns"; import { VenueEvent } from "types/venues"; import { WithId } from "utils/id"; -import { formatHourAndMinute, getTimeBeforeParty } from "utils/time"; +import { formatHourAndMinute } from "utils/time"; import { eventEndTime, eventStartTime } from "utils/event"; export interface VenueEventDetailsProps { @@ -25,7 +25,6 @@ const VenueEventDetails = ({ const startTime = formatHourAndMinute(venueEvent.start_utc_seconds); const endTime = formatHourAndMinute(getUnixTime(eventEndTime(venueEvent))); const startDay = format(eventStartTime(venueEvent), "EEEE LLLL do"); - console.log("here"); return (
    @@ -43,8 +42,6 @@ const VenueEventDetails = ({
    {venueEvent.description} -
    - {getTimeBeforeParty(venueEvent.start_utc_seconds)} {venueEvent.descriptions?.map((description, index) => (

    {description}

    diff --git a/src/utils/event.ts b/src/utils/event.ts index 523071365b..25c367cff9 100644 --- a/src/utils/event.ts +++ b/src/utils/event.ts @@ -1,7 +1,7 @@ import { addMinutes, areIntervalsOverlapping, - differenceInHours, + differenceInMinutes, endOfDay, fromUnixTime, isWithinInterval, @@ -55,7 +55,7 @@ export const eventEndTime = (event: VenueEvent) => addMinutes(eventStartTime(event), event.duration_minutes); export const isEventStartingSoon = (event: VenueEvent) => - differenceInHours(eventStartTime(event), Date.now()) <= 0; + differenceInMinutes(eventStartTime(event), Date.now()) <= 60; export const getEventInterval = (event: VenueEvent) => ({ start: eventStartTime(event), diff --git a/src/utils/formatMeasurement.ts b/src/utils/formatMeasurement.ts index efa53d2586..52c3dd0dc7 100644 --- a/src/utils/formatMeasurement.ts +++ b/src/utils/formatMeasurement.ts @@ -1,7 +1,5 @@ export const formatMeasurement = (value: number, measureUnit: string) => { const baseFormatted = `${value} ${measureUnit}`; - if (value === 0) return ""; - if (value === 1) return baseFormatted; - if (value > 1) return `${baseFormatted}s`; + return value === 1 ? baseFormatted : `${baseFormatted}s`; }; diff --git a/src/utils/time.ts b/src/utils/time.ts index 74f7b955d1..b95880f067 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -14,18 +14,22 @@ import { * @deprecated in favor of using date-fns functions */ export const ONE_SECOND_IN_MILLISECONDS = 1000; + /** * @deprecated in favor of using date-fns functions */ export const ONE_MINUTE_IN_SECONDS = 60; + /** * @deprecated in favor of using date-fns functions */ export const ONE_HOUR_IN_MINUTES = 60; + /** * @deprecated in favor of using date-fns functions */ export const ONE_HOUR_IN_SECONDS = ONE_MINUTE_IN_SECONDS * 60; + /** * @deprecated in favor of using date-fns functions */ @@ -42,6 +46,7 @@ export const FIVE_MINUTES_MS = */ export const ONE_HOUR_IN_MILLISECONDS = ONE_SECOND_IN_MILLISECONDS * ONE_HOUR_IN_SECONDS; + /** * @deprecated in favor of using date-fns functions */ @@ -96,7 +101,7 @@ export const getTimeBeforeParty = (startUtcSeconds?: number) => { return formatDuration( intervalToDuration({ - start: Date.now(), + start: now, end: eventStartDate, }), { format: ["days", "hours", "minutes"] } @@ -187,14 +192,13 @@ export const getCurrentTimeInUTCSeconds = () => getUnixTime(Date.now()); * * @see https://date-fns.org/docs/formatRelative */ -export const formatUtcSecondsRelativeToNow = (utcSeconds: number) => { - return formatRelative(fromUnixTime(utcSeconds), Date.now()); -}; +export const formatUtcSecondsRelativeToNow = (utcSeconds: number) => + formatRelative(fromUnixTime(utcSeconds), Date.now()); -// @debt get rid of ONE_SECOND_IN_MILLISECONDS and use date-fns function export const normalizeTimestampToMilliseconds = (timestamp: number) => { const isTimestampInMilliSeconds = timestamp > SECONDS_TIMESTAMP_MAX_VALUE; + // @debt get rid of ONE_SECOND_IN_MILLISECONDS and use date-fns function return isTimestampInMilliSeconds ? timestamp : timestamp * ONE_SECOND_IN_MILLISECONDS; From eaea7348e4541095956568dd31f39dcd55161ee7 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 12:53:24 +0300 Subject: [PATCH 68/72] Rename default label to ScheduleVenueDescription --- .../ScheduleVenueDescription/ScheduleVenueDescription.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index 67990a6426..c92fe3b472 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -42,7 +42,7 @@ export const ScheduleVenueDescription: FC = ({

    - {scheduleVenue?.name ?? "Sparkle"} + {scheduleVenue?.name ?? "Schedule"}

    {scheduleVenue?.config?.landingPageConfig?.subtitle} From a37241a83c560a47fab9db7ae5e374bafd3cafa3 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 13:38:44 +0300 Subject: [PATCH 69/72] Created NavBarSchedule container to distinguish in/out clicks --- src/components/molecules/NavBar/NavBar.tsx | 6 ++++-- .../InformationLeftColumn/InformationLeftColumn.tsx | 1 + src/components/organisms/NavBarSchedule/NavBarSchedule.tsx | 1 - src/components/templates/Playa/Playa.tsx | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/molecules/NavBar/NavBar.tsx b/src/components/molecules/NavBar/NavBar.tsx index 101bc6a974..787406be7e 100644 --- a/src/components/molecules/NavBar/NavBar.tsx +++ b/src/components/molecules/NavBar/NavBar.tsx @@ -142,7 +142,7 @@ const NavBar: React.FC = ({ setEventScheduleVisible(!isEventScheduleVisible); }, [isEventScheduleVisible]); const hideEventSchedule = useCallback((e) => { - if (e.target.closest(".NavBarSchedule")) return; + if (e.target.closest(".NavBar__schedule-dropdown")) return; setEventScheduleVisible(false); }, []); @@ -317,7 +317,9 @@ const NavBar: React.FC = ({ }`} onClick={hideEventSchedule} > - +
    + +

    {/* @debt Remove back button from Navbar */} diff --git a/src/components/organisms/InformationLeftColumn/InformationLeftColumn.tsx b/src/components/organisms/InformationLeftColumn/InformationLeftColumn.tsx index 2cf340fae3..3a4063d0d5 100644 --- a/src/components/organisms/InformationLeftColumn/InformationLeftColumn.tsx +++ b/src/components/organisms/InformationLeftColumn/InformationLeftColumn.tsx @@ -45,6 +45,7 @@ export const InformationLeftColumn = forwardRef< const [isExpanded, setExpanded] = useState(false); const toggleExpanded = useCallback((e?: React.MouseEvent) => { + // @debt we should try to avoid using event.stopPropagation() e && e.stopPropagation(); setExpanded((prev) => !prev); diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index a4dcfb1434..6b7210c144 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -121,7 +121,6 @@ export const NavBarSchedule: FC = ({ isVisible }) => { }; }, [relatedVenueEvents, userEventIds, selectedDayIndex, getEventLocation]); - // if .NavBarSchedule is changed, we need to update the class name in NavBar#hideEventSchedule event handler as well const containerClasses = classNames("NavBarSchedule", { "NavBarSchedule--show": isVisible, }); diff --git a/src/components/templates/Playa/Playa.tsx b/src/components/templates/Playa/Playa.tsx index ef7176af5e..05af42da60 100644 --- a/src/components/templates/Playa/Playa.tsx +++ b/src/components/templates/Playa/Playa.tsx @@ -305,6 +305,7 @@ const Playa = () => { ); }, 1); + // @debt we should try to avoid using event.stopPropagation() const zoomListener = (event: WheelEvent) => { event.preventDefault(); event.stopPropagation(); From aa7ef18c215abd39ef422d01b27317d954d40dca Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 14:09:19 +0300 Subject: [PATCH 70/72] Create NavBarScheduleClassName const --- src/components/molecules/NavBar/NavBar.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/NavBar/NavBar.tsx b/src/components/molecules/NavBar/NavBar.tsx index 787406be7e..6b5bf702b8 100644 --- a/src/components/molecules/NavBar/NavBar.tsx +++ b/src/components/molecules/NavBar/NavBar.tsx @@ -68,6 +68,8 @@ const GiftPopover = ( ); +const navBarScheduleClassName = "NavBar__schedule-dropdown"; + interface NavBarPropsType { redirectionUrl?: string; hasBackButton?: boolean; @@ -142,7 +144,7 @@ const NavBar: React.FC = ({ setEventScheduleVisible(!isEventScheduleVisible); }, [isEventScheduleVisible]); const hideEventSchedule = useCallback((e) => { - if (e.target.closest(".NavBar__schedule-dropdown")) return; + if (e.target.closest(`.${navBarScheduleClassName}`)) return; setEventScheduleVisible(false); }, []); @@ -317,7 +319,7 @@ const NavBar: React.FC = ({ }`} onClick={hideEventSchedule} > -
    +
    From 959ba6812691a4acb891b713047eaeeab15ec475 Mon Sep 17 00:00:00 2001 From: Viktoryia Date: Tue, 18 May 2021 16:00:20 +0300 Subject: [PATCH 71/72] Use new hooks that fetch related venues --- .../molecules/Schedule/Schedule.tsx | 74 +++++++++++-------- .../ScheduleVenueDescription.tsx | 22 ++---- .../NavBarSchedule/NavBarSchedule.tsx | 23 +++++- 3 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index fcda168ecd..82960e7a4d 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -34,6 +34,7 @@ export interface ScheduleProps { personalEvents: PersonalizedVenueEvent[]; scheduleDate: Date; isToday: boolean; + isLoading: boolean; } export const Schedule: React.FC = ({ @@ -41,6 +42,7 @@ export const Schedule: React.FC = ({ personalEvents, scheduleDate, isToday, + isLoading, }) => { const hasEvents = locatedEvents.length > 0; @@ -130,40 +132,48 @@ export const Schedule: React.FC = ({ [locatedEvents, scheduleStartHour] ); + if (isLoading) + return ( +
    +
    is loading
    +
    + ); + + if (!hasEvents) + return ( +
    +
    No events scheduled
    +
    + ); + return (
    - {hasEvents ? ( - <> -
    -
    -

    My Daily Schedule

    - - {personalEvents.length} events - -
    - - {roomCells} -
    - -
    -
    {hoursRow}
    - - {isToday &&
    } - -
    - -
    - - {rowsWithTheEvents} -
    - - ) : ( -
    No events scheduled
    - )} +
    +
    +

    My Daily Schedule

    + + {personalEvents.length} events + +
    + + {roomCells} +
    + +
    +
    {hoursRow}
    + + {isToday &&
    } + +
    + +
    + + {rowsWithTheEvents} +
    ); }; diff --git a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx index c92fe3b472..77848d5d66 100644 --- a/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx +++ b/src/components/molecules/ScheduleVenueDescription/ScheduleVenueDescription.tsx @@ -1,10 +1,10 @@ -import React, { FC, useMemo } from "react"; +import React, { FC } from "react"; import { useCss } from "react-use"; import classNames from "classnames"; import { DEFAULT_VENUE_LOGO } from "settings"; -import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; +import { useRelatedVenues } from "hooks/useRelatedVenues"; import "./ScheduleVenueDescription.scss"; @@ -15,19 +15,13 @@ export interface ScheduleVenueDescriptionProps { export const ScheduleVenueDescription: FC = ({ venueId, }) => { - const { parentVenue, currentVenue } = useConnectRelatedVenues({ - venueId, + const { sovereignVenue } = useRelatedVenues({ + currentVenueId: venueId, }); - // @debt: ideally this would find the top most parent of parents and use those details - const scheduleVenue = useMemo( - () => (parentVenue ? parentVenue : currentVenue), - [parentVenue, currentVenue] - ); - const venuePictureCssVars = useCss({ "--venue-picture--background-image": `url(${ - scheduleVenue?.host?.icon ?? DEFAULT_VENUE_LOGO + sovereignVenue?.host?.icon ?? DEFAULT_VENUE_LOGO })`, }); @@ -42,15 +36,15 @@ export const ScheduleVenueDescription: FC = ({

    - {scheduleVenue?.name ?? "Schedule"} + {sovereignVenue?.name ?? "Schedule"}

    - {scheduleVenue?.config?.landingPageConfig?.subtitle} + {sovereignVenue?.config?.landingPageConfig?.subtitle}

    -

    {scheduleVenue?.config?.landingPageConfig?.description}

    +

    {sovereignVenue?.config?.landingPageConfig?.description}

    ); diff --git a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx index 6b7210c144..a5467b7556 100644 --- a/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx +++ b/src/components/organisms/NavBarSchedule/NavBarSchedule.tsx @@ -17,14 +17,16 @@ import classNames from "classnames"; import { SCHEDULE_SHOW_DAYS_AHEAD } from "settings"; -import { useConnectRelatedVenues } from "hooks/useConnectRelatedVenues"; +import { useRelatedVenues } from "hooks/useRelatedVenues"; import { useVenueId } from "hooks/useVenueId"; import { useUser } from "hooks/useUser"; +import { useVenueEvents } from "hooks/events"; import { PersonalizedVenueEvent, VenueLocation, LocatedEvents, + VenueEvent, } from "types/venues"; import { Schedule } from "components/molecules/Schedule"; @@ -36,6 +38,7 @@ import { prepareForSchedule, } from "./utils"; import { isEventWithinDate } from "utils/event"; +import { WithVenueId } from "utils/id"; import "./NavBarSchedule.scss"; @@ -43,6 +46,8 @@ interface NavBarScheduleProps { isVisible?: boolean; } +const emptyRelatedEvents: WithVenueId[] = []; + export interface ScheduleDay { isToday: boolean; dayStartUtcSeconds: number; @@ -58,11 +63,19 @@ export const NavBarSchedule: FC = ({ isVisible }) => { const userEventIds = userWithId?.myPersonalizedSchedule ?? emptyPersonalizedSchedule; - const { relatedVenueEvents, relatedVenues } = useConnectRelatedVenues({ - venueId, - withEvents: true, + const { isLoading, relatedVenues, relatedVenueIds } = useRelatedVenues({ + currentVenueId: venueId, + }); + + const { + isEventsLoading, + events: relatedVenueEvents = emptyRelatedEvents, + } = useVenueEvents({ + venueIds: relatedVenueIds, }); + const isLoadingSchedule = isLoading || isEventsLoading; + const [selectedDayIndex, setSelectedDayIndex] = useState(0); const weekdays = useMemo(() => { @@ -129,7 +142,9 @@ export const NavBarSchedule: FC = ({ isVisible }) => {
    {venueId && }
      {weekdays}
    + Date: Tue, 18 May 2021 16:47:42 +0300 Subject: [PATCH 72/72] Add Loading component; fix the calculation for current time line position --- src/assets/icons/icon-loading.svg | 14 ++++++++ src/components/molecules/Loading/Loading.scss | 33 +++++++++++++++++++ src/components/molecules/Loading/Loading.tsx | 18 ++++++++++ src/components/molecules/Loading/index.ts | 1 + .../molecules/Schedule/Schedule.tsx | 18 ++++++---- 5 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 src/assets/icons/icon-loading.svg create mode 100644 src/components/molecules/Loading/Loading.scss create mode 100644 src/components/molecules/Loading/Loading.tsx create mode 100644 src/components/molecules/Loading/index.ts diff --git a/src/assets/icons/icon-loading.svg b/src/assets/icons/icon-loading.svg new file mode 100644 index 0000000000..48d84d3657 --- /dev/null +++ b/src/assets/icons/icon-loading.svg @@ -0,0 +1,14 @@ + + + icon-loading + + + + + + + + + + + diff --git a/src/components/molecules/Loading/Loading.scss b/src/components/molecules/Loading/Loading.scss new file mode 100644 index 0000000000..9d5c8234e8 --- /dev/null +++ b/src/components/molecules/Loading/Loading.scss @@ -0,0 +1,33 @@ +@keyframes loadingspin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +$Loading__icon--size: 40px; +$Loading__icon--margin-bottom: 1rem; +$Loading__message--font-size: 0.9rem; +$Loading__message--opacity: 0.6; + +.Loading { + display: flex; + flex-direction: column; + width: 100%; + text-align: center; + + &__icon { + margin: 0 auto; + width: $Loading__icon--size; + height: $Loading__icon--size; + margin-bottom: $Loading__icon--margin-bottom; + animation: loadingspin 0.6s infinite linear; + } + + &__message { + font-size: $Loading__message--font-size; + opacity: $Loading__message--opacity; + } +} diff --git a/src/components/molecules/Loading/Loading.tsx b/src/components/molecules/Loading/Loading.tsx new file mode 100644 index 0000000000..f2d3f4b038 --- /dev/null +++ b/src/components/molecules/Loading/Loading.tsx @@ -0,0 +1,18 @@ +import React, { FC } from "react"; + +import LoadingIcon from "assets/icons/icon-loading.svg"; + +import "./Loading.scss"; + +export interface LoadingProps { + message?: string; +} + +export const Loading: FC = ({ message }) => { + return ( +
    + loading + {message} +
    + ); +}; diff --git a/src/components/molecules/Loading/index.ts b/src/components/molecules/Loading/index.ts new file mode 100644 index 0000000000..0de49db4c0 --- /dev/null +++ b/src/components/molecules/Loading/index.ts @@ -0,0 +1 @@ +export { Loading } from "./Loading"; diff --git a/src/components/molecules/Schedule/Schedule.tsx b/src/components/molecules/Schedule/Schedule.tsx index 82960e7a4d..47e999dcaf 100644 --- a/src/components/molecules/Schedule/Schedule.tsx +++ b/src/components/molecules/Schedule/Schedule.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import classNames from "classnames"; import { eachHourOfInterval, @@ -23,6 +23,7 @@ import { formatMeasurement } from "utils/formatMeasurement"; import { useInterval } from "hooks/useInterval"; +import { Loading } from "components/molecules/Loading"; import { ScheduleRoomEvents } from "components/molecules/ScheduleRoomEvents"; import { calcStartPosition } from "./Schedule.utils"; @@ -97,17 +98,20 @@ export const Schedule: React.FC = ({ [scheduleStartDateTime] ); + const [currentTimePosition, setCurrentTimePosition] = useState(0); + const calcCurrentTimePosition = useCallback( - () => calcStartPosition(getUnixTime(Date.now()), scheduleStartHour), + () => + setCurrentTimePosition( + calcStartPosition(getUnixTime(Date.now()), scheduleStartHour) + ), [scheduleStartHour] ); - const [currentTimePosition, setCurrentTimePosition] = useState( - calcCurrentTimePosition() - ); + useEffect(() => calcCurrentTimePosition(), [calcCurrentTimePosition]); useInterval(() => { - setCurrentTimePosition(calcCurrentTimePosition()); + calcCurrentTimePosition(); }, SCHEDULE_CURRENT_TIMELINE_MS); const containerVars = useCss({ @@ -135,7 +139,7 @@ export const Schedule: React.FC = ({ if (isLoading) return (
    -
    is loading
    +
    );