code refactoring

This commit is contained in:
sairaj mote 2023-09-09 01:03:16 +05:30
parent 91c4435649
commit 6468c8431b
4 changed files with 133 additions and 58 deletions

View File

@ -170,10 +170,6 @@ a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid; outline: rgba(var(--text-color), 1) 0.1rem solid;
} }
details {
padding: 1rem 0;
}
details summary { details summary {
display: flex; display: flex;
-webkit-user-select: none; -webkit-user-select: none;
@ -776,11 +772,26 @@ h3 {
.loan { .loan {
display: grid; display: grid;
gap: 1rem; gap: 1.5rem;
background-color: rgba(var(--foreground-color), 1); background-color: rgba(var(--foreground-color), 1);
padding: max(1rem, 1.5vw); padding: max(1rem, 1.5vw);
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.loan .status {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 500;
font-size: 0.9rem;
box-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.1);
padding: 0.8rem;
border-radius: 0.5rem;
margin-right: auto;
border: solid thin rgba(var(--text-color), 0.2);
}
.loan .status .icon {
fill: var(--accent-color);
}
.loan-process { .loan-process {
display: grid; display: grid;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -154,9 +154,6 @@ button:disabled {
a:any-link:focus-visible { a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid; outline: rgba(var(--text-color), 1) 0.1rem solid;
} }
details {
padding: 1rem 0;
}
details summary { details summary {
display: flex; display: flex;
@ -732,10 +729,25 @@ h3 {
} }
.loan { .loan {
display: grid; display: grid;
gap: 1rem; gap: 1.5rem;
background-color: rgba(var(--foreground-color), 1); background-color: rgba(var(--foreground-color), 1);
padding: max(1rem, 1.5vw); padding: max(1rem, 1.5vw);
border-radius: 0.5rem; border-radius: 0.5rem;
.status {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 500;
font-size: 0.9rem;
box-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.1);
padding: 0.8rem;
border-radius: 0.5rem;
margin-right: auto;
border: solid thin rgba(var(--text-color), 0.2);
.icon {
fill: var(--accent-color);
}
}
} }
.loan-process { .loan-process {
display: grid; display: grid;

View File

@ -648,10 +648,11 @@
type, type,
loanOpeningProcessID, loanOpeningProcessID,
borrower, isBorrower, coborrower, isCoborrower, lender, isLender, loanAmount, policyID, borrower, isBorrower, coborrower, isCoborrower, lender, isLender, loanAmount, policyID,
initiationTime, loanRequestTime, loanResponseTime, collateralLockAckTime, loanIssuedTime, initiationTime, loanResponseTime, collateralLockAckTime, loanIssuedTime,
hasProvidedCollateral, hasAgreedToLend, hasRequestedCollateralLock, hasLockedCollateral, hasIssuedLoan, hasRequestedCollateralRefund, hasProvidedCollateral, hasAgreedToLend, hasLockedCollateral, hasIssuedLoan, hasRequestedCollateralRefund,
collateralRequestID, loanRequestID, loanResponseID, collateralLockRequestID, collateralLockAckID, loanID, closingTxID, collateralRequestID, loanResponseID, collateralLockRequestID, collateralLockAckID, loanID, closingTxID,
loanClosedAckTime, loanClosedAckID, hasPaidLoan, unlockCollateralRequestTime, unlockCollateralRequestID, hasRequestedCollateralUnlock, unlockCollateralAckTime, unlockCollateralAckID, hasRefundedCollateral unlockCollateralRequestTime, hasRequestedCollateralUnlock, unlockCollateralAckTime, hasRefundedCollateral,
unlockTxHex
} = details } = details
if (type === 'loanOpening') { if (type === 'loanOpening') {
return Component(() => { return Component(() => {
@ -866,7 +867,7 @@
Loan has not been issued even after 24 hours of collateral lock. Loan has not been issued even after 24 hours of collateral lock.
You can request for collateral refund. You can request for collateral refund.
</p> </p>
<button class="button button--primary margin-right-auto" disabled=${requestCollateralRefund} onclick=${requestCollateralRefund}> <button class="button button--primary margin-right-auto" disabled=${requestingCollateralRefund} onclick=${requestCollateralRefund}>
${requestingCollateralRefund ? html` ${requestingCollateralRefund ? html`
Requesting collateral refund Requesting collateral refund
<sm-spinner class="margin-left-0-5"></sm-spinner> <sm-spinner class="margin-left-0-5"></sm-spinner>
@ -942,9 +943,9 @@
})() })()
} else if (type === 'loanClosing') { } else if (type === 'loanClosing') {
return Component(() => { return Component(() => {
const [isRequestingCollateral, setIsRequestingCollateral] = useState(false) const [isRequestingCollateralUnlock, setIsRequestingCollateralUnlock] = useState(false)
let failedToUnlockCollateralAfter24Hours = false let failedToUnlockCollateralAfter24Hours = false
if (isCoborrower && hasRequestedCollateralLock && !hasRefundedCollateral) { if (isCoborrower && hasRequestedCollateralUnlock && !hasRefundedCollateral) {
const timeDiff = Date.now() - collateralLockAckTime const timeDiff = Date.now() - collateralLockAckTime
if (timeDiff > 86400000) { if (timeDiff > 86400000) {
failedToUnlockCollateralAfter24Hours = true failedToUnlockCollateralAfter24Hours = true
@ -954,14 +955,33 @@
const confirmation = await getConfirmation('Request collateral refund?', { message: `You are about to request for collateral refund. Continue?`, confirmText: 'Request', cancelText: 'Cancel' }) const confirmation = await getConfirmation('Request collateral refund?', { message: `You are about to request for collateral refund. Continue?`, confirmText: 'Request', cancelText: 'Cancel' })
if (!confirmation) if (!confirmation)
return; return;
setIsRequestingCollateral(true) setIsRequestingCollateralUnlock(true)
try { try {
console.log('requesting collateral unlock', loanID, closingTxID, await floDapps.user.private)
await btcMortgage.requestUnlockCollateral(loanID, closingTxID, await floDapps.user.private, failedToUnlockCollateralAfter24Hours) await btcMortgage.requestUnlockCollateral(loanID, closingTxID, await floDapps.user.private, failedToUnlockCollateralAfter24Hours)
notify('Collateral refund requested successfully', 'success') notify('Collateral refund requested successfully', 'success')
} catch (err) { } catch (err) {
notify(err, 'error') notify(err, 'error')
} finally { } finally {
setIsRequestingCollateral(false) setIsRequestingCollateralUnlock(false)
}
}
const [isUnlockingCollateral, setIsUnlockingCollateral] = useState(false)
const [hasUnlockedCollateral, setHasUnlockedCollateral] = useState(false)
async function unlockCollateral() {
const confirmation = await getConfirmation('Unlock collateral?', { message: `You are about to unlock collateral. Continue?`, confirmText: 'Unlock', cancelText: 'Cancel' })
if (!confirmation)
return;
setIsUnlockingCollateral(true)
try {
await btcMortgage.unlockCollateral(loanID, closingTxID, unlockTxHex, await floDapps.user.private)
notify('Collateral unlocked successfully', 'success')
setHasUnlockedCollateral(true)
} catch (err) {
notify(err, 'error')
setHasUnlockedCollateral(false)
} finally {
setIsUnlockingCollateral(false)
} }
} }
return html` return html`
@ -979,7 +999,7 @@
</div> </div>
<div class="details"> <div class="details">
<h4>Due amount paid</h4> <h4>Due amount paid</h4>
<time>${getFormattedTime(loanClosedAckTime)}</time> <a href=${`https://blockbook.ranchimall.net/tx/${closingTxID}`} target="_blank" class="button button--colored button--small margin-right-auto">Check on blockchain</a>
</div> </div>
</li> </li>
<li class=${hasRequestedCollateralUnlock ? 'done' : ''}> <li class=${hasRequestedCollateralUnlock ? 'done' : ''}>
@ -988,12 +1008,12 @@
<div class="line"></div> <div class="line"></div>
</div> </div>
<div class="details"> <div class="details">
${hasRequestedCollateralLock ? html` ${hasRequestedCollateralUnlock ? html`
${failedToUnlockCollateralAfter24Hours ? html` ${failedToUnlockCollateralAfter24Hours ? html`
<h4>Lender hasn't unlocked collateral</h4> <h4>Lender hasn't unlocked collateral</h4>
<p>Collateral failed to unlock even after 24 hours of loan closing. Please request to banker below.</p> <p>Collateral failed to unlock even after 24 hours of loan closing. Please request to banker below.</p>
<button class="button button--primary margin-right-auto" disabled=${isRequestingCollateral} onclick=${requestCollateralUnlock}> <button class="button button--primary margin-right-auto" disabled=${isRequestingCollateralUnlock} onclick=${requestCollateralUnlock}>
${isRequestingCollateral ? html` ${isRequestingCollateralUnlock ? html`
Requesting collateral refund Requesting collateral refund
<sm-spinner class="margin-left-0-5"></sm-spinner> <sm-spinner class="margin-left-0-5"></sm-spinner>
`: html` `: html`
@ -1007,8 +1027,8 @@
`: html` `: html`
${isCoborrower ? html` ${isCoborrower ? html`
<h4>Request collateral refund</h4> <h4>Request collateral refund</h4>
<button class="button button--primary margin-right-auto" disabled=${isRequestingCollateral} onclick=${requestCollateralUnlock}> <button class="button button--primary margin-right-auto" disabled=${isRequestingCollateralUnlock} onclick=${requestCollateralUnlock}>
${isRequestingCollateral ? html` ${isRequestingCollateralUnlock ? html`
Requesting collateral refund Requesting collateral refund
<sm-spinner class="margin-left-0-5"></sm-spinner> <sm-spinner class="margin-left-0-5"></sm-spinner>
`: html` `: html`
@ -1022,18 +1042,31 @@
`} `}
</div> </div>
</li> </li>
<li class=${hasRefundedCollateral ? 'done' : ''}> <li class=${hasRefundedCollateral || hasUnlockedCollateral ? 'done' : ''}>
<div class="progress"> <div class="progress">
<div class="circle"></div> <div class="circle"></div>
</div> </div>
<div class="details"> <div class="details">
${hasRefundedCollateral ? html` ${hasRefundedCollateral || hasUnlockedCollateral ? html`
<h4>Collateral refunded. Loan closed.</h4> <h4>Collateral refunded. Loan closed.</h4>
<time>${getFormattedTime(unlockCollateralAckTime)}</time> <time>${getFormattedTime(unlockCollateralAckTime)}</time>
`: html`
${isLender ? html`
<h4>Unlock loan collateral</h4>
<p>Borrower has paid the loan amount. Please unlock the collateral.</p>
<button class="button button--primary margin-right-auto" disabled=${isUnlockingCollateral} onclick=${unlockCollateral}>
${isUnlockingCollateral ? html`
Unlocking collateral
<sm-spinner class="margin-left-0-5"></sm-spinner>
`: html`
Unlock collateral
`}
</button>
`: html` `: html`
<h4>Waiting for collateral to be refunded</h4> <h4>Waiting for collateral to be refunded</h4>
<p>Collateral will be refunded within 24 hours of request.</p> <p>Collateral will be refunded within 24 hours of request.</p>
`} `}
`}
</div> </div>
</li> </li>
</ul> </ul>
@ -1050,7 +1083,7 @@
blocktime, borrower, borrower_sign, btc_start_rate, blocktime, borrower, borrower_sign, btc_start_rate,
coborrower, coborrower_sign, collateral_lock_id, collateral_value, coborrower, coborrower_sign, collateral_lock_id, collateral_value,
lender, lender_sign, loan_amount, loan_id, loan_opening_process_id, loan_transfer_id, lender, lender_sign, loan_amount, loan_id, loan_opening_process_id, loan_transfer_id,
open_time, policy_id, } = btcMortgage.loans[loanID]; open_time, close_time, policy_id } = btcMortgage.loans[loanID];
const amountDue = btcMortgage.util.calcDueAmount(loan_amount, policy_id, open_time) const amountDue = btcMortgage.util.calcDueAmount(loan_amount, policy_id, open_time)
const [isRepayingLoan, setIsRepayingLoan] = useState(false) const [isRepayingLoan, setIsRepayingLoan] = useState(false)
@ -1075,8 +1108,19 @@
const isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id) const isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)
const isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id) const isCoborrower = floCrypto.isSameAddr(coborrower, floDapps.user.id)
const isLender = floCrypto.isSameAddr(lender, floDapps.user.id) const isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
const hasStartedRepayment = Object.values({
...floGlobals.myInbox,
...floGlobals.myOutbox
})
.find(request => request.message.loan_id === loanID)
return html` return html`
<li class="loan"> <li class="loan">
${hasStartedRepayment && !close_time ? html`
<div class="status">
<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="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>
Repayment in-process
</div>
`: ''}
<sm-copy value=${loan_id} clip-text> <sm-copy value=${loan_id} clip-text>
<p>Loan ID: ${loan_id}</p> <p>Loan ID: ${loan_id}</p>
</sm-copy> </sm-copy>
@ -1098,9 +1142,15 @@
<b>${btcMortgage.policies[policy_id]?.interest * 100}% p.a</b> <b>${btcMortgage.policies[policy_id]?.interest * 100}% p.a</b>
</div> </div>
<div class="grid gap-0-3"> <div class="grid gap-0-3">
<p>Loan start date</p> <p>Opening date</p>
<b>${getFormattedTime(open_time)}</b> <b>${getFormattedTime(open_time)}</b>
</div> </div>
${close_time ? html`
<div class="grid gap-0-3">
<p>Closing date</p>
<b>${getFormattedTime(close_time)}</b>
</div>
`: ``}
</div> </div>
<div class="grid gap-0-3"> <div class="grid gap-0-3">
<p>Interest ${isLender ? 'earned' : 'accrued'}</p> <p>Interest ${isLender ? 'earned' : 'accrued'}</p>
@ -1128,7 +1178,7 @@
`: ''} `: ''}
</div> </div>
</details> </details>
${floCrypto.isSameAddr(borrower, floGlobals.myFloID) ? html` ${isBorrower && !hasStartedRepayment ? html`
<div class="flex align-center space-between gap-1-5"> <div class="flex align-center space-between gap-1-5">
<div class="grid gap-0-3"> <div class="grid gap-0-3">
<p>Amount due (If paid now)</p> <p>Amount due (If paid now)</p>
@ -1414,14 +1464,14 @@
} else { } else {
// user homepage // user homepage
const inbox = Component(() => { const inbox = Component(() => {
const loansInProcess = groupLoanProcess() const loanRequestsInProcess = groupLoanProcess()
const { borrowed, coBorrowed, lent } = groupLoans() const { borrowed, coBorrowed, lent } = groupLoans()
const [view, setView] = useState(section) const [view, setView] = useState(section)
let loanRequests = []; let loanRequests = [];
for (const key in floGlobals.loanRequests) { for (const key in floGlobals.loanRequests) {
const { message: { borrower, coborrower, loan_opening_process_id } } = floGlobals.loanRequests[key] const { message: { borrower, coborrower, loan_opening_process_id } } = floGlobals.loanRequests[key]
if (!loan_opening_process_id) continue // TODO: remove this check after all requests are updated if (!loan_opening_process_id) continue // TODO: remove this check after all requests are updated
if (floGlobals.loansInProcess.has(loan_opening_process_id)) continue // if loan request is in process, don't show loan request if (floGlobals.loansOpeningInProcess.has(loan_opening_process_id)) continue // if loan request is in process, don't show loan request
loanRequests.push(key) loanRequests.push(key)
} }
function handleChange(e) { function handleChange(e) {
@ -1442,7 +1492,7 @@
<sm-chips onchange=${handleChange}> <sm-chips onchange=${handleChange}>
<sm-chip value="in-process" selected=${view === 'in-process'}> <sm-chip value="in-process" selected=${view === 'in-process'}>
In process In process
${loansInProcess.length ? html`<span class="badge">${loansInProcess.length}</span>` : ''} ${loanRequestsInProcess.length ? html`<span class="badge">${loanRequestsInProcess.length}</span>` : ''}
</sm-chip> </sm-chip>
<sm-chip value="my-loans" selected=${view === 'my-loans'}> <sm-chip value="my-loans" selected=${view === 'my-loans'}>
My loans My loans
@ -1484,21 +1534,11 @@
</div> </div>
`} `}
`: ''} `: ''}
${view === 'in-process' ? html` ${view === 'in-process' && loanRequestsInProcess.length ? html`
${loansInProcess.length ? html`
<ul class="grid gap-1"> <ul class="grid gap-1">
${loansInProcess.map(loan => render.loanProcess(loan))} ${loanRequestsInProcess.map(loan => render.loanProcess(loan))}
</ul> </ul>
<a href="#/apply-loan" class="button button--primary margin-right-auto">Apply for a new loan</a> <a href="#/apply-loan" class="button button--primary margin-right-auto">Apply for a new loan</a>
`: html`
<div class="grid gap-2 align-center justify-center" style="padding: 2vw 0;">
<div class="grid gap-0-5">
<h1>Looking for USD loans?</h1>
<p>Get a loan against your BTC collateral</p>
</div>
<a href="#/apply-loan" class="button button--primary margin-right-auto">Apply for a loan</a>
</div>
`}
`: ''} `: ''}
${view === 'coBorrowed' && coBorrowed.length ? html` ${view === 'coBorrowed' && coBorrowed.length ? html`
<ul class="grid gap-1"> <ul class="grid gap-1">
@ -1556,18 +1596,23 @@
...floGlobals.myOutbox ...floGlobals.myOutbox
} }
const loansInProcess = {} const loansInProcess = {}
const processedRequests = new Set()
for (const key in allMessages) { for (const key in allMessages) {
const { const {
message: { message: {
borrower, coborrower, lender, borrower, coborrower, lender,
loan_amount, policy_id, loan_opening_process_id, loan_request_id, collateral_lock_id, loan_amount, policy_id, loan_opening_process_id, loan_request_id, collateral_lock_id,
loan_id, closing_txid, unlock_tx_hex, unlock_collateral_id loan_id, closing_txid, unlock_tx_hex, unlock_collateral_id, type_unlock_collateral_ack
} = {}, } = {},
type, time type, time
} = allMessages[key]; } = allMessages[key];
if (processedRequests.has(loan_opening_process_id) || Object.values(btcMortgage.loans).find(loan => loan.loan_opening_process_id === loan_opening_process_id)) {
processedRequests.add(loan_opening_process_id)
continue // Request has been processed
}
if (loan_id && btcMortgage.loans[loan_id] && btcMortgage.loans[loan_id].close_time)
continue // Loan closed
if (loan_opening_process_id) { if (loan_opening_process_id) {
if (Object.values(btcMortgage.loans).find(loan => loan.loan_opening_process_id === loan_opening_process_id))
continue // Loan is already open
if (!loansInProcess[loan_opening_process_id]) { if (!loansInProcess[loan_opening_process_id]) {
loansInProcess[loan_opening_process_id] = { loansInProcess[loan_opening_process_id] = {
loanOpeningProcessID: loan_opening_process_id, loanOpeningProcessID: loan_opening_process_id,
@ -1636,6 +1681,7 @@
} else if (closing_txid) { } else if (closing_txid) {
if (!loansInProcess[closing_txid]) if (!loansInProcess[closing_txid])
loansInProcess[closing_txid] = { loansInProcess[closing_txid] = {
loanID: loan_id,
closingTxID: closing_txid, closingTxID: closing_txid,
hasRequestedCollateralRefund: false, hasRequestedCollateralRefund: false,
hasRefundedCollateral: false, hasRefundedCollateral: false,
@ -1655,6 +1701,9 @@
loansInProcess[closing_txid].lender = lender loansInProcess[closing_txid].lender = lender
loansInProcess[closing_txid].isLender = floCrypto.isSameAddr(lender, floDapps.user.id) loansInProcess[closing_txid].isLender = floCrypto.isSameAddr(lender, floDapps.user.id)
} }
if (unlock_tx_hex) {
loansInProcess[closing_txid].unlockTxHex = unlock_tx_hex
}
switch (type) { switch (type) {
case 'type_loan_closed_ack': case 'type_loan_closed_ack':
loansInProcess[closing_txid].loanClosedAckTime = time loansInProcess[closing_txid].loanClosedAckTime = time
@ -1676,7 +1725,9 @@
} }
// sort by time // sort by time
return Object.values(loansInProcess).sort((a, b) => { return Object.values(loansInProcess).sort((a, b) => {
return (b.initiationTime || b.loanResponseTime || b.loanClosedAckTime) - (a.initiationTime || a.loanResponseTime || a.loanClosedAckTime) const aTime = a.initiationTime || a.loanResponseTime || a.loanClosedAckTime || a.unlockCollateralRequestTime;
const bTime = b.initiationTime || b.loanResponseTime || b.loanClosedAckTime || b.unlockCollateralRequestTime;
return bTime - aTime
}) })
// .reduce((acc, loan) => { // group by borrower, coborrower and lender // .reduce((acc, loan) => { // group by borrower, coborrower and lender
// if (loan.isBorrower) // if (loan.isBorrower)
@ -1696,6 +1747,7 @@
function groupLoans() { function groupLoans() {
console.log(btcMortgage.loans) console.log(btcMortgage.loans)
return Object.values(btcMortgage.loans) return Object.values(btcMortgage.loans)
.sort((a, b) => b.open_time - a.open_time)
.reduce((acc, loan) => { .reduce((acc, loan) => {
const { loan_id, borrower, coborrower, lender } = loan const { loan_id, borrower, coborrower, lender } = loan
if (floCrypto.isSameAddr(borrower, floDapps.user.id) && floCrypto.isSameAddr(coborrower, floDapps.user.id)) if (floCrypto.isSameAddr(borrower, floDapps.user.id) && floCrypto.isSameAddr(coborrower, floDapps.user.id))
@ -1928,11 +1980,11 @@
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
function parseInProcessRequests(requests) { function parseInProcessRequests(requests) {
if (!floGlobals.loansInProcess) if (!floGlobals.loansOpeningInProcess)
floGlobals.loansInProcess = new Set() floGlobals.loansOpeningInProcess = new Set()
for (const key in requests) { for (const key in requests) {
const { message: { loan_opening_process_id } } = requests[key] const { message: { loan_opening_process_id, closing_txid } } = requests[key]
floGlobals.loansInProcess.add(loan_opening_process_id) floGlobals.loansOpeningInProcess.add(loan_opening_process_id)
} }
} }
function getAllInvolvedAddresses() { // get all addresses involved in loan process (except my address) function getAllInvolvedAddresses() { // get all addresses involved in loan process (except my address)