barebones
17
README.org
|
@ -32,7 +32,8 @@ CREATE TABLE sites (
|
|||
sur VARCHAR(50),
|
||||
email VARCHAR(100) NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
code VARCHAR(2)
|
||||
code VARCHAR(2),
|
||||
raw JSONB NOT NULL
|
||||
);
|
||||
#+END_SRC
|
||||
|
||||
|
@ -46,10 +47,9 @@ SELECT * FROM sites;
|
|||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
| id | folder | status | due | name | sur | email | phone | code |
|
||||
|----+-----------+--------+------------------------+------+-----+---------------------------------------+------------+------|
|
||||
| 1 | athos | up | 2026-08-31 15:27:00-06 | John | Doe | sb-8kx8c32267916@personal.example.com | 5068031951 | CR |
|
||||
| 2 | gofitness | up | 2025-08-31 15:29:01-06 | John | Doe | sb-8kx8c32267916@personal.example.com | 5068031951 | CR |
|
||||
| id | folder | status | due | name | sur | email | phone | code | raw |
|
||||
|----+-----------+--------+------------------------+------+-----+---------------------------------------+------------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 2 | gofitness | up | 2025-09-01 00:18:06-06 | John | Doe | sb-8kx8c32267916@personal.example.com | 5068031951 | CR | {"time": 1725171485533, "blocks": [{"id": "hLu8z-l1u5", "data": {"text": "asdfasfasdf", "level": 2}, "type": "header"}, {"id": "frc77fNxnu", "data": {"text": "asdfasfasdf"}, "type": "paragraph"}], "version": "2.30.5"} |
|
||||
|
||||
** Payments table
|
||||
|
||||
|
@ -78,11 +78,8 @@ SELECT * FROM payments;
|
|||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
| id | capture | site | amount | currency | status | date |
|
||||
|----+-------------------+------+--------+----------+-----------+------------|
|
||||
| 1 | 6H6838025H7236834 | 1 | 20.00 | USD | COMPLETED | 2024-08-31 |
|
||||
| 2 | 48H30563GU472432N | 1 | 20.00 | USD | COMPLETED | 2024-08-31 |
|
||||
| 3 | 3UD50608FD4050042 | 2 | 20.00 | USD | COMPLETED | 2024-08-31 |
|
||||
| id | capture | site | amount | currency | status | date |
|
||||
|----+---------+------+--------+----------+--------+------|
|
||||
|
||||
** Changes table
|
||||
|
||||
|
|
277
public/app.js
|
@ -1,195 +1,92 @@
|
|||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const dialog = document.getElementById("dialog");
|
||||
const overlay = document.getElementById("overlay");
|
||||
const menu = document.getElementById("floatingButtons");
|
||||
paypal.Buttons({
|
||||
style: {
|
||||
shape: "pill",
|
||||
layout: "vertical",
|
||||
},
|
||||
async createOrder() {
|
||||
try {
|
||||
const response = await fetch("/api/orders", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
function openDialog() {
|
||||
dialog.style.display = "block";
|
||||
overlay.style.display = "block";
|
||||
menu.style.display = "none";
|
||||
const orderData = await response.json();
|
||||
|
||||
if (orderData.id) {
|
||||
return orderData.id;
|
||||
} else {
|
||||
const errorDetail = orderData?.details?.[0];
|
||||
const errorMessage = errorDetail
|
||||
? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
|
||||
: JSON.stringify(orderData);
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resultMessage(`Could not initiate PayPal Checkout...<br><br>${error}`);
|
||||
}
|
||||
},
|
||||
async onApprove(data, actions) {
|
||||
try {
|
||||
const requestData = {
|
||||
directory: "gofitness",
|
||||
editor_data: await editor.save()
|
||||
};
|
||||
|
||||
function closeDialog() {
|
||||
dialog.style.display = "none";
|
||||
overlay.style.display = "none";
|
||||
menu.style.display = "block";
|
||||
const response = await fetch(`/api/orders/${data.orderID}/capture`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestData),
|
||||
});
|
||||
|
||||
const orderData = await response.json();
|
||||
// Three cases to handle:
|
||||
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
|
||||
// (2) Other non-recoverable errors -> Show a failure message
|
||||
// (3) Successful transaction -> Show confirmation or thank you message
|
||||
|
||||
const errorDetail = orderData?.details?.[0];
|
||||
|
||||
if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
|
||||
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
|
||||
// recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
|
||||
return actions.restart();
|
||||
} else if (errorDetail) {
|
||||
// (2) Other non-recoverable errors -> Show a failure message
|
||||
throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
|
||||
} else if (!orderData.purchase_units) {
|
||||
throw new Error(JSON.stringify(orderData));
|
||||
} else {
|
||||
// (3) Successful transaction -> Show confirmation or thank you message
|
||||
// Or go to another URL: actions.redirect('thank_you.html');
|
||||
const transaction =
|
||||
orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
|
||||
orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
|
||||
resultMessage(
|
||||
`Transaction ${transaction.status}: ${transaction.id}<br><br>See console for all available details`,
|
||||
);
|
||||
console.log(
|
||||
"Capture result",
|
||||
orderData,
|
||||
JSON.stringify(orderData, null, 2),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resultMessage(
|
||||
`Sorry, your transaction could not be processed...<br><br>${error}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
}).render("#paypal-button-container");
|
||||
|
||||
function togglePaymentMethod(selectedButtonId) {
|
||||
// Deselect all buttons and hide all PayPal buttons
|
||||
document.querySelectorAll('#method-button-container button').forEach(button => { button.classList.remove('active'); });
|
||||
document.querySelectorAll('#paypal-button-container > div').forEach(div => { div.classList.remove('active'); });
|
||||
|
||||
// Select the clicked button and show the corresponding PayPal button
|
||||
const selectedButton = document.getElementById(selectedButtonId);
|
||||
selectedButton.classList.add('active');
|
||||
|
||||
if (selectedButtonId === 'showOneTimeButton') {
|
||||
document.getElementById('paypal-button-container').classList.add('active');
|
||||
document.getElementById('paypal-button-container-order').classList.add('active');
|
||||
} else if (selectedButtonId === 'showSubButton') {
|
||||
document.getElementById('paypal-button-container').classList.add('active');
|
||||
document.getElementById('paypal-button-container-subscribe').classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('showOneTimeButton').addEventListener('click', function() {
|
||||
document.getElementById('warning-message').style.display = 'none';
|
||||
togglePaymentMethod('showOneTimeButton');
|
||||
});
|
||||
|
||||
document.getElementById('showSubButton').addEventListener('click', function() {
|
||||
document.getElementById('warning-message').style.display = 'none';
|
||||
togglePaymentMethod('showSubButton');
|
||||
});
|
||||
|
||||
document.getElementById("openDialogButton").addEventListener("click", openDialog);
|
||||
document.getElementById("cancelDialogButton").addEventListener("click", closeDialog);
|
||||
});
|
||||
|
||||
|
||||
window.paypal_order.Buttons({
|
||||
style: { shape: 'pill', color: 'black', layout: 'vertical', label: 'pay' },
|
||||
async createOrder() {
|
||||
try {
|
||||
const response = await fetch("/api/order", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const orderData = await response.json();
|
||||
|
||||
if (orderData.id) {
|
||||
return orderData.id;
|
||||
} else {
|
||||
const errorDetail = orderData?.details?.[0];
|
||||
const errorMessage = errorDetail
|
||||
? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
|
||||
: JSON.stringify(orderData);
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resultMessage(`Could not initiate PayPal Checkout...<br><br>${error}`);
|
||||
}
|
||||
},
|
||||
async onApprove(data, actions) {
|
||||
try {
|
||||
const response = await fetch(`/api/order/${data.orderID}/capture`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(
|
||||
{
|
||||
directory: "tutorias",
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
const orderData = await response.json();
|
||||
// Three cases to handle:
|
||||
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
|
||||
// (2) Other non-recoverable errors -> Show a failure message
|
||||
// (3) Successful transaction -> Show confirmation or thank you message
|
||||
|
||||
const errorDetail = orderData?.details?.[0];
|
||||
|
||||
if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
|
||||
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
|
||||
// recoverable state, per https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
|
||||
return actions.restart();
|
||||
} else if (errorDetail) {
|
||||
// (2) Other non-recoverable errors -> Show a failure message
|
||||
throw new Error(`${errorDetail.description} (${orderData.debug_id})`);
|
||||
} else if (!orderData.purchase_units) {
|
||||
throw new Error(JSON.stringify(orderData));
|
||||
} else {
|
||||
// (3) Successful transaction -> Show confirmation or thank you message
|
||||
// Or go to another URL: actions.redirect('thank_you.html');
|
||||
const transaction =
|
||||
orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
|
||||
orderData?.purchase_units?.[0]?.payments?.authorizations?.[0];
|
||||
resultMessage(
|
||||
`Transaction ${transaction.status}: ${transaction.id}<br><br>See console for all available details`,
|
||||
);
|
||||
console.log(
|
||||
"Capture result",
|
||||
orderData,
|
||||
JSON.stringify(orderData, null, 2),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resultMessage(
|
||||
`Sorry, your transaction could not be processed...<br><br>${error}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
}).render("#paypal-button-container-order");
|
||||
|
||||
window.paypal_subscribe.Buttons({
|
||||
style: { shape: 'pill', color: 'black', layout: 'vertical', label: 'subscribe' },
|
||||
async createSubscription() {
|
||||
try {
|
||||
const response = await fetch("/api/paypal/subscribe", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(
|
||||
{
|
||||
// userAction: "SUBSCRIBE_NOW"
|
||||
directory: "testsite",
|
||||
}
|
||||
),
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data?.id) {
|
||||
const approvalUrl = data.links.find(link => link.rel === "approve").href;
|
||||
window.location.href = approvalUrl;
|
||||
resultMessage(`Successful subscription with ID ${approvalUrl}...<br><br>`);
|
||||
// resultMessage(`Successful subscription with ID ${data.id}...<br><br>`);
|
||||
return data.id;
|
||||
} else {
|
||||
console.error(
|
||||
{ callback: "createSubscription", serverResponse: data },
|
||||
JSON.stringify(data, null, 2),
|
||||
);
|
||||
// (Optional) The following hides the button container and shows a message about why checkout can't be initiated
|
||||
const errorDetail = data?.details?.[0];
|
||||
resultMessage(
|
||||
`Could not initiate PayPal Subscription...<br><br>${
|
||||
errorDetail?.issue || ""
|
||||
} ${errorDetail?.description || data?.message || ""} ` +
|
||||
(data?.debug_id ? `(${data.debug_id})` : ""),
|
||||
{ hideButtons: true },
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
resultMessage(
|
||||
`Could not initiate PayPal Subscription...<br><br>${error}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
onApprove(data) {
|
||||
/*
|
||||
No need to activate manually since SUBSCRIBE_NOW is being used.
|
||||
Learn how to handle other user actions from our docs:
|
||||
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
|
||||
*/
|
||||
if (data.orderID) {
|
||||
resultMessage(
|
||||
`You have successfully subscribed to the plan. Your subscription id is: ${data.subscriptionID}`,
|
||||
);
|
||||
} else {
|
||||
resultMessage(
|
||||
`Failed to activate the subscription: ${data.subscriptionID}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
}).render("#paypal-button-container-subscribe"); // Renders the PayPal button
|
||||
// Example function to show a result to the user. Your site's UI library can be used instead.
|
||||
function resultMessage(message) {
|
||||
const container = document.querySelector("#result-message");
|
||||
container.innerHTML = message;
|
||||
}
|
||||
|
|
|
@ -1,89 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<title>Builder | CONEX.one </title>
|
||||
<link rel="canonical" href="https://builder.conex.one">
|
||||
<link rel='stylesheet' type='text/css' href='/static/css/style.css'>
|
||||
<link rel="icon" href="favicon.png">
|
||||
<meta name="description" content="Constructor de sitios web de CONEX.one">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<!-- EDITORJS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script><!-- Header -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/simple-image@latest"></script><!-- Image -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest"></script><!-- List -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest"></script><!-- Quote -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest"></script><!-- Code -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed@latest"></script><!-- Embed -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table@latest"></script><!-- Table -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link@latest"></script><!-- Link -->
|
||||
<!-- Load Editor.js's Core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
<!-- EDITORJS -->
|
||||
<script
|
||||
src="https://sandbox.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&enable-funding=card&disable-funding=paylater,venmo"
|
||||
data-namespace="paypal_order"
|
||||
></script>
|
||||
<script
|
||||
src="https://sandbox.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&vault=true&intent=subscription&enable-funding=card&disable-funding=paylater"
|
||||
data-namespace="paypal_subscribe"
|
||||
></script>
|
||||
</head>
|
||||
<div class="banner" style="background-image: url(/static/banner.jpg);">
|
||||
<div class="desc">
|
||||
<input type="text" id="title" name="title" class="input-title" placeholder="[Nombre Ejemplo]">
|
||||
<input type="text" id="slogan" name="slogan" class="input-slogan" placeholder="[Slogan llamativo o breve descripción]">
|
||||
<div class="floating-buttons" id="floatingButtons">
|
||||
<button class="floating-button" id="openDialogButton">
|
||||
<img src="/static/svg/cart.svg">
|
||||
<span>$20/año</span>
|
||||
</button>
|
||||
<button class="floating-button" id="updateSiteButton">
|
||||
<img src="/static/svg/edit.svg">
|
||||
<span>Actualizar mi página</span>
|
||||
</button>
|
||||
<button class="floating-button" id="deleteSiteButton">
|
||||
<img src="/static/svg/delete.svg">
|
||||
<span>Eliminar página</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<body>
|
||||
<div id="content" class="content">
|
||||
<div id="editorjs"></div>
|
||||
</div>
|
||||
</body>
|
||||
<div id="overlay"></div>
|
||||
<div id="dialog">
|
||||
<div>
|
||||
<button id="cancelDialogButton" type="button">
|
||||
<picture>
|
||||
<source srcset="/static/svg/xd.svg" media="(prefers-color-scheme: dark)">
|
||||
<img src="/static/svg/x.svg" style="width: 0.7em; height: 0.7em;" alt="Close" id="closeIcon">
|
||||
</picture>
|
||||
</button>
|
||||
</div>
|
||||
<h2>Tipo de Pago</h2>
|
||||
<div>
|
||||
<p><strong>Pago Único:</strong> El pago debe realizarse manualmente un año después de contratar el servicio, le enviaremos notificaciones al correo electrónico recordando el pago.</p>
|
||||
<p><strong>Pago Automático:</strong> Requiere cuenta de PayPal para rebajo automático, si no tiene una le pedirá configurar rápidamente los datos.</p>
|
||||
</div>
|
||||
<div id="warning-message"><p>Por favor digite los campos requeridos.</p></div>
|
||||
<div id="error-with-payment"></div>
|
||||
<div id="checkout">
|
||||
<div id="method-button-container">
|
||||
<button id="showOneTimeButton" type="button">Pago Único</button>
|
||||
<button id="showSubButton" type="button">Pago Automático</button>
|
||||
</div>
|
||||
<div id="paypal-button-container">
|
||||
<div id="paypal-button-container-order"></div>
|
||||
<div id="paypal-button-container-subscribe"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/app.js"></script>
|
||||
<script src="/static/js/config.editor.js"></script>
|
||||
</html>
|
||||
<head>
|
||||
<title>Creador CONEX.one</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/svg/favicon.svg">
|
||||
</head>
|
||||
<h1>PayPal SDK & API Integration</h1>
|
||||
<div id="editorjs"></div>
|
||||
<div id="paypal-button-container"></div>
|
||||
<p id="result-message"></p>
|
||||
<script src="https://sandbox.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&enable-funding=card&disable-funding=paylater,venmo"></script>
|
||||
<!-- EDITORJS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script><!-- Header -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/simple-image@latest"></script><!-- Image -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest"></script><!-- List -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest"></script><!-- Quote -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest"></script><!-- Code -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed@latest"></script><!-- Embed -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/table@latest"></script><!-- Table -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/link@latest"></script><!-- Link -->
|
||||
<!-- Load Editor.js's Core -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||
<!-- EDITORJS -->
|
||||
<script src="/app.js"></script>
|
||||
<!-- <script src="/static/js/config.editor.js"></script> -->
|
||||
<script>
|
||||
// Initialize Editor.js
|
||||
const editor = new EditorJS({
|
||||
holder: 'editorjs',
|
||||
tools: {
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: true
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
Before Width: | Height: | Size: 17 KiB |
1
public/static/css/simplemde-dark.min.css
vendored
7
public/static/css/simplemde.min.css
vendored
|
@ -1,315 +0,0 @@
|
|||
:root {
|
||||
--background-color: white;
|
||||
--color: black;
|
||||
--warning-color: #b24629;
|
||||
--page-width: 768px;
|
||||
--navbar-width: 50%;
|
||||
--font-family: sans-serif;
|
||||
--logo: url('logo.png');
|
||||
--unemph-color: #505050;
|
||||
--hover-background: #dcdcdc;
|
||||
--hover-border: #aaa;
|
||||
--line-height: 1.7;
|
||||
--smaller-font: 0.75em;
|
||||
--hyper-color: #0f82af;
|
||||
text-align: justify;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background-color: #1d2021;
|
||||
--color: white;
|
||||
--hover-background: #282c2d;
|
||||
--unemph-color: #909090;
|
||||
--hover-border: #505050;
|
||||
--hyper-color: #00b4db;
|
||||
}
|
||||
#closeIcon {
|
||||
content: url('/static/svg/xd.svg');
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
:root {
|
||||
--page-width: 90%;
|
||||
--navbar-width: 50vh;
|
||||
}
|
||||
.floating-button span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--background-color);
|
||||
color: var(--color);
|
||||
font-family: var(--font-family);
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0 auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--hyper-color);
|
||||
}
|
||||
|
||||
.banner {
|
||||
padding: 6vh;
|
||||
box-shadow: 0 15vh 30vh black inset;
|
||||
background-position: 50%;
|
||||
background-size: cover;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.input-title {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
background-color: #00000000;
|
||||
border-color: #00000000;
|
||||
color: white;
|
||||
margin-bottom: -0.2em;
|
||||
}
|
||||
|
||||
.input-slogan {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
background-color: #00000000;
|
||||
border-color: #00000000;
|
||||
color: white;
|
||||
line-height: 1em;
|
||||
margin: 0.5em auto 0em auto;
|
||||
}
|
||||
|
||||
div.profilepicture img {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
margin-top: 2em;
|
||||
width: 50%;
|
||||
max-width: 250px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1 0 auto;
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
width: 90%;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.content li {
|
||||
line-height: 1.4em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.content p {
|
||||
line-height: 1.4em;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.content img {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: var(--hover-background);
|
||||
color: var(--unemph-color);
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin: 1em auto 0 auto;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#dialog {
|
||||
width: 85%;
|
||||
max-width: 30em;
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 1.5em;
|
||||
background: var(--background-color);
|
||||
border: 1px solid var(--hover-border);
|
||||
box-shadow: 0 0 3em rgba(0, 0, 0, 0.4);
|
||||
z-index: 1000;
|
||||
border-radius: 10px;
|
||||
text-align: left;
|
||||
overflow: auto;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
#dialog h2, #dialog p {
|
||||
margin: 0;
|
||||
padding: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
#dialog button {
|
||||
margin: 0.5em 0.5em 0 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#dialog input {
|
||||
text-align: left;
|
||||
font-size: 1em;
|
||||
display: block;
|
||||
width: 90%;
|
||||
color: var(--color);
|
||||
background: var(--hover-background);
|
||||
border: 1px solid var(--hover-border);
|
||||
border-radius: 10px;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
#form-container {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#warning-message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#warning-message p {
|
||||
text-decoration: underline;
|
||||
color: var(--warning-color);
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.5em;
|
||||
margin: 1em auto;
|
||||
color: var(--unemph-color);
|
||||
background: var(--background);
|
||||
border: 1px solid var(--hover-border);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#dialog button:hover {
|
||||
background: var(--hover-background);
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
#method-button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
#method-button-container button {
|
||||
transition: 0.3s;
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--hover-border);
|
||||
color: var(--unemph-color);
|
||||
}
|
||||
|
||||
#method-button-container button.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#paypal-button-container > div {
|
||||
margin: 1.5em 0 0 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#paypal-button-container > div.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#cancelDialogButton {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--hover-border);
|
||||
color: var(--unemph-color);
|
||||
position: absolute;
|
||||
transition: 0.3s;
|
||||
border-radius: 50%;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.floating-buttons {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
bottom: 0.2em;
|
||||
right: 0.5em;
|
||||
gap: 0.4em;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.floating-button {
|
||||
height: 2.5em;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
z-index: 1001;
|
||||
border-radius: 999px;
|
||||
box-sizing: border-box;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
outline: 0 solid transparent;
|
||||
padding: 8px 18px;
|
||||
width: fit-content;
|
||||
word-break: break-word;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.floating-button img {
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.floating-button span {
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
|
||||
.floating-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
#updateSiteButton {
|
||||
background: linear-gradient(135deg, #214353, #4c9abf);
|
||||
box-shadow: #0099c5 0 10px 20px -15px;
|
||||
}
|
||||
|
||||
#deleteSiteButton {
|
||||
background: linear-gradient(135deg, #5e2329, #bf4c58);
|
||||
box-shadow: #e31300 0 10px 20px -15px;
|
||||
}
|
||||
|
||||
#openDialogButton {
|
||||
background: linear-gradient(135deg, #21532a, #4fc764);
|
||||
box-shadow: #27d100 0 10px 20px -15px;
|
||||
}
|
|
@ -176,44 +176,7 @@ var editor = new EditorJS({
|
|||
},
|
||||
}
|
||||
},
|
||||
onReady: function(){
|
||||
saveButton.click();
|
||||
},
|
||||
onChange: function(api, event) {
|
||||
console.log('something changed', event);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Saving button
|
||||
*/
|
||||
const saveButton = document.getElementById('saveButton');
|
||||
|
||||
/**
|
||||
* Toggle read-only button
|
||||
*/
|
||||
const toggleReadOnlyButton = document.getElementById('toggleReadOnlyButton');
|
||||
const readOnlyIndicator = document.getElementById('readonly-state');
|
||||
|
||||
/**
|
||||
* Saving example
|
||||
*/
|
||||
saveButton.addEventListener('click', function () {
|
||||
editor.save()
|
||||
.then((savedData) => {
|
||||
cPreview.show(savedData, document.getElementById("output"));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Saving error', error);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Toggle read-only example
|
||||
*/
|
||||
toggleReadOnlyButton.addEventListener('click', async () => {
|
||||
const readOnlyState = await editor.readOnly.toggle();
|
||||
|
||||
readOnlyIndicator.textContent = readOnlyState ? 'On' : 'Off';
|
||||
});
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
var simplemde = new SimpleMDE({
|
||||
element: document.getElementById("editor"),
|
||||
autosave: {
|
||||
enabled: true,
|
||||
uniqueId: "main-editor",
|
||||
delay: 1000,
|
||||
},
|
||||
toolbar: ["preview", "|", "heading", "bold", "italic", "unordered-list", "ordered-list", "|", "link", "image", "table"],
|
||||
spellChecker: false,
|
||||
status: false,
|
||||
placeholder: "Contruye tu página aquí utilizando la barra de herramientas de arriba.\n\nRecuerde editar también\n[Nombre Ejemplo] y [Slogan]."
|
||||
});
|
15
public/static/js/simplemde.min.js
vendored
Before Width: | Height: | Size: 114 KiB |
|
@ -1,5 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="#fff" d="M528.12 301.319l47.273-208C578.806 78.301 567.391 64 551.99 64H159.208l-9.166-44.81C147.758 8.021 137.93 0 126.529 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24h69.883l70.248 343.435C147.325 417.1 136 435.222 136 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-15.674-6.447-29.835-16.824-40h209.647C430.447 426.165 424 440.326 424 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-22.172-12.888-41.332-31.579-50.405l5.517-24.276c3.413-15.018-8.002-29.319-23.403-29.319H218.117l-6.545-32h293.145c11.206 0 20.92-7.754 23.403-18.681z"/></svg>
|
||||
<!--
|
||||
Font Awesome Free 5.2.0 by @fontawesome - https://fontawesome.com
|
||||
License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
-->
|
Before Width: | Height: | Size: 804 B |
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#fff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="800px" height="800px" viewBox="0 0 485 485" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<rect x="67.224" width="350.535" height="71.81"/>
|
||||
<path d="M417.776,92.829H67.237V485h350.537V92.829H417.776z M165.402,431.447h-28.362V146.383h28.362V431.447z M256.689,431.447
|
||||
h-28.363V146.383h28.363V431.447z M347.97,431.447h-28.361V146.383h28.361V431.447z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 727 B |
|
@ -1,9 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#fff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<path d="M70.2,337.4l104.4,104.4L441.5,175L337,70.5L70.2,337.4z M0.6,499.8c-2.3,9.3,2.3,13.9,11.6,11.6L151.4,465L47,360.6
|
||||
viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<circle cx="256" cy="256" r="256" fill="#006eb7" />
|
||||
<path d="M70.2,337.4l104.4,104.4L441.5,175L337,70.5L70.2,337.4z M0.6,499.8c-2.3,9.3,2.3,13.9,11.6,11.6L151.4,465L47,360.6
|
||||
L0.6,499.8z M487.9,24.1c-46.3-46.4-92.8-11.6-92.8-11.6c-7.6,5.8-34.8,34.8-34.8,34.8l104.4,104.4c0,0,28.9-27.2,34.8-34.8
|
||||
C499.5,116.9,534.3,70.6,487.9,24.1z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 639 B |
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 460.775 460.775" xml:space="preserve">
|
||||
<path d="M285.08,230.397L456.218,59.27c6.076-6.077,6.076-15.911,0-21.986L423.511,4.565c-2.913-2.911-6.866-4.55-10.992-4.55
|
||||
c-4.127,0-8.08,1.639-10.993,4.55l-171.138,171.14L59.25,4.565c-2.913-2.911-6.866-4.55-10.993-4.55
|
||||
c-4.126,0-8.08,1.639-10.992,4.55L4.558,37.284c-6.077,6.075-6.077,15.909,0,21.986l171.138,171.128L4.575,401.505
|
||||
c-6.074,6.077-6.074,15.911,0,21.986l32.709,32.719c2.911,2.911,6.865,4.55,10.992,4.55c4.127,0,8.08-1.639,10.994-4.55
|
||||
l171.117-171.12l171.118,171.12c2.913,2.911,6.866,4.55,10.993,4.55c4.128,0,8.081-1.639,10.992-4.55l32.709-32.719
|
||||
c6.074-6.075,6.074-15.909,0-21.986L285.08,230.397z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1 KiB |
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg fill="#fff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 460.775 460.775" xml:space="preserve">
|
||||
<path d="M285.08,230.397L456.218,59.27c6.076-6.077,6.076-15.911,0-21.986L423.511,4.565c-2.913-2.911-6.866-4.55-10.992-4.55
|
||||
c-4.127,0-8.08,1.639-10.993,4.55l-171.138,171.14L59.25,4.565c-2.913-2.911-6.866-4.55-10.993-4.55
|
||||
c-4.126,0-8.08,1.639-10.992,4.55L4.558,37.284c-6.077,6.075-6.077,15.909,0,21.986l171.138,171.128L4.575,401.505
|
||||
c-6.074,6.077-6.074,15.911,0,21.986l32.709,32.719c2.911,2.911,6.865,4.55,10.992,4.55c4.127,0,8.08-1.639,10.994-4.55
|
||||
l171.117-171.12l171.118,171.12c2.913,2.911,6.866,4.55,10.993,4.55c4.128,0,8.081-1.639,10.992-4.55l32.709-32.719
|
||||
c6.074-6.075,6.074-15.909,0-21.986L285.08,230.397z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1 KiB |
1
server/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
go.*
|
|
@ -135,7 +135,7 @@ func Token() (string, error) {
|
|||
return response.AccessToken, nil
|
||||
}
|
||||
|
||||
func RegisterOrder(capture Capture, directory string) {
|
||||
func RegisterOrder(capture Capture, directory string, editorData json.RawMessage) {
|
||||
var (
|
||||
// Payment
|
||||
id string
|
||||
|
@ -158,7 +158,7 @@ func RegisterOrder(capture Capture, directory string) {
|
|||
currency = capture.PurchaseUnits[0].Payments.Captures[0].Amount.CurrencyCode
|
||||
pstatus = capture.PurchaseUnits[0].Payments.Captures[0].Status
|
||||
date = capture.PurchaseUnits[0].Payments.Captures[0].CreateTime
|
||||
wstatus = "up"
|
||||
wstatus = "down"
|
||||
due = date.AddDate(1, 0, 0)
|
||||
name = capture.Payer.Name.GivenName
|
||||
surname = capture.Payer.Name.Surname
|
||||
|
@ -172,11 +172,12 @@ func RegisterOrder(capture Capture, directory string) {
|
|||
|
||||
if newSite == sql.ErrNoRows {
|
||||
if err := db.QueryRow(
|
||||
`INSERT INTO sites (folder, status, due, name, sur, email, phone, code)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`INSERT INTO sites (folder, status, due, name, sur, email, phone, code, raw)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING id`,
|
||||
directory, wstatus, due,
|
||||
name, surname, email, phone, country).Scan(&pkey); err != nil {
|
||||
name, surname, email, phone, country,
|
||||
editorData).Scan(&pkey); err != nil {
|
||||
log.Printf("Error: Could not register site to database: %v", err)
|
||||
return
|
||||
}
|
||||
|
@ -295,7 +296,8 @@ func CaptureOrder(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
var cart struct {
|
||||
Directory string `json:"directory"`
|
||||
Directory string `json:"directory"`
|
||||
EditorData json.RawMessage `json:"editor_data"`
|
||||
}
|
||||
|
||||
err = json.Unmarshal(info, &cart)
|
||||
|
@ -305,7 +307,15 @@ func CaptureOrder(w http.ResponseWriter, r *http.Request) {
|
|||
http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
directory := cart.Directory
|
||||
editorData := cart.EditorData
|
||||
if err != nil {
|
||||
http.Error(w,
|
||||
"Failed to parse request body",
|
||||
http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
path := strings.TrimPrefix(r.URL.Path, "/api/orders/")
|
||||
parts := strings.Split(path, "/")
|
||||
|
@ -374,7 +384,7 @@ func CaptureOrder(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
RegisterOrder(capture, directory)
|
||||
RegisterOrder(capture, directory, editorData)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(receipt); err != nil {
|
||||
|
|