Skip to content

Commit

Permalink
feat(frontend): add content hooks and typesafe websocket client
Browse files Browse the repository at this point in the history
  • Loading branch information
Harjot1Singh committed Nov 5, 2024
1 parent 8922c96 commit 10e4946
Show file tree
Hide file tree
Showing 35 changed files with 1,017 additions and 657 deletions.
4 changes: 3 additions & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@mui/material": "^5.16.6",
"@presenter/swiss-knife": "*",
"@presenter/themes": "*",
"@sentry/browser": "^6.19.7",
"@tanstack/react-router": "^1.49.2",
Expand All @@ -39,15 +40,16 @@
"eventemitter3": "^5.0.1",
"gurmukhi-utils": "^3.2.2",
"is-mobile": "^3.1.1",
"jotai": "^2.10.1",
"lodash": "^4.17.21",
"memoizee": "^0.4.17",
"notistack": "^3.0.1",
"partysocket": "^1.0.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hotkeys": "^2.0.0",
"react-idle-timer": "^5.7.2",
"react-transition-group": "^4.4.5",
"reconnecting-websocket": "^4.4.0",
"scroll-into-view": "^1.16.0",
"zod": "^3.8.2-alpha.6"
},
Expand Down
131 changes: 34 additions & 97 deletions apps/frontend/src/app/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,45 @@
import './__root.css'

import { RecommendedSources, Shabad, Writer } from '@presenter/contract'
import { RecommendedSources, Writer } from '@presenter/contract'
import { createRootRoute, Navigate, Outlet } from '@tanstack/react-router'
import classNames from 'classnames'
import { Provider } from 'jotai'
import { SnackbarProvider } from 'notistack'
import { PureComponent, Suspense } from 'react'

import Loader from '~/components/Loader'
import { API_URL, isDesktop, isMobile, isTablet } from '~/helpers/consts'
import {
BookmarksContext,
ContentContext,
HistoryContext,
RecommendedSourcesContext,
SettingsContext,
StatusContext,
WritersContext,
} from '~/helpers/contexts'
import { DEFAULT_OPTIONS } from '~/helpers/options'
import { merge } from '~/helpers/utils'
import controller from '~/services/controller'
import { store } from '~/services/jotai'
// import controller from '~/services/controller'

const loadSettings = () => merge( { local: controller.readSettings() }, DEFAULT_OPTIONS )
// const loadSettings = () => merge( { local: controller.readSettings() }, DEFAULT_OPTIONS )
const loadSettings = () => DEFAULT_OPTIONS

class App extends PureComponent {
state = {
connected: false,
connectedAt: null,
status: null,
banis: [],
bani: null,
lineId: null,
mainLineId: null,
nextLineId: null,
viewedLines: {},
transitionHistory: {},
latestLines: {},
shabad: null,
recommendedSources: {} as RecommendedSources['recommendedSources'],
writers: {},
settings: loadSettings(),
next: {},
}

componentDidMount() {
// Register controller event
controller.on( 'connected', this.onConnected )
controller.on( 'disconnected', this.onDisconnected )
controller.on( 'shabads:current', this.onShabad )
controller.on( 'lines:current', this.onLine )
controller.on( 'lines:main', this.onMainLine )
controller.on( 'lines:next', this.onNextLine )
controller.on( 'history:viewed-lines', this.onViewedLines )
controller.on( 'history:transitions', this.onTransitionHistory )
controller.on( 'history:latest-lines', this.onLatestLineHistory )
controller.on( 'banis:list', this.onBanis )
controller.on( 'banis:current', this.onBani )
controller.on( 'status', this.onStatus )
controller.on( 'settings', this.onSettings )
// controller.on( 'history:viewed-lines', this.onViewedLines )
// controller.on( 'history:transitions', this.onTransitionHistory )
// controller.on( 'history:latest-lines', this.onLatestLineHistory )
// controller.on( 'banis:list', this.onBanis )
// controller.on( 'settings', this.onSettings )

// Get recommended sources and set as settings, if there are none
void fetch( `${API_URL}/sources` )
Expand All @@ -77,54 +59,22 @@ class App extends PureComponent {

componentWillUnmount() {
// Deregister event listeners from controller
controller.off( 'connected', this.onConnected )
controller.off( 'disconnected', this.onDisconnected )
controller.off( 'shabads:current', this.onShabad )
controller.off( 'lines:current', this.onLine )
controller.off( 'history:transitions', this.onTransitionHistory )
controller.off( 'history:latest-lines', this.onLatestLineHistory )
controller.off( 'lines:main', this.onMainLine )
controller.off( 'lines:next', this.onNextLine )
controller.off( 'lines:viewed', this.onViewedLines )
controller.off( 'banis:list', this.onBanis )
controller.off( 'banis:current', this.onBani )
controller.off( 'status', this.onStatus )
controller.off( 'settings', this.onSettings )
// controller.off( 'shabads:current', this.onShabad )
// controller.off( 'lines:current', this.onLine )
// controller.off( 'history:transitions', this.onTransitionHistory )
// controller.off( 'history:latest-lines', this.onLatestLineHistory )
// controller.off( 'lines:main', this.onMainLine )
// controller.off( 'lines:next', this.onNextLine )
// controller.off( 'lines:viewed', this.onViewedLines )
// controller.off( 'banis:list', this.onBanis )
// controller.off( 'banis:current', this.onBani )
// controller.off( 'settings', this.onSettings )
}

onConnected = () => this.setState( {
connectedAt: new Date(),
connected: true,
bani: null,
shabad: null,
} )

onDisconnected = () => this.setState( { connected: false } )

onShabad = ( shabad: Shabad ) => this.setState( { next: { shabad, bani: null } } )

onLine = ( lineId: string ) => this.setState(
( { next }: any ) => ( { lineId, ...next, next: {} } )
)

onViewedLines = ( viewedLines: any[] ) => this.setState( { viewedLines } )

onMainLine = ( mainLineId: string ) => this.setState( { mainLineId } )

onNextLine = ( nextLineId: string ) => this.setState( { nextLineId } )

onTransitionHistory = ( transitionHistory: any[] ) => this.setState( { transitionHistory } )

onLatestLineHistory = ( latestLines: any[] ) => this.setState( { latestLines } )

onStatus = ( status: any ) => this.setState( { status } )

onBanis = ( banis: any[] ) => this.setState( { banis } )

onBani = ( bani: any ) => this.setState( { next: { bani, shabad: null } } )

onSettings = ( { global = {}, local = {}, ...settings } ) => {
controller.saveLocalSettings( local, false )
// controller.saveLocalSettings( local, false )

this.setState( ( state: typeof this.state ) => ( {
settings: {
Expand All @@ -135,25 +85,16 @@ class App extends PureComponent {
...deviceSettings,
[ host ]: merge( DEFAULT_OPTIONS.local, config ),
} ), {} ),
local: controller.readSettings(),
// local: controller.readSettings(),
global: merge( state.settings.global, global ),
},
} ) )
}

render() {
const {
connected,
connectedAt,
status,
banis,
recommendedSources,
writers,
bani,
shabad,
lineId,
mainLineId,
nextLineId,
viewedLines,
transitionHistory,
latestLines,
Expand All @@ -162,25 +103,21 @@ class App extends PureComponent {

return (
<div className={classNames( { mobile: isMobile, tablet: isTablet, desktop: isDesktop }, 'app' )}>
<Suspense fallback={<Loader />}>
<StatusContext.Provider value={{ connected, connectedAt, status }}>
<Provider store={store}>
<Suspense fallback={<Loader />}>
<SettingsContext.Provider value={settings}>
<HistoryContext.Provider value={{ viewedLines, transitionHistory, latestLines }}>
<BookmarksContext.Provider value={banis}>
<WritersContext.Provider value={writers}>
<RecommendedSourcesContext.Provider value={recommendedSources}>
<ContentContext.Provider value={{ bani, shabad, lineId, mainLineId, nextLineId }}>
<SnackbarProvider>
<Outlet />
</SnackbarProvider>
</ContentContext.Provider>
</RecommendedSourcesContext.Provider>
</WritersContext.Provider>
</BookmarksContext.Provider>
<WritersContext.Provider value={writers}>
<RecommendedSourcesContext.Provider value={recommendedSources}>
<SnackbarProvider>
<Outlet />
</SnackbarProvider>
</RecommendedSourcesContext.Provider>
</WritersContext.Provider>
</HistoryContext.Provider>
</SettingsContext.Provider>
</StatusContext.Provider>
</Suspense>
</Suspense>
</Provider>
</div>
)
}
Expand Down
6 changes: 2 additions & 4 deletions apps/frontend/src/app/overlay/-components/ThemeLoader.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { useContext } from 'react'

import { API_URL } from '~/helpers/consts'
import { StatusContext } from '~/helpers/contexts'
import { useStatus } from '~/services/status'

const OVERLAY_THEMES_URL = `${API_URL}/themes/overlay`

type ThemeLoaderProps = { name?: string }

const ThemeLoader = ( { name }: ThemeLoaderProps ) => {
const { connectedAt } = useContext( StatusContext )
const { connectedAt } = useStatus()

return (
<link
Expand Down
5 changes: 3 additions & 2 deletions apps/frontend/src/app/overlay/index.lazy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ import classNames from 'classnames'
import { mapValues } from 'lodash'
import { useContext } from 'react'

import { SettingsContext, StatusContext } from '~/helpers/contexts'
import { SettingsContext } from '~/helpers/contexts'
import { LANGUAGES } from '~/helpers/data'
import { customiseLine, getTransliterators } from '~/helpers/line'
import { filterFalsyValues } from '~/helpers/utils'
import { useCurrentLine, useTranslations } from '~/hooks'
import { useStatus } from '~/services/status'

import Line from './-components/Line'
import ThemeLoader from './-components/ThemeLoader'

const Overlay = () => {
const settings = useContext( SettingsContext )
const { connected } = useContext( StatusContext )
const { connected } = useStatus()

const { global: globalSettings } = settings || {}
const { overlay: { overlayName, ...overlay } } = globalSettings || {}
Expand Down
11 changes: 5 additions & 6 deletions apps/frontend/src/app/presenter/-components/Display/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { LANGUAGES } from '~/helpers/data'
import { customiseLine, getTransliterators } from '~/helpers/line'
import { ClientSettings } from '~/helpers/options'
import { filterFalsyValues } from '~/helpers/utils'
import { useCurrentLine, useCurrentLines, useTranslations } from '~/hooks'
import { useTranslations } from '~/hooks'
import { useContent } from '~/services/content'

import Line from '../Line'

Expand All @@ -31,9 +32,7 @@ const Display = ( { settings }: DisplayProps ) => {
const { lineEnding } = display

// Find the correct line in the Shabad
const lines = useCurrentLines()
const [ line, lineIndex ] = useCurrentLine()
const typeId = ( line?.typeId ) || -1
const { line, lineIndex, lines } = useContent()

// Get the next lines
const { nextLines: nextLineCount, previousLines: previousLineCount } = display
Expand All @@ -48,7 +47,7 @@ const Display = ( { settings }: DisplayProps ) => {
display.punjabiTranslation && LANGUAGES.punjabi,
display.spanishTranslation && LANGUAGES.spanish,
] ) as number[] ),
( line ) => customiseLine( line, { lineEnding, typeId } ),
( line ) => customiseLine( line, { lineEnding, typeId: line.typeId } ),
)

const transliterators = mapValues(
Expand All @@ -58,7 +57,7 @@ const Display = ( { settings }: DisplayProps ) => {
display.urduTransliteration && LANGUAGES.urdu,
] ) as number[] ),
( transliterate ) => ( text: string ) => transliterate(
customiseLine( text, { lineEnding, typeId } )
customiseLine( text, { lineEnding, typeId: line?.typeId } ),
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import './index.css'

import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useContext } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group'

import { StatusContext } from '~/helpers/contexts'
import { useNotifications } from '~/services/notifications'

const StatusToast = () => {
const { status } = useContext( StatusContext )
const status = useNotifications()

return (
<TransitionGroup component={null}>
{status && (
Expand Down
11 changes: 5 additions & 6 deletions apps/frontend/src/app/presenter/controller/bookmarks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,28 @@ import './index.css'

import { List, ListItem } from '@mui/material'
import { createFileRoute } from '@tanstack/react-router'
import { useContext } from 'react'

import { withNavigationHotkeys } from '~/components/NavigationHotkeys'
import { BookmarksContext } from '~/helpers/contexts'
import { LINE_HOTKEYS } from '~/helpers/keyMap'
import controller from '~/services/controller'
import { useBookmarks } from '~/services/bookmarks'
import { setContent } from '~/services/content'

type BookmarkProps = {
focused?: number,
register: ( index: number, ref: HTMLElement | null ) => void,
}

const Bookmarks = ( { register, focused = 0 }: BookmarkProps ) => {
const bookmarks = useContext( BookmarksContext )
const bookmarks = useBookmarks()

return (
<List className="bookmarks">
{bookmarks.map( ( { id, nameGurmukhi }, index ) => (
{bookmarks?.map( ( { id, nameGurmukhi }, index ) => (
<ListItem
className={focused === index ? 'focused' : ''}
key={id}
ref={( ref ) => register( index, ref )}
onClick={() => controller.bani( { baniId: id } )}
onClick={() => setContent( { id, type: 'bani' } )}
>
<span className="hotkey meta">{LINE_HOTKEYS[ index ]}</span>
<span className="gurmukhi text">{nameGurmukhi}</span>
Expand Down
5 changes: 3 additions & 2 deletions apps/frontend/src/app/presenter/controller/history/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { withNavigationHotkeys } from '~/components/NavigationHotkeys'
import { HISTORY_DOWNLOAD_URL } from '~/helpers/consts'
import { HistoryContext } from '~/helpers/contexts'
import { LINE_HOTKEYS } from '~/helpers/keyMap'
import { setContent } from '~/services/content'
import controller from '~/services/controller'

type HistoryProps = {
Expand Down Expand Up @@ -43,8 +44,8 @@ const History = ( { register, focused = 0 }: HistoryProps ) => {
const latestLineId = latestLine ? latestLine.id : lineId

const onClick = () => ( bani
? controller.bani( { baniId: bani.id, lineId: latestLineId } )
: controller.shabad( { shabadId, lineId: latestLineId } ) )
? setContent( { type: 'bani', id: bani.id, lineId: latestLineId } )
: setContent( { type: 'shabad', id: shabadId, lineId: latestLineId } ) )

return (
<ListItem
Expand Down
Loading

0 comments on commit 10e4946

Please sign in to comment.