I have been working on a chat feature and I have had this problem for a while, I’ve tried everything I can think of to solve (not hard enough obviously lol) and am stumped once again; I’m calling on the problem-solving souls of StackOverflow to hopefully see something I’m not seeing
Here is my ChatInput code, this has a text input box for the user to send a message. Once it does it’s supposed to update an already existing collection in firebase (called “chats”) with the combined userID of both users who are messaging each other, however, each time a message is sent, the docID is updated to null.
Input.jsx
import React, { useContext, useState } from "react";
import Img from "../assets/img.png";
import Attach from "../assets/attach.png";
import { useAuth } from "../contexts/AuthContext";
import { ChatContext } from "../contexts/ChatContext";
import {
arrayUnion,
doc,
serverTimestamp,
Timestamp,
updateDoc,
} from "firebase/firestore";
import { db, storage } from "../firebase";
import { v4 as uuid } from "uuid";
import { getDownloadURL, ref, uploadBytesResumable } from "firebase/storage";
const Input = () => {
const [text, setText] = useState("");
const [img, setImg] = useState(null);
const { currentUser } = useAuth();
const { data } = useContext(ChatContext);
const handleSend = async () => {
if (!data.chatId) {
console.error("Chat ID is not set, cannot update the document.");
return;
}
if (img) {
const storageRef = ref(storage, uuid());
const uploadTask = uploadBytesResumable(storageRef, img);
uploadTask.on(
(error) => {
//TODO:Handle Error
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => {
const messageRef = await updateDoc(doc(db, "chats", data.chatId), {
messages: arrayUnion({
id: uuid(),
text,
senderId: currentUser.uid,
date: Timestamp.now(),
img: downloadURL,
}),
});
});
}
);
} else {
await updateDoc(doc(db, "chats", data.chatId), {
messages: arrayUnion({
id: uuid(),
text,
senderId: currentUser.uid,
date: Timestamp.now(),
}),
});
}
await updateDoc(doc(db, "userChats", currentUser.uid), {
[data.chatId + ".lastMessage"]: {
text,
},
[data.chatId + ".date"]: serverTimestamp(),
});
await updateDoc(doc(db, "userChats", data.user.uid), {
[data.chatId + ".lastMessage"]: {
text,
},
[data.chatId + ".date"]: serverTimestamp(),
});
setText("");
setImg(null);
};
return (
<div className="input">
<input
type="text"
placeholder="Type something..."
onChange={(e) => setText(e.target.value)}
value={text}
/>
<div className="send">
<img src={Attach} alt="" />
<input
type="file"
style={{ display: "none" }}
id="file"
onChange={(e) => setImg(e.target.files[0])}
/>
<label htmlFor="file">
<img src={Img} alt="" />
</label>
<button onClick={handleSend}>Send</button>
</div>
</div>
);
};
export default Input;
And here is my ChatContext…
ChatContext.jsx
import {
createContext,
useReducer,
} from "react";
import { useAuth } from "./AuthContext";
export const ChatContext = createContext();
export const ChatContextProvider = ({ children }) => {
const { currentUser } = useAuth();
const INITIAL_STATE = {
chatId: "null",
user: {},
};
console.log("currentUser", currentUser);
console.log("INITIAL_STATE", INITIAL_STATE);
const chatReducer = (state, action) => {
switch (action.type) {
case "SET_USER":
const { uid, name } = action.payload;
const chatId =
currentUser.uid > uid ? currentUser.uid + uid : uid + currentUser.uid;
return {
chatId,
user: { uid, name },
};
default:
return state;
}
};
const [state, dispatch] = useReducer(chatReducer, INITIAL_STATE);
const setUser = (uid, name) => {
dispatch({ type: "SET_USER", payload: { uid, name } });
};
return (
<ChatContext.Provider value={{ data: state, setUser }}>
{children}
</ChatContext.Provider>
);
};
My suspicion is with the ChatContext, it doesn’t dispatch the switch case and just stays in the INITIAL_STATE, which will set the user as “null,” however I’ve tried to change this, even putting the dispatch in the Input.jsx code, but no changes. I’ve tried changing the chatID
to null
instead of including the double quotes, but that seems to make it worse.
Any input is truly appreciated as I have no idea where to go from here.