merging cloud and blockchain kyc
This commit is contained in:
parent
c9baa64cf9
commit
5c5785d84b
@ -396,10 +396,14 @@ h3 {
|
|||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.justify-center {
|
.justify-content-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.justify-items-center {
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.justify-right {
|
.justify-right {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -364,9 +364,12 @@ h3 {
|
|||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.justify-center {
|
.justify-content-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.justify-items-center {
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.justify-right {
|
.justify-right {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|||||||
311
index.html
311
index.html
@ -206,33 +206,37 @@
|
|||||||
this.routes[route] = callback
|
this.routes[route] = callback
|
||||||
}
|
}
|
||||||
async routeTo(path) {
|
async routeTo(path) {
|
||||||
let page
|
try {
|
||||||
let wildcards = []
|
let page
|
||||||
let queryString
|
let wildcards = []
|
||||||
let params
|
let queryString
|
||||||
[path, queryString] = path.split('?');
|
let params
|
||||||
if (path.includes('#'))
|
[path, queryString] = path.split('?');
|
||||||
path = path.split('#')[1];
|
if (path.includes('#'))
|
||||||
if (path.includes('/'))
|
path = path.split('#')[1];
|
||||||
[, page, ...wildcards] = path.split('/')
|
if (path.includes('/'))
|
||||||
else
|
[, page, ...wildcards] = path.split('/')
|
||||||
page = path
|
else
|
||||||
this.state = { page, wildcards }
|
page = path
|
||||||
if (queryString) {
|
this.state = { page, wildcards }
|
||||||
params = new URLSearchParams(queryString)
|
if (queryString) {
|
||||||
this.state.params = Object.fromEntries(params)
|
params = new URLSearchParams(queryString)
|
||||||
}
|
this.state.params = Object.fromEntries(params)
|
||||||
if (this.routingStart) {
|
}
|
||||||
this.routingStart(this.state)
|
if (this.routingStart) {
|
||||||
}
|
this.routingStart(this.state)
|
||||||
if (this.routes[page]) {
|
}
|
||||||
await this.routes[page](this.state)
|
if (this.routes[page]) {
|
||||||
this.state.lastPage = page
|
await this.routes[page](this.state)
|
||||||
} else {
|
this.state.lastPage = page
|
||||||
this.routes['404'](this.state)
|
} else {
|
||||||
}
|
this.routes['404'](this.state)
|
||||||
if (this.routingEnd) {
|
}
|
||||||
this.routingEnd(this.state)
|
if (this.routingEnd) {
|
||||||
|
this.routingEnd(this.state)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,7 +334,6 @@
|
|||||||
clipPath: 'circle(100%)',
|
clipPath: 'circle(100%)',
|
||||||
},
|
},
|
||||||
], animOptions).onfinish = () => {
|
], animOptions).onfinish = () => {
|
||||||
button.getAnimations().forEach(anim => anim.cancel())
|
|
||||||
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
const potentialTarget = button.parentNode.querySelector('sm-spinner')
|
||||||
if (potentialTarget) potentialTarget.remove();
|
if (potentialTarget) potentialTarget.remove();
|
||||||
}
|
}
|
||||||
@ -376,6 +379,7 @@
|
|||||||
history.scrollRestoration = "manual";
|
history.scrollRestoration = "manual";
|
||||||
}
|
}
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
renderElem(getRef('app_body'), html``);
|
||||||
},
|
},
|
||||||
routingEnd() {
|
routingEnd() {
|
||||||
document.querySelectorAll(".my-flo-address").forEach(elem => {
|
document.querySelectorAll(".my-flo-address").forEach(elem => {
|
||||||
@ -474,11 +478,17 @@
|
|||||||
'driving_license': 'Driving License',
|
'driving_license': 'Driving License',
|
||||||
}
|
}
|
||||||
const btcAddresses = {}
|
const btcAddresses = {}
|
||||||
|
const floAddresses = {}
|
||||||
function getBtcAddress(floAddress) {
|
function getBtcAddress(floAddress) {
|
||||||
if (!btcAddresses[floAddress])
|
if (!btcAddresses[floAddress])
|
||||||
btcAddresses[floAddress] = btcOperator.convert.legacy2bech(floAddress)
|
btcAddresses[floAddress] = btcOperator.convert.legacy2bech(floAddress)
|
||||||
return btcAddresses[floAddress]
|
return btcAddresses[floAddress]
|
||||||
}
|
}
|
||||||
|
function getFloAddress(btcAddress) {
|
||||||
|
if (!floAddresses[btcAddress])
|
||||||
|
floAddresses[btcAddress] = floCrypto.toFloID(btcAddress)
|
||||||
|
return floAddresses[btcAddress]
|
||||||
|
}
|
||||||
const render = {
|
const render = {
|
||||||
approvedKycAddresses() {
|
approvedKycAddresses() {
|
||||||
const approvedKycAddresses = Object.keys(floGlobals.approvedKyc)
|
const approvedKycAddresses = Object.keys(floGlobals.approvedKyc)
|
||||||
@ -487,7 +497,7 @@
|
|||||||
renderElem(getRef('approved_addresses'), html`${approvedKycAddresses}`)
|
renderElem(getRef('approved_addresses'), html`${approvedKycAddresses}`)
|
||||||
},
|
},
|
||||||
approvedAggregatorCard(address) {
|
approvedAggregatorCard(address) {
|
||||||
const floID = floCrypto.toFloID(address)
|
const floID = getFloAddress(address)
|
||||||
const btcID = getBtcAddress(floID)
|
const btcID = getBtcAddress(floID)
|
||||||
return html`
|
return html`
|
||||||
<li class="revoke-card" data-address=${btcID} data-search-key=${`${floGlobals.approvedKycAggregators[address]}-${btcID}-${floID}`}>
|
<li class="revoke-card" data-address=${btcID} data-search-key=${`${floGlobals.approvedKycAggregators[address]}-${btcID}-${floID}`}>
|
||||||
@ -510,8 +520,9 @@
|
|||||||
renderElem(getRef('approved_addresses'), html`${approvedAggregators}`)
|
renderElem(getRef('approved_addresses'), html`${approvedAggregators}`)
|
||||||
},
|
},
|
||||||
pendingKycRequest(request) {
|
pendingKycRequest(request) {
|
||||||
console.log(request)
|
|
||||||
const { senderID, time, files } = request;
|
const { senderID, time, files } = request;
|
||||||
|
const floAddress = getFloAddress(senderID)
|
||||||
|
const btcAddress = getBtcAddress(floAddress)
|
||||||
const fileButtons = files.map(file => {
|
const fileButtons = files.map(file => {
|
||||||
const { message: { docType, docVectorClock }, vectorClock } = file;
|
const { message: { docType, docVectorClock }, vectorClock } = file;
|
||||||
return html`
|
return html`
|
||||||
@ -527,18 +538,19 @@
|
|||||||
<time>${getFormattedTime(time)}</time>
|
<time>${getFormattedTime(time)}</time>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<p>BTC Address</p>
|
<p>BTC Address</p>
|
||||||
<sm-copy value=${getBtcAddress(senderID)}></sm-copy>
|
<sm-copy value=${btcAddress}></sm-copy>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<p>FLO Address</p>
|
<p>FLO Address</p>
|
||||||
<sm-copy value=${senderID}></sm-copy>
|
<sm-copy value=${floAddress}></sm-copy>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-1 flex-wrap">${fileButtons}</div>
|
<div class="flex gap-1 flex-wrap">${fileButtons}</div>
|
||||||
</li>`
|
</li>`
|
||||||
},
|
},
|
||||||
approvedKycRequest(request) {
|
approvedKycRequest(request) {
|
||||||
const { senderID, time, files } = request;
|
const { senderID, time, files } = request;
|
||||||
const btcID = getBtcAddress(senderID)
|
const floAddress = getFloAddress(senderID)
|
||||||
|
const btcAddress = getBtcAddress(floAddress)
|
||||||
const fileButtons = files.map(file => {
|
const fileButtons = files.map(file => {
|
||||||
const { message: { docType, docVectorClock }, vectorClock } = file;
|
const { message: { docType, docVectorClock }, vectorClock } = file;
|
||||||
return html`
|
return html`
|
||||||
@ -550,12 +562,12 @@
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
return html`
|
return html`
|
||||||
<li class="revoke-card" .dataset=${{ address: senderID, requestVC: vectorClock, docVC: docVectorClock }}>
|
<li class="revoke-card" .dataset=${{ address: floAddress, requestVC: vectorClock, docVC: docVectorClock }}>
|
||||||
<label class="flex align-center">
|
<label class="flex align-center">
|
||||||
<input type="checkbox" value=${senderID}/>
|
<input type="checkbox" value=${floAddress}/>
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<span class="wrap-around">BTC: ${btcID}</span>
|
<span class="wrap-around">BTC: ${btcAddress}</span>
|
||||||
<span class="wrap-around">FLO: ${senderID}</span>
|
<span class="wrap-around">FLO: ${floAddress}</span>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="flex gap-1 flex-wrap">${fileButtons}</div>
|
<div class="flex gap-1 flex-wrap">${fileButtons}</div>
|
||||||
@ -563,65 +575,78 @@
|
|||||||
`
|
`
|
||||||
},
|
},
|
||||||
rejectedKycRequest(request) {
|
rejectedKycRequest(request) {
|
||||||
const { senderID, time, message: { docType, docVectorClock }, vectorClock } = request;
|
const { senderID, time, files } = request;
|
||||||
const btcID = getBtcAddress(senderID)
|
const floAddress = getFloAddress(senderID)
|
||||||
|
const btcAddress = getBtcAddress(floAddress)
|
||||||
return html`
|
return html`
|
||||||
<li class="kyc-request" .dataset=${{ requestVC: vectorClock, docVC: docVectorClock }}>
|
<li class="kyc-request">
|
||||||
<time>${getFormattedTime(time)}</time>
|
<div class="flex space-between gap-1 space-between">
|
||||||
<h4>${docTypeNames[docType]}</h4>
|
<time>${getFormattedTime(time)}</time>
|
||||||
|
<div class="flex gap-0-3 align-center">
|
||||||
|
<svg class="icon"style="fill: var(--danger-color)" 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="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zM4 12c0-4.42 3.58-8 8-8 1.85 0 3.55.63 4.9 1.69L5.69 16.9C4.63 15.55 4 13.85 4 12zm8 8c-1.85 0-3.55-.63-4.9-1.69L18.31 7.1C19.37 8.45 20 10.15 20 12c0 4.42-3.58 8-8 8z"/></svg>
|
||||||
|
<b>Rejected</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grid gap-1">
|
<div class="grid gap-1">
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<p>FLO address</p>
|
<p>FLO address</p>
|
||||||
<sm-copy value=${senderID}></sm-copy>
|
<sm-copy value=${floAddress}></sm-copy>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid gap-0-3">
|
<div class="grid gap-0-3">
|
||||||
<p>BTC address</p>
|
<p>BTC address</p>
|
||||||
<sm-copy value=${btcID}></sm-copy>
|
<sm-copy value=${btcAddress}></sm-copy>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>`
|
</li>`
|
||||||
},
|
},
|
||||||
kycRequests(options = {}) {
|
kycRequests(options = {}) {
|
||||||
const { status, address } = options;
|
const { status = 'pending', address } = options;
|
||||||
const kycRequests = floDapps.getNextGeneralData('userKycRequests', '0');
|
const kycRequests = floDapps.getNextGeneralData('userKycRequests', '0');
|
||||||
const filteredRequests = {};
|
const filteredRequests = {};
|
||||||
|
// group requests by senderID
|
||||||
for (const [key, request] of Object.entries(kycRequests)) {
|
for (const [key, request] of Object.entries(kycRequests)) {
|
||||||
const { message, senderID, time, tag, vectorClock } = request;
|
const { message, senderID, time, tag, vectorClock, note } = request;
|
||||||
if (!filteredRequests[senderID]) {
|
const floAddress = getFloAddress(senderID)
|
||||||
filteredRequests[senderID] = {
|
if (!filteredRequests[floAddress]) {
|
||||||
|
filteredRequests[floAddress] = {
|
||||||
time,
|
time,
|
||||||
tag: tag === 'approved' ? 'approved' : tag,
|
tag: tag === 'approved' ? 'approved' : tag,
|
||||||
files: []
|
files: [],
|
||||||
|
note
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
filteredRequests[senderID].files.push({ message, vectorClock });
|
filteredRequests[floAddress].files.push({ message, vectorClock });
|
||||||
}
|
}
|
||||||
const result = [];
|
const result = []
|
||||||
for (const [senderID, request] of Object.entries(filteredRequests)) {
|
Object.entries(filteredRequests).forEach(([senderID, request]) => {
|
||||||
const { time, tag, files } = request;
|
const { time, tag, files, note } = request;
|
||||||
|
const floAddress = getFloAddress(senderID)
|
||||||
if (status) {
|
if (status) {
|
||||||
if (status === 'approved' && tag !== 'approved') continue;
|
switch (status) {
|
||||||
if (status === 'rejected' && tag !== 'rejected') continue;
|
case 'approved':
|
||||||
if (status === 'pending' && tag) continue;
|
if (tag !== 'approved') return;
|
||||||
|
break;
|
||||||
|
case 'rejected':
|
||||||
|
if (note !== 'rejected') return;
|
||||||
|
break;
|
||||||
|
case 'pending':
|
||||||
|
if (tag || note) return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (address) {
|
if (address) {
|
||||||
const equivalentBtcAddress = getBtcAddress(senderID);
|
|
||||||
const senderAddress = senderID.toLowerCase();
|
|
||||||
const query = address.toLowerCase();
|
const query = address.toLowerCase();
|
||||||
if (!senderAddress.includes(query) && !equivalentBtcAddress.includes(query)) continue;
|
if (!floAddress.toLowerCase().includes(query) && !getBtcAddress(floAddress).toLowerCase().includes(query)) return;
|
||||||
}
|
}
|
||||||
switch (tag) {
|
switch (tag || note) {
|
||||||
case 'approved':
|
case 'approved':
|
||||||
result.push(render.approvedKycRequest({ senderID, time, tag, files }));
|
return result.push(render.approvedKycRequest({ senderID: floAddress, time, tag, files }));
|
||||||
break;
|
|
||||||
case 'rejected':
|
case 'rejected':
|
||||||
result.push(render.rejectedKycRequest({ senderID, time, tag, files }));
|
return result.push(render.rejectedKycRequest({ senderID: floAddress, time, tag, files }));
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
result.push(render.pendingKycRequest({ senderID, time, tag, files }));
|
return result.push(render.pendingKycRequest({ senderID: floAddress, time, tag, files }));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
return result.reverse();
|
return result.reverse();
|
||||||
},
|
},
|
||||||
userRequests() {
|
userRequests() {
|
||||||
@ -656,7 +681,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let userAddressTimeInterval;
|
let userAddressTimeInterval;
|
||||||
function renderHome() {
|
function renderHome(appState) {
|
||||||
|
const { params: { filter = 'pending', search } = {} } = appState || {};
|
||||||
const mainHeader = html`
|
const mainHeader = html`
|
||||||
<header id="main_header">
|
<header id="main_header">
|
||||||
<div class="app-brand margin-right-auto hide-on-small">
|
<div class="app-brand margin-right-auto hide-on-small">
|
||||||
@ -675,7 +701,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
`;
|
`;
|
||||||
const renderedKycRequests = render.kycRequests();
|
const renderedKycRequests = render.kycRequests({ status: filter, address: search });
|
||||||
if (floGlobals.isSubAdmin) {
|
if (floGlobals.isSubAdmin) {
|
||||||
renderElem(getRef('app_body'), html`
|
renderElem(getRef('app_body'), html`
|
||||||
<article id="home_page">
|
<article id="home_page">
|
||||||
@ -684,10 +710,10 @@
|
|||||||
<div id="kyc_requests_header" class="flex align-center space-between gap-1 flex-wrap">
|
<div id="kyc_requests_header" class="flex align-center space-between gap-1 flex-wrap">
|
||||||
<h3>KYC requests</h3>
|
<h3>KYC requests</h3>
|
||||||
<sm-chips id="kyc_request_filter" onchange=${handleRequestFilter}>
|
<sm-chips id="kyc_request_filter" onchange=${handleRequestFilter}>
|
||||||
<sm-chip value="pending" selected>Pending</sm-chip>
|
<sm-chip value="pending" ?selected=${filter === "pending"}>Pending</sm-chip>
|
||||||
<sm-chip value="rejected">Rejected</sm-chip>
|
<sm-chip value="rejected" ?selected=${filter === "rejected"}>Rejected</sm-chip>
|
||||||
<sm-chip value="approved">Approved</sm-chip>
|
<sm-chip value="approved" ?selected=${filter === "approved"}>Approved</sm-chip>
|
||||||
<sm-chip value="all">All</sm-chip>
|
<sm-chip value="all" ?selected=${filter === "all"}>All</sm-chip>
|
||||||
</sm-chips>
|
</sm-chips>
|
||||||
</div>
|
</div>
|
||||||
<sm-input id="search_approved" type="search" placeholder="Search address" oninput=${handleRequestSearch}>
|
<sm-input id="search_approved" type="search" placeholder="Search address" oninput=${handleRequestSearch}>
|
||||||
@ -798,10 +824,13 @@
|
|||||||
<article id="home_page">
|
<article id="home_page">
|
||||||
${mainHeader}
|
${mainHeader}
|
||||||
${issuersList.length ? html`
|
${issuersList.length ? html`
|
||||||
${isVerified ? html`${kycCompleteSection}` : html`${concurrentRequests < 100 ? fileUploadSection : tooManyRequestsSection}`}
|
${isVerified ? html`${kycCompleteSection}` : html`${concurrentRequests < 4 ? fileUploadSection : tooManyRequestsSection}`}
|
||||||
${renderedRequests.length ? html`
|
${renderedRequests.length ? html`
|
||||||
<section class="grid gap-1">
|
<section class="grid gap-1">
|
||||||
<h4>KYC requests</h4>
|
<div class="grid gap-0-3">
|
||||||
|
<h4>KYC requests</h4>
|
||||||
|
<p>May take up to 48 hours to process requests</p>
|
||||||
|
</div>
|
||||||
<ul id="verification_list" class="grid gap-0-5">${renderedRequests}</ul>
|
<ul id="verification_list" class="grid gap-0-5">${renderedRequests}</ul>
|
||||||
</section>
|
</section>
|
||||||
`: ''}
|
`: ''}
|
||||||
@ -935,36 +964,42 @@
|
|||||||
// subAdmin functions
|
// subAdmin functions
|
||||||
function handleRequestFilter(e) {
|
function handleRequestFilter(e) {
|
||||||
const filter = e.target.value;
|
const filter = e.target.value;
|
||||||
const renderedKycRequests = render.kycRequests({ status: filter });
|
location.hash = `#/home?filter=${filter}`
|
||||||
renderElem(getRef('kyc_requests_list'), html`
|
|
||||||
${renderedKycRequests?.length ? renderedKycRequests : html`<li class="text-center" style="padding: 3rem;">No requests found</li>`}
|
|
||||||
`)
|
|
||||||
}
|
}
|
||||||
function handleRequestSearch(e) {
|
function handleRequestSearch(e) {
|
||||||
const filter = getRef('kyc_request_filter').value;
|
const filter = getRef('kyc_request_filter').value;
|
||||||
const searchKey = e.target.value.toLowerCase()
|
const searchKey = e.target.value.toLowerCase()
|
||||||
const renderedKycRequests = render.kycRequests({ address: searchKey, status: filter });
|
router.routeTo(`#/home?filter=${filter}&search=${searchKey}`)
|
||||||
renderElem(getRef('kyc_requests_list'), html`
|
|
||||||
${renderedKycRequests?.length ? renderedKycRequests : html`<li class="text-center" style="padding: 3rem;">No requests found</li>`}
|
|
||||||
`)
|
|
||||||
}
|
}
|
||||||
async function viewFile(e) {
|
async function viewFile(e) {
|
||||||
const button = e.target;
|
const button = e.target;
|
||||||
const { requestVC, docVC } = button.dataset;
|
const { requestVC, docVC } = button.dataset;
|
||||||
const { senderID, message: { docType }, tag } = floDapps.getNextGeneralData('userKycRequests', '0')[requestVC]
|
const { senderID, message: { docType }, tag } = floDapps.getNextGeneralData('userKycRequests', '0')[requestVC]
|
||||||
|
const floAddress = getFloAddress(senderID);
|
||||||
floGlobals.currentRequest = {
|
floGlobals.currentRequest = {
|
||||||
requestVC,
|
requestVC,
|
||||||
docVC,
|
docVC,
|
||||||
senderID,
|
senderID: floAddress,
|
||||||
docType,
|
docType,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
buttonLoader(button, true)
|
let objectURL
|
||||||
|
renderElem(getRef('view_file_popup__content'), html`
|
||||||
|
<div class="grid gap-1 justify-items-center text-center">
|
||||||
|
<sm-spinner></sm-spinner>
|
||||||
|
<h4>Loading ${senderID} ${docTypeNames[docType]}</h4>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
openPopup('view_file_popup').closed.then(() => {
|
||||||
|
URL.revokeObjectURL(objectURL);
|
||||||
|
renderElem(getRef('view_file_popup__content'), html``);
|
||||||
|
floGlobals.currentRequest = null;
|
||||||
|
})
|
||||||
const { file } = await floCloudAPI.downloadFile(docVC, {
|
const { file } = await floCloudAPI.downloadFile(docVC, {
|
||||||
decrypt: await floDapps.user.private,
|
decrypt: await floDapps.user.private,
|
||||||
});
|
});
|
||||||
const blob = new Blob([file], { type: file.type });
|
const blob = new Blob([file], { type: file.type });
|
||||||
const objectURL = URL.createObjectURL(blob);
|
objectURL = URL.createObjectURL(blob);
|
||||||
const details = html`
|
const details = html`
|
||||||
<div class="flex gap-1 space-between flex-wrap align-center">
|
<div class="flex gap-1 space-between flex-wrap align-center">
|
||||||
<h4>${senderID} (${docTypeNames[docType]})</h4>
|
<h4>${senderID} (${docTypeNames[docType]})</h4>
|
||||||
@ -993,16 +1028,9 @@
|
|||||||
</object>
|
</object>
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
openPopup('view_file_popup').closed.then(() => {
|
|
||||||
URL.revokeObjectURL(objectURL);
|
|
||||||
renderElem(getRef('view_file_popup__content'), '');
|
|
||||||
floGlobals.currentRequest = null;
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
notify('Error viewing file', 'error');
|
notify('Error viewing file', 'error');
|
||||||
} finally {
|
|
||||||
buttonLoader(button, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function downloadFile(e) {
|
async function downloadFile(e) {
|
||||||
@ -1026,24 +1054,16 @@
|
|||||||
buttonLoader(button, false)
|
buttonLoader(button, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
floGlobals.approvalsToBeCommitted = new Map();
|
||||||
async function approveKyc(e) {
|
async function approveKyc(e) {
|
||||||
const confirmation = await getConfirmation('Are you sure you want to verify this user?', {
|
|
||||||
confirmText: 'Verify',
|
|
||||||
});
|
|
||||||
if (!confirmation) return;
|
|
||||||
const button = e.target.closest('button');
|
const button = e.target.closest('button');
|
||||||
buttonLoader(button, true)
|
const { requestVC, docVC, senderID } = floGlobals.currentRequest;
|
||||||
const { requestVC, docVC } = floGlobals.currentRequest;
|
floGlobals.approvalsToBeCommitted.set(senderID, {
|
||||||
try {
|
requestVC,
|
||||||
await floCloudAPI.tagApplicationData(requestVC, 'verified')
|
docVC,
|
||||||
await floCloudAPI.tagApplicationData(docVC, 'verified')
|
})
|
||||||
notify('User verified successfully', 'success');
|
closePopup()
|
||||||
} catch (err) {
|
floGlobals.currentRequest = null;
|
||||||
console.error(err)
|
|
||||||
notify('Error verifying user', 'error');
|
|
||||||
} finally {
|
|
||||||
buttonLoader(button, false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function rejectKyc(e) {
|
async function rejectKyc(e) {
|
||||||
const confirmation = await getConfirmation('Are you sure you want to reject this user?', {
|
const confirmation = await getConfirmation('Are you sure you want to reject this user?', {
|
||||||
@ -1054,8 +1074,11 @@
|
|||||||
buttonLoader(button, true)
|
buttonLoader(button, true)
|
||||||
const { requestVC, docVC } = floGlobals.currentRequest;
|
const { requestVC, docVC } = floGlobals.currentRequest;
|
||||||
try {
|
try {
|
||||||
await floCloudAPI.noteApplicationData(requestVC, 'rejected')
|
// await floCloudAPI.noteApplicationData(requestVC, 'rejected')
|
||||||
|
floGlobals.generalData[floCloudAPI.util.filterKey('userKycRequests')][requestVC].note = 'rejected'
|
||||||
notify('User rejected successfully', 'success');
|
notify('User rejected successfully', 'success');
|
||||||
|
closePopup()
|
||||||
|
renderHome()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
notify('Error rejecting user', 'error');
|
notify('Error rejecting user', 'error');
|
||||||
@ -1115,54 +1138,16 @@
|
|||||||
getRef('aggregator_balance').classList.add('hidden')
|
getRef('aggregator_balance').classList.add('hidden')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function processAddresses(addresses = []) {
|
async function approveAddresses() {
|
||||||
const uniqueAddresses = new Set()
|
const approverPrivateKey = await floDapps.user.private
|
||||||
addresses.forEach(address => {
|
if (!floGlobals.isSubAdmin) {
|
||||||
let equivalentBtcAddress = address
|
return notify('You are not authorized to approve KYC', 'error')
|
||||||
if (floCrypto.validateFloID(address))
|
|
||||||
equivalentBtcAddress = getBtcAddress(address)
|
|
||||||
uniqueAddresses.add(equivalentBtcAddress)
|
|
||||||
})
|
|
||||||
return [...uniqueAddresses]
|
|
||||||
}
|
|
||||||
function approveAddresses() {
|
|
||||||
const manageType = getRef('manage_type').value
|
|
||||||
const approverPrivateKey = getRef('approver_private_key').value.trim()
|
|
||||||
if (!approverPrivateKey) {
|
|
||||||
return notify(`Enter ${manageType} private key`, 'error')
|
|
||||||
}
|
}
|
||||||
const approverAddress = floCrypto.getFloID(approverPrivateKey)
|
if (floGlobals.approvalsToBeCommitted.size === 0) {
|
||||||
if (manageType === 'aggregator') {
|
|
||||||
if (!floGlobals.approvedKycAggregators.hasOwnProperty(approverAddress)) {
|
|
||||||
return notify('KYC aggregator address is not approved', 'error')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (floGlobals.masterAddress !== approverAddress) {
|
|
||||||
return notify(`Private key doesn't match admin`, 'error')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const addressInputs = [...document.querySelectorAll('.kyc-address')]
|
|
||||||
.filter(input => input.value.trim() !== '')
|
|
||||||
.map(input => input.value.trim())
|
|
||||||
let addressLabels = []
|
|
||||||
if (manageType === 'admin') {
|
|
||||||
addressLabels = [...document.querySelectorAll('.aggregator-label')]
|
|
||||||
.filter(input => input.value.trim() !== '')
|
|
||||||
.map(input => input.value.trim())
|
|
||||||
}
|
|
||||||
const addresses = processAddresses(addressInputs)
|
|
||||||
if (addresses.length === 0) {
|
|
||||||
return notify('Enter at least one address to approve', 'error')
|
return notify('Enter at least one address to approve', 'error')
|
||||||
}
|
}
|
||||||
let floData
|
const addresses = [...floGlobals.approvalsToBeCommitted.keys()]
|
||||||
if (manageType === 'aggregator')
|
let floData = `KYC|APPROVE_KYC|${addresses.join('+')}`
|
||||||
floData = `KYC|APPROVE_KYC|${addresses.join('+')}`
|
|
||||||
else {
|
|
||||||
const addressWithLabels = addresses.map((address, index) => {
|
|
||||||
return `${address}:${addressLabels[index]}`
|
|
||||||
})
|
|
||||||
floData = `KYC|APPROVE_AGGREGATOR|${addressWithLabels.join('+')}`
|
|
||||||
}
|
|
||||||
console.log(floData)
|
console.log(floData)
|
||||||
if (floData.length > 1040) {
|
if (floData.length > 1040) {
|
||||||
return notify('Too many addresses. Try removing one and resubmitting.', 'error')
|
return notify('Too many addresses. Try removing one and resubmitting.', 'error')
|
||||||
@ -1184,12 +1169,20 @@
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
// try {
|
||||||
|
// await floCloudAPI.tagApplicationData(requestVC, 'verified')
|
||||||
|
// await floCloudAPI.tagApplicationData(docVC, 'verified')
|
||||||
|
// notify('User verified successfully', 'success');
|
||||||
|
// } catch (err) {
|
||||||
|
// console.error(err)
|
||||||
|
// notify('Error verifying user', 'error');
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
async function revokeKycs() {
|
async function revokeKycs() {
|
||||||
try {
|
try {
|
||||||
const approverPrivateKey = await floDapps.user.private
|
const approverPrivateKey = await floDapps.user.private
|
||||||
if (!floGlobals.isSubAdmin) {
|
if (!floGlobals.isSubAdmin) {
|
||||||
return notify('You are not authorized to approve KYC', 'error')
|
return notify('You are not authorized to revoke KYC', 'error')
|
||||||
}
|
}
|
||||||
if (addressesToRevoke.size === 0) {
|
if (addressesToRevoke.size === 0) {
|
||||||
return notify('Select at least one address to revoke', 'error')
|
return notify('Select at least one address to revoke', 'error')
|
||||||
@ -1272,8 +1265,8 @@
|
|||||||
floDapps.launchStartUp().then(async result => {
|
floDapps.launchStartUp().then(async result => {
|
||||||
console.log(result)
|
console.log(result)
|
||||||
//App functions....
|
//App functions....
|
||||||
floGlobals.myFloID = floCrypto.toFloID(myFloID);
|
floGlobals.myFloID = getFloAddress(floDapps.user.id);
|
||||||
floGlobals.myBtcID = getBtcAddress(myFloID)
|
floGlobals.myBtcID = getBtcAddress(floGlobals.myFloID)
|
||||||
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(floGlobals.myFloID)
|
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(floGlobals.myFloID)
|
||||||
try {
|
try {
|
||||||
await floCloudAPI.requestObjectData('kycDocs')
|
await floCloudAPI.requestObjectData('kycDocs')
|
||||||
@ -1310,7 +1303,7 @@
|
|||||||
} else[
|
} else[
|
||||||
// fetch user's kyc requests
|
// fetch user's kyc requests
|
||||||
await floCloudAPI.requestGeneralData('userKycRequests', {
|
await floCloudAPI.requestGeneralData('userKycRequests', {
|
||||||
senderID: floGlobals.myFloID,
|
senderID: [floGlobals.myFloID, floGlobals.myBtcID],
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
if (['#/landing', '#/sign_in', '#/sign_up'].includes(window.location.hash)) {
|
if (['#/landing', '#/sign_in', '#/sign_up'].includes(window.location.hash)) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user