Skip to content

Commit

Permalink
filter games by name in my games
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-codes committed Feb 6, 2024
1 parent da51192 commit 69357f2
Show file tree
Hide file tree
Showing 18 changed files with 229 additions and 159 deletions.
4 changes: 2 additions & 2 deletions apps/playnite-web/src/api/client/state/authSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const slice = createSlice({
},
reducers: {
signedIn(state, action) {
return merge(state, { isAuthenticated: true })
return merge({}, state, { isAuthenticated: true })
},
signedOut(state, action) {
return merge(state, { isAuthenticated: false })
return merge({}, state, { isAuthenticated: false })
},
},
})
Expand Down
6 changes: 3 additions & 3 deletions apps/playnite-web/src/api/client/state/deviceFeaturesSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const slice = createSlice({
name: 'deviceFeatures',
initialState,
selectors: {
getDeviceFeatures: (state) => ({
getDeviceFeatures: memoize((state) => ({
device: {
type: state.device?.type,
vendor: state.device?.vendor,
Expand All @@ -32,7 +32,7 @@ const slice = createSlice({
isTouchEnabled: state.isTouchEnabled,
isPwa: state.isPwa,
orientation: state.orientation,
}),
})),
},
reducers: {
setDeviceFeatures(
Expand All @@ -46,7 +46,7 @@ const slice = createSlice({
}
},
) {
return merge(state, action.payload)
return merge({}, state, action.payload)
},
},
})
Expand Down
4 changes: 3 additions & 1 deletion apps/playnite-web/src/api/client/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { combineReducers } from '@reduxjs/toolkit'
import * as authSlice from './authSlice'
import * as deviceFeaturesSlice from './deviceFeaturesSlice'
import * as layoutSlice from './layoutSlice'
import * as librarySlice from './librarySlice'

const reducer = combineReducers({
auth: authSlice.reducer,
layout: layoutSlice.reducer,
deviceFeatures: deviceFeaturesSlice.reducer,
layout: layoutSlice.reducer,
library: librarySlice.reducer,
})

export { reducer }
2 changes: 1 addition & 1 deletion apps/playnite-web/src/api/client/state/layoutSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const slice = createSlice({
},
reducers: {
setDeviceType(state, action) {
return merge(state, { deviceType: action.payload })
return merge({}, state, { deviceType: action.payload })
},
},
})
Expand Down
36 changes: 36 additions & 0 deletions apps/playnite-web/src/api/client/state/librarySlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createSelector, createSlice } from '@reduxjs/toolkit'
import NoFilter from '../../../domain/filters/NoFilter'
import MatchName from '../../../domain/filters/playnite/MatchName'

import _ from 'lodash'

const { memoize, merge } = _

const initialState: {
nameFilter: string | null
} = {
nameFilter: null,
}

const noFilter = new NoFilter()

const getNameFilter = memoize((state: typeof initialState) =>
!state.nameFilter ? noFilter : new MatchName(state.nameFilter),
)

const slice = createSlice({
name: 'library',
initialState,
selectors: {
getFilter: createSelector(getNameFilter, (filter) => filter),
},
reducers: {
setNameFilter(state, action) {
return merge({}, state, { nameFilter: action.payload })
},
},
})

export const { reducer } = slice
export const { setNameFilter } = slice.actions
export const { getFilter } = slice.selectors
13 changes: 13 additions & 0 deletions apps/playnite-web/src/api/client/state/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { configureStore } from '@reduxjs/toolkit'
import { reducer } from '.'

let store
const getStore = () => {
if (!store) {
store = configureStore({ reducer })
}

return store
}

export default getStore
4 changes: 3 additions & 1 deletion apps/playnite-web/src/components/GameFigure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ const Figure = styled('figure')(({ theme }) => ({
const Image = styled('img', {
shouldForwardProp: (prop) => prop !== 'width',
})<{ width: string }>(({ width, theme }) => ({
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shadows[3],
height: `calc(${width} - 16px)`,
objectFit: 'cover',
width: `calc(${width} - 16px)`,
height: `calc(${width} - 16px)`,
}))

const GameFigure: FC<
Expand Down
5 changes: 4 additions & 1 deletion apps/playnite-web/src/components/GameGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ const GameGrid: FC<{
<>
<ImageListWithoutOverflow rowHeight={rowHeight} cols={columns}>
{games.items.map((game, gameIndex) => (
<ImageListItem key={game.oid.asString}>
<ImageListItem
key={game.oid.asString}
sx={{ ...(!game.matches ? { display: 'none' } : {}) }}
>
<GameFigure
game={game}
height={`${rowHeight}px`}
Expand Down
49 changes: 0 additions & 49 deletions apps/playnite-web/src/components/GameImage.tsx

This file was deleted.

51 changes: 51 additions & 0 deletions apps/playnite-web/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Divider, TextField, styled } from '@mui/material'
import { ChangeEvent, FC, PropsWithChildren, useCallback } from 'react'
import { useDispatch, useStore } from 'react-redux'
import { setNameFilter } from '../api/client/state/librarySlice'

const HeaderContainer = styled('header')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
}))

const Filters = styled('section')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
flex: 1,
justifyContent: 'flex-end',
alignItems: 'flex-end',
}))

const Header: FC<PropsWithChildren<{ showFilters?: boolean }>> = ({
children,
showFilters,
}) => {
const store = useStore()
console.dir(store.getState())
const dispatch = useDispatch()
const handleSearch = useCallback((event: ChangeEvent<HTMLInputElement>) => {
dispatch(setNameFilter(event.target.value))
}, [])

return (
<>
<HeaderContainer>
{children}
{showFilters && (
<Filters>
<TextField
onChange={handleSearch}
placeholder="Find"
type="text"
defaultValue=""
variant="outlined"
/>
</Filters>
)}
</HeaderContainer>
<Divider sx={{ margin: `48px 0` }} />
</>
)
}

export default Header
6 changes: 1 addition & 5 deletions apps/playnite-web/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { Box, useMediaQuery, useTheme } from '@mui/material'
import { FC, PropsWithChildren } from 'react'
import { useSelector } from 'react-redux'
import { getDeviceFeatures } from '../api/client/state/deviceFeaturesSlice'
import DrawerNavigation from './Navigation/DrawerNavigation'
import MobileDrawerNavigation from './Navigation/MobileDrawerNavigation'
import useThemeWidth from './useThemeWidth'

const Layout: FC<PropsWithChildren & {}> = ({ children }) => {
const deviceFeatures = useSelector(getDeviceFeatures)

const theme = useTheme()
const shouldUseMobileDrawer = useMediaQuery(theme.breakpoints.down('lg'))
const Drawer = shouldUseMobileDrawer
Expand Down Expand Up @@ -39,7 +35,7 @@ const Layout: FC<PropsWithChildren & {}> = ({ children }) => {
padding: '80px 24px',
},
[theme.breakpoints.up('xl')]: {
padding: '120px 48px',
padding: '80px 48px',
},
[theme.breakpoints.down('xs')]: {
padding: '80px 24px',
Expand Down
54 changes: 54 additions & 0 deletions apps/playnite-web/src/components/MyLibrary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Typography } from '@mui/material'
import { FC, useMemo } from 'react'
import { Helmet } from 'react-helmet'
import { useSelector } from 'react-redux'
import { getFilter } from '../api/client/state/librarySlice'
import GameGrid from '../components/GameGrid'
import Header from '../components/Header'
import FilteredGameList from '../domain/FilteredGameList'
import GameList from '../domain/GameList'
import type { GameOnPlatform } from '../domain/types'

const MyLibrary: FC<{ gamesOnPlatforms: GameOnPlatform[] }> = ({
gamesOnPlatforms = [] as GameOnPlatform[],
}) => {
const gameList = useMemo(() => {
return new GameList(gamesOnPlatforms)
}, [gamesOnPlatforms])

const filter = useSelector(getFilter)
const filteredGames = useMemo(
() => new FilteredGameList(gameList, filter),
[gameList, filter],
)

const noDeferCount = 25

return (
<>
<Helmet>
{gameList.items
.filter((game, index) => index <= noDeferCount)
.map((game) => (
<link
key={game.oid.asString}
rel="preload"
as="image"
href={game.cover}
/>
))}
</Helmet>
<Header showFilters>
<section>
<Typography variant="h2">My Games</Typography>
<Typography variant="subtitle1">
{gameList.items.length} games in my library
</Typography>
</section>
</Header>
<GameGrid games={filteredGames} noDeferCount={noDeferCount} />
</>
)
}

export default MyLibrary
28 changes: 8 additions & 20 deletions apps/playnite-web/src/components/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
import styled from '@emotion/styled'
import { forwardRef, useCallback, useState } from 'react'

const SearchInput = styled.input<{ height: number }>`
display: flex;
justify-content: center;
border-radius: ${({ height }) => height / 2}px;
padding: 0;
color: darkslategray;
`
import { TextField } from '@mui/material'
import { forwardRef, useCallback } from 'react'

const Search = forwardRef<
HTMLInputElement,
{
onSearch: (search: string) => void
defaultValue: string
height?: number
defaultValue?: string
}
>(({ onSearch, defaultValue = '', height }, ref) => {
const [value, setValue] = useState(defaultValue)
>(({ onSearch, defaultValue = '' }) => {
const handleOnChange = useCallback((e) => {
setValue(e.target.value)
onSearch(e.target.value)
}, [])

return (
<SearchInput
height={height ?? 48}
<TextField
onChange={handleOnChange}
placeholder="Search"
ref={ref}
placeholder="Find"
type="text"
value={value}
defaultValue={defaultValue}
variant="outlined"
/>
)
})
Expand Down
8 changes: 7 additions & 1 deletion apps/playnite-web/src/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { CacheProvider } from '@emotion/react'
import { configureStore } from '@reduxjs/toolkit'
import { loadServiceWorker } from '@remix-pwa/sw'
import { RemixBrowser } from '@remix-run/react'
import { startTransition, StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import { reducer } from './api/client/state'
import createEmotionCache from './createEmotionCache'

const clientSideCache = createEmotionCache()

startTransition(() => {
const store = configureStore({ reducer })
hydrateRoot(
document.getElementById('root')!,
<StrictMode>
<CacheProvider value={clientSideCache}>
<RemixBrowser />
<Provider store={store}>
<RemixBrowser />
</Provider>
</CacheProvider>
</StrictMode>,
)
Expand Down
Loading

0 comments on commit 69357f2

Please sign in to comment.