import { createContext, useMemo } from 'react'; import { useParams } from 'react-router-dom'; import PropTypes from 'prop-types'; import useSWR from 'swr'; import { CHANNEL_DATA_REFRESH_INTERVAL } from '../constants'; import { channelsAPI } from '../api'; import { getAvatarSrc } from '../helpers'; import { useUser } from './User'; import useContextHook from './useContextHook'; import useCurrentPage from '../hooks/useCurrentPage'; const Context = createContext(null); Context.displayName = 'Channel'; const channelDataFetcher = async (username) => { const { result: data, error } = await channelsAPI.getUserChannelData( username ); if (error) throw error; return data; }; export const Provider = ({ children }) => { const { isSessionValid, userData } = useUser(); const { username: channelUsername } = useParams(); const currentPage = useCurrentPage(); /** * We use userData.username in the SWR key to ensure that each channel data request * is associated with a unique user. Doing so ensures that the channel data is reset * whenever the user logs out or a new user logs in. This is essential as we need to * make sure that the value of isViewerBanned is always accurate for the user who is * signed in, and this can only be guaranteed if the SWR key is updated appropriately. * The SWR key is filtered to remove duplicate usernames so that duplicate data isn't * fetched by SWR. */ let swrKey = null; if ((isSessionValid && userData) || isSessionValid === false) { if (currentPage === 'channel' && channelUsername) { const keyArr = [channelUsername, userData?.username]; swrKey = keyArr.filter((item, i) => keyArr.indexOf(item) === i); } else if (currentPage !== 'channel' && userData) { swrKey = [userData?.username]; } } const { data: channelData, error: channelError, mutate: refreshChannelData } = useSWR(swrKey, channelDataFetcher, { refreshInterval: CHANNEL_DATA_REFRESH_INTERVAL }); const isChannelLoading = !channelData && !channelError; const avatarSrc = getAvatarSrc(channelData); const augmentedChannelData = useMemo( () => ({ ...channelData, avatarSrc }), [avatarSrc, channelData] ); const value = useMemo( () => ({ channelData: !!channelData ? augmentedChannelData : undefined, channelError, isChannelLoading, refreshChannelData }), [ augmentedChannelData, channelData, channelError, isChannelLoading, refreshChannelData ] ); return {children}; }; Provider.propTypes = { children: PropTypes.node.isRequired }; export const useChannel = () => useContextHook(Context);