diff --git a/expo/features/feed/context/FeedContext.tsx b/expo/features/feed/context/FeedContext.tsx new file mode 100644 index 00000000..1cda9a84 --- /dev/null +++ b/expo/features/feed/context/FeedContext.tsx @@ -0,0 +1,181 @@ +import { + FeedContextQuery, + FeedContextQuery$data, + HPAssetType +} from '@hpapp/features/feed/context/__generated__/FeedContextQuery.graphql'; +import { FeedContextQueryFragmentQuery } from '@hpapp/features/feed/context/__generated__/FeedContextQueryFragmentQuery.graphql'; +import { + FeedContextQuery_helloproject_query_feed$data, + FeedContextQuery_helloproject_query_feed$key +} from '@hpapp/features/feed/context/__generated__/FeedContextQuery_helloproject_query_feed.graphql'; +import * as date from '@hpapp/foundation/date'; +import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; +import { fetchQuery, graphql, usePaginationFragment, useRelayEnvironment } from 'react-relay'; +import { usePaginationFragmentHookType } from 'react-relay/relay-hooks/usePaginationFragment'; + +const NUM_FEED_ITEMS_PER_LOAD = 20; +const DAYS_TO_CALCULATE_MIN_POST_AT_FOR_TAGGEING = 3 * date.N_DAYS; + +const FeedContextQueryGraphQL = graphql` + query FeedContextQuery($params: HPFeedQueryParamsInput!, $first: Int, $after: Cursor) { + helloproject { + ...FeedContextQuery_helloproject_query_feed + } + } +`; + +const FeedContextQueryFragmentGraphQL = graphql` + fragment FeedContextQuery_helloproject_query_feed on HelloProjectQuery + @refetchable(queryName: "FeedContextQueryFragmentQuery") { + feed(params: $params, first: $first, after: $after) @connection(key: "FeedContextQuery_helloproject_query_feed") { + edges { + node { + id + ...FeedListItemFragment + } + } + } + } +`; + +type HPFeedItem = NonNullable< + NonNullable['edges']>[number]>['node'] +>; + +type FeedQueryParams = { + useMemberTaggings?: boolean; + memberIDs: string[]; + assetTypes: HPAssetType[]; +}; + +type FeedContextProviderProps = { + children: React.ReactElement; +} & FeedQueryParams; + +type FeedContextModel = { + data: HPFeedItem[] | null; + isLoading: boolean; + hasNext: boolean; + reload: () => void; + loadNext: () => void; +}; + +function createFeedContext(): [(props: FeedContextProviderProps) => JSX.Element, () => FeedContextModel] { + const feedContext = createContext({ + data: null, + isLoading: false, + hasNext: false, + reload: () => {}, + loadNext: () => {} + }); + + function FeedContextProvider({ children, assetTypes, memberIDs, useMemberTaggings }: FeedContextProviderProps) { + // TODO: #28 Revisit Tagged Feed Feature + // We use 30 days window when fetching tagged feed to get the items without timeout. + // but this prevents users from loading items older than 30 days. + const minPostAt = useMemberTaggings + ? new Date(date.getToday().getTime() - DAYS_TO_CALCULATE_MIN_POST_AT_FOR_TAGGEING).toISOString() + : null; + // TODO: #52 Revisit the use of Relay and Suspense + // We currently don't use usePreloadedQuery or useLazyLoadQuery since it causes suspense fallback, + // which do not support concurrent rendering and it is hard to implement "Pull To Refresh" by VirtualizedList + // components such as FlatList, SectionList, ...etc. + // We intentionally use fetchQuery() with 'isLoading' state control for "Pull To Refresh". + const env = useRelayEnvironment(); + const [isLoading, setIsLoading] = useState(true); + const [fetchCount, setFetchCount] = useState(0); + const [data, setData] = useState(null); + useEffect(() => { + (async () => { + setIsLoading(true); + const result = await fetchQuery(env, FeedContextQueryGraphQL, { + first: NUM_FEED_ITEMS_PER_LOAD, + params: { + assetTypes, + memberIDs, + useMemberTaggings, + minPostAt + } + }).toPromise(); + setData(result!); + setIsLoading(false); + })(); + }, [fetchCount, assetTypes, memberIDs, useMemberTaggings, minPostAt, env]); + const reload = () => { + setFetchCount(fetchCount + 1); + }; + if (data === null) { + return ( + + {children} + + ); + } + return ( + + {children} + + ); + } + function FeedContextPaginationRenderer({ + children, + isLoading, + reload, + fragment + }: { + children: React.ReactElement; + isLoading: boolean; + reload: () => void; + fragment: FeedContextQuery$data; + }) { + const data = usePaginationFragment( + FeedContextQueryFragmentGraphQL, + fragment.helloproject! + ); + return ( + + {children} + + ); + } + + function FeedContextRenderer({ + children, + isLoading, + reload, + data + }: { + children: React.ReactElement; + isLoading: boolean; + reload: () => void; + data: usePaginationFragmentHookType< + FeedContextQueryFragmentQuery, + FeedContextQuery_helloproject_query_feed$key, + FeedContextQuery_helloproject_query_feed$data + > | null; + }) { + const ctxValue = useMemo(() => { + return { + data: data?.data.feed?.edges?.map((e) => e!.node!) ?? null, + isLoading, + hasNext: data?.hasNext ?? false, + reload, + loadNext: () => { + if (data?.hasNext) { + data.loadNext(NUM_FEED_ITEMS_PER_LOAD); + } + } + }; + }, [data]); + return {children}; + } + + function useFeed() { + const value = useContext(feedContext); + return value; + } + + return [FeedContextProvider, useFeed]; +} + +export { createFeedContext, HPFeedItem, HPAssetType, FeedContextModel }; diff --git a/expo/features/feed/__generated__/useFeedFeedQuery.graphql.ts b/expo/features/feed/context/__generated__/FeedContextQuery.graphql.ts similarity index 84% rename from expo/features/feed/__generated__/useFeedFeedQuery.graphql.ts rename to expo/features/feed/context/__generated__/FeedContextQuery.graphql.ts index 0fb0b3f7..b61d006f 100644 --- a/expo/features/feed/__generated__/useFeedFeedQuery.graphql.ts +++ b/expo/features/feed/context/__generated__/FeedContextQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<36fabcd9104b2325d880a87aa1cee387>> + * @generated SignedSource<<4dc1d5445174582f0b27801f41f55bbb>> * @lightSyntaxTransform * @nogrep */ @@ -17,19 +17,19 @@ export type HPFeedQueryParamsInput = { minPostAt?: string | null; useMemberTaggings?: boolean | null; }; -export type useFeedFeedQuery$variables = { +export type FeedContextQuery$variables = { after?: any | null; first?: number | null; params: HPFeedQueryParamsInput; }; -export type useFeedFeedQuery$data = { +export type FeedContextQuery$data = { readonly helloproject: { - readonly " $fragmentSpreads": FragmentRefs<"useFeedQuery_helloproject_query_feed">; + readonly " $fragmentSpreads": FragmentRefs<"FeedContextQuery_helloproject_query_feed">; }; }; -export type useFeedFeedQuery = { - response: useFeedFeedQuery$data; - variables: useFeedFeedQuery$variables; +export type FeedContextQuery = { + response: FeedContextQuery$data; + variables: FeedContextQuery$variables; }; const node: ConcreteRequest = (function(){ @@ -91,7 +91,7 @@ return { ], "kind": "Fragment", "metadata": null, - "name": "useFeedFeedQuery", + "name": "FeedContextQuery", "selections": [ { "alias": null, @@ -104,7 +104,7 @@ return { { "args": null, "kind": "FragmentSpread", - "name": "useFeedQuery_helloproject_query_feed" + "name": "FeedContextQuery_helloproject_query_feed" } ], "storageKey": null @@ -121,7 +121,7 @@ return { (v0/*: any*/) ], "kind": "Operation", - "name": "useFeedFeedQuery", + "name": "FeedContextQuery", "selections": [ { "alias": null, @@ -292,7 +292,7 @@ return { "params" ], "handle": "connection", - "key": "FeedQuery_helloproject_query_feed", + "key": "FeedContextQuery_helloproject_query_feed", "kind": "LinkedHandle", "name": "feed" }, @@ -303,16 +303,16 @@ return { ] }, "params": { - "cacheID": "8e271ec0e07a4452a06a0521ffd59b4d", + "cacheID": "d5c3ccae2fdda3c342091d9ce203c534", "id": null, "metadata": {}, - "name": "useFeedFeedQuery", + "name": "FeedContextQuery", "operationKind": "query", - "text": "query useFeedFeedQuery(\n $params: HPFeedQueryParamsInput!\n $first: Int\n $after: Cursor\n) {\n helloproject {\n ...useFeedQuery_helloproject_query_feed\n id\n }\n}\n\nfragment FeedListItemFragment on HPFeedItem {\n id\n title\n sourceID\n sourceURL\n imageURL\n assetType\n postAt\n ownerMember {\n id\n key\n }\n taggedMembers {\n id\n key\n }\n ...FeedListItemViewHistoryIconFragment\n}\n\nfragment FeedListItemViewHistoryIconFragment on HPFeedItem {\n myViewHistory {\n id\n isFavorite\n }\n}\n\nfragment useFeedQuery_helloproject_query_feed on HelloProjectQuery {\n feed(params: $params, first: $first, after: $after) {\n edges {\n node {\n id\n ...FeedListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n" + "text": "query FeedContextQuery(\n $params: HPFeedQueryParamsInput!\n $first: Int\n $after: Cursor\n) {\n helloproject {\n ...FeedContextQuery_helloproject_query_feed\n id\n }\n}\n\nfragment FeedContextQuery_helloproject_query_feed on HelloProjectQuery {\n feed(params: $params, first: $first, after: $after) {\n edges {\n node {\n id\n ...FeedListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment FeedListItemFragment on HPFeedItem {\n id\n title\n sourceID\n sourceURL\n imageURL\n assetType\n postAt\n ownerMember {\n id\n key\n }\n taggedMembers {\n id\n key\n }\n ...FeedListItemViewHistoryIconFragment\n}\n\nfragment FeedListItemViewHistoryIconFragment on HPFeedItem {\n myViewHistory {\n id\n isFavorite\n }\n}\n" } }; })(); -(node as any).hash = "ca31d7a1c2ed72859f64b0631ff65e83"; +(node as any).hash = "7bcde21bf4d8d7fb5bbcf3ee35ca0489"; export default node; diff --git a/expo/features/feed/__generated__/useFeedQueryFragmentQuery.graphql.ts b/expo/features/feed/context/__generated__/FeedContextQueryFragmentQuery.graphql.ts similarity index 84% rename from expo/features/feed/__generated__/useFeedQueryFragmentQuery.graphql.ts rename to expo/features/feed/context/__generated__/FeedContextQueryFragmentQuery.graphql.ts index fccfd229..08672205 100644 --- a/expo/features/feed/__generated__/useFeedQueryFragmentQuery.graphql.ts +++ b/expo/features/feed/context/__generated__/FeedContextQueryFragmentQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<4cc8299415c0847531ca3ab4a1076020>> + * @generated SignedSource<<910b9c9c15be55f6c5d275ee9e0e707a>> * @lightSyntaxTransform * @nogrep */ @@ -17,20 +17,20 @@ export type HPFeedQueryParamsInput = { minPostAt?: string | null; useMemberTaggings?: boolean | null; }; -export type useFeedQueryFragmentQuery$variables = { +export type FeedContextQueryFragmentQuery$variables = { after?: any | null; first?: number | null; id: string; params: HPFeedQueryParamsInput; }; -export type useFeedQueryFragmentQuery$data = { +export type FeedContextQueryFragmentQuery$data = { readonly node: { - readonly " $fragmentSpreads": FragmentRefs<"useFeedQuery_helloproject_query_feed">; + readonly " $fragmentSpreads": FragmentRefs<"FeedContextQuery_helloproject_query_feed">; } | null; }; -export type useFeedQueryFragmentQuery = { - response: useFeedQueryFragmentQuery$data; - variables: useFeedQueryFragmentQuery$variables; +export type FeedContextQueryFragmentQuery = { + response: FeedContextQueryFragmentQuery$data; + variables: FeedContextQueryFragmentQuery$variables; }; const node: ConcreteRequest = (function(){ @@ -112,7 +112,7 @@ return { ], "kind": "Fragment", "metadata": null, - "name": "useFeedQueryFragmentQuery", + "name": "FeedContextQueryFragmentQuery", "selections": [ { "alias": null, @@ -125,7 +125,7 @@ return { { "args": null, "kind": "FragmentSpread", - "name": "useFeedQuery_helloproject_query_feed" + "name": "FeedContextQuery_helloproject_query_feed" } ], "storageKey": null @@ -143,7 +143,7 @@ return { (v2/*: any*/) ], "kind": "Operation", - "name": "useFeedQueryFragmentQuery", + "name": "FeedContextQueryFragmentQuery", "selections": [ { "alias": null, @@ -313,7 +313,7 @@ return { "params" ], "handle": "connection", - "key": "FeedQuery_helloproject_query_feed", + "key": "FeedContextQuery_helloproject_query_feed", "kind": "LinkedHandle", "name": "feed" } @@ -327,16 +327,16 @@ return { ] }, "params": { - "cacheID": "230ea689d4104853ac886d6b21abd598", + "cacheID": "b8f9d84b43935a019ada7da8ab130469", "id": null, "metadata": {}, - "name": "useFeedQueryFragmentQuery", + "name": "FeedContextQueryFragmentQuery", "operationKind": "query", - "text": "query useFeedQueryFragmentQuery(\n $after: Cursor\n $first: Int\n $params: HPFeedQueryParamsInput!\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...useFeedQuery_helloproject_query_feed\n id\n }\n}\n\nfragment FeedListItemFragment on HPFeedItem {\n id\n title\n sourceID\n sourceURL\n imageURL\n assetType\n postAt\n ownerMember {\n id\n key\n }\n taggedMembers {\n id\n key\n }\n ...FeedListItemViewHistoryIconFragment\n}\n\nfragment FeedListItemViewHistoryIconFragment on HPFeedItem {\n myViewHistory {\n id\n isFavorite\n }\n}\n\nfragment useFeedQuery_helloproject_query_feed on HelloProjectQuery {\n feed(params: $params, first: $first, after: $after) {\n edges {\n node {\n id\n ...FeedListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n" + "text": "query FeedContextQueryFragmentQuery(\n $after: Cursor\n $first: Int\n $params: HPFeedQueryParamsInput!\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...FeedContextQuery_helloproject_query_feed\n id\n }\n}\n\nfragment FeedContextQuery_helloproject_query_feed on HelloProjectQuery {\n feed(params: $params, first: $first, after: $after) {\n edges {\n node {\n id\n ...FeedListItemFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n id\n}\n\nfragment FeedListItemFragment on HPFeedItem {\n id\n title\n sourceID\n sourceURL\n imageURL\n assetType\n postAt\n ownerMember {\n id\n key\n }\n taggedMembers {\n id\n key\n }\n ...FeedListItemViewHistoryIconFragment\n}\n\nfragment FeedListItemViewHistoryIconFragment on HPFeedItem {\n myViewHistory {\n id\n isFavorite\n }\n}\n" } }; })(); -(node as any).hash = "4310868218d058d88bb4e8e7488033d1"; +(node as any).hash = "8086d44e7fab8a475bc632ea014a3594"; export default node; diff --git a/expo/features/feed/__generated__/useFeedQuery_helloproject_query_feed.graphql.ts b/expo/features/feed/context/__generated__/FeedContextQuery_helloproject_query_feed.graphql.ts similarity index 84% rename from expo/features/feed/__generated__/useFeedQuery_helloproject_query_feed.graphql.ts rename to expo/features/feed/context/__generated__/FeedContextQuery_helloproject_query_feed.graphql.ts index 8ca6a9ed..569a5000 100644 --- a/expo/features/feed/__generated__/useFeedQuery_helloproject_query_feed.graphql.ts +++ b/expo/features/feed/context/__generated__/FeedContextQuery_helloproject_query_feed.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<942073a66c3318958fbabcb5998a571e>> + * @generated SignedSource<<416932390cff358a0f0d66d0006f02da>> * @lightSyntaxTransform * @nogrep */ @@ -10,7 +10,7 @@ import { ReaderFragment, RefetchableFragment } from 'relay-runtime'; import { FragmentRefs } from "relay-runtime"; -export type useFeedQuery_helloproject_query_feed$data = { +export type FeedContextQuery_helloproject_query_feed$data = { readonly feed: { readonly edges: ReadonlyArray<{ readonly node: { @@ -20,11 +20,11 @@ export type useFeedQuery_helloproject_query_feed$data = { } | null> | null; } | null; readonly id: string; - readonly " $fragmentType": "useFeedQuery_helloproject_query_feed"; + readonly " $fragmentType": "FeedContextQuery_helloproject_query_feed"; }; -export type useFeedQuery_helloproject_query_feed$key = { - readonly " $data"?: useFeedQuery_helloproject_query_feed$data; - readonly " $fragmentSpreads": FragmentRefs<"useFeedQuery_helloproject_query_feed">; +export type FeedContextQuery_helloproject_query_feed$key = { + readonly " $data"?: FeedContextQuery_helloproject_query_feed$data; + readonly " $fragmentSpreads": FragmentRefs<"FeedContextQuery_helloproject_query_feed">; }; const node: ReaderFragment = (function(){ @@ -75,11 +75,11 @@ return { "fragmentPathInResult": [ "node" ], - "operation": require('./useFeedQueryFragmentQuery.graphql'), + "operation": require('./FeedContextQueryFragmentQuery.graphql'), "identifierField": "id" } }, - "name": "useFeedQuery_helloproject_query_feed", + "name": "FeedContextQuery_helloproject_query_feed", "selections": [ { "alias": "feed", @@ -92,7 +92,7 @@ return { ], "concreteType": "HPFeedItemConnection", "kind": "LinkedField", - "name": "__FeedQuery_helloproject_query_feed_connection", + "name": "__FeedContextQuery_helloproject_query_feed_connection", "plural": false, "selections": [ { @@ -172,6 +172,6 @@ return { }; })(); -(node as any).hash = "4310868218d058d88bb4e8e7488033d1"; +(node as any).hash = "8086d44e7fab8a475bc632ea014a3594"; export default node; diff --git a/expo/features/feed/useFeed.ts b/expo/features/feed/useFeed.ts deleted file mode 100644 index e97462f1..00000000 --- a/expo/features/feed/useFeed.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { FeedQuery, HPAssetType } from '@hpapp/features/feed/__generated__/FeedQuery.graphql'; -import { FeedQueryFragmentQuery } from '@hpapp/features/feed/__generated__/FeedQueryFragmentQuery.graphql'; -import { FeedQuery_helloproject_query_feed$key } from '@hpapp/features/feed/__generated__/FeedQuery_helloproject_query_feed.graphql'; -import * as date from '@hpapp/foundation/date'; -import { graphql, useLazyLoadQuery, usePaginationFragment } from 'react-relay'; - -const useFeedQueryGraphQL = graphql` - query useFeedFeedQuery($params: HPFeedQueryParamsInput!, $first: Int, $after: Cursor) { - helloproject { - ...useFeedQuery_helloproject_query_feed - } - } -`; - -const FeedQueryFragmentGraphQL = graphql` - fragment useFeedQuery_helloproject_query_feed on HelloProjectQuery - @refetchable(queryName: "useFeedQueryFragmentQuery") { - feed(params: $params, first: $first, after: $after) @connection(key: "FeedQuery_helloproject_query_feed") { - edges { - node { - id - ...FeedListItemFragment - } - } - } - } -`; - -export type FeedProps = { - assetTypes: HPAssetType[]; - numFetch: number; - memberIds: string[]; - useMemberTaggings: boolean; -}; - -const minPostAtForTaggedFeed = 3 * date.N_DAYS; - -export default function useFeed({ numFetch, memberIds, assetTypes, useMemberTaggings }: FeedProps) { - // TODO: #28 Revisit Tagged Feed Feature - // We use 30 days window when fetching tagged feed to get the items without timeout. - // but this prevents users from loading items older than 30 days. - const minPostAt = useMemberTaggings - ? new Date(date.getToday().getTime() - minPostAtForTaggedFeed).toISOString() - : null; - const data = useLazyLoadQuery(useFeedQueryGraphQL, { - first: numFetch, - params: { - assetTypes, - memberIDs: memberIds, - useMemberTaggings, - minPostAt - } - }); - const fragment = usePaginationFragment( - FeedQueryFragmentGraphQL, - data.helloproject - ); - return fragment; -} diff --git a/expo/features/home/HomeTab.tsx b/expo/features/home/HomeTab.tsx index 86d17637..a5c11683 100644 --- a/expo/features/home/HomeTab.tsx +++ b/expo/features/home/HomeTab.tsx @@ -1,5 +1,20 @@ +import { HomeTabFeedProvider } from '@hpapp/features/home/HomeTabFeed'; import HomeTabSectionList from '@hpapp/features/home/HomeTabSectionList'; +import { useMe } from '@hpapp/features/root/protected/context'; +import useLocalUserConfig from '@hpapp/features/settings/context/useLocalUserConfig'; export default function HomeTab() { - return ; + const [config] = useLocalUserConfig(); + const followings = useMe() + .followings.filter((f) => f.type !== 'unfollow') + .map((f) => f.memberId); + return ( + + + + ); } diff --git a/expo/features/home/HomeTabFeed.tsx b/expo/features/home/HomeTabFeed.tsx new file mode 100644 index 00000000..10f67c33 --- /dev/null +++ b/expo/features/home/HomeTabFeed.tsx @@ -0,0 +1,5 @@ +import { createFeedContext } from '@hpapp/features/feed/context/FeedContext'; + +const [HomeTabFeedProvider, useHomeTabFeed] = createFeedContext(); + +export { HomeTabFeedProvider, useHomeTabFeed }; diff --git a/expo/features/home/HomeTabSectionList.tsx b/expo/features/home/HomeTabSectionList.tsx index 9e0a5c6c..63e6704a 100644 --- a/expo/features/home/HomeTabSectionList.tsx +++ b/expo/features/home/HomeTabSectionList.tsx @@ -1,46 +1,54 @@ +import Loading from '@hpapp/features/common/components/Loading'; import HomeFeedSection from '@hpapp/features/feed/HomeFeedSection'; -import useFeed from '@hpapp/features/feed/useFeed'; +import { useHomeTabFeed } from '@hpapp/features/home/HomeTabFeed'; import { HomeTabSection } from '@hpapp/features/home/types'; -import { useMe } from '@hpapp/features/root/protected/context'; import { useColor } from '@hpapp/features/settings/context/theme'; -import useLocalUserConfig from '@hpapp/features/settings/context/useLocalUserConfig'; import { useUPFC } from '@hpapp/features/upfc/context'; import NextEventsSection from '@hpapp/features/upfc/home/NextEventsSection'; import PendingPaymentsSection from '@hpapp/features/upfc/home/PendingPaymentsSection'; import { useMemo } from 'react'; -import { SectionList } from 'react-native'; +import { RefreshControl, SectionList } from 'react-native'; export default function HomeTabSectionList() { const [color] = useColor('primary'); - const [config] = useLocalUserConfig(); - const followings = useMe() - .followings.filter((f) => f.type !== 'unfollow') - .map((f) => f.memberId); - const numFetch = followings.length > 10 ? followings.length + 10 : 15; const upfc = useUPFC(); - const feed = useFeed({ - numFetch, - assetTypes: ['ameblo', 'instagram', 'tiktok', 'twitter'], - memberIds: followings, - useMemberTaggings: config?.feedUseMemberTaggings ?? false - }); + const feed = useHomeTabFeed(); const sections: HomeTabSection[] = useMemo(() => { - return [ - new PendingPaymentsSection(color, upfc.data ?? []), - new NextEventsSection(color, upfc.data ?? []), - new HomeFeedSection((feed.data.feed?.edges ?? []).filter((edge) => edge?.node != null).map((edge) => edge!.node!)) - ]; - }, [upfc.data, feed]); + const list: HomeTabSection[] = []; + if (upfc.data !== null) { + list.push(new PendingPaymentsSection(color, upfc.data)); + list.push(new NextEventsSection(color, upfc.data)); + } + if (feed.data !== null) { + list.push(new HomeFeedSection(feed.data)); + } + return list; + }, [feed]); + const refreshing = feed.isLoading || upfc.isLoading; + if (sections.length === 0 && refreshing) { + return ; + } return ( - `hometabsectionlist-${index}`} - renderSectionHeader={({ section }) => { - return section.renderSectionHeader(); - }} - renderItem={(o) => { - return o.section.renderListItem(o); - }} - /> + <> + `hometabsectionlist-${index}`} + renderSectionHeader={({ section }) => { + return section.renderSectionHeader(); + }} + renderItem={(o) => { + return o.section.renderListItem(o); + }} + refreshControl={ + { + upfc.reload(); + feed.reload(); + }} + /> + } + /> + ); } diff --git a/expo/system/logging/Console.ts b/expo/system/logging/Console.ts index c7b78b43..6bb860fb 100644 --- a/expo/system/logging/Console.ts +++ b/expo/system/logging/Console.ts @@ -2,7 +2,7 @@ import { LogLevel, LogSink } from '@hpapp/system/logging/types'; import Constants from 'expo-constants'; -const defaultEvents: string[] = []; //'.*'; // '.*'; +const defaultEvents: string[] = ['^$']; //'.*'; // '.*'; const consoleEvents: RegExp[] = (Constants.expoConfig?.extra?.hpapp?.consoleEvents || [defaultEvents]).map( (re: string) => {