Skip to content

Commit

Permalink
refactor: GroupChannelList migration (#1231)
Browse files Browse the repository at this point in the history
### Changelogs
This is a part of state management migration. This PR migrate
'GroupChannelListProvider' and related files to the new style.
* Created `useGroupChannelList()` hook. It'll replace the previous
`useGroupChannelContext()` hook.
  • Loading branch information
git-babel authored and AhyoungRyu committed Oct 29, 2024
1 parent f05158f commit 7313618
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import React, { useState } from 'react';
import AddGroupChannelView from './AddGroupChannelView';
import { useGroupChannelListContext } from '../../context/GroupChannelListProvider';
import { useGroupChannelList } from '../../context/useGroupChannelList';

export const AddGroupChannel = () => {
const [createChannelVisible, setCreateChannelVisible] = useState(false);
const { onChannelCreated, onBeforeCreateChannel, onCreateChannelClick } = useGroupChannelListContext();
const {
state: {
onChannelCreated,
onBeforeCreateChannel,
onCreateChannelClick,
},
} = useGroupChannelList();

return (
<AddGroupChannelView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { SendableMessageType } from '../../../../utils';
import * as utils from './utils';
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
import { useLocalization } from '../../../../lib/LocalizationContext';
import { useGroupChannelListContext } from '../../context/GroupChannelListProvider';
import { GroupChannelListItemBasicProps, GroupChannelListItemView } from './GroupChannelListItemView';
import { useGroupChannelList } from '../../context/useGroupChannelList';

export interface GroupChannelListItemProps extends GroupChannelListItemBasicProps {}

Expand All @@ -21,7 +21,12 @@ export const GroupChannelListItem = ({
}: GroupChannelListItemProps) => {
const { config } = useSendbirdStateContext();
const { stringSet } = useLocalization();
const { isTypingIndicatorEnabled = false, isMessageReceiptStatusEnabled = false } = useGroupChannelListContext();
const {
state: {
isTypingIndicatorEnabled = false,
isMessageReceiptStatusEnabled = false,
},
} = useGroupChannelList();

const userId = config.userId;
const isMessageStatusEnabled = isMessageReceiptStatusEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import './index.scss';

import React from 'react';
import type { GroupChannel } from '@sendbird/chat/groupChannel';
import { useGroupChannelListContext } from '../../context/GroupChannelListProvider';
import { GroupChannelListUIView } from './GroupChannelListUIView';
import GroupChannelPreviewAction from '../GroupChannelPreviewAction';
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
import { GroupChannelListItem } from '../GroupChannelListItem';
import AddGroupChannel from '../AddGroupChannel';
import { GroupChannelListItemBasicProps } from '../GroupChannelListItem/GroupChannelListItemView';
import { noop } from '../../../../utils/utils';
import { useGroupChannelList } from '../../context/useGroupChannelList';

interface GroupChannelItemProps extends GroupChannelListItemBasicProps {}

Expand All @@ -25,16 +25,18 @@ export const GroupChannelListUI = (props: GroupChannelListUIProps) => {
const { renderHeader, renderChannelPreview, renderPlaceHolderError, renderPlaceHolderLoading, renderPlaceHolderEmptyList } = props;

const {
onChannelSelect,
onThemeChange,
allowProfileEdit,
typingChannelUrls,
groupChannels,
initialized,
selectedChannelUrl,
loadMore,
onUserProfileUpdated,
} = useGroupChannelListContext();
state: {
onChannelSelect,
onThemeChange,
allowProfileEdit,
typingChannelUrls,
groupChannels,
initialized,
selectedChannelUrl,
loadMore,
onUserProfileUpdated,
},
} = useGroupChannelList();

const { stores, config } = useSendbirdStateContext();
const { logger, isOnline } = config;
Expand Down
130 changes: 101 additions & 29 deletions src/modules/GroupChannelList/context/GroupChannelListProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from 'react';
import React, { useContext, useEffect, useRef, useState } from 'react';

import type { User } from '@sendbird/chat';
import type { GroupChannel, GroupChannelCreateParams, GroupChannelFilterParams } from '@sendbird/chat/groupChannel';
Expand All @@ -14,6 +14,8 @@ import useOnlineStatus from '../../../lib/hooks/useOnlineStatus';
import { noop } from '../../../utils/utils';
import type { SdkStore } from '../../../lib/types';
import { PartialRequired } from '../../../utils/typeHelpers/partialRequired';
import { createStore } from '../../../utils/storeManager';
import { useStore } from '../../../hooks/useStore';

type OnCreateChannelClickParams = { users: Array<string>; onClose: () => void; channelType: CHANNEL_TYPE };
type ChannelListDataSource = ReturnType<typeof useGroupChannelList>;
Expand Down Expand Up @@ -52,10 +54,41 @@ export interface GroupChannelListProviderProps extends
children?: React.ReactNode;
}

export const GroupChannelListContext = React.createContext<GroupChannelListContextType | null>(null);
export const GroupChannelListProvider = (props: GroupChannelListProviderProps) => {
export const GroupChannelListContext = React.createContext<ReturnType<typeof createStore<GroupChannelListState>> | null>(null);

export interface GroupChannelListState extends GroupChannelListContextType {
}

const initialState: GroupChannelListState = {
className: '',
selectedChannelUrl: '',
disableAutoSelect: false,
allowProfileEdit: false,
isTypingIndicatorEnabled: false,
isMessageReceiptStatusEnabled: false,
onChannelSelect: noop,
onChannelCreated: noop,
onThemeChange: noop,
onCreateChannelClick: noop,
onBeforeCreateChannel: null,
onUserProfileUpdated: noop,
typingChannelUrls: [],
refreshing: false,
initialized: false,
groupChannels: [],
refresh: null,
loadMore: null,
};

/**
* @returns {ReturnType<typeof createStore<GroupChannelListState>>}
*/
const useGroupChannelListStore = () => {
return useStore(GroupChannelListContext, state => state, initialState);
};

export const GroupChannelListManager: React.FC<GroupChannelListProviderProps> = (props: GroupChannelListProviderProps) => {
const {
children,
className = '',
selectedChannelUrl,

Expand All @@ -72,8 +105,9 @@ export const GroupChannelListProvider = (props: GroupChannelListProviderProps) =
onBeforeCreateChannel,
onUserProfileUpdated,
} = props;
const globalStore = useSendbirdStateContext();
const { config, stores } = globalStore;

const { config, stores } = useSendbirdStateContext();
const { updateState } = useGroupChannelListStore();
const { sdkStore } = stores;

const sdk = sdkStore.sdk;
Expand Down Expand Up @@ -120,33 +154,71 @@ export const GroupChannelListProvider = (props: GroupChannelListProviderProps) =
},
});

useEffect(() => {
updateState({
className,
selectedChannelUrl,
disableAutoSelect,
allowProfileEdit,
isTypingIndicatorEnabled,
isMessageReceiptStatusEnabled,
onChannelSelect,
onChannelCreated,
onThemeChange,
onCreateChannelClick,
onBeforeCreateChannel,
onUserProfileUpdated,
typingChannelUrls,
refreshing,
initialized,
groupChannels,
refresh,
loadMore,
});
}, [
className,
selectedChannelUrl,
disableAutoSelect,
allowProfileEdit,
isTypingIndicatorEnabled,
isMessageReceiptStatusEnabled,
onChannelSelect,
onChannelCreated,
onThemeChange,
onCreateChannelClick,
onBeforeCreateChannel,
onUserProfileUpdated,
typingChannelUrls,
refreshing,
initialized,
groupChannels,
refresh,
loadMore,
]);

return null;
};

const createGroupChannelListStore = () => createStore(initialState);
const InternalGroupChannelListStoreProvider = ({ children }) => {
const storeRef = useRef(createGroupChannelListStore());
return (
<GroupChannelListContext.Provider
value={{
className,
selectedChannelUrl,
disableAutoSelect,
allowProfileEdit: allowProfileEdit ?? config.allowProfileEdit ?? true,
isTypingIndicatorEnabled: isTypingIndicatorEnabled ?? config.groupChannelList.enableTypingIndicator ?? false,
isMessageReceiptStatusEnabled: isMessageReceiptStatusEnabled ?? config.groupChannelList.enableMessageReceiptStatus ?? false,
onChannelSelect,
onChannelCreated,
onThemeChange,
onCreateChannelClick,
onBeforeCreateChannel,
onUserProfileUpdated,
typingChannelUrls,
refreshing,
initialized,
groupChannels,
refresh,
loadMore,
}}
>
<GroupChannelListContext.Provider value={storeRef.current}>
{children}
</GroupChannelListContext.Provider>
);
};

export const GroupChannelListProvider = (props: GroupChannelListProviderProps) => {
const { children, className } = props;

return (
<InternalGroupChannelListStoreProvider>
<GroupChannelListManager {...props} />
<UserProfileProvider {...props}>
<div className={`sendbird-channel-list ${className}`}>{children}</div>
</UserProfileProvider>
</GroupChannelListContext.Provider>
</InternalGroupChannelListStoreProvider>
);
};

Expand Down
14 changes: 14 additions & 0 deletions src/modules/GroupChannelList/context/useGroupChannelList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { GroupChannelListState, useGroupChannelListContext } from './GroupChannelListProvider';
import { useSyncExternalStore } from 'use-sync-external-store/shim';
import { useMemo } from 'react';

export const useGroupChannelList = () => {
const store = useGroupChannelListContext();
if (!store) throw new Error('useChannelSettings must be used within a ChannelSettingsProvider');

const state: GroupChannelListState = useSyncExternalStore(store.subscribe, store.getState);
const actions = useMemo(() => ({
}), [store]);

return { state, actions };
};

0 comments on commit 7313618

Please sign in to comment.