Compare commits
56 commits
master
...
offer-crea
| Author | SHA1 | Date | |
|---|---|---|---|
| 2aa61f46db | |||
| 6ac1f96ee3 | |||
| 2da553f4d6 | |||
| 371204785d | |||
| 042bb43d9c | |||
| 1bd4aa40e6 | |||
| d836c67c58 | |||
| fa0b56d2a6 | |||
| 1e02957bdc | |||
| 971282f01f | |||
| 2ca02bad80 | |||
| 81a3a3d4b2 | |||
| 51fe6cae99 | |||
| d49ea51720 | |||
| f846a7b06c | |||
| 234b2dfdaf | |||
| 2ee89a2412 | |||
| e61a67c14f | |||
| d48a4f062d | |||
| 5e3f2aaaad | |||
| 6193817cb8 | |||
| 82778b91ca | |||
|
|
8449b74dc7 | ||
|
|
3e9c031446 | ||
|
|
c90e89cb0c | ||
|
|
67c33aee3e | ||
|
|
14ee0b4127 | ||
|
|
72594c34c1 | ||
|
|
873493f697 | ||
| e046c8c118 | |||
| efb31cc993 | |||
| 1675d4f7ff | |||
| 5f774dc475 | |||
| 95dd754992 | |||
|
|
a9779c207e | ||
|
|
0a34622a02 | ||
|
|
754c3cf02e | ||
|
|
9bdd2aa23d | ||
| c49a350298 | |||
| b4fa6cb962 | |||
| 7e5fdecf1a | |||
| 935d827c58 | |||
| f480578520 | |||
| e95d240562 | |||
| bc4cb35a31 | |||
| ee80c2f4a9 | |||
| ac614921a4 | |||
| b46087ea6c | |||
| c443b97c19 | |||
| fa8569f0c5 | |||
| 36cbfd2712 | |||
| 7fbfe5d9fd | |||
| 5d21258634 | |||
| 4bd7dfc7ff | |||
| 37b9722643 | |||
|
|
8a6fd5c7e5 |
22 changed files with 1140 additions and 796 deletions
|
|
@ -11,11 +11,11 @@
|
||||||
max-width: 30%;
|
max-width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-selector-area {
|
.premium-selector-area {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#amount-area-content {
|
.amount-area-content {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,11 +50,11 @@
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-selector-area {
|
.premium-selector-area {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#amount-area-content {
|
.amount-area-content {
|
||||||
width: 33%;
|
width: 33%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,10 +221,8 @@
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#create-offer-controls {
|
.create-offer-controls {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow-y: auto;
|
|
||||||
max-height: 800px;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,16 +241,16 @@
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-offer-controls-area {
|
.close-offer-controls-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-area > * {
|
.premium-area > * {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-content-area {
|
.premium-content-area {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -261,19 +259,19 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-selector-area {
|
.premium-selector-area {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: 5%;
|
margin-right: 5%;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-value {
|
.premium-value {
|
||||||
border: 1px solid gray;
|
border: 1px solid gray;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-buttons-container {
|
.premium-buttons-container {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,22 +287,22 @@
|
||||||
background: #fff8ce;
|
background: #fff8ce;
|
||||||
}
|
}
|
||||||
|
|
||||||
#button-increase-premium {
|
.button-increase-premium {
|
||||||
border-top-right-radius: 10px;
|
border-top-right-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#button-decrease-premium {
|
.button-decrease-premium {
|
||||||
border-bottom-right-radius: 10px;
|
border-bottom-right-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-price-display-area {
|
.premium-price-display-area {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
#premium-price-display-area > * {
|
.premium-price-display-area > * {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +312,7 @@
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#amount-area-content {
|
.amount-area-content {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
@ -377,7 +375,7 @@
|
||||||
width: 2em;
|
width: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#submit-button-area {
|
.submit-button-area {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
@ -386,7 +384,7 @@
|
||||||
width: 33%;
|
width: 33%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-offer {
|
.close-offer {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,8 @@ h1 {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
max-width: 95%;
|
max-width: 95%;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow: auto;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,24 @@ const DEFAULT_SESSION_DURATION_SECONDS = 60 * 60 * 24 * 30;
|
||||||
const DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS = 60 * 60 * 24 * 30;
|
const DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS = 60 * 60 * 24 * 30;
|
||||||
const DEFAULT_REDIRECT_DELAY = 3 * 1000; // 3seconds times milliseconds;
|
const DEFAULT_REDIRECT_DELAY = 3 * 1000; // 3seconds times milliseconds;
|
||||||
|
|
||||||
|
const API_ROOT = '/api';
|
||||||
const API_PATHS = {
|
const API_PATHS = {
|
||||||
createProfile: '/createProfile',
|
offer: API_ROOT + '/offer',
|
||||||
|
loginNostrChallenge: API_ROOT + '/login/nostr-challenge',
|
||||||
|
loginNostrVerify: API_ROOT + '/login/nostr-verify',
|
||||||
|
signupNostrChallenge: API_ROOT + '/signup/nostr-challenge',
|
||||||
|
signupNostrVerify: API_ROOT + '/signup/nostr-verify',
|
||||||
|
};
|
||||||
|
|
||||||
|
const WEB_PATHS = {
|
||||||
home: '/home',
|
home: '/home',
|
||||||
|
createProfile: '/createProfile',
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
DEFAULT_SESSION_DURATION_SECONDS,
|
DEFAULT_SESSION_DURATION_SECONDS,
|
||||||
DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS,
|
DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS,
|
||||||
API_PATHS,
|
API_PATHS,
|
||||||
|
WEB_PATHS,
|
||||||
DEFAULT_REDIRECT_DELAY,
|
DEFAULT_REDIRECT_DELAY,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
113
src/front/components/AmountInput.js
Normal file
113
src/front/components/AmountInput.js
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
const formatNumberWithSpaces = require('../utils/formatNumbersWithSpaces');
|
||||||
|
|
||||||
|
class AmountInput {
|
||||||
|
constructor({ parentElement, id }) {
|
||||||
|
this.element = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.eurInput = null;
|
||||||
|
this.btcInput = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const amountArea = document.createElement('div');
|
||||||
|
amountArea.id = this.id;
|
||||||
|
amountArea.className = 'amount-area-content';
|
||||||
|
|
||||||
|
const eurAmount = document.createElement('div');
|
||||||
|
eurAmount.className = 'money-amount-input-area';
|
||||||
|
|
||||||
|
this.eurInput = document.createElement('input');
|
||||||
|
this.eurInput.type = 'text';
|
||||||
|
this.eurInput.className = 'money-input input-money-amount';
|
||||||
|
this.eurInput.value = '100';
|
||||||
|
this.eurInput.required = true;
|
||||||
|
|
||||||
|
const eurSymbol = document.createElement('div');
|
||||||
|
eurSymbol.className = 'curr-symbol';
|
||||||
|
|
||||||
|
const eurCharacter = document.createElement('span');
|
||||||
|
eurCharacter.className = 'curr-character';
|
||||||
|
eurCharacter.textContent = '€';
|
||||||
|
|
||||||
|
eurSymbol.appendChild(eurCharacter);
|
||||||
|
eurAmount.appendChild(this.eurInput);
|
||||||
|
eurAmount.appendChild(eurSymbol);
|
||||||
|
|
||||||
|
const btcAmount = document.createElement('div');
|
||||||
|
btcAmount.className = 'money-amount-input-area';
|
||||||
|
|
||||||
|
this.btcInput = document.createElement('input');
|
||||||
|
this.btcInput.type = 'text';
|
||||||
|
this.btcInput.className = 'money-input input-money-amount';
|
||||||
|
this.btcInput.disabled = true;
|
||||||
|
|
||||||
|
const satsSymbol = document.createElement('div');
|
||||||
|
satsSymbol.className = 'curr-symbol';
|
||||||
|
|
||||||
|
const satsCharacter = document.createElement('span');
|
||||||
|
satsCharacter.className = 'curr-character';
|
||||||
|
satsCharacter.textContent = 'SAT';
|
||||||
|
|
||||||
|
satsSymbol.appendChild(satsCharacter);
|
||||||
|
btcAmount.appendChild(this.btcInput);
|
||||||
|
btcAmount.appendChild(satsSymbol);
|
||||||
|
|
||||||
|
amountArea.appendChild(eurAmount);
|
||||||
|
amountArea.appendChild(btcAmount);
|
||||||
|
|
||||||
|
this.eurInput.addEventListener('blur', () => {
|
||||||
|
this.validateAndFormatEurAmountInput();
|
||||||
|
this.updateBtcInput();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eurInput.addEventListener('input', () => {
|
||||||
|
this.eurInput.value = this.eurInput.value.replace(/[^0-9]/g, '');
|
||||||
|
this.updateBtcInput();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.updateBtcInput();
|
||||||
|
|
||||||
|
this.element = amountArea;
|
||||||
|
this.parentElement.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
get intEurAmount() {
|
||||||
|
const eurAmountFieldValue = this.eurInput.value;
|
||||||
|
const regularExpression = /([\d\s]+)/;
|
||||||
|
const matchResult = eurAmountFieldValue.match(regularExpression);
|
||||||
|
|
||||||
|
if (!matchResult) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberString = matchResult[1];
|
||||||
|
const cleanInputNumber = parseInt(numberString.replace(/\s/gi, ''));
|
||||||
|
|
||||||
|
return cleanInputNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAndFormatEurAmountInput() {
|
||||||
|
const cleanInputNumber = this.intEurAmount;
|
||||||
|
this.eurInput.classList.remove('input-is-valid', 'input-is-invalid');
|
||||||
|
if (cleanInputNumber) {
|
||||||
|
this.eurInput.value = formatNumberWithSpaces(cleanInputNumber);
|
||||||
|
this.eurInput.classList.add('input-is-valid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eurInput.classList.add('input-is-invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBtcInput() {
|
||||||
|
const eurToSatRate = 1021;
|
||||||
|
const cleanEurAmount = this.intEurAmount;
|
||||||
|
|
||||||
|
const satsAmount = cleanEurAmount * eurToSatRate;
|
||||||
|
const formattedSatsAmount = formatNumberWithSpaces(satsAmount);
|
||||||
|
this.btcInput.value = formattedSatsAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AmountInput;
|
||||||
35
src/front/components/BigNotesCheckbox.js
Normal file
35
src/front/components/BigNotesCheckbox.js
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
class BigNotesCheckbox {
|
||||||
|
constructor({ parentElement }) {
|
||||||
|
this.bigNotesContainer = null;
|
||||||
|
this.bigNotesCheckboxElement = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.className = 'checkbox-row';
|
||||||
|
|
||||||
|
const checkbox = document.createElement('input');
|
||||||
|
checkbox.type = 'checkbox';
|
||||||
|
checkbox.name = 'large-bills';
|
||||||
|
checkbox.id = 'large-bills-checkbox';
|
||||||
|
|
||||||
|
const label = document.createElement('label');
|
||||||
|
label.htmlFor = 'large-bills-checkbox';
|
||||||
|
label.textContent = 'Se pueden usar billetes grandes (100€, 200€, 500€)';
|
||||||
|
|
||||||
|
container.appendChild(checkbox);
|
||||||
|
container.appendChild(label);
|
||||||
|
|
||||||
|
this.bigNotesContainer = container;
|
||||||
|
this.bigNotesCheckboxElement = checkbox;
|
||||||
|
|
||||||
|
this.parentElement.append(this.bigNotesContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
get areBigNotesAccepted() {
|
||||||
|
return this.bigNotesCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BigNotesCheckbox;
|
||||||
74
src/front/components/BitcoinMethodCheckboxes.js
Normal file
74
src/front/components/BitcoinMethodCheckboxes.js
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
class BitcoinMethodCheckboxes {
|
||||||
|
constructor({ parentElement }) {
|
||||||
|
this.onchainContainer = null;
|
||||||
|
this.onchainCheckboxElement = null;
|
||||||
|
this.lightningContainer = null;
|
||||||
|
this.lightningCheckboxElement = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.onchainContainer = this.buildCheckbox({
|
||||||
|
id: 'onchain',
|
||||||
|
label: 'Onchain',
|
||||||
|
});
|
||||||
|
this.onchainCheckboxElement = this.onchainContainer.querySelector('input');
|
||||||
|
|
||||||
|
this.lightningContainer = this.buildCheckbox({
|
||||||
|
id: 'lightning',
|
||||||
|
label: 'Lightning',
|
||||||
|
});
|
||||||
|
this.lightningCheckboxElement =
|
||||||
|
this.lightningContainer.querySelector('input');
|
||||||
|
|
||||||
|
for (const btcMethodCheckbox of [
|
||||||
|
this.onchainCheckboxElement,
|
||||||
|
this.lightningCheckboxElement,
|
||||||
|
]) {
|
||||||
|
btcMethodCheckbox.addEventListener('click', () => {
|
||||||
|
this.validateBitcoinMethodCheckboxes(btcMethodCheckbox);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parentElement.appendChild(this.onchainContainer);
|
||||||
|
this.parentElement.appendChild(this.lightningContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildCheckbox({ label }) {
|
||||||
|
const checkboxContainer = document.createElement('div');
|
||||||
|
checkboxContainer.className = 'checkbox-row';
|
||||||
|
|
||||||
|
const checkbox = document.createElement('input');
|
||||||
|
checkbox.type = 'checkbox';
|
||||||
|
checkbox.checked = true;
|
||||||
|
|
||||||
|
const labelElement = document.createElement('label');
|
||||||
|
labelElement.htmlFor = checkbox.id;
|
||||||
|
labelElement.textContent = label;
|
||||||
|
|
||||||
|
checkboxContainer.appendChild(checkbox);
|
||||||
|
checkboxContainer.appendChild(labelElement);
|
||||||
|
|
||||||
|
return checkboxContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
validateBitcoinMethodCheckboxes(clickedCheckbox) {
|
||||||
|
let checkedCount = [
|
||||||
|
this.onchainCheckboxElement,
|
||||||
|
this.lightningCheckboxElement,
|
||||||
|
].filter((cb) => cb.checked).length;
|
||||||
|
if (checkedCount === 0) {
|
||||||
|
clickedCheckbox.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get isOnchainAccepted() {
|
||||||
|
return this.onchainCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLightningAccepted() {
|
||||||
|
return this.lightningCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BitcoinMethodCheckboxes;
|
||||||
21
src/front/components/CloseModalButton.js
Normal file
21
src/front/components/CloseModalButton.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
class CloseModalButton {
|
||||||
|
constructor({ parentElement, id, onClickCallback }) {
|
||||||
|
this.element = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
this.id = id;
|
||||||
|
this.onClickCallback = onClickCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const closeButton = document.createElement('button');
|
||||||
|
closeButton.className = 'close-offer button-secondary button-medium';
|
||||||
|
closeButton.textContent = 'Volver';
|
||||||
|
|
||||||
|
closeButton.addEventListener('click', this.onClickCallback);
|
||||||
|
|
||||||
|
this.element = closeButton;
|
||||||
|
this.parentElement.appendChild(this.element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CloseModalButton;
|
||||||
239
src/front/components/CreateOfferModal.js
Normal file
239
src/front/components/CreateOfferModal.js
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
const PublishOfferButton = require('./PublishOfferButton');
|
||||||
|
const BuyOrSellButtonGroup = require('./BuyOrSellButtonGroup');
|
||||||
|
const PremiumSelector = require('./PremiumSelector');
|
||||||
|
const PriceDisplay = require('./PriceDisplay');
|
||||||
|
const AmountInput = require('./AmountInput');
|
||||||
|
const PlaceInput = require('./PlaceInput');
|
||||||
|
const TimeInput = require('./TimeInput');
|
||||||
|
const BitcoinMethodCheckboxes = require('./BitcoinMethodCheckboxes');
|
||||||
|
const TrustCheckboxes = require('./TrustCheckboxes');
|
||||||
|
const BigNotesCheckbox = require('./BigNotesCheckbox');
|
||||||
|
const CloseModalButton = require('./CloseModalButton');
|
||||||
|
|
||||||
|
class CreateOfferModal {
|
||||||
|
constructor({ parentElement, onCreationCallback, offerService }) {
|
||||||
|
this.element = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
this.onCreationCallback = onCreationCallback;
|
||||||
|
this.offerService = offerService;
|
||||||
|
|
||||||
|
this.publishOfferButton = null;
|
||||||
|
this.buyOrSellButtonGroup = null;
|
||||||
|
this.premiumSelector = null;
|
||||||
|
this.amountInput = null;
|
||||||
|
this.placeInput = null;
|
||||||
|
this.timeInput = null;
|
||||||
|
this.btcMethodCheckboxes = null;
|
||||||
|
this.trustCheckboxes = null;
|
||||||
|
this.bigNotesCheckbox = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const modalRoot = document.createElement('div');
|
||||||
|
this.element = modalRoot;
|
||||||
|
modalRoot.className = 'full-screen-modal-background';
|
||||||
|
|
||||||
|
const modal = document.createElement('div');
|
||||||
|
modal.className = 'full-screen-modal';
|
||||||
|
|
||||||
|
const controls = document.createElement('div');
|
||||||
|
controls.className = 'create-offer-controls';
|
||||||
|
|
||||||
|
const title = document.createElement('h2');
|
||||||
|
title.textContent = 'Añade los detalles de tu oferta';
|
||||||
|
controls.appendChild(title);
|
||||||
|
|
||||||
|
const buyOrSellDiv = document.createElement('div');
|
||||||
|
buyOrSellDiv.className = 'create-offer-step';
|
||||||
|
this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({
|
||||||
|
parentElement: buyOrSellDiv,
|
||||||
|
});
|
||||||
|
this.buyOrSellButtonGroup.render();
|
||||||
|
controls.appendChild(buyOrSellDiv);
|
||||||
|
|
||||||
|
const premiumDiv = document.createElement('div');
|
||||||
|
premiumDiv.classList = 'premium-area';
|
||||||
|
premiumDiv.className = 'create-offer-step';
|
||||||
|
const premiumHeading = document.createElement('h3');
|
||||||
|
premiumHeading.textContent = 'Premium';
|
||||||
|
premiumDiv.appendChild(premiumHeading);
|
||||||
|
const premiumContentDiv = document.createElement('div');
|
||||||
|
premiumContentDiv.classList = 'premium-content-area';
|
||||||
|
premiumDiv.appendChild(premiumContentDiv);
|
||||||
|
controls.appendChild(premiumDiv);
|
||||||
|
|
||||||
|
const createOfferEventBus = new EventTarget();
|
||||||
|
|
||||||
|
const mockPriceProvidingCallback = () => {
|
||||||
|
return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.premiumSelector = new PremiumSelector({
|
||||||
|
parentElement: premiumContentDiv,
|
||||||
|
eventSink: createOfferEventBus,
|
||||||
|
});
|
||||||
|
this.premiumSelector.render();
|
||||||
|
|
||||||
|
const priceDisplay = new PriceDisplay({
|
||||||
|
parentElement: premiumContentDiv,
|
||||||
|
id: 'premium-price-display-area',
|
||||||
|
premiumProvidingCallback: () => {
|
||||||
|
return this.premiumSelector.getPremium();
|
||||||
|
},
|
||||||
|
priceProvidingCallback: mockPriceProvidingCallback,
|
||||||
|
});
|
||||||
|
priceDisplay.render();
|
||||||
|
createOfferEventBus.addEventListener('premium-changed', () => {
|
||||||
|
priceDisplay.updatePrices();
|
||||||
|
});
|
||||||
|
|
||||||
|
const amountDiv = document.createElement('div');
|
||||||
|
amountDiv.className = 'create-offer-step';
|
||||||
|
const amountHeading = document.createElement('h3');
|
||||||
|
amountHeading.textContent = '¿Cuánto?';
|
||||||
|
amountDiv.appendChild(amountHeading);
|
||||||
|
controls.appendChild(amountDiv);
|
||||||
|
|
||||||
|
this.amountInput = new AmountInput({
|
||||||
|
parentElement: amountDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.amountInput.render();
|
||||||
|
|
||||||
|
const placeTimeDiv = document.createElement('div');
|
||||||
|
placeTimeDiv.className = 'create-offer-step';
|
||||||
|
const placeTimeHeading = document.createElement('h3');
|
||||||
|
placeTimeHeading.textContent = '¿Dónde y cuándo?';
|
||||||
|
placeTimeDiv.appendChild(placeTimeHeading);
|
||||||
|
const placeTimeContentDiv = document.createElement('div');
|
||||||
|
placeTimeDiv.appendChild(placeTimeContentDiv);
|
||||||
|
controls.appendChild(placeTimeDiv);
|
||||||
|
|
||||||
|
this.placeInput = new PlaceInput({
|
||||||
|
parentElement: placeTimeContentDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.placeInput.render();
|
||||||
|
|
||||||
|
this.timeInput = new TimeInput({
|
||||||
|
parentElement: placeTimeContentDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.timeInput.render();
|
||||||
|
|
||||||
|
const bitcoinMethodsDiv = document.createElement('div');
|
||||||
|
bitcoinMethodsDiv.className = 'create-offer-step';
|
||||||
|
const bitcoinMethodsHeading = document.createElement('h3');
|
||||||
|
bitcoinMethodsHeading.textContent = '¿Cómo se mueve el Bitcoin?';
|
||||||
|
bitcoinMethodsDiv.appendChild(bitcoinMethodsHeading);
|
||||||
|
const bitcoinMethodsContentDiv = document.createElement('div');
|
||||||
|
bitcoinMethodsDiv.appendChild(bitcoinMethodsContentDiv);
|
||||||
|
controls.appendChild(bitcoinMethodsDiv);
|
||||||
|
|
||||||
|
this.btcMethodCheckboxes = new BitcoinMethodCheckboxes({
|
||||||
|
parentElement: bitcoinMethodsContentDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.btcMethodCheckboxes.render();
|
||||||
|
|
||||||
|
const trustDiv = document.createElement('div');
|
||||||
|
trustDiv.className = 'create-offer-step';
|
||||||
|
const trustHeading = document.createElement('h3');
|
||||||
|
trustHeading.textContent = '¿Quién puede ver la oferta?';
|
||||||
|
trustDiv.appendChild(trustHeading);
|
||||||
|
const trustContentDiv = document.createElement('div');
|
||||||
|
trustDiv.appendChild(trustContentDiv);
|
||||||
|
controls.appendChild(trustDiv);
|
||||||
|
|
||||||
|
this.trustCheckboxes = new TrustCheckboxes({
|
||||||
|
parentElement: trustContentDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.trustCheckboxes.render();
|
||||||
|
|
||||||
|
const otherDiv = document.createElement('div');
|
||||||
|
otherDiv.className = 'create-offer-step';
|
||||||
|
const otherHeading = document.createElement('h3');
|
||||||
|
otherHeading.textContent = 'Extras';
|
||||||
|
otherDiv.appendChild(otherHeading);
|
||||||
|
controls.appendChild(otherDiv);
|
||||||
|
|
||||||
|
this.bigNotesCheckbox = new BigNotesCheckbox({
|
||||||
|
parentElement: otherDiv,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bigNotesCheckbox.render();
|
||||||
|
//Continue moving components up here
|
||||||
|
|
||||||
|
const submitButtonArea = document.createElement('div');
|
||||||
|
submitButtonArea.classList.add('submit-button-area');
|
||||||
|
this.publishOfferButton = new PublishOfferButton({
|
||||||
|
parentElement: submitButtonArea,
|
||||||
|
id: 'button-submit-offer',
|
||||||
|
onClickCallback: async () => {
|
||||||
|
await this.createOffer();
|
||||||
|
await this.onCreationCallback();
|
||||||
|
this.toggle();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.publishOfferButton.render();
|
||||||
|
|
||||||
|
const closeButtonArea = document.createElement('div');
|
||||||
|
closeButtonArea.className = 'close-offer-controls-area';
|
||||||
|
const closeButton = new CloseModalButton({
|
||||||
|
parentElement: closeButtonArea,
|
||||||
|
onClickCallback: () => {
|
||||||
|
this.toggle();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
closeButton.render();
|
||||||
|
|
||||||
|
controls.appendChild(submitButtonArea);
|
||||||
|
controls.appendChild(closeButtonArea);
|
||||||
|
|
||||||
|
modal.appendChild(controls);
|
||||||
|
modalRoot.appendChild(modal);
|
||||||
|
|
||||||
|
this.parentElement.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.element.classList.toggle('shown');
|
||||||
|
}
|
||||||
|
|
||||||
|
async createOffer() {
|
||||||
|
const wants = this.buyOrSellButtonGroup.wants();
|
||||||
|
|
||||||
|
const premium = this.premiumSelector.getPremium();
|
||||||
|
const trade_amount_eur = this.amountInput.intEurAmount;
|
||||||
|
const location_details = this.placeInput.inputText;
|
||||||
|
const time_availability_details = this.timeInput.inputText;
|
||||||
|
const is_onchain_accepted = this.btcMethodCheckboxes.isOnchainAccepted;
|
||||||
|
const is_lightning_accepted = this.btcMethodCheckboxes.isLightningAccepted;
|
||||||
|
const show_offer_to_trusted = this.trustCheckboxes.showOfferToTrusted;
|
||||||
|
const show_offer_to_trusted_trusted =
|
||||||
|
this.trustCheckboxes.showOfferToTrustedTrusted;
|
||||||
|
const show_offer_to_all_members =
|
||||||
|
this.trustCheckboxes.showOfferToAllMembers;
|
||||||
|
const are_big_notes_accepted = this.bigNotesCheckbox.areBigNotesAccepted;
|
||||||
|
|
||||||
|
const offerDetails = {
|
||||||
|
wants,
|
||||||
|
premium,
|
||||||
|
trade_amount_eur,
|
||||||
|
location_details,
|
||||||
|
time_availability_details,
|
||||||
|
is_onchain_accepted,
|
||||||
|
is_lightning_accepted,
|
||||||
|
show_offer_to_trusted,
|
||||||
|
show_offer_to_trusted_trusted,
|
||||||
|
show_offer_to_all_members,
|
||||||
|
are_big_notes_accepted,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.offerService.createOffer(offerDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CreateOfferModal;
|
||||||
374
src/front/components/OfferCard.js
Normal file
374
src/front/components/OfferCard.js
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
class OfferCard {
|
||||||
|
constructor({ offerData, deleteButtonCallback }) {
|
||||||
|
this.uuid = offerData.uuid;
|
||||||
|
this.public_key = offerData.public_key;
|
||||||
|
this.wants = offerData.wants;
|
||||||
|
this.premium = offerData.premium;
|
||||||
|
this.trade_amount_eur = offerData.trade_amount_eur;
|
||||||
|
this.location_details = offerData.location_details;
|
||||||
|
this.time_availability_details = offerData.time_availability_details;
|
||||||
|
this.show_offer_to_trusted = offerData.show_offer_to_trusted;
|
||||||
|
this.show_offer_to_trusted_trusted =
|
||||||
|
offerData.show_offer_to_trusted_trusted;
|
||||||
|
this.show_offer_to_all_members = offerData.show_offer_to_all_members;
|
||||||
|
this.is_onchain_accepted = offerData.is_onchain_accepted;
|
||||||
|
this.is_lightning_accepted = offerData.is_lightning_accepted;
|
||||||
|
this.are_big_notes_accepted = offerData.are_big_notes_accepted;
|
||||||
|
this.created_at = offerData.created_at;
|
||||||
|
this.last_updated_at = offerData.last_updated_at;
|
||||||
|
|
||||||
|
this.deleteButtonCallback = deleteButtonCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildHTML() {
|
||||||
|
const offerCard = document.createElement('div');
|
||||||
|
offerCard.classList.add('myoffer-card');
|
||||||
|
offerCard.classList.add('shadowed-round-area');
|
||||||
|
|
||||||
|
const tradeDescDiv = document.createElement('div');
|
||||||
|
tradeDescDiv.classList.add('trade-desc');
|
||||||
|
|
||||||
|
const youBuyText = document.createElement('p');
|
||||||
|
youBuyText.classList.add('offer-card-content-title');
|
||||||
|
youBuyText.innerText = 'Compras';
|
||||||
|
tradeDescDiv.append(youBuyText);
|
||||||
|
|
||||||
|
const youBuyData = document.createElement('p');
|
||||||
|
youBuyData.classList.add('offer-card-content-data');
|
||||||
|
if (this.wants === 'BTC') {
|
||||||
|
youBuyData.innerText = `${this.trade_amount_eur * 1021} sats`;
|
||||||
|
}
|
||||||
|
if (this.wants === 'EUR') {
|
||||||
|
youBuyData.innerText = `${this.trade_amount_eur} €`;
|
||||||
|
}
|
||||||
|
tradeDescDiv.append(youBuyData);
|
||||||
|
|
||||||
|
const youSellText = document.createElement('p');
|
||||||
|
youSellText.classList.add('offer-card-content-title');
|
||||||
|
youSellText.innerText = 'Vendes';
|
||||||
|
tradeDescDiv.append(youSellText);
|
||||||
|
|
||||||
|
const youSellData = document.createElement('p');
|
||||||
|
youSellData.classList.add('offer-card-content-data');
|
||||||
|
if (this.wants === 'BTC') {
|
||||||
|
youSellData.innerText = `${this.trade_amount_eur} €`;
|
||||||
|
}
|
||||||
|
if (this.wants === 'EUR') {
|
||||||
|
youSellData.innerText = `${this.trade_amount_eur * 1021} sats`;
|
||||||
|
}
|
||||||
|
tradeDescDiv.append(youSellData);
|
||||||
|
|
||||||
|
const premiumDescDiv = document.createElement('div');
|
||||||
|
premiumDescDiv.classList.add('premium-desc');
|
||||||
|
|
||||||
|
const premiumTitle = document.createElement('p');
|
||||||
|
premiumTitle.classList.add('offer-card-content-title');
|
||||||
|
premiumTitle.innerText = 'Premium';
|
||||||
|
premiumDescDiv.append(premiumTitle);
|
||||||
|
|
||||||
|
const premiumData = document.createElement('p');
|
||||||
|
premiumData.classList.add('offer-card-content-data');
|
||||||
|
premiumData.innerText = `${this.premium * 100} %`;
|
||||||
|
premiumDescDiv.append(premiumData);
|
||||||
|
|
||||||
|
const offerPriceTitle = document.createElement('p');
|
||||||
|
offerPriceTitle.classList.add('offer-card-content-title');
|
||||||
|
offerPriceTitle.innerText = 'Precio oferta';
|
||||||
|
premiumDescDiv.append(offerPriceTitle);
|
||||||
|
|
||||||
|
const offerPriceData = document.createElement('p');
|
||||||
|
offerPriceData.classList.add('offer-card-content-data');
|
||||||
|
offerPriceData.innerText = `90000 €/BTC`;
|
||||||
|
premiumDescDiv.append(offerPriceData);
|
||||||
|
|
||||||
|
const marketPriceTitle = document.createElement('p');
|
||||||
|
marketPriceTitle.classList.add('offer-card-content-title');
|
||||||
|
marketPriceTitle.innerText = 'Precio mercado';
|
||||||
|
premiumDescDiv.append(marketPriceTitle);
|
||||||
|
|
||||||
|
const marketPriceData = document.createElement('p');
|
||||||
|
marketPriceData.innerText = `88000 €/BTC`;
|
||||||
|
premiumDescDiv.append(marketPriceData);
|
||||||
|
|
||||||
|
const whereDescDiv = document.createElement('div');
|
||||||
|
whereDescDiv.classList.add('where-desc');
|
||||||
|
|
||||||
|
const whereDescTitle = document.createElement('p');
|
||||||
|
whereDescTitle.classList.add('offer-card-content-title');
|
||||||
|
whereDescTitle.innerText = 'Dónde';
|
||||||
|
whereDescDiv.append(whereDescTitle);
|
||||||
|
|
||||||
|
const whereDescData = document.createElement('p');
|
||||||
|
whereDescData.classList.add('offer-long-text');
|
||||||
|
whereDescData.innerText = `${this.location_details}`;
|
||||||
|
whereDescDiv.append(whereDescData);
|
||||||
|
|
||||||
|
const whenDescDiv = document.createElement('div');
|
||||||
|
whenDescDiv.classList.add('when-desc');
|
||||||
|
|
||||||
|
const whenDescTitle = document.createElement('p');
|
||||||
|
whenDescTitle.classList.add('offer-card-content-title');
|
||||||
|
whenDescTitle.innerText = 'Cúando';
|
||||||
|
whenDescDiv.append(whenDescTitle);
|
||||||
|
|
||||||
|
const whenDescData = document.createElement('p');
|
||||||
|
whenDescData.classList.add('offer-long-text');
|
||||||
|
whenDescData.innerText = `${this.time_availability_details}`;
|
||||||
|
whenDescDiv.append(whenDescData);
|
||||||
|
|
||||||
|
const bitcoinMethodsDiv = document.createElement('div');
|
||||||
|
bitcoinMethodsDiv.classList.add('bitcoin-methods-desc');
|
||||||
|
|
||||||
|
const bitcoinMethodsTitle = document.createElement('p');
|
||||||
|
bitcoinMethodsTitle.classList.add('offer-card-content-title');
|
||||||
|
bitcoinMethodsTitle.innerText = 'Protocolos Bitcoin aceptados';
|
||||||
|
bitcoinMethodsDiv.append(bitcoinMethodsTitle);
|
||||||
|
|
||||||
|
const onchainAcceptedContainer = document.createElement('div');
|
||||||
|
onchainAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
||||||
|
if (this.is_onchain_accepted) {
|
||||||
|
const onchainIcon = document.createElement('img');
|
||||||
|
onchainIcon.src = '/img/chains-lasecagold.svg';
|
||||||
|
const onchainText = document.createElement('p');
|
||||||
|
onchainText.innerText = 'Onchain';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
|
||||||
|
} else {
|
||||||
|
const onchainIcon = document.createElement('img');
|
||||||
|
onchainIcon.src = '/img/chains-gray.svg';
|
||||||
|
const onchainText = document.createElement('p');
|
||||||
|
onchainText.innerText = 'Onchain';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
|
||||||
|
}
|
||||||
|
const lightningAcceptedContainer = document.createElement('div');
|
||||||
|
|
||||||
|
lightningAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
||||||
|
if (this.is_lightning_accepted) {
|
||||||
|
const lightningIcon = document.createElement('img');
|
||||||
|
lightningIcon.src = '/img/bolt-lightning-lasecagold.svg';
|
||||||
|
const lightningText = document.createElement('p');
|
||||||
|
lightningText.innerText = 'Lightning';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
lightningAcceptedContainer.append(
|
||||||
|
lightningIcon,
|
||||||
|
lightningText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const lightningIcon = document.createElement('img');
|
||||||
|
lightningIcon.src = '/img/bolt-lightning-gray.svg';
|
||||||
|
const lightningText = document.createElement('p');
|
||||||
|
lightningText.innerText = 'Lightning';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
lightningAcceptedContainer.append(
|
||||||
|
lightningIcon,
|
||||||
|
lightningText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitcoinMethodsDiv.append(
|
||||||
|
onchainAcceptedContainer,
|
||||||
|
lightningAcceptedContainer
|
||||||
|
);
|
||||||
|
|
||||||
|
const visibilityDiv = document.createElement('div');
|
||||||
|
visibilityDiv.classList.add('visibility-desc');
|
||||||
|
|
||||||
|
const visibilityTitle = document.createElement('p');
|
||||||
|
visibilityTitle.classList.add('offer-card-content-title');
|
||||||
|
visibilityTitle.innerText = 'Visibilidad';
|
||||||
|
visibilityDiv.append(visibilityTitle);
|
||||||
|
|
||||||
|
const showOfferToTrustedContainer = document.createElement('div');
|
||||||
|
showOfferToTrustedContainer.classList.add('right-icon-checkboxed-field');
|
||||||
|
|
||||||
|
if (this.show_offer_to_trusted) {
|
||||||
|
const showOfferToTrustedIcon = document.createElement('img');
|
||||||
|
showOfferToTrustedIcon.src = '/img/user-lasecagold.svg';
|
||||||
|
const showOfferToTrustedText = document.createElement('p');
|
||||||
|
showOfferToTrustedText.innerText = 'Confiados';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
showOfferToTrustedContainer.append(
|
||||||
|
showOfferToTrustedIcon,
|
||||||
|
showOfferToTrustedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const showOfferToTrustedIcon = document.createElement('img');
|
||||||
|
showOfferToTrustedIcon.src = '/img/user-gray.svg';
|
||||||
|
const showOfferToTrustedText = document.createElement('p');
|
||||||
|
showOfferToTrustedText.innerText = 'Confiados';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
showOfferToTrustedContainer.append(
|
||||||
|
showOfferToTrustedIcon,
|
||||||
|
showOfferToTrustedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showOfferToTrustedTrustedContainer = document.createElement('div');
|
||||||
|
showOfferToTrustedTrustedContainer.classList.add(
|
||||||
|
'right-icon-checkboxed-field'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.show_offer_to_trusted_trusted) {
|
||||||
|
const showOfferToTrustedTrustedIcon = document.createElement('img');
|
||||||
|
showOfferToTrustedTrustedIcon.src = '/img/user-group-lasecagold.svg';
|
||||||
|
const showOfferToTrustedTrustedText = document.createElement('p');
|
||||||
|
showOfferToTrustedTrustedText.innerText = 'Sus confiados';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
showOfferToTrustedTrustedContainer.append(
|
||||||
|
showOfferToTrustedTrustedIcon,
|
||||||
|
showOfferToTrustedTrustedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const showOfferToTrustedTrustedIcon = document.createElement('img');
|
||||||
|
showOfferToTrustedTrustedIcon.src = '/img/user-group-gray.svg';
|
||||||
|
const showOfferToTrustedTrustedText = document.createElement('p');
|
||||||
|
showOfferToTrustedTrustedText.innerText = 'Sus confiados';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
showOfferToTrustedTrustedContainer.append(
|
||||||
|
showOfferToTrustedTrustedIcon,
|
||||||
|
showOfferToTrustedTrustedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showOfferToAllMembersContainer = document.createElement('div');
|
||||||
|
showOfferToAllMembersContainer.classList.add('right-icon-checkboxed-field');
|
||||||
|
|
||||||
|
if (this.show_offer_to_all_members) {
|
||||||
|
const showOfferToAllMembersIcon = document.createElement('img');
|
||||||
|
showOfferToAllMembersIcon.src = '/img/many-users-lasecagold.svg';
|
||||||
|
const showOfferToAllMembersText = document.createElement('p');
|
||||||
|
showOfferToAllMembersText.innerText = 'Todos';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
showOfferToAllMembersContainer.append(
|
||||||
|
showOfferToAllMembersIcon,
|
||||||
|
showOfferToAllMembersText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const showOfferToAllMembersIcon = document.createElement('img');
|
||||||
|
showOfferToAllMembersIcon.src = '/img/many-users-gray.svg';
|
||||||
|
const showOfferToAllMembersText = document.createElement('p');
|
||||||
|
showOfferToAllMembersText.innerText = 'Todos';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
showOfferToAllMembersContainer.append(
|
||||||
|
showOfferToAllMembersIcon,
|
||||||
|
showOfferToAllMembersText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
visibilityDiv.append(
|
||||||
|
showOfferToTrustedContainer,
|
||||||
|
showOfferToTrustedTrustedContainer,
|
||||||
|
showOfferToAllMembersContainer
|
||||||
|
);
|
||||||
|
|
||||||
|
const otherOfferFeaturesDiv = document.createElement('div');
|
||||||
|
otherOfferFeaturesDiv.classList.add('other-desc');
|
||||||
|
|
||||||
|
const otherOfferFeaturesTitle = document.createElement('p');
|
||||||
|
otherOfferFeaturesTitle.classList.add('offer-card-content-title');
|
||||||
|
otherOfferFeaturesTitle.innerText = 'Otros';
|
||||||
|
otherOfferFeaturesDiv.append(otherOfferFeaturesTitle);
|
||||||
|
|
||||||
|
const areBigNotesAcceptedContainer = document.createElement('div');
|
||||||
|
areBigNotesAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
||||||
|
|
||||||
|
if (this.are_big_notes_accepted) {
|
||||||
|
const areBigNotesAcceptedIcon = document.createElement('img');
|
||||||
|
areBigNotesAcceptedIcon.src = '/img/eur-bill-lasecagold.svg';
|
||||||
|
const areBigNotesAcceptedText = document.createElement('p');
|
||||||
|
areBigNotesAcceptedText.innerText = 'Billetes grandes';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-check-green.svg';
|
||||||
|
|
||||||
|
areBigNotesAcceptedContainer.append(
|
||||||
|
areBigNotesAcceptedIcon,
|
||||||
|
areBigNotesAcceptedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const areBigNotesAcceptedIcon = document.createElement('img');
|
||||||
|
areBigNotesAcceptedIcon.src = '/img/eur-bill-gray.svg';
|
||||||
|
const areBigNotesAcceptedText = document.createElement('p');
|
||||||
|
areBigNotesAcceptedText.innerText = 'Billetes grandes';
|
||||||
|
const checkIcon = document.createElement('img');
|
||||||
|
checkIcon.src = '/img/circle-xmark-gray.svg';
|
||||||
|
|
||||||
|
areBigNotesAcceptedContainer.append(
|
||||||
|
areBigNotesAcceptedIcon,
|
||||||
|
areBigNotesAcceptedText,
|
||||||
|
checkIcon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
otherOfferFeaturesDiv.append(areBigNotesAcceptedContainer);
|
||||||
|
|
||||||
|
const actionButtonsArea = document.createElement('p');
|
||||||
|
actionButtonsArea.classList.add('offer-action-buttons-area');
|
||||||
|
|
||||||
|
const editActionArea = document.createElement('div');
|
||||||
|
editActionArea.classList.add('offer-action-area');
|
||||||
|
editActionArea.classList.add('subtle-box');
|
||||||
|
const editActionIcon = document.createElement('img');
|
||||||
|
editActionIcon.src = '/img/edit.svg';
|
||||||
|
const editActionText = document.createElement('p');
|
||||||
|
editActionText.innerText = 'Editar';
|
||||||
|
editActionArea.append(editActionIcon, editActionText);
|
||||||
|
|
||||||
|
const deleteActionArea = document.createElement('div');
|
||||||
|
deleteActionArea.classList.add('offer-action-area');
|
||||||
|
deleteActionArea.classList.add('subtle-box');
|
||||||
|
const deleteActionIcon = document.createElement('img');
|
||||||
|
deleteActionIcon.src = '/img/trash-can-darkred.svg';
|
||||||
|
const deleteActionText = document.createElement('p');
|
||||||
|
deleteActionText.innerText = 'Eliminar';
|
||||||
|
deleteActionArea.append(deleteActionIcon, deleteActionText);
|
||||||
|
deleteActionArea.addEventListener('click', async () => {
|
||||||
|
await this.deleteButtonCallback();
|
||||||
|
});
|
||||||
|
|
||||||
|
actionButtonsArea.append(editActionArea, deleteActionArea);
|
||||||
|
|
||||||
|
offerCard.append(
|
||||||
|
tradeDescDiv,
|
||||||
|
premiumDescDiv,
|
||||||
|
whereDescDiv,
|
||||||
|
whenDescDiv,
|
||||||
|
bitcoinMethodsDiv,
|
||||||
|
visibilityDiv,
|
||||||
|
otherOfferFeaturesDiv,
|
||||||
|
actionButtonsArea
|
||||||
|
);
|
||||||
|
|
||||||
|
return offerCard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = OfferCard;
|
||||||
26
src/front/components/PlaceInput.js
Normal file
26
src/front/components/PlaceInput.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
class PlaceInput {
|
||||||
|
constructor({ parentElement, id }) {
|
||||||
|
this.element = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const placeInput = document.createElement('textarea');
|
||||||
|
placeInput.id = this.id;
|
||||||
|
placeInput.className = 'place-and-time-box';
|
||||||
|
placeInput.autocomplete = 'on';
|
||||||
|
placeInput.maxLength = 140;
|
||||||
|
placeInput.placeholder =
|
||||||
|
"¿Dónde? Ej.'Eixample', 'La Maquinista', 'Cualquier lugar en BCN', 'Meetup BBO'";
|
||||||
|
|
||||||
|
this.element = placeInput;
|
||||||
|
this.parentElement.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputText() {
|
||||||
|
return this.element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PlaceInput;
|
||||||
|
|
@ -9,7 +9,7 @@ class PopupNotification {
|
||||||
render() {
|
render() {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.id = this.id;
|
div.id = this.id;
|
||||||
div.className = 'top-notification-good';
|
div.className = 'top-notification-good max-size-zero';
|
||||||
|
|
||||||
div.innerHTML = `<img src="/img/circle-check-white.svg" />
|
div.innerHTML = `<img src="/img/circle-check-white.svg" />
|
||||||
<p>${this.text}</p>`;
|
<p>${this.text}</p>`;
|
||||||
|
|
@ -21,5 +21,19 @@ class PopupNotification {
|
||||||
display() {
|
display() {
|
||||||
this.element.classList.add('revealed');
|
this.element.classList.add('revealed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayTemporarily(milliseconds) {
|
||||||
|
if (!milliseconds) {
|
||||||
|
milliseconds = 1000;
|
||||||
|
}
|
||||||
|
this.element.classList.remove('max-size-zero');
|
||||||
|
this.element.classList.add('revealed');
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.remove('revealed');
|
||||||
|
}, milliseconds);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.add('max-size-zero');
|
||||||
|
}, milliseconds + 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = PopupNotification;
|
module.exports = PopupNotification;
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ class PremiumSelector {
|
||||||
render() {
|
render() {
|
||||||
const premiumSelectorArea = document.createElement('div');
|
const premiumSelectorArea = document.createElement('div');
|
||||||
premiumSelectorArea.id = this.id;
|
premiumSelectorArea.id = this.id;
|
||||||
|
premiumSelectorArea.classList = 'premium-selector-area';
|
||||||
|
|
||||||
const premiumValue = document.createElement('div');
|
const premiumValue = document.createElement('div');
|
||||||
premiumValue.id = 'premium-value';
|
premiumValue.className = 'premium-value';
|
||||||
premiumValue.textContent = '0%';
|
premiumValue.textContent = '0%';
|
||||||
this.premiumValue = premiumValue;
|
this.premiumValue = premiumValue;
|
||||||
|
|
||||||
|
|
@ -22,12 +23,12 @@ class PremiumSelector {
|
||||||
|
|
||||||
const increaseButton = document.createElement('button');
|
const increaseButton = document.createElement('button');
|
||||||
increaseButton.classList.add('premium-button');
|
increaseButton.classList.add('premium-button');
|
||||||
increaseButton.id = 'button-increase-premium';
|
increaseButton.classList.add('button-increase-premium');
|
||||||
increaseButton.textContent = '+';
|
increaseButton.textContent = '+';
|
||||||
|
|
||||||
const decreaseButton = document.createElement('button');
|
const decreaseButton = document.createElement('button');
|
||||||
decreaseButton.classList.add('premium-button');
|
decreaseButton.classList.add('premium-button');
|
||||||
decreaseButton.id = 'button-decrease-premium';
|
decreaseButton.classList.add('button-decrease-premium');
|
||||||
decreaseButton.textContent = '-';
|
decreaseButton.textContent = '-';
|
||||||
|
|
||||||
premiumButtonsContainer.appendChild(increaseButton);
|
premiumButtonsContainer.appendChild(increaseButton);
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ class PriceDisplay {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.id = 'premium-price-display-area';
|
container.id = this.id;
|
||||||
|
container.classList = 'premium-price-display-area';
|
||||||
|
|
||||||
const offerParagraph = document.createElement('p');
|
const offerParagraph = document.createElement('p');
|
||||||
offerParagraph.id = 'offer-price-paragraph';
|
|
||||||
offerParagraph.textContent = 'Tu precio: ';
|
offerParagraph.textContent = 'Tu precio: ';
|
||||||
|
|
||||||
const offerSpan = document.createElement('span');
|
const offerSpan = document.createElement('span');
|
||||||
|
|
@ -30,11 +30,9 @@ class PriceDisplay {
|
||||||
offerParagraph.append('€/BTC');
|
offerParagraph.append('€/BTC');
|
||||||
|
|
||||||
const marketParagraph = document.createElement('p');
|
const marketParagraph = document.createElement('p');
|
||||||
marketParagraph.id = 'market-price-paragraph';
|
|
||||||
marketParagraph.textContent = '(Precio mercado: ';
|
marketParagraph.textContent = '(Precio mercado: ';
|
||||||
|
|
||||||
const marketSpan = document.createElement('span');
|
const marketSpan = document.createElement('span');
|
||||||
marketSpan.id = 'market-price';
|
|
||||||
this.marketPriceSpan = marketSpan;
|
this.marketPriceSpan = marketSpan;
|
||||||
|
|
||||||
marketParagraph.appendChild(marketSpan);
|
marketParagraph.appendChild(marketSpan);
|
||||||
|
|
|
||||||
26
src/front/components/TimeInput.js
Normal file
26
src/front/components/TimeInput.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
class TimeInput {
|
||||||
|
constructor({ parentElement, id }) {
|
||||||
|
this.element = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const timeInput = document.createElement('textarea');
|
||||||
|
timeInput.id = this.id;
|
||||||
|
timeInput.className = 'place-and-time-box';
|
||||||
|
timeInput.autocomplete = 'on';
|
||||||
|
timeInput.maxLength = 140;
|
||||||
|
timeInput.placeholder =
|
||||||
|
'¿Cuándo? Ej."Cualquier hora", "19:00-21:00", "Finde"';
|
||||||
|
|
||||||
|
this.element = timeInput;
|
||||||
|
this.parentElement.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputText() {
|
||||||
|
return this.element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TimeInput;
|
||||||
111
src/front/components/TrustCheckboxes.js
Normal file
111
src/front/components/TrustCheckboxes.js
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
class TrustCheckboxes {
|
||||||
|
constructor({ parentElement }) {
|
||||||
|
this.myTrustedContainer = null;
|
||||||
|
this.myTrustedCheckboxElement = null;
|
||||||
|
this.myTrustedTrustedContainer = null;
|
||||||
|
this.myTrustedTrustedCheckboxElement = null;
|
||||||
|
this.allMembersContainer = null;
|
||||||
|
this.allMembersCheckboxElement = null;
|
||||||
|
this.parentElement = parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const checkboxesDetails = [
|
||||||
|
{
|
||||||
|
label: 'Mis confiados',
|
||||||
|
containerProperty: 'myTrustedContainer',
|
||||||
|
checkboxProperty: 'myTrustedCheckboxElement',
|
||||||
|
defaultChecked: true,
|
||||||
|
isDisabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Los confiados de mis confiados',
|
||||||
|
containerProperty: 'myTrustedTrustedContainer',
|
||||||
|
checkboxProperty: 'myTrustedTrustedCheckboxElement',
|
||||||
|
defaultChecked: true,
|
||||||
|
isDisabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Todos los miembros',
|
||||||
|
containerProperty: 'allMembersContainer',
|
||||||
|
checkboxProperty: 'allMembersCheckboxElement',
|
||||||
|
defaultChecked: false,
|
||||||
|
isDisabled: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const checkboxDetails of checkboxesDetails) {
|
||||||
|
this[checkboxDetails.containerProperty] = this.buildCheckbox({
|
||||||
|
label: checkboxDetails.label,
|
||||||
|
});
|
||||||
|
|
||||||
|
this[checkboxDetails.checkboxProperty] =
|
||||||
|
this[checkboxDetails.containerProperty].querySelector('input');
|
||||||
|
|
||||||
|
this[checkboxDetails.checkboxProperty].addEventListener('click', () => {
|
||||||
|
this.applyTrustCheckboxConstraints(
|
||||||
|
this[checkboxDetails.checkboxProperty]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this[checkboxDetails.checkboxProperty].checked =
|
||||||
|
checkboxDetails.defaultChecked;
|
||||||
|
this[checkboxDetails.checkboxProperty].disabled =
|
||||||
|
checkboxDetails.isDisabled;
|
||||||
|
|
||||||
|
this.parentElement.appendChild(this[checkboxDetails.containerProperty]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildCheckbox({ label }) {
|
||||||
|
const checkboxContainer = document.createElement('div');
|
||||||
|
checkboxContainer.className = 'checkbox-row';
|
||||||
|
|
||||||
|
const checkbox = document.createElement('input');
|
||||||
|
checkbox.type = 'checkbox';
|
||||||
|
checkbox.checked = true;
|
||||||
|
|
||||||
|
const labelElement = document.createElement('label');
|
||||||
|
labelElement.htmlFor = checkbox.id;
|
||||||
|
labelElement.textContent = label;
|
||||||
|
|
||||||
|
checkboxContainer.appendChild(checkbox);
|
||||||
|
checkboxContainer.appendChild(labelElement);
|
||||||
|
|
||||||
|
return checkboxContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTrustCheckboxConstraints(pressedCheckbox) {
|
||||||
|
if (pressedCheckbox === this.myTrustedTrustedCheckboxElement) {
|
||||||
|
if (
|
||||||
|
!this.myTrustedTrustedCheckboxElement.checked &&
|
||||||
|
this.allMembersCheckboxElement.checked
|
||||||
|
) {
|
||||||
|
this.allMembersCheckboxElement.checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pressedCheckbox === this.allMembersCheckboxElement) {
|
||||||
|
if (
|
||||||
|
!this.myTrustedTrustedCheckboxElement.checked &&
|
||||||
|
this.allMembersCheckboxElement.checked
|
||||||
|
) {
|
||||||
|
this.myTrustedTrustedCheckboxElement.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOfferToTrusted() {
|
||||||
|
return this.myTrustedCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOfferToTrustedTrusted() {
|
||||||
|
return this.myTrustedTrustedCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showOfferToAllMembers() {
|
||||||
|
return this.allMembersCheckboxElement.checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TrustCheckboxes;
|
||||||
|
|
@ -24,7 +24,7 @@ const invitesFunction = () => {
|
||||||
if (verifyResponse.ok) {
|
if (verifyResponse.ok) {
|
||||||
signUpSuccessPopup.display();
|
signUpSuccessPopup.display();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = constants.API_PATHS.createProfile;
|
window.location.href = constants.WEB_PATHS.createProfile;
|
||||||
}, constants.DEFAULT_REDIRECT_DELAY);
|
}, constants.DEFAULT_REDIRECT_DELAY);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const loginFunction = () => {
|
||||||
nostrLoginButton.disable();
|
nostrLoginButton.disable();
|
||||||
successPopup.display();
|
successPopup.display();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = constants.API_PATHS.home;
|
window.location.href = constants.WEB_PATHS.home;
|
||||||
}, constants.DEFAULT_REDIRECT_DELAY);
|
}, constants.DEFAULT_REDIRECT_DELAY);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,32 @@
|
||||||
const formatNumberWithSpaces = require('../utils/formatNumbersWithSpaces');
|
const PopupNotification = require('../components/PopupNotification');
|
||||||
const PublishOfferButton = require('../components/PublishOfferButton');
|
const CreateOfferModal = require('../components/CreateOfferModal');
|
||||||
const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup');
|
const OfferCard = require('../components/OfferCard');
|
||||||
const PremiumSelector = require('../components/PremiumSelector');
|
|
||||||
const PriceDisplay = require('../components/PriceDisplay');
|
const offerService = require('../services/offerService');
|
||||||
|
|
||||||
function offersPage() {
|
function offersPage() {
|
||||||
const createOfferEventBus = new EventTarget();
|
const offerCreatedPopup = new PopupNotification({
|
||||||
|
parentElement: document.body,
|
||||||
|
text: '¡Oferta creada! Puedes verla en tus ofertas.',
|
||||||
|
});
|
||||||
|
offerCreatedPopup.render();
|
||||||
|
|
||||||
const publishOfferButton = new PublishOfferButton({
|
const offerDeletedPopup = new PopupNotification({
|
||||||
parentElement: document.getElementById('submit-button-area'),
|
parentElement: document.body,
|
||||||
id: 'button-submit-offer',
|
text: '¡Oferta eliminada!',
|
||||||
onClickCallback: async () => {
|
});
|
||||||
await publishOffer();
|
offerDeletedPopup.render();
|
||||||
|
|
||||||
|
const createOfferModal = new CreateOfferModal({
|
||||||
|
parentElement: document.body,
|
||||||
|
onCreationCallback: async () => {
|
||||||
await myOffers.getOffersFromApi();
|
await myOffers.getOffersFromApi();
|
||||||
await myOffers.render();
|
await myOffers.render();
|
||||||
|
offerCreatedPopup.displayTemporarily(3000);
|
||||||
},
|
},
|
||||||
|
offerService: offerService,
|
||||||
});
|
});
|
||||||
publishOfferButton.render();
|
createOfferModal.render();
|
||||||
|
|
||||||
const buyOrSellButtonGroup = new BuyOrSellButtonGroup({
|
|
||||||
parentElement: document.getElementById('buy-or-sell-area'),
|
|
||||||
id: 'button-group-buy-or-sell',
|
|
||||||
});
|
|
||||||
buyOrSellButtonGroup.render();
|
|
||||||
|
|
||||||
const premiumSelector = new PremiumSelector({
|
|
||||||
parentElement: document.getElementById('premium-content-area'),
|
|
||||||
id: 'premium-selector-area',
|
|
||||||
eventSink: createOfferEventBus,
|
|
||||||
});
|
|
||||||
premiumSelector.render();
|
|
||||||
|
|
||||||
const priceDisplay = new PriceDisplay({
|
|
||||||
parentElement: document.getElementById('premium-content-area'),
|
|
||||||
id: 'premium-price-display-area',
|
|
||||||
premiumProvidingCallback: () => {
|
|
||||||
return premiumSelector.getPremium();
|
|
||||||
},
|
|
||||||
priceProvidingCallback: () => {
|
|
||||||
return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
priceDisplay.render();
|
|
||||||
createOfferEventBus.addEventListener('premium-changed', () => {
|
|
||||||
priceDisplay.updatePrices();
|
|
||||||
});
|
|
||||||
|
|
||||||
// -----------
|
// -----------
|
||||||
const navbuttonHome = document.getElementById('navbutton-home');
|
const navbuttonHome = document.getElementById('navbutton-home');
|
||||||
const navbuttonOffers = document.getElementById('navbutton-offers');
|
const navbuttonOffers = document.getElementById('navbutton-offers');
|
||||||
|
|
@ -62,550 +43,15 @@ function offersPage() {
|
||||||
'button-start-create-offer'
|
'button-start-create-offer'
|
||||||
);
|
);
|
||||||
const buttonViewMyOffers = document.getElementById('button-view-my-offers');
|
const buttonViewMyOffers = document.getElementById('button-view-my-offers');
|
||||||
const closeOffer = document.getElementById('close-offer');
|
|
||||||
const createOfferModalRoot = document.getElementById(
|
|
||||||
'create-offer-modal-root'
|
|
||||||
);
|
|
||||||
const viewMyOffersRoot = document.getElementById('view-my-offers-root');
|
const viewMyOffersRoot = document.getElementById('view-my-offers-root');
|
||||||
|
|
||||||
const eurAmountInput = document.getElementById('input-eur-amount');
|
|
||||||
const btcAmountInput = document.getElementById('input-btc-amount');
|
|
||||||
|
|
||||||
const placeInput = document.getElementById('place-input');
|
|
||||||
const timeInput = document.getElementById('time-input');
|
|
||||||
|
|
||||||
const onchainCheckbox = document.getElementById('onchain-checkbox');
|
|
||||||
const lightningCheckbox = document.getElementById('lightning-checkbox');
|
|
||||||
|
|
||||||
const btcMethodCheckboxes = [onchainCheckbox, lightningCheckbox];
|
|
||||||
|
|
||||||
const myTrustedCheckbox = document.getElementById('my-trusted-checkbox');
|
|
||||||
const myTrustedTrustedCheckbox = document.getElementById(
|
|
||||||
'my-trusted-trusted-checkbox'
|
|
||||||
);
|
|
||||||
const allMembersCheckbox = document.getElementById('all-members-checkbox');
|
|
||||||
|
|
||||||
const bigNotesAcceptedCheckbox = document.getElementById(
|
|
||||||
'large-bills-checkbox'
|
|
||||||
);
|
|
||||||
|
|
||||||
const offerCreatedPopup = document.getElementById(
|
|
||||||
'offer-created-confirmation'
|
|
||||||
);
|
|
||||||
const offerDeletedPopup = document.getElementById(
|
|
||||||
'offer-deleted-confirmation'
|
|
||||||
);
|
|
||||||
|
|
||||||
const ownOffersContainer = document.getElementById('own-offers-container');
|
const ownOffersContainer = document.getElementById('own-offers-container');
|
||||||
|
|
||||||
function toggleCreateOfferModal() {
|
|
||||||
createOfferModalRoot.classList.toggle('shown');
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleViewMyOffersPanel() {
|
function toggleViewMyOffersPanel() {
|
||||||
viewMyOffersRoot.style.display =
|
viewMyOffersRoot.style.display =
|
||||||
viewMyOffersRoot.style.display === 'block' ? 'none' : 'block';
|
viewMyOffersRoot.style.display === 'block' ? 'none' : 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
function readIntFromEurAmountInput() {
|
|
||||||
const eurAmountFieldValue = eurAmountInput.value;
|
|
||||||
const regularExpression = /([\d\s]+)/;
|
|
||||||
const matchResult = eurAmountFieldValue.match(regularExpression);
|
|
||||||
|
|
||||||
if (!matchResult) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const numberString = matchResult[1];
|
|
||||||
const cleanInputNumber = parseInt(numberString.replace(/\s/gi, ''));
|
|
||||||
|
|
||||||
return cleanInputNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateAndFormatEurAmountInput() {
|
|
||||||
const cleanInputNumber = readIntFromEurAmountInput();
|
|
||||||
eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid');
|
|
||||||
if (cleanInputNumber) {
|
|
||||||
eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber);
|
|
||||||
eurAmountInput.classList.add('input-is-valid');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
eurAmountInput.classList.add('input-is-invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateBtcInput() {
|
|
||||||
const eurToSatRate = 1021;
|
|
||||||
const cleanEurAmount = readIntFromEurAmountInput();
|
|
||||||
|
|
||||||
const satsAmount = cleanEurAmount * eurToSatRate;
|
|
||||||
const formattedSatsAmount = formatNumberWithSpaces(satsAmount);
|
|
||||||
btcAmountInput.value = formattedSatsAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateBitcoinMethodCheckboxes(clickedCheckbox) {
|
|
||||||
let checkedCount = btcMethodCheckboxes.filter((cb) => cb.checked).length;
|
|
||||||
if (checkedCount === 0) {
|
|
||||||
clickedCheckbox.checked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyTrustCheckboxConstraints(pressedCheckbox) {
|
|
||||||
if (pressedCheckbox === myTrustedTrustedCheckbox) {
|
|
||||||
console.log('first case!');
|
|
||||||
if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) {
|
|
||||||
allMembersCheckbox.checked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pressedCheckbox === allMembersCheckbox) {
|
|
||||||
console.log('second case!');
|
|
||||||
if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) {
|
|
||||||
myTrustedTrustedCheckbox.checked = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function publishOffer() {
|
|
||||||
const wants = buyOrSellButtonGroup.wants();
|
|
||||||
|
|
||||||
const premium = premiumSelector.getPremium();
|
|
||||||
const trade_amount_eur = eurAmountInput.value;
|
|
||||||
const location_details = placeInput.value;
|
|
||||||
const time_availability_details = timeInput.value;
|
|
||||||
const is_onchain_accepted = onchainCheckbox.checked;
|
|
||||||
const is_lightning_accepted = lightningCheckbox.checked;
|
|
||||||
const show_offer_to_trusted = myTrustedCheckbox.checked;
|
|
||||||
const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked;
|
|
||||||
const show_offer_to_all_members = allMembersCheckbox.checked;
|
|
||||||
const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked;
|
|
||||||
|
|
||||||
const offerDetails = {
|
|
||||||
wants,
|
|
||||||
premium,
|
|
||||||
trade_amount_eur,
|
|
||||||
location_details,
|
|
||||||
time_availability_details,
|
|
||||||
is_onchain_accepted,
|
|
||||||
is_lightning_accepted,
|
|
||||||
show_offer_to_trusted,
|
|
||||||
show_offer_to_trusted_trusted,
|
|
||||||
show_offer_to_all_members,
|
|
||||||
are_big_notes_accepted,
|
|
||||||
};
|
|
||||||
|
|
||||||
await fetch('/api/offer', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ offerDetails }),
|
|
||||||
});
|
|
||||||
|
|
||||||
toggleOfferCreatedAlert();
|
|
||||||
|
|
||||||
toggleCreateOfferModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleOfferCreatedAlert() {
|
|
||||||
offerCreatedPopup.classList.remove('max-size-zero');
|
|
||||||
offerCreatedPopup.classList.add('revealed');
|
|
||||||
setTimeout(() => {
|
|
||||||
offerCreatedPopup.classList.remove('revealed');
|
|
||||||
}, 3000);
|
|
||||||
setTimeout(() => {
|
|
||||||
offerCreatedPopup.classList.add('max-size-zero');
|
|
||||||
}, 4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleOfferDeletedAlert() {
|
|
||||||
offerDeletedPopup.classList.remove('max-size-zero');
|
|
||||||
offerDeletedPopup.classList.add('revealed');
|
|
||||||
setTimeout(() => {
|
|
||||||
offerDeletedPopup.classList.remove('revealed');
|
|
||||||
}, 3000);
|
|
||||||
setTimeout(() => {
|
|
||||||
offerDeletedPopup.classList.add('max-size-zero');
|
|
||||||
}, 4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Offer {
|
|
||||||
constructor(offerData) {
|
|
||||||
this.uuid = offerData.uuid;
|
|
||||||
this.public_key = offerData.public_key;
|
|
||||||
this.wants = offerData.wants;
|
|
||||||
this.premium = offerData.premium;
|
|
||||||
this.trade_amount_eur = offerData.trade_amount_eur;
|
|
||||||
this.location_details = offerData.location_details;
|
|
||||||
this.time_availability_details = offerData.time_availability_details;
|
|
||||||
this.show_offer_to_trusted = offerData.show_offer_to_trusted;
|
|
||||||
this.show_offer_to_trusted_trusted =
|
|
||||||
offerData.show_offer_to_trusted_trusted;
|
|
||||||
this.show_offer_to_all_members = offerData.show_offer_to_all_members;
|
|
||||||
this.is_onchain_accepted = offerData.is_onchain_accepted;
|
|
||||||
this.is_lightning_accepted = offerData.is_lightning_accepted;
|
|
||||||
this.are_big_notes_accepted = offerData.are_big_notes_accepted;
|
|
||||||
this.created_at = offerData.created_at;
|
|
||||||
this.last_updated_at = offerData.last_updated_at;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildHTML() {
|
|
||||||
const offerCard = document.createElement('div');
|
|
||||||
offerCard.classList.add('myoffer-card');
|
|
||||||
offerCard.classList.add('shadowed-round-area');
|
|
||||||
|
|
||||||
const tradeDescDiv = document.createElement('div');
|
|
||||||
tradeDescDiv.classList.add('trade-desc');
|
|
||||||
|
|
||||||
const youBuyText = document.createElement('p');
|
|
||||||
youBuyText.classList.add('offer-card-content-title');
|
|
||||||
youBuyText.innerText = 'Compras';
|
|
||||||
tradeDescDiv.append(youBuyText);
|
|
||||||
|
|
||||||
const youBuyData = document.createElement('p');
|
|
||||||
youBuyData.classList.add('offer-card-content-data');
|
|
||||||
if (this.wants === 'BTC') {
|
|
||||||
youBuyData.innerText = `${this.trade_amount_eur * 1021} sats`;
|
|
||||||
}
|
|
||||||
if (this.wants === 'EUR') {
|
|
||||||
youBuyData.innerText = `${this.trade_amount_eur} €`;
|
|
||||||
}
|
|
||||||
tradeDescDiv.append(youBuyData);
|
|
||||||
|
|
||||||
const youSellText = document.createElement('p');
|
|
||||||
youSellText.id = 'you-sell-title';
|
|
||||||
youSellText.classList.add('offer-card-content-title');
|
|
||||||
youSellText.innerText = 'Vendes';
|
|
||||||
tradeDescDiv.append(youSellText);
|
|
||||||
|
|
||||||
const youSellData = document.createElement('p');
|
|
||||||
youSellData.classList.add('offer-card-content-data');
|
|
||||||
if (this.wants === 'BTC') {
|
|
||||||
youSellData.innerText = `${this.trade_amount_eur} €`;
|
|
||||||
}
|
|
||||||
if (this.wants === 'EUR') {
|
|
||||||
youSellData.innerText = `${this.trade_amount_eur * 1021} sats`;
|
|
||||||
}
|
|
||||||
tradeDescDiv.append(youSellData);
|
|
||||||
|
|
||||||
const premiumDescDiv = document.createElement('div');
|
|
||||||
premiumDescDiv.classList.add('premium-desc');
|
|
||||||
|
|
||||||
const premiumTitle = document.createElement('p');
|
|
||||||
premiumTitle.classList.add('offer-card-content-title');
|
|
||||||
premiumTitle.innerText = 'Premium';
|
|
||||||
premiumDescDiv.append(premiumTitle);
|
|
||||||
|
|
||||||
const premiumData = document.createElement('p');
|
|
||||||
premiumData.classList.add('offer-card-content-data');
|
|
||||||
premiumData.innerText = `${this.premium * 100} %`;
|
|
||||||
premiumDescDiv.append(premiumData);
|
|
||||||
|
|
||||||
const offerPriceTitle = document.createElement('p');
|
|
||||||
offerPriceTitle.classList.add('offer-card-content-title');
|
|
||||||
offerPriceTitle.innerText = 'Precio oferta';
|
|
||||||
premiumDescDiv.append(offerPriceTitle);
|
|
||||||
|
|
||||||
const offerPriceData = document.createElement('p');
|
|
||||||
offerPriceData.classList.add('offer-card-content-data');
|
|
||||||
offerPriceData.innerText = `90000 €/BTC`;
|
|
||||||
premiumDescDiv.append(offerPriceData);
|
|
||||||
|
|
||||||
const marketPriceTitle = document.createElement('p');
|
|
||||||
marketPriceTitle.classList.add('offer-card-content-title');
|
|
||||||
marketPriceTitle.innerText = 'Precio mercado';
|
|
||||||
premiumDescDiv.append(marketPriceTitle);
|
|
||||||
|
|
||||||
const marketPriceData = document.createElement('p');
|
|
||||||
marketPriceData.innerText = `88000 €/BTC`;
|
|
||||||
premiumDescDiv.append(marketPriceData);
|
|
||||||
|
|
||||||
const whereDescDiv = document.createElement('div');
|
|
||||||
whereDescDiv.classList.add('where-desc');
|
|
||||||
|
|
||||||
const whereDescTitle = document.createElement('p');
|
|
||||||
whereDescTitle.classList.add('offer-card-content-title');
|
|
||||||
whereDescTitle.innerText = 'Dónde';
|
|
||||||
whereDescDiv.append(whereDescTitle);
|
|
||||||
|
|
||||||
const whereDescData = document.createElement('p');
|
|
||||||
whereDescData.classList.add('offer-long-text');
|
|
||||||
whereDescData.innerText = `${this.location_details}`;
|
|
||||||
whereDescDiv.append(whereDescData);
|
|
||||||
|
|
||||||
const whenDescDiv = document.createElement('div');
|
|
||||||
whenDescDiv.classList.add('when-desc');
|
|
||||||
|
|
||||||
const whenDescTitle = document.createElement('p');
|
|
||||||
whenDescTitle.classList.add('offer-card-content-title');
|
|
||||||
whenDescTitle.innerText = 'Cúando';
|
|
||||||
whenDescDiv.append(whenDescTitle);
|
|
||||||
|
|
||||||
const whenDescData = document.createElement('p');
|
|
||||||
whenDescData.classList.add('offer-long-text');
|
|
||||||
whenDescData.innerText = `${this.time_availability_details}`;
|
|
||||||
whenDescDiv.append(whenDescData);
|
|
||||||
|
|
||||||
const bitcoinMethodsDiv = document.createElement('div');
|
|
||||||
bitcoinMethodsDiv.classList.add('bitcoin-methods-desc');
|
|
||||||
|
|
||||||
const bitcoinMethodsTitle = document.createElement('p');
|
|
||||||
bitcoinMethodsTitle.classList.add('offer-card-content-title');
|
|
||||||
bitcoinMethodsTitle.innerText = 'Protocolos Bitcoin aceptados';
|
|
||||||
bitcoinMethodsDiv.append(bitcoinMethodsTitle);
|
|
||||||
|
|
||||||
const onchainAcceptedContainer = document.createElement('div');
|
|
||||||
onchainAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
|
||||||
if (this.is_onchain_accepted) {
|
|
||||||
const onchainIcon = document.createElement('img');
|
|
||||||
onchainIcon.src = '/img/chains-lasecagold.svg';
|
|
||||||
const onchainText = document.createElement('p');
|
|
||||||
onchainText.innerText = 'Onchain';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
|
|
||||||
} else {
|
|
||||||
const onchainIcon = document.createElement('img');
|
|
||||||
onchainIcon.src = '/img/chains-gray.svg';
|
|
||||||
const onchainText = document.createElement('p');
|
|
||||||
onchainText.innerText = 'Onchain';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon);
|
|
||||||
}
|
|
||||||
const lightningAcceptedContainer = document.createElement('div');
|
|
||||||
|
|
||||||
lightningAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
|
||||||
if (this.is_lightning_accepted) {
|
|
||||||
const lightningIcon = document.createElement('img');
|
|
||||||
lightningIcon.src = '/img/bolt-lightning-lasecagold.svg';
|
|
||||||
const lightningText = document.createElement('p');
|
|
||||||
lightningText.innerText = 'Lightning';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
lightningAcceptedContainer.append(
|
|
||||||
lightningIcon,
|
|
||||||
lightningText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const lightningIcon = document.createElement('img');
|
|
||||||
lightningIcon.src = '/img/bolt-lightning-gray.svg';
|
|
||||||
const lightningText = document.createElement('p');
|
|
||||||
lightningText.innerText = 'Lightning';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
lightningAcceptedContainer.append(
|
|
||||||
lightningIcon,
|
|
||||||
lightningText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bitcoinMethodsDiv.append(
|
|
||||||
onchainAcceptedContainer,
|
|
||||||
lightningAcceptedContainer
|
|
||||||
);
|
|
||||||
|
|
||||||
const visibilityDiv = document.createElement('div');
|
|
||||||
visibilityDiv.classList.add('visibility-desc');
|
|
||||||
|
|
||||||
const visibilityTitle = document.createElement('p');
|
|
||||||
visibilityTitle.classList.add('offer-card-content-title');
|
|
||||||
visibilityTitle.innerText = 'Visibilidad';
|
|
||||||
visibilityDiv.append(visibilityTitle);
|
|
||||||
|
|
||||||
const showOfferToTrustedContainer = document.createElement('div');
|
|
||||||
showOfferToTrustedContainer.classList.add('right-icon-checkboxed-field');
|
|
||||||
|
|
||||||
if (this.show_offer_to_trusted) {
|
|
||||||
const showOfferToTrustedIcon = document.createElement('img');
|
|
||||||
showOfferToTrustedIcon.src = '/img/user-lasecagold.svg';
|
|
||||||
const showOfferToTrustedText = document.createElement('p');
|
|
||||||
showOfferToTrustedText.innerText = 'Confiados';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
showOfferToTrustedContainer.append(
|
|
||||||
showOfferToTrustedIcon,
|
|
||||||
showOfferToTrustedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const showOfferToTrustedIcon = document.createElement('img');
|
|
||||||
showOfferToTrustedIcon.src = '/img/user-gray.svg';
|
|
||||||
const showOfferToTrustedText = document.createElement('p');
|
|
||||||
showOfferToTrustedText.innerText = 'Confiados';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
showOfferToTrustedContainer.append(
|
|
||||||
showOfferToTrustedIcon,
|
|
||||||
showOfferToTrustedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const showOfferToTrustedTrustedContainer = document.createElement('div');
|
|
||||||
showOfferToTrustedTrustedContainer.classList.add(
|
|
||||||
'right-icon-checkboxed-field'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.show_offer_to_trusted_trusted) {
|
|
||||||
const showOfferToTrustedTrustedIcon = document.createElement('img');
|
|
||||||
showOfferToTrustedTrustedIcon.src = '/img/user-group-lasecagold.svg';
|
|
||||||
const showOfferToTrustedTrustedText = document.createElement('p');
|
|
||||||
showOfferToTrustedTrustedText.innerText = 'Sus confiados';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
showOfferToTrustedTrustedContainer.append(
|
|
||||||
showOfferToTrustedTrustedIcon,
|
|
||||||
showOfferToTrustedTrustedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const showOfferToTrustedTrustedIcon = document.createElement('img');
|
|
||||||
showOfferToTrustedTrustedIcon.src = '/img/user-group-gray.svg';
|
|
||||||
const showOfferToTrustedTrustedText = document.createElement('p');
|
|
||||||
showOfferToTrustedTrustedText.innerText = 'Sus confiados';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
showOfferToTrustedTrustedContainer.append(
|
|
||||||
showOfferToTrustedTrustedIcon,
|
|
||||||
showOfferToTrustedTrustedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const showOfferToAllMembersContainer = document.createElement('div');
|
|
||||||
showOfferToAllMembersContainer.classList.add(
|
|
||||||
'right-icon-checkboxed-field'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.show_offer_to_all_members) {
|
|
||||||
const showOfferToAllMembersIcon = document.createElement('img');
|
|
||||||
showOfferToAllMembersIcon.src = '/img/many-users-lasecagold.svg';
|
|
||||||
const showOfferToAllMembersText = document.createElement('p');
|
|
||||||
showOfferToAllMembersText.innerText = 'Todos';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
showOfferToAllMembersContainer.append(
|
|
||||||
showOfferToAllMembersIcon,
|
|
||||||
showOfferToAllMembersText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const showOfferToAllMembersIcon = document.createElement('img');
|
|
||||||
showOfferToAllMembersIcon.src = '/img/many-users-gray.svg';
|
|
||||||
const showOfferToAllMembersText = document.createElement('p');
|
|
||||||
showOfferToAllMembersText.innerText = 'Todos';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
showOfferToAllMembersContainer.append(
|
|
||||||
showOfferToAllMembersIcon,
|
|
||||||
showOfferToAllMembersText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
}
|
|
||||||
visibilityDiv.append(
|
|
||||||
showOfferToTrustedContainer,
|
|
||||||
showOfferToTrustedTrustedContainer,
|
|
||||||
showOfferToAllMembersContainer
|
|
||||||
);
|
|
||||||
|
|
||||||
const otherOfferFeaturesDiv = document.createElement('div');
|
|
||||||
otherOfferFeaturesDiv.classList.add('other-desc');
|
|
||||||
|
|
||||||
const otherOfferFeaturesTitle = document.createElement('p');
|
|
||||||
otherOfferFeaturesTitle.classList.add('offer-card-content-title');
|
|
||||||
otherOfferFeaturesTitle.innerText = 'Otros';
|
|
||||||
otherOfferFeaturesDiv.append(otherOfferFeaturesTitle);
|
|
||||||
|
|
||||||
const areBigNotesAcceptedContainer = document.createElement('div');
|
|
||||||
areBigNotesAcceptedContainer.classList.add('left-icon-checkboxed-field');
|
|
||||||
|
|
||||||
if (this.are_big_notes_accepted) {
|
|
||||||
const areBigNotesAcceptedIcon = document.createElement('img');
|
|
||||||
areBigNotesAcceptedIcon.src = '/img/eur-bill-lasecagold.svg';
|
|
||||||
const areBigNotesAcceptedText = document.createElement('p');
|
|
||||||
areBigNotesAcceptedText.innerText = 'Billetes grandes';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-check-green.svg';
|
|
||||||
|
|
||||||
areBigNotesAcceptedContainer.append(
|
|
||||||
areBigNotesAcceptedIcon,
|
|
||||||
areBigNotesAcceptedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const areBigNotesAcceptedIcon = document.createElement('img');
|
|
||||||
areBigNotesAcceptedIcon.src = '/img/eur-bill-gray.svg';
|
|
||||||
const areBigNotesAcceptedText = document.createElement('p');
|
|
||||||
areBigNotesAcceptedText.innerText = 'Billetes grandes';
|
|
||||||
const checkIcon = document.createElement('img');
|
|
||||||
checkIcon.src = '/img/circle-xmark-gray.svg';
|
|
||||||
|
|
||||||
areBigNotesAcceptedContainer.append(
|
|
||||||
areBigNotesAcceptedIcon,
|
|
||||||
areBigNotesAcceptedText,
|
|
||||||
checkIcon
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
otherOfferFeaturesDiv.append(areBigNotesAcceptedContainer);
|
|
||||||
|
|
||||||
const actionButtonsArea = document.createElement('p');
|
|
||||||
actionButtonsArea.classList.add('offer-action-buttons-area');
|
|
||||||
|
|
||||||
const editActionArea = document.createElement('div');
|
|
||||||
editActionArea.classList.add('offer-action-area');
|
|
||||||
editActionArea.classList.add('subtle-box');
|
|
||||||
const editActionIcon = document.createElement('img');
|
|
||||||
editActionIcon.src = '/img/edit.svg';
|
|
||||||
const editActionText = document.createElement('p');
|
|
||||||
editActionText.innerText = 'Editar';
|
|
||||||
editActionArea.append(editActionIcon, editActionText);
|
|
||||||
|
|
||||||
const deleteActionArea = document.createElement('div');
|
|
||||||
deleteActionArea.classList.add('offer-action-area');
|
|
||||||
deleteActionArea.classList.add('subtle-box');
|
|
||||||
const deleteActionIcon = document.createElement('img');
|
|
||||||
deleteActionIcon.src = '/img/trash-can-darkred.svg';
|
|
||||||
const deleteActionText = document.createElement('p');
|
|
||||||
deleteActionText.innerText = 'Eliminar';
|
|
||||||
deleteActionArea.append(deleteActionIcon, deleteActionText);
|
|
||||||
deleteActionArea.addEventListener('click', async () => {
|
|
||||||
await deleteOfferByUuid(this.uuid);
|
|
||||||
await myOffers.getOffersFromApi();
|
|
||||||
await myOffers.render();
|
|
||||||
toggleOfferDeletedAlert();
|
|
||||||
});
|
|
||||||
|
|
||||||
actionButtonsArea.append(editActionArea, deleteActionArea);
|
|
||||||
|
|
||||||
offerCard.append(
|
|
||||||
tradeDescDiv,
|
|
||||||
premiumDescDiv,
|
|
||||||
whereDescDiv,
|
|
||||||
whenDescDiv,
|
|
||||||
bitcoinMethodsDiv,
|
|
||||||
visibilityDiv,
|
|
||||||
otherOfferFeaturesDiv,
|
|
||||||
actionButtonsArea
|
|
||||||
);
|
|
||||||
|
|
||||||
return offerCard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyOffers {
|
class MyOffers {
|
||||||
constructor(ownOffersContainerElement) {
|
constructor(ownOffersContainerElement) {
|
||||||
this.ownOffersContainerElement = ownOffersContainerElement;
|
this.ownOffersContainerElement = ownOffersContainerElement;
|
||||||
|
|
@ -620,7 +66,17 @@ function offersPage() {
|
||||||
const offersData = (await offersResponse.json()).data;
|
const offersData = (await offersResponse.json()).data;
|
||||||
if (offersResponse.ok) {
|
if (offersResponse.ok) {
|
||||||
for (const record of offersData) {
|
for (const record of offersData) {
|
||||||
this.offers.push(new Offer(record));
|
this.offers.push(
|
||||||
|
new OfferCard({
|
||||||
|
offerData: record,
|
||||||
|
deleteButtonCallback: async () => {
|
||||||
|
await offerService.deleteOffer(record.uuid);
|
||||||
|
await this.getOffersFromApi();
|
||||||
|
await this.render();
|
||||||
|
offerDeletedPopup.displayTemporarily(3000);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -639,17 +95,8 @@ function offersPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteOfferByUuid(offerUuid) {
|
|
||||||
await fetch(`/api/offer/${offerUuid}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonStartCreateOffer.addEventListener('click', () => {
|
buttonStartCreateOffer.addEventListener('click', () => {
|
||||||
toggleCreateOfferModal();
|
createOfferModal.toggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonViewMyOffers.addEventListener('click', async () => {
|
buttonViewMyOffers.addEventListener('click', async () => {
|
||||||
|
|
@ -658,36 +105,6 @@ function offersPage() {
|
||||||
toggleViewMyOffersPanel();
|
toggleViewMyOffersPanel();
|
||||||
});
|
});
|
||||||
|
|
||||||
closeOffer.addEventListener('click', () => {
|
|
||||||
toggleCreateOfferModal();
|
|
||||||
});
|
|
||||||
|
|
||||||
eurAmountInput.addEventListener('blur', () => {
|
|
||||||
validateAndFormatEurAmountInput();
|
|
||||||
updateBtcInput();
|
|
||||||
});
|
|
||||||
|
|
||||||
eurAmountInput.addEventListener('input', () => {
|
|
||||||
eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, '');
|
|
||||||
updateBtcInput();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const btcMethodCheckbox of btcMethodCheckboxes) {
|
|
||||||
btcMethodCheckbox.addEventListener('click', () => {
|
|
||||||
validateBitcoinMethodCheckboxes(btcMethodCheckbox);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
myTrustedTrustedCheckbox.addEventListener('click', () => {
|
|
||||||
applyTrustCheckboxConstraints(myTrustedTrustedCheckbox);
|
|
||||||
});
|
|
||||||
|
|
||||||
allMembersCheckbox.addEventListener('click', () => {
|
|
||||||
applyTrustCheckboxConstraints(allMembersCheckbox);
|
|
||||||
});
|
|
||||||
|
|
||||||
updateBtcInput();
|
|
||||||
|
|
||||||
const myOffers = new MyOffers(ownOffersContainer);
|
const myOffers = new MyOffers(ownOffersContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
|
const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
|
||||||
let challengeResponse;
|
let challengeResponse;
|
||||||
try {
|
try {
|
||||||
challengeResponse = await fetch('/api/signup/nostr-challenge', {
|
challengeResponse = await fetch(constants.API_PATHS.signupNostrChallenge, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
@ -39,7 +41,7 @@ const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => {
|
||||||
|
|
||||||
let verifyResponse;
|
let verifyResponse;
|
||||||
try {
|
try {
|
||||||
verifyResponse = await fetch('/api/signup/nostr-verify', {
|
verifyResponse = await fetch(constants.API_PATHS.signupNostrVerify, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(signedEvent),
|
body: JSON.stringify(signedEvent),
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
const requestAndRespondLoginChallenge = async ({
|
const requestAndRespondLoginChallenge = async ({
|
||||||
onRejectedPubKeyCallback,
|
onRejectedPubKeyCallback,
|
||||||
onRejectedSignatureCallback,
|
onRejectedSignatureCallback,
|
||||||
}) => {
|
}) => {
|
||||||
onRejectedPubKeyCallback = () => {
|
|
||||||
document.querySelector('#rejected-nostr-nudges').style.display = 'block';
|
|
||||||
};
|
|
||||||
onRejectedSignatureCallback = onRejectedPubKeyCallback;
|
|
||||||
|
|
||||||
let challengeResponse;
|
let challengeResponse;
|
||||||
try {
|
try {
|
||||||
challengeResponse = await fetch('/api/login/nostr-challenge', {
|
challengeResponse = await fetch(constants.API_PATHS.loginNostrChallenge, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
@ -47,7 +44,7 @@ const requestAndRespondLoginChallenge = async ({
|
||||||
|
|
||||||
let verifyResponse;
|
let verifyResponse;
|
||||||
try {
|
try {
|
||||||
verifyResponse = await fetch('/api/login/nostr-verify', {
|
verifyResponse = await fetch(constants.API_PATHS.loginNostrVerify, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(signedEvent),
|
body: JSON.stringify(signedEvent),
|
||||||
|
|
|
||||||
25
src/front/services/offerService.js
Normal file
25
src/front/services/offerService.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
const constants = require('../../constants');
|
||||||
|
|
||||||
|
const createOffer = async (offerDetails) => {
|
||||||
|
await fetch(constants.API_PATHS.offer, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ offerDetails }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteOffer = async (offerUuid) => {
|
||||||
|
await fetch(`${constants.API_PATHS.offer}/${offerUuid}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createOffer,
|
||||||
|
deleteOffer,
|
||||||
|
};
|
||||||
|
|
@ -31,145 +31,6 @@
|
||||||
<p>Vaya, no hay nada por aquí...</p>
|
<p>Vaya, no hay nada por aquí...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="create-offer-modal-root" class="full-screen-modal-background">
|
|
||||||
<div class="full-screen-modal" id="create-offer-root">
|
|
||||||
<div id="create-offer-controls">
|
|
||||||
<h2>Añade los detalles de tu oferta</h2>
|
|
||||||
<div id="buy-or-sell-area" class="create-offer-step"></div>
|
|
||||||
<div id="premium-area" class="create-offer-step">
|
|
||||||
<h3>Premium</h3>
|
|
||||||
<div id="premium-content-area"></div>
|
|
||||||
</div>
|
|
||||||
<div id="amount-area" class="create-offer-step">
|
|
||||||
<h3>¿Cuánto?</h3>
|
|
||||||
<div id="amount-area-content">
|
|
||||||
<div id="eur-amount" class="money-amount-input-area">
|
|
||||||
<input
|
|
||||||
id="input-eur-amount"
|
|
||||||
type="text"
|
|
||||||
class="money-input input-money-amount"
|
|
||||||
value="100"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<div id="eur-symbol" class="curr-symbol">
|
|
||||||
<span id="eur-character" class="curr-character">€</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="btc-amount" class="money-amount-input-area">
|
|
||||||
<input
|
|
||||||
id="input-btc-amount"
|
|
||||||
type="text"
|
|
||||||
class="money-input input-money-amount"
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
<div id="sats-symbol" class="curr-symbol">
|
|
||||||
<span id="sats-character" class="curr-character">SAT</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="place-and-time-area" class="create-offer-step">
|
|
||||||
<h3>¿Dónde y cuándo?</h3>
|
|
||||||
<div id="place-and-time-boxes">
|
|
||||||
<textarea
|
|
||||||
id="place-input"
|
|
||||||
class="place-and-time-box"
|
|
||||||
autocomplete="on"
|
|
||||||
maxlength="140"
|
|
||||||
placeholder='¿Dónde? Ej."Eixample", "La Maquinista", "Cualquier lugar en BCN", "Meetup BBO"'
|
|
||||||
></textarea>
|
|
||||||
<textarea
|
|
||||||
id="time-input"
|
|
||||||
class="place-and-time-box"
|
|
||||||
autocomplete="on"
|
|
||||||
maxlength="140"
|
|
||||||
placeholder='¿Cuándo? Ej."Cualquier hora", "19:00-21:00", "Finde"'
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="bitcoin-methods-area" class="create-offer-step">
|
|
||||||
<h3>¿Cómo se mueve el Bitcoin?</h3>
|
|
||||||
<div id="onchain-checkbox-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="onchain"
|
|
||||||
id="onchain-checkbox"
|
|
||||||
checked
|
|
||||||
/><label for="onchain">Onchain</label>
|
|
||||||
</div>
|
|
||||||
<div id="lightning-checkbox-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="lightning"
|
|
||||||
id="lightning-checkbox"
|
|
||||||
checked
|
|
||||||
/><label for="lightning">Lightning</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="trust-area" class="create-offer-step">
|
|
||||||
<h3>¿Quién puede ver la oferta?</h3>
|
|
||||||
<div id="my-trusted-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="my-trusted"
|
|
||||||
id="my-trusted-checkbox"
|
|
||||||
checked
|
|
||||||
disabled
|
|
||||||
/><label for="my-trusted">Mis confiados</label>
|
|
||||||
</div>
|
|
||||||
<div id="my-trusted-trusted-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="my-trusted-trusted"
|
|
||||||
id="my-trusted-trusted-checkbox"
|
|
||||||
checked
|
|
||||||
/><label for="my-trusted-trusted"
|
|
||||||
>Los confiados de mis confiados</label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div id="all-members-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="all-members"
|
|
||||||
id="all-members-checkbox"
|
|
||||||
/><label for="all-members">Todos los miembros</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="other-area" class="create-offer-step">
|
|
||||||
<h3>Extras</h3>
|
|
||||||
<div id="large-bills-area" class="checkbox-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
name="large-bills"
|
|
||||||
id="large-bills-checkbox"
|
|
||||||
/><label for="large-bills"
|
|
||||||
>Se pueden usar billetes grandes (100€, 200€, 500€)</label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="submit-button-area"></div>
|
|
||||||
<div id="close-offer-controls-area">
|
|
||||||
<button id="close-offer" class="button-secondary button-medium">
|
|
||||||
Volver
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="offer-created-confirmation"
|
|
||||||
class="top-notification-good max-size-zero"
|
|
||||||
>
|
|
||||||
<img src="/img/circle-check-white.svg" />
|
|
||||||
<p>¡Oferta creada! Puedes verla en tus ofertas.</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="offer-deleted-confirmation"
|
|
||||||
class="top-notification-good max-size-zero"
|
|
||||||
>
|
|
||||||
<img src="/img/circle-check-white.svg" />
|
|
||||||
<p>¡Oferta eliminada!</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/javascript/offers.bundle.js"></script>
|
<script src="/javascript/offers.bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue