From c6246a291ab2a141518395760c0c79bd884d457f Mon Sep 17 00:00:00 2001 From: Alessandro Mazzon Date: Fri, 10 Nov 2023 13:30:30 +0100 Subject: [PATCH] feat: dates localization (#23) ## Description Now dates are localized using the same logic the mobile app is using - Fixed some UI issues - Removed the usage of `getDetails` from google maps --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] targeted the correct branch - [ ] provided a link to the relevant issue or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed all author checklist items have been addressed --- app/components/NavigationBar.tsx | 21 ++-- .../BondscapeDateTimePicker.tsx | 40 +++++- app/creator/create/LocationInput.tsx | 25 ++-- .../create/[[...id]]/CreateTicketCategory.tsx | 30 ++++- app/creator/create/[[...id]]/MainSection.tsx | 20 +-- app/creator/create/[[...id]]/useHooks.ts | 8 +- app/creator/events/[id]/page.tsx | 105 ++++++++++------ app/hooks/events/useGetGooglePlace.ts | 65 ---------- app/hooks/layout/useBreakpoints.ts | 2 +- app/hooks/timeformat/useFormatDateToTZ.ts | 108 ++++++++++------ app/lib/DateUtils/index.ts | 119 ++++++++++++++++++ .../bondscape/fragments/EventsFields.ts | 10 ++ app/types/event.ts | 33 +++++ 13 files changed, 400 insertions(+), 186 deletions(-) delete mode 100644 app/hooks/events/useGetGooglePlace.ts create mode 100644 app/lib/DateUtils/index.ts diff --git a/app/components/NavigationBar.tsx b/app/components/NavigationBar.tsx index 106799b..74f935a 100644 --- a/app/components/NavigationBar.tsx +++ b/app/components/NavigationBar.tsx @@ -1,16 +1,16 @@ "use client"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import Link from "next/link"; -import BondscapeLogo from "./BondscapeLogo"; -import useBreakpoints from "../hooks/layout/useBreakpoints"; -import { usePathname } from "next/navigation"; -import useUser from "@/hooks/user/useUser"; -import SelectComponent from "@/components/SelectComponent"; -import { AnimatePresence, motion } from "framer-motion"; +import CreateEventHeader from "@/components/CreateEventHeader"; import EventsHeader from "@/components/EventsHeader"; +import SelectComponent from "@/components/SelectComponent"; import Tabs from "@/components/Tabs"; +import useUser from "@/hooks/user/useUser"; import { useActiveTab, useSetActiveTab } from "@/jotai/activeTab"; -import CreateEventHeader from "@/components/CreateEventHeader"; +import { AnimatePresence, motion } from "framer-motion"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import useBreakpoints from "../hooks/layout/useBreakpoints"; +import BondscapeLogo from "./BondscapeLogo"; interface Props { readonly disableNavbarBgInDesktop?: boolean; @@ -33,7 +33,8 @@ const NavigationBar = ({ const setActiveTab = useSetActiveTab(); const [navbarBgVisible, setNavbarBgVisible] = useState(false); // Hooks - const [isMobile, isMd, isDesktop, isBreakpointReady] = + // Do not remove unused values + const [isMobile, isMd, isLg, isXl, isDesktop, isBreakpointReady] = useBreakpoints(); const pathname = usePathname(); const { user } = useUser(); diff --git a/app/creator/create/BondscapeDateTimePicker/BondscapeDateTimePicker.tsx b/app/creator/create/BondscapeDateTimePicker/BondscapeDateTimePicker.tsx index da619ee..129791b 100644 --- a/app/creator/create/BondscapeDateTimePicker/BondscapeDateTimePicker.tsx +++ b/app/creator/create/BondscapeDateTimePicker/BondscapeDateTimePicker.tsx @@ -1,8 +1,9 @@ +import { getDatePickerParsedDate, normalizeDateTime } from "@/lib/DateUtils"; import { DatePicker } from "antd"; import dayjs from "dayjs"; import timezone from "dayjs/plugin/timezone"; import utc from "dayjs/plugin/utc"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import "./style.css"; interface Props { @@ -30,6 +31,8 @@ const BondscapeDateTimePicker = ({ onChangeEnd, footer, }: Props) => { + const [startValue, setStartValue] = useState(); + const [endValue, setEndValue] = useState(); const [minDate, setMinDate] = useState(); const [maxDate, setMaxDate] = useState(); @@ -61,6 +64,25 @@ const BondscapeDateTimePicker = ({ ); }; + useEffect(() => { + if (initialStartValue) { + const startValueWithoutTz = initialStartValue?.slice(0, -6); + setStartValue(dayjs(startValueWithoutTz)); + onChangeStart( + normalizeDateTime(getDatePickerParsedDate(dayjs(startValueWithoutTz))), + ); + } + if (initialEndValue) { + const endValueWithoutTz = initialEndValue?.slice(0, -6); + setEndValue(dayjs(endValueWithoutTz)); + onChangeEnd( + normalizeDateTime(getDatePickerParsedDate(dayjs(endValueWithoutTz))), + ); + } + // Adding those deps will cause an infinite loop + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [initialEndValue, initialStartValue]); + return (
@@ -77,12 +99,13 @@ const BondscapeDateTimePicker = ({
current > maxDate : undefined} onChange={(date) => { setMinDate(date || undefined); if (date) { - onChangeStart(dayjs.utc(date).tz().format()); + setStartValue(dayjs(date)); + onChangeStart(normalizeDateTime(getDatePickerParsedDate(date))); } else { onChangeStart(undefined); } @@ -107,12 +130,13 @@ const BondscapeDateTimePicker = ({
current < minDate : undefined} onChange={(date) => { setMaxDate(date || undefined); if (date) { - onChangeEnd(dayjs.utc(date).tz().format()); + setEndValue(dayjs(date)); + onChangeEnd(normalizeDateTime(getDatePickerParsedDate(date))); } else { onChangeEnd(undefined); } @@ -129,7 +153,11 @@ const BondscapeDateTimePicker = ({
- {footer &&
{footer}
} + {footer && ( +
+ {footer} +
+ )} ); }; diff --git a/app/creator/create/LocationInput.tsx b/app/creator/create/LocationInput.tsx index 8b116e8..dee98ca 100644 --- a/app/creator/create/LocationInput.tsx +++ b/app/creator/create/LocationInput.tsx @@ -1,15 +1,22 @@ import React, { useEffect } from "react"; -import usePlacesAutocomplete, { getDetails } from "use-places-autocomplete"; import useOnclickOutside from "react-cool-onclickoutside"; +import usePlacesAutocomplete from "use-places-autocomplete"; interface Props { readonly defaultValue?: string; + readonly formattedAddress?: string; readonly title: string; readonly required: boolean; readonly onChange: (placeId: string) => void; } -const LocationInput = ({ defaultValue, title, required, onChange }: Props) => { +const LocationInput = ({ + defaultValue, + formattedAddress, + title, + required, + onChange, +}: Props) => { const { ready, value, @@ -22,18 +29,10 @@ const LocationInput = ({ defaultValue, title, required, onChange }: Props) => { }); useEffect(() => { - if (defaultValue) { - getDetails({ - placeId: defaultValue, - }).then((result) => { - if (typeof result !== "string") { - if (result?.formatted_address != null) { - setValue(result?.formatted_address, false); - } - } - }); + if (formattedAddress) { + setValue(formattedAddress, false); } - }, [defaultValue, setValue]); + }, [formattedAddress, setValue]); const ref = useOnclickOutside(() => { clearSuggestions(); diff --git a/app/creator/create/[[...id]]/CreateTicketCategory.tsx b/app/creator/create/[[...id]]/CreateTicketCategory.tsx index 76b2f7e..199c6f1 100644 --- a/app/creator/create/[[...id]]/CreateTicketCategory.tsx +++ b/app/creator/create/[[...id]]/CreateTicketCategory.tsx @@ -26,6 +26,7 @@ const CreateTicketCategory = ({ onHide, }: CreateTicketCategoryProps) => { const { user } = useUser(); + const [loading, setLoading] = useState(false); const [initialValues, setInitialValues] = useState({ description: "", category: "", @@ -43,9 +44,11 @@ const CreateTicketCategory = ({ useEffect(() => { if (selectedCategoryIndex !== undefined && globalValues.ticketsCategories) { + setLoading(true); setInitialValues({ ...globalValues.ticketsCategories[selectedCategoryIndex], }); + setLoading(false); } }, [globalValues.ticketsCategories, selectedCategoryIndex]); @@ -80,6 +83,16 @@ const CreateTicketCategory = ({ onHide(); }; + if (!initialValues) { + return ( +
+
+
+
+
+ ); + } + return (
@@ -107,7 +120,8 @@ const CreateTicketCategory = ({ text={"Upload an image"} description={
- This image will be the one used to create the NFTs of the tickets for this category. + This image will be the one used to create the NFTs + of the tickets for this category.
} fileToUpload={values.coverPic} @@ -165,14 +179,18 @@ const CreateTicketCategory = ({
Tickets quantities
- Here you can define the maximum amount of tickets that a single user can get for this - category, as well as the maximum amount of tickets available for this category. + Here you can define the maximum amount of tickets + that a single user can get for this category, as + well as the maximum amount of tickets available for + this category.
setFieldValue( @@ -186,7 +204,9 @@ const CreateTicketCategory = ({ setFieldValue( diff --git a/app/creator/create/[[...id]]/MainSection.tsx b/app/creator/create/[[...id]]/MainSection.tsx index 5bad559..621c396 100644 --- a/app/creator/create/[[...id]]/MainSection.tsx +++ b/app/creator/create/[[...id]]/MainSection.tsx @@ -79,20 +79,21 @@ const MainSection = ({ setFieldValue("startDate", value)} onChangeEnd={(value) => setFieldValue("endDate", value)} footer={ -
- The start and end dates of the event will be in the time zone based on where the event will be held. - If no location is entered, the timezone will default to the UTC time zone. - -
- The event can only be published if the dates are entered; otherwise, it can only be saved as a draft. +
+ The start and end dates of the event will be in the time zone + based on where the event will be held. If no location is + entered, the timezone will default to the UTC time zone. +
+ The event can only be published if the dates are entered; + otherwise, it can only be saved as a draft. +
-
} /> setFieldValue("placeId", placeId)} diff --git a/app/creator/create/[[...id]]/useHooks.ts b/app/creator/create/[[...id]]/useHooks.ts index ffad96e..7a2f231 100644 --- a/app/creator/create/[[...id]]/useHooks.ts +++ b/app/creator/create/[[...id]]/useHooks.ts @@ -21,6 +21,7 @@ const useHooks = (eventId?: string) => { startDate: undefined, endDate: undefined, placeId: undefined, + location: undefined, ticketsCategories: [], }); @@ -62,9 +63,12 @@ const useHooks = (eventId?: string) => { eventDetails: event.description, coverPicUrl: event.coverPic, startDate: event.startDate, + startDateLocalized: event.startDateLocalized, endDate: event.endDate, + endDateLocalized: event.endDateLocalized, categories: event.categories.map((category) => category.category), placeId: event.googlePlaceId, + location: event.location, organizers: event.organizers, tags: event.tags, website: event.website, @@ -73,8 +77,8 @@ const useHooks = (eventId?: string) => { id: ticketCategory.id, category: ticketCategory.name, description: ticketCategory.description, - availableFrom: ticketCategory.startDate, - availableUntil: ticketCategory.endDate, + availableFrom: ticketCategory.startDateLocalized, + availableUntil: ticketCategory.endDateLocalized, ticketsSold: ticketCategory.ticketsSold?.aggregate.count || 0, maxQuantityPerPerson: ticketCategory.ticketsPerUser, maxQuantityPerCategory: ticketCategory.totalTicketsAvailable, diff --git a/app/creator/events/[id]/page.tsx b/app/creator/events/[id]/page.tsx index d8c247c..41575cd 100644 --- a/app/creator/events/[id]/page.tsx +++ b/app/creator/events/[id]/page.tsx @@ -1,10 +1,13 @@ "use client"; import BondscapeButton from "@/components/BondscapeButton"; -import useGetGooglePlace from "@/hooks/events/useGetGooglePlace"; import useCustomLazyQuery from "@/hooks/graphql/useCustomLazyQuery"; import useBreakpoints from "@/hooks/layout/useBreakpoints"; import useFormatDateToTZ from "@/hooks/timeformat/useFormatDateToTZ"; import MainLayout from "@/layouts/MainLayout"; +import { + extractTimezoneOffset, + serializeTimezoneOffset, +} from "@/lib/DateUtils"; import GetEventJoinLink from "@/services/axios/requests/GetEventJoinLink"; import GetQrCode from "@/services/axios/requests/GetQrCode"; import GetEventById from "@/services/graphql/queries/bondscape/GetEventById"; @@ -33,7 +36,6 @@ export default function EventDetails({ params }: { params: any }) { const router = useRouter(); const [getEventById] = useCustomLazyQuery(GetEventById); const { getEventPeriodExtended } = useFormatDateToTZ(); - const { googlePlace } = useGetGooglePlace(selectedEvent?.googlePlaceId); // Callbacks @@ -218,19 +220,32 @@ export default function EventDetails({ params }: { params: any }) {
{selectedEvent ? ( getEventPeriodExtended( - selectedEvent?.startDate, - selectedEvent?.endDate, + selectedEvent?.startDateLocalized, + selectedEvent?.endDateLocalized, ).date ) : ( )}
-
+
{selectedEvent ? ( - getEventPeriodExtended( - selectedEvent?.startDate, - selectedEvent?.endDate, - ).time +
+
+ { + getEventPeriodExtended( + selectedEvent?.startDateLocalized, + selectedEvent?.endDateLocalized, + ).time + } +
+
+ {serializeTimezoneOffset( + extractTimezoneOffset( + selectedEvent?.startDateLocalized, + ), + )} +
+
) : ( )} @@ -240,8 +255,12 @@ export default function EventDetails({ params }: { params: any }) {