Merge pull request #13 from ranchimall/ui-work

UI work
This commit is contained in:
sairaj mote 2022-04-23 01:37:18 +05:30 committed by GitHub
commit 1b63f7cd4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1452 additions and 1475 deletions

View File

@ -207,6 +207,10 @@ sm-form {
--gap: 1rem;
}
sm-select {
--padding: 0.8rem;
}
strip-select {
--gap: 0;
background-color: rgba(var(--text-color), 0.06);
@ -667,11 +671,6 @@ ul {
z-index: 1;
}
.clip {
-webkit-clip-path: circle(0);
clip-path: circle(0);
}
#home {
padding: 0;
position: relative;
@ -927,46 +926,24 @@ ul {
fill: rgba(var(--background-color), 1);
}
#transaction_result {
display: grid;
gap: 0.5rem;
height: max(40vh, 24rem);
align-items: center;
justify-content: center;
text-align: center;
align-content: center;
}
#transaction_result.success .icon--failed {
display: none;
}
#transaction_result.failed .icon--success {
display: none;
}
#transaction_result h3 {
text-align: center;
width: 100%;
}
#transaction_result .icon {
.user-action-result__icon {
justify-self: center;
height: 4rem;
width: 4rem;
border-radius: 5rem;
margin-bottom: 1rem;
margin-bottom: 2rem;
-webkit-animation: popup 1s;
animation: popup 1s;
}
#transaction_result .icon--success {
.user-action-result__icon.success {
fill: rgba(var(--background-color), 1);
padding: 1rem;
background-color: #0bbe56;
}
#transaction_result .icon--failed {
.user-action-result__icon.failed {
background-color: rgba(var(--text-color), 0.03);
fill: var(--danger-color);
}
#transaction_result sm-copy {
font-size: 0.8rem;
}
@-webkit-keyframes popup {
0% {
@ -1136,6 +1113,21 @@ ul {
margin-right: 0.5rem;
}
#saved_upi_ids_list {
display: grid;
gap: 0.5rem;
width: min(24rem, 100%);
}
.saved-upi {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem 0.4rem 0.4rem 1rem;
border-radius: 0.5rem;
background-color: rgba(var(--foreground-color), 1);
}
@media screen and (max-width: 40rem) {
#main_navbar.hide-away {
bottom: 0;
@ -1220,7 +1212,7 @@ ul {
@media screen and (min-width: 56rem) {
#main_card {
width: 56rem;
height: min(80vh, 48rem);
height: min(90vh, 48rem);
}
}
@media (any-hover: hover) {
@ -1244,11 +1236,11 @@ ul {
background-color: rgba(var(--text-color), 0.06);
}
button,
button:not([disabled]),
.button:not([disabled]) {
transition: background-color 0.3s, filter 0.3s;
}
button:hover,
button:not([disabled]):hover,
.button:not([disabled]):hover {
filter: contrast(2);
}

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,6 @@
box-sizing: border-box;
font-family: "Roboto", sans-serif;
}
:root {
font-size: clamp(1rem, 1.2vmax, 1.2rem);
}
@ -187,6 +186,9 @@ sm-spinner {
sm-form {
--gap: 1rem;
}
sm-select {
--padding: 0.8rem;
}
strip-select {
--gap: 0;
background-color: rgba(var(--text-color), 0.06);
@ -389,6 +391,7 @@ ul {
background-color: var(--accent-color);
}
}
.icon {
width: 1.2rem;
height: 1.2rem;
@ -624,9 +627,6 @@ ul {
z-index: 1;
}
}
.clip {
clip-path: circle(0);
}
#home {
padding: 0;
position: relative;
@ -871,48 +871,21 @@ ul {
fill: rgba(var(--background-color), 1);
}
}
#transaction_result {
display: grid;
gap: 0.5rem;
height: max(40vh, 24rem);
align-items: center;
justify-content: center;
text-align: center;
align-content: center;
.user-action-result__icon {
justify-self: center;
height: 4rem;
width: 4rem;
border-radius: 5rem;
margin-bottom: 2rem;
animation: popup 1s;
&.success {
.icon--failed {
display: none;
}
fill: rgba(var(--background-color), 1);
padding: 1rem;
background-color: #0bbe56;
}
&.failed {
.icon--success {
display: none;
}
}
h3 {
text-align: center;
width: 100%;
}
.icon {
justify-self: center;
height: 4rem;
width: 4rem;
border-radius: 5rem;
margin-bottom: 1rem;
animation: popup 1s;
&--success {
fill: rgba(var(--background-color), 1);
padding: 1rem;
background-color: #0bbe56;
}
&--failed {
background-color: rgba(var(--text-color), 0.03);
fill: var(--danger-color);
}
}
sm-copy {
font-size: 0.8rem;
background-color: rgba(var(--text-color), 0.03);
fill: var(--danger-color);
}
}
@keyframes popup {
@ -1073,6 +1046,19 @@ ul {
margin-right: 0.5rem;
}
}
#saved_upi_ids_list {
display: grid;
gap: 0.5rem;
width: min(24rem, 100%);
}
.saved-upi {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem 0.4rem 0.4rem 1rem;
border-radius: 0.5rem;
background-color: rgba(var(--foreground-color), 1);
}
@media screen and (max-width: 40rem) {
#main_navbar {
&.hide-away {
@ -1155,7 +1141,7 @@ ul {
@media screen and (min-width: 56rem) {
#main_card {
width: 56rem;
height: min(80vh, 48rem);
height: min(90vh, 48rem);
}
}
@media (any-hover: hover) {
@ -1178,7 +1164,7 @@ ul {
background-color: rgba(var(--text-color), 0.06);
}
}
button,
button:not([disabled]),
.button:not([disabled]) {
transition: background-color 0.3s, filter 0.3s;
&:hover {

View File

@ -642,7 +642,7 @@
<h1 class="h1" id="rupee_balance"></h1>
</div>
<div class="flex">
<button class="wallet-action" onclick="walletAction('deposit')">
<button class="wallet-action" onclick="showPopup('topup_wallet_popup')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
<path d="M0 0h24v24H0z" fill="none" />
@ -651,7 +651,7 @@
</svg>
Top-up wallet
</button>
<button class="wallet-action" onclick="walletAction('withdraw')">
<button class="wallet-action" onclick="showPopup('withdraw_wallet_popup')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
@ -789,12 +789,29 @@
transform="translate(-223.5 -209.52444)" fill="#cacaca" />
</svg>
</div>
<section class="grid gap-1">
<div class="grid">
<h5>My FLO ID</h5>
<sm-copy id="logged_in_user_id" style="font-size: 0.9rem;"></sm-copy>
<section class="grid gap-2">
<div class="grid gap-1">
<div class="grid">
<h5>My FLO ID</h5>
<sm-copy id="logged_in_user_id" style="font-size: 0.9rem;"></sm-copy>
</div>
<sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button>
</div>
<div class="grid gap-1">
<h4>My UPI IDs</h4>
<ul id="saved_upi_ids_list" class="observe-empty-state"></ul>
<div class="empty-state">
<p>Add your UPI IDs for easier access during transactions.</p>
</div>
<button class="button justify-self-start" onclick="showPopup('save_upi_popup')">
<svg class="icon margin-right-0-5" 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="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</svg>
Add UPI ID
</button>
</div>
<sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button>
</section>
<section class="admin-element grid gap-1">
<h4>Change UPI ID</h4>
@ -921,14 +938,14 @@
<sm-form>
<sm-input id="get_new_title" placeholder="Name" autofocus animate required></sm-input>
<div class="flex align-center space-between">
<button class="button icon-only" title="Delete this FLO ID?" onclick="deleteSaved()">
<button class="button icon-only" title="Delete this FLO ID?" onclick="deleteSavedId()">
<svg class="icon" 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 d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" />
</svg>
</button>
<button class="button button--primary cta" type="submit" onclick="saveChanges()">Save</button>
<button class="button button--primary cta" type="submit" onclick="saveIdChanges()">Save</button>
</div>
</sm-form>
</section>
@ -970,7 +987,7 @@
</sm-form>
</section>
</sm-popup>
<sm-popup id="wallet_popup">
<sm-popup id="topup_wallet_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
@ -981,27 +998,154 @@
</svg>
</button>
</header>
<sm-form>
<div class="grid gap-0-5">
<h4 id="wallet_popup__title"></h4>
<p id="request_description"></p>
</div>
<sm-input id="request_cashier_amount" type="number" min="1" error-text="Amount should al least be ₹1"
name="amount" placeholder="Amount" autofocus animate required>
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<div id="topup_wallet_process">
<sm-form id="get_topup_amount_form">
<div class="grid gap-0-5">
<h4>Top-up wallet</h4>
<p>Add money to your wallet</p>
</div>
<sm-input id="request_cashier_amount" type="number" min="1" error-text="Amount should al least be ₹1"
name="amount" placeholder="Amount" autofocus animate required>
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<path
d="M13.66,7C13.1,5.82,11.9,5,10.5,5L6,5V3h12v2l-3.26,0c0.48,0.58,0.84,1.26,1.05,2L18,7v2l-2.02,0c-0.25,2.8-2.61,5-5.48,5 H9.77l6.73,7h-2.77L7,14v-2h3.5c1.76,0,3.22-1.3,3.46-3L6,9V7L13.66,7z" />
<rect fill="none" height="24" width="24" />
</g>
</g>
<g>
<g>
<path
d="M13.66,7C13.1,5.82,11.9,5,10.5,5L6,5V3h12v2l-3.26,0c0.48,0.58,0.84,1.26,1.05,2L18,7v2l-2.02,0c-0.25,2.8-2.61,5-5.48,5 H9.77l6.73,7h-2.77L7,14v-2h3.5c1.76,0,3.22-1.3,3.46-3L6,9V7L13.66,7z" />
</g>
</g>
</svg>
</sm-input>
<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>
<sm-copy id="topup_wallet__upi_id" style="font-weight: 700;"></sm-copy>
<p>After sending money, please enter the UPI transaction ID of completed transfer.</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>
<div class="multi-state-button">
<button id="topup_wallet_button" class="button button--primary cta" onclick="depositMoneyToWallet()"
type="submit">Confirm</button>
</div>
</sm-form>
<div class="grid gap-0-5 hide justify-center text-center">
<svg class="icon user-action-result__icon success" 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="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
</svg>
</sm-input>
<button id="wallet_popup__cta" class="button button--primary cta" type="submit">Continue</button>
<h4>Sent top-up request</h4>
<p>This may take upto 30 mins to complete</p>
</div>
<div class="grid gap-0-5 hide justify-center text-center">
<svg class="icon user-action-result__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
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" />
</svg>
<h4>Failed to top-up wallet</h4>
<p id="topup_failed_reason"></p>
</div>
</div>
</sm-popup>
<sm-popup id="withdraw_wallet_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
<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="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg>
</button>
</header>
<div id="withdraw_wallet_process">
<sm-form>
<div class="grid gap-0-5">
<h4>Transfer to bank</h4>
<p>Money will be sent to your bank account linked to selected UPI ID</p>
</div>
<sm-input id="send_cashier_amount" type="number" min="1" error-text="Amount should al least be ₹1"
name="amount" placeholder="Amount" autofocus animate required>
<svg class="icon" slot="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<g>
<path
d="M13.66,7C13.1,5.82,11.9,5,10.5,5L6,5V3h12v2l-3.26,0c0.48,0.58,0.84,1.26,1.05,2L18,7v2l-2.02,0c-0.25,2.8-2.61,5-5.48,5 H9.77l6.73,7h-2.77L7,14v-2h3.5c1.76,0,3.22-1.3,3.46-3L6,9V7L13.66,7z" />
</g>
</g>
</svg>
</sm-input>
<div class="grid gap-0-5 hide">
<p>
<b>Select UPI ID to receive money</b>
</p>
<sm-select id="select_upi_id"></sm-select>
</div>
<button class="button" onclick="showPopup('save_upi_popup')">
<svg class="icon margin-right-0-5" 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="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</svg>
Add UPI ID
</button>
<div class="multi-state-button">
<button id="withdraw_rupee_button" class="button button--primary cta"
onclick="withdrawMoneyFromWallet()" type="submit">Transfer</button>
</div>
</sm-form>
<div class="grid gap-0-5 hide justify-center text-center">
<svg class="icon user-action-result__icon success" 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="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
</svg>
<h4>Sent transfer to bank request</h4>
<p>This may take upto 30 mins to complete</p>
</div>
<div class="grid gap-0-5 hide justify-center text-center">
<svg class="icon user-action-result__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
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" />
</svg>
<h4>Failed to request</h4>
<p id="withdrawal_failed_reason"></p>
</div>
</div>
</sm-popup>
<sm-popup id="save_upi_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
<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="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
</svg>
</button>
<h4>Save UPI ID</h4>
</header>
<sm-form>
<sm-input id="get_upi_id" placeholder="UPI ID" pattern="[a-zA-Z0-9_]{3,}@[a-zA-Z]{3,}"
error-text="Invalid UPI ID" autofocus animate required></sm-input>
<button class="button button--primary cta" onclick="saveUpiId()" type="submit">Save</button>
</sm-form>
</sm-popup>
@ -1101,6 +1245,20 @@
<time class="transaction-message__time"></time>
</li>
</template>
<template id="saved_upi_template">
<li class="saved-upi">
<div class="saved-upi__id"></div>
<button class="delete-upi" title="Delete this UPI ID">
<svg class="icon" 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 d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" />
</svg>
</button>
</li>
</template>
<script src="scripts/components.js"></script>
<script src="scripts/std_ui.js"></script>
<script src="scripts/std_op.js"></script>
@ -1111,8 +1269,12 @@
showPage('loading')
console.log("Starting the app! Please Wait!")
floDapps.setCustomPrivKeyInput(getSignedIn)
floDapps.setAppObjectStores({ savedIds: {} })
floDapps.setAppObjectStores({ savedIds: {}, savedUserData: {} })
floDapps.launchStartUp().then(result => {
floGlobals.savedIds = {};
floGlobals.savedUserData = {
upiIds: {}
}
console.log(`Welcome ${myFloID}`);
getRef('logged_in_user_id').value = myFloID;
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
@ -1139,6 +1301,7 @@
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hide'))
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hide'))
showPage(window.location.hash, { firstLoad: true })
floGlobals.loaded = true
}).catch(error => console.error(error))
}
}).catch(error => console.error(error))

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@ User.init = function () {
}));
*/
promises.push(User.getCashierUPI());
promises.push(organizeSyncedData('savedUserData'));
Promise.all(promises)
.then(result => resolve(result))
.catch(error => reject(error))
@ -86,7 +87,6 @@ User.findCashier = function () {
if (!online.length)
return null;
else {
console.log(online);
const random = floCrypto.randInt(0, online.length - 1)
return online[random];
}

View File

@ -9,49 +9,148 @@
!function (e, t) { var o = o || {}; "function" == typeof o && o.amd ? o([], t) : "object" == typeof exports && "object" == typeof module ? module.exports = t() : "object" == typeof exports ? exports.RelativeTime = t() : e.RelativeTime = t() }(this, (function () { const e = { year: 31536e6, month: 2628e6, day: 864e5, hour: 36e5, minute: 6e4, second: 1e3 }, t = "en", o = { numeric: "auto" }; function n(e) { e = { locale: (e = e || {}).locale || t, options: { ...o, ...e.options } }, this.rtf = new Intl.RelativeTimeFormat(e.locale, e.options) } return n.prototype = { from(t, o) { const n = t - (o || new Date); for (let t in e) if (Math.abs(n) > e[t] || "second" == t) return this.rtf.format(Math.round(n / e[t]), t) } }, n }));
const relativeTime = new RelativeTime({ style: 'narrow' });
const userUI = {};
let walletActionType = null;
getRef('wallet_popup__cta').addEventListener('click', function () {
let cashier = User.findCashier();
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
if (walletActionType === 'deposit') {
//get UPI txid from user
let upiTxID = prompt(`Send Rs. ${amount} to ${cashierUPI[cashier]} and enter UPI txid`);
if (!upiTxID)
return;
User.cashToToken(cashier, amount, upiTxID).then(result => {
console.log(result);
notify("Requested cashier. please wait!");
}).catch(error => console.error(error))
function syncUserData(obsName, data) {
const dataToSend = Crypto.AES.encrypt(JSON.stringify(data), myPrivKey);
return floCloudAPI.sendApplicationData(dataToSend, obsName, { receiverID: myFloID });
}
async function organizeSyncedData(obsName) {
const fetchedData = await floCloudAPI.requestApplicationData(obsName, { mostRecent: true, senderIDs: [myFloID], receiverID: myFloID });
if (fetchedData.length && await compactIDB.readData(obsName, 'lastSyncTime') !== fetchedData[0].time) {
await compactIDB.clearData(obsName);
const dataToDecrypt = floCloudAPI.util.decodeMessage(fetchedData[0].message);
const decryptedData = JSON.parse(Crypto.AES.decrypt(dataToDecrypt, myPrivKey));
for (let key in decryptedData) {
floGlobals[obsName][key] = decryptedData[key];
compactIDB.addData(obsName, decryptedData[key], key);
}
compactIDB.addData(obsName, fetchedData[0].time, 'lastSyncTime');
return true;
} else {
//get confirmation from user
let upiID = prompt(`${amount} ${floGlobals.currency}# will be sent to ${cashier}. Enter UPI ID`);
if (!upiID)
return;
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
User.tokenToCash(cashier, amount, txid, upiID).then(result => {
console.log(result);
notify("Requested cashier. please wait!");
}).catch(error => console.error(error))
}).catch(error => console.error(error))
const idbData = await compactIDB.readAllData(obsName);
for (const key in idbData) {
if (key !== 'lastSyncTime')
floGlobals[obsName][key] = idbData[key];
}
return true;
}
})
function walletAction(type) {
walletActionType = type;
}
const userUI = {};
function continueWalletTopup() {
let cashier = User.findCashier();
if (!cashier)
return notify("No cashier online. Please try again in a while.", 'error');
if (type === 'deposit') {
getRef('wallet_popup__title').textContent = 'Top-up wallet';
getRef('request_description').textContent = 'Add money to your wallet';
} else {
getRef('wallet_popup__title').textContent = 'Transfer to bank';
getRef('request_description').textContent = 'Money will be sent to your bank account linked to given UPI ID';
}
showPopup('wallet_popup')
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
getRef('topup_wallet__details').innerHTML = `Send <b>${formatAmount(amount)}</b> to UPI ID below`;
getRef('topup_wallet__upi_id').value = cashierUPI[cashier];
showProcessStage('topup_wallet_process', 1)
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();
if (upiTxID === '')
return notify("Please enter UPI transaction ID", 'error');
buttonLoader('topup_wallet_button', true);
User.cashToToken(cashier, amount, upiTxID).then(result => {
console.log(result);
showProcessStage('topup_wallet_process', 2);
}).catch(error => {
console.error(error)
getRef('topup_failed_reason').textContent = error;
showProcessStage('topup_wallet_process', 3);
})
}
function withdrawMoneyFromWallet() {
let cashier = User.findCashier();
if (!cashier)
return notify("No cashier online. Please try again in a while.", 'error');
let amount = parseFloat(getRef('send_cashier_amount').value.trim());
const upiId = getRef('select_upi_id').value;
if (!upiId)
return notify("Please add an UPI ID to continue", 'error');
buttonLoader('withdraw_rupee_button', true);
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
User.tokenToCash(cashier, amount, txid, upiId).then(result => {
showProcessStage('withdraw_wallet_process', 1);
console.log(result);
}).catch(error => {
getRef('withdrawal_failed_reason').textContent = error;
showProcessStage('withdraw_wallet_process', 2);
console.error(error)
}).finally(() => {
buttonLoader('withdraw_rupee_button', false);
});
}).catch(error => {
getRef('withdrawal_failed_reason').textContent = error;
showProcessStage('withdraw_wallet_process', 2);
buttonLoader('withdraw_rupee_button', false);
console.error(error)
})
}
async function renderSavedUpiIds() {
const frag = document.createDocumentFragment();
for (const upiId in floGlobals.savedUserData.upiIds) {
frag.append(render.savedUpiId(upiId));
}
getRef('saved_upi_ids_list').innerHTML = '';
getRef('saved_upi_ids_list').append(frag);
}
function saveUpiId() {
const upiId = getRef('get_upi_id').value.trim();
if (upiId === '')
return notify("Please add an UPI ID to continue", 'error');
if (floGlobals.savedUserData.upiIds.hasOwnProperty(upiId))
return notify('This UPI ID is already saved', 'error');
floGlobals.savedUserData.upiIds[upiId] = {}
syncUserData('savedUserData', floGlobals.savedUserData).then(() => {
notify(`Saved ${upiId}`, 'success');
if (pagesData.lastPage === 'settings') {
getRef('saved_upi_ids_list').append(render.savedUpiId(upiId));
} else if (pagesData.lastPage === 'wallet') {
getRef('select_upi_id').append(
createElement('sm-option', {
textContent: upiId,
attributes: {
value: upiId,
}
})
)
getRef('select_upi_id').parentNode.classList.remove('hide')
}
hidePopup();
}).catch(error => {
notify(error, 'error');
})
}
delegate(getRef('saved_upi_ids_list'), 'click', '.saved-upi', e => {
if (e.target.closest('.delete-upi')) {
const upiId = e.delegateTarget.dataset.upiId;
getConfirmation('Do you want delete this UPI ID?', {
confirmText: 'Delete',
}).then(res => {
if (res) {
const toDelete = getRef('saved_upi_ids_list').querySelector(`.saved-upi[data-upi-id="${upiId}"]`);
if (toDelete)
toDelete.remove();
delete floGlobals.savedUserData.upiIds[upiId];
hidePopup();
syncUserData('savedUserData', floGlobals.savedUserData).then(() => {
notify(`Deleted UPI ID`, 'success');
}).catch(error => {
notify(error, 'error');
});
}
});
}
});
userUI.sendMoneyToUser = function (floID, amount, remark) {
getConfirmation('Confirm', { message: `Do you want to SEND ${amount} to ${floID}?` }).then(confirmation => {
@ -84,20 +183,25 @@ userUI.renderCashierRequests = function (requests, error = null) {
return;
if (pagesData.lastPage === 'wallet') {
for (let transactionID in requests) {
let oldCard = getRef('pending_wallet_transactions').querySelector(`[data-vc-${transactionID}]`);
if (oldCard) {
oldCard.remove()
getRef('wallet_history').prepend(render.walletRequestCard(requests[transactionID]))
}
const { note, tag } = requests[transactionID];
let status = tag ? 'done' : (note ? 'failed' : "pending");
getRef('wallet_history_wrapper').querySelectorAll(`[data-vc="${transactionID}"]`).forEach(card => card.remove());
getRef(status !== 'pending' ? 'wallet_history' : 'pending_wallet_transactions').prepend(render.walletRequestCard(requests[transactionID]))
}
}
};
delegate(getRef('wallet_history_wrapper'), 'click', '.wallet-request', e => {
let transactionID = e.delegateTarget.dataset.vc;
let request = User.cashierRequests[transactionID];
console.log(request)
})
const pendingTransactionsObserver = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
if (mutation.target.children.length)
mutation.target.parentNode.classList.remove('hide')
else
mutation.target.parentNode.classList.add('hide')
}
})
});
userUI.renderMoneyRequests = function (requests, error = null) {
if (error)
@ -106,9 +210,26 @@ userUI.renderMoneyRequests = function (requests, error = null) {
return;
if (pagesData.lastPage === 'requests') {
for (let r in requests) {
let oldCard = getRef('payment_request_history').querySelector(`[data-vc-${r}]`);
if (oldCard)
oldCard.replaceWith(render.paymentRequestCard(requests[r]));
getRef('requests_history_wrapper').querySelectorAll(`[data-vc="${r}"]`).forEach(card => card.remove());
if (requests[r].note) {
getRef('payment_request_history').prepend(render.paymentRequestCard(requests[r]));
} else {
getRef('pending_payment_requests').prepend(render.paymentRequestCard(requests[r]));
}
}
}
if (floGlobals.loaded) {
for (let r in requests) {
if (!requests[r].note) {
notify(`You have received payment request from ${getFloIdTitle(requests[r].senderID)}`, '', {
action: {
label: 'View',
callback: () => {
window.location.hash = `#/requests`
}
}
});
}
}
}
};
@ -335,9 +456,42 @@ const render = {
clone.querySelector('.transaction-message__amount').textContent = formatAmount(tokenAmount);
clone.querySelector('.transaction-message__time').textContent = getFormattedTime(time * 1000);
return clone;
},
savedUpiId(upiId) {
const clone = getRef('saved_upi_template').content.cloneNode(true).firstElementChild;
clone.dataset.upiId = upiId;
clone.querySelector('.saved-upi__id').textContent = upiId;
return clone;
}
};
function buttonLoader(id, show) {
getRef(id).disabled = show;
const animOptions = {
duration: 200,
fill: 'forwards',
easing: 'ease'
}
if (show) {
getRef(id).animate([
{
clipPath: 'circle(100%)',
},
{
clipPath: 'circle(0)',
},
], animOptions).onfinish = e => {
e.target.commitStyles()
e.target.cancel()
}
getRef(id).parentNode.append(createElement('sm-spinner'))
} else {
getRef(id).style = ''
const potentialTarget = getRef(id).parentNode.querySelector('sm-spinner')
if (potentialTarget) potentialTarget.remove();
}
}
let currentUserAction;
function showTokenTransfer(type) {
getRef('tt_button').textContent = type;
@ -351,35 +505,18 @@ function showTokenTransfer(type) {
}
function getArrayOfSavedIds() {
const arr = []
const arr = [];
for (const key in floGlobals.savedIds) {
arr.push({
floID: key,
details: floGlobals.savedIds[key]
})
});
}
return arr.sort((a, b) => a.details.title.localeCompare(b.details.title))
return arr.sort((a, b) => a.details.title.localeCompare(b.details.title));
}
userUI.renderSavedIds = async function () {
floGlobals.savedIds = {}
const frag = document.createDocumentFragment()
const savedIds = await floCloudAPI.requestApplicationData('savedIds', { mostRecent: true, senderIDs: [myFloID], receiverID: myFloID });
if (savedIds.length && await compactIDB.readData('savedIds', 'lastSyncTime') !== savedIds[0].time) {
await compactIDB.clearData('savedIds');
const dataToDecrypt = floCloudAPI.util.decodeMessage(savedIds[0].message)
const data = JSON.parse(Crypto.AES.decrypt(dataToDecrypt, myPrivKey));
for (let key in data) {
floGlobals.savedIds[key] = data[key];
compactIDB.addData('savedIds', data[key], key);
}
compactIDB.addData('savedIds', savedIds[0].time, 'lastSyncTime');
} else {
const idsToRender = await compactIDB.readAllData('savedIds');
for (const key in idsToRender) {
if (key !== 'lastSyncTime')
floGlobals.savedIds[key] = idsToRender[key];
}
}
const frag = document.createDocumentFragment();
await organizeSyncedData('savedIds');
getArrayOfSavedIds().forEach(({ floID, details }) => {
frag.append(render.savedId(floID, details));
})
@ -387,9 +524,11 @@ userUI.renderSavedIds = async function () {
}
async function saveId() {
const floID = getRef('flo_id_to_save').value.trim();
if (floGlobals.savedIds.hasOwnProperty(floID))
return notify('This FLO ID is already saved', 'error');
const title = getRef('flo_id_title_to_save').value.trim();
floGlobals.savedIds[floID] = { title }
syncSavedIds().then(() => {
syncUserData('savedIds', floGlobals.savedIds).then(() => {
insertElementAlphabetically(title, render.savedId(floID, { title }))
notify(`Saved ${floID}`, 'success');
hidePopup();
@ -397,10 +536,6 @@ async function saveId() {
notify(error, 'error');
})
}
function syncSavedIds() {
const dataToSend = Crypto.AES.encrypt(JSON.stringify(floGlobals.savedIds), myPrivKey);
return floCloudAPI.sendApplicationData(dataToSend, 'savedIds', { receiverID: myFloID });
}
delegate(getRef('saved_ids_list'), 'click', '.saved-id', e => {
if (e.target.closest('.edit-saved')) {
const target = e.target.closest('.saved-id');
@ -421,13 +556,13 @@ delegate(getRef('saved_ids_list'), 'click', '.saved-id', e => {
window.location.hash = `#/contact?floId=${target.dataset.floId}`;
}
});
function saveChanges() {
function saveIdChanges() {
const floID = getRef('edit_saved_id').value;
let title = getRef('get_new_title').value.trim();
if (title == '')
title = 'Unknown';
floGlobals.savedIds[floID] = { title }
syncSavedIds().then(() => {
syncUserData('savedIds', floGlobals.savedIds).then(() => {
const potentialTarget = getRef('saved_ids_list').querySelector(`.saved-id[data-flo-id="${floID}"]`)
if (potentialTarget) {
potentialTarget.querySelector('.saved-id__title').textContent = title;
@ -442,7 +577,7 @@ function saveChanges() {
notify(error, 'error');
})
}
function deleteSaved() {
function deleteSavedId() {
getConfirmation('Do you want delete this FLO ID?', {
confirmText: 'Delete',
}).then(res => {
@ -452,7 +587,7 @@ function deleteSaved() {
toDelete.remove();
delete floGlobals.savedIds[getRef('edit_saved_id').value];
hidePopup();
syncSavedIds().then(() => {
syncUserData('savedIds', floGlobals.savedIds).then(() => {
notify(`Deleted saved ID`, 'success');
}).catch(error => {
notify(error, 'error');
@ -495,8 +630,8 @@ function executeUserAction() {
}
function changeUpi() {
const upiID = getRef('upi_id').value.trim();
Cashier.updateUPI(upiID).then(() => {
const upiId = getRef('upi_id').value.trim();
Cashier.updateUPI(upiId).then(() => {
notify('UPI ID updated successfully', 'success');
}).catch(err => {
notify(err, 'error');

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/*jshint esversion: 6 */
/*jshint esversion: 9 */
// Global variables
const domRefs = {};
const currentYear = new Date().getFullYear();
@ -89,9 +89,9 @@ function hidePopup() {
}
document.addEventListener('popupopened', async e => {
const frag = document.createDocumentFragment()
switch (e.target.id) {
case 'saved_ids_popup':
const frag = document.createDocumentFragment()
const allSavedIds = await getArrayOfSavedIds()
allSavedIds.forEach(({ floID, name }) => {
frag.append(render.savedIdPickerCard(floID, name))
@ -100,7 +100,22 @@ document.addEventListener('popupopened', async e => {
getRef('saved_ids_picker_list').append(frag)
getRef('search_saved_ids_picker').focusIn()
break;
case 'get_private_key_popup':
case 'withdraw_wallet_popup':
let hasSavedIds = false
for (const upiId in floGlobals.savedUserData.upiIds) {
frag.append(createElement('sm-option', {
textContent: upiId,
attributes: {
value: upiId,
}
}))
hasSavedIds = true
}
if (hasSavedIds) {
getRef('select_upi_id').parentNode.classList.remove('hide')
getRef('select_upi_id').append(frag)
}
showProcessStage('withdraw_wallet_process', 0)
break;
}
})
@ -111,14 +126,12 @@ document.addEventListener('popupclosed', e => {
getRef('saved_ids_picker_list').innerHTML = ''
getRef('search_saved_ids_picker').value = ''
break;
case 'get_private_key_popup':
getRef('get_private_key').classList.remove('hide')
getRef('transaction_result').classList.add('hide')
getRef('confirm_transaction_button').classList.remove('hide')
getRef('confirm_transaction_button').nextElementSibling.classList.add('hide')
case 'topup_wallet_popup':
showProcessStage('topup_wallet_process', 0)
break;
case 'retrieve_flo_id_popup':
getRef('recovered_flo_id_wrapper').classList.add('hide')
case 'withdraw_wallet_popup':
getRef('select_upi_id').parentNode.classList.add('hide')
getRef('select_upi_id').innerHTML = ''
break;
}
})
@ -147,7 +160,6 @@ const getConfirmation = (title, options = {}) => {
//Function for displaying toast notifications. pass in error for mode param if you want to show an error.
function notify(message, mode, options = {}) {
const { pinned = false, sound = false } = options
let icon
switch (mode) {
case 'success':
@ -157,7 +169,7 @@ function notify(message, mode, options = {}) {
icon = `<svg class="icon icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>`
break;
}
getRef("notification_drawer").push(message, { pinned, icon });
getRef("notification_drawer").push(message, { icon, ...options });
if (mode === 'error') {
console.error(message)
}
@ -332,7 +344,7 @@ async function showPage(targetPage, options = {}) {
const paymentTransactions = []
if (paymentsHistoryLoader)
paymentsHistoryLoader.clear()
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>'
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>';
tokenAPI.getAllTxs(myFloID).then(({ transactions }) => {
for (const transactionId in transactions) {
paymentTransactions.push({
@ -341,21 +353,21 @@ async function showPage(targetPage, options = {}) {
})
}
if (paymentsHistoryLoader) {
paymentsHistoryLoader.update(paymentTransactions)
paymentsHistoryLoader.update(paymentTransactions);
} else {
paymentsHistoryLoader = new LazyLoader('#payments_history', paymentTransactions, render.transactionCard);
}
paymentsHistoryLoader.init()
paymentsHistoryLoader.init();
}).catch(e => {
console.error(e)
})
break;
case 'requests':
const paymentRequests = []
const paymentRequests = [];
if (paymentRequestsLoader)
paymentRequestsLoader.clear()
paymentRequestsLoader.clear();
const pendingPaymentRequests = document.createDocumentFragment()
const pendingPaymentRequests = document.createDocumentFragment();
let arePaymentsPending = false
for (const transactionId in User.moneyRequests) {
if (!User.moneyRequests[transactionId].note) {
@ -365,17 +377,15 @@ async function showPage(targetPage, options = {}) {
paymentRequests.unshift(User.moneyRequests[transactionId])
}
}
if (arePaymentsPending) {
getRef('pending_payment_requests').innerHTML = ''
getRef('pending_payment_requests').append(pendingPaymentRequests)
getRef('pending_payment_requests').parentNode.classList.remove('hide')
} else {
getRef('pending_payment_requests').parentNode.classList.add('hide')
}
if (paymentRequestsLoader) {
paymentRequestsLoader.update(paymentRequests)
} else {
paymentRequestsLoader = new LazyLoader('#payment_request_history', paymentRequests, render.paymentRequestCard);
pendingTransactionsObserver.observe(getRef('pending_payment_requests'), { childList: true });
}
if (arePaymentsPending) {
getRef('pending_payment_requests').innerHTML = ''
getRef('pending_payment_requests').append(pendingPaymentRequests)
}
paymentRequestsLoader.init()
break;
@ -391,20 +401,18 @@ async function showPage(targetPage, options = {}) {
areTransactionsPending = true
pendingWalletTransactions.prepend(render.walletRequestCard(User.cashierRequests[transactionId]))
} else {
walletTransactions.push(User.cashierRequests[transactionId])
walletTransactions.unshift(User.cashierRequests[transactionId])
}
}
if (areTransactionsPending) {
getRef('pending_wallet_transactions').innerHTML = ''
getRef('pending_wallet_transactions').append(pendingWalletTransactions)
getRef('pending_wallet_transactions').parentNode.classList.remove('hide')
} else {
getRef('pending_wallet_transactions').parentNode.classList.add('hide')
}
if (walletHistoryLoader) {
walletHistoryLoader.update(walletTransactions)
} else {
walletHistoryLoader = new LazyLoader('#wallet_history', walletTransactions, render.walletRequestCard);
pendingTransactionsObserver.observe(getRef('pending_wallet_transactions'), { childList: true });
}
if (areTransactionsPending) {
getRef('pending_wallet_transactions').innerHTML = ''
getRef('pending_wallet_transactions').append(pendingWalletTransactions)
}
walletHistoryLoader.init()
break;
@ -427,7 +435,6 @@ async function showPage(targetPage, options = {}) {
getRef('transaction__remark').textContent = remark
getRef('transaction__remark').classList.remove('hide')
}
console.log(status)
} else if (params.type === 'wallet') {
transactionDetails = User.cashierRequests[params.transactionId]
const { message: { amount, mode, upi_id, upi_txid }, note, tag } = transactionDetails
@ -453,12 +460,14 @@ async function showPage(targetPage, options = {}) {
getRef('transaction__note').classList.remove('hide')
}
}
const { message: { amount, remark }, note, senderID, receiverID, time } = transactionDetails
console.table(transactionDetails)
const { message: { amount }, time } = transactionDetails
getRef('transaction__time').textContent = getFormattedTime(time)
getRef('transaction__amount').textContent = formatAmount(amount)
getRef('transaction__status').textContent = status
break;
case 'settings':
renderSavedUpiIds()
break;
default:
break;
}
@ -474,6 +483,9 @@ async function showPage(targetPage, options = {}) {
if (walletHistoryLoader)
walletHistoryLoader.clear()
}
if (pageId !== 'settings') {
getRef('saved_upi_ids_list').innerHTML = '';
}
if (pagesData.lastPage !== pageId) {
const animOptions = {
@ -721,4 +733,13 @@ function handleMobileChange(e) {
isMobileView = e.matches
}
mobileQuery.addEventListener('change', handleMobileChange)
handleMobileChange(mobileQuery)
handleMobileChange(mobileQuery)
function showProcessStage(id, index) {
[...getRef(id).children].forEach((child, i) => {
if (i === index)
child.classList.remove('hide')
else
child.classList.add('hide')
})
}