Add self chat feature#474
Conversation
Codecov Report
@@ Coverage Diff @@
## master #474 +/- ##
==========================================
+ Coverage 63.05% 64.66% +1.60%
==========================================
Files 110 110
Lines 2550 2595 +45
Branches 420 429 +9
==========================================
+ Hits 1608 1678 +70
+ Misses 810 790 -20
+ Partials 132 127 -5
Continue to review full report at Codecov.
|
JongtaekChoi
left a comment
There was a problem hiding this comment.
It seems really good!
| if (channelType !== ChannelType.self) | ||
| await createMemberships(channel.id, filteredPeerUserIds); |
There was a problem hiding this comment.
We don't need to resolve this in this PR, but I think we need some refactoring in this file. Functions are getting quite big.
| export const getChannelType = ( | ||
| userId: string, | ||
| peerUserIds: string[], | ||
| ): ChannelType => { | ||
| if (peerUserIds.length === 1 && peerUserIds[0] === userId) | ||
| return ChannelType.self; | ||
|
|
||
| return ChannelType.private; | ||
| }; |
There was a problem hiding this comment.
I like how this logic is extracted into a separate function; however, I think the name can be more clear. How about we name this isSelfChannel(userId, memberIds): boolean?
There was a problem hiding this comment.
I intended this function to return ChannelType not boolean because there might be new feature added to server 'public' type channel. But now I know that in that case, we should create totally new different mutation function which is not findOrCreatePrivateChannel..
So I'll make change as you suggested, thanks always
There was a problem hiding this comment.
I had changed codes as you suggested but it brings 3 test case failures in server side Channel.test.ts. I think it is because old createNewChannel function was used even when creating public channel..
So I had to revert that commit.
I think we should refactor all related codes when we introduce public channel feature.
There was a problem hiding this comment.
I see. Thanks for trying 👍
|
Changed all |
|
@rarira Just making sure you did not miss it. There are 19 hidden comments in my first review. Github automatically folds when there are too many comments in one review 😅 |
I'll try once again later. Thanks. |
Co-authored-by: Donghyeon Kim <0916dhkim@gmail.com>
This reverts commit 3a7f471.
It should be changed update store properly
Co-authored-by: Donghyeon Kim <0916dhkim@gmail.com>
Co-authored-by: Donghyeon Kim <0916dhkim@gmail.com>
7055403 to
c94fcf2
Compare
@0916dhkim |
| }; | ||
|
|
||
| const ProfileModalContext = createContext<ProfileModalContext>({ | ||
| export const ProfileModalContext = createContext<ProfileModalContext>({ |
There was a problem hiding this comment.
So I think mocking useAuthContext here in test code is unnecessary.
@rarira Thank you for addressing AuthProvider related comments 👍
The point was avoid exporting AuthContextProvider. Can you take similar approach for ProfileModalContext and remove export here?
| const screen = render(component); | ||
| const btn = await screen.findByTestId('list-item-0'); | ||
| const screen = render(component); | ||
| const channelItemBtn = await screen.findByTestId('list-item-0'); |
There was a problem hiding this comment.
I think adding accessibility label on any icon-only button is a good idea. It helps people who use screen reader.
| class FilteredMemberships { | ||
| constructor( | ||
| private memberships: Maybe<Membership[]> | undefined, | ||
| private user: AuthProviderMeQueryResponse['me'] | null, | ||
| private channelType: string, | ||
| ) { | ||
| this.memberships = memberships; | ||
| this.channelType = channelType; | ||
| this.user = user; | ||
| } | ||
|
|
||
| private get filtered(): (Maybe<Membership> | undefined)[] | undefined { | ||
| return this.memberships?.filter((member) => { | ||
| if (this.channelType !== 'self') | ||
| return member?.user?.id !== this.user?.id; | ||
|
|
||
| return true; | ||
| }); | ||
| } | ||
|
|
||
| get users(): (Maybe<User> | undefined)[] | undefined { | ||
| return this.filtered?.map((membership) => membership?.user); | ||
| } | ||
|
|
||
| get userNames(): string[] | undefined { | ||
| return this.users?.map((v) => v?.nickname || v?.name || ''); | ||
| } | ||
| calculatedPhotoUrls(): (Maybe<string> | undefined)[] | undefined { | ||
| return this.filtered?.map( | ||
| (membership) => membership?.user?.thumbURL || membership?.user?.photoURL, | ||
| ); | ||
| } | ||
|
|
||
| calculateOnlineStatus(): Maybe<Boolean> | undefined { | ||
| return this.filtered?.[0]?.user?.isOnline; | ||
| } | ||
|
|
||
| calculateDisplayName(): Maybe<string> | undefined { | ||
| return this.users?.length === 1 | ||
| ? this.users?.[0]?.nickname || | ||
| this.users?.[0]?.name || | ||
| getString('NO_NAME') | ||
| : this.userNames?.join(', '); | ||
| } | ||
| } |
There was a problem hiding this comment.
I think functions are simpler than a class. Something like this:
const calculateUsers = (memberships: Membership[], channelType: string, authUserId): (Maybe<User>)[] =>
memberships.filter((member) => channelType !== 'self' && member?.user?.id !== authUserId);
const calculatePhotoUrls = (memberships: Membership[]): (Maybe<string>)[] =>
memberships.map((member) => member?.user?.thumbURL || member?.user?.photoURL);
const calculateOnlineStatus = (users: (Maybe<User>)[]): boolean =>
users[0]?.isOnline ?? false;There was a problem hiding this comment.
Indeed, calculatePhotoUrls also needs 'filtered by channel type' memberships passed as an argument, So there needs to be filteredMemberships calculated first and the calculated filteredMemberships is only used for this functions/class method.
if someone pass normal memberships array to calculatePhotoUrls function which is okay in tsc check but we can have unwanted results So I think the reusability of that function is very low.
| }); | ||
|
|
||
| it('renders [StyledMeCircleView] when channelType is "self"', () => { | ||
| TEST_CHANNEL.channelType = 'self'; |
There was a problem hiding this comment.
I think you forgot to copy this TEST_CHANNEL
| if (includeMe) { | ||
| const myProfile = await prisma.user.findUnique({ | ||
| where: { | ||
| id: userId, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
but it had some problem with sorting, I mean, I wanted to display 'ME' always at the top
@rarira It makes sense. Let's leave it like this for now.
|
I don't know why I can't reply this review comment.. I'm afraid I can't take similar approach to
|
0916dhkim
left a comment
There was a problem hiding this comment.
@rarira Thank you for quick followup!
But I don't know which one is better to add export or new prop only for testing.
I suggest adding new prop for testing. Both approaches break encapsulation for testing as you mentioned, but it is less likely to make mistake with the prop than with exports. If you are concerned, we can name the prop something like testModalState (as opposed to initialModalState) so other developers do not get confused about the purpose of that prop.
| const calculatePhotoUrls = ( | ||
| memberships: (Maybe<Membership> | undefined)[] | undefined, | ||
| ): (Maybe<string> | undefined)[] | undefined => | ||
| memberships?.map( | ||
| (membership) => membership?.user?.thumbURL || membership?.user?.photoURL, | ||
| ); | ||
|
|
||
| const calculateOnlineStatus = ( | ||
| memberships: (Maybe<Membership> | undefined)[] | undefined, | ||
| ): Maybe<Boolean> | undefined => memberships?.[0]?.user?.isOnline; |
There was a problem hiding this comment.
calculatePhotoUrls & calculateOnlineStatus can take users parameter like calculateDisplayNames function does. You can then combine calculateFilteredMemberships & calculateUsers functions into one.
There was a problem hiding this comment.
I finally find jest.spyOn example Message.test.tsx and update MainFriend.test.tsx
and update those calculate functions as suggested.. now it looks simple :)
| {modalState.isMyself ? ( | ||
| <TouchableOpacity | ||
| testID="profile-update-button" | ||
| style={{padding: 8}} |
* Fix rendering issue in [UserListItem] * Hotfix - statusMessage rendering throw error on empty string * Remove the borderColor in profile `viewBtn`

Specify project
Both Server and Client
Description
UserListItemof mySelf in the top of theFriendTab, just like KakaoTalk does.ProfileModalof myself ifUserListItemmentioned above is pressed.ProfileModalof myself only rendersProfileUpdatebutton andChat with myselfbutton:Chat with myselfbutton finds already opened self chatroom and navigate to that self chat room.If failed, it creates
ChannelType.selfchatroom and navigate to newly created room.FAB Buttonin theChannelCreategetString('Me')) in front of users name to distinguish a self chat room from othersAdditional Comments:
Add result message when updating profile #470
Add result message when updating profile #470
Related Issues
Create empty channel (Self Chat?) #459
['yourID', 'otherId'] => ['otherId']Self chat feature #311
Tests
I added the following tests:
Add almost 100% of test codes for the lines newly added
Checklist
Before you create this PR confirms that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.yarn lint && yarn tscyarn testoryarn test -uif you need to update snapshot.[wehack2021] - [cloud]