Added trusted banker UI

This commit is contained in:
sairaj mote 2023-09-15 05:00:36 +05:30
parent f47f653a4d
commit e590182644
6 changed files with 243 additions and 15 deletions

View File

@ -544,6 +544,30 @@ h3 {
display: none;
}
.tooltip {
position: relative;
cursor: pointer;
isolation: isolate;
}
.tooltip:hover .tooltip__content {
opacity: 1;
pointer-events: auto;
}
.tooltip__content {
pointer-events: none;
position: absolute;
opacity: 0;
top: 100%;
justify-self: center;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: rgba(var(--text-color), 0.8);
color: rgba(var(--background-color), 1);
font-size: 0.8rem;
transition: opacity 0.2s;
z-index: 1;
}
#confirmation_popup,
#prompt_popup {
flex-direction: column;
@ -909,6 +933,16 @@ h3 {
margin-top: auto;
}
#create_policy_form {
padding: 1rem;
width: min(24rem, 100%);
border-radius: 0.5rem;
background-color: rgba(var(--foreground-color), 1);
}
#create_policy_form sm-select {
height: 3.2rem;
flex: 1;
}
@media screen and (max-width: 40rem) {
theme-toggle {
order: 2;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -515,6 +515,31 @@ h3 {
}
}
}
.tooltip {
position: relative;
cursor: pointer;
isolation: isolate;
&:hover {
.tooltip__content {
opacity: 1;
pointer-events: auto;
}
}
&__content {
pointer-events: none;
position: absolute;
opacity: 0;
top: 100%;
justify-self: center;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: rgba(var(--text-color), 0.8);
color: rgba(var(--background-color), 1);
font-size: 0.8rem;
transition: opacity 0.2s;
z-index: 1;
}
}
#confirmation_popup,
#prompt_popup {
flex-direction: column;
@ -864,6 +889,18 @@ h3 {
margin-top: auto;
}
}
#create_policy_form {
padding: 1rem;
width: min(24rem, 100%);
border-radius: 0.5rem;
background-color: rgba(var(--foreground-color), 1);
sm-select {
height: 3.2rem;
flex: 1;
}
.button {
}
}
@media screen and (max-width: 40rem) {
theme-toggle {
order: 2;

View File

@ -161,6 +161,14 @@
popupStack.peek().popup.hide(options)
}
// displays a popup for asking permission. Use this instead of JS confirm
/**
@param {string} title - Title of the popup
@param {object} options - Options for the popup
@param {string} options.message - Message to be displayed in the popup
@param {string} options.cancelText - Text for the cancel button
@param {string} options.confirmText - Text for the confirm button
@param {boolean} options.danger - If true, confirm button will be red
*/
const getConfirmation = (title, options = {}) => {
return new Promise(resolve => {
const { message = '', cancelText = 'Cancel', confirmText = 'OK', danger = false } = options
@ -566,7 +574,7 @@
},
loanRequest(requestId, details) {
const { message: { borrower, coborrower, collateral: { btc_id, quantity, rate }, loan_amount, loan_collateral_req_id, loan_opening_process_id, policy_id }, vectorClock } = details;
const { duration, interest } = btcMortgage.policies[policy_id];
const { duration, interest } = btcMortgage.policies[policy_id] || {};
const isRequester = floCrypto.isSameAddr(borrower, floGlobals.myFloID) || floCrypto.isSameAddr(coborrower, floGlobals.myFloID)
const [isLending, setIsLending] = useState(false)
async function startLendingProcess() {
@ -1537,18 +1545,166 @@
return html``
}
})
const [bankerView, setBankerView] = useState(wildcards[0] || 'inbox')
function handleChange(e) {
history.pushState(null, null, `#/home/${e.target.value}`)
setBankerView(e.target.value)
}
const [duration, setDuration] = useState(0)
const [durationUnit, setDurationUnit] = useState('Y')
let durationUnitInput
switch (durationUnit) {
case 'D':
durationUnitInput = html`
<sm-select id="policy_duration" required>
${[...Array(31)].map((_, i) => html`
<sm-option value=${i + 1}>${i + 1}</sm-option>
`)}
</sm-select>
`
break;
case 'M':
case 'Y':
durationUnitInput = html` <sm-input id="policy_duration" class="flex-1" type="number" min="1" max="100" error-text="Must be between 1-100" required></sm-input> `
break;
}
const [isCreatingPolicy, setIsCreatingPolicy] = useState(false)
async function createPolicy() {
const interestRate = parseFloat(getRef('policy_interest_rate').value.trim())
const duration = parseInt(getRef('policy_duration').value.trim())
const collateralRatio = parseFloat(getRef('loan_to_collateral_ratio').value.trim())
const preLiquidateCollateralThreshold = parseFloat(getRef('policy_pre_liquidation_threshold').value.trim()) || null
const confirmation = await getConfirmation('Create policy?', {
message: `
You are about to create a new policy with the following details: \n
Interest rate: ${interestRate}% \n
Duration: ${duration} ${durationUnit} \n
Collateral ratio: ${collateralRatio}% \n
${preLiquidateCollateralThreshold ? `Pre-liquidation threshold: ${preLiquidateCollateralThreshold}% \n` : ''}
`,
confirmText: 'Create',
})
if (!confirmation) return
try {
setIsCreatingPolicy(true)
const txid = await btcMortgage.writePolicy(await floDapps.user.private, `${duration}${durationUnit}`, interestRate, preLiquidateCollateralThreshold, collateralRatio)
notify('Policy created. May take 20 Mins to be visible in policy list.', 'success')
getRef('create_policy_form').reset()
} catch (error) {
notify(error.message || error, 'error')
} finally {
setIsCreatingPolicy(false)
}
}
function policyCard(policyId, details = {}) {
const { duration, interest, loan_collateral_ratio, policy_creation_time, pre_liquidation_threshold } = details
return html`
<section class="grid gap-1">
<li class="grid gap-1-5" style="background-color: rgba(var(--foreground-color),1); padding: 1rem; border-radius: 0.5rem;">
<p>${getFormattedTime(policy_creation_time)}</p>
<div class="flex flex-wrap gap-1-5">
<div class="grid gap-0-3">
<p>Interest rate</p>
<b>${interest * 100}%</b>
</div>
<div class="grid gap-0-3">
<p>Duration</p>
<b>${duration}</b>
</div>
<div class="grid gap-0-3">
<p>Loan to collateral ratio</p>
<b>${loan_collateral_ratio * 100}%</b>
</div>
${pre_liquidation_threshold ? html`
<div class="grid gap-0-3">
<p>Pre-liquidation threshold</p>
<b>${pre_liquidation_threshold * 100}%</b>
</div>
`: ''}
</div>
<a href=${`https://blockbook.ranchimall.net/tx/${policyId}`} target="_blank" class="button button--small button--colored margin-left-auto">Check on blockchain</a>
</li>
`
}
const policies = Object.entries(btcMortgage.policies)
.sort((a, b) => b[1].policy_creation_time - a[1].policy_creation_time)
.map(([policyId, policyDetails]) => policyCard(policyId, policyDetails))
return html`
<section class=${`grid gap-1 ${bankerView}`}>
<sm-chips onchange=${handleChange}>
<sm-chip value="inbox" selected=${bankerView === 'inbox'}>
Inbox
${requests.length ? html`<span class="badge">${requests.length}</span>` : ''}
</sm-chip>
<sm-chip value="create-policy" selected=${bankerView === 'create-policy'}>
Create policy
</sm-chip>
<sm-chip value="policies" selected=${bankerView === 'policies'}>
Policies
</sm-chip>
</sm-chips>
${bankerView === 'inbox' ? html`
<h3>Banker Inbox</h3>
${requests.length ? html`
<ul id="banker_inbox_list">
${requests}
</ul>
`: html` <strong> No requests </strong> `}
`: ``}
${bankerView === 'policies' ? html`
<h3>Policies</h3>
<ul class="grid gap-1">
${policies}
</ul>
`: ''}
${bankerView === 'create-policy' ? html`
<h3>Create policy</h3>
<sm-form id="create_policy_form">
<div class="grid gap-0-5">
<p>Interest rate (%)</p>
<sm-input id="policy_interest_rate" type="number" min="1" max="100" step="0.01" error-text="Must be between 1-100" required></sm-input>
</div>
<div class="grid gap-0-5">
<p>Duration</p>
<div class="flex gap-0-5">
${durationUnitInput}
<sm-select onchange=${e => setDurationUnit(e.target.value)} required>
<sm-option value="D" selected=${durationUnit === 'D'}>Days</sm-option>
<sm-option value="M" selected=${durationUnit === 'M'}>Months</sm-option>
<sm-option value="Y" selected=${durationUnit === 'Y'}>Years</sm-option>
</sm-select>
</div>
</div>
<div class="grid gap-0-5">
<div class="flex align-center tooltip gap-0-3">
<p>Loan to collateral ratio (%)</p>
<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 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
<p class="tooltip__content">
The percentage of collateral value that can be borrowed. <br>
e.g. 50% means 1 BTC collateral can be borrowed as 0.5 BTC worth of USD tokens.
</p>
</div>
<sm-input id="loan_to_collateral_ratio" type="number" min="1" max="100" step="0.01" error-text="Must be between 1-100" required></sm-input>
</div>
<div class="grid gap-0-5">
<div class="flex align-center tooltip gap-0-3">
<p>Pre-liquidation threshold (%) (Optional)</p>
<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 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
<p class="tooltip__content">
If the collateral value falls below this threshold, the collateral can be liquidated. <br>
This is an optional field.
</p>
</div>
<sm-input id="policy_pre_liquidation_threshold" type="number" min="1" max="100" step="0.01" error-text="Must be between 1-100"></sm-input>
</div>
${isCreatingPolicy ? html`
<button class="button button--primary" type="submit" disabled=${true}>
Creating <sm-spinner class="margin-left-0-5"></sm-spinner>
</button>
`: html`
<strong>
No requests
</strong>
<button class="button button--primary" type="submit" onclick=${createPolicy} disabled="true">Create</button>
`}
</sm-form>
`: ''}
</section>
`
})
@ -2063,7 +2219,7 @@
hasPaidLoan: false,
type: 'loanClosing'
}
const { borrower, coborrower, lender } = btcMortgage.loans[loan_id]
const { borrower, coborrower, lender } = btcMortgage.loans[loan_id] || {}
if (borrower) {
uiGlobals.inProcessRequests[closing_txid].borrower = borrower
uiGlobals.inProcessRequests[closing_txid].isBorrower = floCrypto.isSameAddr(borrower, floDapps.user.id)

View File

@ -5,8 +5,8 @@
const APP_NAME = "BTCMortgage";
const APP_IDENTIFIER = "BTC Mortgage";
const BANKER_ID = "F6uMddaTDCZgojENbqRnFo5PCknArE7dKz";
// const BANKER_ID = "FPFeL5PXzW9bGosUjQYCxTHSMHidnygvvd";
// const BANKER_ID = "F6uMddaTDCZgojENbqRnFo5PCknArE7dKz";
const BANKER_ID = "FPFeL5PXzW9bGosUjQYCxTHSMHidnygvvd";
const BANKER_PUBKEY = '03EE0FB1868EE7D03BC741B10CD56057769445C7D37703115E428A93236C714E61';
const CURRENCY = "usd";

File diff suppressed because one or more lines are too long