Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @baseapp-frontend/components

## 1.1.0

### Minor Changes

- Restructure several components from the `messages` module to make it more customizable.

## 1.0.36

### Patch Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const NewContentPost: FC<NewContentPostProps> = () => {

commitMutation({
variables: {
// @ts-ignore this will be handle on BA-2452
input: {
content: data.content,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
} from 'react'

import { LoadingState } from '@baseapp-frontend/design-system/components/web/displays'
import { Iconify } from '@baseapp-frontend/design-system/components/web/images'
import { Searchbar as DefaultSearchbar } from '@baseapp-frontend/design-system/components/web/inputs'

import { Box, CircularProgress, Tab, Tabs, Typography } from '@mui/material'
import { Box, Button, CircularProgress, Tab, Tabs, Typography } from '@mui/material'
import { useForm } from 'react-hook-form'
import { Virtuoso } from 'react-virtuoso'

Expand All @@ -23,11 +24,12 @@ import { useChatRoom, useRoomListSubscription, useRoomsList } from '../../common
import DefaultChatRoomItem from './ChatRoomItem'
import DefaultEmptyChatRoomsState from './EmptyChatRoomsState'
import { CHAT_TAB_LABEL, CHAT_TAB_VALUES } from './constants'
import { ChatRoomListContainer } from './styled'
import { ChatRoomNode, ChatRoomsListProps, ChatTabValues } from './types'
import { Header, MainContainer } from './styled'
import { AllChatRoomsListProps, ChatRoomNode, ChatTabValues } from './types'

const ChatRoomsList: FC<ChatRoomsListProps> = ({
const AllChatRoomsList: FC<AllChatRoomsListProps> = ({
targetRef,
onHeaderClick = () => {},
Searchbar = DefaultSearchbar,
SearchbarProps = {},
ChatRoomItem = DefaultChatRoomItem,
Expand Down Expand Up @@ -160,67 +162,84 @@ const ChatRoomsList: FC<ChatRoomsListProps> = ({
}

return (
<ChatRoomListContainer>
<Box
sx={{
paddingX: {
xs: 1.5,
sm: 2.5,
},
paddingTop: 2,
}}
>
<Searchbar
key={
tab /* The handleSearchChange function depends on tab.
<>
<Header>
<Box display="grid" width="100%" gridTemplateColumns="auto min-content" gap={1}>
<Typography variant="h4" component="span">
Messages
</Typography>
<Button
variant="contained"
color="inherit"
startIcon={<Iconify icon="mingcute:add-line" />}
onClick={onHeaderClick}
>
New
</Button>
</Box>
</Header>
<MainContainer>
<Box
sx={{
paddingX: {
xs: 1.5,
sm: 2.5,
},
paddingTop: 2,
}}
>
<Searchbar
key={
tab /* The handleSearchChange function depends on tab.
Searchbar calls useRef on the onChange function (to debounce),
hence it does not see the changes unless it is reloaded */
}
name="search"
control={control}
onChange={handleSearchChange}
onClear={handleSearchClear}
isPending={isPending}
{...SearchbarProps}
/>
</Box>
<Tabs
value={tab}
onChange={handleChange}
centered
variant="fullWidth"
sx={{
paddingX: {
xs: 0,
sm: 2.5,
},
paddingTop: 2,
}}
>
<Tab label={renderTabLabel(CHAT_TAB_VALUES.active)} value={CHAT_TAB_VALUES.active} />
<Tab label={renderTabLabel(CHAT_TAB_VALUES.unread)} value={CHAT_TAB_VALUES.unread} />
<Tab label={renderTabLabel(CHAT_TAB_VALUES.archived)} value={CHAT_TAB_VALUES.archived} />
</Tabs>
{renderListContent()}
{renderList && (
<Virtuoso
data={chatRooms}
overscan={1}
itemContent={(_index, item) => renderItem(item)}
style={{ scrollbarWidth: 'none' }}
components={{
Footer: renderLoadingState,
}}
endReached={() => {
if (hasNext) {
loadNext(5)
}
name="search"
control={control}
onChange={handleSearchChange}
onClear={handleSearchClear}
isPending={isPending}
{...SearchbarProps}
/>
</Box>
<Tabs
value={tab}
onChange={handleChange}
centered
variant="fullWidth"
sx={{
paddingX: {
xs: 0,
sm: 2.5,
},
paddingTop: 2,
}}
{...VirtuosoProps}
/>
)}
</ChatRoomListContainer>
>
<Tab label={renderTabLabel(CHAT_TAB_VALUES.active)} value={CHAT_TAB_VALUES.active} />
<Tab label={renderTabLabel(CHAT_TAB_VALUES.unread)} value={CHAT_TAB_VALUES.unread} />
<Tab label={renderTabLabel(CHAT_TAB_VALUES.archived)} value={CHAT_TAB_VALUES.archived} />
</Tabs>
{renderListContent()}
{renderList && (
<Virtuoso
data={chatRooms}
overscan={1}
itemContent={(_index, item) => renderItem(item)}
style={{ scrollbarWidth: 'none' }}
components={{
Footer: renderLoadingState,
}}
endReached={() => {
if (hasNext) {
loadNext(5)
}
}}
{...VirtuosoProps}
/>
)}
</MainContainer>
</>
)
}

export default ChatRoomsList
export default AllChatRoomsList
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ComponentType } from 'react'

import { Box, BoxProps } from '@mui/material'
import { styled } from '@mui/material/styles'

export const MainContainer = styled(Box)(() => ({
display: 'grid',
gridTemplateRows: 'min-content min-content auto',
height: '100%',
width: '100%',
}))

export const Header: ComponentType<BoxProps> = styled(Box)(({ theme }) => ({
width: '100%',
padding: `${theme.spacing(2.5)} ${theme.spacing(2.5)} ${theme.spacing(2)}`,
[theme.breakpoints.down('sm')]: {
padding: `${theme.spacing(2)} ${theme.spacing(1.5)} ${theme.spacing(2)}`,
},
}))
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ type ChatRooms = NonNullable<RoomsListFragment$data['chatRooms']>
type ChatRoomsEdges = ChatRooms['edges']
export type ChatRoomNode = NonNullable<ChatRoomsEdges[number]>['node']

export interface ChatRoomsListProps {
export interface AllChatRoomsListProps {
targetRef: ChatRoomsQuery$data
onHeaderClick: () => void
Searchbar?: FC<SearchbarProps>
SearchbarProps?: Partial<SearchbarProps>
ChatRoomItem?: FC<ChatRoomItemProps>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const LEFT_PANEL_CONTENT = {
chatRoomList: 0,
createChat: 1,
createGroupChat: 2,
editGroupChat: 3,
groupDetails: 4,
} as const
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
'use client'

import { FC, useState } from 'react'

import { useResponsive } from '@baseapp-frontend/design-system/hooks/web'

import { useQueryLoader } from 'react-relay'

import { GroupDetailsQuery as GroupDetailsQueryType } from '../../../../__generated__/GroupDetailsQuery.graphql'
import { GroupDetailsQuery, useChatRoom } from '../../common'
import DefaultAllChatRoomsList from '../AllChatRoomsList'
import ChatRoom from '../ChatRoom'
import DefaultGroupChatCreate from '../GroupChatCreate'
import DefaultGroupChatDetails from '../GroupChatDetails'
import DefaultGroupChatEdit from '../GroupChatEdit'
import DefaultSingleChatCreate from '../SingleChatCreate'
import { LEFT_PANEL_CONTENT } from './constants'
import { ChatRoomContainer, ChatRoomsContainer, ChatRoomsListContainer } from './styled'
import { ChatRoomsComponentProps, LeftPanelContentValues } from './types'

const ChatRoomsComponent: FC<ChatRoomsComponentProps> = ({
chatRoomsQueryData,
settings,
AllChatRoomsListComponent = DefaultAllChatRoomsList,
AllChatRoomsListComponentProps = {},
GroupChatCreateComponent = DefaultGroupChatCreate,
GroupChatCreateComponentProps = {},
GroupChatDetailsComponent = DefaultGroupChatDetails,
GroupChatDetailsComponentProps = {},
GroupChatEditComponent = DefaultGroupChatEdit,
GroupChatEditComponentProps = {},
SingleChatCreateComponent = DefaultSingleChatCreate,
SingleChatCreateComponentProps = {},
}) => {
const isUpToMd = useResponsive('up', 'md')
const [leftPanelContent, setLeftPanelContent] = useState<LeftPanelContentValues>(
LEFT_PANEL_CONTENT.chatRoomList,
)

const [groupDetailsQueryRef, loadGroupDetailsQuery] =
useQueryLoader<GroupDetailsQueryType>(GroupDetailsQuery)
const { id: selectedRoom } = useChatRoom()

const displayGroupDetails = () => {
if (selectedRoom) {
setLeftPanelContent(LEFT_PANEL_CONTENT.groupDetails)
loadGroupDetailsQuery({ roomId: selectedRoom }, { fetchPolicy: 'network-only' })
}
}

const shouldRenderLeftPanel =
isUpToMd || leftPanelContent !== LEFT_PANEL_CONTENT.chatRoomList || !selectedRoom
const shouldRenderRightPanel =
isUpToMd || (leftPanelContent === LEFT_PANEL_CONTENT.chatRoomList && !!selectedRoom)

const renderLeftPanelContent = () => {
switch (leftPanelContent) {
case LEFT_PANEL_CONTENT.createGroupChat:
return (
<GroupChatCreateComponent
allProfilesRef={chatRoomsQueryData}
onValidSubmission={() => setLeftPanelContent(LEFT_PANEL_CONTENT.chatRoomList)}
onBackButtonClicked={() => setLeftPanelContent(LEFT_PANEL_CONTENT.createChat)}
{...GroupChatCreateComponentProps}
/>
)
case LEFT_PANEL_CONTENT.editGroupChat:
if (!groupDetailsQueryRef) return null
return (
<GroupChatEditComponent
onCancellation={() => setLeftPanelContent(LEFT_PANEL_CONTENT.groupDetails)}
onRemovalFromGroup={() => setLeftPanelContent(LEFT_PANEL_CONTENT.chatRoomList)}
onValidSubmission={() => setLeftPanelContent(LEFT_PANEL_CONTENT.groupDetails)}
queryRef={groupDetailsQueryRef}
roomId={selectedRoom}
allProfilesRef={chatRoomsQueryData}
{...GroupChatEditComponentProps}
/>
)
case LEFT_PANEL_CONTENT.groupDetails:
if (!groupDetailsQueryRef) return null
return (
<GroupChatDetailsComponent
queryRef={groupDetailsQueryRef}
onBackButtonClicked={() => setLeftPanelContent(LEFT_PANEL_CONTENT.chatRoomList)}
onEditButtonClicked={() => setLeftPanelContent(LEFT_PANEL_CONTENT.editGroupChat)}
{...GroupChatDetailsComponentProps}
/>
)
case LEFT_PANEL_CONTENT.createChat:
return (
<SingleChatCreateComponent
allProfilesRef={chatRoomsQueryData}
onHeaderClick={() => setLeftPanelContent(LEFT_PANEL_CONTENT.chatRoomList)}
onChatCreation={() => setLeftPanelContent(LEFT_PANEL_CONTENT.chatRoomList)}
onGroupChatCreationButtonClicked={() =>
setLeftPanelContent(LEFT_PANEL_CONTENT.createGroupChat)
}
{...SingleChatCreateComponentProps}
/>
)
default:
return (
<AllChatRoomsListComponent
targetRef={chatRoomsQueryData}
onHeaderClick={() => setLeftPanelContent(LEFT_PANEL_CONTENT.createChat)}
{...AllChatRoomsListComponentProps}
/>
)
}
}

const renderRightPanelContent = () => {
if (!selectedRoom) return <div />

return <ChatRoom roomId={selectedRoom} onDisplayGroupDetailsClicked={displayGroupDetails} />
}

return (
<ChatRoomsContainer themeLayout={settings.themeLayout}>
{shouldRenderLeftPanel && (
<ChatRoomsListContainer hide={!shouldRenderLeftPanel /* TODO: Why? */}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think those "Why" comments (here and 5 lines below) are from me, don't know how they made it to master, I thought I had deleted them. Maybe you can remove them before merging? (I still don't understand why this prop is necessary, maybe someone can explain that to me.)

{renderLeftPanelContent()}
</ChatRoomsListContainer>
)}
{shouldRenderRightPanel && (
<ChatRoomContainer hide={!shouldRenderRightPanel /* TODO: Why? */}>
{renderRightPanelContent()}
</ChatRoomContainer>
)}
</ChatRoomsContainer>
)
Comment on lines +118 to +132
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove redundant hide props and TODO comments

The hide props on ChatRoomsListContainer and ChatRoomContainer are redundant and potentially confusing. They're set to the negation of the conditions already used for conditional rendering, which doesn't make sense. Additionally, remove the "TODO: Why?" comments as requested in a previous review.

 return (
   <ChatRoomsContainer themeLayout={settings.themeLayout}>
     {shouldRenderLeftPanel && (
-      <ChatRoomsListContainer hide={!shouldRenderLeftPanel /* TODO: Why? */}>
+      <ChatRoomsListContainer>
         {renderLeftPanelContent()}
       </ChatRoomsListContainer>
     )}
     {shouldRenderRightPanel && (
-      <ChatRoomContainer hide={!shouldRenderRightPanel /* TODO: Why? */}>
+      <ChatRoomContainer>
         {renderRightPanelContent()}
       </ChatRoomContainer>
     )}
   </ChatRoomsContainer>
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<ChatRoomsContainer themeLayout={settings.themeLayout}>
{shouldRenderLeftPanel && (
<ChatRoomsListContainer hide={!shouldRenderLeftPanel /* TODO: Why? */}>
{renderLeftPanelContent()}
</ChatRoomsListContainer>
)}
{shouldRenderRightPanel && (
<ChatRoomContainer hide={!shouldRenderRightPanel /* TODO: Why? */}>
{renderRightPanelContent()}
</ChatRoomContainer>
)}
</ChatRoomsContainer>
)
return (
<ChatRoomsContainer themeLayout={settings.themeLayout}>
{shouldRenderLeftPanel && (
<ChatRoomsListContainer>
{renderLeftPanelContent()}
</ChatRoomsListContainer>
)}
{shouldRenderRightPanel && (
<ChatRoomContainer>
{renderRightPanelContent()}
</ChatRoomContainer>
)}
</ChatRoomsContainer>
)

}

export default ChatRoomsComponent
Loading
Loading