From d9c6f29dd34c997d1c3f380b730efe12e85bb1b3 Mon Sep 17 00:00:00 2001 From: Michael Clapham Date: Sun, 31 Mar 2024 18:18:17 +0200 Subject: [PATCH] Move sending of messages to top level. Refactor sharing actions UI. --- src/App.tsx | 16 ++- src/feature/history/HistoryCard.tsx | 4 +- .../session-actions/OpenWebsiteModal.tsx | 45 -------- .../session-actions/SessionActionModal.ts | 11 -- .../session-actions/SessionActionsList.tsx | 107 ------------------ src/feature/session/SessionMessage.ts | 6 +- src/feature/session/SessionPage.tsx | 9 +- src/feature/share/ShareCard.tsx | 49 ++++---- .../share/share-actions/SendMessageModal.tsx | 34 ++++++ .../share/share-actions/ShareModal.tsx | 20 ++++ 10 files changed, 108 insertions(+), 193 deletions(-) delete mode 100644 src/feature/session-actions/OpenWebsiteModal.tsx delete mode 100644 src/feature/session-actions/SessionActionModal.ts delete mode 100644 src/feature/session-actions/SessionActionsList.tsx create mode 100644 src/feature/share/share-actions/SendMessageModal.tsx create mode 100644 src/feature/share/share-actions/ShareModal.tsx diff --git a/src/App.tsx b/src/App.tsx index 6f6c263..4ef8a4a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -89,6 +89,19 @@ export const App: React.FC = () => { setChangeToRoute("/index.html"); }; + const onShare = (msg: SessionMessage) => { + let msgWithSender: SessionMessage = { + ...msg, + senderId: wsClient.getId() ?? "", + senderName: wsClient.getName(), + } + let serverMsg: ServerTypes.BroadcastToSessionMsg = { + type: "BroadcastToSession", + payload: msgWithSender + }; + wsClient.sendMessage(serverMsg); + } + return ( @@ -107,10 +120,11 @@ export const App: React.FC = () => { diff --git a/src/feature/history/HistoryCard.tsx b/src/feature/history/HistoryCard.tsx index 32e4486..e1bd129 100644 --- a/src/feature/history/HistoryCard.tsx +++ b/src/feature/history/HistoryCard.tsx @@ -13,7 +13,7 @@ export const HistoryCard: React.FC = ({messages}) => { { messages.length === 0 ? : - messages.map(msg => ) } + messages.map(msg => ) } ; }; @@ -24,7 +24,7 @@ type MessageProps = { const Message: React.FC = ({msg}) => { return - {msg.senderName}: + {msg.senderName}: {msg.text} } diff --git a/src/feature/session-actions/OpenWebsiteModal.tsx b/src/feature/session-actions/OpenWebsiteModal.tsx deleted file mode 100644 index cc27ccc..0000000 --- a/src/feature/session-actions/OpenWebsiteModal.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { IonButton, IonInput } from "@ionic/react"; -import React from "react"; -import { SessionMessage } from "../session/SessionMessage"; -import { SessionActionModal } from "./SessionActionModal"; - -export class OpenWebsiteModal extends SessionActionModal< - {}, - { urlInput: string } -> { - state = { - urlInput: "", - }; - - onOpenWebsiteClick = () => { - let id = this.props.wsClient.getId(); - if (this.props.wsClient && id != null) { - let sessionMsg: SessionMessage = { - type: "OPEN_WEBSITE", - text: this.state.urlInput, - senderId: id, - senderName: this.props.wsClient.getName(), - }; - this.props.wsClient.sendMessage({ - type: "BroadcastToSession", - payload: sessionMsg, - }); - } - this.props.closeModal(); - }; - - render() { - return ( - <> -

Open Website

-

Open a website on devices controlled by this session

- this.setState({ urlInput: e.detail.value! })} - > - Open Website - - ); - } -} diff --git a/src/feature/session-actions/SessionActionModal.ts b/src/feature/session-actions/SessionActionModal.ts deleted file mode 100644 index 8f0b7a6..0000000 --- a/src/feature/session-actions/SessionActionModal.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; -import { WSClient } from "../../WSClient"; - -export interface SessionActionModalProps { - wsClient: WSClient; - closeModal: () => any; -} - -export class SessionActionModal

extends React.Component { - -} \ No newline at end of file diff --git a/src/feature/session-actions/SessionActionsList.tsx b/src/feature/session-actions/SessionActionsList.tsx deleted file mode 100644 index 7ce4683..0000000 --- a/src/feature/session-actions/SessionActionsList.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import React from "react"; -import { globeOutline } from "ionicons/icons"; -import { IonIcon, IonModal } from "@ionic/react"; -import { OpenWebsiteModal } from "./OpenWebsiteModal"; -import { WSClient } from "../../WSClient"; -import { SessionActionModal } from "./SessionActionModal"; - -export interface SessionActionsListProps { - wsClient: WSClient; - userIsSessionOwner: boolean; -} - -export interface SessionActionsListState { - actionModalOpen: boolean; - actionModalComponent?: typeof SessionActionModal; -} - -export interface SessionActionSummary { - name: string; - ionicon: string; - ownerOnly: boolean; - modalComponent?: typeof SessionActionModal; -} - -const sessionActions: SessionActionSummary[] = [ - { - name: "Open Website", - ionicon: globeOutline, - ownerOnly: true, - modalComponent: OpenWebsiteModal, - }, -]; - -export class SessionActionsList extends React.Component< - SessionActionsListProps, - SessionActionsListState -> { - state: SessionActionsListState = { - actionModalOpen: false, - }; - - render() { - console.log("User is session owner", this.props.userIsSessionOwner); - return ( -

-

- User is session owner? {this.props.userIsSessionOwner ? "yes" : "no"} -

- {sessionActions - .filter( - (action) => this.props.userIsSessionOwner || !action.ownerOnly - ) - .map((action) => this.renderActionButton(action))} - - {this.renderModal()} - -
- ); - } - - renderActionButton = (action: SessionActionSummary) => { - return ( -
this.onActionClicked(action)} - style={{ - borderWidth: 1, - borderStyle: "solid", - borderColor: "white", - borderRadius: 20, - display: "inline-block", - }} - > -

{action.name}

- -
- ); - }; - - renderModal = () => { - let ModalComponent = this.state.actionModalComponent; - if (ModalComponent) { - return ( - - ); - } - }; - - closeModal = () => { - this.setState({ actionModalOpen: false }); - }; - - onActionClicked = (action: SessionActionSummary) => { - if (action.name === "Open Website") { - this.setState({ - actionModalOpen: true, - actionModalComponent: action.modalComponent, - }); - } - }; -} diff --git a/src/feature/session/SessionMessage.ts b/src/feature/session/SessionMessage.ts index ff3c137..1d953fb 100644 --- a/src/feature/session/SessionMessage.ts +++ b/src/feature/session/SessionMessage.ts @@ -4,9 +4,10 @@ export const sessionMessageTypes = ["TEXT_MESSAGE", "FILE", "OPEN_WEBSITE"] as c export type SessionMessageType = typeof sessionMessageTypes[number]; export interface SessionMessage { + uuid?: string; type?: SessionMessageType; - senderId: string; - senderName: string; + senderId?: string; + senderName?: string; text?: string; } @@ -20,6 +21,7 @@ export function mapSessionMsg(serverMsg: ServerTypes.BroadcastFromSessionMsg): S sessionMsgType = undefined; } return { + uuid: ("" + Math.random() + "-" + Math.random()).replace(".", "0"), type: sessionMsgType, senderId: serverMsg.senderId, senderName: serverMsg.payload["senderName"] ?? "", diff --git a/src/feature/session/SessionPage.tsx b/src/feature/session/SessionPage.tsx index c64b89f..f43db1b 100644 --- a/src/feature/session/SessionPage.tsx +++ b/src/feature/session/SessionPage.tsx @@ -8,7 +8,6 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { WSClient } from "../../WSClient"; import { ClientsCard } from "../clients/ClientsCard"; import { HistoryCard } from "../history/HistoryCard"; import { ShareCard } from "../share/ShareCard"; @@ -19,7 +18,8 @@ export interface SessionPageProps { sessionId: string | undefined; sessionOwnerId: string | undefined; clientMap: Record; - wsClient: WSClient; + userIsSessionOwner: boolean; + onShare: (msg: SessionMessage) => void; onLeaveSession: () => any; } @@ -28,7 +28,8 @@ export const SessionPage: React.FC = ({ sessionId, sessionOwnerId, clientMap, - wsClient, + userIsSessionOwner, + onShare, onLeaveSession, }) => { return ( @@ -49,7 +50,7 @@ export const SessionPage: React.FC = ({ - + Leave Session with id: {sessionId} diff --git a/src/feature/share/ShareCard.tsx b/src/feature/share/ShareCard.tsx index 26c23a8..7233598 100644 --- a/src/feature/share/ShareCard.tsx +++ b/src/feature/share/ShareCard.tsx @@ -1,25 +1,32 @@ -import { IonCard, IonCardHeader, IonCardTitle, IonCardContent } from "@ionic/react"; -import React from "react"; -import { SessionActionsList } from "../session-actions/SessionActionsList"; -import { WSClient } from "../../WSClient"; +import { IonCard, IonCardHeader, IonCardTitle, IonCardContent, IonButton, IonModal } from "@ionic/react"; +import React, { useState } from "react"; +import { SessionMessage, SessionMessageType } from "../session/SessionMessage"; +import { ShareModal } from "./share-actions/ShareModal"; export type ShareCardProps = { - wsClient: WSClient; - sessionOwnerId?: string; + onShare: (msg: SessionMessage) => void; + userIsSessionOwner?: boolean; } -export const ShareCard: React.FC = ({wsClient, sessionOwnerId}) => { - return - - Share - - - - - ; -}; +export const ShareCard: React.FC = ({onShare, userIsSessionOwner}) => { + const [shareModalTypeOpen, setShareModalTypeOpen] = useState(null); + + return + + Share + + + {/* Send text message */} + setShareModalTypeOpen("TEXT_MESSAGE")} + >Send Message + + setShareModalTypeOpen(null)}> + setShareModalTypeOpen(null)} + /> + + ; +}; \ No newline at end of file diff --git a/src/feature/share/share-actions/SendMessageModal.tsx b/src/feature/share/share-actions/SendMessageModal.tsx new file mode 100644 index 0000000..a45853d --- /dev/null +++ b/src/feature/share/share-actions/SendMessageModal.tsx @@ -0,0 +1,34 @@ +import { IonButton, IonInput } from "@ionic/react"; +import React, { useState } from "react"; +import { ShareModalProps } from "./ShareModal"; +import { SessionMessage } from "../../session/SessionMessage"; + +export const SendMessageModal: React.FC = ({ + onShare, + closeModal, +}) => { + + const [text, setText] = useState(""); + + const sendClick = () => { + let sessionMsg: SessionMessage = { + type: "TEXT_MESSAGE", + text: text, + }; + onShare(sessionMsg); + closeModal(); + }; + + return ( +
+

Send message

+

Send message to all clients in this session.

+ setText(e.detail.value!)} + > + sendClick()}>Send +
+ ); +} diff --git a/src/feature/share/share-actions/ShareModal.tsx b/src/feature/share/share-actions/ShareModal.tsx new file mode 100644 index 0000000..db6b1ca --- /dev/null +++ b/src/feature/share/share-actions/ShareModal.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { SessionMessage, SessionMessageType } from "../../session/SessionMessage"; +import { SendMessageModal } from "./SendMessageModal"; + +export type ShareModalProps = { + type: SessionMessageType | null; + onShare: (msg: SessionMessage) => void; + closeModal: () => any; +}; + +export const ShareModal: React.FC = ({type, onShare, closeModal}) => { + switch(type) { + case "TEXT_MESSAGE": return + default: return null; + } +} \ No newline at end of file