Skip to content

Commit 368f685

Browse files
authored
Merge pull request #142 from TaloDev/develop
Release 0.25.0
2 parents cc2b329 + 9cc23e4 commit 368f685

File tree

11 files changed

+753
-707
lines changed

11 files changed

+753
-707
lines changed

README.md

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,42 @@
11
# Talo dashboard
22

3-
## Installation
3+
Talo's dashboard lets you see your players and interact with your game directly.
44

5-
Run `yarn` or `npm install`.
5+
## Features
6+
- ⚡️ [Event tracking](https://trytalo.com/events)
7+
- 👥 [Player management](https://trytalo.com/players) (including cross-session data, groups and identity management)
8+
- 🎮 [Unity SDK](https://trytalo.com/unity)
9+
- 🗃️ Data exports
10+
- 🕹️ [Leaderboards](https://trytalo.com/leaderboards)
11+
- 💾 [Game saves](https://trytalo.com/saves)
12+
- 📊 [Game stats](https://trytalo.com/stats) (global and per-player)
13+
- ⚙️ [Live config](https://trytalo.com/live-config) (update your game config from the web, no releases required)
614

7-
## Available Scripts
15+
## Docs
16+
17+
Our docs are [available here](https://docs.trytalo.com).
18+
19+
## Self-hosting
20+
21+
See the [self-hosting docs](https://docs.trytalo.com/docs/selfhosting/overview) and the [self-hosting example repo](https://github.com/TaloDev/hosting).
22+
23+
## Discord
24+
25+
For help and support, [join our Discord](https://discord.gg/2RWwxXVY3v).
26+
27+
## Installing, building & running
28+
29+
Run `yarn` or `npm install` to install the dependencies.
830

931
### yarn dev
1032

1133
Runs the app in the development mode.
1234
Open http://localhost:8080 to view it in the browser.
1335

14-
The page will reload if you make edits.
15-
You will also see any lint errors in the console.
16-
1736
### yarn build
1837

19-
Builds a static copy of your site to the `dist/` folder.
38+
Builds a static copy of the site to the `dist/` folder.
2039

2140
## Docker?
2241

23-
We use Docker to build a production image of the frontend (which is simply an nginx server that hosts the static build files). It's not needed for development.
42+
We use Docker to build a production image of the dashboard (which is a simple NGINX server that hosts the static build files). It's not needed for development.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"classnames": "^2.3.2",
2020
"date-fns": "^2.29.3",
2121
"dinero.js": "^2.0.0-alpha.11",
22-
"framer-motion": "^9.0.0",
22+
"framer-motion": "^10.0.0",
2323
"lodash-es": "^4.17.21",
2424
"prop-types": "^15.7.2",
2525
"querystring": "^0.2.1",
@@ -47,7 +47,7 @@
4747
"@types/react": "^18.0.27",
4848
"@types/react-dom": "^18.0.10",
4949
"@vitejs/plugin-react-swc": "^3.0.1",
50-
"@vitest/coverage-c8": "^0.28.1",
50+
"@vitest/coverage-c8": "^0.29.0",
5151
"autoprefixer": "^10.2.5",
5252
"axios-mock-adapter": "^1.20.0",
5353
"cypress": "^12.3.0",
@@ -61,17 +61,17 @@
6161
"jsdom": "^21.0.0",
6262
"lint-staged": ">=10",
6363
"postcss": "^8.3.0",
64-
"start-server-and-test": "^1.15.2",
64+
"start-server-and-test": "^2.0.0",
6565
"tailwindcss": "^3.2.4",
6666
"vite": "^4.0.4",
67-
"vitest": "^0.28.5"
67+
"vitest": "^0.29.0"
6868
},
6969
"license": "MIT",
7070
"browserslist": ">0.75%",
7171
"lint-staged": {
7272
"*.{js,jsx}": "eslint --fix"
7373
},
74-
"version": "0.24.1",
74+
"version": "0.25.0",
7575
"engines": {
7676
"node": "16.x"
7777
}

src/components/ColourfulCheckbox.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState } from 'react'
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44
import { IconCheck } from '@tabler/icons-react'
5-
import { labelFocusStyle } from '../styles/theme'
5+
import { hiddenInputStyle, labelFocusStyle } from '../styles/theme'
66

77
const ColourfulCheckbox = (props) => {
88
const [focus, setFocus] = useState(false)
@@ -12,7 +12,7 @@ const ColourfulCheckbox = (props) => {
1212
<input
1313
id={props.id}
1414
type='checkbox'
15-
className='absolute inset-0 opacity-0'
15+
className={hiddenInputStyle}
1616
onFocus={() => setFocus(true)}
1717
onBlur={() => setFocus(false)}
1818
{...props}

src/components/Modal.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ const Modal = (props) => {
2929
<div className='fixed w-screen md:p-4 bg-gray-900 bg-opacity-60 flex items-start md:items-center justify-center inset-0 z-50 text-black transition-colors'>
3030
<dialog
3131
className={classNames('block w-full h-full md:h-auto md:w-[640px] bg-white md:rounded p-0', {
32-
'overflow-scroll': props.scroll,
33-
'overflow-visible': !props.scroll
32+
'overflow-y-scroll': props.scroll,
33+
'overflow-y-visible': !props.scroll
3434
})}
3535
aria-modal='true'
3636
aria-labelledby={`modal-${props.id}-label`}

src/components/RadioGroup.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from 'react'
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
4-
import { labelFocusStyle } from '../styles/theme'
4+
import { hiddenInputStyle, labelFocusStyle } from '../styles/theme'
55

66
function RadioGroup({ label, name, options, onChange, value, info }) {
77
const [focusedValue, setFocusedValue] = useState()
@@ -18,7 +18,7 @@ function RadioGroup({ label, name, options, onChange, value, info }) {
1818
<div key={option.value} className='min-w-[96px]'>
1919
<input
2020
id={`${name}${idx}`}
21-
className='absolute inset-0 opacity-0'
21+
className={hiddenInputStyle}
2222
type='radio'
2323
name={name}
2424
onChange={() => onChange(option.value)}

src/components/toggles/DevDataToggle.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from 'react'
22
import classNames from 'classnames'
33
import { motion } from 'framer-motion'
4-
import { labelFocusStyle } from '../../styles/theme'
4+
import { hiddenInputStyle, labelFocusStyle } from '../../styles/theme'
55
import { IconCheck, IconX } from '@tabler/icons-react'
66
import { useRecoilState } from 'recoil'
77
import devDataState from '../../state/devDataState'
@@ -23,7 +23,7 @@ function DevDataToggle() {
2323
<input
2424
id='dev-data'
2525
type='checkbox'
26-
className='absolute inset-0 opacity-0'
26+
className={hiddenInputStyle}
2727
onFocus={() => setFocus(true)}
2828
onBlur={() => setFocus(false)}
2929
onChange={() => setInnerEnabled(!innerEnabled)}

src/components/toggles/Toggle.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState } from 'react'
22
import PropTypes from 'prop-types'
33
import classNames from 'classnames'
44
import { motion } from 'framer-motion'
5-
import { labelFocusStyle } from '../../styles/theme'
5+
import { hiddenInputStyle, labelFocusStyle } from '../../styles/theme'
66

77
function Toggle({ id, enabled, onToggle, disabled, inputRef }) {
88
const [focus, setFocus] = useState(false)
@@ -25,7 +25,7 @@ function Toggle({ id, enabled, onToggle, disabled, inputRef }) {
2525
data-testid={id}
2626
ref={inputRef}
2727
type='checkbox'
28-
className='absolute inset-0 opacity-0'
28+
className={hiddenInputStyle}
2929
onFocus={() => setFocus(true)}
3030
onBlur={() => setFocus(false)}
3131
onChange={() => setInnerEnabled(!innerEnabled)}

src/pages/Groups.jsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import useGroups from '../api/useGroups'
1414
import GroupDetails from '../modals/groups/GroupDetails'
1515
import useSortedItems from '../utils/useSortedItems'
1616
import Identifier from '../components/Identifier'
17+
import { useNavigate } from 'react-router-dom'
18+
import routes from '../constants/routes'
1719

1820
export default function Groups() {
1921
const activeGame = useRecoilValue(activeGameState)
@@ -24,6 +26,8 @@ export default function Groups() {
2426
const { groups, loading, error, mutate } = useGroups(activeGame)
2527
const sortedGroups = useSortedItems(groups, 'name', 'asc')
2628

29+
const navigate = useNavigate()
30+
2731
useEffect(() => {
2832
if (!showModal) setEditingGroup(null)
2933
}, [showModal, editingGroup])
@@ -33,6 +37,10 @@ export default function Groups() {
3337
setShowModal(true)
3438
}
3539

40+
const goToPlayersForGroup = (group) => {
41+
navigate(`${routes.players}?search=group:${group.id}`)
42+
}
43+
3644
return (
3745
<Page
3846
title='Groups'
@@ -56,12 +64,12 @@ export default function Groups() {
5664

5765
{groups.length > 0 &&
5866
<>
59-
<Table columns={['ID', 'Name', 'Players', 'Last updated', '']}>
67+
<Table columns={['ID', 'Name', 'Players', 'Last updated', '', '']}>
6068
<TableBody iterator={sortedGroups}>
6169
{(group) => (
6270
<>
6371
<TableCell className='min-w-80'>
64-
<Identifier id='ccb3226c-54ac-4e8d-af27-6154a6315f2f' />
72+
<Identifier id={group.id} />
6573
</TableCell>
6674
<TableCell className='min-w-[320px] max-w-[320px] lg:min-w-0'>
6775
{group.name}
@@ -79,6 +87,14 @@ export default function Groups() {
7987
Edit
8088
</Button>
8189
</TableCell>
90+
<TableCell className='w-48'>
91+
<Button
92+
variant='grey'
93+
onClick={() => goToPlayersForGroup(group)}
94+
>
95+
View players
96+
</Button>
97+
</TableCell>
8298
</>
8399
)}
84100
</TableBody>

src/pages/Players.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import Page from '../components/Page'
1818
import Table from '../components/tables/Table'
1919

2020
const Players = () => {
21-
const [search, setSearch] = useState(new URLSearchParams(window.location.search).get('search') ?? '')
21+
const initialSearch = new URLSearchParams(window.location.search).get('search')
22+
23+
const [search, setSearch] = useState(initialSearch ?? '')
2224
const [debouncedSearch] = useDebounce(search, 300)
2325
const activeGame = useRecoilValue(activeGameState)
2426
const navigate = useNavigate()
@@ -36,7 +38,7 @@ const Players = () => {
3638
}, [page])
3739

3840
return (
39-
<Page title='Players' isLoading={loading}>
41+
<Page title='Players' isLoading={loading} showBackButton={Boolean(initialSearch)}>
4042
{(players.length > 0 || debouncedSearch.length > 0) &&
4143
<div className='flex items-center'>
4244
<div className='w-1/2 flex-grow md:flex-grow-0 lg:w-1/4'>

src/styles/theme.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ export const labelFocusStyle = 'ring ring-pink-500'
55
export const linkStyle = 'text-indigo-400 hover:underline font-semibold transition-colors rounded-none'
66

77
export const unauthedContainerStyle = 'w-full md:w-2/3 xl:w-1/3'
8+
9+
export const hiddenInputStyle = 'absolute inset-0 opacity-0 w-0 h-0'

0 commit comments

Comments
 (0)