A primeira coisa que vamos fazer é criar o nosso chatService.ts, e nele, iremos criar nossos métodos de pegar todos os chats, iniciar um chat e também de mandar alguma mensagem
import api from "./api";
import * as SecureStore from "expo-secure-store";
interface startChat {
product: string;
seller: string;
initialMessage: string;
}
interface sendMessage {
_id: string;
content: string;
reciver: string;
sender: string;
}
const chatService = {
getChats: async () => {
const token = await SecureStore.getItemAsync("onebitshop-token");
const res = await api.get("/conversations", {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res;
},
startChat: async (params: startChat) => {
const token = await SecureStore.getItemAsync("onebitshop-token");
const res = await api.post("/conversations", params, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res;
},
sendMessage: async (params: sendMessage) => {
const token = await SecureStore.getItemAsync("onebitshop-token");
const res = await api.post(`/conversations/${params._id}/send`, params, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res;
},
};
export default chatService;
Com isso feito, nós vamos agora criar uma entidade chamada messages, e nela nós iremos colocar a tipagem das mensagens trocadas pelos usuários
export interface Messages {
_id?: string;
content: string;
receiver: string;
sender: string;
}
E agora vamos fazer a tipagem lá nas rotas
Chat: {
_id?: string;
product: Product;
sellerName: string;
sellerId: string;
buyerId: string;
messages: Messages[];
};
Com essa tipagem, a gente vai conseguir navegar para a tela de chat individual tranquilamente quando iniciarmos uma conversa. Nós vamos agora fazer isso, então iremos para a nossa tela de “Product” para poder criar aqui o nosso handleChatSeller
const handleChatSeller = async () => {
const user = await AsyncStorage.getItem("user");
const { _id } = JSON.parse(user || "");
const initialMessage = `Olá, quero saber mais sobre o seu produto, ${route.params.seller.name}`;
const params = {
product: route.params._id,
seller: route.params.seller._id,
initialMessage,
};
const res = await chatService.startChat(params);
if (res.status === 201) {
navigation.navigate("Chat", {
product: route.params,
sellerName: route.params.seller.name,
sellerId: route.params.seller._id,
buyerId: _id,
messages: [
{
content: initialMessage,
receiver: route.params.seller._id,
sender: _id,
},
],
});
}
};
Dessa forma, ao iniciar um chat, a gente será enviado para a sua tela individual e faremos o envio da primeira mensagem
Agora, precisamos ir lá para o nosso Chat modificar as informações recebidas
const Chat = ({ route }: Props) => {
return (
<Container>
<ChatHeader
sellerName={route.params.sellerName}
product={route.params.product}
/>
<MessagesList messages={route.params.messages} />
<InputContainer>
<Input
placeholder="Digite sua mensagem"
placeholderTextColor="white"
multiline
/>
<SendButton onPress={() => {}}>
<SendIcon source={chatImage} />
</SendButton>
</InputContainer>
<NavBar />
</Container>
);
};
Com isso feito, vamos em ChatHeader e lá iremos colocar as informações recebidas. Primeiro, criando a tipagem para as informações base
interface Props {
sellerId: string;
sellerName: string;
product: Product;
}
const ChatHeader = ({ sellerName, product, sellerId }: Props) => {
Depois, modificando o nosso handle de navegação para o perfil do vendedor
const handleSellerProfile = () => {
navigation.navigate("SellerProfile", {
sellerId,
});
};
E por fim, modificar aqui as coisas dentro do nosso componente
<Container>
<Row>
<BackArrow marginLeft={0} />
<SellerName>{sellerName}</SellerName>
<ModalButton onPress={handleToggleModal}>
<ModalImage source={modalImg} />
</ModalButton>
<Modal animationType="fade" transparent={true} visible={modalVisible}>
<ModalOverlay onPress={handleToggleModal} activeOpacity={1}>
<ModalContainer>
<ModalText onPress={handleSellerProfile}>Ver Perfil</ModalText>
<ModalText>Deletar Conversa</ModalText>
<ModalText onPress={handleFeedback}>Avaliar</ModalText>
<ModalText onPress={handleDenounce}>Denunciar</ModalText>
</ModalContainer>
</ModalOverlay>
</Modal>
</Row>
<AdCard product={product} />
</Container>
Por último, vamos para o nosso AdCard, e aqui dentro de AdCard vamos receber o product
interface Props {
product: Product;
}
const AdCard = ({ product }: Props) => {
const navigation = useNavigation<PropsStack>();
return (
<Container
onPress={() => {
navigation.navigate("Product", {
...product,
});
}}
>
E já podemos testar o nosso envio. Agora, faremos que o botão do perfil de vendedor para falar com ele também funcione, nós vamos copiar esse handle para usar ele lá, vamos fazer algumas modificações no handle, mas será a mesma base
if (!userInfo || loading) {
return <Loader />;
}
const handleChatSeller = async () => {
if (userInfo.products.length <= 0) {
Alert.alert(
"Esse vendedor não vende nada, então você não pode falar com ele!"
);
return;
}
const user = await AsyncStorage.getItem("user");
const { _id } = JSON.parse(user || "");
const initialMessage = `Olá, quero saber mais sobre o seu produto, ${userInfo.name}`;
const params = {
product: userInfo.products[0]._id,
seller: userInfo._id,
initialMessage,
};
const res = await chatService.startChat(params);
if (res.status === 201) {
navigation.navigate("Chat", {
product: userInfo.products[0],
sellerName: userInfo.name,
sellerId: userInfo._id,
messages: [
{
content: initialMessage,
receiver: userInfo._id,
sender: _id,
},
],
});
}
};
return
Agora já temos o início do chat funcionando corretamente