From 8a6fd5c7e5c361616968b1493655e9c0ab93e40f Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Wed, 19 Mar 2025 19:17:23 +0100 Subject: [PATCH 01/60] wip amountInput --- src/front/pages/offers.js | 172 ++++++++++++++++++++++++++++---------- src/views/offers.ejs | 25 ------ 2 files changed, 128 insertions(+), 69 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 1913e7a..948638c 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -4,9 +4,129 @@ const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup'); const PremiumSelector = require('../components/PremiumSelector'); const PriceDisplay = require('../components/PriceDisplay'); +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; +} + + +class AmountInput { + constructor({parentElement, id}) { + this.element = null; + this.parentElement = parentElement; + this.id = id; + } + + render(){ + const amountArea = document.createElement('div'); + amountArea.id = this.id; + + const eurAmount = document.createElement('div'); + eurAmount.id = 'eur-amount'; + eurAmount.className = 'money-amount-input-area'; + + const eurInput = document.createElement('input'); + eurInput.id = 'input-eur-amount'; + eurInput.type = 'text'; + eurInput.className = 'money-input input-money-amount'; + eurInput.value = '100'; + eurInput.required = true; + + const eurSymbol = document.createElement('div'); + eurSymbol.id = 'eur-symbol'; + eurSymbol.className = 'curr-symbol'; + + const eurCharacter = document.createElement('span'); + eurCharacter.id = 'eur-character'; + eurCharacter.className = 'curr-character'; + eurCharacter.textContent = '€'; + + eurSymbol.appendChild(eurCharacter); + eurAmount.appendChild(eurInput); + eurAmount.appendChild(eurSymbol); + + const btcAmount = document.createElement('div'); + btcAmount.id = 'btc-amount'; + btcAmount.className = 'money-amount-input-area'; + + const btcInput = document.createElement('input'); + btcInput.id = 'input-btc-amount'; + btcInput.type = 'text'; + btcInput.className = 'money-input input-money-amount'; + btcInput.disabled = true; + + const satsSymbol = document.createElement('div'); + satsSymbol.id = 'sats-symbol'; + satsSymbol.className = 'curr-symbol'; + + const satsCharacter = document.createElement('span'); + satsCharacter.id = 'sats-character'; + satsCharacter.className = 'curr-character'; + satsCharacter.textContent = 'SAT'; + + satsSymbol.appendChild(satsCharacter); + btcAmount.appendChild(btcInput); + btcAmount.appendChild(satsSymbol); + + amountArea.appendChild(eurAmount); + amountArea.appendChild(btcAmount); + + + + eurInput.addEventListener('blur', () => { + validateAndFormatEurAmountInput(); + updateBtcInput(); + }); + + eurInput.addEventListener('input', () => { + eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, ''); + updateBtcInput(); + }); + + this.element = amountArea; + this.parentElement.appendChild(this.element); + } +} + function offersPage() { const createOfferEventBus = new EventTarget(); + const mockPriceProvidingCallback = () => { + return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); + } + const publishOfferButton = new PublishOfferButton({ parentElement: document.getElementById('submit-button-area'), id: 'button-submit-offer', @@ -37,15 +157,20 @@ function offersPage() { premiumProvidingCallback: () => { return premiumSelector.getPremium(); }, - priceProvidingCallback: () => { - return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); - }, + priceProvidingCallback: mockPriceProvidingCallback, }); priceDisplay.render(); createOfferEventBus.addEventListener('premium-changed', () => { priceDisplay.updatePrices(); }); + + const amountInput = new AmountInput({ + parentElement: document.getElementById('amount-area'), + id: 'amount-area-content' + }) + + amountInput.render(); // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -107,41 +232,8 @@ function offersPage() { 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; @@ -662,15 +754,7 @@ function offersPage() { 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', () => { diff --git a/src/views/offers.ejs b/src/views/offers.ejs index aba756c..175422a 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -42,31 +42,6 @@

¿Cuánto?

-
-
- -
- -
-
-
- -
- SAT -
-
-

¿Dónde y cuándo?

From 37b972264384d062fb3a308e62449fae799f3966 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:04:25 +0100 Subject: [PATCH 02/60] format --- src/front/pages/offers.js | 44 +++++++++++++++------------------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 948638c..d0cec08 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -19,7 +19,6 @@ function readIntFromEurAmountInput() { return cleanInputNumber; } - function validateAndFormatEurAmountInput() { const cleanInputNumber = readIntFromEurAmountInput(); eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid'); @@ -41,75 +40,72 @@ function updateBtcInput() { btcAmountInput.value = formattedSatsAmount; } - class AmountInput { - constructor({parentElement, id}) { + constructor({ parentElement, id }) { this.element = null; this.parentElement = parentElement; this.id = id; } - render(){ + render() { const amountArea = document.createElement('div'); amountArea.id = this.id; - + const eurAmount = document.createElement('div'); eurAmount.id = 'eur-amount'; eurAmount.className = 'money-amount-input-area'; - + const eurInput = document.createElement('input'); eurInput.id = 'input-eur-amount'; eurInput.type = 'text'; eurInput.className = 'money-input input-money-amount'; eurInput.value = '100'; eurInput.required = true; - + const eurSymbol = document.createElement('div'); eurSymbol.id = 'eur-symbol'; eurSymbol.className = 'curr-symbol'; - + const eurCharacter = document.createElement('span'); eurCharacter.id = 'eur-character'; eurCharacter.className = 'curr-character'; eurCharacter.textContent = '€'; - + eurSymbol.appendChild(eurCharacter); eurAmount.appendChild(eurInput); eurAmount.appendChild(eurSymbol); - + const btcAmount = document.createElement('div'); btcAmount.id = 'btc-amount'; btcAmount.className = 'money-amount-input-area'; - + const btcInput = document.createElement('input'); btcInput.id = 'input-btc-amount'; btcInput.type = 'text'; btcInput.className = 'money-input input-money-amount'; btcInput.disabled = true; - + const satsSymbol = document.createElement('div'); satsSymbol.id = 'sats-symbol'; satsSymbol.className = 'curr-symbol'; - + const satsCharacter = document.createElement('span'); satsCharacter.id = 'sats-character'; satsCharacter.className = 'curr-character'; satsCharacter.textContent = 'SAT'; - + satsSymbol.appendChild(satsCharacter); btcAmount.appendChild(btcInput); btcAmount.appendChild(satsSymbol); - + amountArea.appendChild(eurAmount); amountArea.appendChild(btcAmount); - - eurInput.addEventListener('blur', () => { validateAndFormatEurAmountInput(); updateBtcInput(); }); - + eurInput.addEventListener('input', () => { eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, ''); updateBtcInput(); @@ -125,7 +121,7 @@ function offersPage() { const mockPriceProvidingCallback = () => { return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); - } + }; const publishOfferButton = new PublishOfferButton({ parentElement: document.getElementById('submit-button-area'), @@ -164,11 +160,10 @@ function offersPage() { priceDisplay.updatePrices(); }); - const amountInput = new AmountInput({ parentElement: document.getElementById('amount-area'), - id: 'amount-area-content' - }) + id: 'amount-area-content', + }); amountInput.render(); // ----------- @@ -232,9 +227,6 @@ function offersPage() { viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - - - function validateBitcoinMethodCheckboxes(clickedCheckbox) { let checkedCount = btcMethodCheckboxes.filter((cb) => cb.checked).length; if (checkedCount === 0) { @@ -754,8 +746,6 @@ function offersPage() { toggleCreateOfferModal(); }); - - for (const btcMethodCheckbox of btcMethodCheckboxes) { btcMethodCheckbox.addEventListener('click', () => { validateBitcoinMethodCheckboxes(btcMethodCheckbox); From 4bd7dfc7ffb52bfca1fc157739f53c3b13a71aa0 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:17:48 +0100 Subject: [PATCH 03/60] working --- src/front/pages/offers.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index d0cec08..2c27ad3 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -4,7 +4,7 @@ const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup'); const PremiumSelector = require('../components/PremiumSelector'); const PriceDisplay = require('../components/PriceDisplay'); -function readIntFromEurAmountInput() { +function readIntFromEurAmountInput(eurAmountInput) { const eurAmountFieldValue = eurAmountInput.value; const regularExpression = /([\d\s]+)/; const matchResult = eurAmountFieldValue.match(regularExpression); @@ -19,8 +19,8 @@ function readIntFromEurAmountInput() { return cleanInputNumber; } -function validateAndFormatEurAmountInput() { - const cleanInputNumber = readIntFromEurAmountInput(); +function validateAndFormatEurAmountInput(eurAmountInput) { + const cleanInputNumber = readIntFromEurAmountInput(eurAmountInput); eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid'); if (cleanInputNumber) { eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber); @@ -31,9 +31,9 @@ function validateAndFormatEurAmountInput() { eurAmountInput.classList.add('input-is-invalid'); } -function updateBtcInput() { +function updateBtcInput(eurInput, btcAmountInput) { const eurToSatRate = 1021; - const cleanEurAmount = readIntFromEurAmountInput(); + const cleanEurAmount = readIntFromEurAmountInput(eurInput); const satsAmount = cleanEurAmount * eurToSatRate; const formattedSatsAmount = formatNumberWithSpaces(satsAmount); @@ -102,13 +102,13 @@ class AmountInput { amountArea.appendChild(btcAmount); eurInput.addEventListener('blur', () => { - validateAndFormatEurAmountInput(); - updateBtcInput(); + validateAndFormatEurAmountInput(eurInput); + updateBtcInput(eurInput, btcInput); }); eurInput.addEventListener('input', () => { - eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, ''); - updateBtcInput(); + eurInput.value = eurInput.value.replace(/[^0-9]/g, ''); + updateBtcInput(eurInput, btcInput); }); this.element = amountArea; @@ -760,8 +760,6 @@ function offersPage() { applyTrustCheckboxConstraints(allMembersCheckbox); }); - updateBtcInput(); - const myOffers = new MyOffers(ownOffersContainer); } From 5d212586342fe81c190c28bb99367f1cf79d2b50 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:19:14 +0100 Subject: [PATCH 04/60] function into method --- src/front/pages/offers.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 2c27ad3..bd6c0fe 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -31,15 +31,6 @@ function validateAndFormatEurAmountInput(eurAmountInput) { eurAmountInput.classList.add('input-is-invalid'); } -function updateBtcInput(eurInput, btcAmountInput) { - const eurToSatRate = 1021; - const cleanEurAmount = readIntFromEurAmountInput(eurInput); - - const satsAmount = cleanEurAmount * eurToSatRate; - const formattedSatsAmount = formatNumberWithSpaces(satsAmount); - btcAmountInput.value = formattedSatsAmount; -} - class AmountInput { constructor({ parentElement, id }) { this.element = null; @@ -103,17 +94,26 @@ class AmountInput { eurInput.addEventListener('blur', () => { validateAndFormatEurAmountInput(eurInput); - updateBtcInput(eurInput, btcInput); + this.updateBtcInput(eurInput, btcInput); }); eurInput.addEventListener('input', () => { eurInput.value = eurInput.value.replace(/[^0-9]/g, ''); - updateBtcInput(eurInput, btcInput); + this.updateBtcInput(eurInput, btcInput); }); this.element = amountArea; this.parentElement.appendChild(this.element); } + + updateBtcInput(eurInput, btcAmountInput) { + const eurToSatRate = 1021; + const cleanEurAmount = readIntFromEurAmountInput(eurInput); + + const satsAmount = cleanEurAmount * eurToSatRate; + const formattedSatsAmount = formatNumberWithSpaces(satsAmount); + btcAmountInput.value = formattedSatsAmount; + } } function offersPage() { From 7fbfe5d9fd95dbd8722ca9c33e2958214ff50fb0 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:20:45 +0100 Subject: [PATCH 05/60] use property instead of flying data around --- src/front/pages/offers.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index bd6c0fe..eaf3169 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -36,6 +36,8 @@ class AmountInput { this.element = null; this.parentElement = parentElement; this.id = id; + + this.eurInput = null; } render() { @@ -46,12 +48,12 @@ class AmountInput { eurAmount.id = 'eur-amount'; eurAmount.className = 'money-amount-input-area'; - const eurInput = document.createElement('input'); - eurInput.id = 'input-eur-amount'; - eurInput.type = 'text'; - eurInput.className = 'money-input input-money-amount'; - eurInput.value = '100'; - eurInput.required = true; + this.eurInput = document.createElement('input'); + this.eurInput.id = 'input-eur-amount'; + 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.id = 'eur-symbol'; @@ -63,7 +65,7 @@ class AmountInput { eurCharacter.textContent = '€'; eurSymbol.appendChild(eurCharacter); - eurAmount.appendChild(eurInput); + eurAmount.appendChild(this.eurInput); eurAmount.appendChild(eurSymbol); const btcAmount = document.createElement('div'); @@ -92,23 +94,23 @@ class AmountInput { amountArea.appendChild(eurAmount); amountArea.appendChild(btcAmount); - eurInput.addEventListener('blur', () => { - validateAndFormatEurAmountInput(eurInput); - this.updateBtcInput(eurInput, btcInput); + this.eurInput.addEventListener('blur', () => { + validateAndFormatEurAmountInput(this.eurInput); + this.updateBtcInput(btcInput); }); - eurInput.addEventListener('input', () => { - eurInput.value = eurInput.value.replace(/[^0-9]/g, ''); - this.updateBtcInput(eurInput, btcInput); + this.eurInput.addEventListener('input', () => { + this.eurInput.value = this.eurInput.value.replace(/[^0-9]/g, ''); + this.updateBtcInput(btcInput); }); this.element = amountArea; this.parentElement.appendChild(this.element); } - updateBtcInput(eurInput, btcAmountInput) { + updateBtcInput(btcAmountInput) { const eurToSatRate = 1021; - const cleanEurAmount = readIntFromEurAmountInput(eurInput); + const cleanEurAmount = readIntFromEurAmountInput(this.eurInput); const satsAmount = cleanEurAmount * eurToSatRate; const formattedSatsAmount = formatNumberWithSpaces(satsAmount); From 36cbfd27123d1dc67a90934623788f9f9086c295 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:34:36 +0100 Subject: [PATCH 06/60] make btcinput property --- src/front/pages/offers.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index eaf3169..580b263 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -38,6 +38,7 @@ class AmountInput { this.id = id; this.eurInput = null; + this.btcInput = null; } render() { @@ -72,11 +73,11 @@ class AmountInput { btcAmount.id = 'btc-amount'; btcAmount.className = 'money-amount-input-area'; - const btcInput = document.createElement('input'); - btcInput.id = 'input-btc-amount'; - btcInput.type = 'text'; - btcInput.className = 'money-input input-money-amount'; - btcInput.disabled = true; + this.btcInput = document.createElement('input'); + this.btcInput.id = 'input-btc-amount'; + this.btcInput.type = 'text'; + this.btcInput.className = 'money-input input-money-amount'; + this.btcInput.disabled = true; const satsSymbol = document.createElement('div'); satsSymbol.id = 'sats-symbol'; @@ -88,7 +89,7 @@ class AmountInput { satsCharacter.textContent = 'SAT'; satsSymbol.appendChild(satsCharacter); - btcAmount.appendChild(btcInput); + btcAmount.appendChild(this.btcInput); btcAmount.appendChild(satsSymbol); amountArea.appendChild(eurAmount); @@ -96,25 +97,27 @@ class AmountInput { this.eurInput.addEventListener('blur', () => { validateAndFormatEurAmountInput(this.eurInput); - this.updateBtcInput(btcInput); + this.updateBtcInput(); }); this.eurInput.addEventListener('input', () => { this.eurInput.value = this.eurInput.value.replace(/[^0-9]/g, ''); - this.updateBtcInput(btcInput); + this.updateBtcInput(); }); + this.updateBtcInput(); + this.element = amountArea; this.parentElement.appendChild(this.element); } - updateBtcInput(btcAmountInput) { + updateBtcInput() { const eurToSatRate = 1021; const cleanEurAmount = readIntFromEurAmountInput(this.eurInput); const satsAmount = cleanEurAmount * eurToSatRate; const formattedSatsAmount = formatNumberWithSpaces(satsAmount); - btcAmountInput.value = formattedSatsAmount; + this.btcInput.value = formattedSatsAmount; } } From fa8569f0c565b73105550054ec35244e4d21e0d8 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:38:58 +0100 Subject: [PATCH 07/60] everything inside class --- src/front/pages/offers.js | 58 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 580b263..771ce9f 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -4,33 +4,6 @@ const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup'); const PremiumSelector = require('../components/PremiumSelector'); const PriceDisplay = require('../components/PriceDisplay'); -function readIntFromEurAmountInput(eurAmountInput) { - 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(eurAmountInput) { - const cleanInputNumber = readIntFromEurAmountInput(eurAmountInput); - 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'); -} - class AmountInput { constructor({ parentElement, id }) { this.element = null; @@ -96,7 +69,7 @@ class AmountInput { amountArea.appendChild(btcAmount); this.eurInput.addEventListener('blur', () => { - validateAndFormatEurAmountInput(this.eurInput); + this.validateAndFormatEurAmountInput(this.eurInput); this.updateBtcInput(); }); @@ -111,9 +84,36 @@ class AmountInput { 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(eurAmountInput) { + const cleanInputNumber = this.intEurAmount; + 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'); + } + updateBtcInput() { const eurToSatRate = 1021; - const cleanEurAmount = readIntFromEurAmountInput(this.eurInput); + const cleanEurAmount = this.intEurAmount; const satsAmount = cleanEurAmount * eurToSatRate; const formattedSatsAmount = formatNumberWithSpaces(satsAmount); From c443b97c1980425dd41fc2a6e5ee3ba3dcb981ec Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 12:56:28 +0100 Subject: [PATCH 08/60] remove all references --- src/front/pages/offers.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 771ce9f..75b0f74 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -69,7 +69,7 @@ class AmountInput { amountArea.appendChild(btcAmount); this.eurInput.addEventListener('blur', () => { - this.validateAndFormatEurAmountInput(this.eurInput); + this.validateAndFormatEurAmountInput(); this.updateBtcInput(); }); @@ -99,16 +99,16 @@ class AmountInput { return cleanInputNumber; } - validateAndFormatEurAmountInput(eurAmountInput) { + validateAndFormatEurAmountInput() { const cleanInputNumber = this.intEurAmount; - eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid'); + this.eurInput.classList.remove('input-is-valid', 'input-is-invalid'); if (cleanInputNumber) { - eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber); - eurAmountInput.classList.add('input-is-valid'); + this.eurInput.value = formatNumberWithSpaces(cleanInputNumber); + this.eurInput.classList.add('input-is-valid'); return; } - eurAmountInput.classList.add('input-is-invalid'); + this.eurInput.classList.add('input-is-invalid'); } updateBtcInput() { @@ -259,7 +259,7 @@ function offersPage() { const wants = buyOrSellButtonGroup.wants(); const premium = premiumSelector.getPremium(); - const trade_amount_eur = eurAmountInput.value; + const trade_amount_eur = amountInput.intEurAmount; const location_details = placeInput.value; const time_availability_details = timeInput.value; const is_onchain_accepted = onchainCheckbox.checked; From b46087ea6cac71699bd799cace0fc1a8f042c04b Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 16:51:54 +0100 Subject: [PATCH 09/60] remove unused vars --- src/front/pages/offers.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 75b0f74..b20ed10 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -193,9 +193,6 @@ function offersPage() { ); 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'); From ac614921a46b80ff12d4b81a6cedceafa52d5e56 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 17:11:24 +0100 Subject: [PATCH 10/60] refactor into its own file --- src/front/components/AmountInput.js | 120 ++++++++++++++++++++++++++++ src/front/pages/offers.js | 119 +-------------------------- 2 files changed, 121 insertions(+), 118 deletions(-) create mode 100644 src/front/components/AmountInput.js diff --git a/src/front/components/AmountInput.js b/src/front/components/AmountInput.js new file mode 100644 index 0000000..8364bca --- /dev/null +++ b/src/front/components/AmountInput.js @@ -0,0 +1,120 @@ +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; + + const eurAmount = document.createElement('div'); + eurAmount.id = 'eur-amount'; + eurAmount.className = 'money-amount-input-area'; + + this.eurInput = document.createElement('input'); + this.eurInput.id = 'input-eur-amount'; + 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.id = 'eur-symbol'; + eurSymbol.className = 'curr-symbol'; + + const eurCharacter = document.createElement('span'); + eurCharacter.id = 'eur-character'; + eurCharacter.className = 'curr-character'; + eurCharacter.textContent = '€'; + + eurSymbol.appendChild(eurCharacter); + eurAmount.appendChild(this.eurInput); + eurAmount.appendChild(eurSymbol); + + const btcAmount = document.createElement('div'); + btcAmount.id = 'btc-amount'; + btcAmount.className = 'money-amount-input-area'; + + this.btcInput = document.createElement('input'); + this.btcInput.id = 'input-btc-amount'; + this.btcInput.type = 'text'; + this.btcInput.className = 'money-input input-money-amount'; + this.btcInput.disabled = true; + + const satsSymbol = document.createElement('div'); + satsSymbol.id = 'sats-symbol'; + satsSymbol.className = 'curr-symbol'; + + const satsCharacter = document.createElement('span'); + satsCharacter.id = 'sats-character'; + 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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index b20ed10..88f3432 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -1,125 +1,8 @@ -const formatNumberWithSpaces = require('../utils/formatNumbersWithSpaces'); const PublishOfferButton = require('../components/PublishOfferButton'); const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup'); const PremiumSelector = require('../components/PremiumSelector'); const PriceDisplay = require('../components/PriceDisplay'); - -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; - - const eurAmount = document.createElement('div'); - eurAmount.id = 'eur-amount'; - eurAmount.className = 'money-amount-input-area'; - - this.eurInput = document.createElement('input'); - this.eurInput.id = 'input-eur-amount'; - 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.id = 'eur-symbol'; - eurSymbol.className = 'curr-symbol'; - - const eurCharacter = document.createElement('span'); - eurCharacter.id = 'eur-character'; - eurCharacter.className = 'curr-character'; - eurCharacter.textContent = '€'; - - eurSymbol.appendChild(eurCharacter); - eurAmount.appendChild(this.eurInput); - eurAmount.appendChild(eurSymbol); - - const btcAmount = document.createElement('div'); - btcAmount.id = 'btc-amount'; - btcAmount.className = 'money-amount-input-area'; - - this.btcInput = document.createElement('input'); - this.btcInput.id = 'input-btc-amount'; - this.btcInput.type = 'text'; - this.btcInput.className = 'money-input input-money-amount'; - this.btcInput.disabled = true; - - const satsSymbol = document.createElement('div'); - satsSymbol.id = 'sats-symbol'; - satsSymbol.className = 'curr-symbol'; - - const satsCharacter = document.createElement('span'); - satsCharacter.id = 'sats-character'; - 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; - } -} +const AmountInput = require('../components/AmountInput'); function offersPage() { const createOfferEventBus = new EventTarget(); From ee80c2f4a926a12a3733488efb1b94b461ae84ed Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 17:24:25 +0100 Subject: [PATCH 11/60] place input object --- src/front/pages/offers.js | 34 ++++++++++++++++++++++++++++++++-- src/views/offers.ejs | 9 +-------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 88f3432..4fbf8a9 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -4,6 +4,31 @@ const PremiumSelector = require('../components/PremiumSelector'); const PriceDisplay = require('../components/PriceDisplay'); const AmountInput = require('../components/AmountInput'); +class PlaceInput { + constructor({ parentElement, id }) { + this.element = null; + this.parentElement = parentElement; + this.id = id; + } + + render() { + const placeInput = document.createElement('textarea'); + placeInput.id = 'place-input'; + 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; + } +} + function offersPage() { const createOfferEventBus = new EventTarget(); @@ -54,6 +79,12 @@ function offersPage() { }); amountInput.render(); + + const placeInput = new PlaceInput({ + parentElement: document.getElementById('place-and-time-boxes'), + }); + + placeInput.render(); // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -76,7 +107,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - const placeInput = document.getElementById('place-input'); const timeInput = document.getElementById('time-input'); const onchainCheckbox = document.getElementById('onchain-checkbox'); @@ -140,7 +170,7 @@ function offersPage() { const premium = premiumSelector.getPremium(); const trade_amount_eur = amountInput.intEurAmount; - const location_details = placeInput.value; + const location_details = placeInput.inputText; const time_availability_details = timeInput.value; const is_onchain_accepted = onchainCheckbox.checked; const is_lightning_accepted = lightningCheckbox.checked; diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 175422a..9d1fef7 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -46,14 +46,7 @@

¿Dónde y cuándo?

- -
From 935d827c58bdf392ec57855cf20e82e8fc46ac24 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 22 Mar 2025 17:57:06 +0100 Subject: [PATCH 15/60] add an extra container --- src/views/offers.ejs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/views/offers.ejs b/src/views/offers.ejs index a788793..c60400e 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -45,26 +45,27 @@

¿Dónde y cuándo?

-
-
+

¿Cómo se mueve el Bitcoin?

-
- -
-
- +
+
+ +
+
+ +
From 7e5fdecf1a785a139a68055aab427d2a8b431665 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 23 Mar 2025 11:00:06 +0100 Subject: [PATCH 16/60] bitcoin methods objectified --- src/front/pages/offers.js | 105 ++++++++++++++++++++++++++++++-------- src/views/offers.ejs | 16 ------ 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index d37dd08..d69b12f 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -6,6 +6,83 @@ const AmountInput = require('../components/AmountInput'); const PlaceInput = require('../components/PlaceInput'); const TimeInput = require('../components/TimeInput'); +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({ id, label }) { + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-row'; + checkboxContainer.id = `${id}-checkbox-area`; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.name = id; + checkbox.id = `${id}-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; + console.log(checkedCount); + if (checkedCount === 0) { + clickedCheckbox.checked = true; + } + } + + get isOnchainAccepted() { + return this.onchainCheckboxElement.checked; + } + + get isLightningAccepted() { + return this.lightningCheckboxElement.checked; + } +} + function offersPage() { const createOfferEventBus = new EventTarget(); @@ -70,6 +147,12 @@ function offersPage() { }); timeInput.render(); + + const btcMethodCheckboxes = new BitcoinMethodCheckboxes({ + parentElement: document.getElementById('bitcoin-methods-checkboxes'), + }); + + btcMethodCheckboxes.render(); // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -92,11 +175,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - 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' @@ -125,13 +203,6 @@ function offersPage() { viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - 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!'); @@ -155,8 +226,8 @@ function offersPage() { const trade_amount_eur = amountInput.intEurAmount; const location_details = placeInput.inputText; const time_availability_details = timeInput.inputText; - const is_onchain_accepted = onchainCheckbox.checked; - const is_lightning_accepted = lightningCheckbox.checked; + const is_onchain_accepted = btcMethodCheckboxes.isOnchainAccepted; + const is_lightning_accepted = btcMethodCheckboxes.isLightningAccepted; const show_offer_to_trusted = myTrustedCheckbox.checked; const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked; const show_offer_to_all_members = allMembersCheckbox.checked; @@ -644,12 +715,6 @@ function offersPage() { toggleCreateOfferModal(); }); - for (const btcMethodCheckbox of btcMethodCheckboxes) { - btcMethodCheckbox.addEventListener('click', () => { - validateBitcoinMethodCheckboxes(btcMethodCheckbox); - }); - } - myTrustedTrustedCheckbox.addEventListener('click', () => { applyTrustCheckboxConstraints(myTrustedTrustedCheckbox); }); diff --git a/src/views/offers.ejs b/src/views/offers.ejs index c60400e..ab3b572 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -50,22 +50,6 @@

¿Cómo se mueve el Bitcoin?

-
- -
-
- -
From b4fa6cb9624d6fd278aea7d21bc3580404dc0c66 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 23 Mar 2025 11:10:36 +0100 Subject: [PATCH 17/60] move into its own file --- .../components/BitcoinMethodCheckboxes.js | 78 +++++++++++++++++++ src/front/pages/offers.js | 78 +------------------ 2 files changed, 79 insertions(+), 77 deletions(-) create mode 100644 src/front/components/BitcoinMethodCheckboxes.js diff --git a/src/front/components/BitcoinMethodCheckboxes.js b/src/front/components/BitcoinMethodCheckboxes.js new file mode 100644 index 0000000..01c0743 --- /dev/null +++ b/src/front/components/BitcoinMethodCheckboxes.js @@ -0,0 +1,78 @@ +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({ id, label }) { + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-row'; + checkboxContainer.id = `${id}-checkbox-area`; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.name = id; + checkbox.id = `${id}-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; + console.log(checkedCount); + if (checkedCount === 0) { + clickedCheckbox.checked = true; + } + } + + get isOnchainAccepted() { + return this.onchainCheckboxElement.checked; + } + + get isLightningAccepted() { + return this.lightningCheckboxElement.checked; + } +} + +module.exports = BitcoinMethodCheckboxes; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index d69b12f..3a2bd0b 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -5,83 +5,7 @@ const PriceDisplay = require('../components/PriceDisplay'); const AmountInput = require('../components/AmountInput'); const PlaceInput = require('../components/PlaceInput'); const TimeInput = require('../components/TimeInput'); - -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({ id, label }) { - const checkboxContainer = document.createElement('div'); - checkboxContainer.className = 'checkbox-row'; - checkboxContainer.id = `${id}-checkbox-area`; - - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.name = id; - checkbox.id = `${id}-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; - console.log(checkedCount); - if (checkedCount === 0) { - clickedCheckbox.checked = true; - } - } - - get isOnchainAccepted() { - return this.onchainCheckboxElement.checked; - } - - get isLightningAccepted() { - return this.lightningCheckboxElement.checked; - } -} +const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); function offersPage() { const createOfferEventBus = new EventTarget(); From c49a35029876cd04e21174b10a63d4c12161e854 Mon Sep 17 00:00:00 2001 From: counterweight Date: Mon, 24 Mar 2025 16:12:30 +0100 Subject: [PATCH 18/60] wip --- src/front/pages/offers.js | 102 ++++++++++++++++++++++++++++++++++++++ src/views/offers.ejs | 55 ++++++++++---------- 2 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 3a2bd0b..4a16016 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -7,6 +7,108 @@ const PlaceInput = require('../components/PlaceInput'); const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); +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 labelsAndVars = [ + { + id: 'my-trusted', + label: 'Mis confiados', + containerProperty: 'myTrustedContainer', + checkboxProperty: 'myTrustedCheckboxElement', + }, + { + id: 'my-trusted-trusted', + label: 'Los confiados de mis confiados', + containerProperty: 'myTrustedTrustedContainer', + checkboxProperty: 'myTrustedTrustedCheckboxElement', + }, + { + id: 'all-members', + label: 'Todos los miembros', + containerProperty: 'allMembersContainer', + checkboxProperty: 'allMembersCheckboxElement', + }, + ]; + + for (const labelAndVar of labelsAndVars) { + this[labelAndVar.containerProperty] = this.buildCheckbox({ + id: labelAndVar.id, + label: labelAndVar.label, + }); + + this[labelAndVar.checkboxProperty] = + this[labelAndVar.containerProperty].querySelector('input'); + + this[labelAndVar.checkboxProperty].addEventListener('click', () => { + this.applyTrustCheckboxConstraints(this[labelAndVar.checkboxProperty]); + }); + + this.parentElement.appendChild(this[labelAndVar.containerProperty]); + } + } + + buildCheckbox({ id, label }) { + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-row'; + checkboxContainer.id = `${id}-checkbox-area`; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.name = id; + checkbox.id = `${id}-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) { + console.log('first case!'); + if ( + !this.myTrustedTrustedCheckboxElement.checked && + this.allMembersCheckboxElement.checked + ) { + this.allMembersCheckboxElement.checked = false; + } + } + + if (pressedCheckbox === this.allMembersCheckboxElement) { + console.log('second case!'); + if ( + !this.myTrustedTrustedCheckboxElement.checked && + this.allMembersCheckboxElement.checked + ) { + this.myTrustedTrustedCheckboxElement.checked = true; + } + } + } + + get isOnchainAccepted() { + return this.onchainCheckboxElement.checked; + } + + get isLightningAccepted() { + return this.lightningCheckboxElement.checked; + } +} + function offersPage() { const createOfferEventBus = new EventTarget(); diff --git a/src/views/offers.ejs b/src/views/offers.ejs index ab3b572..941f689 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -49,36 +49,37 @@

¿Cómo se mueve el Bitcoin?

-
-
+

¿Quién puede ver la oferta?

-
- -
-
- -
-
- +
+
+ +
+
+ +
+
+ +
From 9bdd2aa23d74fcaedc027bd05da2768fe0af9504 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Tue, 25 Mar 2025 16:11:17 +0100 Subject: [PATCH 19/60] trust checkboxes now in object --- src/front/pages/offers.js | 91 ++++++++++++++++++--------------------- src/views/offers.ejs | 29 +------------ 2 files changed, 43 insertions(+), 77 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 4a16016..eafd4d7 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -19,41 +19,54 @@ class TrustCheckboxes { } render() { - const labelsAndVars = [ + const checkboxesDetails = [ { id: 'my-trusted', label: 'Mis confiados', containerProperty: 'myTrustedContainer', checkboxProperty: 'myTrustedCheckboxElement', + defaultChecked: true, + isDisabled: true, }, { id: 'my-trusted-trusted', label: 'Los confiados de mis confiados', containerProperty: 'myTrustedTrustedContainer', checkboxProperty: 'myTrustedTrustedCheckboxElement', + defaultChecked: true, + isDisabled: false, }, { id: 'all-members', label: 'Todos los miembros', containerProperty: 'allMembersContainer', checkboxProperty: 'allMembersCheckboxElement', + defaultChecked: false, + isDisabled: false, }, ]; - for (const labelAndVar of labelsAndVars) { - this[labelAndVar.containerProperty] = this.buildCheckbox({ - id: labelAndVar.id, - label: labelAndVar.label, + for (const checkboxDetails of checkboxesDetails) { + this[checkboxDetails.containerProperty] = this.buildCheckbox({ + id: checkboxDetails.id, + label: checkboxDetails.label, }); - this[labelAndVar.checkboxProperty] = - this[labelAndVar.containerProperty].querySelector('input'); + this[checkboxDetails.checkboxProperty] = + this[checkboxDetails.containerProperty].querySelector('input'); - this[labelAndVar.checkboxProperty].addEventListener('click', () => { - this.applyTrustCheckboxConstraints(this[labelAndVar.checkboxProperty]); + this[checkboxDetails.checkboxProperty].addEventListener('click', () => { + this.applyTrustCheckboxConstraints( + this[checkboxDetails.checkboxProperty] + ); }); - this.parentElement.appendChild(this[labelAndVar.containerProperty]); + this[checkboxDetails.checkboxProperty].checked = + checkboxDetails.defaultChecked; + this[checkboxDetails.checkboxProperty].disabled = + checkboxDetails.isDisabled; + + this.parentElement.appendChild(this[checkboxDetails.containerProperty]); } } @@ -80,7 +93,6 @@ class TrustCheckboxes { applyTrustCheckboxConstraints(pressedCheckbox) { if (pressedCheckbox === this.myTrustedTrustedCheckboxElement) { - console.log('first case!'); if ( !this.myTrustedTrustedCheckboxElement.checked && this.allMembersCheckboxElement.checked @@ -90,7 +102,6 @@ class TrustCheckboxes { } if (pressedCheckbox === this.allMembersCheckboxElement) { - console.log('second case!'); if ( !this.myTrustedTrustedCheckboxElement.checked && this.allMembersCheckboxElement.checked @@ -100,12 +111,16 @@ class TrustCheckboxes { } } - get isOnchainAccepted() { - return this.onchainCheckboxElement.checked; + get showOfferToTrusted() { + return this.myTrustedCheckboxElement.checked; } - get isLightningAccepted() { - return this.lightningCheckboxElement.checked; + get showOfferToTrustedTrusted() { + return this.myTrustedTrustedCheckboxElement.checked; + } + + get showOfferToAllMembers() { + return this.allMembersCheckboxElement.checked; } } @@ -179,6 +194,13 @@ function offersPage() { }); btcMethodCheckboxes.render(); + + const trustCheckboxes = new TrustCheckboxes({ + parentElement: document.getElementById('trusted-checkboxes-area'), + }); + + trustCheckboxes.render(); + // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -201,12 +223,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - 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' ); @@ -229,22 +245,6 @@ function offersPage() { viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - 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(); @@ -254,9 +254,10 @@ function offersPage() { const time_availability_details = timeInput.inputText; const is_onchain_accepted = btcMethodCheckboxes.isOnchainAccepted; const is_lightning_accepted = btcMethodCheckboxes.isLightningAccepted; - const show_offer_to_trusted = myTrustedCheckbox.checked; - const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked; - const show_offer_to_all_members = allMembersCheckbox.checked; + const show_offer_to_trusted = trustCheckboxes.showOfferToTrusted; + const show_offer_to_trusted_trusted = + trustCheckboxes.showOfferToTrustedTrusted; + const show_offer_to_all_members = trustCheckboxes.showOfferToAllMembers; const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked; const offerDetails = { @@ -741,14 +742,6 @@ function offersPage() { toggleCreateOfferModal(); }); - myTrustedTrustedCheckbox.addEventListener('click', () => { - applyTrustCheckboxConstraints(myTrustedTrustedCheckbox); - }); - - allMembersCheckbox.addEventListener('click', () => { - applyTrustCheckboxConstraints(allMembersCheckbox); - }); - const myOffers = new MyOffers(ownOffersContainer); } diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 941f689..79a91e6 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -53,34 +53,7 @@

¿Quién puede ver la oferta?

-
-
- -
-
- -
-
- -
-
+

Extras

From 754c3cf02e5518818c3f6b9e44c99c386dcf603b Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Tue, 25 Mar 2025 16:14:18 +0100 Subject: [PATCH 20/60] move to separate file --- src/front/components/TrustCheckboxes.js | 118 ++++++++++++++++++++++++ src/front/pages/offers.js | 118 +----------------------- 2 files changed, 119 insertions(+), 117 deletions(-) create mode 100644 src/front/components/TrustCheckboxes.js diff --git a/src/front/components/TrustCheckboxes.js b/src/front/components/TrustCheckboxes.js new file mode 100644 index 0000000..bd47e84 --- /dev/null +++ b/src/front/components/TrustCheckboxes.js @@ -0,0 +1,118 @@ +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 = [ + { + id: 'my-trusted', + label: 'Mis confiados', + containerProperty: 'myTrustedContainer', + checkboxProperty: 'myTrustedCheckboxElement', + defaultChecked: true, + isDisabled: true, + }, + { + id: 'my-trusted-trusted', + label: 'Los confiados de mis confiados', + containerProperty: 'myTrustedTrustedContainer', + checkboxProperty: 'myTrustedTrustedCheckboxElement', + defaultChecked: true, + isDisabled: false, + }, + { + id: 'all-members', + label: 'Todos los miembros', + containerProperty: 'allMembersContainer', + checkboxProperty: 'allMembersCheckboxElement', + defaultChecked: false, + isDisabled: false, + }, + ]; + + for (const checkboxDetails of checkboxesDetails) { + this[checkboxDetails.containerProperty] = this.buildCheckbox({ + id: checkboxDetails.id, + 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({ id, label }) { + const checkboxContainer = document.createElement('div'); + checkboxContainer.className = 'checkbox-row'; + checkboxContainer.id = `${id}-checkbox-area`; + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.name = id; + checkbox.id = `${id}-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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index eafd4d7..b587106 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -6,123 +6,7 @@ const AmountInput = require('../components/AmountInput'); const PlaceInput = require('../components/PlaceInput'); const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); - -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 = [ - { - id: 'my-trusted', - label: 'Mis confiados', - containerProperty: 'myTrustedContainer', - checkboxProperty: 'myTrustedCheckboxElement', - defaultChecked: true, - isDisabled: true, - }, - { - id: 'my-trusted-trusted', - label: 'Los confiados de mis confiados', - containerProperty: 'myTrustedTrustedContainer', - checkboxProperty: 'myTrustedTrustedCheckboxElement', - defaultChecked: true, - isDisabled: false, - }, - { - id: 'all-members', - label: 'Todos los miembros', - containerProperty: 'allMembersContainer', - checkboxProperty: 'allMembersCheckboxElement', - defaultChecked: false, - isDisabled: false, - }, - ]; - - for (const checkboxDetails of checkboxesDetails) { - this[checkboxDetails.containerProperty] = this.buildCheckbox({ - id: checkboxDetails.id, - 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({ id, label }) { - const checkboxContainer = document.createElement('div'); - checkboxContainer.className = 'checkbox-row'; - checkboxContainer.id = `${id}-checkbox-area`; - - const checkbox = document.createElement('input'); - checkbox.type = 'checkbox'; - checkbox.name = id; - checkbox.id = `${id}-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; - } -} +const TrustCheckboxes = require('../components/TrustCheckboxes'); function offersPage() { const createOfferEventBus = new EventTarget(); From 0a34622a02a09ec36dfaffe0b24450fc62add6c3 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Tue, 25 Mar 2025 16:52:24 +0100 Subject: [PATCH 21/60] big notes with object --- src/front/pages/offers.js | 46 ++++++++++++++++++++++++++++++++++----- src/views/offers.ejs | 9 -------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index b587106..4859729 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -8,6 +8,41 @@ const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); const TrustCheckboxes = require('../components/TrustCheckboxes'); +class BigNotesCheckbox { + constructor({parentElement}) { + this.bigNotesContainer = null; + this.bigNotesCheckboxElement = null; + this.parentElement = parentElement; + } + + render() { + const container = document.createElement('div'); + container.id = 'large-bills-area'; + 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; + } +} + function offersPage() { const createOfferEventBus = new EventTarget(); @@ -85,6 +120,11 @@ function offersPage() { trustCheckboxes.render(); + const bigNotesCheckbox = new BigNotesCheckbox({ + parentElement: document.getElementById('other-area') + }) + + bigNotesCheckbox.render(); // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -107,10 +147,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - const bigNotesAcceptedCheckbox = document.getElementById( - 'large-bills-checkbox' - ); - const offerCreatedPopup = document.getElementById( 'offer-created-confirmation' ); @@ -142,7 +178,7 @@ function offersPage() { const show_offer_to_trusted_trusted = trustCheckboxes.showOfferToTrustedTrusted; const show_offer_to_all_members = trustCheckboxes.showOfferToAllMembers; - const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked; + const are_big_notes_accepted = bigNotesCheckbox.areBigNotesAccepted; const offerDetails = { wants, diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 79a91e6..2fb3977 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -57,15 +57,6 @@

Extras

-
- -
From a9779c207ed82a66023d59baa77f4bee8959c976 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Tue, 25 Mar 2025 16:56:10 +0100 Subject: [PATCH 22/60] move to file --- src/front/components/BigNotesCheckbox.js | 36 +++++++++++++++++++++ src/front/pages/offers.js | 40 ++---------------------- 2 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 src/front/components/BigNotesCheckbox.js diff --git a/src/front/components/BigNotesCheckbox.js b/src/front/components/BigNotesCheckbox.js new file mode 100644 index 0000000..005502c --- /dev/null +++ b/src/front/components/BigNotesCheckbox.js @@ -0,0 +1,36 @@ +class BigNotesCheckbox { + constructor({ parentElement }) { + this.bigNotesContainer = null; + this.bigNotesCheckboxElement = null; + this.parentElement = parentElement; + } + + render() { + const container = document.createElement('div'); + container.id = 'large-bills-area'; + 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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 4859729..f60febf 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -7,41 +7,7 @@ const PlaceInput = require('../components/PlaceInput'); const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); const TrustCheckboxes = require('../components/TrustCheckboxes'); - -class BigNotesCheckbox { - constructor({parentElement}) { - this.bigNotesContainer = null; - this.bigNotesCheckboxElement = null; - this.parentElement = parentElement; - } - - render() { - const container = document.createElement('div'); - container.id = 'large-bills-area'; - 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; - } -} +const BigNotesCheckbox = require('../components/BigNotesCheckbox'); function offersPage() { const createOfferEventBus = new EventTarget(); @@ -121,8 +87,8 @@ function offersPage() { trustCheckboxes.render(); const bigNotesCheckbox = new BigNotesCheckbox({ - parentElement: document.getElementById('other-area') - }) + parentElement: document.getElementById('other-area'), + }); bigNotesCheckbox.render(); // ----------- From 95dd754992b8dcdb94797f0ecf92d8ecfb8235f6 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 30 Mar 2025 18:47:06 +0200 Subject: [PATCH 23/60] createoffermodal is now one big ass object --- src/front/pages/offers.js | 378 ++++++++++++++++++++++++-------------- src/views/offers.ejs | 36 ---- 2 files changed, 245 insertions(+), 169 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index f60febf..f0435a3 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -9,88 +9,253 @@ const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes') const TrustCheckboxes = require('../components/TrustCheckboxes'); const BigNotesCheckbox = require('../components/BigNotesCheckbox'); +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); +} + +class CreateOfferModal { + constructor({ parentElement }) { + this.element = null; + this.parentElement = parentElement; + + 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.id = 'create-offer-modal-root'; + modalRoot.className = 'full-screen-modal-background'; + + const modal = document.createElement('div'); + modal.className = 'full-screen-modal'; + modal.id = 'create-offer-root'; + + const controls = document.createElement('div'); + controls.id = 'create-offer-controls'; + + const title = document.createElement('h2'); + title.textContent = 'Añade los detalles de tu oferta'; + + const sections = [ + { id: 'buy-or-sell-area', class: 'create-offer-step', title: '' }, + { + id: 'premium-area', + class: 'create-offer-step', + title: 'Premium', + contentId: 'premium-content-area', + }, + { id: 'amount-area', class: 'create-offer-step', title: '¿Cuánto?' }, + { + id: 'place-and-time-area', + class: 'create-offer-step', + title: '¿Dónde y cuándo?', + contentId: 'place-and-time-boxes', + }, + { + id: 'bitcoin-methods-area', + class: 'create-offer-step', + title: '¿Cómo se mueve el Bitcoin?', + contentId: 'bitcoin-methods-checkboxes', + }, + { + id: 'trust-area', + class: 'create-offer-step', + title: '¿Quién puede ver la oferta?', + contentId: 'trusted-checkboxes-area', + }, + { id: 'other-area', class: 'create-offer-step', title: 'Extras' }, + ]; + + controls.appendChild(title); + + sections.forEach((section) => { + const div = document.createElement('div'); + div.id = section.id; + div.className = section.class; + if (section.title) { + const heading = document.createElement('h3'); + heading.textContent = section.title; + div.appendChild(heading); + } + if (section.contentId) { + const contentDiv = document.createElement('div'); + contentDiv.id = section.contentId; + div.appendChild(contentDiv); + } + controls.appendChild(div); + }); + + const submitButtonArea = document.createElement('div'); + submitButtonArea.id = 'submit-button-area'; + + const closeButtonArea = document.createElement('div'); + closeButtonArea.id = 'close-offer-controls-area'; + const closeButton = document.createElement('button'); + closeButton.id = 'close-offer'; + closeButton.className = 'button-secondary button-medium'; + closeButton.textContent = 'Volver'; + closeButtonArea.appendChild(closeButton); + + controls.appendChild(submitButtonArea); + controls.appendChild(closeButtonArea); + + modal.appendChild(controls); + modalRoot.appendChild(modal); + + this.parentElement.appendChild(this.element); + + const createOfferEventBus = new EventTarget(); + + const mockPriceProvidingCallback = () => { + return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); + }; + + this.publishOfferButton = new PublishOfferButton({ + parentElement: document.getElementById('submit-button-area'), + id: 'button-submit-offer', + onClickCallback: async () => { + await this.createOffer(); + //await myOffers.getOffersFromApi(); + //await myOffers.render(); + }, + }); + this.publishOfferButton.render(); + + this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({ + parentElement: document.getElementById('buy-or-sell-area'), + id: 'button-group-buy-or-sell', + }); + this.buyOrSellButtonGroup.render(); + + this.premiumSelector = new PremiumSelector({ + parentElement: document.getElementById('premium-content-area'), + id: 'premium-selector-area', + eventSink: createOfferEventBus, + }); + this.premiumSelector.render(); + + const priceDisplay = new PriceDisplay({ + parentElement: document.getElementById('premium-content-area'), + id: 'premium-price-display-area', + premiumProvidingCallback: () => { + return this.premiumSelector.getPremium(); + }, + priceProvidingCallback: mockPriceProvidingCallback, + }); + priceDisplay.render(); + createOfferEventBus.addEventListener('premium-changed', () => { + priceDisplay.updatePrices(); + }); + + this.amountInput = new AmountInput({ + parentElement: document.getElementById('amount-area'), + id: 'amount-area-content', + }); + + this.amountInput.render(); + + this.placeInput = new PlaceInput({ + parentElement: document.getElementById('place-and-time-boxes'), + id: 'place-input', + }); + + this.placeInput.render(); + + this.timeInput = new TimeInput({ + parentElement: document.getElementById('place-and-time-boxes'), + id: 'time-input', + }); + + this.timeInput.render(); + + this.btcMethodCheckboxes = new BitcoinMethodCheckboxes({ + parentElement: document.getElementById('bitcoin-methods-checkboxes'), + }); + + this.btcMethodCheckboxes.render(); + + this.trustCheckboxes = new TrustCheckboxes({ + parentElement: document.getElementById('trusted-checkboxes-area'), + }); + + this.trustCheckboxes.render(); + + this.bigNotesCheckbox = new BigNotesCheckbox({ + parentElement: document.getElementById('other-area'), + }); + + this.bigNotesCheckbox.render(); + } + + 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 fetch('/api/offer', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ offerDetails }), + }); + + toggleOfferCreatedAlert(); + + this.toggle(); + } +} + function offersPage() { - const createOfferEventBus = new EventTarget(); - - const mockPriceProvidingCallback = () => { - return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); - }; - - const publishOfferButton = new PublishOfferButton({ - parentElement: document.getElementById('submit-button-area'), - id: 'button-submit-offer', - onClickCallback: async () => { - await publishOffer(); - await myOffers.getOffersFromApi(); - await myOffers.render(); - }, + const createOfferModal = new CreateOfferModal({ + parentElement: document.body, }); - publishOfferButton.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: mockPriceProvidingCallback, - }); - priceDisplay.render(); - createOfferEventBus.addEventListener('premium-changed', () => { - priceDisplay.updatePrices(); - }); - - const amountInput = new AmountInput({ - parentElement: document.getElementById('amount-area'), - id: 'amount-area-content', - }); - - amountInput.render(); - - const placeInput = new PlaceInput({ - parentElement: document.getElementById('place-and-time-boxes'), - id: 'place-input', - }); - - placeInput.render(); - - const timeInput = new TimeInput({ - parentElement: document.getElementById('place-and-time-boxes'), - id: 'time-input', - }); - - timeInput.render(); - - const btcMethodCheckboxes = new BitcoinMethodCheckboxes({ - parentElement: document.getElementById('bitcoin-methods-checkboxes'), - }); - - btcMethodCheckboxes.render(); - - const trustCheckboxes = new TrustCheckboxes({ - parentElement: document.getElementById('trusted-checkboxes-area'), - }); - - trustCheckboxes.render(); - - const bigNotesCheckbox = new BigNotesCheckbox({ - parentElement: document.getElementById('other-area'), - }); - - bigNotesCheckbox.render(); + createOfferModal.render(); // ----------- const navbuttonHome = document.getElementById('navbutton-home'); const navbuttonOffers = document.getElementById('navbutton-offers'); @@ -131,59 +296,6 @@ function offersPage() { viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - async function publishOffer() { - const wants = buyOrSellButtonGroup.wants(); - - const premium = premiumSelector.getPremium(); - const trade_amount_eur = amountInput.intEurAmount; - const location_details = placeInput.inputText; - const time_availability_details = timeInput.inputText; - const is_onchain_accepted = btcMethodCheckboxes.isOnchainAccepted; - const is_lightning_accepted = btcMethodCheckboxes.isLightningAccepted; - const show_offer_to_trusted = trustCheckboxes.showOfferToTrusted; - const show_offer_to_trusted_trusted = - trustCheckboxes.showOfferToTrustedTrusted; - const show_offer_to_all_members = trustCheckboxes.showOfferToAllMembers; - const are_big_notes_accepted = 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 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'); diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 2fb3977..22141c7 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -31,42 +31,6 @@

Vaya, no hay nada por aquí...

-
-
-
-

Añade los detalles de tu oferta

-
-
-

Premium

-
-
-
-

¿Cuánto?

-
-
-

¿Dónde y cuándo?

-
-
-
-

¿Cómo se mueve el Bitcoin?

-
-
-
-

¿Quién puede ver la oferta?

-
-
-
-

Extras

-
-
-
- -
-
-
-
Date: Sun, 30 Mar 2025 19:05:09 +0200 Subject: [PATCH 24/60] on creation callback --- src/front/pages/offers.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index f0435a3..1414e0f 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -9,6 +9,7 @@ const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes') const TrustCheckboxes = require('../components/TrustCheckboxes'); const BigNotesCheckbox = require('../components/BigNotesCheckbox'); +const offerCreatedPopup = document.getElementById('offer-created-confirmation'); function toggleOfferCreatedAlert() { offerCreatedPopup.classList.remove('max-size-zero'); offerCreatedPopup.classList.add('revealed'); @@ -21,9 +22,12 @@ function toggleOfferCreatedAlert() { } class CreateOfferModal { - constructor({ parentElement }) { + // Actual creation logic to be provided by a service + // Stop relying on IDs + constructor({ parentElement, onCreationCallback }) { this.element = null; this.parentElement = parentElement; + this.onCreationCallback = onCreationCallback; this.publishOfferButton = null; this.buyOrSellButtonGroup = null; @@ -131,8 +135,7 @@ class CreateOfferModal { id: 'button-submit-offer', onClickCallback: async () => { await this.createOffer(); - //await myOffers.getOffersFromApi(); - //await myOffers.render(); + await this.onCreationCallback(); }, }); this.publishOfferButton.render(); @@ -254,6 +257,10 @@ class CreateOfferModal { function offersPage() { const createOfferModal = new CreateOfferModal({ parentElement: document.body, + onCreationCallback: async () => { + await myOffers.getOffersFromApi(); + await myOffers.render(); + }, }); createOfferModal.render(); // ----------- @@ -278,9 +285,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - const offerCreatedPopup = document.getElementById( - 'offer-created-confirmation' - ); const offerDeletedPopup = document.getElementById( 'offer-deleted-confirmation' ); From 1675d4f7ff470a008835885873d19f1178547073 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 30 Mar 2025 19:14:34 +0200 Subject: [PATCH 25/60] popup also gets callbacked --- src/front/pages/offers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 1414e0f..3a8ef6a 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -136,6 +136,7 @@ class CreateOfferModal { onClickCallback: async () => { await this.createOffer(); await this.onCreationCallback(); + await this.toggleOfferCreatedAlert(); }, }); this.publishOfferButton.render(); @@ -248,8 +249,6 @@ class CreateOfferModal { body: JSON.stringify({ offerDetails }), }); - toggleOfferCreatedAlert(); - this.toggle(); } } @@ -260,6 +259,7 @@ function offersPage() { onCreationCallback: async () => { await myOffers.getOffersFromApi(); await myOffers.render(); + await toggleOfferCreatedAlert(); }, }); createOfferModal.render(); From efb31cc99375f8627e48c854e1e9bcbabcf3b3a2 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 30 Mar 2025 19:20:30 +0200 Subject: [PATCH 26/60] popup with object --- src/front/components/PopupNotification.js | 16 +++++++++++++++- src/front/pages/offers.js | 21 ++++++++------------- src/views/offers.ejs | 7 ------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/front/components/PopupNotification.js b/src/front/components/PopupNotification.js index e2a0588..8604184 100644 --- a/src/front/components/PopupNotification.js +++ b/src/front/components/PopupNotification.js @@ -9,7 +9,7 @@ class PopupNotification { render() { const div = document.createElement('div'); div.id = this.id; - div.className = 'top-notification-good'; + div.className = 'top-notification-good max-size-zero'; div.innerHTML = `

${this.text}

`; @@ -21,5 +21,19 @@ class PopupNotification { display() { 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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 3a8ef6a..c1c7604 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -8,18 +8,7 @@ const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); const TrustCheckboxes = require('../components/TrustCheckboxes'); const BigNotesCheckbox = require('../components/BigNotesCheckbox'); - -const offerCreatedPopup = document.getElementById('offer-created-confirmation'); -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); -} +const PopupNotification = require('../components/PopupNotification'); class CreateOfferModal { // Actual creation logic to be provided by a service @@ -254,12 +243,18 @@ class CreateOfferModal { } function offersPage() { + const offerCreatedPopup = new PopupNotification({ + parentElement: document.body, + text: '¡Oferta creada! Puedes verla en tus ofertas.', + }); + + offerCreatedPopup.render(); const createOfferModal = new CreateOfferModal({ parentElement: document.body, onCreationCallback: async () => { await myOffers.getOffersFromApi(); await myOffers.render(); - await toggleOfferCreatedAlert(); + offerCreatedPopup.displayTemporarily(3000); }, }); createOfferModal.render(); diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 22141c7..a5f978c 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -31,13 +31,6 @@

Vaya, no hay nada por aquí...

-
- -

¡Oferta creada! Puedes verla en tus ofertas.

-
Date: Sun, 30 Mar 2025 19:59:17 +0200 Subject: [PATCH 27/60] offerdeleted popup --- src/front/pages/offers.js | 26 ++++++++------------------ src/views/offers.ejs | 9 +-------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index c1c7604..b6cc7cc 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -247,8 +247,14 @@ function offersPage() { parentElement: document.body, text: '¡Oferta creada! Puedes verla en tus ofertas.', }); - offerCreatedPopup.render(); + + const offerDeletedPopup = new PopupNotification({ + parentElement: document.body, + text: '¡Oferta eliminada!', + }); + offerDeletedPopup.render(); + const createOfferModal = new CreateOfferModal({ parentElement: document.body, onCreationCallback: async () => { @@ -280,10 +286,6 @@ function offersPage() { ); const viewMyOffersRoot = document.getElementById('view-my-offers-root'); - const offerDeletedPopup = document.getElementById( - 'offer-deleted-confirmation' - ); - const ownOffersContainer = document.getElementById('own-offers-container'); function toggleCreateOfferModal() { @@ -294,18 +296,6 @@ function offersPage() { viewMyOffersRoot.style.display = viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - - 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; @@ -663,7 +653,7 @@ function offersPage() { await deleteOfferByUuid(this.uuid); await myOffers.getOffersFromApi(); await myOffers.render(); - toggleOfferDeletedAlert(); + offerDeletedPopup.displayTemporarily(3000); }); actionButtonsArea.append(editActionArea, deleteActionArea); diff --git a/src/views/offers.ejs b/src/views/offers.ejs index a5f978c..3194059 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -31,14 +31,7 @@

Vaya, no hay nada por aquí...

-
- -

¡Oferta eliminada!

-
- + From 873493f697dacde785108208a120e72573ff8d85 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 16:12:33 +0200 Subject: [PATCH 28/60] use service to create offer --- src/front/pages/offers.js | 14 ++++++-------- src/front/services/offerService.js | 13 +++++++++++++ src/views/offers.ejs | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 src/front/services/offerService.js diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index b6cc7cc..3c639dd 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -10,13 +10,16 @@ const TrustCheckboxes = require('../components/TrustCheckboxes'); const BigNotesCheckbox = require('../components/BigNotesCheckbox'); const PopupNotification = require('../components/PopupNotification'); +const offerService = require('../services/offerService'); + class CreateOfferModal { // Actual creation logic to be provided by a service // Stop relying on IDs - constructor({ parentElement, onCreationCallback }) { + constructor({ parentElement, onCreationCallback, offerService }) { this.element = null; this.parentElement = parentElement; this.onCreationCallback = onCreationCallback; + this.offerService = offerService; this.publishOfferButton = null; this.buyOrSellButtonGroup = null; @@ -230,13 +233,7 @@ class CreateOfferModal { are_big_notes_accepted, }; - await fetch('/api/offer', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ offerDetails }), - }); + await this.offerService.createOffer(offerDetails); this.toggle(); } @@ -262,6 +259,7 @@ function offersPage() { await myOffers.render(); offerCreatedPopup.displayTemporarily(3000); }, + offerService: offerService, }); createOfferModal.render(); // ----------- diff --git a/src/front/services/offerService.js b/src/front/services/offerService.js new file mode 100644 index 0000000..65b1c44 --- /dev/null +++ b/src/front/services/offerService.js @@ -0,0 +1,13 @@ +const createOffer = async (offerDetails) => { + await fetch('/api/offer', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ offerDetails }), + }); +}; + +module.exports = { + createOffer, +}; diff --git a/src/views/offers.ejs b/src/views/offers.ejs index 3194059..6fa2e9f 100644 --- a/src/views/offers.ejs +++ b/src/views/offers.ejs @@ -31,7 +31,7 @@

Vaya, no hay nada por aquí...

- + From 72594c34c13e4f3a62af1396341b3b989429a216 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 16:27:21 +0200 Subject: [PATCH 29/60] don't hardcode api and web endpoints --- src/constants.js | 10 ++++++++-- src/front/pages/invite.js | 2 +- src/front/pages/login.js | 2 +- src/front/services/offerService.js | 4 +++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/constants.js b/src/constants.js index 7af448b..4274f46 100644 --- a/src/constants.js +++ b/src/constants.js @@ -2,14 +2,20 @@ const DEFAULT_SESSION_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 API_ROOT = '/api' const API_PATHS = { - createProfile: '/createProfile', - home: '/home', + offer: API_ROOT + '/offer' }; +const WEB_PATHS = { + home: '/home', + createProfile: '/createProfile', +} + module.exports = { DEFAULT_SESSION_DURATION_SECONDS, DEFAULT_NOSTR_CHALLENGE_DURATION_SECONDS, API_PATHS, + WEB_PATHS, DEFAULT_REDIRECT_DELAY, }; diff --git a/src/front/pages/invite.js b/src/front/pages/invite.js index 24bc3b5..d756ca3 100644 --- a/src/front/pages/invite.js +++ b/src/front/pages/invite.js @@ -24,7 +24,7 @@ const invitesFunction = () => { if (verifyResponse.ok) { signUpSuccessPopup.display(); setTimeout(() => { - window.location.href = constants.API_PATHS.createProfile; + window.location.href = constants.WEB_PATHS.createProfile; }, constants.DEFAULT_REDIRECT_DELAY); } }, diff --git a/src/front/pages/login.js b/src/front/pages/login.js index 5620a99..4b304e2 100644 --- a/src/front/pages/login.js +++ b/src/front/pages/login.js @@ -38,7 +38,7 @@ const loginFunction = () => { nostrLoginButton.disable(); successPopup.display(); setTimeout(() => { - window.location.href = constants.API_PATHS.home; + window.location.href = constants.WEB_PATHS.home; }, constants.DEFAULT_REDIRECT_DELAY); } }, diff --git a/src/front/services/offerService.js b/src/front/services/offerService.js index 65b1c44..7b5151c 100644 --- a/src/front/services/offerService.js +++ b/src/front/services/offerService.js @@ -1,5 +1,7 @@ +const constants = require('../../constants'); + const createOffer = async (offerDetails) => { - await fetch('/api/offer', { + await fetch(constants.API_PATHS.offer, { method: 'POST', headers: { 'Content-Type': 'application/json', From 14ee0b41274833b49dc2070cf68aa21bb59f1ecf Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 16:38:48 +0200 Subject: [PATCH 30/60] more no-hardcoded-paths --- src/constants.js | 6 +++++- src/front/services/inviteService.js | 6 ++++-- src/front/services/loginService.js | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/constants.js b/src/constants.js index 4274f46..323ce6d 100644 --- a/src/constants.js +++ b/src/constants.js @@ -4,7 +4,11 @@ const DEFAULT_REDIRECT_DELAY = 3 * 1000; // 3seconds times milliseconds; const API_ROOT = '/api' const API_PATHS = { - offer: API_ROOT + '/offer' + 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 = { diff --git a/src/front/services/inviteService.js b/src/front/services/inviteService.js index d494c6c..590913e 100644 --- a/src/front/services/inviteService.js +++ b/src/front/services/inviteService.js @@ -1,7 +1,9 @@ +const constants = require('../../constants'); + const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => { let challengeResponse; try { - challengeResponse = await fetch('/api/signup/nostr-challenge', { + challengeResponse = await fetch(constants.API_PATHS.signupNostrChallenge, { method: 'GET', headers: { 'Content-Type': 'application/json', @@ -39,7 +41,7 @@ const requestAndRespondSignUpChallenge = async ({ onNostrErrorCallback }) => { let verifyResponse; try { - verifyResponse = await fetch('/api/signup/nostr-verify', { + verifyResponse = await fetch(constants.API_PATHS.signupNostrVerify, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(signedEvent), diff --git a/src/front/services/loginService.js b/src/front/services/loginService.js index d1f5815..e97196a 100644 --- a/src/front/services/loginService.js +++ b/src/front/services/loginService.js @@ -1,3 +1,5 @@ +const constants = require('../../constants'); + const requestAndRespondLoginChallenge = async ({ onRejectedPubKeyCallback, onRejectedSignatureCallback, From 67c33aee3efb8308ced9a32260742d0f906106fd Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 16:50:11 +0200 Subject: [PATCH 31/60] submit button de-id-d --- public/css/offers.css | 2 +- src/front/pages/offers.js | 27 ++++++++++++--------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 17ac4b5..54ecefa 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -377,7 +377,7 @@ width: 2em; } -#submit-button-area { +.submit-button-area { margin-top: 1em; margin-bottom: 1em; } diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 3c639dd..6cc7221 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -12,9 +12,7 @@ const PopupNotification = require('../components/PopupNotification'); const offerService = require('../services/offerService'); -class CreateOfferModal { - // Actual creation logic to be provided by a service - // Stop relying on IDs +class CreateOfferModal { // Stop relying on IDs constructor({ parentElement, onCreationCallback, offerService }) { this.element = null; this.parentElement = parentElement; @@ -98,7 +96,17 @@ class CreateOfferModal { }); const submitButtonArea = document.createElement('div'); - submitButtonArea.id = 'submit-button-area'; + submitButtonArea.classList.add('submit-button-area') + this.publishOfferButton = new PublishOfferButton({ + parentElement: submitButtonArea, + id: 'button-submit-offer', + onClickCallback: async () => { + await this.createOffer(); + await this.onCreationCallback(); + await this.toggleOfferCreatedAlert(); + }, + }); + this.publishOfferButton.render(); const closeButtonArea = document.createElement('div'); closeButtonArea.id = 'close-offer-controls-area'; @@ -122,17 +130,6 @@ class CreateOfferModal { return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); }; - this.publishOfferButton = new PublishOfferButton({ - parentElement: document.getElementById('submit-button-area'), - id: 'button-submit-offer', - onClickCallback: async () => { - await this.createOffer(); - await this.onCreationCallback(); - await this.toggleOfferCreatedAlert(); - }, - }); - this.publishOfferButton.render(); - this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({ parentElement: document.getElementById('buy-or-sell-area'), id: 'button-group-buy-or-sell', From c90e89cb0cf21c2b1596e515d11938141c8005ad Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 17:13:03 +0200 Subject: [PATCH 32/60] unfold loop --- src/constants.js | 6 +- src/front/pages/offers.js | 116 ++++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src/constants.js b/src/constants.js index 323ce6d..a454e1b 100644 --- a/src/constants.js +++ b/src/constants.js @@ -2,19 +2,19 @@ const DEFAULT_SESSION_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 API_ROOT = '/api' +const API_ROOT = '/api'; const API_PATHS = { 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' + signupNostrVerify: API_ROOT + '/signup/nostr-verify', }; const WEB_PATHS = { home: '/home', createProfile: '/createProfile', -} +}; module.exports = { DEFAULT_SESSION_DURATION_SECONDS, diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 6cc7221..34d173c 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -12,7 +12,8 @@ const PopupNotification = require('../components/PopupNotification'); const offerService = require('../services/offerService'); -class CreateOfferModal { // Stop relying on IDs +class CreateOfferModal { + // Stop relying on IDs constructor({ parentElement, onCreationCallback, offerService }) { this.element = null; this.parentElement = parentElement; @@ -45,58 +46,75 @@ class CreateOfferModal { // Stop relying on IDs const title = document.createElement('h2'); title.textContent = 'Añade los detalles de tu oferta'; - - const sections = [ - { id: 'buy-or-sell-area', class: 'create-offer-step', title: '' }, - { - id: 'premium-area', - class: 'create-offer-step', - title: 'Premium', - contentId: 'premium-content-area', - }, - { id: 'amount-area', class: 'create-offer-step', title: '¿Cuánto?' }, - { - id: 'place-and-time-area', - class: 'create-offer-step', - title: '¿Dónde y cuándo?', - contentId: 'place-and-time-boxes', - }, - { - id: 'bitcoin-methods-area', - class: 'create-offer-step', - title: '¿Cómo se mueve el Bitcoin?', - contentId: 'bitcoin-methods-checkboxes', - }, - { - id: 'trust-area', - class: 'create-offer-step', - title: '¿Quién puede ver la oferta?', - contentId: 'trusted-checkboxes-area', - }, - { id: 'other-area', class: 'create-offer-step', title: 'Extras' }, - ]; - controls.appendChild(title); - sections.forEach((section) => { - const div = document.createElement('div'); - div.id = section.id; - div.className = section.class; - if (section.title) { - const heading = document.createElement('h3'); - heading.textContent = section.title; - div.appendChild(heading); - } - if (section.contentId) { - const contentDiv = document.createElement('div'); - contentDiv.id = section.contentId; - div.appendChild(contentDiv); - } - controls.appendChild(div); - }); + const buyOrSellDiv = document.createElement('div'); + buyOrSellDiv.id = 'buy-or-sell-area'; + buyOrSellDiv.className = 'create-offer-step'; + controls.appendChild(buyOrSellDiv); + + const premiumDiv = document.createElement('div'); + premiumDiv.id = 'premium-area'; + premiumDiv.className = 'create-offer-step'; + const premiumHeading = document.createElement('h3'); + premiumHeading.textContent = 'Premium'; + premiumDiv.appendChild(premiumHeading); + const premiumContentDiv = document.createElement('div'); + premiumContentDiv.id = 'premium-content-area'; + premiumDiv.appendChild(premiumContentDiv); + controls.appendChild(premiumDiv); + + const amountDiv = document.createElement('div'); + amountDiv.id = 'amount-area'; + amountDiv.className = 'create-offer-step'; + const amountHeading = document.createElement('h3'); + amountHeading.textContent = '¿Cuánto?'; + amountDiv.appendChild(amountHeading); + controls.appendChild(amountDiv); + + const placeTimeDiv = document.createElement('div'); + placeTimeDiv.id = 'place-and-time-area'; + 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'); + placeTimeContentDiv.id = 'place-and-time-boxes'; + placeTimeDiv.appendChild(placeTimeContentDiv); + controls.appendChild(placeTimeDiv); + + const bitcoinMethodsDiv = document.createElement('div'); + bitcoinMethodsDiv.id = 'bitcoin-methods-area'; + 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'); + bitcoinMethodsContentDiv.id = 'bitcoin-methods-checkboxes'; + bitcoinMethodsDiv.appendChild(bitcoinMethodsContentDiv); + controls.appendChild(bitcoinMethodsDiv); + + const trustDiv = document.createElement('div'); + trustDiv.id = 'trust-area'; + 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'); + trustContentDiv.id = 'trusted-checkboxes-area'; + trustDiv.appendChild(trustContentDiv); + controls.appendChild(trustDiv); + + const otherDiv = document.createElement('div'); + otherDiv.id = 'other-area'; + otherDiv.className = 'create-offer-step'; + const otherHeading = document.createElement('h3'); + otherHeading.textContent = 'Extras'; + otherDiv.appendChild(otherHeading); + controls.appendChild(otherDiv); const submitButtonArea = document.createElement('div'); - submitButtonArea.classList.add('submit-button-area') + submitButtonArea.classList.add('submit-button-area'); this.publishOfferButton = new PublishOfferButton({ parentElement: submitButtonArea, id: 'button-submit-offer', From 3e9c03144628d07b50787f8b18f9599ae8798501 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 17:14:48 +0200 Subject: [PATCH 33/60] move button group --- src/front/pages/offers.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 34d173c..c3fcff7 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -51,6 +51,10 @@ class CreateOfferModal { const buyOrSellDiv = document.createElement('div'); buyOrSellDiv.id = 'buy-or-sell-area'; buyOrSellDiv.className = 'create-offer-step'; + this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({ + parentElement: buyOrSellDiv, + }); + this.buyOrSellButtonGroup.render(); controls.appendChild(buyOrSellDiv); const premiumDiv = document.createElement('div'); @@ -148,12 +152,6 @@ class CreateOfferModal { return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); }; - this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({ - parentElement: document.getElementById('buy-or-sell-area'), - id: 'button-group-buy-or-sell', - }); - this.buyOrSellButtonGroup.render(); - this.premiumSelector = new PremiumSelector({ parentElement: document.getElementById('premium-content-area'), id: 'premium-selector-area', From 8449b74dc77276ad3907506239160f652d52b5c0 Mon Sep 17 00:00:00 2001 From: Pablo Martin Date: Mon, 31 Mar 2025 17:15:35 +0200 Subject: [PATCH 34/60] anchor --- src/front/pages/offers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index c3fcff7..45686ed 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -57,6 +57,8 @@ class CreateOfferModal { this.buyOrSellButtonGroup.render(); controls.appendChild(buyOrSellDiv); + breaks(); + //Continue moving components up here const premiumDiv = document.createElement('div'); premiumDiv.id = 'premium-area'; premiumDiv.className = 'create-offer-step'; From 82778b91ca9588ec6c74c801c5f3741f834d7a42 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 12:41:28 +0200 Subject: [PATCH 35/60] move premium selector --- public/css/offers.css | 6 +-- src/front/components/PremiumSelector.js | 1 + src/front/pages/offers.js | 54 ++++++++++++------------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 54ecefa..a0d9705 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -11,7 +11,7 @@ max-width: 30%; } - #premium-selector-area { + .premium-selector-area { width: 80px; } @@ -50,7 +50,7 @@ width: 50px; } - #premium-selector-area { + .premium-selector-area { width: 100px; } @@ -261,7 +261,7 @@ display: flex; } -#premium-selector-area { +.premium-selector-area { margin-left: auto; margin-right: 5%; display: flex; diff --git a/src/front/components/PremiumSelector.js b/src/front/components/PremiumSelector.js index d2defdd..a1b1f4e 100644 --- a/src/front/components/PremiumSelector.js +++ b/src/front/components/PremiumSelector.js @@ -11,6 +11,7 @@ class PremiumSelector { render() { const premiumSelectorArea = document.createElement('div'); premiumSelectorArea.id = this.id; + premiumSelectorArea.classList = 'premium-selector-area'; const premiumValue = document.createElement('div'); premiumValue.id = 'premium-value'; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 45686ed..fd73a64 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -57,8 +57,6 @@ class CreateOfferModal { this.buyOrSellButtonGroup.render(); controls.appendChild(buyOrSellDiv); - breaks(); - //Continue moving components up here const premiumDiv = document.createElement('div'); premiumDiv.id = 'premium-area'; premiumDiv.className = 'create-offer-step'; @@ -70,6 +68,32 @@ class CreateOfferModal { 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(); + }); + + //Continue moving components up here const amountDiv = document.createElement('div'); amountDiv.id = 'amount-area'; amountDiv.className = 'create-offer-step'; @@ -148,32 +172,6 @@ class CreateOfferModal { this.parentElement.appendChild(this.element); - const createOfferEventBus = new EventTarget(); - - const mockPriceProvidingCallback = () => { - return Math.floor(Math.random() * (95000 - 70000 + 1) + 70000); - }; - - this.premiumSelector = new PremiumSelector({ - parentElement: document.getElementById('premium-content-area'), - id: 'premium-selector-area', - eventSink: createOfferEventBus, - }); - this.premiumSelector.render(); - - const priceDisplay = new PriceDisplay({ - parentElement: document.getElementById('premium-content-area'), - id: 'premium-price-display-area', - premiumProvidingCallback: () => { - return this.premiumSelector.getPremium(); - }, - priceProvidingCallback: mockPriceProvidingCallback, - }); - priceDisplay.render(); - createOfferEventBus.addEventListener('premium-changed', () => { - priceDisplay.updatePrices(); - }); - this.amountInput = new AmountInput({ parentElement: document.getElementById('amount-area'), id: 'amount-area-content', From 6193817cb87f0039b939e6832f97e16817ad47cb Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 12:44:02 +0200 Subject: [PATCH 36/60] id to class style --- public/css/offers.css | 4 ++-- src/front/components/PriceDisplay.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index a0d9705..f498978 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -297,14 +297,14 @@ border-bottom-right-radius: 10px; } -#premium-price-display-area { +.premium-price-display-area { margin-left: 0; margin-right: auto; font-size: 1em; text-align: start; } -#premium-price-display-area > * { +.premium-price-display-area > * { margin-top: 0; margin-bottom: 0; } diff --git a/src/front/components/PriceDisplay.js b/src/front/components/PriceDisplay.js index 39eb16d..9d2dd02 100644 --- a/src/front/components/PriceDisplay.js +++ b/src/front/components/PriceDisplay.js @@ -16,7 +16,8 @@ class PriceDisplay { render() { 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'); offerParagraph.id = 'offer-price-paragraph'; From 5e3f2aaaad5df87d437e759d7eb2bed7ab5eee46 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 12:46:18 +0200 Subject: [PATCH 37/60] remove bloaty ids --- src/front/components/PriceDisplay.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/front/components/PriceDisplay.js b/src/front/components/PriceDisplay.js index 9d2dd02..be3055d 100644 --- a/src/front/components/PriceDisplay.js +++ b/src/front/components/PriceDisplay.js @@ -20,7 +20,6 @@ class PriceDisplay { container.classList = 'premium-price-display-area'; const offerParagraph = document.createElement('p'); - offerParagraph.id = 'offer-price-paragraph'; offerParagraph.textContent = 'Tu precio: '; const offerSpan = document.createElement('span'); @@ -31,11 +30,9 @@ class PriceDisplay { offerParagraph.append('€/BTC'); const marketParagraph = document.createElement('p'); - marketParagraph.id = 'market-price-paragraph'; marketParagraph.textContent = '(Precio mercado: '; const marketSpan = document.createElement('span'); - marketSpan.id = 'market-price'; this.marketPriceSpan = marketSpan; marketParagraph.appendChild(marketSpan); From d48a4f062d960c4da97cc6f125a7e7946bc5713c Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 12:51:42 +0200 Subject: [PATCH 38/60] change id styling to class --- public/css/offers.css | 8 ++++---- src/front/components/PremiumSelector.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index f498978..5d4f833 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -267,13 +267,13 @@ display: flex; } -#premium-value { +.premium-value { border: 1px solid gray; width: 50%; align-content: center; } -#premium-buttons-container { +.premium-buttons-container { width: 50%; } @@ -289,11 +289,11 @@ background: #fff8ce; } -#button-increase-premium { +.button-increase-premium { border-top-right-radius: 10px; } -#button-decrease-premium { +.button-decrease-premium { border-bottom-right-radius: 10px; } diff --git a/src/front/components/PremiumSelector.js b/src/front/components/PremiumSelector.js index a1b1f4e..68f994d 100644 --- a/src/front/components/PremiumSelector.js +++ b/src/front/components/PremiumSelector.js @@ -14,7 +14,7 @@ class PremiumSelector { premiumSelectorArea.classList = 'premium-selector-area'; const premiumValue = document.createElement('div'); - premiumValue.id = 'premium-value'; + premiumValue.className = 'premium-value'; premiumValue.textContent = '0%'; this.premiumValue = premiumValue; @@ -23,12 +23,12 @@ class PremiumSelector { const increaseButton = document.createElement('button'); increaseButton.classList.add('premium-button'); - increaseButton.id = 'button-increase-premium'; + increaseButton.classList.add('button-increase-premium'); increaseButton.textContent = '+'; const decreaseButton = document.createElement('button'); decreaseButton.classList.add('premium-button'); - decreaseButton.id = 'button-decrease-premium'; + decreaseButton.classList.add('button-decrease-premium'); decreaseButton.textContent = '-'; premiumButtonsContainer.appendChild(increaseButton); From e61a67c14fad1a58c849b8cd4c339b8c0834d855 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 12:52:57 +0200 Subject: [PATCH 39/60] id style to class --- public/css/offers.css | 4 ++-- src/front/pages/offers.js | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 5d4f833..4d62410 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -248,11 +248,11 @@ justify-content: end; } -#premium-area > * { +.premium-area > * { display: block; } -#premium-content-area { +.premium-content-area { width: 80%; height: 50px; align-items: center; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index fd73a64..6371340 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -49,7 +49,6 @@ class CreateOfferModal { controls.appendChild(title); const buyOrSellDiv = document.createElement('div'); - buyOrSellDiv.id = 'buy-or-sell-area'; buyOrSellDiv.className = 'create-offer-step'; this.buyOrSellButtonGroup = new BuyOrSellButtonGroup({ parentElement: buyOrSellDiv, @@ -58,13 +57,13 @@ class CreateOfferModal { controls.appendChild(buyOrSellDiv); const premiumDiv = document.createElement('div'); - premiumDiv.id = 'premium-area'; + 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.id = 'premium-content-area'; + premiumContentDiv.classList = 'premium-content-area'; premiumDiv.appendChild(premiumContentDiv); controls.appendChild(premiumDiv); From 2ee89a24128f0255e4a613cc020180f7a730efba Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 13:00:25 +0200 Subject: [PATCH 40/60] refactor styles, remove ids --- public/css/offers.css | 6 +++--- src/front/components/AmountInput.js | 9 +-------- src/front/pages/offers.js | 12 ++++++------ 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 4d62410..6942f0a 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -15,7 +15,7 @@ width: 80px; } - #amount-area-content { + .amount-area-content { width: 50%; } @@ -54,7 +54,7 @@ width: 100px; } - #amount-area-content { + .amount-area-content { width: 33%; } @@ -314,7 +314,7 @@ font-size: 0.8em; } -#amount-area-content { +.amount-area-content { margin-left: auto; margin-right: auto; } diff --git a/src/front/components/AmountInput.js b/src/front/components/AmountInput.js index 8364bca..9badd2a 100644 --- a/src/front/components/AmountInput.js +++ b/src/front/components/AmountInput.js @@ -13,24 +13,21 @@ class AmountInput { render() { const amountArea = document.createElement('div'); amountArea.id = this.id; + amountArea.className = 'amount-area-content'; const eurAmount = document.createElement('div'); - eurAmount.id = 'eur-amount'; eurAmount.className = 'money-amount-input-area'; this.eurInput = document.createElement('input'); - this.eurInput.id = 'input-eur-amount'; 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.id = 'eur-symbol'; eurSymbol.className = 'curr-symbol'; const eurCharacter = document.createElement('span'); - eurCharacter.id = 'eur-character'; eurCharacter.className = 'curr-character'; eurCharacter.textContent = '€'; @@ -39,21 +36,17 @@ class AmountInput { eurAmount.appendChild(eurSymbol); const btcAmount = document.createElement('div'); - btcAmount.id = 'btc-amount'; btcAmount.className = 'money-amount-input-area'; this.btcInput = document.createElement('input'); - this.btcInput.id = 'input-btc-amount'; this.btcInput.type = 'text'; this.btcInput.className = 'money-input input-money-amount'; this.btcInput.disabled = true; const satsSymbol = document.createElement('div'); - satsSymbol.id = 'sats-symbol'; satsSymbol.className = 'curr-symbol'; const satsCharacter = document.createElement('span'); - satsCharacter.id = 'sats-character'; satsCharacter.className = 'curr-character'; satsCharacter.textContent = 'SAT'; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 6371340..946c72f 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -92,7 +92,6 @@ class CreateOfferModal { priceDisplay.updatePrices(); }); - //Continue moving components up here const amountDiv = document.createElement('div'); amountDiv.id = 'amount-area'; amountDiv.className = 'create-offer-step'; @@ -101,6 +100,12 @@ class CreateOfferModal { amountDiv.appendChild(amountHeading); controls.appendChild(amountDiv); + this.amountInput = new AmountInput({ + parentElement: amountDiv, + }); + + //Continue moving components up here + const placeTimeDiv = document.createElement('div'); placeTimeDiv.id = 'place-and-time-area'; placeTimeDiv.className = 'create-offer-step'; @@ -171,11 +176,6 @@ class CreateOfferModal { this.parentElement.appendChild(this.element); - this.amountInput = new AmountInput({ - parentElement: document.getElementById('amount-area'), - id: 'amount-area-content', - }); - this.amountInput.render(); this.placeInput = new PlaceInput({ From 234b2dfdaff9169b80f480ef4850309d3191ba7c Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 13:07:02 +0200 Subject: [PATCH 41/60] move up, remove ids --- src/front/pages/offers.js | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 946c72f..01b96f4 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -104,19 +104,31 @@ class CreateOfferModal { parentElement: amountDiv, }); - //Continue moving components up here + this.amountInput.render(); const placeTimeDiv = document.createElement('div'); - placeTimeDiv.id = 'place-and-time-area'; 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'); - placeTimeContentDiv.id = 'place-and-time-boxes'; placeTimeDiv.appendChild(placeTimeContentDiv); controls.appendChild(placeTimeDiv); + this.placeInput = new PlaceInput({ + parentElement: placeTimeContentDiv, + }); + + this.placeInput.render(); + + this.timeInput = new TimeInput({ + parentElement: placeTimeContentDiv, + }); + + this.timeInput.render(); + + //Continue moving components up here + const bitcoinMethodsDiv = document.createElement('div'); bitcoinMethodsDiv.id = 'bitcoin-methods-area'; bitcoinMethodsDiv.className = 'create-offer-step'; @@ -176,22 +188,6 @@ class CreateOfferModal { this.parentElement.appendChild(this.element); - this.amountInput.render(); - - this.placeInput = new PlaceInput({ - parentElement: document.getElementById('place-and-time-boxes'), - id: 'place-input', - }); - - this.placeInput.render(); - - this.timeInput = new TimeInput({ - parentElement: document.getElementById('place-and-time-boxes'), - id: 'time-input', - }); - - this.timeInput.render(); - this.btcMethodCheckboxes = new BitcoinMethodCheckboxes({ parentElement: document.getElementById('bitcoin-methods-checkboxes'), }); From f846a7b06c847fecd548742b9b3a3554a706f1da Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 13:17:21 +0200 Subject: [PATCH 42/60] mvoe up remove ids --- src/front/pages/offers.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 01b96f4..42475c6 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -127,19 +127,23 @@ class CreateOfferModal { this.timeInput.render(); - //Continue moving components up here - const bitcoinMethodsDiv = document.createElement('div'); - bitcoinMethodsDiv.id = 'bitcoin-methods-area'; 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'); - bitcoinMethodsContentDiv.id = 'bitcoin-methods-checkboxes'; bitcoinMethodsDiv.appendChild(bitcoinMethodsContentDiv); controls.appendChild(bitcoinMethodsDiv); + this.btcMethodCheckboxes = new BitcoinMethodCheckboxes({ + parentElement: bitcoinMethodsContentDiv, + }); + + this.btcMethodCheckboxes.render(); + + //Continue moving components up here + const trustDiv = document.createElement('div'); trustDiv.id = 'trust-area'; trustDiv.className = 'create-offer-step'; @@ -188,12 +192,6 @@ class CreateOfferModal { this.parentElement.appendChild(this.element); - this.btcMethodCheckboxes = new BitcoinMethodCheckboxes({ - parentElement: document.getElementById('bitcoin-methods-checkboxes'), - }); - - this.btcMethodCheckboxes.render(); - this.trustCheckboxes = new TrustCheckboxes({ parentElement: document.getElementById('trusted-checkboxes-area'), }); From d49ea51720afddeb327b6b5dd8c91dd226abdc93 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 13:23:38 +0200 Subject: [PATCH 43/60] bitcoin methods tidy up --- src/front/components/BitcoinMethodCheckboxes.js | 6 +----- src/front/pages/offers.js | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/front/components/BitcoinMethodCheckboxes.js b/src/front/components/BitcoinMethodCheckboxes.js index 01c0743..27cb3f8 100644 --- a/src/front/components/BitcoinMethodCheckboxes.js +++ b/src/front/components/BitcoinMethodCheckboxes.js @@ -34,15 +34,12 @@ class BitcoinMethodCheckboxes { this.parentElement.appendChild(this.lightningContainer); } - buildCheckbox({ id, label }) { + buildCheckbox({ label }) { const checkboxContainer = document.createElement('div'); checkboxContainer.className = 'checkbox-row'; - checkboxContainer.id = `${id}-checkbox-area`; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; - checkbox.name = id; - checkbox.id = `${id}-checkbox`; checkbox.checked = true; const labelElement = document.createElement('label'); @@ -60,7 +57,6 @@ class BitcoinMethodCheckboxes { this.onchainCheckboxElement, this.lightningCheckboxElement, ].filter((cb) => cb.checked).length; - console.log(checkedCount); if (checkedCount === 0) { clickedCheckbox.checked = true; } diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 42475c6..c31f6f1 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -171,7 +171,6 @@ class CreateOfferModal { onClickCallback: async () => { await this.createOffer(); await this.onCreationCallback(); - await this.toggleOfferCreatedAlert(); }, }); this.publishOfferButton.render(); From 51fe6cae99aa3ba060c99bfdd9c604660ae288b7 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 14:05:15 +0200 Subject: [PATCH 44/60] tidy up checkboxes --- src/front/components/TrustCheckboxes.js | 9 +-------- src/front/pages/offers.js | 18 ++++++++---------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/front/components/TrustCheckboxes.js b/src/front/components/TrustCheckboxes.js index bd47e84..f1b8768 100644 --- a/src/front/components/TrustCheckboxes.js +++ b/src/front/components/TrustCheckboxes.js @@ -12,7 +12,6 @@ class TrustCheckboxes { render() { const checkboxesDetails = [ { - id: 'my-trusted', label: 'Mis confiados', containerProperty: 'myTrustedContainer', checkboxProperty: 'myTrustedCheckboxElement', @@ -20,7 +19,6 @@ class TrustCheckboxes { isDisabled: true, }, { - id: 'my-trusted-trusted', label: 'Los confiados de mis confiados', containerProperty: 'myTrustedTrustedContainer', checkboxProperty: 'myTrustedTrustedCheckboxElement', @@ -28,7 +26,6 @@ class TrustCheckboxes { isDisabled: false, }, { - id: 'all-members', label: 'Todos los miembros', containerProperty: 'allMembersContainer', checkboxProperty: 'allMembersCheckboxElement', @@ -39,7 +36,6 @@ class TrustCheckboxes { for (const checkboxDetails of checkboxesDetails) { this[checkboxDetails.containerProperty] = this.buildCheckbox({ - id: checkboxDetails.id, label: checkboxDetails.label, }); @@ -61,15 +57,12 @@ class TrustCheckboxes { } } - buildCheckbox({ id, label }) { + buildCheckbox({ label }) { const checkboxContainer = document.createElement('div'); checkboxContainer.className = 'checkbox-row'; - checkboxContainer.id = `${id}-checkbox-area`; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; - checkbox.name = id; - checkbox.id = `${id}-checkbox`; checkbox.checked = true; const labelElement = document.createElement('label'); diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index c31f6f1..53e18e2 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -142,19 +142,23 @@ class CreateOfferModal { this.btcMethodCheckboxes.render(); - //Continue moving components up here - const trustDiv = document.createElement('div'); - trustDiv.id = 'trust-area'; 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'); - trustContentDiv.id = 'trusted-checkboxes-area'; trustDiv.appendChild(trustContentDiv); controls.appendChild(trustDiv); + this.trustCheckboxes = new TrustCheckboxes({ + parentElement: trustContentDiv, + }); + + this.trustCheckboxes.render(); + + //Continue moving components up here + const otherDiv = document.createElement('div'); otherDiv.id = 'other-area'; otherDiv.className = 'create-offer-step'; @@ -191,12 +195,6 @@ class CreateOfferModal { this.parentElement.appendChild(this.element); - this.trustCheckboxes = new TrustCheckboxes({ - parentElement: document.getElementById('trusted-checkboxes-area'), - }); - - this.trustCheckboxes.render(); - this.bigNotesCheckbox = new BigNotesCheckbox({ parentElement: document.getElementById('other-area'), }); From 81a3a3d4b2c9b9d31b2374bba44d761c53f25e59 Mon Sep 17 00:00:00 2001 From: counterweight Date: Sat, 5 Apr 2025 14:05:40 +0200 Subject: [PATCH 45/60] leave breaking anchor for future self --- src/front/pages/offers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 53e18e2..4d92e5b 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -157,6 +157,7 @@ class CreateOfferModal { this.trustCheckboxes.render(); + breaksssssss(); //Continue moving components up here const otherDiv = document.createElement('div'); From 2ca02bad80970623c6e116e166fe847a55c7b65a Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 9 Apr 2025 18:14:33 +0200 Subject: [PATCH 46/60] move up --- src/front/pages/offers.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 4d92e5b..95ccde8 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -157,9 +157,6 @@ class CreateOfferModal { this.trustCheckboxes.render(); - breaksssssss(); - //Continue moving components up here - const otherDiv = document.createElement('div'); otherDiv.id = 'other-area'; otherDiv.className = 'create-offer-step'; @@ -168,6 +165,13 @@ class CreateOfferModal { 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({ @@ -195,12 +199,6 @@ class CreateOfferModal { modalRoot.appendChild(modal); this.parentElement.appendChild(this.element); - - this.bigNotesCheckbox = new BigNotesCheckbox({ - parentElement: document.getElementById('other-area'), - }); - - this.bigNotesCheckbox.render(); } toggle() { From 971282f01fe95cde82fcd37648f0e6ecb945d946 Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 9 Apr 2025 18:16:43 +0200 Subject: [PATCH 47/60] remove ids --- src/front/components/BigNotesCheckbox.js | 1 - src/front/pages/offers.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/front/components/BigNotesCheckbox.js b/src/front/components/BigNotesCheckbox.js index 005502c..6361a72 100644 --- a/src/front/components/BigNotesCheckbox.js +++ b/src/front/components/BigNotesCheckbox.js @@ -7,7 +7,6 @@ class BigNotesCheckbox { render() { const container = document.createElement('div'); - container.id = 'large-bills-area'; container.className = 'checkbox-row'; const checkbox = document.createElement('input'); diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 95ccde8..bb0b8ed 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -158,7 +158,6 @@ class CreateOfferModal { this.trustCheckboxes.render(); const otherDiv = document.createElement('div'); - otherDiv.id = 'other-area'; otherDiv.className = 'create-offer-step'; const otherHeading = document.createElement('h3'); otherHeading.textContent = 'Extras'; From 1e02957bdca18b7a300d3f06625662e66efb59da Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 9 Apr 2025 18:17:40 +0200 Subject: [PATCH 48/60] class-ify some id-fied styles --- public/css/offers.css | 4 ++-- src/front/pages/offers.js | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 6942f0a..4d10d6e 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -243,7 +243,7 @@ margin-top: 0; } -#close-offer-controls-area { +.close-offer-controls-area { display: flex; justify-content: end; } @@ -386,7 +386,7 @@ width: 33%; } -#close-offer { +.close-offer { margin-left: auto; margin-right: auto; } diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index bb0b8ed..3eba71d 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -184,10 +184,9 @@ class CreateOfferModal { this.publishOfferButton.render(); const closeButtonArea = document.createElement('div'); - closeButtonArea.id = 'close-offer-controls-area'; + closeButtonArea.className = 'close-offer-controls-area'; const closeButton = document.createElement('button'); - closeButton.id = 'close-offer'; - closeButton.className = 'button-secondary button-medium'; + closeButton.className = 'close-offer button-secondary button-medium'; closeButton.textContent = 'Volver'; closeButtonArea.appendChild(closeButton); From fa0b56d2a6bcf2e6303f520b4006ab5d47bcd49a Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 10 Apr 2025 08:44:04 +0200 Subject: [PATCH 49/60] close button works --- src/front/components/CloseModalButton.js | 21 +++++++++++++++++ src/front/pages/offers.js | 30 +++++++++--------------- 2 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 src/front/components/CloseModalButton.js diff --git a/src/front/components/CloseModalButton.js b/src/front/components/CloseModalButton.js new file mode 100644 index 0000000..b857ea5 --- /dev/null +++ b/src/front/components/CloseModalButton.js @@ -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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 3eba71d..b7dcd2d 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -8,6 +8,7 @@ const TimeInput = require('../components/TimeInput'); const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); const TrustCheckboxes = require('../components/TrustCheckboxes'); const BigNotesCheckbox = require('../components/BigNotesCheckbox'); +const CloseModalButton = require('../components/CloseModalButton'); const PopupNotification = require('../components/PopupNotification'); const offerService = require('../services/offerService'); @@ -179,16 +180,21 @@ class CreateOfferModal { 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 = document.createElement('button'); - closeButton.className = 'close-offer button-secondary button-medium'; - closeButton.textContent = 'Volver'; - closeButtonArea.appendChild(closeButton); + const closeButton = new CloseModalButton({ + parentElement: closeButtonArea, + onClickCallback: () => { + this.toggle(); + }, + }); + + closeButton.render(); controls.appendChild(submitButtonArea); controls.appendChild(closeButtonArea); @@ -234,8 +240,6 @@ class CreateOfferModal { }; await this.offerService.createOffer(offerDetails); - - this.toggle(); } } @@ -278,18 +282,10 @@ function offersPage() { 'button-start-create-offer' ); 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 ownOffersContainer = document.getElementById('own-offers-container'); - function toggleCreateOfferModal() { - createOfferModalRoot.classList.toggle('shown'); - } - function toggleViewMyOffersPanel() { viewMyOffersRoot.style.display = viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; @@ -714,7 +710,7 @@ function offersPage() { } buttonStartCreateOffer.addEventListener('click', () => { - toggleCreateOfferModal(); + createOfferModal.toggle(); }); buttonViewMyOffers.addEventListener('click', async () => { @@ -723,10 +719,6 @@ function offersPage() { toggleViewMyOffersPanel(); }); - closeOffer.addEventListener('click', () => { - toggleCreateOfferModal(); - }); - const myOffers = new MyOffers(ownOffersContainer); } From d836c67c5886da26573615677a38db4756adc0e1 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 10 Apr 2025 08:56:49 +0200 Subject: [PATCH 50/60] less ids --- public/css/offers.css | 2 +- src/front/pages/offers.js | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 4d10d6e..577cc52 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -221,7 +221,7 @@ font-size: 0.9em; } -#create-offer-controls { +.create-offer-controls { text-align: center; overflow-y: auto; max-height: 800px; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index b7dcd2d..971722a 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -14,7 +14,6 @@ const PopupNotification = require('../components/PopupNotification'); const offerService = require('../services/offerService'); class CreateOfferModal { - // Stop relying on IDs constructor({ parentElement, onCreationCallback, offerService }) { this.element = null; this.parentElement = parentElement; @@ -35,15 +34,13 @@ class CreateOfferModal { render() { const modalRoot = document.createElement('div'); this.element = modalRoot; - modalRoot.id = 'create-offer-modal-root'; modalRoot.className = 'full-screen-modal-background'; const modal = document.createElement('div'); modal.className = 'full-screen-modal'; - modal.id = 'create-offer-root'; const controls = document.createElement('div'); - controls.id = 'create-offer-controls'; + controls.className = 'create-offer-controls'; const title = document.createElement('h2'); title.textContent = 'Añade los detalles de tu oferta'; @@ -94,7 +91,6 @@ class CreateOfferModal { }); const amountDiv = document.createElement('div'); - amountDiv.id = 'amount-area'; amountDiv.className = 'create-offer-step'; const amountHeading = document.createElement('h3'); amountHeading.textContent = '¿Cuánto?'; @@ -334,7 +330,6 @@ function offersPage() { 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); From 1bd4aa40e639ac89812c14c216273594946677b0 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 10 Apr 2025 08:58:51 +0200 Subject: [PATCH 51/60] move to component file --- src/front/components/CreateOfferModal.js | 239 +++++++++++++++++++++++ src/front/pages/offers.js | 238 +--------------------- 2 files changed, 240 insertions(+), 237 deletions(-) create mode 100644 src/front/components/CreateOfferModal.js diff --git a/src/front/components/CreateOfferModal.js b/src/front/components/CreateOfferModal.js new file mode 100644 index 0000000..b5301d1 --- /dev/null +++ b/src/front/components/CreateOfferModal.js @@ -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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 971722a..a88e96b 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -1,244 +1,8 @@ -const PublishOfferButton = require('../components/PublishOfferButton'); -const BuyOrSellButtonGroup = require('../components/BuyOrSellButtonGroup'); -const PremiumSelector = require('../components/PremiumSelector'); -const PriceDisplay = require('../components/PriceDisplay'); -const AmountInput = require('../components/AmountInput'); -const PlaceInput = require('../components/PlaceInput'); -const TimeInput = require('../components/TimeInput'); -const BitcoinMethodCheckboxes = require('../components/BitcoinMethodCheckboxes'); -const TrustCheckboxes = require('../components/TrustCheckboxes'); -const BigNotesCheckbox = require('../components/BigNotesCheckbox'); -const CloseModalButton = require('../components/CloseModalButton'); const PopupNotification = require('../components/PopupNotification'); +const CreateOfferModal = require('../components/CreateOfferModal'); const offerService = require('../services/offerService'); -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); - } -} - function offersPage() { const offerCreatedPopup = new PopupNotification({ parentElement: document.body, From 042bb43d9ce745531deed9438f42efc216e2afee Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 16 Apr 2025 16:38:10 +0200 Subject: [PATCH 52/60] fix some css for small screen --- public/css/offers.css | 2 -- public/css/seca.css | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/css/offers.css b/public/css/offers.css index 577cc52..6a4e706 100644 --- a/public/css/offers.css +++ b/public/css/offers.css @@ -223,8 +223,6 @@ .create-offer-controls { text-align: center; - overflow-y: auto; - max-height: 800px; padding: 20px; } diff --git a/public/css/seca.css b/public/css/seca.css index 1cc3034..35b6217 100644 --- a/public/css/seca.css +++ b/public/css/seca.css @@ -141,6 +141,8 @@ h1 { padding: 10px; width: fit-content; max-width: 95%; + max-height: 90vh; + overflow: auto; margin: 20px auto; } From 371204785d77554498f28768a0cd7e068badec1c Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 16 Apr 2025 16:41:39 +0200 Subject: [PATCH 53/60] refactor Offer to OfferCard --- src/front/pages/offers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index a88e96b..de827b2 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -50,7 +50,7 @@ function offersPage() { viewMyOffersRoot.style.display = viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - class Offer { + class OfferCard { constructor(offerData) { this.uuid = offerData.uuid; this.public_key = offerData.public_key; @@ -440,7 +440,7 @@ function offersPage() { const offersData = (await offersResponse.json()).data; if (offersResponse.ok) { for (const record of offersData) { - this.offers.push(new Offer(record)); + this.offers.push(new OfferCard(record)); } } } From 2da553f4d6cf540403ad386c743d5648d6844552 Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 16 Apr 2025 16:56:02 +0200 Subject: [PATCH 54/60] some opportunistic refactors --- src/front/services/loginService.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/front/services/loginService.js b/src/front/services/loginService.js index e97196a..852b438 100644 --- a/src/front/services/loginService.js +++ b/src/front/services/loginService.js @@ -4,14 +4,9 @@ const requestAndRespondLoginChallenge = async ({ onRejectedPubKeyCallback, onRejectedSignatureCallback, }) => { - onRejectedPubKeyCallback = () => { - document.querySelector('#rejected-nostr-nudges').style.display = 'block'; - }; - onRejectedSignatureCallback = onRejectedPubKeyCallback; - let challengeResponse; try { - challengeResponse = await fetch('/api/login/nostr-challenge', { + challengeResponse = await fetch(constants.API_PATHS.loginNostrChallenge, { method: 'GET', headers: { 'Content-Type': 'application/json', @@ -49,7 +44,7 @@ const requestAndRespondLoginChallenge = async ({ let verifyResponse; try { - verifyResponse = await fetch('/api/login/nostr-verify', { + verifyResponse = await fetch(constants.API_PATHS.loginNostrVerify, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(signedEvent), From 6ac1f96ee38c3ee1376359aa2d7a6d87d2110348 Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 16 Apr 2025 16:56:10 +0200 Subject: [PATCH 55/60] extract offercard component --- src/front/components/OfferCard.js | 374 ++++++++++++++++++++++++++++ src/front/pages/offers.js | 388 +----------------------------- 2 files changed, 386 insertions(+), 376 deletions(-) create mode 100644 src/front/components/OfferCard.js diff --git a/src/front/components/OfferCard.js b/src/front/components/OfferCard.js new file mode 100644 index 0000000..5c11452 --- /dev/null +++ b/src/front/components/OfferCard.js @@ -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; diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index de827b2..04ebc55 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -1,5 +1,6 @@ const PopupNotification = require('../components/PopupNotification'); const CreateOfferModal = require('../components/CreateOfferModal'); +const OfferCard = require('../components/OfferCard'); const offerService = require('../services/offerService'); @@ -50,381 +51,6 @@ function offersPage() { viewMyOffersRoot.style.display = viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } - class OfferCard { - 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.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(); - offerDeletedPopup.displayTemporarily(3000); - }); - - actionButtonsArea.append(editActionArea, deleteActionArea); - - offerCard.append( - tradeDescDiv, - premiumDescDiv, - whereDescDiv, - whenDescDiv, - bitcoinMethodsDiv, - visibilityDiv, - otherOfferFeaturesDiv, - actionButtonsArea - ); - - return offerCard; - } - } class MyOffers { constructor(ownOffersContainerElement) { @@ -440,7 +66,17 @@ function offersPage() { const offersData = (await offersResponse.json()).data; if (offersResponse.ok) { for (const record of offersData) { - this.offers.push(new OfferCard(record)); + this.offers.push( + new OfferCard({ + offerData: record, + deleteButtonCallback: async () => { + await deleteOfferByUuid(record.uuid); + await this.getOffersFromApi(); + await this.render(); + offerDeletedPopup.displayTemporarily(3000); + }, + }) + ); } } } From 2aa61f46dbda1523e53bac4c7cf947a1cbea3d8c Mon Sep 17 00:00:00 2001 From: counterweight Date: Wed, 16 Apr 2025 19:44:22 +0200 Subject: [PATCH 56/60] transfer delete offer to service --- src/front/pages/offers.js | 11 +---------- src/front/services/offerService.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/front/pages/offers.js b/src/front/pages/offers.js index 04ebc55..01c6ab3 100644 --- a/src/front/pages/offers.js +++ b/src/front/pages/offers.js @@ -70,7 +70,7 @@ function offersPage() { new OfferCard({ offerData: record, deleteButtonCallback: async () => { - await deleteOfferByUuid(record.uuid); + await offerService.deleteOffer(record.uuid); await this.getOffersFromApi(); await this.render(); offerDeletedPopup.displayTemporarily(3000); @@ -95,15 +95,6 @@ function offersPage() { } } - async function deleteOfferByUuid(offerUuid) { - await fetch(`/api/offer/${offerUuid}`, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - }, - }); - } - buttonStartCreateOffer.addEventListener('click', () => { createOfferModal.toggle(); }); diff --git a/src/front/services/offerService.js b/src/front/services/offerService.js index 7b5151c..591a0f0 100644 --- a/src/front/services/offerService.js +++ b/src/front/services/offerService.js @@ -10,6 +10,16 @@ const createOffer = async (offerDetails) => { }); }; +const deleteOffer = async (offerUuid) => { + await fetch(`${constants.API_PATHS.offer}/${offerUuid}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); +}; + module.exports = { createOffer, + deleteOffer, }; From 74263b1e1c4cf8590f41b46ef5b79504b70b8e92 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 28 Aug 2025 22:43:21 +0200 Subject: [PATCH 57/60] add migration command to package.json --- Dockerfile | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 10706ec..42d2c5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:latest +FROM debian:12 # Install dependencies RUN apt-get update diff --git a/package.json b/package.json index a1170cb..cd0889f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "start": "node src/app.js", "start:container": "docker compose up -d --build", "stop:container": "docker compose down", + "migrate": "npx sequelize-cli db:migrate", "build": "webpack", "watch": "webpack --watch", "cli": "node src/cli.js", From f444bd792fb6ab56dbced7d63a588bf792a29904 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 28 Aug 2025 22:45:36 +0200 Subject: [PATCH 58/60] remove tests --- package.json | 1 - tests/createOffer.spec.js | 106 ----------------------------------- tests/recorderHelper.spec.js | 27 --------- tests/test-setup.js | 72 ------------------------ 4 files changed, 206 deletions(-) delete mode 100644 tests/createOffer.spec.js delete mode 100644 tests/recorderHelper.spec.js delete mode 100644 tests/test-setup.js diff --git a/package.json b/package.json index cd0889f..2c904f5 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "build": "webpack", "watch": "webpack --watch", "cli": "node src/cli.js", - "test": "playwright test", "lint": "eslint . --fix", "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,html,ejs}\"" }, diff --git a/tests/createOffer.spec.js b/tests/createOffer.spec.js deleted file mode 100644 index 2820b3a..0000000 --- a/tests/createOffer.spec.js +++ /dev/null @@ -1,106 +0,0 @@ -const { test, expect, hardcodedSessionUuid } = require('./test-setup'); - -const SessionCreated = require('../src/models/SessionCreated'); -const SessionRelatedToPublickey = require('../src/models/SessionRelatedToPublickey'); -const NymSet = require('../src/models/NymSet'); -const ContactDetailsSet = require('../src/models/ContactDetailsSet'); -const OfferDetailsSet = require('../src/models/OfferDetailsSet'); - -test('Mock records are present', async () => { - for (const someModel of [ - SessionCreated, - SessionRelatedToPublickey, - NymSet, - ContactDetailsSet, - ]) { - expect(await someModel.findOne()).toBeTruthy(); - } -}); - -test('Hardcoded session cookie is there', async ({ context }) => { - const page = await context.newPage(); - const cookiesInPage = await page.context().cookies(); - expect(cookiesInPage).toHaveLength(1); - expect(cookiesInPage[0].name).toBe('sessionUuid'); - expect(cookiesInPage[0].value).toBe(hardcodedSessionUuid); -}); - -test('Offers is reachable', async ({ context }) => { - const page = await context.newPage(); - - await page.goto('http://localhost/offers'); - const createOfferButton = page.locator('#button-start-create-offer'); - await expect(createOfferButton).toBeVisible(); - await expect(createOfferButton).toContainText('Crear nueva oferta'); -}); - -test('Create an offer with a few options creates in DB', async ({ - context, -}) => { - const page = await context.newPage(); - await page.goto('http://localhost/offers'); - - await page.getByRole('button', { name: 'Crear nueva oferta' }).click(); - await expect(page.locator('#close-offer-controls-area')).toBeVisible(); - await page.getByRole('button', { name: 'Quiero vender Bitcoin' }).click(); - await page.getByRole('button', { name: 'Quiero comprar Bitcoin' }).click(); - await page.getByRole('button', { name: '+' }).click(); - await page.getByRole('button', { name: '+' }).click(); - await page.getByRole('button', { name: '+' }).click(); - await page.getByRole('button', { name: '-' }).click(); - await expect(page.locator('#premium-value')).toContainText('2%'); - await page.locator('#input-eur-amount').click(); - await page.locator('#input-eur-amount').press('ControlOrMeta+a'); - await page.locator('#input-eur-amount').fill('50'); - await expect(page.locator('#input-eur-amount')).toHaveValue('50'); - await page - .getByText( - 'Añade los detalles de tu oferta Quiero comprar Bitcoin Quiero vender Bitcoin' - ) - .click(); - await page - .getByRole('textbox', { name: '¿Dónde? Ej."Eixample", "La' }) - .click(); - await page - .getByRole('textbox', { name: '¿Dónde? Ej."Eixample", "La' }) - .fill('En algún lugar'); - await page - .getByRole('textbox', { name: '¿Cuándo? Ej."Cualquier hora' }) - .click(); - await page - .getByRole('textbox', { name: '¿Cuándo? Ej."Cualquier hora' }) - .fill('En algún momento'); - await page.locator('#onchain-checkbox').uncheck(); - await expect(page.locator('#onchain-checkbox')).not.toBeChecked(); - await expect(page.locator('#lightning-checkbox')).toBeChecked(); - await page.locator('#my-trusted-trusted-checkbox').uncheck(); - await page.locator('#all-members-checkbox').check(); - await page.locator('#my-trusted-trusted-checkbox').check(); - await expect(page.locator('#my-trusted-trusted-checkbox')).toBeChecked(); - await page.locator('#all-members-checkbox').uncheck(); - await expect(page.locator('#all-members-checkbox')).not.toBeChecked(); - await page.locator('#large-bills-checkbox').check(); - await expect(page.locator('#large-bills-checkbox')).toBeChecked(); - - await page.getByRole('button', { name: 'Publicar oferta' }).click(); - await expect(page.locator('#offer-created-confirmation')).toBeInViewport(); - await expect( - page.locator('#offer-created-confirmation') - ).not.toBeInViewport(); - await expect(page.locator('#close-offer-controls-area')).not.toBeVisible(); - - const createdOfferDetailsSetRecord = await OfferDetailsSet.findOne(); - expect(createdOfferDetailsSetRecord.wants).toBe('BTC'); - expect(createdOfferDetailsSetRecord.premium).toBe('0.02'); - expect(createdOfferDetailsSetRecord.trade_amount_eur).toBe(50); - expect(createdOfferDetailsSetRecord.location_details).toBe('En algún lugar'); - expect(createdOfferDetailsSetRecord.time_availability_details).toBe( - 'En algún momento' - ); - expect(createdOfferDetailsSetRecord.show_offer_to_trusted).toBe(true); - expect(createdOfferDetailsSetRecord.show_offer_to_trusted_trusted).toBe(true); - expect(createdOfferDetailsSetRecord.show_offer_to_all_members).toBe(false); - expect(createdOfferDetailsSetRecord.is_onchain_accepted).toBe(false); - expect(createdOfferDetailsSetRecord.is_lightning_accepted).toBe(true); - expect(createdOfferDetailsSetRecord.are_big_notes_accepted).toBe(true); -}); diff --git a/tests/recorderHelper.spec.js b/tests/recorderHelper.spec.js deleted file mode 100644 index 2c87c21..0000000 --- a/tests/recorderHelper.spec.js +++ /dev/null @@ -1,27 +0,0 @@ -// You can uncomment this below to open a recorder page - -/* -const { chromium } = require('playwright'); -test('Mock records are present', async () => { - const browser = await chromium.launch({ headless: false }); - const context = await browser.newContext(); - await context.addCookies([ - { - name: 'sessionUuid', - value: hardcodedSessionUuid, - domain: 'localhost', - path: '/', - expires: Math.floor( - new Date(new Date().setMonth(new Date().getMonth() + 1)).getTime() / - 1000 - ), //This monster is this day next month, turned into epoch format - httpOnly: true, - secure: false, - sameSite: 'Lax', - }, - ]); - - const page = await context.newPage(); - await page.goto('http://localhost'); -}); -*/ diff --git a/tests/test-setup.js b/tests/test-setup.js deleted file mode 100644 index 3d4b669..0000000 --- a/tests/test-setup.js +++ /dev/null @@ -1,72 +0,0 @@ -const { test, expect } = require('@playwright/test'); - -const SessionCreated = require('../src/models/SessionCreated'); -const SessionRelatedToPublickey = require('../src/models/SessionRelatedToPublickey'); -const NymSet = require('../src/models/NymSet'); -const ContactDetailsSet = require('../src/models/ContactDetailsSet'); - -const hardcodedSessionUuid = '0195423c-33d7-75f8-921b-a06e6d3cb8c5'; -const hardcodedPublicKey = - 'd3d4c49e7bdbbbf3082151add080e92f9a458d5dec993b371fe6d02cd394d57a'; - -test.beforeEach(async () => { - for (const someModel of [ - SessionCreated, - SessionRelatedToPublickey, - NymSet, - ContactDetailsSet, - ]) { - someModel.truncate(); - } - - const currentTimestamp = new Date(); - const expiryTimestamp = new Date(currentTimestamp.getTime()); - expiryTimestamp.setSeconds(expiryTimestamp.getSeconds() + 60); - await SessionCreated.create({ - uuid: hardcodedSessionUuid, - created_at: currentTimestamp.toISOString(), - expires_at: expiryTimestamp.toISOString(), - }); - - await SessionRelatedToPublickey.create({ - uuid: '0195423b-f9ae-737e-98f3-880f6563ed8a', - session_uuid: hardcodedSessionUuid, - public_key: hardcodedPublicKey, - created_at: new Date().toISOString(), - }); - - await NymSet.create({ - uuid: '01954240-ddbb-7d01-9017-efb3e500d333', - public_key: hardcodedPublicKey, - nym: 'test_nym', - created_at: new Date().toISOString(), - }); - - await ContactDetailsSet.create({ - uuid: '01954240-ddbb-7d01-9017-efb3e500d333', - public_key: hardcodedPublicKey, - encrypted_contact_details: - '+OD0/Y2IkJ99/E0KAJL/mp3kxQo4DFp1deSPnqiejlyGoeWzBiipemPVSTT/Jg/fCQbN9Pd/GJ6shxuwWECOVyB5PnMZOVJ1MPQ7I8A+63XZ0gKnSnJgry6F69f3MhEjH49JbeVJ37TbruFu/Woevo24VWz2gPXGBuyHLzeg1tyT9+7ZSygkcCrh+bchvymCoF1nNOm/UQKnwecH1wWzo8a+rNokazD1/3iey6iKmKewi+yGCgmljrB866akqBAl?iv=PAKhqTeBfYVX/muhM8xaEA==', - created_at: new Date().toISOString(), - }); -}); - -test.beforeEach(async ({ context }) => { - await context.addCookies([ - { - name: 'sessionUuid', - value: hardcodedSessionUuid, - domain: 'localhost', - path: '/', - expires: Math.floor( - new Date(new Date().setMonth(new Date().getMonth() + 1)).getTime() / - 1000 - ), //This monster is this day next month, turned into epoch format - httpOnly: true, - secure: false, - sameSite: 'Lax', - }, - ]); -}); - -module.exports = { test, expect, hardcodedSessionUuid }; From cd9c7678eeac5753d4eaad7811b0e4264e120153 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 28 Aug 2025 22:49:07 +0200 Subject: [PATCH 59/60] add AGENTS.md --- AGENTS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..fa244c9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,10 @@ +# secajs + +## Architecture + +This repository contains a webapp. It covers the full stack which consists of: +- The client side code, in `src/front/`. +- The backend service in `src/`, except for `src/front/`. +- A Postgres database. Database connections and migrations are in `src/database/`. +- Besides, there is an admin CLI, with entrypoint in `src/cli.js` and commands in `src/commands/`. + From 1a5ef88c55cdaecf2d30bf241ba9c2f33020b635 Mon Sep 17 00:00:00 2001 From: counterweight Date: Thu, 28 Aug 2025 22:57:20 +0200 Subject: [PATCH 60/60] basic tests --- package.json | 3 ++- playwright.config.js | 13 +++++++++++++ tests/basic.spec.js | 12 ++++++++++++ tests/invite.spec.js | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 playwright.config.js create mode 100644 tests/basic.spec.js create mode 100644 tests/invite.spec.js diff --git a/package.json b/package.json index 2c904f5..568a109 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "watch": "webpack --watch", "cli": "node src/cli.js", "lint": "eslint . --fix", - "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,html,ejs}\"" + "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,html,ejs}\"", + "test": "playwright test" }, "keywords": [], "author": "", diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..c7f57c8 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,13 @@ +const { defineConfig } = require('@playwright/test'); + +module.exports = defineConfig({ + testDir: './tests', + use: { + baseURL: 'http://localhost:3000', + }, + webServer: { + command: 'npm start', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/tests/basic.spec.js b/tests/basic.spec.js new file mode 100644 index 0000000..3c51e92 --- /dev/null +++ b/tests/basic.spec.js @@ -0,0 +1,12 @@ +const { test, expect } = require('@playwright/test'); + +test('app starts and public page is reachable', async ({ page }) => { + // Navigate to the root page + await page.goto('/'); + + // Check that the page loads (should redirect to login) + await expect(page).toHaveURL('/login'); + + // Verify we can see some content on the login page + await expect(page.locator('body')).toBeVisible(); +}); diff --git a/tests/invite.spec.js b/tests/invite.spec.js new file mode 100644 index 0000000..d49cde1 --- /dev/null +++ b/tests/invite.spec.js @@ -0,0 +1,36 @@ +const { test, expect } = require('@playwright/test'); +const { execSync } = require('child_process'); + +test('can create invite with CLI and access invite page', async ({ page }) => { + // Create an invite using the CLI + const inviterNpub = 'npub1test1234567890abcdefghijklmnopqrstuvwxyz'; + + try { + const output = execSync(`npm run cli createAppInvite ${inviterNpub}`, { + encoding: 'utf8', + cwd: process.cwd() + }); + + // Extract the invite UUID from the CLI output + const match = output.match(/http:\/\/localhost\/invite\/([a-f0-9-]+)/); + if (!match) { + throw new Error('Could not extract invite UUID from CLI output'); + } + + const inviteUuid = match[1]; + console.log(`Created invite with UUID: ${inviteUuid}`); + + // Navigate to the invite page + await page.goto(`/invite/${inviteUuid}`); + + // Check that the invite page loads correctly + await expect(page).toHaveTitle('Invite Details'); + await expect(page.locator('h1')).toContainText('¡Has sido invitado a la seca!'); + await expect(page.locator('#laseca-logo')).toBeVisible(); + await expect(page.locator('#nostr-signup-button')).toBeVisible(); + + } catch (error) { + console.error('Error creating invite or accessing page:', error); + throw error; + } +});