Skip to content

Commit 9894107

Browse files
committed
feat: adding calendar and game links
1 parent 9165c3b commit 9894107

File tree

18 files changed

+311
-60
lines changed

18 files changed

+311
-60
lines changed

src/Routes.tsx

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ export const Routes = () => {
2828
const GameDetails = L(lazy(() => import('./pages/Game/Details')))
2929
const GameCrackers = L(lazy(() => import('./pages/Game/Crackers')))
3030
const GamePlatforms = L(lazy(() => import('./pages/Game/Platforms')))
31+
const GameCondition = L(lazy(() => import('./pages/Game/Condition')))
3132
const GamePublishers = L(lazy(() => import('./pages/Game/Publishers')))
3233
const GameCategories = L(lazy(() => import('./pages/Game/Categories')))
3334
const GameDevelopers = L(lazy(() => import('./pages/Game/Developers')))
35+
const GameProtections = L(lazy(() => import('./pages/Game/Protections')))
3436

3537
return useRoutes([
3638
{ path: '/login', element: <Login /> },
@@ -54,26 +56,42 @@ export const Routes = () => {
5456
},
5557
{
5658
path: '/games',
57-
children: [{ index: true, element: <>Games</> }],
59+
children: [
60+
{ index: true, element: <>Games</> },
61+
{ path: 'tags/:tag', element: <GameTags /> },
62+
{ path: 'genres/:genre', element: <GameGenres /> },
63+
{ path: 'cracks/:crack', element: <GameCracks /> },
64+
{ path: 'crackers/:cracker', element: <GameCrackers /> },
65+
{
66+
path: 'platforms/:platform',
67+
element: <GamePlatforms />,
68+
},
69+
{
70+
path: 'categories/:category',
71+
element: <GameCategories />,
72+
},
73+
{
74+
path: 'developers/:developer',
75+
element: <GameDevelopers />,
76+
},
77+
{
78+
path: 'publishers/:publisher',
79+
element: <GamePublishers />,
80+
},
81+
{
82+
path: 'protections/:protection',
83+
element: <GameProtections />,
84+
},
85+
{
86+
path: 'condition/:condition',
87+
element: <GameCondition />,
88+
},
89+
],
5890
},
5991
{
6092
path: 'news',
6193
children: [{ index: true, element: <News /> }],
6294
},
63-
{ path: '/tags/:tag', element: <GameTags /> },
64-
{ path: '/genres/:genre', element: <GameGenres /> },
65-
{ path: '/cracks/:crack', element: <GameCracks /> },
66-
{ path: '/crackers/:cracker', element: <GameCrackers /> },
67-
{ path: '/platforms/:platform', element: <GamePlatforms /> },
68-
{ path: '/categories/:category', element: <GameCategories /> },
69-
{
70-
path: '/developers/:developer',
71-
element: <GameDevelopers />,
72-
},
73-
{
74-
path: '/publishers/:publisher',
75-
element: <GamePublishers />,
76-
},
7795
],
7896
},
7997
],

src/components/GameCard/GameCard.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('GameCard Component', () => {
7878
name: genre.name,
7979
})
8080

81-
expect(genreLink).toHaveAttribute('href', `/genres/${genre.slug}`)
81+
expect(genreLink).toHaveAttribute('href', `/games/genres/${genre.slug}`)
8282
})
8383
})
8484

@@ -100,7 +100,7 @@ describe('GameCard Component', () => {
100100

101101
expect(platformLink).toHaveAttribute(
102102
'href',
103-
`/platforms/${platform.slug}`,
103+
`/games/platforms/${platform.slug}`,
104104
)
105105
})
106106
})

src/components/GameCard/GameCard.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ function GameCard(props: GameCardProps) {
7474
<Link href={`/games/${game.slug}`}>
7575
<Typography
7676
variant="h6"
77-
className="text-lg font-bold text-white hover:text-theme-red-900 transition duration-500">
77+
className="text-lg font-bold text-white transition-all duration-300 ease-in-out hover:bg-gradient-to-r hover:from-white hover:to-red-600 hover:bg-clip-text hover:text-transparent">
7878
{game.title}
7979
</Typography>
8080
</Link>
@@ -122,7 +122,7 @@ function GameCard(props: GameCardProps) {
122122
<Box className="grid xl:grid-cols-3 lg:grid-cols-2 md:grid-cols-2 grid-cols-1 items-center my-2 sm:gap-1 gap-2 w-full">
123123
{game.platforms.map((platform) => (
124124
<Link
125-
href={`/platforms/${platform.slug}`}
125+
href={`/games/platforms/${platform.slug}`}
126126
className="dark:bg-gray-800 dark:hover:bg-gray-700 hover:bg-gray-400 bg-gray-300 dark:text-white text-black px-3 py-1 rounded-full sm:w-auto w-full text-center transition-colors duration-300"
127127
key={platform.id}>
128128
<Typography
@@ -138,7 +138,7 @@ function GameCard(props: GameCardProps) {
138138

139139
<Box className="flex flex-wrap gap-2 my-2 w-full mt-auto">
140140
{game.genres.map((genre) => (
141-
<Link href={`/genres/${genre.slug}`} key={genre.id}>
141+
<Link href={`/games/genres/${genre.slug}`} key={genre.id}>
142142
<Chip
143143
className="font-bold border border-theme-red-900 dark:text-gray-300 text-gray-700 sm:w-auto w-full hover:bg-theme-red-900 hover:text-white hover:border-none hover:outline-none"
144144
label={genre.name}
@@ -163,8 +163,13 @@ function GameCard(props: GameCardProps) {
163163
</Typography>
164164
<Typography
165165
variant="body2"
166-
className="font-bold dark:text-white text-gray-800 hover:text-theme-red-900 transition-all duration-300">
167-
{game.crack.by.name}
166+
className="font-bold dark:text-white text-gray-800">
167+
<Link
168+
href={`/crackers/${game.crack.by.slug}`}
169+
className="hover:text-theme-red-900 transition-colors duration-300"
170+
target="_blank">
171+
{game.crack.by.name}
172+
</Link>
168173
</Typography>
169174
</Box>
170175
)}
@@ -178,8 +183,13 @@ function GameCard(props: GameCardProps) {
178183
</Typography>
179184
<Typography
180185
variant="body2"
181-
className="font-bold dark:text-white text-gray-800 hover:text-theme-red-900 transition-all duration-300">
182-
{game.crack.protection.name}
186+
className="font-bold dark:text-white text-gray-800">
187+
<Link
188+
href={`/games/protections/${game.crack.protection.slug}`}
189+
className="hover:text-theme-red-900 transition-colors duration-300"
190+
target="_blank">
191+
{game.crack.protection.name}
192+
</Link>
183193
</Typography>
184194
</Box>
185195
)}

src/components/Header/modules/HeaderCarousel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function HeaderCarousel(props: HeaderCarouselProps) {
6868
component="span"
6969
className="bg-gray-800 px-3 py-1 rounded-full text-sm"
7070
key={id}>
71-
<Link href={`/platforms/${slug}`}>{name}</Link>
71+
<Link href={`/games/platforms/${slug}`}>{name}</Link>
7272
</Box>
7373
))}
7474
</Box>
@@ -78,7 +78,7 @@ function HeaderCarousel(props: HeaderCarouselProps) {
7878
component="span"
7979
className="bg-gray-700 px-3 py-1 rounded-full text-sm"
8080
key={id}>
81-
<Link href={`/genres/${slug}`}>{name}</Link>
81+
<Link href={`/games/genres/${slug}`}>{name}</Link>
8282
</Box>
8383
))}
8484
</Box>

src/components/HeartButton/HeartButton.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ function HeartButton(props: HeartButtonProps) {
8282
<IoHeartOutline
8383
size={size}
8484
className={
85-
hearted ? 'text-theme-red-900 animate-pulse' : 'text-white'
85+
hearted
86+
? 'text-theme-red-900 animate-pulse'
87+
: 'dark:text-white text-black'
8688
}
8789
/>
8890
</IconButton>

src/hooks/useGames.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function useGames(params: {
2323
developer?: string
2424
publisher?: string
2525
crack?: string
26+
protection?: string
2627
}) {
2728
const [trigger, { games, isLoading }] = useLazyFindGamesByQuery({
2829
selectFromResult: ({ data = [], isLoading, isFetching }) => ({
@@ -48,7 +49,7 @@ function useGames(params: {
4849
)
4950

5051
const fetchGames = async () => {
51-
const sortedGames = displayedGames.sort((a, b) => {
52+
const sortedGames = [...displayedGames].sort((a, b) => {
5253
const aValue = a[sort.field]
5354
const bValue = b[sort.field]
5455

@@ -93,6 +94,7 @@ function useGames(params: {
9394
{ by: 'categories', filterable: memoizedParams.category },
9495
{ by: 'developers', filterable: memoizedParams.developer },
9596
{ by: 'publishers', filterable: memoizedParams.publisher },
97+
{ by: 'protections', filterable: memoizedParams.protection },
9698
]
9799

98100
filters.forEach((filter) => {

src/pages/Calendar/Calendar.tsx

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import {
22
Box,
33
Chip,
4+
CircularProgress,
45
Tooltip,
56
Typography,
67
useMediaQuery,
78
} from '@mui/material'
89
import { format, isSameDay, parseISO } from 'date-fns'
910
import { useNavigate } from 'react-router-dom'
1011

12+
import { Icon } from '@/components'
1113
import { useTheme } from '@/hooks'
12-
import { MOCK_UPCOMING_GAMES } from '@/mocks'
14+
import { useCalendarGamesQuery } from '@/services/api'
1315

1416
import { StyledCalendar, StyledCalendarLight } from './Calendar.styles'
1517
import { UpcomingList } from './modules'
@@ -23,10 +25,15 @@ interface CalendarTileProperties {
2325
}
2426

2527
function Calendar() {
26-
const games = MOCK_UPCOMING_GAMES
2728
const mode = useTheme()
2829
const go = useNavigate()
2930
const isMobile = useMediaQuery('(max-width: 490px)')
31+
const { games, isLoading } = useCalendarGamesQuery(undefined, {
32+
selectFromResult: ({ data = [], isLoading, isFetching }) => ({
33+
games: data,
34+
isLoading: isLoading || isFetching,
35+
}),
36+
})
3037

3138
const getTileContent = ({ date, view }: CalendarTileProperties) => {
3239
const appointment = games.filter((game) =>
@@ -44,6 +51,7 @@ function Calendar() {
4451
disableInteractive
4552
key={item.id}>
4653
<Chip
54+
className="group"
4755
onClick={() => go(`/games/${item.slug}`)}
4856
sx={{
4957
width: 'auto',
@@ -55,15 +63,40 @@ function Calendar() {
5563
color: ({ palette }) => palette.primary.contrastText,
5664
},
5765
}}
58-
label={item.title}
66+
label={
67+
<Box className="flex items-center gap-1">
68+
{item.title}
69+
{item.crack &&
70+
['cracked', 'cracked-oneday'].includes(
71+
item.crack.status,
72+
) && (
73+
<Tooltip title="Crack is available" arrow>
74+
<span>
75+
<Icon
76+
name="IoCheckmarkCircleOutline"
77+
className="group-hover:text-green-600 text-green-400 mb-0.5"
78+
size={14}
79+
/>
80+
</span>
81+
</Tooltip>
82+
)}
83+
</Box>
84+
}
5985
/>
6086
</Tooltip>
6187
))}
6288
</Box>
6389
)
6490
}
6591

66-
return (
92+
return isLoading ? (
93+
<Box className="py-24">
94+
<CircularProgress
95+
color="error"
96+
className="m-auto flex justify-center"
97+
/>
98+
</Box>
99+
) : (
67100
<Box className={!isMobile ? 'p-12' : 'p-8'}>
68101
{!isMobile ? (
69102
mode === 'dark' ? (

src/pages/Game/Categories.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useState } from 'react'
22
import { useParams } from 'react-router-dom'
33

4-
import { LoadingScreen } from '@/components'
54
import { useGames } from '@/hooks'
65

76
import ModuledFilters from './ModuledFilters'
@@ -17,7 +16,6 @@ function Categories() {
1716
currentPage,
1817
pageSize,
1918
sort,
20-
isLoading,
2119
handlePageChange,
2220
handleSortChange,
2321
handlePageSizeChange,
@@ -33,9 +31,7 @@ function Categories() {
3331
}, 500)
3432
}
3533

36-
return isLoading ? (
37-
<LoadingScreen />
38-
) : (
34+
return (
3935
<ModuledFilters
4036
games={games}
4137
totalGames={totalGames}

0 commit comments

Comments
 (0)