Skip to content

Commit 0f347f2

Browse files
authored
feat: add cats/dogs setting (#4)
1 parent d1b3a51 commit 0f347f2

File tree

18 files changed

+154
-64
lines changed

18 files changed

+154
-64
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ dist-ssr
2525

2626
# Custom
2727
.env
28-
.eslintcache
28+
.eslintcache
29+
.vercel

docs/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Those are building blocks that encapsulate some of the domain logic to decrease
4646

4747
Infrastructure elements related to the domain. Often composed from reusable elements from `shared/infrastructure`.
4848

49-
Examples: `CardRepository`, `CardAPIClient`
49+
Examples: `PetImageApiClient`
5050

5151
#### Services
5252

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import ky from 'ky'
2+
3+
import { PetType } from '@/modules/game-settings'
4+
import {
5+
ImageApiClient,
6+
ImageApiSearchParams,
7+
ImageApiClientFactory,
8+
} from '@/shared/infrastructure'
9+
10+
const PET_TYPE_TO_API_URL_MAP = {
11+
[PetType.CATS]: 'https://api.thecatapi.com',
12+
[PetType.DOGS]: 'https://api.thedogapi.com',
13+
}
14+
15+
const PET_TYPE_TO_API_KEY_MAP = {
16+
[PetType.CATS]: import.meta.env.VITE_CAT_API_KEY,
17+
[PetType.DOGS]: import.meta.env.VITE_DOG_API_KEY,
18+
}
19+
20+
export class PetImageApiClientFactory extends ImageApiClientFactory {
21+
constructor(private petType: PetType) {
22+
super()
23+
}
24+
25+
public create(): ImageApiClient {
26+
const baseApiClient = ky.create({
27+
prefixUrl: PET_TYPE_TO_API_URL_MAP[this.petType],
28+
headers: {
29+
'x-api-key': PET_TYPE_TO_API_KEY_MAP[this.petType],
30+
},
31+
})
32+
33+
return {
34+
fetchImages: ({ limit }: ImageApiSearchParams) =>
35+
baseApiClient
36+
.get('v1/images/search', {
37+
searchParams: {
38+
limit,
39+
},
40+
})
41+
.json(),
42+
}
43+
}
44+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './PetImageApiClientFactory'
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import { useShallow } from 'zustand/shallow'
22

33
import { useGameSettingsState } from './state'
4+
import { GameSettings } from './types'
5+
import { PetImageApiClientFactory } from '../infrastructure'
46

5-
export const useGameSettings = () =>
7+
export const useGameSettings = (): GameSettings =>
68
useGameSettingsState(
7-
useShallow(({ playerCount, cardMatrixSize }) => ({
8-
playerCount,
9-
cardMatrixSize,
10-
})),
9+
useShallow(({ playerCount, cardMatrixSize, petType }) => {
10+
const petImageApiClientFactory = new PetImageApiClientFactory(petType)
11+
12+
return {
13+
playerCount,
14+
cardMatrixSize,
15+
apiClient: petImageApiClientFactory.create(),
16+
}
17+
}),
1118
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './hooks'
2+
export * from './types'
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import { create } from 'zustand'
22

3-
type GameSettingsState = {
3+
import { PetType } from './types'
4+
5+
export type GameSettingsState = {
46
playerCount: number
57
cardMatrixSize: number
8+
petType: PetType
9+
610
setPlayerCount: (players: number) => void
711
setCardMatrixSize: (cards: number) => void
12+
setPetType: (petType: PetType) => void
813
}
914

1015
export const useGameSettingsState = create<GameSettingsState>((set) => ({
1116
playerCount: 1,
1217
cardMatrixSize: 4,
18+
petType: PetType.CATS,
19+
1320
setPlayerCount: (playerCount: number) => set({ playerCount }),
1421
setCardMatrixSize: (cardMatrixSize: number) => set({ cardMatrixSize }),
22+
setPetType: (petType: PetType) => set({ petType }),
1523
}))
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { ImageApiClient } from '@/shared/infrastructure'
2+
3+
import { GameSettingsState } from './state'
4+
5+
export type GameSettings = Pick<
6+
GameSettingsState,
7+
'playerCount' | 'cardMatrixSize'
8+
> & {
9+
apiClient: ImageApiClient
10+
}
11+
12+
export enum PetType {
13+
CATS = 'CATS',
14+
DOGS = 'DOGS',
15+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useShallow } from 'zustand/shallow'
2+
3+
import { Chooser } from '@/shared/ui/Chooser'
4+
5+
import { useGameSettingsState } from '../model/state'
6+
import { PetType } from '../model/types'
7+
8+
const OPTIONS = [
9+
{ option: 'Cats', value: PetType.CATS },
10+
{ option: 'Dogs', value: PetType.DOGS },
11+
]
12+
13+
const PET_TYPE_TO_ICON_MAP = {
14+
[PetType.CATS]: 'i-lucide-cat',
15+
[PetType.DOGS]: 'i-lucide-dog',
16+
}
17+
18+
export const PetTypeSettingsChooser = () => {
19+
const [petType, setPetType] = useGameSettingsState(
20+
useShallow((state) => [state.petType, state.setPetType]),
21+
)
22+
23+
return (
24+
<Chooser
25+
icon={PET_TYPE_TO_ICON_MAP[petType]}
26+
options={OPTIONS}
27+
value={petType}
28+
onChange={setPetType}
29+
/>
30+
)
31+
}

src/modules/game-settings/ui/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './CardMatrixSettingsChooser'
22
export * from './PlayersSettingsChooser'
3+
export * from './PetTypeSettingsChooser'

0 commit comments

Comments
 (0)