From 7b694fd860d165296e1aebd4420d97d77f7681fa Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 30 Apr 2024 18:15:48 +0100 Subject: [PATCH] [Clipclops] Use API data for clipclop list (#3769) * use real API * remove extra tab icon * messages list web layout + style improvements * use style's text color for input * make new chat button way more obvious --------- Co-authored-by: Hailey --- src/components/dms/NewChat.tsx | 9 +- .../Messages/Conversation/MessageInput.tsx | 2 +- src/screens/Messages/List/index.tsx | 276 +++++++++++------- src/screens/Messages/Temp/query/query.ts | 31 +- src/view/shell/bottom-bar/BottomBarWeb.tsx | 10 - 5 files changed, 204 insertions(+), 124 deletions(-) diff --git a/src/components/dms/NewChat.tsx b/src/components/dms/NewChat.tsx index bbe118f045..86d421ebad 100644 --- a/src/components/dms/NewChat.tsx +++ b/src/components/dms/NewChat.tsx @@ -23,8 +23,13 @@ import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '../icons/Envelope' import {ListMaybePlaceholder} from '../Lists' import {Text} from '../Typography' -export function NewChat({onNewChat}: {onNewChat: (chatId: string) => void}) { - const control = Dialog.useDialogControl() +export function NewChat({ + control, + onNewChat, +}: { + control: Dialog.DialogControlProps + onNewChat: (chatId: string) => void +}) { const t = useTheme() const {_} = useLingui() diff --git a/src/screens/Messages/Conversation/MessageInput.tsx b/src/screens/Messages/Conversation/MessageInput.tsx index bd73594cee..3a3ce38f66 100644 --- a/src/screens/Messages/Conversation/MessageInput.tsx +++ b/src/screens/Messages/Conversation/MessageInput.tsx @@ -42,7 +42,7 @@ export function MessageInput({ value={message} onChangeText={setMessage} placeholder="Write a message" - style={[a.flex_1, a.text_sm, a.px_sm]} + style={[a.flex_1, a.text_sm, a.px_sm, t.atoms.text]} onSubmitEditing={onSubmit} onFocus={onFocus} onBlur={onBlur} diff --git a/src/screens/Messages/List/index.tsx b/src/screens/Messages/List/index.tsx index ff4e8e83ec..2dd406fe65 100644 --- a/src/screens/Messages/List/index.tsx +++ b/src/screens/Messages/List/index.tsx @@ -1,9 +1,10 @@ +/* eslint-disable react/prop-types */ + import React, {useCallback, useMemo, useState} from 'react' import {View} from 'react-native' -import {msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {NativeStackScreenProps} from '@react-navigation/native-stack' -import {useInfiniteQuery} from '@tanstack/react-query' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import {MessagesTabNavigatorParams} from '#/lib/routes/types' @@ -14,19 +15,26 @@ import {useAgent} from '#/state/session' import {List} from '#/view/com/util/List' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {ViewHeader} from '#/view/com/util/ViewHeader' -import {useTheme} from '#/alf' +import {useBreakpoints, useTheme} from '#/alf' import {atoms as a} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {DialogControlProps, useDialogControl} from '#/components/Dialog' +import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '#/components/icons/Envelope' import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider' import {Link} from '#/components/Link' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' import {Text} from '#/components/Typography' +import * as TempDmChatDefs from '#/temp/dm/defs' import {NewChat} from '../../../components/dms/NewChat' import {ClipClopGate} from '../gate' +import {useListChats} from '../Temp/query/query' type Props = NativeStackScreenProps export function MessagesListScreen({navigation}: Props) { const {_} = useLingui() const t = useTheme() + const newChatControl = useDialogControl() + const {gtMobile} = useBreakpoints() const renderButton = useCallback(() => { return ( @@ -50,13 +58,13 @@ export function MessagesListScreen({navigation}: Props) { fetchNextPage, error, refetch, - } = usePlaceholderConversations() + } = useListChats() const isError = !!error const conversations = useMemo(() => { if (data?.pages) { - return data.pages.flat() + return data.pages.flatMap(page => page.chats) } return [] }, [data]) @@ -86,6 +94,14 @@ export function MessagesListScreen({navigation}: Props) { [navigation], ) + const onNavigateToSettings = useCallback(() => { + navigation.navigate('MessagesSettings') + }, [navigation]) + + const renderItem = useCallback(({item}: {item: TempDmChatDefs.ChatView}) => { + return + }, []) + const gate = useGate() if (!gate('dms')) return @@ -102,73 +118,35 @@ export function MessagesListScreen({navigation}: Props) { errorMessage={cleanError(error)} onRetry={isError ? refetch : undefined} /> - + ) } return ( - - + {!gtMobile && ( + + )} + { - return ( - - - - - - - {item.profile.displayName || item.profile.handle} - {' '} - - @{item.profile.handle} - - - {item.unread && ( - - )} - - - {item.lastMessage} - - - - ) - }} - keyExtractor={item => item.profile.did} + renderItem={renderItem} + keyExtractor={item => item.id} refreshing={isPTRing} onRefresh={onRefresh} onEndReached={onEndReached} + ListHeaderComponent={ + + } ListFooterComponent={ ) } -function usePlaceholderConversations() { +function ChatListItem({chat}: {chat: TempDmChatDefs.ChatView}) { + const t = useTheme() + const {_} = useLingui() const {getAgent} = useAgent() - return useInfiniteQuery({ - queryKey: ['messages'], - queryFn: async () => { - const people = await getAgent().getProfiles({actors: PLACEHOLDER_PEOPLE}) - return people.data.profiles.map(profile => ({ - profile, - unread: Math.random() > 0.5, - lastMessage: getRandomPost(), - })) - }, - initialPageParam: undefined, - getNextPageParam: () => undefined, - }) -} - -const PLACEHOLDER_PEOPLE = [ - 'pfrazee.com', - 'haileyok.com', - 'danabra.mov', - 'esb.lol', - 'samuel.bsky.team', -] - -function getRandomPost() { - const num = Math.floor(Math.random() * 10) - switch (num) { - case 0: - return 'hello' - case 1: - return 'lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua' - case 2: - return 'banger post' - case 3: - return 'lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua' - case 4: - return 'lol look at this bug' - case 5: - return 'wow' - case 6: - return "that's pretty cool, wow!" - case 7: - return 'I think this is a bug' - case 8: - return 'Hello World!' - case 9: - return 'DMs when???' - default: - return 'this is unlikely' + let lastMessage = _(msg`No messages yet`) + if (TempDmChatDefs.isMessageView(chat.lastMessage)) { + lastMessage = chat.lastMessage.text } + + const otherUser = chat.members.find( + member => member.did !== getAgent().session?.did, + ) + + if (!otherUser) { + return null + } + + return ( + + {({hovered, pressed}) => ( + + + + + + + 0 && a.font_bold]}> + {otherUser.displayName || otherUser.handle} + {' '} + + @{otherUser.handle} + + + + {lastMessage} + + + {chat.unreadCount > 0 && ( + + )} + + )} + + ) +} + +function DesktopHeader({ + newChatControl, + onNavigateToSettings, +}: { + newChatControl: DialogControlProps + onNavigateToSettings: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const {gtMobile, gtTablet} = useBreakpoints() + + if (!gtMobile) { + return null + } + + return ( + + + Messages + + + + {gtTablet && ( + + )} + + + ) } diff --git a/src/screens/Messages/Temp/query/query.ts b/src/screens/Messages/Temp/query/query.ts index 26f9e625fb..d207f04af2 100644 --- a/src/screens/Messages/Temp/query/query.ts +++ b/src/screens/Messages/Temp/query/query.ts @@ -1,4 +1,9 @@ -import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query' +import { + useInfiniteQuery, + useMutation, + useQuery, + useQueryClient, +} from '@tanstack/react-query' import {useAgent} from '#/state/session' import * as TempDmChatDefs from '#/temp/dm/defs' @@ -6,6 +11,7 @@ import * as TempDmChatGetChat from '#/temp/dm/getChat' import * as TempDmChatGetChatForMembers from '#/temp/dm/getChatForMembers' import * as TempDmChatGetChatLog from '#/temp/dm/getChatLog' import * as TempDmChatGetChatMessages from '#/temp/dm/getChatMessages' +import * as TempDmChatListChats from '#/temp/dm/listChats' import {useDmServiceUrlStorage} from '../useDmServiceUrlStorage' /** @@ -250,3 +256,26 @@ export function useGetChatFromMembers({ onError, }) } + +export function useListChats() { + const headers = useHeaders() + const {serviceUrl} = useDmServiceUrlStorage() + + return useInfiniteQuery({ + queryKey: ['chats'], + queryFn: async ({pageParam}) => { + const response = await fetch( + `${serviceUrl}/xrpc/temp.dm.listChats${ + pageParam ? `?cursor=${pageParam}` : '' + }`, + {headers}, + ) + + if (!response.ok) throw new Error('Failed to fetch chats') + + return (await response.json()) as TempDmChatListChats.OutputSchema + }, + initialPageParam: undefined as string | undefined, + getNextPageParam: lastPage => lastPage.cursor, + }) +} diff --git a/src/view/shell/bottom-bar/BottomBarWeb.tsx b/src/view/shell/bottom-bar/BottomBarWeb.tsx index d8deaf6960..8b316faa5e 100644 --- a/src/view/shell/bottom-bar/BottomBarWeb.tsx +++ b/src/view/shell/bottom-bar/BottomBarWeb.tsx @@ -122,16 +122,6 @@ export function BottomBarWeb() { ) }} - - {() => { - return ( - - ) - }} - {gate('dms') && ( {({isActive}) => {