feat: Add country flag display functionality in BillingManager for improved user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m47s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m47s
This commit is contained in:
@@ -314,6 +314,66 @@ function BillingManager() {
|
||||
return purposeMap[purpose] || purpose || 'Не указано';
|
||||
}
|
||||
|
||||
// Флаги стран (эмодзи) по коду/названию
|
||||
function countryCodeToFlag(isoCode) {
|
||||
if (!isoCode || isoCode.length !== 2) return '';
|
||||
const codePoints = isoCode
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.map(char => 127397 + char.charCodeAt(0));
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
||||
|
||||
function getCountryFlag(countryRaw) {
|
||||
if (!countryRaw) return '';
|
||||
const value = String(countryRaw).trim();
|
||||
if (!value) return '';
|
||||
const upper = value.toUpperCase();
|
||||
// Если уже ISO-2
|
||||
if (/^[A-Z]{2}$/.test(upper)) {
|
||||
return countryCodeToFlag(upper);
|
||||
}
|
||||
// Маппинг распространённых названий -> ISO-2
|
||||
const mapNameToCode = {
|
||||
// RU
|
||||
'RUSSIA': 'RU', 'RUSSIAN FEDERATION': 'RU', 'РОССИЯ': 'RU',
|
||||
// US
|
||||
'USA': 'US', 'UNITED STATES': 'US', 'США': 'US', 'СОЕДИНЕННЫЕ ШТАТЫ': 'US',
|
||||
// DE
|
||||
'GERMANY': 'DE', 'DEUTSCHLAND': 'DE', 'ГЕРМАНИЯ': 'DE',
|
||||
// NL
|
||||
'NETHERLANDS': 'NL', 'NEDERLAND': 'NL', 'НИДЕРЛАНДЫ': 'NL',
|
||||
// FR
|
||||
'FRANCE': 'FR', 'ФРАНЦИЯ': 'FR',
|
||||
// GB
|
||||
'UNITED KINGDOM': 'GB', 'UK': 'GB', 'ВЕЛИКОБРИТАНИЯ': 'GB',
|
||||
// SG
|
||||
'SINGAPORE': 'SG', 'СИНГАПУР': 'SG',
|
||||
// PL
|
||||
'POLAND': 'PL', 'ПОЛЬША': 'PL',
|
||||
// ES
|
||||
'SPAIN': 'ES', 'ИСПАНИЯ': 'ES',
|
||||
// IT
|
||||
'ITALY': 'IT', 'ИТАЛИЯ': 'IT',
|
||||
// TR
|
||||
'TURKEY': 'TR', 'ТУРЦИЯ': 'TR',
|
||||
// KZ
|
||||
'KAZAKHSTAN': 'KZ', 'КАЗАХСТАН': 'KZ',
|
||||
// LT, LV, EE, CZ, UA, BY, SE, FI, CA
|
||||
'LITHUANIA': 'LT', 'ЛИТВА': 'LT',
|
||||
'LATVIA': 'LV', 'ЛАТВИЯ': 'LV',
|
||||
'ESTONIA': 'EE', 'ЭСТОНИЯ': 'EE',
|
||||
'CZECHIA': 'CZ', 'CZECH REPUBLIC': 'CZ', 'ЧЕХИЯ': 'CZ',
|
||||
'UKRAINE': 'UA', 'УКРАИНА': 'UA',
|
||||
'BELARUS': 'BY', 'БЕЛАРУСЬ': 'BY',
|
||||
'SWEDEN': 'SE', 'ШВЕЦИЯ': 'SE',
|
||||
'FINLAND': 'FI', 'ФИНЛЯНДИЯ': 'FI',
|
||||
'CANADA': 'CA', 'КАНАДА': 'CA',
|
||||
};
|
||||
const code = mapNameToCode[upper];
|
||||
return code ? countryCodeToFlag(code) : '';
|
||||
}
|
||||
|
||||
// Экспорт данных
|
||||
const exportData = () => {
|
||||
const csvContent = [
|
||||
@@ -542,7 +602,7 @@ function BillingManager() {
|
||||
<h3 className="card-title">Оплачиваемые ноды</h3>
|
||||
<div className="card-actions">
|
||||
<button
|
||||
className="btn btn-primary btn-sm"
|
||||
className="btn btn-primary"
|
||||
onClick={handleSaveChanges}
|
||||
disabled={loading}
|
||||
>
|
||||
@@ -650,8 +710,9 @@ function BillingManager() {
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div className="d-flex align-items-center">
|
||||
{item.country}
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
<span style={{ fontSize: '18px' }}>{getCountryFlag(item.country)}</span>
|
||||
<span>{item.country}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@@ -697,14 +758,14 @@ function BillingManager() {
|
||||
<td>
|
||||
<div className="btn-list">
|
||||
<button
|
||||
className="btn btn-sm btn-outline-primary"
|
||||
className="btn btn-outline-primary btn-icon"
|
||||
onClick={() => handleEditItem(item)}
|
||||
title="Редактировать"
|
||||
>
|
||||
<IconEdit size={14} />
|
||||
<IconEdit size={18} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-outline-success"
|
||||
className="btn btn-outline-success btn-icon"
|
||||
onClick={() => {
|
||||
setPaymentDraft({
|
||||
serverId: item.id,
|
||||
@@ -717,14 +778,14 @@ function BillingManager() {
|
||||
}}
|
||||
title="Добавить платеж"
|
||||
>
|
||||
<IconPlus size={14} />
|
||||
<IconPlus size={18} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-outline-danger"
|
||||
className="btn btn-outline-danger btn-icon"
|
||||
onClick={() => handleDeleteItem(item)}
|
||||
title="Удалить"
|
||||
>
|
||||
<IconTrash size={14} />
|
||||
<IconTrash size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
@@ -786,8 +847,8 @@ function BillingManager() {
|
||||
История платежей
|
||||
</h3>
|
||||
<div className="card-actions">
|
||||
<button
|
||||
className="btn btn-outline-primary btn-sm"
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
onClick={() => { setPaymentDraft({ serverId: '', date: '', amount: 0, currency: 'USD', note: '' }); setShowPaymentModal(true); }}
|
||||
>
|
||||
<IconPlus size={16} />
|
||||
|
||||
Reference in New Issue
Block a user