Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/1239 message wrapper for render library #1297

Merged
merged 17 commits into from Mar 24, 2021

Conversation

AudreyKj
Copy link
Contributor

@AudreyKj AudreyKj commented Mar 19, 2021

closes #1239

changes

  • updated typing related to the templates api (both in frontend and httpClient)
  • created SharedServices to share fallbackImage across frontend and the render library
  • typing for rendering content
  • render library revamp with better typing + cleaned its components from all unnecessary props
  • moved all message rendering logic to InfoMessageWrapper and updated all the frontend

screenshots
--> as all the message-rendering logic is moved to the wrapper, the template modal renders nicely all types of templates + the fallback image improves user experience for all non-valid images

Screenshot 2021-03-17 at 17 49 01

Screenshot 2021-03-17 at 15 00 48

@github-actions github-actions bot added the fix label Mar 19, 2021
return {
fromContact,
contact: props.contact ?? null,
commandCallback: props.commandCallback,
sentAt: props.lastInGroup ? formatTime(props.message.sentAt) : null,
};
Copy link
Contributor Author

@AudreyKj AudreyKj Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the logic exclusive to rendering messages is moved to the wrapper <InfoMessageWrapper />, which displays the Avatar and sentAt time along with the message's content.

This wrapper is also responsible for determining is which side the messages are displayed. The components inside the render library are stripped down from this logic and are just pure components.

  • RenderProps contains the base props common to all the content that the library needs to render (i.e. we need the source and the renderedContent for both messages and templates). It's the base type from MessageRenderProps and TemplateRenderProps . <InfoMessageWrapper /> takes in MessageRenderProps to get the necessary data for the message rendering logic.

  • DefaultRenderingProps are needed by some components that the library needs to render, for all content (for all the components that use <Text />, as this props will determine the backgroundColor of the message)


export function isFromContact(message: RenderedContentUnion) {
if (message && 'senderType' in message) return message?.senderType === SenderType.sourceContact;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typing for render library: RenderedContentUnion represents the type for the content that the library is rendering

@@ -22,7 +23,8 @@ export default function templatesReducer(state = defaultState, action: Action):
case getType(actions.listTemplatesAction):
return {
...state,
all: action.payload,
all: action.payload.templates,
source: action.payload.source,
};
Copy link
Contributor Author

@AudreyKj AudreyKj Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps track of the source of the templates that are listed. This is needed because we fetch the list of templates only when the conversation's source channel changes (as the api lists templates based on the source).

}

event.currentTarget.alt = 'fallback image';
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With @thorstenairy we had the idea of creating SharedServices that contains helper functions needed by both the frontend and our libraries. Here fallbackImage serves for images in both the frontend and the render library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah so this was brought up many times and I should probably write down the answer eheh

the tl;dr is "shared" "util" is always bad as then we mix things that have nothing to do with each other. (I think last I talked to @thorstenairy exactly about this because he introduced a shared lib with was a date lib)

A better approach is to have small libraries that solve a specific problem.

to me, it feels like here we're introducting an avatar library. So best is 1) call it what it does 2) that way we can move more "avatar related things" there 3) by far themost important point: we do not open the door to catch all libraries

Copy link
Contributor Author

@AudreyKj AudreyKj Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lucapette the idea was to also use this function for the fallback images in the render library.

I totally get the point of not falling in 'catch all libraries' so should we create 2 libraries: one avatar library used for the channel avatars (and possibly also the Avatar component), and another library (fallback image library) for the fallback images in the render library? (but then we would duplicate code)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicating a little of code is better than the wrong abstraction for sure

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok we talked offline about it: we do not need to introduce libraries as the abstraction is not worth it. //c @thorstenairy

chatplugin = 'chatplugin',
smsTwilio = 'twilio.sms',
whatsappTwilio = 'twilio.whatsapp',
}
Copy link
Contributor Author

@AudreyKj AudreyKj Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the enum SourceType was duplicated in both Message and Channels in the httpClient library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source was a better name :D (sorry... I suggested source type somewhere else.... without realising we call the field source everywhere in the api)

@@ -18,5 +19,6 @@ export const Media = ({height, contentInfo: {altText, fileUrl}}: MediaRenderProp
className={`${styles.mediaImage} ${
height === MediaHeight.tall ? styles.tall : height === MediaHeight.medium ? styles.medium : styles.short
}`}
onError={(event: React.SyntheticEvent<HTMLImageElement, Event>) => fallbackImage(event, 'mediaImage')}
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added fallbackImage for all the images inside the render library. This fallback does not work for video, I've created an issue for this #1299

@AudreyKj AudreyKj marked this pull request as ready for review March 19, 2021 09:14
Copy link
Contributor

@chrismatix chrismatix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass. Amazing work already!

@@ -47,6 +47,9 @@ const MessageInput = (props: MessageInputProps & ConnectedProps<typeof connector
const sendButtonRef = useRef(null);
const emojiDiv = useRef<HTMLDivElement>(null);

const conversationIdParams = useParams();
const currentConversationId: string = conversationIdParams[Object.keys(conversationIdParams)[0]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible I would suggest to always use the getCurrentConversation selector since it also uses the routing params but in a declarative and typed way :)

message: RenderedContent;
interface RenderProps {
contentType: 'message' | 'template';
renderedContent: RenderedContentUnion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: At this point the content is not yet rendered so maybe just content would be enough (applies to other places too)

import {isFromContact, RenderedContent, Contact} from 'httpclient';
import {formatTime} from 'dates';
import {DefaultMessageRenderingProps} from './components';
import {isFromContact, RenderedContentUnion} from 'httpclient';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: shared.ts was never a great name for this file. Looking at it, what do you think about props.ts or something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think props.ts makes sense :)

load("@com_github_airyhq_bazel_tools//lint:buildifier.bzl", "check_pkg")
load("@com_github_airyhq_bazel_tools//web:typescript.bzl", "ts_web_library")

package(default_visibility = ["//visibility:public"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the intention of this module, but I think the name is too generic and not quite accurate (It hosts a component and not a service). Only thing I can think of for now would be frontend/components

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frontend/lib/avatar would be my suggestion (given the previous point I made about it)

import {Channel, SourceType} from 'httpclient';
import {SourceTypeInfo} from '../MainPage';
import {Channel, Source} from 'httpclient';
import {SourceInfo} from '../MainPage';
import {fallbackImage} from '../../../services/image/index';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here updated naming to follow api naming Source

Copy link
Contributor

@bitboxer bitboxer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff 🥳 . Some minor comments. After the rebase is done I will 🟢 this.

@@ -14,7 +14,7 @@ const AvatarImage = (props: AvatarProps) => {

return (
<div className={styles.avatar}>
<img className={styles.avatarImage} src={contact.avatarUrl || fallbackAvatar} />
<img className={styles.avatarImage} src={(contact && contact.avatarUrl) || fallbackAvatar} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the new optional chaining operator instead:

Suggested change
<img className={styles.avatarImage} src={(contact && contact.avatarUrl) || fallbackAvatar} />
<img className={styles.avatarImage} src={(contact?.avatarUrl) || fallbackAvatar} />

@@ -184,7 +184,7 @@ const ConversationMetadata = (props: ConnectedProps<typeof connector>) => {
<AvatarImage contact={contact} />
</div>

<div className={styles.displayName}>{contact.displayName}</div>
<div className={styles.displayName}>{contact && contact.displayName}</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like above:

Suggested change
<div className={styles.displayName}>{contact && contact.displayName}</div>
<div className={styles.displayName}>{contact?.displayName}</div>

@@ -0,0 +1 @@
1.5:b2a9215c-db31-4f1b-b3db-1e3a1e879bbe
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the .vagrant folder is gone now because minikube ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! don't know how this snugged into my PR!

Copy link
Contributor

@lucapette lucapette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great!

I think we should merge, I'm requesting changes so we don't forget to remove all the vagrant files before we merge :)

bitboxer
bitboxer previously approved these changes Mar 23, 2021
Copy link
Contributor

@bitboxer bitboxer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@AudreyKj AudreyKj merged commit c389630 into develop Mar 24, 2021
@AudreyKj AudreyKj deleted the fix/1239-message-wrapper-for-render-library branch March 24, 2021 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Message Wrapper for render library
4 participants