From a7815ef1809e0dfd11a97c9c0a7ed15f7459d5a7 Mon Sep 17 00:00:00 2001 From: labm1997 Date: Sat, 24 Apr 2021 20:32:48 -0300 Subject: [PATCH 1/4] Chat page and buttons to get into Chat page in Interested and Detail. Also, places where ChatAPI should be called were indicated using console.log --- package.json | 1 + src/constants/theme.ts | 6 + src/layouts/HeaderLayout/index.tsx | 13 +- src/pages/Animal/Details/index.tsx | 17 +- src/pages/Animal/Details/styles.ts | 5 +- src/pages/Animal/Interested/index.tsx | 10 +- src/pages/Chat/Chat/index.tsx | 237 ++++++++++++++++++++++++++ src/pages/Chat/Chat/styles.ts | 88 ++++++++++ src/routes.tsx | 6 + src/types/routes.ts | 7 + 10 files changed, 381 insertions(+), 9 deletions(-) create mode 100644 src/pages/Chat/Chat/index.tsx create mode 100644 src/pages/Chat/Chat/styles.ts diff --git a/package.json b/package.json index 4098f1a..82962ae 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "react-native": "~0.63.4", "react-native-gesture-handler": "^1.8.0", "react-native-get-random-values": "^1.6.0", + "react-native-gifted-chat": "^0.16.3", "react-native-image-picker": "^3.3.2", "react-native-paper": "^4.7.2", "react-native-reanimated": "^1.13.2", diff --git a/src/constants/theme.ts b/src/constants/theme.ts index f882733..de46d00 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -49,6 +49,12 @@ const Theme = { adoptionButton: '#FDCF58', floatingButton: '#FAFAFA', notificationCounter: '#D55', + chatTextInput: '#FFFFFF', + chatBackground: '#F1F2F2', + chatSendIcon: '#FFFFFF', + chatSendBall: '#88C9BF', + chatText: '#434343', + chatBubleUser: '#CFE9E5', }, named: { blue: '#007BFF', diff --git a/src/layouts/HeaderLayout/index.tsx b/src/layouts/HeaderLayout/index.tsx index 0806ba7..76d6562 100644 --- a/src/layouts/HeaderLayout/index.tsx +++ b/src/layouts/HeaderLayout/index.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { useNavigation } from '@react-navigation/native'; import Ionicons from 'react-native-vector-icons/Ionicons'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import { ScrollView } from 'react-native-gesture-handler'; import SideMenu from 'react-native-side-menu-updated'; @@ -12,7 +13,7 @@ import { Theme } from '../../constants'; import { styledComponents, IHeaderProps, ITitleProps } from './styles'; -type HeaderActions = 'back' | 'drawer' | 'share' | 'search'; +type HeaderActions = 'back' | 'drawer' | 'share' | 'search' | 'options'; interface IButtonAction { hidden?: boolean, @@ -100,6 +101,16 @@ export default function HeaderLayout({ /> ); + case 'options': + return ( + null}> + + + ); } }; diff --git a/src/pages/Animal/Details/index.tsx b/src/pages/Animal/Details/index.tsx index 8e75b01..3283776 100644 --- a/src/pages/Animal/Details/index.tsx +++ b/src/pages/Animal/Details/index.tsx @@ -75,7 +75,6 @@ export default function AnimalDetails() : JSX.Element { // Styled components. const { - AdoptionButtonWrapper, AnimalImage, ButtonText, ButtonTextStrong, @@ -286,7 +285,7 @@ export default function AnimalDetails() : JSX.Element { setLabelStyles(styles.secondaryLabel); setPageButtons( - + { resultInterestedIn ? 'Desistir da adoção' : 'Pretendo adotar' } - , + navigation.navigate('Chat', { + /* eslint-disable camelcase */ + title: owner.data()?.full_name, + targetUser: animalData.owner, + animal, + })} + > + Chat + + , ); setFloatingButton( diff --git a/src/pages/Animal/Details/styles.ts b/src/pages/Animal/Details/styles.ts index 21df941..d4e99f8 100644 --- a/src/pages/Animal/Details/styles.ts +++ b/src/pages/Animal/Details/styles.ts @@ -141,11 +141,12 @@ export const styledComponents = { // Styles. export const styles = { adoptionButton: { - alignItems: 'center', backgroundColor: Theme.elements.adoptionButton, borderRadius: '2px', height: '40px', - width: '232px', + marginLeft: '8px', + marginRight: '8px', + width: '148px', }, floatingButtonIcon: { diff --git a/src/pages/Animal/Interested/index.tsx b/src/pages/Animal/Interested/index.tsx index 0738eca..a9a61ab 100644 --- a/src/pages/Animal/Interested/index.tsx +++ b/src/pages/Animal/Interested/index.tsx @@ -151,8 +151,12 @@ const Interested = (): JSX.Element => { callback={(u: InterestedUser): void => { Alert.alert(u.userName, 'Selecione a ação', [ { - text: 'Cancelar', - onPress: () => null, + text: 'Chat', + onPress: () => navigation.navigate('Chat', { + title: user.userName, + targetUser: u.ref, + animal, + }), }, { text: 'Remover', @@ -176,7 +180,7 @@ const Interested = (): JSX.Element => { } }, }, - ]); + ], { cancelable: true }); }} /> )} diff --git a/src/pages/Chat/Chat/index.tsx b/src/pages/Chat/Chat/index.tsx new file mode 100644 index 0000000..04dab4d --- /dev/null +++ b/src/pages/Chat/Chat/index.tsx @@ -0,0 +1,237 @@ +import React, { + useCallback, useEffect, useLayoutEffect, useState, +} from 'react'; +import { setStatusBarBackgroundColor } from 'expo-status-bar'; +import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'; +import { + GiftedChat, InputToolbar, InputToolbarProps, Send, SendProps, MessageProps, IMessage, +} from 'react-native-gifted-chat'; +import MaterialIcons from 'react-native-vector-icons/MaterialIcons'; + +import HeaderLayout from '../../../layouts/HeaderLayout'; +import { Theme } from '../../../constants'; +import * as RouteTypes from '../../../types/routes'; +import { styledComponents, styles } from './styles'; + +const mock = [ + { + _id: 1, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(1), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 2, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(2), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 3, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(3), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 5, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(5), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 6, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(6), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 7, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(7), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 8, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(8), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 4, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(4), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 9, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(9), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 10, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(10), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 11, + text: 'Olá! Gostaria de adotar o seu gato!', + createdAt: new Date(11), + user: { + _id: 2, + name: 'React Native', + }, + }, + { + _id: 12, + text: 'Que maravilha, Marília! Você mora aqui em Brasília?', + createdAt: new Date(12), + user: { + _id: 1, + name: 'React Native', + }, + }, +]; + +export default (): JSX.Element => { + const navigation = useNavigation(); + const chatTitle = useRoute>().params?.title; + const animal = useRoute>().params?.animal; + const targetUser = useRoute>().params?.targetUser; + + useLayoutEffect(() => { + setStatusBarBackgroundColor(Theme.elements.statusBarPrimaryDark, false); + }, [navigation]); + + const [messages, setMessages] = useState([]); + + useEffect(() => { + // eslint-disable-next-line + console.log('================ CHAT PAGE ================'); + // eslint-disable-next-line + console.log('chatAPI.getChat(currentUser, targetUser, animal): ', targetUser.id, animal.id); + // eslint-disable-next-line + console.log('...then'); + // eslint-disable-next-line + console.log('chatAPI.loadMessages(chat, pageSize) if chat'); + setMessages(mock.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())); + }, [targetUser, animal]); + + const onSend = useCallback((newMessages = []) => { + // eslint-disable-next-line + console.log('chatAPI.pushPessages(chat, newMessages): ', newMessages); + setMessages((previousMessages) => GiftedChat.append(previousMessages, newMessages)); + }, []); + + const onLoadEarlier = (): void => { + // eslint-disable-next-line + console.log('chatAPI.loadMessages(chat, pageSize, lastMessage): ', messages[0]); + }; + + const { + Container, + SendWrapper, + MessageBubble, + SelfMessageBubble, + MessageText, + } = styledComponents; + + const renderInputToolbar = (props: InputToolbarProps): JSX.Element => ( + + ); + + const renderSend = (props: SendProps): JSX.Element => ( + + + + + + ); + + const renderMessage = (props: MessageProps): JSX.Element => { + const isSameUser = props.currentMessage?.user._id === 1; + const MessageView = isSameUser ? SelfMessageBubble : MessageBubble; + + return ( + + {props.currentMessage?.text} + + ); + }; + + return ( + + + onSend(newMessages)} + user={{ _id: 1 }} + messagesContainerStyle={styles.messagesContainer} + renderAvatar={() => null} + placeholder="" + alignTop + alwaysShowSend + textInputProps={{ style: styles.textInput }} + renderInputToolbar={renderInputToolbar} + renderSend={renderSend} + renderMessage={renderMessage} + /> + + + ); +}; diff --git a/src/pages/Chat/Chat/styles.ts b/src/pages/Chat/Chat/styles.ts new file mode 100644 index 0000000..be97f40 --- /dev/null +++ b/src/pages/Chat/Chat/styles.ts @@ -0,0 +1,88 @@ +import { ViewProps, TextProps } from 'react-native'; + +import styled from 'styled-components/native'; +import { Theme } from '../../../constants'; + +// Styled components. +export const styledComponents = { + Container: styled.View` + flex: 1; + align-items: center; + flex-grow: 1; + background-color: ${Theme.elements.chatBackground}; + `, + SendWrapper: styled.View` + background-color: ${Theme.elements.chatSendBall}; + border-radius: 100px; + flex-direction: column; + align-items: center; + width: 50px; + height: 50px; + `, + MessageBubble: styled.View` + background-color: ${Theme.elements.chatTextInput}; + max-width: 300px; + padding: 15px; + margin-top: 8px; + border-radius: 6px; + `, + SelfMessageBubble: styled.View` + background-color: ${Theme.elements.chatBubleUser}; + max-width: 300px; + padding: 15px; + margin-top: 8px; + border-radius: 6px; + align-self: flex-end; + `, + MessageText: styled.Text` + color: ${Theme.elements.chatText}; + font-family: Roboto_400Regular; + line-height: 24; + font-size: 18; + `, +}; + +// Style props. +export const styles = { + inputContainer: { + backgroundColor: 'transparent', + borderColor: 'transparent', + marginBottom: 16, + borderTopWidth: 0, + }, + + textInput: { + flex: 1, + backgroundColor: '#FFFFFF', + marginRight: 16, + padding: 15, + fontFamily: 'Roboto_400Regular', + fontSize: 18, + color: Theme.elements.chatText, + lineHeight: 24, + }, + + sendButtonContainer: { + marginBottom: 4, + }, + + sendButtonWrapper: { + backgroundColor: Theme.elements.chatSendBall, + borderRadius: 100, + flexDirection: 'column', + alignItems: 'center', + width: 50, + height: 50, + }, + + sendButtonIcon: { + color: Theme.elements.chatSendIcon, + marginTop: 'auto', + marginBottom: 'auto', + }, + + messagesContainer: { + width: 350, + paddingBottom: 32, + }, +}; diff --git a/src/routes.tsx b/src/routes.tsx index 8e6a9c0..a4e504a 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -16,6 +16,7 @@ import Unauthorized from './pages/Unauthorized'; import Context from './contexts/user/context'; import NotificationsList from './pages/NotificationsList'; import Interested from './pages/Animal/Interested'; +import Chat from './pages/Chat/Chat'; interface IRouteRule { name: string, @@ -87,6 +88,11 @@ export default class Routes extends React.Component { component: Interested, requireSession: true, }, + { + name: 'Chat', + component: Chat, + requireSession: true, + }, ]; routesProvider: () => IRoute[] = () => { diff --git a/src/types/routes.ts b/src/types/routes.ts index b5fe319..ffd9aed 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -1,3 +1,5 @@ +import { DocumentRefData } from './firebase'; + // Type declarations. export type RouteParams = { AnimalDetails: { @@ -5,5 +7,10 @@ export type RouteParams = { }, Interested: { animalUID: string + }, + Chat: { + title: string, + targetUser: DocumentRefData, + animal: DocumentRefData, } }; From f5eb0cf48f071231a23c4c1c4b6513cba95b5beb Mon Sep 17 00:00:00 2001 From: labm1997 Date: Thu, 29 Apr 2021 21:32:00 -0300 Subject: [PATCH 2/4] Fix navigation warning with complex data being passed --- src/pages/Animal/Details/index.tsx | 4 ++-- src/pages/Animal/Interested/index.tsx | 4 ++-- src/pages/Chat/Chat/index.tsx | 8 ++++---- src/types/routes.ts | 6 ++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/pages/Animal/Details/index.tsx b/src/pages/Animal/Details/index.tsx index 3283776..fadb064 100644 --- a/src/pages/Animal/Details/index.tsx +++ b/src/pages/Animal/Details/index.tsx @@ -316,8 +316,8 @@ export default function AnimalDetails() : JSX.Element { callback={() => navigation.navigate('Chat', { /* eslint-disable camelcase */ title: owner.data()?.full_name, - targetUser: animalData.owner, - animal, + targetUserUID: animalData.owner.id, + animalUID: animal.id, })} > Chat diff --git a/src/pages/Animal/Interested/index.tsx b/src/pages/Animal/Interested/index.tsx index a9a61ab..7c8dcf4 100644 --- a/src/pages/Animal/Interested/index.tsx +++ b/src/pages/Animal/Interested/index.tsx @@ -154,8 +154,8 @@ const Interested = (): JSX.Element => { text: 'Chat', onPress: () => navigation.navigate('Chat', { title: user.userName, - targetUser: u.ref, - animal, + targetUserUID: u.id, + animalUID: animal?.id, }), }, { diff --git a/src/pages/Chat/Chat/index.tsx b/src/pages/Chat/Chat/index.tsx index 04dab4d..406c922 100644 --- a/src/pages/Chat/Chat/index.tsx +++ b/src/pages/Chat/Chat/index.tsx @@ -127,8 +127,8 @@ const mock = [ export default (): JSX.Element => { const navigation = useNavigation(); const chatTitle = useRoute>().params?.title; - const animal = useRoute>().params?.animal; - const targetUser = useRoute>().params?.targetUser; + const animalUID = useRoute>().params?.animalUID; + const targetUserUID = useRoute>().params?.targetUserUID; useLayoutEffect(() => { setStatusBarBackgroundColor(Theme.elements.statusBarPrimaryDark, false); @@ -140,13 +140,13 @@ export default (): JSX.Element => { // eslint-disable-next-line console.log('================ CHAT PAGE ================'); // eslint-disable-next-line - console.log('chatAPI.getChat(currentUser, targetUser, animal): ', targetUser.id, animal.id); + console.log('chatAPI.getChat(currentUser, targetUser, animal): ', targetUserUID, animalUID); // eslint-disable-next-line console.log('...then'); // eslint-disable-next-line console.log('chatAPI.loadMessages(chat, pageSize) if chat'); setMessages(mock.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())); - }, [targetUser, animal]); + }, [targetUserUID, animalUID]); const onSend = useCallback((newMessages = []) => { // eslint-disable-next-line diff --git a/src/types/routes.ts b/src/types/routes.ts index ffd9aed..fb1494a 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -1,5 +1,3 @@ -import { DocumentRefData } from './firebase'; - // Type declarations. export type RouteParams = { AnimalDetails: { @@ -10,7 +8,7 @@ export type RouteParams = { }, Chat: { title: string, - targetUser: DocumentRefData, - animal: DocumentRefData, + targetUserUID: string, + animalUID: string, } }; From 309e024dcad9412d3c2006e8b9403a9398dd5956 Mon Sep 17 00:00:00 2001 From: labm1997 Date: Thu, 29 Apr 2021 22:37:27 -0300 Subject: [PATCH 3/4] Updated to new way to change status bar background --- src/pages/Chat/Chat/index.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pages/Chat/Chat/index.tsx b/src/pages/Chat/Chat/index.tsx index 406c922..fd99738 100644 --- a/src/pages/Chat/Chat/index.tsx +++ b/src/pages/Chat/Chat/index.tsx @@ -1,8 +1,8 @@ import React, { - useCallback, useEffect, useLayoutEffect, useState, + useCallback, useEffect, useState, } from 'react'; import { setStatusBarBackgroundColor } from 'expo-status-bar'; -import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'; +import { RouteProp, useFocusEffect, useRoute } from '@react-navigation/native'; import { GiftedChat, InputToolbar, InputToolbarProps, Send, SendProps, MessageProps, IMessage, } from 'react-native-gifted-chat'; @@ -125,14 +125,15 @@ const mock = [ ]; export default (): JSX.Element => { - const navigation = useNavigation(); const chatTitle = useRoute>().params?.title; const animalUID = useRoute>().params?.animalUID; const targetUserUID = useRoute>().params?.targetUserUID; - useLayoutEffect(() => { - setStatusBarBackgroundColor(Theme.elements.statusBarPrimaryDark, false); - }, [navigation]); + useFocusEffect( + useCallback(() => { + setStatusBarBackgroundColor(Theme.elements.statusBarPrimaryDark, true); + }, []), + ); const [messages, setMessages] = useState([]); From 715cd4e125037b9d5ca6bbb5304d460b7832aaaf Mon Sep 17 00:00:00 2001 From: labm1997 Date: Fri, 30 Apr 2021 09:26:20 -0300 Subject: [PATCH 4/4] Fixed missing units in styled component --- src/pages/Chat/Chat/styles.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Chat/Chat/styles.ts b/src/pages/Chat/Chat/styles.ts index be97f40..0126708 100644 --- a/src/pages/Chat/Chat/styles.ts +++ b/src/pages/Chat/Chat/styles.ts @@ -37,8 +37,8 @@ export const styledComponents = { MessageText: styled.Text` color: ${Theme.elements.chatText}; font-family: Roboto_400Regular; - line-height: 24; - font-size: 18; + line-height: 24px; + font-size: 18px; `, };