Skip to content

Commit d1c7c27

Browse files
feat: implement Redux for game state management
1 parent 71cb8d8 commit d1c7c27

File tree

11 files changed

+199
-68
lines changed

11 files changed

+199
-68
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
},
1313
"dependencies": {
1414
"@mui/material": "^6.4.8",
15+
"@reduxjs/toolkit": "^2.6.1",
1516
"devicon": "^2.16.0",
1617
"react": "^19.0.0",
1718
"react-dom": "^19.0.0",
19+
"react-redux": "^9.2.0",
1820
"react-router": "^7.4.0"
1921
},
2022
"devDependencies": {

pnpm-lock.yaml

Lines changed: 86 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/game/Game.tsx

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,48 @@
1-
import { useEffect, useState } from 'react'
21
import '@/styles/game/index.css'
3-
import type { Item, OwnedItems } from '@/types'
2+
import { useEffect } from 'react'
43
import { Grid2 as Grid, Card, CardContent, CardHeader } from '@mui/material'
5-
import { items } from '@/constants/items'
64
import { Score, Gitcoin } from '@/components/game/core'
75
import { Skills } from '@/components/game/skills'
86
import { Store } from '@/components/game/store'
7+
import { loop } from '@/modules/game'
98

10-
export function Game() {
11-
const [lines, setLines] = useState(0)
12-
const [linesPerMillisecond, setLinesPerMillisecond] = useState(0)
9+
import { useDispatch } from 'react-redux'
1310

14-
const [ownedItems, setOwnedItems] = useState<OwnedItems>({})
11+
export function Game() {
12+
const dispatch = useDispatch()
1513

1614
useEffect(() => {
1715
const interval = setInterval(() => {
18-
setLines(prev => prev + linesPerMillisecond)
16+
dispatch(loop())
1917
}, 100)
20-
return () => clearInterval(interval)
21-
}, [linesPerMillisecond])
22-
23-
useEffect(() => {
24-
let count = 0
2518

26-
Object.keys(ownedItems).forEach((name) => {
27-
const item = items.find(element => element.name === name)
28-
29-
if (item != null) {
30-
count += item.linesPerMillisecond * ownedItems[name]
31-
}
32-
})
33-
34-
setLinesPerMillisecond(count)
35-
}, [ownedItems])
36-
37-
const handleClick = () => {
38-
setLines(lines + 1)
39-
}
40-
41-
const handleBuy = (item: Item) => {
42-
setLines(lines - item.price)
43-
setOwnedItems({
44-
...ownedItems,
45-
[item.name]: (ownedItems[item.name] || 0) + 1,
46-
})
47-
}
19+
return () => clearInterval(interval)
20+
// eslint-disable-next-line react-hooks/exhaustive-deps
21+
}, [])
4822

4923
return (
5024
<>
5125
<Grid size={3}>
5226
<Card component="section" className="card">
5327
<CardContent className="content">
54-
<Score
55-
lines={Math.ceil(lines)}
56-
linesPerSecond={Math.ceil(linesPerMillisecond * 10)}
57-
/>
58-
<Gitcoin onClick={handleClick} />
28+
<Score />
29+
<Gitcoin />
5930
</CardContent>
6031
</Card>
6132
</Grid>
6233
<Grid size="grow">
6334
<Card component="section" className="card">
6435
<CardHeader title="Skills" />
6536
<CardContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
66-
<Skills skills={ownedItems} />
37+
<Skills />
6738
</CardContent>
6839
</Card>
6940
</Grid>
7041
<Grid size="grow">
7142
<Card component="section" className="card">
7243
<CardHeader title="Store" />
7344
<CardContent>
74-
<Store lines={lines} onBuy={handleBuy} />
45+
<Store />
7546
</CardContent>
7647
</Card>
7748
</Grid>

src/components/game/core/Gitcoin.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import '@/styles/game/core/gitcoin.css'
22
import githubIcon from '@/assets/github.svg'
3+
import { click } from '@/modules/game'
4+
import { useDispatch } from 'react-redux'
35

4-
type Props = {
5-
onClick: () => void
6-
}
6+
export function Gitcoin() {
7+
const dispatch = useDispatch()
8+
const handleClick = () => dispatch(click())
79

8-
export function Gitcoin({ onClick }: Props) {
910
return (
10-
<button className="gitcoin" onClick={onClick} type="button">
11+
<button className="gitcoin" onClick={handleClick} type="button">
1112
<img src={githubIcon} alt="Gitcoin" />
1213
</button>
1314
)

src/components/game/core/Score.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
type Props = {
2-
lines: number
3-
linesPerSecond: number
4-
}
1+
import { useSelector } from 'react-redux'
2+
import { RootState } from '@/store'
3+
4+
export const Score = () => {
5+
const lines = useSelector((state: RootState) => state.game.lines)
6+
const linesPerMillisecond = useSelector((state: RootState) => state.game.linesPerMillisecond)
57

6-
export function Score({ lines, linesPerSecond }: Props) {
78
return (
89
<>
910
<h3 style={{ fontFamily: 'Orbitron' }}>
1011
{Math.ceil(lines)} lines
1112
</h3>
1213
<small>
13-
per second: {Math.ceil(linesPerSecond * 10)}
14+
per second: {Math.ceil(Math.ceil(linesPerMillisecond * 10) * 10)}
1415
</small>
1516
</>
1617
)

src/components/game/skills/Skills.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1+
import { RootState } from '@/store'
2+
import { useSelector } from 'react-redux'
13
import { Section } from './Section'
2-
import { OwnedItems } from '@/types'
34

4-
type Props = {
5-
skills: OwnedItems
6-
}
5+
export const Skills = () => {
6+
const skills = useSelector((state: RootState) => state.game.skills)
77

8-
export const Skills = ({ skills }: Props) => {
98
return (
109
<>
11-
{Object.keys(skills).map((name, key) => (
10+
{Object.keys(skills).map(name => (
1211
<Section
13-
key={key}
12+
key={name}
1413
itemName={name}
1514
number={skills[name]}
1615
/>

src/components/game/store/Store.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ import { Item as ItemType } from '@/types'
22
import { Item } from './Item.tsx'
33
import { items } from '@/constants/items.ts'
44
import { Grid2 as Grid } from '@mui/material'
5+
import { buyItem } from '@/modules/game.ts'
6+
import { RootState } from '@/store.ts'
7+
import { useSelector, useDispatch } from 'react-redux'
58

6-
type Props = {
7-
lines: number
8-
onBuy: (item: ItemType) => void
9-
}
9+
export function Store() {
10+
const lines = useSelector((state: RootState) => state.game.lines)
11+
const dispatch = useDispatch()
12+
const handleBuy = (item: ItemType) => dispatch(buyItem(item))
1013

11-
export function Store({ lines, onBuy }: Props) {
1214
return (
1315
<Grid container component="ul" spacing={2} display="flex" flexDirection="column">
1416
{items.map((item, key) => (
1517
<Item
1618
key={key}
1719
item={item}
1820
lines={lines}
19-
onBuy={onBuy}
21+
onBuy={handleBuy}
2022
/>
2123
))}
2224
</Grid>

0 commit comments

Comments
 (0)