0

Currently, I am making a private messaging feature for a React app. I'm fairly new to React, so I'm not sure where I'm messing this up. Also, please note: For this particular project, I am unable to use jQuery/Redux/etc... just plain React.

So before I show my code, this is what results I have now:

enter image description here

The sent messages appear ordered properly, and the received messages are ordered properly, BUT it shows all sent messages before then showing all received messages. I would like for them all to display in the order that they were sent, regardless of which user sent it (think of how your average texting app works)

Now for my code (sorry I included a lot, I'm not sure where in the process it is messing up):

data.json

"privateMessages": [
    {
      "userId": 2,
      "receiverId": 3,
      "message": "first",
      "id": 1
    },
    {
      "userId": 3,
      "receiverId": 2,
      "message": "second",
      "id": 2
    },
    {
      "userId": 2,
      "receiverId": 3,
      "message": "third",
      "id": 3
    },
    {
      "userId": 2,
      "receiverId": 3,
      "message": "fourth",
      "id": 4
    },
    {
      "userId": 3,
      "receiverId": 2,
      "message": "fifth",
      "id": 5
    }
  ],
"users": [
    {
      "name": "User 1",
      "id": 2
    },
    {
      "name": "User 2",
      "id": 3
    }

MsgCard.js --- I suspect the problem is here but not sure.

export const MsgCard = ({message}) => {
    const currentUserId = sessionStorage.getItem("nutshell_user");
    if (message.sentBySelf) {
        return (
            <div className="sentMsg">
                <h4>
                    <span className="nameOfSender">{message.user?.name}: </span>
                    {`${message.message}`}
                </h4>
            </div>
        )
    } else if (message.receiverId === parseInt(currentUserId)) {
        return (
            <div className="receivedMsg">
                <h4>
                    <span className="nameOfSender">{message.user?.name}: </span>
                    {`${message.message}`}
                </h4>
            </div>
        )
    }
}

MsgList.js

export const MsgList = () => {
    const [messages, setMessages] = useState([])
    const currentUserId = sessionStorage.getItem("nutshell_user");
    
    const getAllPMs = () => {
    return fetch(`${remoteURL}/privateMessages/?_expand=user`)
        .then(res=>res.json())
    }

    const scrollToEnd = () => {
        const container = document.querySelector(".messagesContainer")
        container.scrollTop = container.scrollHeight
    }

    const getPMs = () => {
        
        getAllPMs().then(allPMs => {
            const sentByCurrent = allPMs.filter(message => message.userId === parseInt(currentUserId))
            const sentByOthers = allPMs.filter(message => message.userId !== parseInt(currentUserId))

            const newCurrent = sentByCurrent.map(message => { 
                message.sentBySelf = true
                return message
            })
            const newOthers = sentByOthers.map(message => {
                message.sentBySelf = false
                return message
            })

            const allMessages = newCurrent.concat(newOthers)
            return allMessages
        })
        .then(allMsgsArray => {
            setMessages(allMsgsArray)
        })
        .then(() => {
            scrollToEnd()
        })
    }

    useEffect(() => {
        getPMs()
    },[])
    
    if (messages.length > 0) {
        return (
            <>
            <div className="messagesContainer">
                {messages.map(message => {
                    return <MsgCard key={message.id} message={message} />
                })}
            </div>
            IGNORE THIS COMPONENT<MsgInput renderList={getPMs} />
            </>
        )
    } else {
        return (
            <>
            <div className="messagesContainer">

            </div>
            IGNORE THIS COMPONENT <MsgInput renderList={getPMs} />
            </>
        )
    }
}
1
  • 2
    You’re concatenation the arrays (user 1 and then user 2), so all of user 1 messages will come before all of user 2 messages. If you want to sort them chronologically you probably will need to either sort them by ascending IDs (assuming your IDs are incremental), or provide more info (such as the message time stamps) to allow for correct chronological sorting. Commented Apr 17, 2021 at 21:25

2 Answers 2

1

Your issue is how you handle adding the sentBySelf attribute to each message:

getAllPMs().then(allPMs => {
    const sentByCurrent = allPMs.filter(message => message.userId === parseInt(currentUserId))
    const sentByOthers = allPMs.filter(message => message.userId !== parseInt(currentUserId))

    const newCurrent = sentByCurrent.map(message => {
        message.sentBySelf = true
        return message
    })
    const newOthers = sentByOthers.map(message => {
        message.sentBySelf = false
        return message
    })

    const allMessages = newCurrent.concat(newOthers)
    return allMessages
})

You filter all sentByCurrent then all sentByOthers then when you rebuild the list you concat current with others. Ensuring all current come before all others.


You can use map instead to add the attribute without affecting the order.

const allPMs = [
    {
        "userId": 2,
        "receiverId": 3,
        "message": "first",
        "id": 1
    },
    {
        "userId": 3,
        "receiverId": 2,
        "message": "second",
        "id": 2
    },
    {
        "userId": 2,
        "receiverId": 3,
        "message": "third",
        "id": 3
    },
    {
        "userId": 2,
        "receiverId": 3,
        "message": "fourth",
        "id": 4
    },
    {
        "userId": 3,
        "receiverId": 2,
        "message": "fifth",
        "id": 5
    }
];

const currentUserId = "2";


const orderMaintained = allPMs.map(curr => ({...curr, sentBySelf: curr.userId === parseInt(currentUserId)}));

console.log(orderMaintained);


In your program this would look something like:

getAllPMs().then(allPMs => {
    return allPMs.map(curr => ({...curr, sentBySelf: curr.userId === parseInt(currentUserId)}));
})
Sign up to request clarification or add additional context in comments.

Comments

0

Add sentBySelf for the current object, so you will keep the sequence.

getAllPMs()
  .then((allPMs) =>
    allPMs.privateMessages.map((msg) => ({
      ...msg,
      msg.userId === parseInt(currentUserId),
    }))
  ) [...]

Here a live example:

https://codesandbox.io/s/ecstatic-hamilton-uck5n?fontsize=14&hidenavigation=1&theme=dark

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.