add unified provider

This commit is contained in:
Pavel Prichodko 2023-02-28 14:56:21 +01:00
parent 2d2938c057
commit 3625fa355a
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
6 changed files with 192 additions and 0 deletions

View File

@ -6,6 +6,7 @@ export * from './icon-button'
export * from './image' export * from './image'
export * from './input' export * from './input'
export * from './messages' export * from './messages'
export * from './provider'
export * from './sidebar' export * from './sidebar'
export * from './sidebar-members' export * from './sidebar-members'
export * from './topbar' export * from './topbar'

View File

@ -0,0 +1,67 @@
import { createContext, useContext, useReducer } from 'react'
/*
* CONTEXT
*/
const DispatchContext = createContext<React.Dispatch<Action> | undefined>(
undefined
)
const StateContext = createContext<State | undefined>(undefined)
/*
* REDUCER
*/
type State = {
channelId?: string
}
type Action = { type: 'set-channel'; channelId: string }
const reducer = (_state: State, action: Action): State => {
switch (action.type) {
case 'set-channel': {
return { channelId: action.channelId }
}
}
}
type Props = {
children: React.ReactNode
}
const AppProvider = (props: Props) => {
const { children } = props
const [state, dispatch] = useReducer(reducer, { channelId: 'welcome' })
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>
</DispatchContext.Provider>
)
}
const useAppState = (): State => {
const context = useContext(StateContext)
if (context === undefined) {
throw new Error('useMessagesState must be used within a MessagesProvider')
}
return context
}
const useAppDispatch = () => {
const context = useContext(DispatchContext)
if (context === undefined) {
throw new Error(
'useMessagesDispatch must be used within a MessagesProvider'
)
}
return context
}
export { AppProvider, useAppDispatch, useAppState }

View File

@ -0,0 +1,74 @@
import { createContext, useContext, useReducer } from 'react'
/*
* CONTEXT
*/
const DispatchContext = createContext<React.Dispatch<Action> | undefined>(
undefined
)
const StateContext = createContext<State | null>(null)
/*
* REDUCER
*/
type State = {
type: 'edit' | 'reply'
messageId: string
} | null
type Action =
| { type: 'edit'; messageId: string }
| { type: 'reply'; messageId: string }
| { type: 'cancel' }
const reducer = (_state: State, action: Action): State => {
switch (action.type) {
case 'edit':
return { type: 'edit', messageId: action.messageId }
case 'reply':
return { type: 'reply', messageId: action.messageId }
case 'cancel':
return null
}
}
type Props = {
children: React.ReactNode
}
const ChatProvider = (props: Props) => {
const { children } = props
const [state, dispatch] = useReducer(reducer, null)
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>{children}</StateContext.Provider>
</DispatchContext.Provider>
)
}
const useChatState = (): State => {
const context = useContext(StateContext)
if (context === undefined) {
throw new Error('useMessagesState must be used within a MessagesProvider')
}
return context
}
const useChatDispatch = () => {
const context = useContext(DispatchContext)
if (context === undefined) {
throw new Error(
'useMessagesDispatch must be used within a MessagesProvider'
)
}
return context
}
export { ChatProvider, useChatDispatch, useChatState }

View File

@ -0,0 +1,3 @@
export { useAppDispatch, useAppState } from './app-context'
export { useChatDispatch, useChatState } from './chat-context'
export { Provider } from './provider'

View File

@ -0,0 +1,23 @@
import { AppProvider } from './app-context'
import { ChatProvider } from './chat-context'
import { ThemeProvider } from './theme-context'
import type { ThemeProviderProps } from './theme-context'
type Props = ThemeProviderProps & {
children: React.ReactNode
}
const Provider = (props: Props) => {
const { children } = props
return (
<ThemeProvider defaultTheme={props.defaultTheme}>
<AppProvider>
<ChatProvider>{children}</ChatProvider>
</AppProvider>
</ThemeProvider>
)
}
export { Provider }

View File

@ -0,0 +1,24 @@
import { TamaguiProvider } from '@tamagui/core'
import { config } from '../tamagui.config'
type Theme = 'light' | 'dark'
type Props = {
children: React.ReactNode
defaultTheme?: Theme
}
const ThemeProvider = (props: Props) => {
const { children, defaultTheme = 'light' } = props
return (
// TODO: store theme in localStorage
<TamaguiProvider config={config} defaultTheme={defaultTheme}>
{children}
</TamaguiProvider>
)
}
export { ThemeProvider }
export type ThemeProviderProps = Omit<Props, 'children'>
export type { Theme }