stream-chat-react-native icon indicating copy to clipboard operation
stream-chat-react-native copied to clipboard

[🐛] Unable to auth user due to "user_details is a required field"

Open abdalem opened this issue 1 year ago • 5 comments

Issue

While trying to auth a user I am getting this error: image

I have tried with multiple users, the one from the tutorial and one of my own, it's impossible to make it work. The issue is not with the token as when token is wrong this is not this error. This is my implementation:

import React from 'react';
import { StreamChat } from 'stream-chat';
import { OverlayProvider, Chat } from 'stream-chat-expo';

const CHAT_API_KEY = 'bdx6n6zernjh';
const CHAT_USER_ID = 'autumn-glitter-4';
const CHAT_USER_NAME = 'autumn-glitter-4';
const CHAT_USER_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYXV0dW1uLWdsaXR0ZXItNCJ9.CBDhN-L7AI_xrLR6Kl6WpS7t40n0gzZxdOhgS0EClj8';

const user = {
  id: CHAT_USER_ID,
  name: CHAT_USER_NAME,
};

export const client = StreamChat.getInstance(CHAT_API_KEY);

type ChatSession = {
  userIsReadyToChat: boolean;
  userId?: string;
  handleLogin: () => Promise<void>;
  handleLogout: () => void;
}

export const ChatContext = React.createContext<ChatSession | null>(null);

export const ChatProvider: React.FC<React.PropsWithChildren> = ({ children })  => {
  const [userIsReadyToChat, setUserIsReadyToChat] = React.useState(false);


  const handleLogin = async () => {
    try {
      if(!client.userID) {
        console.log(user.id)
        await client.connectUser(user, CHAT_USER_TOKEN);
        setUserIsReadyToChat(true);
      }
    } catch (error) {
      if (error instanceof Error) {
        console.error(`An error occurred while connecting the user: ${error.message}`);
      }
    }
  }

  const handleLogout = () => {
    try {
      if(client.userID) {
        client.disconnectUser();
        setUserIsReadyToChat(false);
      }
    } catch (error) {
      if (error instanceof Error) {
        console.error(`An error occurred while disconnecting the user: ${error.message}`);
      }
    }
  }

  return (
    <ChatContext.Provider value={{ userIsReadyToChat, userId: client.userID, handleLogin, handleLogout }}>
      {/* <OverlayProvider> */}
        {/* <Chat client={client}> */}
          {children}
        {/* </Chat> */}
      {/* </OverlayProvider> */}
    </ChatContext.Provider>
  )
};

export const useChatContext = () => {
  const context = React.useContext(ChatContext);

  if (!context) throw new Error('useChatContext must be used within a ChatProvider');

  return context;
}

Steps to reproduce

Steps to reproduce the behavior:

  1. Following the tutorial and when trying to connectUser, See this error.

Expected behavior

Connecting user

Project Related Information

Customization

Click To Expand

# N/A

Offline support

  • [ ] I have enabled offline support.
  • [ ] The feature I'm having does not occur when offline support is disabled. (stripe out if not applicable)

Environment

Click To Expand

package.json:

# N/A

react-native info output:

 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • [ ] iOS
    • [ ] Android
    • [ ] iOS but have not tested behavior on Android
    • [ ] Android but have not tested behavior on iOS
    • [ ] Both
  • stream-chat-react-native version you're using that has this issue:
    • e.g. 5.4.3
  • Device/Emulator info:
    • [ ] I am using a physical device
    • OS version: e.g. Android 10
    • Device/Emulator: e.g. iPhone 11

Additional context

Screenshots

Click To Expand


abdalem avatar Apr 07 '24 11:04 abdalem

Where do you pass this client to the Chat component? Can you share with us your code, to help us assist you better? Thanks 😄

khushal87 avatar Apr 11 '24 05:04 khushal87

Hey @abdalem, is it still relevant for you?

khushal87 avatar Apr 16 '24 06:04 khushal87

Hey @khushal87. Sorry, I was following it through the support page of stream. The fact is that it raise the error before passing it to the Chat component, as you can see it is commented. It happen exactly on the handleLogin call.

abdalem avatar Apr 16 '24 11:04 abdalem

Hey @abdalem, can you please share your whole code so that I can run it locally to test your issue? Thanks 😄

The above code seems incomplete

khushal87 avatar Apr 22 '24 17:04 khushal87

@khushal87 Of course here is a repo: https://github.com/abdalem/expo-chat-poc

abdalem avatar Apr 24 '24 15:04 abdalem

Hi @khushal87 did you had the time to explore the repo ? I am still locked at the time

abdalem avatar May 03 '24 15:05 abdalem

Yes, you had a mistake in the handleLogin where you were checking for client.userId rather than client to connect to a new user. Also, your useEffect in chat.tsx was wrong. You simply returned the handleLogout. That is not the right way to unmount the component. It should be:

  React.useEffect(() => {
    handleLogin();

    return () => {
      handleLogout();
    };
  }, []);

Anyways please update the following code on your side:

ChatProvider.tsx

// useChatClient.js

import React from "react";
import { StreamChat } from "stream-chat";
import { OverlayProvider, Chat } from "stream-chat-expo";

const CHAT_API_KEY = "fz7q3t2w9nf6";
const CHAT_USER_ID = "autumn-glitter-4";
const CHAT_USER_NAME = "autumn-glitter-4";
const CHAT_USER_TOKEN =
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYXV0dW1uLWdsaXR0ZXItNCJ9.pgdoXAULF4zPYMOPDTxcYPctrFdle5vG2DUvFH1eo6I";

const user = {
  id: CHAT_USER_ID,
  name: CHAT_USER_NAME,
};

export const client = StreamChat.getInstance(CHAT_API_KEY);

type ChatSession = {
  userIsReadyToChat: boolean;
  userId?: string;
  handleLogin: () => Promise<void>;
  handleLogout: () => void;
};

export const ChatContext = React.createContext<ChatSession | null>(null);

export const ChatProvider: React.FC<React.PropsWithChildren> = ({
  children,
}) => {
  const [userIsReadyToChat, setUserIsReadyToChat] = React.useState(false);

  const handleLogin = async () => {
    try {
      if (client) {
        await client.connectUser(user, CHAT_USER_TOKEN);
        setUserIsReadyToChat(true);
      }
    } catch (error) {
      if (error instanceof Error) {
        console.error(
          `An error occurred while connecting the user: ${error.message}`
        );
      }
    }
  };

  const handleLogout = () => {
    try {
      if (client.userID) {
        client.disconnectUser();
        setUserIsReadyToChat(false);
      }
    } catch (error) {
      if (error instanceof Error) {
        console.error(
          `An error occurred while disconnecting the user: ${error.message}`
        );
      }
    }
  };

  return (
    <ChatContext.Provider
      value={{
        userIsReadyToChat,
        userId: client.userID,
        handleLogin,
        handleLogout,
      }}
    >
      <OverlayProvider>
        <Chat client={client}>{children}</Chat>
      </OverlayProvider>
    </ChatContext.Provider>
  );
};

export const useChatContext = () => {
  const context = React.useContext(ChatContext);

  if (!context)
    throw new Error("useChatContext must be used within a ChatProvider");

  return context;
};

And,

chat.tsx

import { StyleSheet } from "react-native";
import { useChatContext } from "@/providers/ChatProvider";
import { ChannelList } from "stream-chat-expo";

import EditScreenInfo from "@/components/EditScreenInfo";
import { Text, View } from "@/components/Themed";
import React from "react";

export default function TabTwoScreen() {
  const { userIsReadyToChat, userId, handleLogin, handleLogout } =
    useChatContext();

  React.useEffect(() => {
    handleLogin();

    return () => {
      handleLogout();
    };
  }, []);

  const filters = React.useMemo(
    () => ({
      members: {
        $in: [userId],
      },
    }),
    [userId]
  );

  return (
    <View style={styles.container}>
      {userIsReadyToChat && userId && (
        <>
          <Text style={{ fontSize: 30, color: "black" }}>{userId}</Text>
          <ChannelList
            filters={{
              members: {
                $in: [userId],
              },
            }}
            sort={{
              last_message_at: -1,
            }}
          />
        </>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  title: {
    fontSize: 20,
    fontWeight: "bold",
  },
  separator: {
    marginVertical: 30,
    height: 1,
    width: "80%",
  },
});

Hope that helps. 😄

khushal87 avatar May 06 '24 06:05 khushal87

Oh great @khushal87 So many thanks !!!!

abdalem avatar May 06 '24 15:05 abdalem