Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show active offers #461

Merged
merged 11 commits into from
Aug 24, 2022
113 changes: 109 additions & 4 deletions src/components/Earn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { EarnReportOverlay } from './EarnReport'
import * as Api from '../libs/JmWalletApi'
import styles from './Earn.module.css'
import { OrderbookOverlay } from './Orderbook'
import Balance from './Balance'

// In order to prevent state mismatch, the 'maker stop' response is delayed shortly.
// Even though the API response suggests that the maker has started or stopped immediately, it seems that this is not always the case.
Expand All @@ -28,8 +29,11 @@ const RELOAD_FIDELITY_BONDS_DELAY_MS = 2_000
const OFFERTYPE_REL = 'sw0reloffer'
const OFFERTYPE_ABS = 'sw0absoffer'

const isRelativeOffer = (offertype) => offertype === OFFERTYPE_REL
const isAbsoluteOffer = (offertype) => offertype === OFFERTYPE_ABS
// can be any of ['sw0reloffer', 'swreloffer', 'reloffer']
const isRelativeOffer = (offertype) => offertype.includes('reloffer')

// can be any of ['sw0absoffer', 'swabsoffer', 'absoffer']
const isAbsoluteOffer = (offertype) => offertype.includes('absoffer')

const FORM_INPUT_LOCAL_STORAGE_KEYS = {
offertype: 'jm-offertype',
Expand Down Expand Up @@ -83,6 +87,95 @@ const factorToPercentage = (val, precision = 6) => {
return Number((val * 100).toFixed(precision))
}

const renderOrderType = (val, t) => {
if (isAbsoluteOffer(val)) {
return <rb.Badge bg="info">{t('earn.current.text_offer_type_absolute')}</rb.Badge>
}
if (isRelativeOffer(val)) {
return <rb.Badge bg="primary">{t('earn.current.text_offer_type_relative')}</rb.Badge>
}
return <rb.Badge bg="secondary">{val}</rb.Badge>
}

function CurrentOffer({ offer, nickname }) {
const { t } = useTranslation()
const settings = useSettings()

return (
<div className={styles.offerContainer}>
<div className="d-flex justify-content-between align-items-center">
<div className={`${styles.offerTitle} slashed-zeroes`}>
{nickname}:{offer.oid}
</div>
<div className="d-flex align-items-center gap-1">{renderOrderType(offer.ordertype, t)}</div>
</div>
<rb.Container className="mt-2">
<rb.Row className="mb-1">
<rb.Col xs={6}>
<div className="d-flex flex-column">
<div className={styles.offerLabel}>{t('earn.current.text_cjfee')}</div>
<div>
{isRelativeOffer(offer.ordertype) ? (
<>{factorToPercentage(offer.cjfee)}%</>
) : (
<>
<Balance
valueString={String(offer.cjfee)}
convertToUnit={settings.unit}
showBalance={settings.showBalance}
/>
</>
)}
</div>
</div>
</rb.Col>

<rb.Col xs={6}>
<div className="d-flex flex-column">
<div className={styles.offerLabel}>{t('earn.current.text_minsize')}</div>
<div>
<Balance
valueString={String(offer.minsize)}
convertToUnit={settings.unit}
showBalance={settings.showBalance}
/>
</div>
</div>
</rb.Col>
</rb.Row>

<rb.Row>
<rb.Col xs={6}>
<div className="d-flex flex-column">
<div className={styles.offerLabel}>{t('earn.current.text_txfee')}</div>
<div>
<Balance
valueString={String(offer.txfee)}
convertToUnit={settings.unit}
showBalance={settings.showBalance}
/>
</div>
</div>
</rb.Col>

<rb.Col xs={6}>
<div className="d-flex flex-column">
<div className={styles.offerLabel}>{t('earn.current.text_maxsize')}</div>
<div>
<Balance
valueString={String(offer.maxsize)}
convertToUnit={settings.unit}
showBalance={settings.showBalance}
/>
</div>
</div>
</rb.Col>
</rb.Row>
</rb.Container>
</div>
)
}

export default function Earn() {
const { t } = useTranslation()
const settings = useSettings()
Expand Down Expand Up @@ -294,10 +387,22 @@ export default function Earn() {
!serviceInfo?.makerRunning &&
!isWaitingMakerStart &&
!isWaitingMakerStop && <p className="text-secondary mb-4">{t('earn.market_explainer')}</p>}
{serviceInfo?.makerRunning &&
(serviceInfo?.offers && serviceInfo?.nickname ? (
<>
{serviceInfo.offers.map((offer, index) => (
<CurrentOffer key={index} offer={offer} nickname={serviceInfo.nickname} />
))}
</>
) : (
<rb.Placeholder as="div" animation="wave">
<rb.Placeholder xs={12} className={styles.offerLoader} />
</rb.Placeholder>
))}
{!serviceInfo?.coinjoinInProgress && (
<>
<PageTitle
title={fidelityBonds.length > 0 ? t('earn.title_fidelity_bond_exists') : t('earn.title_fidelity_bonds')}
title={t('earn.title_fidelity_bonds', { count: fidelityBonds.length })}
subtitle={t('earn.subtitle_fidelity_bonds')}
/>
<div className="d-flex flex-column gap-3">
Expand All @@ -319,7 +424,7 @@ export default function Earn() {
/>
) : (
<rb.Placeholder as="div" animation="wave">
<rb.Placeholder xs={12} className={styles['fb-loader']} />
<rb.Placeholder xs={12} className={styles.fidelityBondsLoader} />
</rb.Placeholder>
))}
</>
Expand Down
35 changes: 34 additions & 1 deletion src/components/Earn.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
border-radius: 0.25rem;
}

.earn .fb-loader {
.earn .fidelityBondsLoader {
height: 11rem;
border-radius: 0.25rem;
}
Expand Down Expand Up @@ -46,3 +46,36 @@
border-color: var(--bs-gray-800);
opacity: 100%;
}

.offerLoader {
height: 10rem;
border-radius: 0.25rem;
margin-bottom: 1.5rem;
}

.offerContainer {
border: 1px solid var(--bs-gray-200);
border-radius: 0.3rem;
padding: 1.25rem;
margin-bottom: 1.5rem;
}

:root[data-theme='dark'] .offerContainer {
border-color: var(--bs-gray-700);
}

.offerContainer .offerTitle {
width: 100%;
font-size: 1.2rem;
color: var(--bs-body-color);
}

.offerContainer .offerLabel {
color: var(--bs-gray-600);
font-size: 0.8rem;
}

.offerContainer .offerContent {
font-size: 0.8rem;
word-break: break-all;
}
Comment on lines +56 to +81
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the same styles as the existing FB box right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

13 changes: 11 additions & 2 deletions src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@
"text_stopping": "Stopping",
"button_show_report": "Show earnings report",
"button_show_orderbook": "Show orderbook",
"current": {
"text_cjfee": "Fee",
"text_minsize": "Minimum Size",
"text_maxsize": "Maximum Size",
"text_txfee": "Transaction Fee",
"text_offer_type_absolute": "absolute",
"text_offer_type_relative": "relative"
},
"report": {
"title": "Earnings Report",
"text_report_summary_one": "{{ count }} entry",
Expand All @@ -261,8 +269,9 @@
"heading_earned": "Earned",
"heading_notes": "Notes"
},
"title_fidelity_bonds": "Create a Fidelity Bond",
"title_fidelity_bond_exists": "Your Fidelity Bonds",
"title_fidelity_bonds_zero": "Create a Fidelity Bond",
"title_fidelity_bonds_one": "Your Fidelity Bond",
"title_fidelity_bonds_other": "Your Fidelity Bonds",
"subtitle_fidelity_bonds": "A fidelity bond is a long-term deposit that makes cryptographic identities deliberately costly. By cryptographically locking up funds for a specific duration, you signal that you are a serious market participant and increase the chance of your offers being taken.",
"fidelity_bond": {
"error_freezing_utxos": "Could not freeze UTXOs.",
Expand Down
5 changes: 4 additions & 1 deletion src/libs/JmWalletApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ interface WalletUnlockRequest {
password: string
}

type OrderType = 'sw0reloffer' | 'sw0absoffer'
// only support starting the maker with native segwit offers
type RelOfferType = 'sw0reloffer'
type AbsOfferType = 'sw0absoffer'
type OrderType = RelOfferType | AbsOfferType

interface StartMakerRequest {
cjfee_a: AmountSats
Expand Down