import React, { ReactNode, PropsWithChildren, useContext, useEffect, useState } from 'react'; import StreamAnalytics from 'stream-analytics'; import { connect, UR, StreamClient, StreamUser, ClientOptions, OGAPIResponse, GetFeedOptions } from 'getstream'; import { FeedManager } from './FeedManager'; import { ErrorHandler, handleError } from '../utils/errors'; import { Streami18n } from '../i18n/Streami18n'; import { TranslationContextValue, TranslationProvider } from './TranslationContext'; export type SharedFeedManagers< UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT, CT extends UR = UR, RT extends UR = UR, CRT extends UR = UR, PT extends UR = UR > = Record>; type Attachments = { files?: Array<{ mimeType: string; name: string; url: string }>; images?: string[]; og?: OGAPIResponse; }; export type DefaultUT = UR & { name: string; id?: string; profileImage?: string }; export type DefaultAT = UR & { attachments?: Attachments; text?: string }; export type SharedFeed = { feedGroup: string; notify: boolean; options: GetFeedOptions }; export type StreamAppProps = { apiKey: string; appId: string; token: string; analyticsToken?: string; children?: ReactNode; defaultUserData?: UT; errorHandler?: ErrorHandler; i18nInstance?: Streami18n; options?: ClientOptions; sharedFeeds?: Array; }; export type StreamContextValue< UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT, CT extends UR = UR, RT extends UR = UR, CRT extends UR = UR, PT extends UR = UR > = { analyticsClient: null | StreamAnalytics; client: null | StreamClient; errorHandler: ErrorHandler; sharedFeedManagers: SharedFeedManagers; user?: StreamUser; userData?: UT; }; export const StreamContext = React.createContext({ analyticsClient: null, client: null, errorHandler: handleError, sharedFeedManagers: {}, }); export const StreamAppProvider = < UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT, CT extends UR = UR, RT extends UR = UR, CRT extends UR = UR, PT extends UR = UR >({ children, value, }: PropsWithChildren<{ value: StreamContextValue; }>) => {children}; export const useStreamContext = < UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT, CT extends UR = UR, RT extends UR = UR, CRT extends UR = UR, PT extends UR = UR >() => useContext(StreamContext) as StreamContextValue; /** * Manages the connection with Stream. Any components that should talk to * Stream should be a child of this component. */ export function StreamApp< UT extends DefaultUT = DefaultUT, AT extends DefaultAT = DefaultAT, CT extends UR = UR, RT extends UR = UR, CRT extends UR = UR, PT extends UR = UR >({ apiKey, appId, errorHandler = handleError, i18nInstance, token, analyticsToken, children, defaultUserData, options, sharedFeeds = [{ feedGroup: 'notification', notify: true, options: { mark_seen: true } }], }: StreamAppProps) { const [client, setClient] = useState | null>(null); const [user, setUser] = useState>(); const [analyticsClient, setAnalyticsClient] = useState | null>(null); const [userData, setUserDate] = useState(); const [translator, setTranslator] = useState(); const [sharedFeedManagers, setSharedFeedManagers] = useState>({}); useEffect(() => { const streami18n = i18nInstance && i18nInstance instanceof Streami18n ? i18nInstance : new Streami18n({ language: 'en' }); streami18n.getTranslators().then(setTranslator); streami18n.registerSetLanguageCallback((t) => setTranslator((prevState) => ({ ...(prevState as TranslationContextValue), t })), ); }, [i18nInstance]); const getUserInfo = async (user: StreamUser) => { try { const { data } = await user.getOrCreate((defaultUserData || { name: 'Unknown' }) as UT); setUserDate(data); } catch (e) { errorHandler(e, 'get-user-info', { userId: user.id }); } }; useEffect(() => { const client = connect(apiKey, token, appId, options || {}); let analyticsClient: StreamAnalytics | null = null; if (analyticsToken) { analyticsClient = new StreamAnalytics({ apiKey, token: analyticsToken }); analyticsClient.setUser(client.userId as string); } const feeds: Record> = {}; for (const feedProps of sharedFeeds) { const manager = new FeedManager({ ...feedProps, client, analyticsClient, errorHandler, user, }); feeds[manager.feed().id] = manager; } setClient(client); setUser(client.currentUser as StreamUser); setAnalyticsClient(analyticsClient); setSharedFeedManagers(feeds); getUserInfo(client.currentUser as StreamUser); return () => client.fayeClient?.disconnect(); }, [apiKey, token, appId, analyticsClient]); if (!translator?.t) return null; return ( <>{children || 'You are connected to Stream, Throw some components in here!'} ); }