Skip to content

Commit

Permalink
Merge pull request #3397 from tloncorp/lb/native-channel-search
Browse files Browse the repository at this point in the history
mobile: channel search
  • Loading branch information
latter-bolden authored Apr 9, 2024
2 parents 5c944c0 + f84e971 commit 071aa35
Show file tree
Hide file tree
Showing 51 changed files with 1,039 additions and 87 deletions.
26 changes: 15 additions & 11 deletions apps/tlon-mobile/cosmos.imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,31 @@
import { RendererConfig, UserModuleWrappers } from 'react-cosmos-core';

import * as fixture0 from './src/App.fixture';
import * as fixture6 from './src/fixtures/Button.fixture';
import * as fixture5 from './src/fixtures/Channel.fixture';
import * as fixture4 from './src/fixtures/ChannelSwitcherSheet.fixture';
import * as fixture3 from './src/fixtures/GroupList.fixture';
import * as fixture2 from './src/fixtures/HeaderButton.fixture';
import * as fixture8 from './src/fixtures/Button.fixture';
import * as fixture7 from './src/fixtures/Channel.fixture';
import * as fixture6 from './src/fixtures/ChannelSwitcherSheet.fixture';
import * as fixture5 from './src/fixtures/GroupList.fixture';
import * as fixture4 from './src/fixtures/HeaderButton.fixture';
import * as fixture3 from './src/fixtures/Input.fixture';
import * as fixture2 from './src/fixtures/SearchBar.fixture';
import * as fixture1 from './src/fixtures/TlonButton.fixture';
import * as decorator0 from './src/fixtures/cosmos.decorator';

export const rendererConfig: RendererConfig = {
playgroundUrl: 'http://localhost:5000',
playgroundUrl: 'http://localhost:5001',
rendererUrl: null,
};

const fixtures = {
'src/App.fixture.tsx': { module: fixture0 },
'src/fixtures/TlonButton.fixture.tsx': { module: fixture1 },
'src/fixtures/HeaderButton.fixture.tsx': { module: fixture2 },
'src/fixtures/GroupList.fixture.tsx': { module: fixture3 },
'src/fixtures/ChannelSwitcherSheet.fixture.tsx': { module: fixture4 },
'src/fixtures/Channel.fixture.tsx': { module: fixture5 },
'src/fixtures/Button.fixture.tsx': { module: fixture6 },
'src/fixtures/SearchBar.fixture.tsx': { module: fixture2 },
'src/fixtures/Input.fixture.tsx': { module: fixture3 },
'src/fixtures/HeaderButton.fixture.tsx': { module: fixture4 },
'src/fixtures/GroupList.fixture.tsx': { module: fixture5 },
'src/fixtures/ChannelSwitcherSheet.fixture.tsx': { module: fixture6 },
'src/fixtures/Channel.fixture.tsx': { module: fixture7 },
'src/fixtures/Button.fixture.tsx': { module: fixture8 },
};

const decorators = {
Expand Down
15 changes: 10 additions & 5 deletions apps/tlon-mobile/src/components/AuthenticatedApp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sync } from '@tloncorp/shared';
import { QueryClient, QueryClientProvider } from '@tloncorp/shared/dist/api';
import { ZStack } from '@tloncorp/ui';
import { useEffect } from 'react';

Expand All @@ -15,6 +16,8 @@ export interface AuthenticatedAppProps {
initialNotificationPath?: string;
}

const queryClient = new QueryClient();

function AuthenticatedApp({ initialNotificationPath }: AuthenticatedAppProps) {
const { ship, shipUrl } = useShip();
useNotificationListener(initialNotificationPath);
Expand All @@ -39,10 +42,12 @@ export default function ConnectedAuthenticatedApp(
props: AuthenticatedAppProps
) {
return (
<WebviewPositionProvider>
<WebviewProvider>
<AuthenticatedApp {...props} />
</WebviewProvider>
</WebviewPositionProvider>
<QueryClientProvider client={queryClient}>
<WebviewPositionProvider>
<WebviewProvider>
<AuthenticatedApp {...props} />
</WebviewProvider>
</WebviewPositionProvider>
</QueryClientProvider>
);
}
5 changes: 5 additions & 0 deletions apps/tlon-mobile/src/fixtures/Button.fixture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ export default {
<Button.Text>Primary</Button.Text>
</Button>
),
text: () => (
<Button minimal>
<Button.Text>Text Button</Button.Text>
</Button>
),
};
18 changes: 18 additions & 0 deletions apps/tlon-mobile/src/fixtures/Input.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Icon } from '@tloncorp/ui';
import { Input } from '@tloncorp/ui/src/components/Input';

export default {
['Basic']: () => (
<Input size="$m">
<Input.Area placeholder="Enter details..." />
</Input>
),
['With Left Icon']: () => (
<Input>
<Input.Icon>
<Icon type="Face" />
</Input.Icon>
<Input.Area placeholder="Find pal" />
</Input>
),
};
10 changes: 10 additions & 0 deletions apps/tlon-mobile/src/fixtures/SearchBar.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SearchBar } from '@tloncorp/ui';

export default {
base: (
<SearchBar
onChangeQuery={() => {}}
placeholder="Search in Internet Cafe..."
/>
),
};
2 changes: 2 additions & 0 deletions apps/tlon-mobile/src/navigation/HomeStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, { useEffect } from 'react';
import { useWebviewPositionContext } from '../contexts/webview/position';
import { useScreenOptions } from '../hooks/useScreenOptions';
import ChannelScreen from '../screens/ChannelScreen';
import ChannelSearch from '../screens/ChannelSearchScreen';
import GroupsListScreen from '../screens/GroupsListScreen';
import type { HomeStackParamList, TabParamList } from '../types';

Expand Down Expand Up @@ -49,6 +50,7 @@ export const HomeStack = ({ navigation }: Props) => {
>
<Stack.Screen name="GroupsList" component={GroupsListScreen} />
<Stack.Screen name="Channel" component={ChannelScreen} />
<Stack.Screen name="ChannelSearch" component={ChannelSearch} />
</Stack.Navigator>
);
};
20 changes: 1 addition & 19 deletions apps/tlon-mobile/src/navigation/TabStack.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import type * as client from '@tloncorp/shared/dist/client';
import * as db from '@tloncorp/shared/dist/db';
import type { IconType } from '@tloncorp/ui';
import {
Expand All @@ -18,19 +17,6 @@ import { HomeStack } from './HomeStack';

const Tab = createBottomTabNavigator<TabParamList>();

function fallbackContact(id: string): client.Contact {
return {
id,
nickname: null,
bio: null,
status: null,
color: null,
avatarImage: null,
coverImage: null,
pinnedGroupIds: [],
};
}

export const TabStack = () => {
const { contactId } = useShip();
const { result: unreadCount } = db.useAllUnreadsCounts();
Expand Down Expand Up @@ -124,11 +110,7 @@ export const TabStack = () => {
function AvatarTabIcon({ id, focused }: { id: string; focused: boolean }) {
const { result: contact } = db.useContact({ id });
return (
<Avatar
contactId={id}
contact={contact ?? fallbackContact(id)}
opacity={focused ? 1 : 0.6}
/>
<Avatar contact={contact} contactId={id} opacity={focused ? 1 : 0.6} />
);
}

Expand Down
30 changes: 25 additions & 5 deletions apps/tlon-mobile/src/screens/ChannelScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,26 @@ type ChannelScreenProps = NativeStackScreenProps<HomeStackParamList, 'Channel'>;
export default function ChannelScreen(props: ChannelScreenProps) {
const [open, setOpen] = React.useState(false);
const [currentChannel, setCurrentChannel] = React.useState<db.Channel | null>(
null
props.route.params.channel ?? null
);
const { group } = props.route.params;
const {
result: groupWithRelations,
isLoading,
error,
} = db.useGroup({ id: group.id });

const { result: posts } = db.useChannelPosts({
channelId: currentChannel?.id ?? '',
});
const { result: aroundPosts } = db.useChannelPostsAround({
channelId: currentChannel?.id ?? '',
postId: props.route.params.selectedPost?.id ?? '',
});

const { result: contacts } = db.useContacts();
const { top, bottom } = useSafeAreaInsets();
const hasSelectedPost = !!props.route.params.selectedPost;

useEffect(() => {
if (groupWithRelations) {
Expand All @@ -44,12 +51,18 @@ export default function ChannelScreen(props: ChannelScreenProps) {
}, [error]);

useEffect(() => {
const syncChannel = async (id: string) => sync.syncChannel(id, Date.now());
const syncChannel = async (id: string) => {
if (props.route.params.selectedPost) {
sync.syncPostsAround(props.route.params.selectedPost);
} else {
sync.syncChannel(id, Date.now());
}
};

if (currentChannel) {
syncChannel(currentChannel.id);
}
}, [currentChannel]);
}, [currentChannel, props.route.params.selectedPost]);

if (isLoading || !groupWithRelations || !currentChannel) {
return null;
Expand All @@ -68,10 +81,17 @@ export default function ChannelScreen(props: ChannelScreenProps) {
}}
group={groupWithRelations ?? []}
contacts={contacts ?? []}
posts={posts}
posts={hasSelectedPost ? aroundPosts : posts}
selectedPost={
hasSelectedPost && aroundPosts?.length
? props.route.params.selectedPost?.id
: undefined
}
goBack={props.navigation.goBack}
goToChannels={() => setOpen(true)}
goToSearch={() => {}}
goToSearch={() =>
props.navigation.push('ChannelSearch', { channel: currentChannel })
}
/>
<ChannelSwitcherSheet
open={open}
Expand Down
81 changes: 81 additions & 0 deletions apps/tlon-mobile/src/screens/ChannelSearchScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import { useChannelSearch } from '@tloncorp/shared/dist';
import * as db from '@tloncorp/shared/dist/db';
import { XStack, YStack } from '@tloncorp/ui';
import { Button, SearchBar, SearchResults } from '@tloncorp/ui';
import { useCallback, useLayoutEffect, useState } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';

import type { HomeStackParamList } from '../types';

type ChannelSearchProps = NativeStackScreenProps<
HomeStackParamList,
'ChannelSearch'
>;

export default function ChannelSearch({
route,
navigation,
}: ChannelSearchProps) {
const { channel } = route.params;
const { result: group } = db.useGroupByChannel(channel.id);
const [query, setQuery] = useState('');
const { posts, loading, errored, hasMore, loadMore, searchedThroughDate } =
useChannelSearch(channel.id, query);

// handle full screen view without bottom nav, resets on dismout
useLayoutEffect(() => {
navigation.getParent()?.setOptions({
headerShown: false,
tabBarStyle: { display: 'none' },
});

return () => {
navigation.getParent()?.setOptions({
tabBarStyle: undefined,
});
};
}, [navigation]);

const navigateToPost = useCallback(
(post: db.PostWithRelations) => {
navigation.navigate('Channel', {
group: group!,
channel,
selectedPost: post,
});
},
[channel, group, navigation]
);

return (
<SafeAreaView edges={['top']} style={{ flex: 1 }}>
<YStack flex={1} paddingHorizontal="$l">
<XStack gap="$l">
<SearchBar
onChangeQuery={setQuery}
placeholder={`Search ${channel.title}`}
/>
<Button minimal onPress={() => navigation.pop()}>
<Button.Text>Cancel</Button.Text>
</Button>
</XStack>

<SearchResults
posts={posts ?? []}
navigateToPost={navigateToPost}
search={{
query,
loading,
errored,
hasMore,
loadMore,
searchComplete: !loading && !hasMore,
numResults: posts?.length ?? 0,
searchedThroughDate,
}}
/>
</YStack>
</SafeAreaView>
);
}
8 changes: 0 additions & 8 deletions apps/tlon-mobile/src/tamagui.d.ts

This file was deleted.

5 changes: 5 additions & 0 deletions apps/tlon-mobile/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ export type HomeStackParamList = {
GroupsList: undefined;
Channel: {
group: db.Group;
channel?: db.Channel;
selectedPost?: db.PostWithRelations;
};
ChannelSearch: {
channel: db.Channel;
};
};

Expand Down
3 changes: 2 additions & 1 deletion apps/tlon-mobile/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"module": "ESNext",
"moduleResolution": "Node",
"esModuleInterop": false,
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"types": ["../../packages/ui/src/tamagui.d.ts"]
}
}
3 changes: 2 additions & 1 deletion apps/tlon-web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"vite/client",
"vitest/globals",
"@testing-library/jest-dom",
"vite-plugin-pwa/react"
"vite-plugin-pwa/react",
"../../packages/ui/src/tamagui.d.ts"
],
"paths": {
"@/*": ["./src/*"]
Expand Down
Loading

0 comments on commit 071aa35

Please sign in to comment.