diff --git a/src/play-dates/components/MatchDetailsModal.jsx b/src/play-dates/components/MatchDetailsModal.jsx index 550d178a..d7cfc108 100644 --- a/src/play-dates/components/MatchDetailsModal.jsx +++ b/src/play-dates/components/MatchDetailsModal.jsx @@ -27,17 +27,14 @@ import { import PlayerAvatar from "./PlayerAvatar"; import { cancelMatch, - createMatchMessage, deleteMatchNotification, getShareLink, joinMatch, leaveMatch, - listMatchMessages, listMatchNotifications, notifyMatchPlayers, removeParticipant, searchPlayers, - sendMatchPlayerDirectMessage, updateMatch, } from "../services/matches"; import { rejectInvite } from "../services/invites"; @@ -553,6 +550,45 @@ const getInviteStatus = (invite) => { return ""; }; +const openSmsComposer = (recipients, onToast) => { + if (!Array.isArray(recipients) || recipients.length === 0) { + return; + } + + try { + const ua = + typeof navigator !== "undefined" && navigator.userAgent + ? navigator.userAgent + : ""; + const isAndroid = /Android/i.test(ua); + const isAppleMobile = /(iPad|iPhone|iPod)/i.test(ua); + + let url = "sms:"; + if (recipients.length > 0) { + if (isAndroid) { + const path = recipients.map((value) => encodeURIComponent(value)).join(";"); + const addresses = encodeURIComponent(recipients.join(";")); + url = `smsto:${path}?addresses=${addresses}`; + } else if (isAppleMobile) { + const addresses = encodeURIComponent(recipients.join(",")); + url = `sms:&addresses=${addresses}`; + } else { + const path = recipients.map((value) => encodeURIComponent(value)).join(","); + url = `sms:${path}`; + } + } + + onToast?.(isAppleMobile ? "Opening Messages..." : "Opening messages..."); + + if (typeof window !== "undefined") { + window.location.href = url; + } + } catch (error) { + console.error(error); + onToast?.("We couldn't open messages", "error"); + } +}; + const ACCEPTED_INVITE_STATUSES = new Set([ "accepted", "confirmed", @@ -808,10 +844,6 @@ const MatchDetailsModal = ({ const [notifyResults, setNotifyResults] = useState([]); const [notifySelected, setNotifySelected] = useState([]); const [notifySending, setNotifySending] = useState(false); - const [messageText, setMessageText] = useState(""); - const [messages, setMessages] = useState([]); - const [messagesLoading, setMessagesLoading] = useState(false); - const [messageSending, setMessageSending] = useState(false); const googleApiKey = import.meta.env.VITE_GOOGLE_API_KEY; const shareCopyTimeoutRef = useRef(null); @@ -1191,31 +1223,10 @@ const MatchDetailsModal = ({ } }, [isHost, isOpenMatch, matchId]); - const loadMatchMessages = useCallback(async () => { - if (!matchId || !isJoined) { - setMessages([]); - return; - } - try { - setMessagesLoading(true); - const data = await listMatchMessages(matchId); - setMessages(Array.isArray(data?.messages) ? data.messages : []); - } catch (error) { - console.error("Failed to load match messages", error); - setMessages([]); - } finally { - setMessagesLoading(false); - } - }, [isJoined, matchId]); - useEffect(() => { loadMatchNotifications(); }, [loadMatchNotifications]); - useEffect(() => { - loadMatchMessages(); - }, [loadMatchMessages]); - useEffect(() => { if (!isOpen || !isHost || !isOpenMatch) return undefined; const query = notifySearch.trim(); @@ -1328,58 +1339,6 @@ const MatchDetailsModal = ({ [matchId, onToast], ); - const handleSendGroupMessage = useCallback(async () => { - const body = messageText.trim(); - if (!matchId || !body) return; - try { - setMessageSending(true); - const response = await createMatchMessage(matchId, { body }); - setMessageText(""); - if (response?.message) { - setMessages((prev) => [...prev, response.message]); - } else { - await loadMatchMessages(); - } - onToast?.("Message posted."); - } catch (error) { - console.error(error); - onToast?.( - error?.response?.data?.message || - error?.response?.data?.error || - error?.message || - "Failed to send message", - "error", - ); - } finally { - setMessageSending(false); - } - }, [loadMatchMessages, matchId, messageText, onToast]); - - const handleSendDm = useCallback( - async (player) => { - if (!matchId || !player?.playerId) return; - const body = window.prompt(`Message ${player.name}`); - if (!body || !body.trim()) return; - try { - await sendMatchPlayerDirectMessage(matchId, player.playerId, { - body: body.trim(), - }); - onToast?.(`Message sent to ${player.name}.`); - loadMatchMessages(); - } catch (error) { - console.error(error); - onToast?.( - error?.response?.data?.message || - error?.response?.data?.error || - error?.message || - "Failed to send direct message", - "error", - ); - } - }, - [loadMatchMessages, matchId, onToast], - ); - useEffect(() => { if ((!isHost || isArchived || isCancelled) && isEditing) { setIsEditing(false); @@ -1962,10 +1921,31 @@ const MatchDetailsModal = ({ return Math.max(remainingSpots, 0); }, [remainingSpots]); - const canMessageParticipants = committedParticipants.length > 1; + const participantPhoneRecipients = useMemo(() => { + if (!isHost) return []; + const seen = new Set(); + return committedParticipants.reduce((numbers, participant) => { + if (!participant) return numbers; + if (match?.host_id && participantMatchesMember(participant, match.host_id)) { + return numbers; + } + const phoneRaw = getParticipantPhone(participant); + const normalized = normalizePhoneValue(phoneRaw); + if (!normalized || seen.has(normalized)) { + return numbers; + } + seen.add(normalized); + numbers.push(normalized); + return numbers; + }, []); + }, [committedParticipants, isHost, match?.host_id]); + + const canMessageParticipants = participantPhoneRecipients.length > 0; const messageParticipantsDescription = canMessageParticipants - ? "Post a group update to confirmed players." - : "Add another confirmed player to enable group messages."; + ? participantPhoneRecipients.length === 1 + ? "Start a group text with the confirmed player." + : "Start a group text with your confirmed players." + : "Add player phone numbers to enable group texts."; const pendingInvitesList = useMemo(() => { if (pendingInvitees.length === 0) return []; @@ -2895,29 +2875,22 @@ const MatchDetailsModal = ({
- Message group + Message participants
- Post a match-scoped update for everyone confirmed on this roster. + {messageParticipantsDescription}
Match messages
-Loading messages...
- ) : messages.length === 0 ? ( -No messages yet.
- ) : ( -- {sender.full_name || sender.name || `Player ${message.sender_id}`} - {message.recipient_id ? " ยท Direct message" : ""} -
-- {message.body} -
-