From fff2ac4cde70876338b75fa4660cb4e9c6b62113 Mon Sep 17 00:00:00 2001 From: Ayobami Date: Tue, 1 Jul 2025 18:10:45 +0100 Subject: [PATCH] ISSUE 7: add message validation before sending --- src/pages/Common/Messages/MessagesPage.jsx | 831 ++++++++++++++------- 1 file changed, 576 insertions(+), 255 deletions(-) diff --git a/src/pages/Common/Messages/MessagesPage.jsx b/src/pages/Common/Messages/MessagesPage.jsx index 073bb0f..5c7cda1 100644 --- a/src/pages/Common/Messages/MessagesPage.jsx +++ b/src/pages/Common/Messages/MessagesPage.jsx @@ -22,7 +22,6 @@ import PersonIcon from "@/components/frontend/icons/PersonIcon"; import PropertySpaceMapImage from "@/components/frontend/PropertySpaceMapImage"; import ImagePreviewModal from "./ImagePreviewModal"; - let sdk = new MkdSDK(); let treeSdk = new TreeSDK(); const ctrl = new AbortController(); @@ -31,7 +30,8 @@ const MessagesPage = () => { const { state, dispatch } = useContext(AuthContext); const [rooms, setRooms] = useState(Array(4).fill({})); const [roomUnread, setRoomUnread] = useState([]); - const { state: globalState, dispatch: globalDispatch } = useContext(GlobalContext); + const { state: globalState, dispatch: globalDispatch } = + useContext(GlobalContext); const [message, setMessage] = useState(""); const [searchParams, setSearchParams] = useSearchParams(); @@ -58,15 +58,19 @@ const MessagesPage = () => { const [sending, setSending] = useState(false); const [roomsFetched, setRoomsFetched] = useState(false); - const [showImagePreviewModal, setShowImagePreviewModal] = useState(false) + const [showImagePreviewModal, setShowImagePreviewModal] = useState(false); const formatAmenities = (propertyAmenities) => { var amenities = (propertyAmenities ?? "").split(","); amenities = Array.from(new Set(amenities)); - return amenities - } + return amenities; + }; - const bookingExpired = activeBooking.booking_start_time && activeBooking.status < BOOKING_STATUS.ONGOING ? new Date(activeBooking.booking_end_time) < Date.now() : false; + const bookingExpired = + activeBooking.booking_start_time && + activeBooking.status < BOOKING_STATUS.ONGOING + ? new Date(activeBooking.booking_end_time) < Date.now() + : false; async function getRooms() { try { @@ -77,7 +81,7 @@ const MessagesPage = () => { result.messages.filter((msg) => { const messageSenderId = JSON.parse(msg.chat).user_id; return Number(messageSenderId) != Number(state.user); - }).length, + }).length ); globalDispatch({ type: "SET_UNREAD_MESSAGES_COUNT", @@ -88,11 +92,10 @@ const MessagesPage = () => { }); } setRooms(result?.list); - setRoomUnread(result?.messages) + setRoomUnread(result?.messages); setRoomsFetched(true); globalDispatch({ type: "STOP_LOADING" }); - } catch (err) { tokenExpireError(dispatch, err.message); globalDispatch({ @@ -107,13 +110,17 @@ const MessagesPage = () => { async function getArchivedRooms() { try { - const result = await treeSdk.getList("room", { join: ["user|other_user_id", "booking"], filter: [`user_id,eq,${state.user}`] }); - setArchivedAccount((result?.list.filter((item) => item.is_archive == 1)).length) + const result = await treeSdk.getList("room", { + join: ["user|other_user_id", "booking"], + filter: [`user_id,eq,${state.user}`], + }); + setArchivedAccount( + (result?.list.filter((item) => item.is_archive == 1)).length + ); setRooms(result.list.filter((item) => item.is_archive == 1)); - console.log((result?.list.filter((item) => item.is_archive == 1)).length) + console.log((result?.list.filter((item) => item.is_archive == 1)).length); globalDispatch({ type: "STOP_LOADING" }); - } catch (err) { tokenExpireError(dispatch, err.message); globalDispatch({ @@ -126,7 +133,6 @@ const MessagesPage = () => { } } - async function getMessages(room_id) { try { const result = await sdk.getChats(room_id); @@ -137,7 +143,7 @@ const MessagesPage = () => { return copy; }); } - return result.model + return result.model; } catch (err) { tokenExpireError(dispatch, err.message); globalDispatch({ @@ -154,9 +160,64 @@ const MessagesPage = () => { if (message == "") return; setShowEmoji(false); - - //Add checks to validate message based on active booking - + + // ---Validation checks --- + // 1. Profanity/bad words + const lowerMsg = message.toLowerCase(); + const badWordFound = badWords.some((word) => + new RegExp( + `\\b${word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, + "i" + ).test(lowerMsg) + ); + if (badWordFound) { + setMessageErr("Your message contains inappropriate language."); + return; + } + + // 2. Links/URLs + if (linkify.find(message).length > 0) { + setMessageErr("Sharing links or URLs is not allowed."); + return; + } + + // 3. Phone/email (if not ongoing) + const phoneRegex = + /(?:\+\d{1,3}[ -]?)?(?:\(\d{1,4}\)[ -]?)?(?:\d[ -]?){6,14}\d/; + const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/; + if (activeBooking.status !== BOOKING_STATUS.ONGOING) { + if (phoneRegex.test(message)) { + setMessageErr( + "Sharing phone numbers is not allowed unless the booking is ongoing." + ); + return; + } + if (emailRegex.test(message)) { + setMessageErr( + "Sharing emails is not allowed unless the booking is ongoing." + ); + return; + } + } + + // 4. Message count restriction (if not ongoing) + if (activeBooking.status !== BOOKING_STATUS.ONGOING) { + const roomId = activeRoom.id; + const msgs = messages[roomId] || []; + // Only count text messages between host and customer + const userMsgs = msgs.filter( + (m) => m.chat && !m.chat.is_image && m.chat.user_id === state.user + ); + console.log(userMsgs); + if (userMsgs.length >= 3) { + setMessageErr( + "You cannot send more than 3 messages unless the booking is ongoing." + ); + return; + } + } + + setMessageErr(""); setSending(true); try { @@ -175,19 +236,22 @@ const MessagesPage = () => { { user_id: state.user, other_user_id: Number(activeRoom.other_user_id), - booking_id: activeRoom.booking_id === null ? null : Number(activeRoom.booking_id), + booking_id: + activeRoom.booking_id === null + ? null + : Number(activeRoom.booking_id), property_id: spaceId, user_update_at: date2, other_user_update_at: date2, chat_id: -1, }, - "POST", - ) + "POST" + ); setRooms((prev) => { const copy = [...prev]; copy[prev.findIndex((rm) => rm?.is_temp_chat)].id = result?.message; return copy; - }) + }); // setRooms((prev) => [...prev,r]) setActiveRoom((prev) => ({ ...prev, id: result.message })); } @@ -215,19 +279,27 @@ const MessagesPage = () => { setMessages((prev) => { const copy = { ...prev }; - copy[room_id === "temp" ? result?.message : Number(room_id)] = [...copy[room_id === "temp" ? result?.message : Number(room_id)], newMessageObj]; + copy[room_id === "temp" ? result?.message : Number(room_id)] = [ + ...copy[room_id === "temp" ? result?.message : Number(room_id)], + newMessageObj, + ]; return copy; }); // is_temp_chat = false; - getRooms() + getRooms(); // send email alert - sendEmailAlert(activeRoom.other_user_id, activeBooking.property_name, message, activeRoom.id); + sendEmailAlert( + activeRoom.other_user_id, + activeBooking.property_name, + message, + activeRoom.id + ); setMessage(""); // TODO: scroll to bottom } catch (err) { - console.log(err) + console.log(err); globalDispatch({ type: "SHOW_ERROR", payload: { @@ -242,10 +314,17 @@ const MessagesPage = () => { async function sendEmailAlert(to, property_name, message, room_id) { try { // get receiver preferences - const result = await sdk.callRawAPI("/v2/api/custom/ergo/get-user", { id: to }, "POST"); + const result = await sdk.callRawAPI( + "/v2/api/custom/ergo/get-user", + { id: to }, + "POST" + ); - if (parseJsonSafely(result.settings, {}).email_on_new_chat_message == true) { - let sender_name = globalState.user.first_name + " " + globalState.user.last_name; + if ( + parseJsonSafely(result.settings, {}).email_on_new_chat_message == true + ) { + let sender_name = + globalState.user.first_name + " " + globalState.user.last_name; // get email template const tmpl = await sdk.getEmailTemplate("chat-message-alert"); const body = tmpl.html @@ -284,11 +363,11 @@ const MessagesPage = () => { try { const result = await sdk.callRestAPI({ id }, "DELETE"); if (!result.error) { - getRooms() - setActiveRoom({}) - setActiveBooking({}) - setActiveProperty({}) - showToast(globalDispatch, result.message, 5000) + getRooms(); + setActiveRoom({}); + setActiveBooking({}); + setActiveProperty({}); + showToast(globalDispatch, result.message, 5000); } } catch (err) { globalDispatch({ @@ -319,8 +398,23 @@ const MessagesPage = () => { if (activeBooking?.extrasFetched) return; setFetchingExtra(true); try { - const result = await sdk.callRawAPI(`/v2/api/custom/ergo/booking/details`, { where: [`ergo_booking.id = ${activeRoom.booking_id} AND (ergo_booking.deleted_at IS NULL AND ergo_booking.status = ${BOOKING_STATUS.ONGOING} OR ergo_booking.status = ${BOOKING_STATUS.UPCOMING})`] }, "POST"); - if (result.list.id && new Date(new Date(result.list.booking_end_time).setDate(new Date(result.list.booking_end_time).getDate() + 1)) > new Date()) { + const result = await sdk.callRawAPI( + `/v2/api/custom/ergo/booking/details`, + { + where: [ + `ergo_booking.id = ${activeRoom.booking_id} AND (ergo_booking.deleted_at IS NULL AND ergo_booking.status = ${BOOKING_STATUS.ONGOING} OR ergo_booking.status = ${BOOKING_STATUS.UPCOMING})`, + ], + }, + "POST" + ); + if ( + result.list.id && + new Date( + new Date(result.list.booking_end_time).setDate( + new Date(result.list.booking_end_time).getDate() + 1 + ) + ) > new Date() + ) { const fullBooking = { ...result.list, ...activeBooking, @@ -351,17 +445,28 @@ const MessagesPage = () => { }, 500); } catch (err) { tokenExpireError(dispatch, err.message); - globalDispatch({ type: "SHOW_ERROR", payload: { heading: "Error fetching booking details", message: err.message } }); + globalDispatch({ + type: "SHOW_ERROR", + payload: { + heading: "Error fetching booking details", + message: err.message, + }, + }); } } async function markMessagesAsRead(room_id, arr) { try { sdk.setTable("chat"); - await Promise.all(arr.map((id) => sdk.callRestAPI({ id, unread: 0 }, "PUT"))); + await Promise.all( + arr.map((id) => sdk.callRestAPI({ id, unread: 0 }, "PUT")) + ); setMessages((prev) => { const copy = { ...prev }; - copy[room_id] = (copy[room_id] ?? []).map((msg) => ({ ...msg, unread: 0 })); + copy[room_id] = (copy[room_id] ?? []).map((msg) => ({ + ...msg, + unread: 0, + })); return copy; }); setUnreadCount((prev) => { @@ -386,13 +491,20 @@ const MessagesPage = () => { async function getPropertyDetails(id) { const user_id = localStorage.getItem("user"); - const where = [`ergo_property_spaces.id = ${id} AND ergo_property_spaces.deleted_at IS NULL`]; + const where = [ + `ergo_property_spaces.id = ${id} AND ergo_property_spaces.deleted_at IS NULL`, + ]; try { - const result = await sdk.callRawAPI("/v2/api/custom/ergo/popular/PAGINATE", { page: 1, limit: 1, user_id: Number(user_id), where, all: true }, "POST", ctrl.signal); + const result = await sdk.callRawAPI( + "/v2/api/custom/ergo/popular/PAGINATE", + { page: 1, limit: 1, user_id: Number(user_id), where, all: true }, + "POST", + ctrl.signal + ); if (Array.isArray(result.list) && result.list.length > 0) { setActiveProperty(result.list[0]); - fetchFavoriteStatus(Number(result.list[0].id), Number(user_id)) - } else setActiveProperty({}) + fetchFavoriteStatus(Number(result.list[0].id), Number(user_id)); + } else setActiveProperty({}); } catch (err) { tokenExpireError(dispatch, err.message); if (err.name == "AbortError") return; @@ -408,7 +520,7 @@ const MessagesPage = () => { } async function createVirtualRoom(other_user_id, booking_id, new_booking_id) { - setSpaceId(Number(new_booking_id)) + setSpaceId(Number(new_booking_id)); try { const result = await treeSdk.getOne("user", other_user_id, { join: [] }); const room = { @@ -426,8 +538,12 @@ const MessagesPage = () => { deleted_at: null, user: { id: other_user_id, - first_name: result.model.deleted_at == null ? result.model.first_name : "[Deleted User]", - last_name: result.model.deleted_at == null ? result.model.last_name : "", + first_name: + result.model.deleted_at == null + ? result.model.first_name + : "[Deleted User]", + last_name: + result.model.deleted_at == null ? result.model.last_name : "", photo: result.model.deleted_at == null ? result.model.photo : null, }, booking: { @@ -436,49 +552,81 @@ const MessagesPage = () => { }; setRooms((prev) => [...prev, room]); - setVirtual(true) + setVirtual(true); setActiveRoom(room); } catch (err) { tokenExpireError(dispatch, err.message); - globalDispatch({ type: "SHOW_ERROR", payload: { heading: "Failed to fetch other user data", message: err.message } }); + globalDispatch({ + type: "SHOW_ERROR", + payload: { + heading: "Failed to fetch other user data", + message: err.message, + }, + }); } } async function getBookingDetails() { - setFetchingExtra(true); + setFetchingExtra(true); const room_id = searchParams.get("room_id"); const booking_id = searchParams.get("booking"); setActiveProperty({}); setActiveBooking({}); if (room_id === "temp" || room_id === null) return; - sdk.setTable("room") - const data = await sdk.callRestAPI({ id: Number(room_id) }, "GET") + sdk.setTable("room"); + const data = await sdk.callRestAPI({ id: Number(room_id) }, "GET"); - await sdk.setTable("booking") + await sdk.setTable("booking"); const bookings = await sdk.callRestAPI({}, "GETALL"); - const fetched_booking = bookings.list.reverse().find((item) => - (item.host_id === data.model?.user_id || item.host_id === data.model?.other_user_id) && - (item.customer_id === data.model?.user_id || item.customer_id === data.model?.other_user_id) && - (item.property_space_id === data?.model?.property_id) && - (item.status === BOOKING_STATUS.UPCOMING || item.status === BOOKING_STATUS.ONGOING) - ) - if (data.model?.booking_id !== null || booking_id !== null || (fetched_booking !== undefined && fetched_booking !== null) ) { + const fetched_booking = bookings.list + .reverse() + .find( + (item) => + (item.host_id === data.model?.user_id || + item.host_id === data.model?.other_user_id) && + (item.customer_id === data.model?.user_id || + item.customer_id === data.model?.other_user_id) && + item.property_space_id === data?.model?.property_id && + (item.status === BOOKING_STATUS.UPCOMING || + item.status === BOOKING_STATUS.ONGOING) + ); + if ( + data.model?.booking_id !== null || + booking_id !== null || + (fetched_booking !== undefined && fetched_booking !== null) + ) { if (fetched_booking) { - setActiveBooking(fetched_booking) + setActiveBooking(fetched_booking); return; - } - await sdk.setTable("booking") - const payload = { id: data.model?.booking_id ?? (booking_id ?? fetched_booking?.id) } + } + await sdk.setTable("booking"); + const payload = { + id: data.model?.booking_id ?? booking_id ?? fetched_booking?.id, + }; const result = await sdk.callRestAPI(payload, "GET"); - setActiveBooking((result?.model?.status === BOOKING_STATUS.ONGOING || result?.model?.status === BOOKING_STATUS.UPCOMING) ? result.model : {}) + setActiveBooking( + result?.model?.status === BOOKING_STATUS.ONGOING || + result?.model?.status === BOOKING_STATUS.UPCOMING + ? result.model + : {} + ); } else { const user_id = localStorage.getItem("user"); - const where = [`ergo_property_spaces.id = ${Number(data.model?.property_id)} AND ergo_property_spaces.deleted_at IS NULL`]; - const result = await sdk.callRawAPI("/v2/api/custom/ergo/popular/PAGINATE", { page: 1, limit: 1, user_id: Number(user_id), where, all: true }, "POST", ctrl.signal); + const where = [ + `ergo_property_spaces.id = ${Number( + data.model?.property_id + )} AND ergo_property_spaces.deleted_at IS NULL`, + ]; + const result = await sdk.callRawAPI( + "/v2/api/custom/ergo/popular/PAGINATE", + { page: 1, limit: 1, user_id: Number(user_id), where, all: true }, + "POST", + ctrl.signal + ); if (Array.isArray(result.list) && result.list.length > 0) { setActiveProperty(result.list[0]); - setActiveBooking({}) - } else setActiveProperty({}) + setActiveBooking({}); + } else setActiveProperty({}); } setTimeout(() => { setFetchingExtra(false); @@ -486,9 +634,9 @@ const MessagesPage = () => { } useEffect(() => { - getBookingDetails() + getBookingDetails(); }, [searchParams.get("room_id")]); - + useEffect(() => { getRooms(); }, []); @@ -507,45 +655,52 @@ const MessagesPage = () => { const other_user_id = searchParams.get("other_user_id"); if (!other_user_id) return; const booking_id = searchParams.get("booking"); - room = rooms.find((rm) => ((rm.booking_id === booking_id && rm.other_user_id === other_user_id) || rm.property_id === Number(property_space_id))); + room = rooms.find( + (rm) => + (rm.booking_id === booking_id && rm.other_user_id === other_user_id) || + rm.property_id === Number(property_space_id) + ); if (room) { setActiveRoom(room); } else { - getPropertyDetails(property_space_id) - createVirtualRoom(other_user_id, booking_id, property_space_id) - + getPropertyDetails(property_space_id); + createVirtualRoom(other_user_id, booking_id, property_space_id); } }, [roomsFetched]); useEffect(() => { - const controller = new AbortController(); const pollMessages = async () => { const abortController = new AbortController(); try { - const poll = await sdk.startPolling(localStorage.getItem("user"), abortController.signal) + const poll = await sdk.startPolling( + localStorage.getItem("user"), + abortController.signal + ); if (poll.message) { // Do whatever you want here let room = searchParams.get("room_id"); if (room === "temp") return; - getRooms() + getRooms(); if (Number(searchParams.get("room_id"))) { getMessages(Number(searchParams.get("room_id"))).then((res) => { - const unread = res.filter((msg) => msg.unread === 1 && msg.chat.user_id !== state.user).map((msg) => msg.id); + const unread = res + .filter( + (msg) => msg.unread === 1 && msg.chat.user_id !== state.user + ) + .map((msg) => msg.id); markMessagesAsRead(Number(searchParams.get("room_id")), unread); - } - ); + }); } } } catch (error) { - console.log(error) - } - finally { + console.log(error); + } finally { if (!abortController.signal.aborted) { - pollMessages() + pollMessages(); } } - } + }; return () => { clearInterval(5000); @@ -553,11 +708,10 @@ const MessagesPage = () => { }; }, []); - function showImageModal(){ - setShowImagePreviewModal(true) + function showImageModal() { + setShowImagePreviewModal(true); } - useEffect(() => { setFetchingExtra(true); globalDispatch({ type: "START_LOADING" }); @@ -574,20 +728,21 @@ const MessagesPage = () => { setSearchParams(searchParams); setMessage(""); getMessages(activeRoom.id).then((res) => { - const unread = res.filter((msg) => msg.unread === 1 && msg.chat.user_id !== state.user).map((msg) => msg.id); + const unread = res + .filter((msg) => msg.unread === 1 && msg.chat.user_id !== state.user) + .map((msg) => msg.id); markMessagesAsRead(activeRoom.id, unread); }); if (activeRoom.booking_id !== null) { fetchExtraBookingDetails(); } if (activeRoom.id) { - getPropertyDetails(activeRoom.property_id) + getPropertyDetails(activeRoom.property_id); } setTimeout(() => { setFetchingExtra(false); }, 500); globalDispatch({ type: "STOP_LOADING" }); - }, [activeRoom.id, render]); function sortByUpdateAt(a, b) { @@ -597,14 +752,18 @@ const MessagesPage = () => { return ( <>
setShowEmoji(false)} > -
-
-
+
+
+
- {roomsFetched && -
+ {roomsFetched && ( +
{searchParams.get("message_tab") != "archive" && rooms && rooms .filter((rm) => rm.is_archive == ARCHIVE_STATUS.NOT_ARCHIVE) - .sort((a, b) => new Date(b.update_at) - new Date(a.update_at)) + .sort( + (a, b) => new Date(b.update_at) - new Date(a.update_at) + ) .map((room, idx) => { return ( { setActiveBooking={setActiveBooking} setActiveProperty={setActiveProperty} activeBooking={activeBooking} - first={room.first_name ? room.first_name : room.user.first_name} - last={room.last_name ? room.last_name : room.user.last_name} + first={ + room.first_name + ? room.first_name + : room.user.first_name + } + last={ + room.last_name + ? room.last_name + : room.user.last_name + } setMobileChatSection={setMobileChatSection} markMessagesAsRead={() => markMessagesAsRead} messages={messages} @@ -657,7 +830,9 @@ const MessagesPage = () => { rooms && rooms .filter((rm) => rm.is_archive == ARCHIVE_STATUS.IS_ARCHIVE) - .sort((a, b) => new Date(b.update_at) - new Date(a.update_at)) + .sort( + (a, b) => new Date(b.update_at) - new Date(a.update_at) + ) .map((room, idx) => { return ( { setActiveBooking={setActiveBooking} setActiveProperty={setActiveProperty} activeBooking={activeBooking} - first={room.first_name ? room.first_name : room.user.first_name} - last={room.last_name ? room.last_name : room.user.last_name} + first={ + room.first_name + ? room.first_name + : room.user.first_name + } + last={ + room.last_name + ? room.last_name + : room.user.last_name + } setMobileChatSection={setMobileChatSection} messages={messages} deleteRoom={deleteRoom} @@ -680,188 +863,277 @@ const MessagesPage = () => { ); })}
- } + )}
- -
0 && !fetchingExtra) ? "block" : "hidden"} absolute top-0 right-0 -left-0 overflow-y-hidden bg-white md:static md:block md:max-h-[unset] md:w-[48%]`}> -
+ +
0 && + !fetchingExtra + ? "block" + : "hidden" + } absolute -left-0 right-0 top-0 overflow-y-hidden bg-white md:static md:block md:max-h-[unset] md:w-[48%]`} + > +
{activeRoom?.id ? ( <> -
+
-
-

Chat with {activeRoom?.first_name === undefined ? rooms[0]?.user?.first_name : activeRoom?.first_name + " " + activeRoom?.last_name === undefined ? rooms[0]?.user?.last_name : activeRoom?.last_name}

+
+

+ Chat with{" "} + {activeRoom?.first_name === undefined + ? rooms[0]?.user?.first_name + : activeRoom?.first_name + " " + activeRoom?.last_name === + undefined + ? rooms[0]?.user?.last_name + : activeRoom?.last_name} +

{mobileChatSection && activeRoom.booking_id && ( )}
-
-
- -
+
+
+ +
-
-
+
+
- +
- +
{ e.preventDefault(); sendMessage(); }} > setMessage(e.target.value)} - autoComplete="off" + autoComplete='off' />
+
-
- ) : ( -
Select a chat to view
+
+ Select a chat to view +
)}
-
0 && !fetchingExtra ) ? "block" : "hidden"} lg:block absolute top-0 right-0 -left-0 overflow-y-auto max-h-[var(--messages-page-height)] bg-white md:static md:block md:max-h-[unset] w-full md:w-[26%]`}> -
-
+
0 && + !fetchingExtra + ? "block" + : "hidden" + } absolute -left-0 right-0 top-0 max-h-[var(--messages-page-height)] w-full overflow-y-auto bg-white md:static md:block md:max-h-[unset] md:w-[26%] lg:block`} + > +
+
+ {activeRoom?.booking_id && activeRoom?.booking?.id && ( +

Booking Preview

+ )} - {(activeRoom?.booking_id && activeRoom?.booking?.id) && -

Booking Preview

- } - - {(activeRoom?.booking_id && !activeRoom?.booking?.id) && -

Property Preview

- } + {activeRoom?.booking_id && !activeRoom?.booking?.id && ( +

Property Preview

+ )} {mobilePreviewOpen && ( )}
-
-
+
+
{activeRoom.id && !activeRoom?.booking?.id ? ( -
+
- {activeProperty?.category || "N/A"} + + {activeProperty?.category || "N/A"} +
-
-
-

{activeProperty?.name}

-

{activeProperty?.city}

-

{activeProperty?.country}

-
-

- from: ${activeProperty?.rate}/hour +

+
+

+ {activeProperty?.name} +

+

+ {activeProperty?.city} +

+

+ {activeProperty?.country}{" "} +

+
+

+ from:{" "} + + ${activeProperty?.rate} + + /hour

-
+
{activeProperty?.max_capacity}
-
-
-

+

+
+

- - {(Number(activeProperty?.average_space_rating) || 0).toFixed(1)} - ({activeProperty?.space_rating_count}) + + {( + Number(activeProperty?.average_space_rating) || + 0 + ).toFixed(1)} + + ({activeProperty?.space_rating_count}) +

-
- {formatAmenities(activeProperty?.amenities).slice(0, 3).map((am, idx) => ( - - {am} +
+ {formatAmenities(activeProperty?.amenities) + .slice(0, 3) + .map((am, idx) => ( + + {am} + + ))} + {formatAmenities(activeProperty?.amenities).length > + 3 ? ( + + + + {formatAmenities(activeProperty?.amenities) + .length - 3}{" "} + more - ))} - {formatAmenities(activeProperty?.amenities).length > 3 ? +{formatAmenities(activeProperty?.amenities).length - 3} more : null} + ) : null}
-
+
) : null} - {(activeRoom?.booking_id && activeRoom?.booking?.id) ? ( + {activeRoom?.booking_id && activeRoom?.booking?.id ? ( <>
- {activeRoom?.booking?.space_category ? activeRoom?.booking?.space_category : "N/A"} + + {activeRoom?.booking?.space_category + ? activeRoom?.booking?.space_category + : "N/A"} +
-
-
+
+

Date

-

+

{" "} - {monthsMapping[new Date(activeRoom?.booking?.booking_start_time).getMonth()] + + {monthsMapping[ + new Date( + activeRoom?.booking?.booking_start_time + ).getMonth() + ] + " " + - new Date(activeRoom?.booking?.booking_start_time).getDate() + + new Date( + activeRoom?.booking?.booking_start_time + ).getDate() + "/" + - new Date(activeRoom?.booking?.booking_start_time).getFullYear()} + new Date( + activeRoom?.booking?.booking_start_time + ).getFullYear()}

-
+

Time

-

- {formatAMPM(activeRoom.booking?.booking_start_time)} - {formatAMPM(activeRoom?.booking?.booking_end_time)} +

+ {formatAMPM(activeRoom.booking?.booking_start_time)} -{" "} + {formatAMPM(activeRoom?.booking?.booking_end_time)}

-
+

Duration

-

{activeRoom?.booking?.duration / 3600} hours

+

+ {activeRoom?.booking?.duration / 3600} hours +

-
-

Add-ons:

-
+
+

Add-ons:

+
{activeRoom?.booking?.add_ons?.map((addon, idx) => ( -
+

{addon.name}

))}
-
+
) : null} -
- {(activeRoom?.booking_id && activeRoom?.booking?.id) && +
+ {activeRoom?.booking_id && activeRoom?.booking?.id && ( View booking - } + + )} - {activeRoom.id && !activeRoom?.booking?.id && + {activeRoom.id && !activeRoom?.booking?.id && ( View property - } + )}
@@ -959,36 +1260,56 @@ const MessagesPage = () => {
{showEmoji && ( -
-
- { - setMessage((prev) => prev + em.emoji); - setShowEmoji(false); - }} - searchDisabled - /> -
-
- )} +
+
+ { + setMessage((prev) => prev + em.emoji); + setShowEmoji(false); + }} + searchDisabled + /> +
+
+ )} - {showImagePreviewModal && - getRooms()} state={state} setMessages={setMessages} setActiveRoom={setActiveRoom} setRooms={setRooms} spaceId={spaceId} activeBooking={activeBooking} setShowImagePreviewModal={setShowImagePreviewModal}/> - } + {showImagePreviewModal && ( + getRooms()} + state={state} + setMessages={setMessages} + setActiveRoom={setActiveRoom} + setRooms={setRooms} + spaceId={spaceId} + activeBooking={activeBooking} + setShowImagePreviewModal={setShowImagePreviewModal} + /> + )} - {activeRoom?.booking_id === null && + {activeRoom?.booking_id === null && ( setShowMap(false)} /> - } + )}
); }; -export default MessagesPage; \ No newline at end of file +export default MessagesPage;