From dabcf8d3fdc0d166f51d21a44bfc701753891521 Mon Sep 17 00:00:00 2001 From: Vlad Velici Date: Tue, 25 Jun 2024 11:29:05 +0100 Subject: [PATCH 1/3] Show the clientId and createdAt for messages in demo app. Rename Message to MessageComponent since that's the name it's used as anyway. Make MessageComponent accept a Message as opposed to children elements to display the content. --- demo/src/components/Message/Message.tsx | 39 ------------ demo/src/components/Message/index.ts | 1 - .../MessageComponent/MessageComponent.tsx | 60 +++++++++++++++++++ demo/src/components/MessageComponent/index.ts | 1 + demo/src/containers/Chat/Chat.tsx | 9 +-- demo/src/index.css | 16 +++++ 6 files changed, 80 insertions(+), 46 deletions(-) delete mode 100644 demo/src/components/Message/Message.tsx delete mode 100644 demo/src/components/Message/index.ts create mode 100644 demo/src/components/MessageComponent/MessageComponent.tsx create mode 100644 demo/src/components/MessageComponent/index.ts diff --git a/demo/src/components/Message/Message.tsx b/demo/src/components/Message/Message.tsx deleted file mode 100644 index 7c697068..00000000 --- a/demo/src/components/Message/Message.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { ReactNode, useCallback } from 'react'; -import clsx from 'clsx'; - -interface MessageProps { - id: string; - self?: boolean; - children?: ReactNode | undefined; - onMessageClick?(id: string): void; -} -export const Message: React.FC = ({ id, self = false, children, onMessageClick }) => { - const handleMessageClick = useCallback(() => { - onMessageClick?.(id); - }, [id, onMessageClick]); - - return ( -
-
-
-
- {children} -
-
-
-
- ); -}; diff --git a/demo/src/components/Message/index.ts b/demo/src/components/Message/index.ts deleted file mode 100644 index f57df395..00000000 --- a/demo/src/components/Message/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Message } from './Message.tsx'; diff --git a/demo/src/components/MessageComponent/MessageComponent.tsx b/demo/src/components/MessageComponent/MessageComponent.tsx new file mode 100644 index 00000000..ad8acf9a --- /dev/null +++ b/demo/src/components/MessageComponent/MessageComponent.tsx @@ -0,0 +1,60 @@ +import { Message } from '@ably-labs/chat'; +import React, { useCallback } from 'react'; +import clsx from 'clsx'; + +function twoDigits(input : number) : string { + if (input === 0) { + return "00"; + } + if (input < 10) { + return "0"+input; + } + return ""+input; +} + +interface MessageProps { + id: string; + self?: boolean; + message: Message; + onMessageClick?(id: string): void; +} +export const MessageComponent: React.FC = ({ id, self = false, message, onMessageClick }) => { + const handleMessageClick = useCallback(() => { + onMessageClick?.(id); + }, [id, onMessageClick]); + + let displayCreatedAt : string; + if (new Date().getTime() - message.createdAt.getTime() < 1000 * 60 * 60 * 24) { + // last 24h show the time + displayCreatedAt = twoDigits(message.createdAt.getHours()) + ":" + twoDigits(message.createdAt.getMinutes()); + } else { + // older, show full date + displayCreatedAt = message.createdAt.getDate()+"/"+message.createdAt.getMonth()+"/"+message.createdAt.getFullYear() + " " + twoDigits(message.createdAt.getHours()) + ":" + twoDigits(message.createdAt.getMinutes()); + } + + return ( +
+
+
+
{ message.clientId } · { displayCreatedAt }{ message.createdAt.toLocaleString() }
+
+ { message.content } +
+
+
+
+ ); +}; diff --git a/demo/src/components/MessageComponent/index.ts b/demo/src/components/MessageComponent/index.ts new file mode 100644 index 00000000..8a6911a3 --- /dev/null +++ b/demo/src/components/MessageComponent/index.ts @@ -0,0 +1 @@ +export { MessageComponent } from './MessageComponent.tsx'; diff --git a/demo/src/containers/Chat/Chat.tsx b/demo/src/containers/Chat/Chat.tsx index 84ebe320..749c3cea 100644 --- a/demo/src/containers/Chat/Chat.tsx +++ b/demo/src/containers/Chat/Chat.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from 'react'; -import { Message as MessageComponent } from '../../components/Message'; +import { MessageComponent } from '../../components/MessageComponent'; import { MessageInput } from '../../components/MessageInput'; import { useMessages } from '../../hooks/useMessages'; import { useTypingIndicators } from '../../hooks/useTypingIndicators.ts'; @@ -41,11 +41,8 @@ export const Chat = () => { id={msg.timeserial} key={msg.timeserial} self={msg.clientId === clientId} - > -
-
{msg.content}
-
- + message={msg} + > ))} )} diff --git a/demo/src/index.css b/demo/src/index.css index ac65e450..714f518c 100644 --- a/demo/src/index.css +++ b/demo/src/index.css @@ -39,4 +39,20 @@ body { .reactions-picker > a:active { scale: 1.4; transform: rotate(7deg); +} + +.sent-at-time > .short { + display: inline; +} + +.sent-at-time > .long { + display: none; +} + +.sent-at-time:hover > .long { + display: inline; +} + +.sent-at-time:hover > .short { + display: none; } \ No newline at end of file From f079ed0ad23ba1ff8d9ad61170e6e1e6578694e5 Mon Sep 17 00:00:00 2001 From: Vlad Velici Date: Tue, 25 Jun 2024 11:31:49 +0100 Subject: [PATCH 2/3] Allow users to change their clientId in the demo app ... so we can have simple usernames when trying it out with other people --- demo/src/containers/Chat/Chat.tsx | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/demo/src/containers/Chat/Chat.tsx b/demo/src/containers/Chat/Chat.tsx index 749c3cea..22f290d8 100644 --- a/demo/src/containers/Chat/Chat.tsx +++ b/demo/src/containers/Chat/Chat.tsx @@ -28,8 +28,44 @@ export const Chat = () => { [sendMessage], ); + /** + * In a real app, changing the logged in user typically means navigating to + * some sort of login page and then navigating back to the main app. + * + * There is no real login here. We just have to specify a clientId in the + * request that we sent to get a valid token from our function at + * demo/api/ably-token-request. This happens when the demo app loads the + * first time and periodically to refresh the token (handled by ably-js). + * + * See demo/src/main.tsx to see how the clientId is initially set (random + * and saved in sessionStorage for consistency between page refreshes). This + * function sets the given clientId in sessionStorage and refreshes the page, + * meaning the new clientId will be read and set on page load. + * + * In a live app if you need to re-authenticate with another clientId you + * will need to stop everything including the Ably Pubsub Client and restart + * with the new clientId. Neither libraries support changing the clientId + * witohut reconnecting. Typically changing user is achieved by navigating to + * a login page and back, unless the login page is part of the same single- + * page app as the chat. + * + * Ably and Ably Chat also offer a feature called Presence where user profile + * data can be attached (things like avatar URLs or display names). Editing a + * profile through Presence is possible without dropping the connection and + * it does not change the clientId. See @todo link to docs for Presence. + */ + function changeClientId() { + const newClientId = prompt("Enter your new clientId"); + if (!newClientId) { + return; + } + sessionStorage.setItem("ably-chat-demo-clientId", newClientId); + window.location.reload(); + } + return (
+
You are {clientId}. Change clientId.
{loading &&
loading...
} {!loading && (
Date: Tue, 25 Jun 2024 13:49:55 +0100 Subject: [PATCH 3/3] Make send button and message input not overlap --- demo/src/components/MessageInput/MessageInput.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demo/src/components/MessageInput/MessageInput.tsx b/demo/src/components/MessageInput/MessageInput.tsx index 06afa8ae..2b40e203 100644 --- a/demo/src/components/MessageInput/MessageInput.tsx +++ b/demo/src/components/MessageInput/MessageInput.tsx @@ -38,7 +38,7 @@ export const MessageInput: FC = ({ return (
= ({ onChange={handleValueChange} disabled={disabled} placeholder="Type.." - className="w-full focus:outline-none focus:placeholder-gray-400 text-gray-600 placeholder-gray-600 pl-2 bg-gray-200 rounded-md py-1" + className="w-full focus:outline-none focus:placeholder-gray-400 text-gray-600 placeholder-gray-600 pl-2 pr-2 bg-gray-200 rounded-l-md py-1" autoFocus /> -
+