Skip to content

Commit 499a9aa

Browse files
authored
Merge pull request #1179 from PaiJi/style/player-search-button
style(players): improve search button style in disabled and loading state
2 parents f3aac92 + 6436ed8 commit 499a9aa

File tree

2 files changed

+78
-31
lines changed

2 files changed

+78
-31
lines changed

src/pages/players/index.css

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
.search-button {
22
padding: .2rem;
33
border-radius: 4px;
4+
cursor: pointer;
45
}
56

67
.search-button:disabled {
7-
background-color: var(--color-gold-two);
8-
color: var(--color-gray);
8+
opacity: 0.5;
9+
position: relative;
10+
cursor: not-allowed;
11+
}
12+
13+
.search-button:disabled::before {
14+
content: '';
15+
position: absolute;
16+
top: 0;
17+
left: 0;
18+
right: 0;
19+
bottom: 0;
20+
background-color: rgba(0, 0, 0, 0.3);
21+
border-radius: 4px;
22+
pointer-events: none;
923
}
1024

1125
.search-controls {

src/pages/players/index.js

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
22
import { useSelector } from 'react-redux';
33
import { Link, useSearchParams } from 'react-router-dom';
44
import { Trans, useTranslation } from 'react-i18next';
5-
import { Turnstile } from '@marsidev/react-turnstile'
5+
import { Turnstile } from '@marsidev/react-turnstile';
66
import Select from 'react-select';
77
import { Icon } from '@mdi/react';
88
import { mdiAccountSearch } from '@mdi/js';
99

10+
import LoadingSmall from '../../components/loading-small/index.js';
11+
1012
import useKeyPress from '../../hooks/useKeyPress.jsx';
1113

1214
import SEO from '../../components/SEO.jsx';
@@ -18,7 +20,7 @@ import gameModes from '../../data/game-modes.json';
1820
import './index.css';
1921

2022
function Players() {
21-
const [ searchParams, setSearchParams ] = useSearchParams();
23+
const [searchParams, setSearchParams] = useSearchParams();
2224
const turnstileRef = useRef();
2325
const turnstileToken = useRef(false);
2426

@@ -30,23 +32,26 @@ function Players() {
3032
const defaultGameMode = useMemo(() => {
3133
return searchParams.get('gameMode') ?? gameModeSetting;
3234
}, [searchParams, gameModeSetting]);
33-
const [ gameMode, setGameMode ] = useState(defaultGameMode);
34-
const lastSearch = useRef({name: '', gameMode});
35+
const [gameMode, setGameMode] = useState(defaultGameMode);
36+
const lastSearch = useRef({ name: '', gameMode });
3537

3638
const [nameFilter, setNameFilter] = useState('');
3739
const [nameResults, setNameResults] = useState([]);
3840
const [nameResultsError, setNameResultsError] = useState(false);
3941

4042
const [isButtonDisabled, setButtonDisabled] = useState(true);
4143
const [searched, setSearched] = useState(false);
44+
const [searching, setSearching] = useState(false);
4245
const [tokenState, setTokenState] = useState(false);
4346

4447
const searchTextValid = useMemo(() => {
4548
const charactersValid = !!nameFilter.match(/^[a-zA-Z0-9-_]*$/);
4649
const lengthValid = !!nameFilter.match(/^[a-zA-Z0-9-_]{3,15}$|^TarkovCitizen\d{1,10}$/i);
4750
setNameResultsError(false);
4851
if (!charactersValid) {
49-
setNameResultsError(`Names can only contain letters, numbers, dashes (-), and underscores (_)`);
52+
setNameResultsError(
53+
`Names can only contain letters, numbers, dashes (-), and underscores (_)`,
54+
);
5055
}
5156
return charactersValid && lengthValid;
5257
}, [nameFilter, setNameResultsError]);
@@ -75,8 +80,13 @@ function Players() {
7580
return;
7681
}
7782
try {
83+
setSearching(true);
7884
setNameResultsError(false);
79-
setNameResults((await playerStats.searchPlayers(nameFilter, gameMode, turnstileToken.current)).sort((a, b) => a.name.localeCompare(b.name)));
85+
setNameResults(
86+
(
87+
await playerStats.searchPlayers(nameFilter, gameMode, turnstileToken.current)
88+
).sort((a, b) => a.name.localeCompare(b.name)),
89+
);
8090
setSearched(true);
8191
lastSearch.current.name = nameFilter;
8292
lastSearch.current.gameMode = gameMode;
@@ -85,12 +95,22 @@ function Players() {
8595
lastSearch.current.name = '';
8696
setNameResults([]);
8797
setNameResultsError(error.message);
98+
} finally {
99+
setSearching(false);
88100
}
89101
setTokenState(false);
90102
if (turnstileRef.current?.reset) {
91103
turnstileRef.current.reset();
92104
}
93-
}, [nameFilter, searchTextValid, setNameResults, setNameResultsError, turnstileToken, turnstileRef, gameMode]);
105+
}, [
106+
nameFilter,
107+
searchTextValid,
108+
setNameResults,
109+
setNameResultsError,
110+
turnstileToken,
111+
turnstileRef,
112+
gameMode,
113+
]);
94114

95115
const searchResults = useMemo(() => {
96116
if (!searched) {
@@ -101,18 +121,18 @@ function Players() {
101121
}
102122
let morePlayers = '';
103123
if (nameResults.length >= 5) {
104-
morePlayers = <p>{t('Refine your search to get better results')}</p>
124+
morePlayers = <p>{t('Refine your search to get better results')}</p>;
105125
}
106126
return (
107127
<div>
108128
{morePlayers}
109129
<ul className="name-results-list">
110-
{nameResults.map(result => {
111-
return <li key={`account-${result.aid}`}>
112-
<Link to={`/players/${gameMode}/${result.aid}`}>
113-
{result.name}
114-
</Link>
115-
</li>
130+
{nameResults.map((result) => {
131+
return (
132+
<li key={`account-${result.aid}`}>
133+
<Link to={`/players/${gameMode}/${result.aid}`}>{result.name}</Link>
134+
</li>
135+
);
116136
})}
117137
</ul>
118138
</div>
@@ -128,7 +148,10 @@ function Players() {
128148
return [
129149
<SEO
130150
title={`${t('Players')} - ${t('Escape from Tarkov')} - ${t('Tarkov.dev')}`}
131-
description={t('players-page-description', 'Search Escape from Tarkov players. View player profiles and see their stats.')}
151+
description={t(
152+
'players-page-description',
153+
'Search Escape from Tarkov players. View player profiles and see their stats.',
154+
)}
132155
key="seo-wrapper"
133156
/>,
134157
<div className={'page-wrapper'} key="players-page-wrapper">
@@ -140,35 +163,37 @@ function Players() {
140163
</div>
141164
<div>
142165
<Trans i18nKey={'players-page-p'}>
143-
<p>
144-
Search for Escape From Tarkov players and view their profiles.
145-
</p>
166+
<p>Search for Escape From Tarkov players and view their profiles.</p>
146167
</Trans>
147168
</div>
148-
<label className={'single-filter-wrapper'} style={{marginBottom: '1em'}}>
169+
<label className={'single-filter-wrapper'} style={{ marginBottom: '1em' }}>
149170
<span className={'single-filter-label'}>{t('Game mode')}</span>
150171
<Select
151172
label={t('Game mode')}
152173
placeholder={t(`game_mode_${defaultGameMode}`)}
153174
defaultValue={defaultGameMode}
154-
options={gameModes.map(m => {
175+
options={gameModes.map((m) => {
155176
return {
156177
label: t(`game_mode_${m}`),
157178
value: m,
158-
}
179+
};
159180
})}
160181
className="basic-multi-select game-mode"
161182
classNamePrefix="select"
162183
onChange={(event) => {
163-
setSearchParams({gameMode: event.value});
164-
if (searchTextValid && gameMode !== event.value && !!turnstileToken.current) {
184+
setSearchParams({ gameMode: event.value });
185+
if (
186+
searchTextValid &&
187+
gameMode !== event.value &&
188+
!!turnstileToken.current
189+
) {
165190
setButtonDisabled(false);
166191
}
167192
setGameMode(event.value);
168193
}}
169194
/>
170195
</label>
171-
<div className='search-controls'>
196+
<div className="search-controls">
172197
<InputFilter
173198
label={t('Player Name')}
174199
defaultValue={nameFilter}
@@ -180,31 +205,39 @@ function Players() {
180205
}}
181206
className="player-name-search"
182207
/>
183-
<button className="search-button" onClick={searchForName} disabled={isButtonDisabled}>{t('Search')}</button>
208+
<button
209+
className="search-button"
210+
onClick={searchForName}
211+
disabled={isButtonDisabled}
212+
>
213+
{searching ? <LoadingSmall /> : t('Search')}
214+
</button>
184215
</div>
185216
{!!nameResultsError && (
186217
<div>
187218
<p className="error">{nameResultsError}</p>
188219
</div>
189220
)}
190-
<Turnstile
221+
<Turnstile
191222
ref={turnstileRef}
192223
className="turnstile-widget"
193-
siteKey='0x4AAAAAAAVVIHGZCr2PPwrR'
224+
siteKey="0x4AAAAAAAVVIHGZCr2PPwrR"
194225
onSuccess={(token) => {
195226
setTokenState(token);
196227
}}
197228
onError={(errorCode) => {
198229
// https://developers.cloudflare.com/turnstile/reference/client-side-errors#error-codes
199230
if (errorCode === '110200') {
200-
setNameResultsError(`Turnstile error: ${window.location.hostname} is not a valid hostname`);
231+
setNameResultsError(
232+
`Turnstile error: ${window.location.hostname} is not a valid hostname`,
233+
);
201234
} else if (errorCode.startsWith('600')) {
202235
setNameResultsError('Turnstile challenge failed');
203236
} else {
204237
setNameResultsError(`Turnstile error code ${errorCode}`);
205238
}
206239
}}
207-
options={{appearance: 'interaction-only'}}
240+
options={{ appearance: 'interaction-only' }}
208241
/>
209242
{!nameResultsError && searchResults}
210243
</div>,

0 commit comments

Comments
 (0)