diff --git a/h5/hyapp/bd-leader-center/index.html b/h5/hyapp/bd-leader-center/index.html index 8d841b7..b70c785 100644 --- a/h5/hyapp/bd-leader-center/index.html +++ b/h5/hyapp/bd-leader-center/index.html @@ -4,7 +4,7 @@ BD Leader Center - +
@@ -53,10 +53,10 @@
-
My available salary
+
salary
-
- +
@@ -223,6 +223,6 @@
- + diff --git a/h5/hyapp/bd-leader-center/script.js b/h5/hyapp/bd-leader-center/script.js index 8529927..010b72b 100644 --- a/h5/hyapp/bd-leader-center/script.js +++ b/h5/hyapp/bd-leader-center/script.js @@ -17,8 +17,8 @@ language_button_aria: "Change language", role: "BD Leader", uid_prefix: "UID:", - my_available_salary: "My available salary", - details: "Details", + my_available_salary: "salary", + details: "Withdraw/Exchange", bd_number: "BD number", team_salary: "Team salary", bd_policy_link: "BD policy", @@ -67,8 +67,8 @@ language_button_aria: "تغيير اللغة", role: "قائد BD", uid_prefix: "UID:", - my_available_salary: "راتبي المتاح", - details: "التفاصيل", + my_available_salary: "الراتب", + details: "سحب/تبديل", bd_number: "عدد BD", team_salary: "راتب الفريق", bd_policy_link: "سياسة BD", @@ -117,8 +117,8 @@ language_button_aria: "Dili değiştir", role: "BD Leader", uid_prefix: "UID:", - my_available_salary: "Kullanılabilir maaşım", - details: "Detaylar", + my_available_salary: "Maaş", + details: "Withdraw/Exchange", bd_number: "BD sayısı", team_salary: "Takım maaşı", bd_policy_link: "BD politikası", @@ -167,8 +167,8 @@ language_button_aria: "Ubah bahasa", role: "BD Leader", uid_prefix: "UID:", - my_available_salary: "Gaji tersedia", - details: "Detail", + my_available_salary: "Gaji", + details: "Withdraw/Exchange", bd_number: "Jumlah BD", team_salary: "Gaji tim", bd_policy_link: "Kebijakan BD", @@ -451,6 +451,11 @@ if (node) node.textContent = formatMoney(balance); } + function balanceAmount(balance) { + const value = Number(balance?.availableBalance ?? balance?.balance ?? balance?.currentSalary ?? 0); + return Number.isFinite(value) ? value : 0; + } + function renderBill() { const bill = state.bill || {}; const members = Array.isArray(bill.memberBillList) ? bill.memberBillList : []; @@ -1019,7 +1024,24 @@ } async function fetchBalanceTotal() { - state.balanceTotal = await requestJSON("/wallet/salary-account/balance/total") || {}; + const salaryTypes = ["BD_SALARY", "BD_LEADER_SALARY"]; + const results = await Promise.allSettled( + salaryTypes.map((salaryType) => requestJSON(`/wallet/salary-account/balance?salaryType=${encodeURIComponent(salaryType)}`)) + ); + const balances = {}; + results.forEach((result, index) => { + const salaryType = salaryTypes[index]; + if (result.status === "fulfilled") { + balances[salaryType] = result.value || {}; + } else { + balances[salaryType] = {}; + console.warn(`Failed to load ${salaryType} balance:`, result.reason); + } + }); + state.balanceTotal = { + ...balances, + availableBalance: salaryTypes.reduce((total, salaryType) => total + balanceAmount(balances[salaryType]), 0) + }; renderBalance(); } diff --git a/h5/hyapp/withdraw-exchange/index.html b/h5/hyapp/withdraw-exchange/index.html index 197a5fe..ed8008d 100644 --- a/h5/hyapp/withdraw-exchange/index.html +++ b/h5/hyapp/withdraw-exchange/index.html @@ -4,7 +4,7 @@ Withdraw/Exchange - +
@@ -46,6 +46,13 @@
+ +
@@ -147,6 +154,6 @@
- + diff --git a/h5/hyapp/withdraw-exchange/script.js b/h5/hyapp/withdraw-exchange/script.js index a7e48b9..cfd8346 100644 --- a/h5/hyapp/withdraw-exchange/script.js +++ b/h5/hyapp/withdraw-exchange/script.js @@ -16,6 +16,8 @@ title: "Withdraw/Exchange", language_button_aria: "Change language", available_income: "salary", + bd_salary: "BD salary", + bd_leader_salary: "BD Leader salary", withdraw: "Withdraw", exchange: "Exchange", transfer: "Transfer", @@ -66,6 +68,8 @@ title: "سحب/تبديل", language_button_aria: "تغيير اللغة", available_income: "الراتب", + bd_salary: "راتب BD", + bd_leader_salary: "راتب قائد BD", withdraw: "سحب", exchange: "تبديل", transfer: "تحويل", @@ -116,6 +120,8 @@ title: "Çek/Değiştir", language_button_aria: "Dili değiştir", available_income: "Maaş", + bd_salary: "BD maaşı", + bd_leader_salary: "BD Leader maaşı", withdraw: "Withdraw", exchange: "Exchange", transfer: "Transfer", @@ -166,6 +172,8 @@ title: "Tarik/Tukar", language_button_aria: "Ubah bahasa", available_income: "Gaji", + bd_salary: "Gaji BD", + bd_leader_salary: "Gaji BD Leader", withdraw: "Tarik", exchange: "Tukar", transfer: "Transfer", @@ -215,8 +223,11 @@ const params = readURLParams(); let currentLang = normalizeLanguage(params.get("lang")); let currentMode = normalizeMode(params.get("mode")) || "withdraw"; + const pageIdentity = normalizeIdentity(params.get("identity")); + let currentSalaryType = normalizeSalaryType(params.get("salaryType")) || defaultSalaryTypeForIdentity(pageIdentity); let currentMessages = translations[currentLang] || translations.en; let availableBalance = 0; + let salaryBalances = {}; let selectedPaymentInfo = null; let selectedPayee = null; let currentProfile = null; @@ -242,6 +253,7 @@ const transferAccountInput = document.querySelector("#transferAccount"); const searchPayeeButton = document.querySelector("#searchPayeeButton"); const exchangeRateText = document.querySelector("#exchangeRateText"); + const salarySelector = document.querySelector("#salarySelector"); function readURLParams() { const result = new URLSearchParams(window.location.search); @@ -289,6 +301,35 @@ return ["withdraw", "exchange", "transfer"].includes(mode) ? mode : ""; } + function normalizeIdentity(identity) { + const value = String(identity || "").trim().toUpperCase(); + return ["HOST", "BD", "BD_LEADER", "ADMIN"].includes(value) ? value : ""; + } + + function normalizeSalaryType(type) { + const value = String(type || "").trim().toUpperCase(); + return ["HOST_SALARY", "BD_SALARY", "BD_LEADER_SALARY", "ADMIN_SALARY"].includes(value) ? value : ""; + } + + function defaultSalaryTypeForIdentity(identity) { + if (identity === "BD_LEADER") return "BD_LEADER_SALARY"; + if (identity === "BD") return "BD_SALARY"; + if (identity === "ADMIN") return "ADMIN_SALARY"; + return ""; + } + + function isSalaryAccountMode() { + return Boolean(currentSalaryType && currentSalaryType !== "HOST_SALARY"); + } + + function activeSalaryType() { + return currentSalaryType || "HOST_SALARY"; + } + + function responseBody(data) { + return data?.body ?? data?.data ?? null; + } + function apiBaseURL() { const override = window.HYAPP_API_BASE_URL || params.get("apiBase"); if (override) return String(override).replace(/\/+$/, ""); @@ -360,6 +401,34 @@ return `1$ = ${EXCHANGE_RATE} golds`; } + function salaryBalanceValue(type) { + const balance = salaryBalances[type] || {}; + return moneyNumber(balance.availableBalance ?? balance.balance ?? balance.currentSalary ?? 0); + } + + function renderSalarySelector() { + if (!salarySelector) return; + const showSelector = pageIdentity === "BD_LEADER"; + salarySelector.hidden = !showSelector; + if (!showSelector) return; + + salarySelector.querySelectorAll("[data-salary-type]").forEach((button) => { + const type = normalizeSalaryType(button.dataset.salaryType); + const active = type === currentSalaryType; + const label = message(type === "BD_SALARY" ? "bd_salary" : "bd_leader_salary"); + button.classList.toggle("active", active); + button.setAttribute("aria-pressed", String(active)); + button.textContent = `${label} $${formatMoney(salaryBalanceValue(type))}`; + }); + } + + function setActiveSalaryType(type) { + const nextType = normalizeSalaryType(type); + if (!nextType || nextType === currentSalaryType) return; + currentSalaryType = nextType; + renderBalance(salaryBalanceValue(nextType)); + } + function isValidTrc20Address(value) { return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || "").trim()); } @@ -396,6 +465,7 @@ button.setAttribute("aria-pressed", String(isActive)); }); if (exchangeRateText) exchangeRateText.textContent = formatExchangeRate(); + renderSalarySelector(); renderPayee(); updateSubmitState(); } @@ -456,6 +526,7 @@ function renderBalance(value) { availableBalance = moneyNumber(value); if (balanceAmount) balanceAmount.textContent = formatMoney(availableBalance); + renderSalarySelector(); Object.values(inputs).forEach((input) => { if (input) input.max = formatMoney(availableBalance); }); @@ -524,11 +595,36 @@ async function fetchBalance() { try { + if (pageIdentity === "BD_LEADER") { + const salaryTypes = ["BD_SALARY", "BD_LEADER_SALARY"]; + const results = await Promise.allSettled( + salaryTypes.map((type) => requestJSON(`/wallet/salary-account/balance?salaryType=${encodeURIComponent(type)}`)) + ); + salaryBalances = {}; + results.forEach((result, index) => { + const type = salaryTypes[index]; + salaryBalances[type] = result.status === "fulfilled" ? responseBody(result.value) || {} : {}; + if (result.status === "rejected") console.warn(`Failed to load ${type} balance:`, result.reason); + }); + if (results.every((result) => result.status === "rejected")) throw results[0].reason; + if (!currentSalaryType) currentSalaryType = "BD_LEADER_SALARY"; + renderBalance(salaryBalanceValue(currentSalaryType)); + return; + } + + if (isSalaryAccountMode()) { + const data = await requestJSON(`/wallet/salary-account/balance?salaryType=${encodeURIComponent(currentSalaryType)}`); + const body = responseBody(data) || {}; + salaryBalances = { [currentSalaryType]: body }; + renderBalance(body.availableBalance ?? body.balance ?? body.currentSalary ?? 0); + return; + } + const data = await requestJSON("/wallet/bank/balance"); - const body = data.body ?? data.data ?? 0; + const body = responseBody(data) ?? 0; renderBalance(typeof body === "number" ? body : body.currentSalary ?? body.availableBalance ?? body.balance ?? 0); } catch (error) { - console.error("Failed to load bank balance:", error); + console.error("Failed to load balance:", error); renderBalance(0); showToast("load_balance_failed", error.message); } @@ -683,7 +779,7 @@ body: { amount: activeAmount(), acceptBankCardId: selectedPaymentInfo.id, - salaryType: "HOST_SALARY" + salaryType: activeSalaryType() } }); showToast("withdraw_success"); @@ -696,11 +792,11 @@ return; } - await requestJSON("/wallet/bank/exchange/gold", { + await requestJSON(isSalaryAccountMode() ? "/wallet/salary-account/exchange/gold" : "/wallet/bank/exchange/gold", { method: "POST", - body: { - amount: activeAmount() - } + body: isSalaryAccountMode() + ? { amount: activeAmount(), salaryType: activeSalaryType() } + : { amount: activeAmount() } }); showToast("exchange_success"); } @@ -712,13 +808,11 @@ return; } - await requestJSON("/wallet/bank/transferGold", { + await requestJSON(isSalaryAccountMode() ? "/wallet/salary-account/transferGold" : "/wallet/bank/transferGold", { method: "POST", - body: { - amount: activeAmount(), - acceptUserId: selectedPayee.id, - acceptMethod: "BANK_TRANSFER" - } + body: isSalaryAccountMode() + ? { amount: activeAmount(), acceptUserId: selectedPayee.id, salaryType: activeSalaryType() } + : { amount: activeAmount(), acceptUserId: selectedPayee.id, acceptMethod: "BANK_TRANSFER" } }); showToast("transfer_success"); } @@ -760,7 +854,8 @@ if (token) nextParams.set("token", token); if (currentLang) nextParams.set("lang", currentLang); const query = nextParams.toString(); - window.location.href = `../host-center/index.html${query ? `?${query}` : ""}`; + const fallbackPage = pageIdentity === "BD_LEADER" ? "../bd-leader-center/index.html" : "../host-center/index.html"; + window.location.href = `${fallbackPage}${query ? `?${query}` : ""}`; }); } @@ -795,6 +890,10 @@ tab.addEventListener("click", () => setMode(tab.dataset.mode)); }); + document.querySelectorAll("[data-salary-type]").forEach((button) => { + button.addEventListener("click", () => setActiveSalaryType(button.dataset.salaryType)); + }); + document.querySelector(".text-action")?.addEventListener("click", () => { if (inputs.withdraw) inputs.withdraw.value = formatMoney(availableBalance); updateSubmitState(); diff --git a/h5/hyapp/withdraw-exchange/style.css b/h5/hyapp/withdraw-exchange/style.css index 9bd89a9..e592072 100644 --- a/h5/hyapp/withdraw-exchange/style.css +++ b/h5/hyapp/withdraw-exchange/style.css @@ -294,6 +294,7 @@ select { } .balance-card, +.salary-selector-card, .mode-card, .card-section, .bind-panel { @@ -332,6 +333,32 @@ select { line-height: 1; } +.salary-selector-card { + padding: 10px; +} + +.salary-selector-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; +} + +.salary-selector-tab { + min-height: 40px; + padding: 0 8px; + border-radius: 8px; + background: #eef1f1; + color: #777a80; + font-size: 13px; + font-weight: 900; +} + +.salary-selector-tab.active { + background: #e7fbf8; + color: #0e8f82; + box-shadow: inset 0 0 0 1px rgba(22, 185, 172, 0.22); +} + .mode-card { padding: 16px; }