import { createContext, useContext, useMemo } from 'react'; import { useSubscription, Subscription, Unsubscribe } from 'use-subscription'; type SubscriptionQuery = { rid: string | Mongo.ObjectID; } | { name: string; } type Fields = { [key: string]: boolean; } type UserContextValue = { userId: string | null; user: Meteor.User | null; loginWithPassword: (user: string | object, password: string) => Promise; queryPreference: (key: string | Mongo.ObjectID, defaultValue?: T) => Subscription; querySubscription: (query: SubscriptionQuery, fields: Fields) => Subscription ; }; export const UserContext = createContext({ userId: null, user: null, loginWithPassword: async () => undefined, queryPreference: () => ({ getCurrentValue: (): undefined => undefined, subscribe: (): Unsubscribe => (): void => undefined, }), querySubscription: () => ({ getCurrentValue: (): undefined => undefined, subscribe: (): Unsubscribe => (): void => undefined, }), }); export const useUserId = (): string | Mongo.ObjectID | null => useContext(UserContext).userId; export const useUser = (): Meteor.User | null => useContext(UserContext).user; export const useLoginWithPassword = (): ((user: string | object, password: string) => Promise) => useContext(UserContext).loginWithPassword; export const useUserPreference = (key: string | Mongo.ObjectID, defaultValue?: T): T | undefined => { const { queryPreference } = useContext(UserContext); const subscription = useMemo(() => queryPreference(key, defaultValue), [queryPreference, key, defaultValue]); return useSubscription(subscription); }; export const useUserSubscription = (rid: string | Mongo.ObjectID, fields: Fields): T | undefined => { const { querySubscription } = useContext(UserContext); const subscription = useMemo(() => querySubscription({ rid }, fields), [querySubscription, rid, fields]); return useSubscription(subscription); }; export const useUserSubscriptionByName = (name: string, fields: Fields): T | undefined => { const { querySubscription } = useContext(UserContext); const subscription = useMemo(() => querySubscription({ name }, fields), [querySubscription, name, fields]); return useSubscription(subscription); };