UI/UX and feature update

-- changes user flow for wallet top-up and changed the visual design to reflect that
-- top-up now works with random generated string
-- removed UPI ID asking step
-- implemented required changes to cashier side also
This commit is contained in:
sairaj mote 2022-06-02 15:30:20 +05:30
parent 5168fc3517
commit 5ee21d2994
7 changed files with 212 additions and 91 deletions

View File

@ -67,10 +67,6 @@ strong {
line-height: 1.7;
color: rgba(var(--text-color), 0.9);
}
p:not(:last-of-type),
strong:not(:last-of-type) {
margin-bottom: 1.5rem;
}
.warning {
line-height: normal;
@ -257,10 +253,49 @@ strip-option {
user-select: none;
}
ul {
ul,
ol {
list-style: none;
}
ol {
counter-reset: item;
}
ol li {
position: relative;
display: flex;
align-items: flex-start;
counter-increment: item;
}
ol li:not(:last-of-type) {
padding-bottom: 1.5rem;
}
ol li:not(:last-of-type)::after {
content: "";
position: absolute;
width: 0.1rem;
height: calc(100% - 1.5rem);
background: var(--accent-color);
margin-left: 0.6rem;
margin-top: 1.5rem;
}
ol li::before {
content: counter(item);
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 0.8rem;
font-weight: 500;
margin-top: 0.15rem;
padding: 0.4rem;
margin-right: 1rem;
aspect-ratio: 1/1;
border-radius: 100%;
color: rgba(var(--text-color), 0.8);
background: rgba(var(--text-color), 0.1);
}
.overflow-ellipsis {
width: 100%;
overflow: hidden;
@ -872,10 +907,7 @@ ul {
background-color: rgba(var(--text-color), 0.03);
border-radius: 0.5rem;
height: 12rem;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
margin: 0 auto;
justify-self: flex-start;
}
#topup_wallet__qr_code svg {
width: 100%;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -63,10 +63,6 @@ strong {
max-width: 65ch;
line-height: 1.7;
color: rgba(var(--text-color), 0.9);
&:not(:last-of-type) {
margin-bottom: 1.5rem;
}
}
.warning {
line-height: normal;
@ -231,9 +227,47 @@ strip-option {
--border-radius: 0.2rem;
user-select: none;
}
ul {
ul,
ol {
list-style: none;
}
ol {
counter-reset: item;
li {
position: relative;
display: flex;
align-items: flex-start;
counter-increment: item;
&:not(:last-of-type) {
padding-bottom: 1.5rem;
&::after {
content: "";
position: absolute;
width: 0.1rem;
height: calc(100% - 1.5rem);
background: var(--accent-color);
margin-left: 0.6rem;
margin-top: 1.5rem;
}
}
}
li::before {
content: counter(item);
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 0.8rem;
font-weight: 500;
margin-top: 0.15rem;
padding: 0.4rem;
margin-right: 1rem;
aspect-ratio: 1/1;
border-radius: 100%;
color: rgba(var(--text-color), 0.8);
background: rgba(var(--text-color), 0.1);
}
}
.overflow-ellipsis {
width: 100%;
@ -811,8 +845,7 @@ ul {
background-color: rgba(var(--text-color), 0.03);
border-radius: 0.5rem;
height: 12rem;
width: max-content;
margin: 0 auto;
justify-self: flex-start;
svg {
width: 100%;
height: 100%;

View File

@ -326,7 +326,7 @@
</div>
</section>
<section id="wallet" class="inner-page hide">
<div class="flex sticky top-0" style="background-color: rgba(var(--foreground-color),1);">
<div class="flex sticky top-0" style="background-color: rgba(var(--foreground-color),1); z-index: 1;">
<a href="#/home" class="button icon-only margin-right-0-5">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000">
@ -813,7 +813,7 @@
</g>
</svg>
</sm-input>
<div class="grid gap-1">
<!-- <div class="grid gap-1">
<div class="grid gap-0-5 hide">
<p>
<b>Select UPI ID you'll send money from</b>
@ -828,42 +828,70 @@
</svg>
Add UPI ID
</button>
</div>
</div> -->
<strong id="low_user_flo_warning" class="hide warning"></strong>
<button class="button button--primary cta" onclick="continueWalletTopup()"
type="submit">Continue</button>
</sm-form>
<sm-form id="confirm_topup_form" class="hide">
<div class="grid gap-0-5">
<h4>Confirm</h4>
<p id="topup_wallet__details"></p>
</div>
<div class="grid gap-1">
<details>
<summary class="interact">
<b style="font-size: 0.9rem;">Show QR code to scan</b>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" />
</svg>
</summary>
<div id="topup_wallet__qr_code"></div>
</details>
<div class="grid gap-0-5">
<h4>Transfer money</h4>
<ol type="1">
<li>
<p>
or send money to UPI ID below
Open your<strong> preferred UPI app </strong>
</p>
<sm-copy id="topup_wallet__upi_id" style="font-weight: 700;"></sm-copy>
</div>
</div>
<p>
After sending money, please enter the transaction ID of completed transaction. <br>
* <strong>PhonePe</strong> users please enter <strong>UTR ID</strong> instead of transaction ID
</p>
<sm-input id="topup_wallet__txid" minlength="12" maxlength="12"
error-text="Please enter UPI transaction ID of money you sent to continue."
placeholder="UPI transaction ID" autofocus animate required></sm-input>
</li>
<li>
<div class="grid gap-1">
<div class="grid gap-0-5">
<p>
Enter <strong> UPI ID </strong>below as recipient
</p>
<sm-copy id="topup_wallet__upi_id" style="font-weight: 700;"></sm-copy>
</div>
<details>
<summary class="interact">
<b style="font-size: 0.9rem;">Or get QR code to scan</b>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z" />
</svg>
</summary>
<div class="grid gap-0-5">
<div id="topup_wallet__qr_code"></div>
<p>
<strong>
*If you are paying by scanning the QR code, amount and remark/message will
be
added automatically.</strong>
</p>
</div>
</details>
</div>
</li>
<li>
<p id="topup_wallet__details"></p>
</li>
<li>
<div class="grid gap-0-5">
<p>
Enter <strong>code</strong> below in the <strong> message/remark </strong> field
</p>
<sm-copy id="topup_wallet__code" style="font-weight: 700;"></sm-copy>
<p>
<strong>*This is very important step. If you skip or enter wrong code, transaction can't
be
verified.</strong>
</p>
</div>
</li>
<li>
<p>
After sending money, press <b>Confirm</b>.
</p>
</li>
</ol>
<div class="multi-state-button">
<button id="topup_wallet_button" class="button button--primary cta" onclick="depositMoneyToWallet()"
type="submit">Confirm</button>
@ -947,7 +975,7 @@
</div>
<div class="multi-state-button">
<button id="withdraw_rupee_button" class="button button--primary cta"
onclick="withdrawMoneyFromWallet()" type="submit">Transfer</button>
onclick="withdrawMoneyFromWallet()" type="submit">Withdraw</button>
</div>
</sm-form>
<div class="grid gap-0-5 hide justify-center text-center">
@ -1089,14 +1117,18 @@
<b id="top_up_amount" style="font-size: 1.5rem;"></b>
</div>
<div class="grid">
<!-- <div class="grid">
<div class="label">UPI ID</div>
<sm-copy id="top_up_upi_id"></sm-copy>
</div>
</div> -->
<div class="grid">
<div class="label">Transaction code</div>
<sm-copy id="top_up__code"></sm-copy>
</div>
<!-- <div class="grid">
<div class="label">Transaction ID</div>
<sm-copy id="top_up_txid"></sm-copy>
</div>
</div> -->
<div class="flex justify-right gap-0-3">
<button class="button" onclick="showChildElement('confirm_topup_wrapper', 1)">Decline</button>
<div class="multi-state-button">
@ -1108,7 +1140,7 @@
<div class="grid gap-0-3">
<p>Select reason</p>
<sm-select id="top_up__reason_selector">
<sm-option value="1001">Invalid transaction ID</sm-option>
<sm-option value="1003">Transaction code mismatch</sm-option>
<sm-option value="1002">Amount doesn't match</sm-option>
<sm-option value="other">Other</sm-option>
</sm-select>

View File

@ -107,15 +107,16 @@ User.findCashier = function () {
}
}
User.cashToToken = function (cashier, amount, upiTxID, upiID) {
User.cashToToken = function (cashier, amount, txCode, upiID) {
return new Promise((resolve, reject) => {
if (!floGlobals.subAdmins.includes(cashier))
return reject("Invalid cashier");
floCloudAPI.sendGeneralData({
mode: "cash-to-token",
amount: amount,
upi_txid: upiTxID,
upiID
// upi_txid: upiTxID,
upiID,
txCode
}, TYPE_CASHIER_REQUEST, {
receiverID: cashier
}).then(result => resolve(result))
@ -232,7 +233,6 @@ Cashier.updateUPI = function (upi_id) {
.catch(error => reject(error))
})
}
Object.defineProperty(Cashier, 'Requests', {
get: function () {
let fk = floCloudAPI.util.filterKey(TYPE_CASHIER_REQUEST, {

View File

@ -41,31 +41,34 @@ function continueWalletTopup() {
let cashier = User.findCashier();
if (!cashier)
return notify("No cashier online. Please try again in a while.", 'error');
const upiId = getRef('select_topup_upi_id').value;
if (!upiId)
return notify("Please add the UPI ID which you'll use to send the money", 'error');
// const upiId = getRef('select_topup_upi_id').value;
const txCode = randomString(6);
getRef('topup_wallet__code').value = txCode;
// if (!upiId)
// return notify("Please add the UPI ID which you'll use to send the money", 'error');
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
renderElem(getRef('topup_wallet__details'), html`Send <b>${formatAmount(amount)}</b> from your UPI ID <b>${upiId}</b>`);
renderElem(getRef('topup_wallet__details'), html`Enter <b>${formatAmount(amount)}</b> as amount`);
getRef('topup_wallet__upi_id').value = cashierUPI[cashier];
getRef('topup_wallet__qr_code').innerHTML = ''
getRef('topup_wallet__qr_code').append(new QRCode({
msg: `upi://pay?pn=FLOPay&pa=${cashierUPI[cashier]}&am=${amount}`,
msg: `upi://pay?pn=FLOPay&pa=${cashierUPI[cashier]}&am=${amount}&tn=${txCode}`,
ecl: 'H'
}))
showChildElement('topup_wallet_process', 1)
getRef('topup_wallet__txid').focusIn();
// getRef('topup_wallet__txid').focusIn();
}
function depositMoneyToWallet() {
let cashier = User.findCashier();
if (!cashier)
return notify("No cashier online. Please try again in a while.", 'error');
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
let upiTxID = getRef('topup_wallet__txid').value.trim();
const upiId = getRef('select_topup_upi_id').value;
if (upiTxID === '')
return notify("Please enter UPI transaction ID", 'error');
// let upiTxID = getRef('topup_wallet__txid').value.trim();
const txCode = getRef('topup_wallet__code').value;
// const upiId = getRef('select_topup_upi_id').value;
// if (upiTxID === '')
// return notify("Please enter UPI transaction ID", 'error');
buttonLoader('topup_wallet_button', true);
User.cashToToken(cashier, amount, upiTxID, upiId).then(result => {
User.cashToToken(cashier, amount, txCode/* , upiId */).then(result => {
console.log(result);
showChildElement('topup_wallet_process', 2);
refreshBalance()
@ -153,8 +156,8 @@ function saveUpiId() {
if (pagesData.lastPage === 'settings') {
getRef('saved_upi_ids_list').append(render.savedUpiId(upiId));
} else if (pagesData.lastPage === 'home') {
getRef('select_topup_upi_id').append(render.savedUpiIdOption(upiId));
getRef('select_topup_upi_id').parentNode.classList.remove('hide')
// getRef('select_topup_upi_id').append(render.savedUpiIdOption(upiId));
// getRef('select_topup_upi_id').parentNode.classList.remove('hide')
getRef('select_withdraw_upi_id').append(render.savedUpiIdOption(upiId));
getRef('select_withdraw_upi_id').parentNode.classList.remove('hide')
}
@ -354,20 +357,24 @@ cashierUI.completeRequest = function (reqID) {
}
function completeCashToTokenRequest(request) {
const { message: { upi_txid, amount, upiID }, vectorClock, senderID } = request;
Cashier.checkIfUpiTxIsValid(upi_txid).then(_ => {
const { message: { upi_txid, amount, upiID, txCode }, vectorClock } = request;
getRef('top_up_amount').textContent = formatAmount(amount);
getRef('top_up_txid').value = upi_txid;
getRef('top_up_upi_id').value = upiID;
getRef('top_up__code').value = txCode;
showPopup('confirm_topup_popup');
}).catch(error => {
notify(error, 'error');
if (Array.isArray(error) && error[0] === true && typeof error[1] === 'string')
Cashier.rejectRequest(request, error[1]).then(result => {
console.log(result);
console.info('Rejected cash-to-token request:', vectorClock);
}).catch(error => console.error(error))
})
// Cashier.checkIfUpiTxIsValid(upi_txid).then(_ => {
// getRef('top_up_amount').textContent = formatAmount(amount);
// // getRef('top_up_txid').value = upi_txid;
// // getRef('top_up_upi_id').value = upiID;
// getRef('top_up__code').value = txCode;
// showPopup('confirm_topup_popup');
// }).catch(error => {
// notify(Array.isArray(error) ? error[1]: error, 'error');
// if (Array.isArray(error) && error[0] === true && typeof error[1] === 'string')
// Cashier.rejectRequest(request, error[1]).then(result => {
// console.log(result);
// console.info('Rejected cash-to-token request:', vectorClock);
// }).catch(error => console.error(error))
// })
}
function confirmTopUp(button) {
@ -485,7 +492,8 @@ function getStatusIcon(status) {
const cashierRejectionErrors = {
1001: `Your request was reject because of wrong transaction ID. If you have sent money, it'll be returned within 24 hrs.`,
1002: `Amount requested and amount sent via UPI doesn't match. your transferred money will be returned within 24hrs.`
1002: `Amount requested and amount sent via UPI doesn't match. your transferred money will be returned within 24hrs.`,
1003: `Your request was rejected because of wrong or missing remark/message code. If you have sent money, it'll be returned within 24 hrs.`,
}
const render = {

View File

@ -109,8 +109,8 @@ document.addEventListener('popupopened', async e => {
}
if (hasSavedIds) {
const clone = frag.cloneNode(true)
getRef('select_topup_upi_id').append(frag)
getRef('select_topup_upi_id').parentNode.classList.remove('hide')
// getRef('select_topup_upi_id').append(frag)
// getRef('select_topup_upi_id').parentNode.classList.remove('hide')
getRef('select_withdraw_upi_id').append(clone)
getRef('select_withdraw_upi_id').parentNode.classList.remove('hide')
}
@ -125,8 +125,8 @@ document.addEventListener('popupclosed', e => {
getRef('search_saved_ids_picker').value = ''
break;
case 'topup_wallet_popup':
getRef('select_topup_upi_id').parentNode.classList.add('hide')
getRef('select_topup_upi_id').innerHTML = ''
// getRef('select_topup_upi_id').parentNode.classList.add('hide')
// getRef('select_topup_upi_id').innerHTML = ''
showChildElement('topup_wallet_process', 0)
break;
case 'withdraw_wallet_popup':
@ -454,7 +454,7 @@ async function showPage(targetPage, options = {}) {
} else if (params.type === 'wallet') {
transactionDetails = User.cashierRequests[params.transactionId]
console.log(transactionDetails)
const { message: { amount, mode, upi_id, upi_txid, token_txid }, note, tag } = transactionDetails
const { message: { amount, mode, upi_id, upi_txid, token_txid, txCode }, note, tag } = transactionDetails
status = tag ? tag : (note ? 'REJECTED' : "PENDING");
getRef('transaction__type').textContent = mode === 'cash-to-token' ? 'Wallet top-up' : 'Withdraw';
if (status === 'COMPLETED') {
@ -466,9 +466,13 @@ async function showPage(targetPage, options = {}) {
}
if (mode === 'cash-to-token') {
if (status === 'COMPLETED') {
getRef('transaction__note').textContent = `UPI transaction ID: ${upi_txid}`
if (txCode) {
getRef('transaction__note').textContent = `Transaction code: ${txCode}`
} else if (upi_txid) {
getRef('transaction__note').textContent = `UPI Transaction ID: ${upi_txid}`
}
} else if (status === 'REJECTED') {
const reason = ['1001', '1002'].includes(note.split(':')[1]) ? cashierRejectionErrors[note.split(':')[1]] : note.split(':')[1]
const reason = cashierRejectionErrors.hasOwnProperty(note.split(':')[1]) ? cashierRejectionErrors[note.split(':')[1]] : note.split(':')[1]
getRef('transaction__note').innerHTML = `
<svg class="icon failed" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"></path><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></svg>
${reason}
@ -839,4 +843,16 @@ class SmState extends HTMLElement {
reactiveState.unsubscribe(this.getAttribute('sid'), this)
}
}
window.customElements.define('r-s', SmState);
window.customElements.define('r-s', SmState);
// generate random string with numbers and capital and small letters
function randomString(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}