feat: allow to set country

This commit is contained in:
Alexander Medvedev 2026-07-08 10:47:16 +02:00
parent b65b88c804
commit 7ab986fb5a
4 changed files with 413 additions and 357 deletions

693
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,13 @@
"dependencies": { "dependencies": {
"@marsidev/react-turnstile": "^1.5.3", "@marsidev/react-turnstile": "^1.5.3",
"@vnedyalk0v/react19-simple-maps": "^2.0.9", "@vnedyalk0v/react19-simple-maps": "^2.0.9",
"axios": "^1.17.0", "axios": "^1.18.1",
"country-list": "^2.4.1",
"d3-geo": "^3.1.1", "d3-geo": "^3.1.1",
"d3-scale": "^4.0.2", "d3-scale": "^4.0.2",
"i18next": "^26.3.1", "i18next": "^26.3.4",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"lucide-react": "^1.17.0", "lucide-react": "^1.23.0",
"or": "^0.2.0", "or": "^0.2.0",
"qrcode.react": "^4.2.0", "qrcode.react": "^4.2.0",
"react": "^19.2.7", "react": "^19.2.7",
@ -26,25 +27,26 @@
"react-i18next": "^17.0.8", "react-i18next": "^17.0.8",
"react-is": "^19.2.7", "react-is": "^19.2.7",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-router-dom": "^7.17.0", "react-router-dom": "^7.18.1",
"recharts": "^3.8.1", "recharts": "^3.9.2",
"remark-gfm": "^4.0.1" "remark-gfm": "^4.0.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@types/node": "^25.9.3", "@types/country-list": "^2.1.4",
"@types/node": "^26.1.1",
"@types/react": "^19.2.17", "@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.2", "@vitejs/plugin-react": "^6.0.3",
"eslint": "^10.4.1", "eslint": "^10.6.0",
"eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint-plugin-react-refresh": "^0.5.3",
"globals": "^17.6.0", "globals": "^17.7.0",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.61.0", "typescript-eslint": "^8.63.0",
"vite": "^8.0.16" "vite": "^8.1.3"
}, },
"overrides": { "overrides": {
"vite": "^8.0.16" "vite": "^8.1.3"
} }
} }

View File

@ -3,6 +3,7 @@ import { useNavigate, useLocation, Link } from 'react-router-dom';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import api from '../api'; import api from '../api';
import { useAuth } from '../App'; import { useAuth } from '../App';
import { getNames } from 'country-list';
interface LibraryEntry { interface LibraryEntry {
plugin_id: number; plugin_id: number;
@ -31,7 +32,7 @@ const ProfilePage = () => {
else setActiveTab('accountDetails'); else setActiveTab('accountDetails');
}, [location]); }, [location]);
const [formData, setFormData] = useState({ username: '', email: '', password: '', currentPassword: '', disable2faPassword: '' }); const [formData, setFormData] = useState({ username: '', email: '', country: '', password: '', currentPassword: '', disable2faPassword: '' });
const [message, setMessage] = useState({ text: '', type: '' }); const [message, setMessage] = useState({ text: '', type: '' });
const [isStripeLoading, setIsStripeLoading] = useState(false); const [isStripeLoading, setIsStripeLoading] = useState(false);
@ -49,7 +50,7 @@ const ProfilePage = () => {
useEffect(() => { useEffect(() => {
if (user) { if (user) {
setFormData(prev => ({ ...prev, username: user.username || '', email: user.email || '' })); setFormData(prev => ({ ...prev, username: user.username || '', email: user.email || '', country: user.country || '' }));
setIs2faEnabled(user.totp_enabled || false); setIs2faEnabled(user.totp_enabled || false);
} }
}, [user]); }, [user]);
@ -213,6 +214,49 @@ const ProfilePage = () => {
</div> </div>
<button type="submit" className="btn">Update Email</button> <button type="submit" className="btn">Update Email</button>
</form> </form>
<form onSubmit={(e) => {
if (!formData.country) {
e.preventDefault();
showMessage('Please select a country', true);
return;
}
handleUpdate(e, '/user/change-country', { newCountry: formData.country });
}} style={{ marginTop: '2rem' }}>
<div className="form-group">
<label>COUNTRY</label>
<p style={{ fontSize: '0.85rem', color: 'var(--text-muted)', margin: '0.5rem 0', fontStyle: 'italic' }}>
Auto-detected from your IP address during registration. You can change it here.
</p>
<select
value={formData.country}
onChange={e => setFormData({ ...formData, country: e.target.value })}
required
style={{
width: '100%',
padding: '12px 15px',
borderRadius: '8px',
border: '1px solid var(--border)',
background: 'var(--bg)',
color: 'var(--text)',
fontSize: '1rem',
outline: 'none',
transition: 'border-color 0.2s',
cursor: 'pointer',
marginTop: '0.5rem',
}}
onFocus={(e) => e.target.style.borderColor = 'var(--primary)'}
onBlur={(e) => e.target.style.borderColor = 'var(--border)'}>
<option value="">Select a country</option>
{Object.entries(getNames()).map(([code, name]) => (
<option key={code} value={code}>
{name}
</option>
))}
</select>
</div>
<button type="submit" className="btn">Update Country</button>
</form>
</div> </div>
)} )}

View File

@ -1,4 +1,3 @@
import React from 'react';
import './LegalPages.css'; import './LegalPages.css';
const GuidelinesPage = () => { const GuidelinesPage = () => {