diff --git a/h5/mifa-pay/app.js b/h5/mifa-pay/app.js
index deb1395..8b4f6d6 100644
--- a/h5/mifa-pay/app.js
+++ b/h5/mifa-pay/app.js
@@ -2,7 +2,29 @@ const query = readURLParams();
const storedAppId = window.localStorage.getItem("mifa-pay-application-id") || "";
const API_BASE_URL = "https://jvapi.haiyihy.com";
const LOCAL_API_BASE_URL = "http://127.0.0.1:1100";
-const LOGO_SRC = "./mifapay-logo.png";
+
+const CHANNEL_LOGOS = [
+ ["qris", "./logos/qris.png"],
+ ["dana", "./logos/dana.png"],
+ ["linkaja", "./logos/linkaja.png"],
+ ["ovo", "./logos/ovo.png"],
+ ["shopeepay", "./logos/shopeepay.png"],
+ ["bca", "./logos/bca.png"],
+ ["bni", "./logos/bni.png"],
+ ["permata", "./logos/permata.png"],
+ ["mandiri", "./logos/mandiri.png"],
+ ["bri", "./logos/bri.png"],
+ ["upi", "./logos/upi.png"],
+ ["paytm", "./logos/paytm.png"],
+ ["phonepe", "./logos/phonepe.png"],
+ ["googlepay", "./logos/googlepay.png"],
+ ["bhim", "./logos/bhim.png"],
+ ["mobikwik", "./logos/mobikwik.png"],
+ ["jazzcash", "./logos/jazzcash.png"],
+ ["easypaisa", "./logos/easypaisa.png"],
+ ["vietqr", "./logos/vietqr.png"],
+ ["vnbanktransfer", "./logos/vn-banktransfer.png"],
+];
function readURLParams() {
const result = new URLSearchParams(window.location.search);
@@ -46,8 +68,11 @@ const state = {
regionId: "",
selectedCountryId: "",
commodityCard: null,
+ loading: true,
+ unsupportedRegion: false,
selectedGoodsId: "",
selectedGoods: null,
+ selectedChannelCode: "",
pendingChannelCode: "",
};
@@ -55,6 +80,8 @@ const els = {
applicationId: document.getElementById("applicationId"),
productList: document.getElementById("productList"),
channelList: document.getElementById("channelList"),
+ unsupportedMessage: document.getElementById("unsupportedMessage"),
+ goRecharge: document.getElementById("goRecharge"),
pageStatus: document.getElementById("pageStatus"),
};
@@ -146,7 +173,14 @@ function currentLanguage() {
return query.get("lang") || document.documentElement.lang || navigator.language || "en";
}
+function currentSysOrigin() {
+ return String(state.application?.appCode || query.get("sysOrigin") || query.get("origin") || "LIKEI")
+ .trim()
+ .toUpperCase();
+}
+
function authHeadersFromToken(token) {
+ const sysOrigin = currentSysOrigin();
return {
Accept: "application/json, text/plain, */*",
Authorization: normalizeAuthorization(token),
@@ -155,7 +189,7 @@ function authHeadersFromToken(token) {
"req-version": "V2",
"req-zone": Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai",
"req-app-intel": "version=1.0.0;build=1;model=H5;sysVersion=Web;channel=Web",
- "req-sys-origin": "origin=ATYOU;originChild=ATYOU",
+ "req-sys-origin": `origin=${sysOrigin};originChild=${sysOrigin}`,
};
}
@@ -224,6 +258,23 @@ function extractErrorMessage(error) {
);
}
+function escapeHTML(value) {
+ return String(value ?? "").replace(/[&<>"']/g, (char) => {
+ const entities = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
+ };
+ return entities[char];
+ });
+}
+
+function escapeAttribute(value) {
+ return escapeHTML(value).replace(/`/g, "`");
+}
+
function readStoredUserProfile() {
const raw = window.localStorage.getItem("userProfile");
if (!raw) {
@@ -250,8 +301,16 @@ function currentUserId() {
return String(state.userProfile?.id || "").trim();
}
-function currentCountryId() {
- return state.selectedCountryId;
+function currentCountry() {
+ return (
+ state.countries.find((item) => String(item.id) === String(state.selectedCountryId)) ||
+ null
+ );
+}
+
+function currentPayCountryId() {
+ const selected = currentCountry();
+ return String(selected?.payCountryId || selected?.id || state.selectedCountryId || "");
}
function currentRegionId() {
@@ -282,22 +341,230 @@ function getGoodsList() {
return state.commodityCard?.commodity || [];
}
-function getChannelList() {
+function getAllChannelList() {
return state.commodityCard?.channels || [];
}
+function toNumber(value, fallback = 0) {
+ const number = Number(value);
+ return Number.isFinite(number) ? number : fallback;
+}
+
+function channelSupportsGoods(channel, goods) {
+ if (!goods) {
+ return true;
+ }
+
+ const details = channel?.details || {};
+ const amountUsd = toNumber(goods?.amountUsd || goods?.amount);
+ const min = toNumber(details.factoryMinLimit, 0);
+ const max = toNumber(details.factoryMaxLimit, Number.MAX_SAFE_INTEGER);
+ const daily = toNumber(details.factoryDailyLimit, Number.MAX_SAFE_INTEGER);
+ return amountUsd >= min && amountUsd <= max && amountUsd <= daily;
+}
+
+function getChannelList(goods = state.selectedGoods) {
+ return getAllChannelList().filter((item) => channelSupportsGoods(item, goods));
+}
+
+function goodsHasChannel(goods) {
+ return getChannelList(goods).length > 0;
+}
+
+function hasAvailablePayment() {
+ return getGoodsList().some((goods) => goodsHasChannel(goods));
+}
+
+function setUnsupportedRegion(value) {
+ state.unsupportedRegion = Boolean(value);
+ renderUnsupportedState();
+}
+
+function renderUnsupportedState() {
+ const show = !state.loading && state.unsupportedRegion;
+ els.unsupportedMessage.hidden = !show;
+ els.unsupportedMessage.className = show
+ ? "unsupported-state show"
+ : "unsupported-state";
+ els.productList.hidden = show;
+ els.channelList.hidden = show;
+ if (show) {
+ els.goRecharge.hidden = true;
+ els.productList.innerHTML = "";
+ els.channelList.innerHTML = "";
+ }
+}
+
function getChannelCode(item) {
return item?.details?.channelCode || item?.channel?.channelCode || "";
}
+function getChannelName(item) {
+ return String(
+ item?.channel?.channelName ||
+ item?.details?.factoryChannel ||
+ item?.details?.channelCode ||
+ item?.channel?.channelCode ||
+ "Pay"
+ ).trim();
+}
+
+function normalizeLogoKey(value) {
+ return String(value || "")
+ .trim()
+ .toLowerCase()
+ .replace(/[^a-z0-9]/g, "");
+}
+
+function getChannelLogoCandidates(item) {
+ const values = [
+ item?.channel?.channelCode,
+ item?.details?.channelCode,
+ item?.details?.factoryChannel,
+ item?.channel?.channelName,
+ getChannelName(item),
+ ];
+ const keys = new Set();
+ values.filter(Boolean).forEach((value) => {
+ const text = String(value);
+ const normalized = normalizeLogoKey(text);
+ if (normalized) {
+ keys.add(normalized);
+ }
+ text
+ .split(/[_\s/-]+/)
+ .map(normalizeLogoKey)
+ .filter(Boolean)
+ .forEach((key) => keys.add(key));
+ });
+ return Array.from(keys);
+}
+
+function getLocalChannelIconURL(item) {
+ const candidates = getChannelLogoCandidates(item);
+ const exact = CHANNEL_LOGOS.find(([key]) => candidates.includes(key));
+ if (exact) {
+ return exact[1];
+ }
+
+ const combined = candidates.join(" ");
+ const partial = CHANNEL_LOGOS.find(([key]) => combined.includes(key));
+ return partial?.[1] || "";
+}
+
+function getChannelIconURL(item) {
+ return String(
+ item?.channel?.channelIcon || item?.details?.channelIcon || getLocalChannelIconURL(item)
+ ).trim();
+}
+
+function getChannelAbbr(item) {
+ const candidates = [getChannelCode(item), getChannelName(item)];
+ for (const value of candidates) {
+ const segments = String(value || "")
+ .split(/[_\s/-]+/)
+ .map((segment) => segment.replace(/[^A-Za-z0-9]/g, ""))
+ .filter(Boolean);
+ if (segments.length) {
+ return segments[segments.length - 1].slice(0, 5).toUpperCase();
+ }
+ }
+ return "PAY";
+}
+
+function channelIconHTML(item) {
+ const name = getChannelName(item);
+ const icon = getChannelIconURL(item);
+ if (icon) {
+ return `
`;
+ }
+ return `${escapeHTML(getChannelAbbr(item))}`;
+}
+
function getAmountText(item) {
const content = item?.content || item?.obtainGoldsQuantity || "-";
return `${content} ${item?.type || ""}`.trim();
}
+function currentCurrency(item = null) {
+ return String(
+ item?.currency || state.commodityCard?.payCountry?.currency || currentCountry()?.currency || "USD"
+ )
+ .trim()
+ .toUpperCase();
+}
+
+function formatMoney(value, currency = "") {
+ if (value === null || value === undefined || value === "") {
+ return "-";
+ }
+
+ const number = Number(value);
+ if (!Number.isFinite(number)) {
+ return String(value);
+ }
+
+ const zeroDecimalCurrencies = new Set(["IDR", "JPY", "KRW", "VND"]);
+ const maximumFractionDigits = zeroDecimalCurrencies.has(currency) ? 0 : 2;
+ return number.toLocaleString("en-US", {
+ minimumFractionDigits: 0,
+ maximumFractionDigits,
+ });
+}
+
function getPriceText(item) {
- const currency = item?.currency || state.commodityCard?.payCountry?.currency || "USD";
- return `${item?.amount || item?.amountUsd || "-"} ${currency}`;
+ const currency = currentCurrency(item);
+ return `${currency} ${formatMoney(item?.amount ?? item?.amountUsd, currency)}`;
+}
+
+function getUsdPriceText(item) {
+ return `USD ${formatMoney(item?.amountUsd ?? item?.amount ?? "-", "USD")}`;
+}
+
+function getCountryCodes(item) {
+ const country = item?.country || {};
+ return [
+ item?.countryCode,
+ country?.alphaTwo,
+ country?.alphaThree,
+ ...(Array.isArray(country?.countryCodeAliases) ? country.countryCodeAliases : []),
+ ]
+ .filter(Boolean)
+ .map((value) => String(value).trim().toUpperCase())
+ .filter(Boolean);
+}
+
+function getCountryId(item) {
+ return String(item?.countryId || item?.country?.id || "").trim();
+}
+
+function mergeCompatibleCountries(regionCountries, openCountries) {
+ const compatibleCountryMap = new Map();
+ openCountries.forEach((item) => {
+ const countryId = getCountryId(item);
+ if (countryId && !compatibleCountryMap.has(countryId)) {
+ compatibleCountryMap.set(countryId, item);
+ }
+ });
+
+ return regionCountries.map((item) => {
+ if (item?.payCountryId) {
+ return item;
+ }
+
+ const compatibleCountry = compatibleCountryMap.get(getCountryId(item));
+ if (!compatibleCountry) {
+ return item;
+ }
+
+ return {
+ ...item,
+ payCountryId: compatibleCountry.payCountryId || compatibleCountry.id,
+ currency: item.currency || compatibleCountry.currency,
+ };
+ });
}
function ensureSelectedGoods() {
@@ -312,11 +579,53 @@ function ensureSelectedGoods() {
goods.find((item) => String(item.id) === state.selectedGoodsId) ||
goods.find((item) => item.type === state.productType) ||
goods[0];
- state.selectedGoods = matched;
- state.selectedGoodsId = String(matched.id);
+ const payableGoods = goodsHasChannel(matched)
+ ? matched
+ : goods.find((item) => goodsHasChannel(item)) || matched;
+ state.selectedGoods = payableGoods;
+ state.selectedGoodsId = String(payableGoods.id);
+}
+
+function renderProductLoading() {
+ els.productList.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+ `;
+}
+
+function renderChannelLoading() {
+ els.goRecharge.hidden = true;
+ els.channelList.innerHTML = Array.from({ length: 8 })
+ .map(
+ () => `
+
+
+
+
+ `
+ )
+ .join("");
}
function renderProducts() {
+ if (state.loading) {
+ renderProductLoading();
+ return;
+ }
+
+ if (state.unsupportedRegion) {
+ els.productList.innerHTML = "";
+ return;
+ }
+
const goods = getGoodsList();
ensureSelectedGoods();
@@ -327,21 +636,28 @@ function renderProducts() {
els.productList.innerHTML = goods
.map((item) => {
- const selected = String(item.id) === state.selectedGoodsId;
+ const payable = goodsHasChannel(item);
+ const selected = payable && String(item.id) === state.selectedGoodsId;
+ const amount = item?.content || item?.obtainGoldsQuantity || "-";
+ const type = item?.type || "Recharge";
return `
`;
@@ -355,12 +671,50 @@ function renderProducts() {
state.selectedGoods =
getGoodsList().find((item) => String(item.id) === goodsId) || null;
renderProducts();
+ renderChannels();
});
});
}
+function ensureSelectedChannel(channels) {
+ if (!channels.length) {
+ state.selectedChannelCode = "";
+ return;
+ }
+
+ const selectedExists = channels.some(
+ (item) => String(getChannelCode(item)) === String(state.selectedChannelCode)
+ );
+ if (!selectedExists) {
+ state.selectedChannelCode = getChannelCode(channels[0]);
+ }
+}
+
+function renderGoRecharge(channels = getChannelList()) {
+ const hasSelection = channels.some(
+ (item) => String(getChannelCode(item)) === String(state.selectedChannelCode)
+ );
+ els.goRecharge.hidden = !channels.length;
+ els.goRecharge.disabled = !hasSelection || Boolean(state.pendingChannelCode);
+ els.goRecharge.textContent = state.pendingChannelCode ? "Processing..." : "Go Recharge";
+}
+
function renderChannels() {
+ if (state.loading) {
+ renderChannelLoading();
+ return;
+ }
+
+ if (state.unsupportedRegion) {
+ els.channelList.innerHTML = "";
+ els.goRecharge.hidden = true;
+ return;
+ }
+
const channels = getChannelList();
+ ensureSelectedChannel(channels);
+ renderGoRecharge(channels);
+
if (!channels.length) {
els.channelList.innerHTML = 'No payment method available.
';
return;
@@ -369,46 +723,47 @@ function renderChannels() {
els.channelList.innerHTML = channels
.map((item) => {
const code = getChannelCode(item);
- const pending = state.pendingChannelCode === code;
+ const selected = String(code) === String(state.selectedChannelCode);
+ const name = getChannelName(item);
return `
`;
})
.join("");
els.channelList.querySelectorAll("[data-channel-code]").forEach((button) => {
- button.addEventListener("click", async () => {
+ button.addEventListener("click", () => {
const channelCode = button.getAttribute("data-channel-code");
- try {
- await createOrder(channelCode);
- } catch (error) {
- state.pendingChannelCode = "";
- renderChannels();
- setStatus(extractErrorMessage(error));
- }
+ state.selectedChannelCode = channelCode;
+ setStatus("");
+ renderChannels();
});
});
}
function selectCountryByProfile() {
- const userCountryCode = state.userProfile?.countryCode;
- if (!userCountryCode) {
+ const userCountryCode = String(state.userProfile?.countryCode || "").trim().toUpperCase();
+ const userCountryId = String(state.userProfile?.countryId || "").trim();
+ if (!userCountryCode && !userCountryId) {
return false;
}
- const matched = state.countries.find((item) =>
- getCountryLabel(item).toUpperCase().includes(userCountryCode.toUpperCase())
- );
+ const matched = state.countries.find((item) => {
+ const itemCountryId = getCountryId(item);
+ if (userCountryId && itemCountryId === userCountryId) {
+ return true;
+ }
+ return userCountryCode && getCountryCodes(item).includes(userCountryCode);
+ });
if (!matched) {
return false;
@@ -469,9 +824,18 @@ async function refreshMeta() {
if (!state.countries.length) {
state.selectedCountryId = "";
state.commodityCard = null;
+ state.loading = false;
+ setUnsupportedRegion(true);
renderProducts();
renderChannels();
- throw new Error("No supported country");
+ setStatus("");
+ return;
+ }
+
+ if (state.countries.some((item) => !item?.payCountryId)) {
+ const countryResp = await apiGet("/order/web/pay/country");
+ const openCountries = Array.isArray(countryResp?.body) ? countryResp.body : [];
+ state.countries = mergeCompatibleCountries(state.countries, openCountries);
}
if (
@@ -486,12 +850,14 @@ async function refreshMeta() {
const commodityResp = await apiGet(
`/order/web/pay/commodity?applicationId=${encodeURIComponent(
state.applicationId
- )}&payCountryId=${encodeURIComponent(currentCountryId())}&type=${encodeURIComponent(
+ )}&payCountryId=${encodeURIComponent(currentPayCountryId())}&type=${encodeURIComponent(
state.productType
)}®ionId=${encodeURIComponent(currentRegionId())}`
);
state.commodityCard = commodityResp?.body || {};
+ state.loading = false;
+ setUnsupportedRegion(!hasAvailablePayment());
renderProducts();
renderChannels();
setStatus("");
@@ -514,10 +880,15 @@ async function createOrder(channelCode) {
throw new Error("Select an amount first");
}
+ if (!channelCode) {
+ throw new Error("Select a payment method first");
+ }
+
if (!currentUserId()) {
throw new Error("Account not available");
}
+ state.selectedChannelCode = channelCode;
state.pendingChannelCode = channelCode;
setStatus("");
renderChannels();
@@ -525,7 +896,7 @@ async function createOrder(channelCode) {
const payload = {
applicationId: state.applicationId,
goodsId: state.selectedGoodsId,
- payCountryId: currentCountryId(),
+ payCountryId: currentPayCountryId(),
userId: currentUserId(),
channelCode,
newVersion: true,
@@ -546,12 +917,27 @@ async function reloadPageData() {
}
async function init() {
+ state.loading = true;
+ setUnsupportedRegion(false);
renderProducts();
renderChannels();
+ els.goRecharge.addEventListener("click", async () => {
+ try {
+ await createOrder(state.selectedChannelCode);
+ } catch (error) {
+ state.pendingChannelCode = "";
+ renderChannels();
+ setStatus(extractErrorMessage(error));
+ }
+ });
try {
await reloadPageData();
} catch (error) {
+ state.loading = false;
+ setUnsupportedRegion(false);
+ renderProducts();
+ renderChannels();
setStatus(extractErrorMessage(error));
}
}
diff --git a/h5/mifa-pay/bg.png b/h5/mifa-pay/bg.png
new file mode 100644
index 0000000..7513f52
Binary files /dev/null and b/h5/mifa-pay/bg.png differ
diff --git a/h5/mifa-pay/index.html b/h5/mifa-pay/index.html
index 86c94ae..d95b00d 100644
--- a/h5/mifa-pay/index.html
+++ b/h5/mifa-pay/index.html
@@ -12,10 +12,13 @@
--bg: #08131f;
--surface: rgba(15, 28, 42, 0.92);
--surface-strong: #102030;
- --line: rgba(214, 170, 82, 0.18);
- --line-strong: rgba(214, 170, 82, 0.42);
+ --line: rgba(72, 224, 208, 0.2);
+ --line-strong: rgba(72, 224, 208, 0.78);
--text: #f6f1e6;
- --muted: #bcae8d;
+ --muted: #bed4d1;
+ --accent: #48e0d0;
+ --accent-strong: #1baaa3;
+ --accent-soft: rgba(72, 224, 208, 0.16);
--gold: #d6aa52;
--gold-strong: #c49335;
--danger: #ff9f9f;
@@ -38,8 +41,9 @@
sans-serif;
color: var(--text);
background:
- radial-gradient(circle at top, rgba(214, 170, 82, 0.1), transparent 24%),
- linear-gradient(180deg, #091321 0%, var(--bg) 100%);
+ linear-gradient(180deg, rgba(8, 19, 31, 0.44), rgba(8, 19, 31, 0.72)),
+ url("./bg.png") center top / cover no-repeat,
+ var(--bg);
}
button {
@@ -59,9 +63,12 @@
font-size: 30px;
line-height: 1;
font-weight: 800;
- color: var(--gold);
+ color: #f8fbff;
text-align: center;
letter-spacing: 0.03em;
+ text-shadow:
+ 0 2px 10px rgba(8, 19, 31, 0.88),
+ 0 0 18px rgba(72, 224, 208, 0.3);
}
.list {
@@ -69,39 +76,48 @@
gap: 12px;
}
- .amount-item,
- .channel-button {
+ .amount-item {
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
- padding: 16px 18px;
+ padding: 16px 54px 16px 18px;
border-radius: 22px;
border: 1px solid var(--line);
background:
- linear-gradient(180deg, rgba(214, 170, 82, 0.04), transparent 60%),
+ linear-gradient(180deg, rgba(72, 224, 208, 0.07), transparent 62%),
var(--surface);
box-shadow: var(--shadow);
color: var(--text);
text-align: left;
transition:
transform 0.18s ease,
+ background 0.18s ease,
border-color 0.18s ease,
box-shadow 0.18s ease;
}
- .amount-item:active,
- .channel-button:active {
+ .amount-item:active {
transform: scale(0.988);
}
.amount-item.selected {
border-color: var(--line-strong);
+ background:
+ linear-gradient(135deg, rgba(72, 224, 208, 0.22), rgba(13, 30, 44, 0.96)),
+ var(--surface-strong);
+ transform: scale(1.012);
box-shadow:
- 0 0 0 1px rgba(214, 170, 82, 0.12),
- 0 16px 36px rgba(0, 0, 0, 0.24);
+ 0 0 0 1px rgba(72, 224, 208, 0.22),
+ 0 0 22px rgba(72, 224, 208, 0.28),
+ 0 16px 36px rgba(0, 0, 0, 0.28);
+ }
+
+ .amount-item:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
}
.amount-copy {
@@ -111,12 +127,37 @@
}
.amount-value {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
font-size: 24px;
line-height: 1;
font-weight: 800;
color: var(--text);
}
+ .coin-icon {
+ position: relative;
+ width: 24px;
+ height: 24px;
+ flex: 0 0 auto;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 35% 28%, #fff5b8 0 18%, transparent 19%),
+ linear-gradient(135deg, #ffd96a, #d79a26);
+ box-shadow:
+ inset 0 0 0 2px rgba(142, 91, 13, 0.46),
+ 0 0 12px rgba(255, 217, 106, 0.36);
+ }
+
+ .coin-icon::after {
+ content: "";
+ position: absolute;
+ inset: 6px;
+ border-radius: 50%;
+ border: 2px solid rgba(122, 78, 10, 0.48);
+ }
+
.amount-meta {
font-size: 11px;
line-height: 1;
@@ -130,12 +171,14 @@
display: grid;
gap: 6px;
flex-shrink: 0;
+ max-width: 46%;
}
.price-copy strong {
- font-size: 22px;
+ font-size: 20px;
line-height: 1;
- color: var(--gold);
+ color: var(--accent);
+ white-space: nowrap;
}
.price-copy span {
@@ -145,17 +188,20 @@
.check {
position: absolute;
- top: 14px;
- right: 14px;
+ top: 50%;
+ right: 18px;
width: 20px;
height: 20px;
border-radius: 50%;
- border: 1px solid rgba(214, 170, 82, 0.3);
+ border: 1px solid rgba(72, 224, 208, 0.36);
+ transform: translateY(-50%);
+ pointer-events: none;
}
.amount-item.selected .check {
border-color: transparent;
- background: linear-gradient(135deg, #efcf82, var(--gold-strong));
+ background: linear-gradient(135deg, #8cf5ec, var(--accent-strong));
+ box-shadow: 0 0 14px rgba(72, 224, 208, 0.45);
}
.amount-item.selected .check::after {
@@ -174,32 +220,107 @@
margin-top: 18px;
}
- .channel-button {
- justify-content: flex-start;
- padding-right: 18px;
+ .channel-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 10px;
}
- .channel-logo {
- width: 78px;
- height: 44px;
+ .channel-button {
+ position: relative;
+ width: 100%;
+ min-height: 84px;
+ display: grid;
+ align-content: center;
+ justify-items: center;
+ gap: 8px;
+ padding: 10px 6px;
+ border-radius: 16px;
+ border: 1px solid var(--line);
+ background:
+ linear-gradient(180deg, rgba(72, 224, 208, 0.06), transparent 62%),
+ var(--surface);
+ box-shadow: var(--shadow);
+ color: var(--text);
+ text-align: center;
+ transition:
+ transform 0.18s ease,
+ background 0.18s ease,
+ border-color 0.18s ease,
+ box-shadow 0.18s ease;
+ }
+
+ .channel-button:active {
+ transform: scale(0.98);
+ }
+
+ .channel-button.selected {
+ border-color: var(--line-strong);
+ background:
+ linear-gradient(135deg, rgba(72, 224, 208, 0.28), rgba(13, 30, 44, 0.97)),
+ var(--surface-strong);
+ transform: translateY(-2px) scale(1.045);
+ box-shadow:
+ 0 0 0 1px rgba(72, 224, 208, 0.26),
+ 0 0 22px rgba(72, 224, 208, 0.34),
+ 0 18px 40px rgba(0, 0, 0, 0.32);
+ }
+
+ .channel-button.selected::after {
+ content: "";
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 9px;
+ height: 9px;
+ border-radius: 50%;
+ background: var(--accent);
+ box-shadow: 0 0 12px rgba(72, 224, 208, 0.68);
+ }
+
+ .channel-icon {
+ width: 54px;
+ height: 38px;
display: grid;
place-items: center;
flex-shrink: 0;
- border-radius: 14px;
+ padding: 4px;
+ border-radius: 10px;
background: #ffffff;
overflow: hidden;
}
- .channel-logo img {
+ .channel-icon img {
display: block;
- width: 68px;
- height: auto;
+ max-width: 48px;
+ max-height: 30px;
+ object-fit: contain;
+ }
+
+ .channel-fallback {
+ width: 42px;
+ height: 42px;
+ padding: 0;
+ border-radius: 12px;
+ background: linear-gradient(135deg, #8cf5ec, var(--accent-strong));
+ color: #0c1520;
+ font-size: 12px;
+ line-height: 1;
+ font-weight: 800;
}
.channel-name {
- font-size: 16px;
+ width: 100%;
+ min-height: 24px;
+ display: -webkit-box;
+ overflow: hidden;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 2;
+ font-size: 10px;
+ line-height: 1.2;
font-weight: 700;
color: var(--text);
+ overflow-wrap: anywhere;
}
.channel-button:disabled {
@@ -207,6 +328,32 @@
opacity: 0.55;
}
+ .recharge-button {
+ width: 100%;
+ margin-top: 14px;
+ padding: 14px 18px;
+ border-radius: 18px;
+ background: linear-gradient(135deg, #8cf5ec, var(--accent-strong));
+ color: #0c1520;
+ font-size: 16px;
+ font-weight: 800;
+ box-shadow:
+ 0 0 18px rgba(72, 224, 208, 0.28),
+ 0 16px 32px rgba(0, 0, 0, 0.28);
+ transition:
+ transform 0.18s ease,
+ box-shadow 0.18s ease;
+ }
+
+ .recharge-button:active {
+ transform: scale(0.985);
+ }
+
+ .recharge-button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+ }
+
.status {
display: none;
margin-top: 14px;
@@ -225,6 +372,7 @@
}
.empty {
+ grid-column: 1 / -1;
padding: 16px;
border-radius: 20px;
border: 1px dashed var(--line);
@@ -232,18 +380,136 @@
text-align: center;
font-size: 13px;
}
+
+ .unsupported-state {
+ display: none;
+ min-height: calc(100vh - 130px);
+ place-items: center;
+ padding: 36px 8px;
+ }
+
+ .unsupported-state.show {
+ display: grid;
+ }
+
+ .unsupported-panel {
+ width: 100%;
+ max-width: 360px;
+ display: grid;
+ justify-items: center;
+ gap: 14px;
+ padding: 28px 22px;
+ border-radius: 24px;
+ border: 1px solid rgba(72, 224, 208, 0.46);
+ background:
+ radial-gradient(circle at top, rgba(72, 224, 208, 0.18), transparent 58%),
+ rgba(8, 19, 31, 0.82);
+ box-shadow:
+ 0 0 0 1px rgba(248, 251, 255, 0.06),
+ 0 0 28px rgba(72, 224, 208, 0.24),
+ 0 18px 44px rgba(0, 0, 0, 0.34);
+ text-align: center;
+ }
+
+ .unsupported-icon {
+ width: 44px;
+ height: 44px;
+ display: grid;
+ place-items: center;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #8cf5ec, var(--accent-strong));
+ color: #0c1520;
+ font-size: 24px;
+ font-weight: 900;
+ box-shadow: 0 0 18px rgba(72, 224, 208, 0.42);
+ }
+
+ .unsupported-title {
+ margin: 0;
+ max-width: 290px;
+ color: #f8fbff;
+ font-size: 20px;
+ line-height: 1.35;
+ font-weight: 800;
+ text-shadow: 0 2px 10px rgba(8, 19, 31, 0.72);
+ }
+
+ .skeleton {
+ position: relative;
+ overflow: hidden;
+ }
+
+ .skeleton::after {
+ content: "";
+ position: absolute;
+ inset: 0;
+ transform: translateX(-100%);
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ rgba(248, 251, 255, 0.12),
+ transparent
+ );
+ animation: shimmer 1.25s infinite;
+ }
+
+ .skeleton-line,
+ .skeleton-icon {
+ display: block;
+ border-radius: 999px;
+ background: rgba(248, 251, 255, 0.12);
+ }
+
+ .skeleton-line.strong {
+ width: 92px;
+ height: 22px;
+ }
+
+ .skeleton-line.short {
+ width: 64px;
+ height: 10px;
+ }
+
+ .skeleton-line.price {
+ width: 104px;
+ height: 18px;
+ margin-left: auto;
+ }
+
+ .skeleton-icon {
+ width: 54px;
+ height: 38px;
+ border-radius: 10px;
+ }
+
+ @keyframes shimmer {
+ 100% {
+ transform: translateX(100%);
+ }
+ }
Recharge
-
+
+
+
+
!
+
+ Sorry, this region is currently not supported.
+
+
+
+
-
+