VulpesOS/assets/webapps/costcontrol.gaiamobile.org/js/views/balance.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

468 lines
14 KiB
JavaScript

/* global BalanceView, TopUpLayoutView, CostControl, ConfigManager,
ViewManager, debug, MozActivity, getTopUpTimeout, LazyLoader,
sendBalanceThresholdNotification
*/
/*
* The balance tab is in charge of show balance details and allows the use
* to manually update or top up via USSD or code.
*
* It has four areas of drawing: balance, top up dialog, top up countdown and
* error area. The update is done by demand when the application is shown or
* when the user taps on the update button. Furthermore, the balance update
* can be triggered by a successful top up request.
*/
'use strict';
var BalanceTab = (function() {
var view, updateButton;
var topUpUSSD, topUp, topUpDialog, topUpCodeInput, sendCode, countdownSpan;
var balanceView, topUpLayoutView;
var costcontrol, initialized;
function showTopUpWithCode(evt) {
topUpWithCode();
}
function setupTab() {
if (initialized) {
return;
}
CostControl.getInstance(function _onCostControl(instance) {
costcontrol = instance;
// we need to load topUpDialog to get elements from inside
// it should be a separate function run on startup of the module
// after HTML is generated
topUpDialog = document.getElementById('topup-dialog');
var vm = new ViewManager(); // XXX: used to eagerly load top up dialog
vm.loadPanel(topUpDialog);
// HTML entities
view = document.getElementById('balance-tab');
updateButton = document.getElementById('balance-tab-update-button');
sendCode = document.getElementById('topup-send-button');
topUpUSSD = document.getElementById('balance-tab-topup-ussd-button');
topUp = document.getElementById('balance-tab-topup-button');
topUpCodeInput = document.getElementById('topup-code-input');
countdownSpan = document.getElementById('top-up-countdown');
// Subviews
topUpLayoutView = new TopUpLayoutView(topUpUSSD, topUp);
var balanceConfig = ConfigManager.configuration.balance;
balanceView = new BalanceView(
document.getElementById('balance-tab-credit'),
document.getElementById('balance-tab-time'),
balanceConfig ? balanceConfig.minimum_delay : undefined
);
window.addEventListener('localized', localize);
// Configure updates
document.addEventListener('visibilitychange', updateWhenVisible);
updateButton.addEventListener('click', lockAndUpdateUI);
ConfigManager.observe('lowLimit', toogleLimits, true);
ConfigManager.observe('lowLimitThreshold', resetNotification, true);
ConfigManager.observe('lastBalance', onBalance, true);
ConfigManager.observe('errors', onBalanceTimeout, true);
// Configure top up
topUpUSSD.addEventListener('click', topUpWithUSSD);
topUp.addEventListener('click', showTopUpWithCode);
topUpCodeInput.addEventListener('input', toogleSend);
sendCode.addEventListener('click', requestTopUp);
ConfigManager.observe('waitingForTopUp', onConfirmation, true);
ConfigManager.observe('errors', onTopUpErrors, true);
toogleSend();
updateUI();
initialized = true;
});
}
function localize() {
if (initialized) {
updateUI();
}
}
function finalize() {
if (!initialized) {
return;
}
document.removeEventListener('visibilitychange', updateWhenVisible);
updateButton.removeEventListener('click', lockAndUpdateUI);
ConfigManager.removeObserver('lowLimit', toogleLimits);
ConfigManager.removeObserver('lowLimitThreshold', resetNotification);
ConfigManager.removeObserver('lastBalance', onBalance);
ConfigManager.removeObserver('errors', onBalanceTimeout);
topUpUSSD.removeEventListener('click', topUpWithUSSD);
topUp.removeEventListener('click', showTopUpWithCode);
topUpCodeInput.removeEventListener('input', toogleSend);
sendCode.removeEventListener('click', requestTopUp);
ConfigManager.removeObserver('waitingForTopUp', onConfirmation);
ConfigManager.removeObserver('errors', onTopUpErrors);
topUpLayoutSet = false;
initialized = false;
}
// BALANCE ACTIONS
// On showing the application
function updateWhenVisible() {
if (!document.hidden && initialized) {
updateUI();
} else {
clearInterval(topUpCountdown);
}
}
// On tapping update
function lockAndUpdateUI() {
updateButton.disabled = true;
updateUI(true);
}
// On changing low limit alert
function toogleLimits(isEnabled, old, key, settings) {
updateBalance(settings.lastBalance,
isEnabled && settings.lowLimitThreshold);
if (isEnabled) {
sendBalanceThresholdNotification(settings.lastBalance, settings, false);
updateBalance(settings.lastBalance, settings.lowLimitThreshold);
}
}
// On changing the threshold for low limit
function resetNotification() {
ConfigManager.setOption({ 'lowLimitNotified': false });
ConfigManager.requestAll(function _onSettings(configuration, settings) {
updateBalance(settings.lastBalance, settings.lowLimitThreshold);
sendBalanceThresholdNotification(settings.lastBalance, settings, false);
});
}
// On balance update received
function onBalance(balance, old, key, settings) {
debug('Balance received:', balance);
setBalanceMode();
updateBalance(balance, settings.lowLimit && settings.lowLimitThreshold);
debug('Balance updated!');
}
// On balance timeout
function onBalanceTimeout(errors) {
if (!errors.BALANCE_TIMEOUT) {
return;
}
debug('Balance timeout!');
setBalanceMode('warning');
setError('balance_error');
// Error handled, disabling
errors.BALANCE_TIMEOUT = false;
ConfigManager.setOption({errors: errors});
}
// TOP UP ACTIONS
// On tapping Top Up and Pay
function topUpWithUSSD() {
var dialing;
dialing = new MozActivity({
name: 'dial',
data: {
type: 'webtelephony/number',
number: ConfigManager.configuration.topup.ussd_destination
}
});
}
// On tapping Top Up with code
function topUpWithCode(lastWasError) {
window.location.hash = '##topup-dialog';
if (lastWasError) {
setTopUpMode('incorrect_code');
}
topUpCodeInput.focus();
}
// On typing the code
function toogleSend(evt) {
sendCode.disabled = !topUpCodeInput.value.trim();
}
// On tapping send code button
var DIALOG_TIMEOUT = 10 * 1000; // 10s
function requestTopUp() {
sendCode.disabled = true;
var code = topUpCodeInput.value.trim();
var requestObj = { type: 'topup', data: code };
costcontrol.request(requestObj, function _onTopUpRequest(result) {
debug(result);
sendCode.disabled = false;
var status = result.status;
if (status === 'success' || status === 'in_progress') {
setTopUpMode('in_progress');
setTimeout(closeTopUp, DIALOG_TIMEOUT);
} else if (status === 'error') {
setTopUpMode(result.details);
}
});
}
function closeTopUp() {
// Remove from hash
if (isTopUpShown()) {
window.location.hash = '#';
}
}
function isTopUpShown() {
return window.location.hash.split('#')[2] === topUpDialog.id;
}
// On confirmation SMS for top up received
function onConfirmation(isWaiting) {
if (isWaiting !== null) {
return;
}
debug('TopUp confirmed!');
setTopUpMode('default');
topUpCodeInput.value = '';
updateUI();
}
// On top up timeout or incorrect code
function onTopUpErrors(errors) {
debug('ERRORS:', errors);
var mode;
if (errors.TOPUP_TIMEOUT) {
errors.TOPUP_TIMEOUT = false;
mode = 'topup_timeout';
}
if (errors.INCORRECT_TOPUP_CODE) {
errors.INCORRECT_TOPUP_CODE = false;
mode = 'incorrect_code';
}
debug('Most important error: ', mode);
// XXX: Very important to call this only if something has changed. If not,
// infinite events are triggered.
if (mode) {
setTopUpMode(mode);
ConfigManager.setOption({errors: errors});
}
}
// USER INTERFACE
var topUpLayoutSet = false;
function updateUI(force) {
ConfigManager.requestAll(function _onSettings(configuration, settings) {
if (!topUpLayoutSet) {
topUpLayoutView.setupLayout(configuration.topup);
topUpLayoutSet = true;
}
resetTopUpCountdown();
updateBalance(settings.lastBalance,
settings.lowLimit && settings.lowLimitThreshold);
var requestObj = { type: 'balance', force: !!force };
costcontrol.request(requestObj, function _onRequest(result) {
debug(result);
updateButton.disabled = false;
var status = result.status;
var balance = result.data;
var isError = status === 'error' && result.details !== 'minimum_delay';
var isUpdating = status !== 'error';
if (isError) {
setBalanceMode('warning');
setError(result.details);
} else {
setBalanceMode(isUpdating ? 'updating' : 'default');
setError();
}
updateBalance(balance,
settings.lowLimit && settings.lowLimitThreshold);
});
});
}
// Update the balance in balance view
function updateBalance(balance, limit) {
if (!balance) {
debug('Balance not available');
balanceView.update();
return;
}
var isUpdating = view.classList.contains('updating');
balanceView.update(balance, isUpdating);
// Limits: reaching zero / low limit
if (balance.balance === 0) {
view.classList.add('no-credit');
} else {
view.classList.remove('no-credit');
if (limit && balance.balance < limit) {
view.classList.add('low-credit');
} else {
view.classList.remove('low-credit');
}
}
}
// Set warning / updating modes
var lastBalanceMode;
function setBalanceMode(mode) {
if (mode === lastBalanceMode) {
return;
}
lastBalanceMode = mode;
view.classList.remove('updating');
view.classList.remove('warning');
if (mode === 'warning') {
view.classList.add('warning');
}
if (mode === 'updating') {
view.classList.add('updating');
}
}
// Control info messages in the top up dialog as well as the top up countdown
// and error messages in the error area
var lastTopUpMode;
function setTopUpMode(mode) {
if (lastTopUpMode === mode) {
return;
}
lastTopUpMode = mode;
// Messages in top up dialog
var isShown;
var defaultMessage = document.getElementById('topup-code-explanation');
var inprogressMessage = document.getElementById('topup-in-progress');
var errorMessage = document.getElementById('topup-error');
var incorrectCodeMessage = document.getElementById('topup-incorrect-code');
isShown = (mode === 'default' || mode === 'topup_timeout');
defaultMessage.hidden = !isShown;
isShown = (mode === 'in_progress');
inprogressMessage.hidden = !isShown;
isShown = (mode === 'request_fail' || mode === 'no_service');
errorMessage.hidden = !isShown;
isShown = (mode === 'incorrect_code');
incorrectCodeMessage.hidden = !isShown;
// Count down
var countdownArea = document.getElementById('cost-control-topup-countdown');
isShown = (mode === 'in_progress');
countdownArea.hidden = !isShown;
if (isShown) {
resetTopUpCountdown();
}
// Messages in error message area
if (mode === 'topup_timeout') {
setError(mode);
}
}
var topUpCountdown, countdown;
function resetTopUpCountdown() {
getTopUpTimeout(function(timeout) {
if (!timeout) {
return;
}
countdown = Math.floor((timeout.getTime() - Date.now()) / 1000);
if (countdown < 0) {
return;
}
clearInterval(topUpCountdown);
topUpCountdown = setInterval(function _updateCountdown() {
var minutes = Math.floor(countdown / 60);
var seconds = (countdown % 60).toFixed(0);
var padding = '';
if (seconds < 10) {
padding = '0';
}
countdownSpan.textContent = (minutes + ' : ' + padding + seconds);
if (countdown > 0) {
countdown -= 1;
}
}, 1000);
});
}
var ERRORS = {
'airplane_mode': { priority: 1, string: 'airplane-mode-error-message2' },
'no_service': { priority: 2, string: 'no-coverage-error-message2' },
'no_coverage': { priority: 2, string: 'no-coverage-error-message' },
'topup_timeout': { priority: 3, string: 'top-up-timed-out2' },
'balance_error': { priority: 4, string: 'balance-error-message2' },
'non_free_in_roaming': { priority: 4, string: 'on-roaming-message2' }
};
var currentError = '';
// Decide which error should be shown taking in count error priorities
function setError(error) {
// Ignore showing message if the message is not registered
if (error && !ERRORS[error]) {
return;
}
debug('Error mode:', error ? error : 'no error');
var messageArea = document.getElementById('cost-control-message-area');
var message = document.getElementById('error-message-placeholder');
if (!error) {
messageArea.hidden = true;
message.removeAttribute('data-l10n-id');
message.textContent = '';
} else {
messageArea.hidden = false;
var curPriority = currentError ? ERRORS[currentError].priority : 0;
var newPriority = ERRORS[error] ? ERRORS[error].priority : 0;
if (newPriority >= curPriority) {
message.setAttribute('data-l10n-id', ERRORS[error].string);
currentError = error;
}
}
}
return {
topUpWithCode: topUpWithCode,
initialize: function() {
var SCRIPTS_NEEDED = [
'js/views/TopUpLayoutView.js',
'js/views/BalanceView.js'
];
LazyLoader.load(SCRIPTS_NEEDED, setupTab);
},
finalize: finalize
};
}());
BalanceTab.initialize();