diff --git a/app/screens/ExploreScreen/ExploreScreen.tsx b/app/screens/ExploreScreen/ExploreScreen.tsx index 057c1bdc..d8a7d9b6 100644 --- a/app/screens/ExploreScreen/ExploreScreen.tsx +++ b/app/screens/ExploreScreen/ExploreScreen.tsx @@ -21,7 +21,7 @@ import { groupBy } from "../../utils/groupBy" import { customSortObjectKeys } from "../../utils/customSort" const recommendationTypes = Object.values(WEBFLOW_MAP.recommendationType) -type RecommendationType = typeof recommendationTypes[number] +type RecommendationType = (typeof recommendationTypes)[number] type GroupedRecommendations = Record const initialRecs = recommendationTypes.reduce( diff --git a/app/screens/InfoScreen/OurSponsorsScreen.tsx b/app/screens/InfoScreen/OurSponsorsScreen.tsx index 3379a183..01ca95b1 100644 --- a/app/screens/InfoScreen/OurSponsorsScreen.tsx +++ b/app/screens/InfoScreen/OurSponsorsScreen.tsx @@ -18,7 +18,7 @@ import { SponsorCard } from "./SponsorCard" import { groupBy } from "../../utils/groupBy" const sponsorTiers = Object.values(WEBFLOW_MAP.sponsorTier) -type Tiers = typeof sponsorTiers[number] +type Tiers = (typeof sponsorTiers)[number] const initialTiers = sponsorTiers.reduce>( (acc, tier) => ({ ...acc, [tier]: [] }), diff --git a/app/screens/WelcomeScreen.tsx b/app/screens/WelcomeScreen.tsx index b1290263..d8f02137 100644 --- a/app/screens/WelcomeScreen.tsx +++ b/app/screens/WelcomeScreen.tsx @@ -1,10 +1,11 @@ -import React from "react" +import React, { useLayoutEffect } from "react" import { Dimensions, Image, ImageStyle, Platform, TextStyle, View, ViewStyle } from "react-native" import { SafeAreaView } from "react-native-safe-area-context" import { Button, Screen, Text } from "../components" import { useAppNavigation } from "../hooks" import { AppStackScreenProps } from "../navigators" import { colors, spacing } from "../theme" +import { prefetchScheduledEvents } from "../services/api" const welcomeLogo = require("../../assets/images/welcome-shapes.png") const { width: screenWidth } = Dimensions.get("screen") @@ -18,6 +19,10 @@ export const WelcomeScreen: React.FC = (_props) => { navigation.navigate("Tabs", { screen: "Schedule" }) } + useLayoutEffect(() => { + prefetchScheduledEvents() + }, []) + return ( diff --git a/app/services/api/webflow-api.ts b/app/services/api/webflow-api.ts index a8a48121..329d61ee 100644 --- a/app/services/api/webflow-api.ts +++ b/app/services/api/webflow-api.ts @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query" +import { useQueries, useQuery, UseQueryOptions } from "@tanstack/react-query" import { Schedule } from "../../screens" import { axiosInstance, PaginatedItems } from "./axios" import type { @@ -13,6 +13,7 @@ import type { RawWorkshop, } from "./webflow-api.types" import { + CollectionConst, RECOMMENDATIONS, RECURRING_EVENTS, SCHEDULE, @@ -31,76 +32,83 @@ import { cleanedWorkshops, convertScheduleToScheduleCard, } from "./webflow-helpers" +import { queryClient } from "./react-query" -const useWebflowAPI = (key: string, collectionId: string, enabled = true) => - useQuery({ - queryKey: [key], - queryFn: async () => { - const { data } = await axiosInstance.get>( - `/collections/${collectionId}/items`, - ) - return data.items - }, - enabled, - }) - -export const useRecommendations = () => { - return useWebflowAPI(RECOMMENDATIONS.key, RECOMMENDATIONS.collectionId) +const getCollectionById = async (collectionId: string) => { + const { data } = await axiosInstance.get>(`/collections/${collectionId}/items`) + return data.items } -export const useRecurringEvents = () => { - return useWebflowAPI(RECURRING_EVENTS.key, RECURRING_EVENTS.collectionId) -} +const webflowOptions = ( + collection: Collection, +) => + ({ + queryKey: [collection.key, collection.collectionId] as const, + queryFn: async () => getCollectionById(collection.collectionId), + } satisfies UseQueryOptions) -export const useSpeakers = () => { - return useWebflowAPI(SPEAKERS.key, SPEAKERS.collectionId) -} +const recommendationsOptions = webflowOptions(RECOMMENDATIONS) +export const useRecommendations = () => useQuery(recommendationsOptions) -export const useSpeakerNames = () => { - return useWebflowAPI(SPEAKER_NAMES.key, SPEAKER_NAMES.collectionId) -} +const recurringEventsOptions = webflowOptions(RECURRING_EVENTS) +export const useRecurringEvents = () => useQuery(recurringEventsOptions) -export const useSponsors = (): { isLoading: boolean; data: RawSponsor[] } => { - const { data: sponsors, isLoading } = useWebflowAPI( - SPONSORS.key, - SPONSORS.collectionId, - ) +const speakersOptions = webflowOptions(SPEAKERS) +export const useSpeakers = () => useQuery(speakersOptions) + +const speakerNamesOptions = webflowOptions(SPEAKER_NAMES) +export const useSpeakerNames = () => useQuery(speakerNamesOptions) + +const sponsorsOptions = webflowOptions(SPONSORS) +export const useSponsors = () => { + const { data: sponsors, ...rest } = useQuery(sponsorsOptions) const data = cleanedSponsors(sponsors) - return { isLoading, data } -} -export const useTalks = () => { - return useWebflowAPI(TALKS.key, TALKS.collectionId) + return { data, ...rest } } -export const useVenues = () => { - return useWebflowAPI(VENUES.key, VENUES.collectionId) -} +const talksOptions = webflowOptions(TALKS) +export const useTalks = () => useQuery(talksOptions) -export const useWorkshops = () => { - return useWebflowAPI(WORKSHOPS.key, WORKSHOPS.collectionId) -} +const venuesOptions = webflowOptions(VENUES) +export const useVenues = () => useQuery(venuesOptions) -export const useScheduledEvents = () => { - const { data: speakers, isLoading } = useSpeakers() - const { data: workshops } = useWorkshops() - const { data: recurringEvents } = useRecurringEvents() - const { data: talks } = useTalks() - const { data: scheduledEvents, ...rest } = useWebflowAPI( - SCHEDULE.key, - SCHEDULE.collectionId, - !isLoading && !!speakers && !!workshops && !!recurringEvents && !!talks, +const workshopsOptions = webflowOptions(WORKSHOPS) +export const useWorkshops = () => useQuery(workshopsOptions) + +const scheduledEventsOptions = webflowOptions(SCHEDULE) +const scheduledEventsQueries = [ + speakersOptions, + workshopsOptions, + recurringEventsOptions, + talksOptions, + scheduledEventsOptions, +] as const +export const prefetchScheduledEvents = async () => { + await Promise.all( + scheduledEventsQueries.map(async (query) => { + return queryClient.prefetchQuery(query) + }), ) +} +export const useScheduledEvents = () => { + const queries = useQueries({ + queries: scheduledEventsQueries, + }) + + const [speakers, workshops, recurringEvents, talks, scheduledEvents] = queries return { data: cleanedSchedule({ - recurringEvents, - scheduledEvents, - speakers: cleanedSpeakers(speakers), - talks: cleanedTalks({ speakers, talks }), - workshops: cleanedWorkshops(workshops, cleanedSpeakers(speakers)), + recurringEvents: recurringEvents.data, + scheduledEvents: scheduledEvents.data, + speakers: cleanedSpeakers(speakers.data), + talks: cleanedTalks({ speakers: speakers.data, talks: talks.data }), + workshops: cleanedWorkshops(workshops.data, cleanedSpeakers(speakers.data)), }), - ...rest, + refetch: async () => Promise.all(queries.map((query) => query.refetch())), + isLoading: queries.map((query) => query.isLoading).some((isLoading) => isLoading), + isRefetching: queries.map((query) => query.isFetching).some((isFetching) => isFetching), } } @@ -126,7 +134,7 @@ export const useScheduleScreenData = () => { title: "Conference Day 2", events: convertScheduleToScheduleCard(events, "Friday"), }, - ] as Schedule[], + ] satisfies Schedule[], refetch, } } diff --git a/app/services/api/webflow-consts.ts b/app/services/api/webflow-consts.ts index 20925245..44fcfddd 100644 --- a/app/services/api/webflow-consts.ts +++ b/app/services/api/webflow-consts.ts @@ -3,12 +3,12 @@ export const SITE_ID = "5ca38f35db5d2ea94aea469d" export const SPONSORS = { collectionId: "640a728fc24f8e73575fe189", key: "sponsors", -} +} as const export const SPEAKERS = { collectionId: "640a728fc24f8e94385fe188", key: "speakers", -} +} as const export const SPEAKER_NAMES = { collectionId: "640a728fc24f8e74d05fe18a", @@ -23,32 +23,44 @@ export const WORKSHOPS = { export const SCHEDULE = { collectionId: "640a728fc24f8e63325fe185", key: "schedule", -} +} as const export const PAST_TALKS = { collectionId: "640a728fc24f8e76ef5fe186", key: "pastTalks", -} +} as const export const RECURRING_EVENTS = { collectionId: "640a728fc24f8e85a75fe18c", key: "recurringEvents", -} +} as const export const TALKS = { collectionId: "640a728fc24f8e31ee5fe18e", key: "talks", -} +} as const export const VENUES = { collectionId: "640a728fc24f8e553c5fe18d", key: "venues", -} +} as const export const RECOMMENDATIONS = { collectionId: "640a728fc24f8e083b5fe18f", key: "recommendations", -} +} as const + +export type CollectionConst = + | typeof SPONSORS + | typeof SPEAKERS + | typeof SPEAKER_NAMES + | typeof WORKSHOPS + | typeof SCHEDULE + | typeof PAST_TALKS + | typeof RECURRING_EVENTS + | typeof TALKS + | typeof VENUES + | typeof RECOMMENDATIONS // [NOTE] these keys probably have to change when webflow is updated // `/collections/${collectionId}` api will the keys diff --git a/package.json b/package.json index bc453440..18b07c03 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "mocha": "6", "patch-package": "6.4.7", "postinstall-prepare": "1.0.1", - "prettier": "2.6.2", + "prettier": "2.8.7", "query-string": "^7.0.1", "react-devtools-core": "4.24.7", "reactotron-core-client": "^2.8.10", diff --git a/yarn.lock b/yarn.lock index 96c5b308..8ba1f841 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11621,10 +11621,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prettier@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" - integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== +prettier@2.8.7: + version "2.8.7" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450" + integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw== pretty-bytes@5.6.0: version "5.6.0"