feat: Add favicon display functionality in BillingManager for improved visual identification of providers
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m41s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m41s
This commit is contained in:
@@ -325,6 +325,30 @@ function BillingManager() {
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
||||
|
||||
// Favicon для провайдера по ссылке входа
|
||||
function normalizeToUrl(value) {
|
||||
if (!value) return '';
|
||||
try {
|
||||
const hasProtocol = /^https?:\/\//i.test(value);
|
||||
const url = new URL(hasProtocol ? value : `https://${value}`);
|
||||
return url.toString();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getFaviconUrl(loginUrl) {
|
||||
const normalized = normalizeToUrl(loginUrl);
|
||||
if (!normalized) return '';
|
||||
try {
|
||||
const { hostname } = new URL(normalized);
|
||||
// DuckDuckGo Icons API: быстрая выдача favicon по домену
|
||||
return `https://icons.duckduckgo.com/ip3/${hostname}.ico`;
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getCountryFlag(countryRaw) {
|
||||
if (!countryRaw) return '';
|
||||
const value = String(countryRaw).trim();
|
||||
@@ -717,9 +741,19 @@ function BillingManager() {
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span className="badge bg-green-lt text-green">
|
||||
{item.provider}
|
||||
</span>
|
||||
<div className="d-flex align-items-center gap-2">
|
||||
{item.loginUrl && (
|
||||
<img
|
||||
src={getFaviconUrl(item.loginUrl)}
|
||||
alt=""
|
||||
width="16"
|
||||
height="16"
|
||||
style={{ borderRadius: 3 }}
|
||||
onError={(e) => { e.currentTarget.style.display = 'none'; }}
|
||||
/>
|
||||
)}
|
||||
<span className="badge bg-green-lt text-green">{item.provider}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="fw-bold">
|
||||
@@ -880,7 +914,19 @@ function BillingManager() {
|
||||
<tr key={r._key}>
|
||||
<td>
|
||||
<div className="fw-bold">{r.server.hostName}</div>
|
||||
<div className="text-muted small">{r.server.provider}</div>
|
||||
<div className="text-muted small d-flex align-items-center gap-2">
|
||||
{r.server.loginUrl && (
|
||||
<img
|
||||
src={getFaviconUrl(r.server.loginUrl)}
|
||||
alt=""
|
||||
width="14"
|
||||
height="14"
|
||||
style={{ borderRadius: 3 }}
|
||||
onError={(e) => { e.currentTarget.style.display = 'none'; }}
|
||||
/>
|
||||
)}
|
||||
<span>{r.server.provider}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{formatDate(r.date)}</td>
|
||||
<td>
|
||||
@@ -1318,42 +1364,8 @@ function EditBillingModal({ show, item, onItemChange, onSubmit, onClose }) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Исторические платежи */}
|
||||
<div className="col-12">
|
||||
<h6 className="text-muted mb-3 mt-4">Исторические платежи</h6>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<label className="form-label">Дата последнего платежа</label>
|
||||
<input
|
||||
type="date"
|
||||
className="form-control"
|
||||
value={item.lastPaymentDate || ''}
|
||||
onChange={(e) => onItemChange({ ...item, lastPaymentDate: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<label className="form-label">Сумма последнего платежа</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
className="form-control"
|
||||
value={item.lastPaymentAmount || 0}
|
||||
onChange={(e) => onItemChange({ ...item, lastPaymentAmount: parseFloat(e.target.value) || 0 })}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<label className="form-label">Валюта последнего платежа</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={item.lastPaymentCurrency || 'USD'}
|
||||
onChange={(e) => onItemChange({ ...item, lastPaymentCurrency: e.target.value })}
|
||||
>
|
||||
<option value="USD">USD</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="RUB">RUB</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
{/* Дополнительно */}
|
||||
<div className="col-md-12">
|
||||
<label className="form-label">Заметки</label>
|
||||
<input
|
||||
type="text"
|
||||
|
||||
Reference in New Issue
Block a user