function offersPage() { const buttonStartCreateOffer = document.getElementById( '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 buyOrSellButtonGroup = document.getElementById( 'button-group-buy-or-sell' ); const buyOrSellButtons = buyOrSellButtonGroup.querySelectorAll('button'); const buyButton = document.getElementById('button-buy-bitcoin'); const sellButton = document.getElementById('button-sell-bitcoin'); const premiumValue = document.getElementById('premium-value'); const buttonIncreasePremium = document.getElementById( 'button-increase-premium' ); const buttonDecreasePremium = document.getElementById( 'button-decrease-premium' ); const eurAmountInput = document.getElementById('input-eur-amount'); const btcAmountInput = document.getElementById('input-btc-amount'); const placeInput = document.getElementById('place-input'); const timeInput = document.getElementById('time-input'); const onchainCheckbox = document.getElementById('onchain-checkbox'); const lightningCheckbox = document.getElementById('lightning-checkbox'); const btcMethodCheckboxes = [onchainCheckbox, lightningCheckbox]; const myTrustedCheckbox = document.getElementById('my-trusted-checkbox'); const myTrustedTrustedCheckbox = document.getElementById( 'my-trusted-trusted-checkbox' ); const allMembersCheckbox = document.getElementById('all-members-checkbox'); const bigNotesAcceptedCheckbox = document.getElementById( 'large-bills-checkbox' ); const publishOfferButton = document.getElementById('button-submit-offer'); const offerCreatedPopup = document.getElementById( 'offer-created-confirmation' ); const offerDeletedPopup = document.getElementById( 'offer-deleted-confirmation' ); const ownOffersContainer = document.getElementById('own-offers-container'); function toggleCreateOfferModal() { createOfferModalRoot.classList.toggle('shown'); } function toggleViewMyOffersPanel() { viewMyOffersRoot.style.display = viewMyOffersRoot.style.display === 'block' ? 'none' : 'block'; } function modifyPremiumValue(delta) { const regexExpression = /-*\d+/; const numValue = parseInt(premiumValue.innerText.match(regexExpression)[0]); const newValue = `${numValue + delta}%`; premiumValue.innerText = newValue; } function toggleBuyOrSellButtonGroup() { buyOrSellButtons.forEach((button) => { if (button.classList.contains('selected')) { button.classList.remove('selected'); } else { button.classList.add('selected'); } }); } function readIntFromEurAmountInput() { const eurAmountFieldValue = eurAmountInput.value; const regularExpression = /([\d\s]+)/; const matchResult = eurAmountFieldValue.match(regularExpression); if (!matchResult) { return null; } const numberString = matchResult[1]; const cleanInputNumber = parseInt(numberString.replace(/\s/gi, '')); return cleanInputNumber; } function validateAndFormatEurAmountInput() { const cleanInputNumber = readIntFromEurAmountInput(); eurAmountInput.classList.remove('input-is-valid', 'input-is-invalid'); if (cleanInputNumber) { eurAmountInput.value = formatNumberWithSpaces(cleanInputNumber); eurAmountInput.classList.add('input-is-valid'); return; } eurAmountInput.classList.add('input-is-invalid'); } function updateBtcInput() { const eurToSatRate = 1021; const cleanEurAmount = readIntFromEurAmountInput(); const satsAmount = cleanEurAmount * eurToSatRate; const formattedSatsAmount = formatNumberWithSpaces(satsAmount); btcAmountInput.value = formattedSatsAmount; } function validateBitcoinMethodCheckboxes(clickedCheckbox) { let checkedCount = btcMethodCheckboxes.filter((cb) => cb.checked).length; if (checkedCount === 0) { clickedCheckbox.checked = true; } } function applyTrustCheckboxConstraints(pressedCheckbox) { if (pressedCheckbox === myTrustedTrustedCheckbox) { console.log('first case!'); if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) { allMembersCheckbox.checked = false; } } if (pressedCheckbox === allMembersCheckbox) { console.log('second case!'); if (!myTrustedTrustedCheckbox.checked && allMembersCheckbox.checked) { myTrustedTrustedCheckbox.checked = true; } } } async function publishOffer() { let wants; if (buyButton.classList.contains('selected')) { wants = 'BTC'; } if (sellButton.classList.contains('selected')) { wants = 'EUR'; } const premium = parseInt(premiumValue.innerText.match(/\d+/)[0]) / 100; const trade_amount_eur = eurAmountInput.value; const location_details = placeInput.value; const time_availability_details = timeInput.value; const is_onchain_accepted = onchainCheckbox.checked; const is_lightning_accepted = lightningCheckbox.checked; const show_offer_to_trusted = myTrustedCheckbox.checked; const show_offer_to_trusted_trusted = myTrustedTrustedCheckbox.checked; const show_offer_to_all_members = allMembersCheckbox.checked; const are_big_notes_accepted = bigNotesAcceptedCheckbox.checked; const offerDetails = { wants, premium, trade_amount_eur, location_details, time_availability_details, is_onchain_accepted, is_lightning_accepted, show_offer_to_trusted, show_offer_to_trusted_trusted, show_offer_to_all_members, are_big_notes_accepted, }; await fetch('/api/offer', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ offerDetails }), }); toggleOfferCreatedAlert(); toggleCreateOfferModal(); } function toggleOfferCreatedAlert() { offerCreatedPopup.classList.remove('max-size-zero'); offerCreatedPopup.classList.add('revealed'); setTimeout(() => { offerCreatedPopup.classList.remove('revealed'); }, 3000); setTimeout(() => { offerCreatedPopup.classList.add('max-size-zero'); }, 4000); } function toggleOfferDeletedAlert() { offerDeletedPopup.classList.remove('max-size-zero'); offerDeletedPopup.classList.add('revealed'); setTimeout(() => { offerDeletedPopup.classList.remove('revealed'); }, 3000); setTimeout(() => { offerDeletedPopup.classList.add('max-size-zero'); }, 4000); } class Offer { constructor(offerData) { this.uuid = offerData.uuid; this.public_key = offerData.public_key; this.wants = offerData.wants; this.premium = offerData.premium; this.trade_amount_eur = offerData.trade_amount_eur; this.location_details = offerData.location_details; this.time_availability_details = offerData.time_availability_details; this.show_offer_to_trusted = offerData.show_offer_to_trusted; this.show_offer_to_trusted_trusted = offerData.show_offer_to_trusted_trusted; this.show_offer_to_all_members = offerData.show_offer_to_all_members; this.is_onchain_accepted = offerData.is_onchain_accepted; this.is_lightning_accepted = offerData.is_lightning_accepted; this.are_big_notes_accepted = offerData.are_big_notes_accepted; this.created_at = offerData.created_at; this.last_updated_at = offerData.last_updated_at; } buildHTML() { const offerCard = document.createElement('div'); offerCard.classList.add('myoffer-card'); offerCard.classList.add('shadowed-round-area'); const tradeDescDiv = document.createElement('div'); tradeDescDiv.classList.add('trade-desc'); const youBuyText = document.createElement('p'); youBuyText.classList.add('offer-card-content-title'); youBuyText.innerText = 'Compras'; tradeDescDiv.append(youBuyText); const youBuyData = document.createElement('p'); youBuyData.classList.add('offer-card-content-data'); if (this.wants === 'BTC') { youBuyData.innerText = `${this.trade_amount_eur * 1021} sats`; } if (this.wants === 'EUR') { youBuyData.innerText = `${this.trade_amount_eur} €`; } tradeDescDiv.append(youBuyData); const youSellText = document.createElement('p'); youSellText.id = 'you-sell-title'; youSellText.classList.add('offer-card-content-title'); youSellText.innerText = 'Vendes'; tradeDescDiv.append(youSellText); const youSellData = document.createElement('p'); youSellData.classList.add('offer-card-content-data'); if (this.wants === 'BTC') { youSellData.innerText = `${this.trade_amount_eur} €`; } if (this.wants === 'EUR') { youSellData.innerText = `${this.trade_amount_eur * 1021} sats`; } tradeDescDiv.append(youSellData); const premiumDescDiv = document.createElement('div'); premiumDescDiv.classList.add('premium-desc'); const premiumTitle = document.createElement('p'); premiumTitle.classList.add('offer-card-content-title'); premiumTitle.innerText = 'Premium'; premiumDescDiv.append(premiumTitle); const premiumData = document.createElement('p'); premiumData.classList.add('offer-card-content-data'); premiumData.innerText = `${this.premium * 100} %`; premiumDescDiv.append(premiumData); const offerPriceTitle = document.createElement('p'); offerPriceTitle.classList.add('offer-card-content-title'); offerPriceTitle.innerText = 'Precio oferta'; premiumDescDiv.append(offerPriceTitle); const offerPriceData = document.createElement('p'); offerPriceData.classList.add('offer-card-content-data'); offerPriceData.innerText = `90000 €/BTC`; premiumDescDiv.append(offerPriceData); const marketPriceTitle = document.createElement('p'); marketPriceTitle.classList.add('offer-card-content-title'); marketPriceTitle.innerText = 'Precio mercado'; premiumDescDiv.append(marketPriceTitle); const marketPriceData = document.createElement('p'); marketPriceData.innerText = `88000 €/BTC`; premiumDescDiv.append(marketPriceData); const whereDescDiv = document.createElement('div'); whereDescDiv.classList.add('where-desc'); const whereDescTitle = document.createElement('p'); whereDescTitle.classList.add('offer-card-content-title'); whereDescTitle.innerText = 'Dónde'; whereDescDiv.append(whereDescTitle); const whereDescData = document.createElement('p'); whereDescData.classList.add('offer-long-text'); whereDescData.innerText = `${this.location_details}`; whereDescDiv.append(whereDescData); const whenDescDiv = document.createElement('div'); whenDescDiv.classList.add('when-desc'); const whenDescTitle = document.createElement('p'); whenDescTitle.classList.add('offer-card-content-title'); whenDescTitle.innerText = 'Cúando'; whenDescDiv.append(whenDescTitle); const whenDescData = document.createElement('p'); whenDescData.classList.add('offer-long-text'); whenDescData.innerText = `${this.time_availability_details}`; whenDescDiv.append(whenDescData); const bitcoinMethodsDiv = document.createElement('div'); bitcoinMethodsDiv.classList.add('bitcoin-methods-desc'); const bitcoinMethodsTitle = document.createElement('p'); bitcoinMethodsTitle.classList.add('offer-card-content-title'); bitcoinMethodsTitle.innerText = 'Protocolos Bitcoin aceptados'; bitcoinMethodsDiv.append(bitcoinMethodsTitle); const onchainAcceptedContainer = document.createElement('div'); onchainAcceptedContainer.classList.add('left-icon-checkboxed-field'); if (this.is_onchain_accepted) { const onchainIcon = document.createElement('img'); onchainIcon.src = '/img/chains-lasecagold.svg'; const onchainText = document.createElement('p'); onchainText.innerText = 'Onchain'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon); } else { const onchainIcon = document.createElement('img'); onchainIcon.src = '/img/chains-gray.svg'; const onchainText = document.createElement('p'); onchainText.innerText = 'Onchain'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; onchainAcceptedContainer.append(onchainIcon, onchainText, checkIcon); } const lightningAcceptedContainer = document.createElement('div'); lightningAcceptedContainer.classList.add('left-icon-checkboxed-field'); if (this.is_lightning_accepted) { const lightningIcon = document.createElement('img'); lightningIcon.src = '/img/bolt-lightning-lasecagold.svg'; const lightningText = document.createElement('p'); lightningText.innerText = 'Lightning'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; lightningAcceptedContainer.append( lightningIcon, lightningText, checkIcon ); } else { const lightningIcon = document.createElement('img'); lightningIcon.src = '/img/bolt-lightning-gray.svg'; const lightningText = document.createElement('p'); lightningText.innerText = 'Lightning'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; lightningAcceptedContainer.append( lightningIcon, lightningText, checkIcon ); } bitcoinMethodsDiv.append( onchainAcceptedContainer, lightningAcceptedContainer ); const visibilityDiv = document.createElement('div'); visibilityDiv.classList.add('visibility-desc'); const visibilityTitle = document.createElement('p'); visibilityTitle.classList.add('offer-card-content-title'); visibilityTitle.innerText = 'Visibilidad'; visibilityDiv.append(visibilityTitle); const showOfferToTrustedContainer = document.createElement('div'); showOfferToTrustedContainer.classList.add('right-icon-checkboxed-field'); if (this.show_offer_to_trusted) { const showOfferToTrustedIcon = document.createElement('img'); showOfferToTrustedIcon.src = '/img/user-lasecagold.svg'; const showOfferToTrustedText = document.createElement('p'); showOfferToTrustedText.innerText = 'Confiados'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; showOfferToTrustedContainer.append( showOfferToTrustedIcon, showOfferToTrustedText, checkIcon ); } else { const showOfferToTrustedIcon = document.createElement('img'); showOfferToTrustedIcon.src = '/img/user-gray.svg'; const showOfferToTrustedText = document.createElement('p'); showOfferToTrustedText.innerText = 'Confiados'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; showOfferToTrustedContainer.append( showOfferToTrustedIcon, showOfferToTrustedText, checkIcon ); } const showOfferToTrustedTrustedContainer = document.createElement('div'); showOfferToTrustedTrustedContainer.classList.add( 'right-icon-checkboxed-field' ); if (this.show_offer_to_trusted_trusted) { const showOfferToTrustedTrustedIcon = document.createElement('img'); showOfferToTrustedTrustedIcon.src = '/img/user-group-lasecagold.svg'; const showOfferToTrustedTrustedText = document.createElement('p'); showOfferToTrustedTrustedText.innerText = 'Sus confiados'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; showOfferToTrustedTrustedContainer.append( showOfferToTrustedTrustedIcon, showOfferToTrustedTrustedText, checkIcon ); } else { const showOfferToTrustedTrustedIcon = document.createElement('img'); showOfferToTrustedTrustedIcon.src = '/img/user-group-gray.svg'; const showOfferToTrustedTrustedText = document.createElement('p'); showOfferToTrustedTrustedText.innerText = 'Sus confiados'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; showOfferToTrustedTrustedContainer.append( showOfferToTrustedTrustedIcon, showOfferToTrustedTrustedText, checkIcon ); } const showOfferToAllMembersContainer = document.createElement('div'); showOfferToAllMembersContainer.classList.add( 'right-icon-checkboxed-field' ); if (this.show_offer_to_all_members) { const showOfferToAllMembersIcon = document.createElement('img'); showOfferToAllMembersIcon.src = '/img/many-users-lasecagold.svg'; const showOfferToAllMembersText = document.createElement('p'); showOfferToAllMembersText.innerText = 'Todos'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; showOfferToAllMembersContainer.append( showOfferToAllMembersIcon, showOfferToAllMembersText, checkIcon ); } else { const showOfferToAllMembersIcon = document.createElement('img'); showOfferToAllMembersIcon.src = '/img/many-users-gray.svg'; const showOfferToAllMembersText = document.createElement('p'); showOfferToAllMembersText.innerText = 'Todos'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; showOfferToAllMembersContainer.append( showOfferToAllMembersIcon, showOfferToAllMembersText, checkIcon ); } visibilityDiv.append( showOfferToTrustedContainer, showOfferToTrustedTrustedContainer, showOfferToAllMembersContainer ); const otherOfferFeaturesDiv = document.createElement('div'); otherOfferFeaturesDiv.classList.add('other-desc'); const otherOfferFeaturesTitle = document.createElement('p'); otherOfferFeaturesTitle.classList.add('offer-card-content-title'); otherOfferFeaturesTitle.innerText = 'Otros'; otherOfferFeaturesDiv.append(otherOfferFeaturesTitle); const areBigNotesAcceptedContainer = document.createElement('div'); areBigNotesAcceptedContainer.classList.add('left-icon-checkboxed-field'); if (this.are_big_notes_accepted) { const areBigNotesAcceptedIcon = document.createElement('img'); areBigNotesAcceptedIcon.src = '/img/eur-bill-lasecagold.svg'; const areBigNotesAcceptedText = document.createElement('p'); areBigNotesAcceptedText.innerText = 'Billetes grandes'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-check-green.svg'; areBigNotesAcceptedContainer.append( areBigNotesAcceptedIcon, areBigNotesAcceptedText, checkIcon ); } else { const areBigNotesAcceptedIcon = document.createElement('img'); areBigNotesAcceptedIcon.src = '/img/eur-bill-gray.svg'; const areBigNotesAcceptedText = document.createElement('p'); areBigNotesAcceptedText.innerText = 'Billetes grandes'; const checkIcon = document.createElement('img'); checkIcon.src = '/img/circle-xmark-gray.svg'; areBigNotesAcceptedContainer.append( areBigNotesAcceptedIcon, areBigNotesAcceptedText, checkIcon ); } otherOfferFeaturesDiv.append(areBigNotesAcceptedContainer); const actionButtonsArea = document.createElement('p'); actionButtonsArea.classList.add('offer-action-buttons-area'); const editActionArea = document.createElement('div'); editActionArea.classList.add('offer-action-area'); editActionArea.classList.add('subtle-box'); const editActionIcon = document.createElement('img'); editActionIcon.src = '/img/edit.svg'; const editActionText = document.createElement('p'); editActionText.innerText = 'Editar'; editActionArea.append(editActionIcon, editActionText); const deleteActionArea = document.createElement('div'); deleteActionArea.classList.add('offer-action-area'); deleteActionArea.classList.add('subtle-box'); const deleteActionIcon = document.createElement('img'); deleteActionIcon.src = '/img/trash-can-darkred.svg'; const deleteActionText = document.createElement('p'); deleteActionText.innerText = 'Eliminar'; deleteActionArea.append(deleteActionIcon, deleteActionText); deleteActionArea.addEventListener('click', async () => { await deleteOfferByUuid(this.uuid); await myOffers.getOffersFromApi(); await myOffers.render(); toggleOfferDeletedAlert(); }); actionButtonsArea.append(editActionArea, deleteActionArea); offerCard.append( tradeDescDiv, premiumDescDiv, whereDescDiv, whenDescDiv, bitcoinMethodsDiv, visibilityDiv, otherOfferFeaturesDiv, actionButtonsArea ); return offerCard; } } class MyOffers { constructor(ownOffersContainerElement) { this.ownOffersContainerElement = ownOffersContainerElement; this.offers = []; } async getOffersFromApi() { const offersResponse = await fetch('/api/publickey-offers'); this.offers = []; const offersData = (await offersResponse.json()).data; if (offersResponse.ok) { for (const record of offersData) { this.offers.push(new Offer(record)); } } } async render() { if (this.offers.length === 0) { this.ownOffersContainerElement.innerHTML = '
Vaya, no hay nada por aquí...
'; return; } this.ownOffersContainerElement.innerHTML = ''; for (const someOffer of this.offers) { this.ownOffersContainerElement.append(someOffer.buildHTML()); } } } async function deleteOfferByUuid(offerUuid) { await fetch(`/api/offer/${offerUuid}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', }, }); } buttonStartCreateOffer.addEventListener('click', () => { toggleCreateOfferModal(); }); buttonViewMyOffers.addEventListener('click', async () => { await myOffers.getOffersFromApi(); await myOffers.render(); toggleViewMyOffersPanel(); }); closeOffer.addEventListener('click', () => { toggleCreateOfferModal(); }); buyOrSellButtons.forEach((button) => { button.addEventListener('click', () => { toggleBuyOrSellButtonGroup(); }); }); buttonIncreasePremium.addEventListener('click', () => { modifyPremiumValue(1); }); buttonDecreasePremium.addEventListener('click', () => { modifyPremiumValue(-1); }); eurAmountInput.addEventListener('blur', () => { validateAndFormatEurAmountInput(); updateBtcInput(); }); eurAmountInput.addEventListener('input', () => { eurAmountInput.value = eurAmountInput.value.replace(/[^0-9]/g, ''); updateBtcInput(); }); for (const btcMethodCheckbox of btcMethodCheckboxes) { btcMethodCheckbox.addEventListener('click', () => { validateBitcoinMethodCheckboxes(btcMethodCheckbox); }); } myTrustedTrustedCheckbox.addEventListener('click', () => { applyTrustCheckboxConstraints(myTrustedTrustedCheckbox); }); allMembersCheckbox.addEventListener('click', () => { applyTrustCheckboxConstraints(allMembersCheckbox); }); publishOfferButton.addEventListener('click', async () => { await publishOffer(); await myOffers.getOffersFromApi(); await myOffers.render(); }); updateBtcInput(); const myOffers = new MyOffers(ownOffersContainer); } offersPage;