Skip to content

Commit

Permalink
Reply Feature with styles
Browse files Browse the repository at this point in the history
  • Loading branch information
HarshRajat committed Sep 27, 2024
1 parent 36a808a commit e454e13
Show file tree
Hide file tree
Showing 18 changed files with 521 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ChatDataContext } from '../../../context';
import { useChatData } from '../../../hooks';
import { ReplyIcon } from '../../../icons/PushIcons';
import { Div, Image, Section, Span } from '../../reusables';
import { checkTwitterUrl } from '../helpers/twitter';
import { ThemeContext } from '../theme/ThemeProvider';

import { useConnectWallet, useSetChain } from '@web3-onboard/react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// React + Web3 Essentials
import { useContext, useRef, useState, useEffect, RefObject } from 'react';
import { RefObject, useContext, useEffect, useRef, useState } from 'react';

// External Packages

// Internal Compoonents
import { Image, Section, Button, Spinner, Span } from '../../../reusables';
import { Button, Image, Section, Span, Spinner } from '../../../reusables';
import { ThemeContext } from '../../theme/ThemeProvider';

// Internal Configs
Expand Down Expand Up @@ -42,6 +42,9 @@ export const Reactions = ({ chatReactions }: { chatReactions: IReactionsForChatM
return acc;
}, {} as IReactions);

// generate a unique key for the reactions
const reactionsKey = chatReactions.map((reaction) => reaction.reference).join('-');

console.debug('UIWeb::components::ChatViewBubble::Reactions::uniqueReactions', uniqueReactions);

// render reactions
Expand All @@ -50,6 +53,7 @@ export const Reactions = ({ chatReactions }: { chatReactions: IReactionsForChatM
<>
{Object.keys(uniqueReactions).length > 2 ? (
<Section
key={`reactions-${reactionsKey}`}
borderRadius={theme.borderRadius?.reactionsBorderRadius}
background={theme.backgroundColor?.chatReceivedBubbleBackground}
padding={theme.padding?.reactionsPadding}
Expand All @@ -74,6 +78,7 @@ export const Reactions = ({ chatReactions }: { chatReactions: IReactionsForChatM
) : (
Object.entries(uniqueReactions).map(([content, reactions]) => (
<Section
key={`reactions-${content}-${reactionsKey}`}
borderRadius={theme.borderRadius?.reactionsBorderRadius}
background={theme.backgroundColor?.chatReceivedBubbleBackground}
padding={theme.padding?.reactionsPadding}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ import { ImageCard } from './cards/image/ImageCard';
import { MessageCard } from './cards/message/MessageCard';
import { TwitterCard } from './cards/twitter/TwitterCard';

export const CardRenderer = ({ chat, position }: { chat: IMessagePayload; position: number }) => {
export const CardRenderer = ({
chat,
position,
previewMode = false,
activeMode = false,
}: {
chat: IMessagePayload;
position: number;
previewMode?: boolean;
activeMode?: boolean;
}) => {
// get theme
const theme = useContext(ThemeContext);

Expand All @@ -26,15 +36,6 @@ export const CardRenderer = ({ chat, position }: { chat: IMessagePayload; positi
? (typeof chat.messageObj?.content === 'string' ? chat.messageObj?.content : '') ?? ''
: (chat.messageObj as string);

// check and render tweets
const { tweetId, messageType }: TwitterFeedReturnType = checkTwitterUrl({
message: message,
});

if (messageType === 'TwitterFeedLink') {
chat.messageType = 'TwitterFeedLink';
}

// test if the payload is encrypted, if so convert it to text
if (isMessageEncrypted(message)) {
chat.messageType = 'Text';
Expand All @@ -43,32 +44,71 @@ export const CardRenderer = ({ chat, position }: { chat: IMessagePayload; positi
// get user account
const account = user?.account ?? '';

// deduce font color
const fontColor =
position && !activeMode ? theme.textColor?.chatSentBubbleText : theme.textColor?.chatReceivedBubbleText;

// Render the card render
return (
<>
{/* Message Card */}
{/* Twitter Card is handled by PreviewRenderer */}
{/* Frame Card is handled by PreviewRenderer */}
{/* Code Card is handled by CodeRenderer */}
{chat && chat.messageType === 'Text' && (
<MessageCard
chat={chat}
position={position}
account={account}
color={fontColor}
previewMode={previewMode}
activeMode={activeMode}
/>
)}

{/* Image Card */}
{chat.messageType === 'Image' && <ImageCard chat={chat} />}
{chat.messageType === 'Image' && (
// Background only valid when no preview or active mode
<ImageCard
chat={chat}
background={
position && !activeMode && !previewMode
? theme.backgroundColor?.chatSentBubbleBackground
: theme.backgroundColor?.chatReceivedBubbleBackground
}
color={fontColor}
previewMode={previewMode}
activeMode={activeMode}
/>
)}

{/* File Card */}
{chat.messageType === 'File' && <FileCard chat={chat} />}
{chat.messageType === 'File' && (
<FileCard
chat={chat}
background={
position && !activeMode
? theme.backgroundColor?.chatPreviewSentBubbleBackground
: theme.backgroundColor?.chatPreviewRecievedBubbleBackground
}
color={fontColor}
previewMode={previewMode}
activeMode={activeMode}
/>
)}

{/* Gif Card */}
{chat.messageType === 'GIF' && <GIFCard chat={chat} />}

{/* Twitter Card */}
{chat.messageType === 'TwitterFeedLink' && (
<TwitterCard
tweetId={tweetId}
{chat.messageType === 'GIF' && (
<GIFCard
chat={chat}
background={
position && !activeMode && !previewMode
? theme.backgroundColor?.chatSentBubbleBackground
: theme.backgroundColor?.chatReceivedBubbleBackground
}
color={fontColor}
previewMode={previewMode}
activeMode={activeMode}
/>
)}

Expand All @@ -78,6 +118,9 @@ export const CardRenderer = ({ chat, position }: { chat: IMessagePayload; positi
chat={chat}
position={position}
account={account}
color={fontColor}
previewMode={previewMode}
activeMode={activeMode}
/>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import { ReactNode, useContext, useEffect, useRef, useState } from 'react';
// React + Web3 Essentials
import { useContext } from 'react';

// External Packages
import styled from 'styled-components';

// Internal Components
import { useChatData } from '../../../hooks';
import { checkTwitterUrl } from '../helpers/twitter';
import { ThemeContext } from '../theme/ThemeProvider';

import { isMessageEncrypted, pCAIP10ToWallet } from '../../../helpers';
import { IMessagePayload, TwitterFeedReturnType } from '../exportedTypes';

import { Section } from '../../reusables';
import { CardRenderer } from './CardRenderer';
import { ReplyCard } from './cards/reply/ReplyCard';

// Internal Configs

// Assets

// Interfaces & Types
interface ChatViewBubbleCoreProps extends React.ComponentProps<typeof Section> {
borderBG?: string;
previewMode?: boolean;
}

// Main Logic
// Deep Copy Helper Function
function deepCopy<T>(obj: T): T {
if (obj === null || typeof obj !== 'object') {
return obj;
Expand All @@ -36,7 +53,18 @@ function deepCopy<T>(obj: T): T {
throw new Error(`Unable to copy obj! Its type isn't supported.`);
}

export const ChatViewBubbleCore = ({ chat, chatId }: { chat: IMessagePayload; chatId: string | undefined }) => {
// Exported Default Component
export const ChatViewBubbleCore = ({
chat,
chatId,
previewMode = false,
activeMode = false,
}: {
chat: IMessagePayload;
chatId: string | undefined;
previewMode?: boolean;
activeMode?: boolean;
}) => {
// get theme
const theme = useContext(ThemeContext);

Expand All @@ -47,36 +75,6 @@ export const ChatViewBubbleCore = ({ chat, chatId }: { chat: IMessagePayload; ch
const chatPosition =
pCAIP10ToWallet(chat.fromDID).toLowerCase() !== pCAIP10ToWallet(user?.account ?? '')?.toLowerCase() ? 0 : 1;

// // manale reply payload loader
// type ReplyPayloadManagerType = {
// payload: IMessagePayload | null;
// loading: boolean;
// loaded: boolean;
// err: string | null;
// };

// const [replyPayloadManager, setReplyPayloadManager] = useState<ReplyPayloadManagerType>({
// payload: null,
// loading: true,
// loaded: false,
// err: null,
// });

// const resolveReplyPayload = async (chat: IMessagePayload, reference: string | null) => {
// if (reference && chatId) {
// try {
// const payloads = await user?.chat.history(chatId, { reference: reference, limit: 1 });
// const payload = payloads ? payloads[0] : null;
// console.log('resolving reply payload', payload);
// setReplyPayloadManager({ payload: payload, loading: false, loaded: true, err: null });
// } catch (err) {
// setReplyPayloadManager({ payload: null, loading: false, loaded: true, err: 'Unable to load Preview' });
// }
// } else {
// setReplyPayloadManager({ payload: null, loading: false, loaded: true, err: 'Reference not found' });
// }
// };

const renderBubble = (chat: IMessagePayload, position: number) => {
const components: JSX.Element[] = [];

Expand All @@ -97,8 +95,9 @@ export const ChatViewBubbleCore = ({ chat, chatId }: { chat: IMessagePayload; ch
// Reply is it's own card that calls ChatViewBubbleCardRenderer
// This avoids transitive recursion

// Use replyReference to check and call reply card
if (replyReference !== '') {
// Use replyReference to check and call reply card but only if activeMode is false
// as activeMode will be true when user is replying to a message
if (replyReference !== '' && !activeMode) {
// Add Reply Card
components.push(
<ReplyCard
Expand All @@ -118,12 +117,42 @@ export const ChatViewBubbleCore = ({ chat, chatId }: { chat: IMessagePayload; ch
key="card"
chat={derivedMsg}
position={position}
previewMode={previewMode}
activeMode={activeMode}
/>
);
}

return <>{components}</>;
// deduce background color
// if active mode, use the normal background color as this is user replying to a message
// if preview mode, use the reply background color
// if not preview mode, use the normal background color
const background = activeMode
? theme.backgroundColor?.chatActivePreviewBubbleBackground
: position
? previewMode
? theme.backgroundColor?.chatPreviewSentBubbleBackground
: theme.backgroundColor?.chatSentBubbleBackground
: previewMode
? theme.backgroundColor?.chatPreviewRecievedBubbleBackground
: theme.backgroundColor?.chatReceivedBubbleBackground;

return (
<ChatViewBubbleCoreSection
flexDirection="column"
background={background}
borderBG={activeMode ? theme.backgroundColor?.chatActivePreviewBorderBubbleBackground : 'transparent'}
borderRadius={activeMode ? theme.borderRadius?.chatBubbleReplyBorderRadius : '0px'}
previewMode={previewMode}
>
{components}
</ChatViewBubbleCoreSection>
);
};

return renderBubble(chat, chatPosition);
};

const ChatViewBubbleCoreSection = styled(Section)<ChatViewBubbleCoreProps>`
border-left: ${({ borderBG, previewMode }) => (previewMode ? `4px solid ${borderBG || 'transparent'}` : 'none')};
`;
Loading

0 comments on commit e454e13

Please sign in to comment.