|
| 1 | +import { Box, Flex, HStack, Spinner, Text } from "@chakra-ui/react"; |
| 2 | +import { useCallback, useEffect, useState } from "react"; |
| 3 | +import InputBox from "./inputBox"; |
| 4 | +import { MessageSnapshotResponse } from "@/context/Chat/types"; |
| 5 | +import { useChat } from "@/context/Chat"; |
| 6 | +import { fetchCommonRoomMessages, fetchOneToOneMessages } from "@/services"; |
| 7 | +import MessageItems from "./messageItems"; |
| 8 | +import { |
| 9 | + limitToLast, |
| 10 | + ref, |
| 11 | + query, |
| 12 | + onChildAdded, |
| 13 | + DataSnapshot, |
| 14 | +} from "firebase/database"; |
| 15 | +import { firebaseDatabase } from "@/config"; |
| 16 | + |
| 17 | +const Message = () => { |
| 18 | + const { chatRoomId, oneToOneRoomId } = useChat(); |
| 19 | + const [isLoading, setIsLoading] = useState(true); |
| 20 | + const [messages, setMessages] = useState<MessageSnapshotResponse>({}); |
| 21 | + |
| 22 | + // Handle child added |
| 23 | + const handleChildAdded = (snapshot: DataSnapshot) => { |
| 24 | + if (!snapshot.exists() || !snapshot.key) return; |
| 25 | + setMessages((prev) => { |
| 26 | + if (prev[snapshot.key as string]) return prev; |
| 27 | + return { ...prev, [snapshot.key as string]: snapshot.val() }; |
| 28 | + }); |
| 29 | + }; |
| 30 | + |
| 31 | + // Subscribe to room |
| 32 | + const subscribeToRoom = useCallback(() => { |
| 33 | + const collectionRef = ref(firebaseDatabase, chatRoomId); |
| 34 | + const limitedQuery = query(collectionRef, limitToLast(1)); |
| 35 | + onChildAdded(limitedQuery, handleChildAdded); |
| 36 | + |
| 37 | + if (oneToOneRoomId) { |
| 38 | + const oneToOneCollectionRef = ref(firebaseDatabase, oneToOneRoomId); |
| 39 | + const oneToOneLimitedQuery = query(oneToOneCollectionRef, limitToLast(1)); |
| 40 | + onChildAdded(oneToOneLimitedQuery, handleChildAdded); |
| 41 | + } |
| 42 | + }, [chatRoomId, oneToOneRoomId]); |
| 43 | + |
| 44 | + // Fetch messages |
| 45 | + const fetchData = useCallback(async () => { |
| 46 | + setIsLoading(true); |
| 47 | + const results = |
| 48 | + chatRoomId && oneToOneRoomId |
| 49 | + ? await fetchOneToOneMessages(chatRoomId, oneToOneRoomId) |
| 50 | + : await fetchCommonRoomMessages(); |
| 51 | + setMessages(results); |
| 52 | + subscribeToRoom(); |
| 53 | + setIsLoading(false); |
| 54 | + }, [chatRoomId, oneToOneRoomId, subscribeToRoom]); |
| 55 | + |
| 56 | + useEffect(() => { |
| 57 | + if (!chatRoomId) return; |
| 58 | + fetchData(); |
| 59 | + }, [chatRoomId, fetchData, oneToOneRoomId]); |
| 60 | + |
| 61 | + return ( |
| 62 | + <Box |
| 63 | + flex={3} |
| 64 | + borderWidth={"1px"} |
| 65 | + borderTop={"none"} |
| 66 | + borderBottomRightRadius={"md"} |
| 67 | + className="right__section" |
| 68 | + > |
| 69 | + <Flex direction={"column"} h={"full"}> |
| 70 | + <Box |
| 71 | + p={3} |
| 72 | + flex={1} |
| 73 | + borderBottom={"none"} |
| 74 | + overflowX={"hidden"} |
| 75 | + overflowY={"auto"} |
| 76 | + height={"100%"} |
| 77 | + > |
| 78 | + {/* loading */} |
| 79 | + {isLoading && ( |
| 80 | + <HStack justifyContent={"center"} alignItems={"center"} h={"full"}> |
| 81 | + <Text textAlign={"center"} color={"gray.500"}> |
| 82 | + Loading messages... |
| 83 | + </Text> |
| 84 | + <Spinner /> |
| 85 | + </HStack> |
| 86 | + )} |
| 87 | + {/* messages */} |
| 88 | + {!isLoading && <MessageItems messages={messages} />} |
| 89 | + </Box> |
| 90 | + {/* input */} |
| 91 | + <InputBox /> |
| 92 | + </Flex> |
| 93 | + </Box> |
| 94 | + ); |
| 95 | +}; |
| 96 | + |
| 97 | +export default Message; |
0 commit comments