huesos/mirzaev/arming_bot/system/public/js/modules/delivery.mjs

1059 lines
28 KiB
JavaScript
Executable File

"use strict";
/**
* @name Delivery
*
* @description
* Implements actions with delivery
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
export default class delivery {
/**
* @name Type of the program
*/
static type = "module";
/**
* @name Company (interface)
*
* @description
* Choose a delivery company
*
* @param {HTMLInputElement} company The button for choose a delivery company <input> (radio)
* @param {bool} force Ignore the damper? (false)
*
* @return {bool} Did the execution complete without errors?
*/
static company = (company, force = false) => {
if (company instanceof HTMLInputElement) {
// Initialized the delivery company <input> (radio) element
// Disabling the delivery company <input> (radio) element
company.setAttribute("disabled", true);
// Initializing timer of enabling the delivery company <input> (radio) element
const enabling = setTimeout(() => {
// Enabling the delivery company <input> (radio) element
company.removeAttribute("disabled");
}, 3000);
// Initializing the order <button> element
const order = document.getElementById("order");
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Disabling the order <button> element
order.setAttribute("disabled", true);
}
// Initializing the delivery data request <section> element
const request = document.getElementById("delivery_request");
/**
* @name Resolved
*
* @description
* Render the result of the resolved request
*
* @param {object} json
*
* @return {void}
*/
const resolved = (json) => {
if (json) {
// Received JSON-response
// Deinitializing timer of enabling the delivery company <input> (radio) element
clearTimeout(enabling);
// Enabling the delivery company <input> (radio) element
company.removeAttribute("disabled");
if (json.status === "success") {
// Received "success" status of execution
// Select the delivery company <input> (radio) element
company.checked = true;
}
if (json.ready) {
// Received readiness status
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Enabling the order <button> element
order.removeAttribute("disabled");
}
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("hidden");
}
} else {
// Not received readiness status or readiness status is false
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("hidden");
}
}
// Calculating delivery
this.calculate();
if (json.company) {
// Received company property
// Initializing the delivery company <input> (radio) element
const button = document.getElementById(json.company);
if (button instanceof HTMLInputElement) {
// Initialized the delivery company <input> (radio) element
// Select the delivery company <input> (radio) element
button.checked = true;
}
}
if (json.delivery) {
// Received delivery HTML-code
core.modules.connect(["telegram"])
.then(() => {
//
core.telegram.api.LocationManager.init(() => {
//if (core.telegram.api.LocationManager.isAccessRequested && !core.telegram.api.LocationManager.isAccessGranted) {
// alert('Предоставьте разрешение на доступ к геопозиции');
// core.telegram.api.LocationManager.openSettings();
//}
if (!core.telegram.api.LocationManager.isLocationAvailable) {
// Dispatching event
document.dispatchEvent(
new CustomEvent("core.telegram.api.location.rejected"),
);
} else {
core.telegram.api.LocationManager.getLocation(
(location) => {
// Dispatching event
document.dispatchEvent(
new CustomEvent(
"core.telegram.api.location.received",
{
detail: {
location,
},
},
),
);
},
);
}
});
});
// Initializing the deliveries <div> element
const deliveries = document.getElementById("deliveries");
if (deliveries instanceof HTMLElement) {
// Initialized the deliveries <div> element
// Initializing the deliveries <section> element
let section = deliveries.nextElementSibling;
if (section instanceof HTMLElement) {
// Initialized the deliveries <section> element
// Deinitializing the delivery <section> element
section.remove();
}
// Creating the delivery <section> element
section = document.createElement("section");
// Writing the delivery <section> element after the delivery <div> element
deliveries.parentElement.insertBefore(
section,
deliveries.nextElementSibling,
);
// Reinitializing the delivery <section> element
section.outerHTML = json.delivery.html;
// Reinitializing the deliveries <section> element
section = deliveries.nextElementSibling;
for (const javascript of json.delivery.javascript) {
// Received delivery JavaScript-code and delivery JavaScript-links
// Initializing the delivery JavaScript-code <script> element
const script = document.createElement("script");
script.setAttribute("defer", "true");
if (javascript.link) {
// Initializing the delivery JavaScript-link <script> element attributes
script.setAttribute("type", "text/javascript");
script.setAttribute("src", javascript.link);
script.setAttribute("charset", 'charset="utf-8');
} else if (javascript.code) {
// Delivery JavaScript-code
// Initializing the delivery JavaScript-code <script> element value
script.innerHTML = javascript.code;
}
// Writing the delivery JavaScript-code <script> element and executing the delivery JavaScript-code
section.appendChild(script);
}
}
}
}
};
/**
* @name Rejected
*
* @description
* Render the result of the rejected request
*
* @param {object} json
*
* @return {void}
*/
const rejected = (json) => {
if (json) {
// Received JSON-response
// Deinitializing timer of enabling the delivery company <input> (radio) element
clearTimeout(enabling);
// Enabling the delivery company <input> (radio) element
company.removeAttribute("disabled");
}
};
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Execute under damper
this.write.damper("company", company.getAttribute("id"), force)
.then(resolved, rejected);
},
() => {
// Not imported the damper module
// Execute
this.write.system("company", company.getAttribute("id"), force)
.then(resolved, rejected);
},
);
// Exit (success)
return true;
}
// Exit (fail)
return false;
};
/**
* @name Location (interface)
*
* @description
* Write name of the location for delivery
*
* @param {HTMLInputElement} location The input element with name of the location <input>
* @param {bool} force Ignore the damper? (false)
*
* @return {bool} Did the execution complete without errors?
*/
static location = (location, force = false) => {
if (location instanceof HTMLInputElement) {
// Initialized the location <input> element
// Deleting statuses from the location <input> element
location.classList.remove("success", "fail");
// Initializing the order <button> element
const order = document.getElementById("order");
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Disabling the order <button> element
order.setAttribute("disabled", true);
}
// Initializing the delivery data request <section> element
const request = document.getElementById("delivery_request");
/**
* @name Resolved
*
* @description
* Render the result of the resolved request
*
* @param {object} json
*
* @return {void}
*/
const resolved = (json) => {
if (json) {
// Received JSON-response
if (json.status) {
// Received status of execution
// Deleting statuses from the location <input> element
location.classList.remove("success", "fail");
// Writing status of execution as CSS class
location.classList.add(json.status);
}
if (json.ready) {
// Received readiness status
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Enabling the order <button> element
order.removeAttribute("disabled");
}
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("hidden");
}
} else {
// Not received readiness status or readiness status is false
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("hidden");
}
}
// Calculating delivery
this.calculate();
if (json.location) {
// Received location
if (json.location.identifier) {
// Received location identifier
if (location.value !== json.location) {
// The value entered differs from what was written on the server
// Writing attribute with location identifier
/* location.setAttribute(
"data-location-identifier",
json.location.identifier,
); */
// Writing CSS variable with location identifier
/* location.style.setProperty(
"--identifier",
json.location.identifier,
); */
}
}
if (json.location.input) {
// Received location value for <input> element
if (location.value !== json.location.input) {
// The value entered differs from what was written on the server
// Writing location property to the location <input> element
location.value = json.location.input;
}
}
}
if (json.locations) {
// Reveived locations suggestions
// Initializing the locations suggestions <datalist> element
let locations = document.getElementById("locations");
if (!(locations instanceof HTMLDataListElement)) {
// Not initialized the locations suggestions <datalist> element
// Initializing the locations suggestions <datalist> element
const datalist = document.createElement("datalist");
datalist.setAttribute("id", "locations");
// Connection the locations suggestions <datalist> element to the location <input> element
location.setAttribute("list", "locations");
// Writing the locations suggestions <datalist> element after the location <input> element
location.parentElement.insertBefore(
datalist,
location.nextElementSibling,
);
// Reinitializing the locations suggestions <datalist> element
locations = document.getElementById("locations");
}
}
if (locations instanceof HTMLDataListElement) {
// Initialized locations suggestions <datalist> element
// Initializing buffer of created options
const options = new Set();
for (const location of json.locations ?? []) {
// Iterating over locations suggestions
// Initializing the location <option> element
const option = document.createElement("option");
option.setAttribute(
"value",
(location.name + ", " + location.structure.reverse().join(", "))
.trim(),
);
// Writing to buffer of created options
options.add(option);
}
// Replacing content of the locations suggestions <datalist> element
locations.replaceChildren(...Array.from(options));
// locations.focus();
}
}
};
/**
* @name Rejected
*
* @description
* Render the result of the rejected request
*
* @param {object} json
*
* @return {void}
*/
const rejected = (json) => {
if (json) {
// Received JSON-response
if (json.status) {
// Reveived status of execution
// Deleting statuses from the location <input> element
location.classList.remove("success", "fail");
// Writing status of execution as CSS class
location.classList.add(json.status);
}
}
};
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Execute under damper
this.write.damper("location", location.value, force)
.then(resolved, rejected);
},
() => {
// Not imported the damper module
// Execute
this.write.system("location", location.value, force)
.then(resolved, rejected);
},
);
// Exit (success)
return true;
}
// Exit (fail)
return false;
};
/**
* @name Street (interface)
*
* @description
* Write name of the street for delivery
*
* @param {HTMLInputElement} element The input element with name of the street <input>
* @param {bool} force Ignore the damper? (false)
*
* @return {bool} Did the execution complete without errors?
*/
static street = (street, force = false) => {
if (street instanceof HTMLInputElement) {
// Initialized the street <input> element
// Deleting statuses from the street <input> element
street.classList.remove("success", "fail");
// Initializing the order <button> element
const order = document.getElementById("order");
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Disabling the order <button> element
order.setAttribute("disabled", true);
}
// Initializing the delivery data request <section> element
const request = document.getElementById("delivery_request");
/**
* @name Resolved
*
* @description
* Render the result of the resolved request
*
* @param {object} json
*
* @return {void}
*/
const resolved = (json) => {
if (json) {
// Received JSON-response
if (json.status) {
// Reveived status of execution
// Deleting statuses from the street <input> element
street.classList.remove("success", "fail");
// Writing status of execution as CSS class
street.classList.add(json.status);
}
if (json.ready) {
// Received readiness status
if (order instanceof HTMLButtonElement) {
// Initializeg the order <button> element
// Enabling the order <button> element
order.removeAttribute("disabled");
}
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.add("hidden");
}
core.modules.connect("telegram").then(() => {
// Imported the telegram module
core.telegram.api.HapticFeedback.notificationOccurred("success");
});
} else {
// Not received readiness status or readiness status is false
if (request instanceof HTMLElement) {
// Initializeg the delivery data request <section> element
// Hiding the delivery data request <section> element
request.classList.remove("hidden");
}
}
// Calculating delivery
this.calculate();
if (json.street) {
// Received street property
if (street.value !== json.street) {
// The value entered differs from what was written on the server
// Writing street property to the street element <input>
street.value = json.street;
}
}
}
};
/**
* @name Rejected
*
* @description
* Render the result of the rejected request
*
* @param {object} json
*
* @return {void}
*/
const rejected = (json) => {
if (json) {
// Received JSON-response
if (json.status) {
// Reveived status of execution
// Deleting statuses from the street <input> element
street.classList.remove("success", "fail");
// Writing status of execution as CSS class
street.classList.add(json.status);
}
}
};
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Execute under damper
this.write.damper("street", street.value, force)
.then(resolved, rejected);
},
() => {
// Not imported the damper module
// Execute
this.write.system("street", street.value, force)
.then(resolved, rejected);
},
);
// Exit (success)
return true;
}
// Exit (fail)
return false;
};
/**
* @name Write (interface)
*
* @return {void}
*/
static write = () => {};
/**
* @name Calculate (interface)
*
* @description
* Calculate delivery by validated data from buffers
*
* @return {bool} Did the execution complete without errors?
*/
static calculate = () => {
core.modules.connect("damper").then(
() => {
// Imported the damper module
// Execute under damper
this.calculate.damper();
},
() => {
// Not imported the damper module
// Execute
this.calculate.system();
},
);
// Exit (success)
return true;
};
}
core.modules.connect("damper").then(() => {
// Imported the damper module
Object.assign(
delivery.write,
{
/**
* @name Write (damper)
*
* @description
* Validate and write a delivery parameter into buffers
*
* @memberof delivery.write
*
* @param {string} name Name of the parameter
* @param {string|number} value Value of the parameter
* @param {bool} force Ignore the damper? (false)
*
* @return {Promise}
*/
damper: core.damper(
(...variables) => delivery.write.system(...variables),
400,
3,
),
},
);
Object.assign(
delivery.calculate,
{
/**
* @name Calculate (damper)
*
* @description
* Calculate delivery by validated data from buffers
*
* @memberof delivery.calculate
*
* @return {Promise}
*/
damper: core.damper(
(...variables) => delivery.calculate.system(...variables),
200,
),
},
);
});
Object.assign(
delivery.write,
{
/**
* @name Write (system)
*
* @description
* Validate and write a delivery parameter into buffers
*
* @memberof delivery.write
*
* @param {string} name Name of the parameter
* @param {string|number} value Value of the parameter
*
* @return {Promise}
*/
async system(
name,
value,
resolve = () => {},
reject = () => {},
) {
try {
if (
typeof name === "string" &&
(typeof value === "string" || typeof value === "number")
) {
// Received and validated required arguments
// Sending request to the server
return await core.request(
"/delivery/write",
`${name}=${value}`,
"PATCH",
)
.then(
(json) => {
if (json) {
// Received a JSON-response
if (
json.errors !== null &&
typeof json.errors === "object" &&
json.errors.length > 0
) {
// Fail (received errors)
// Exit (fail)
reject(json);
} else {
// Success (not received errors)
if (json.validated) {
// Validated delivery data from all fields
// Unblocking the "continue" button in the summary <section> element
document.getElementById("summary")
?.classList.remove("disabled");
}
// Exit (success)
resolve(json);
}
}
},
() => reject(),
);
}
} catch (e) {
// Exit (fail)
reject(e);
}
},
},
);
Object.assign(
delivery.calculate,
{
/**
* @name Calculate (system)
*
* @description
* Calculate delivery by validated data from buffers
*
* @memberof delivery.calculate
*
* @return {Promise}
*/
async system(
resolve = () => {},
reject = () => {},
) {
try {
// Sending request to the server
return await core.request(
"/delivery/calculate",
undefined,
"GET",
)
.then(
(json) => {
if (json) {
// Received JSON-response
if (json.cost) {
// Received delivery cost
// Initializing the delivery cost <span> element
const cost = document.getElementById("cost_delivery");
if (cost instanceof HTMLElement) {
// Initialized the delivery cost <span> element
// Writing delivery cost to the delivery cost <span> element
cost.innerText = json.cost;
} else {
// Not initialized the delivery cost <span> element
// Initializing the delivery cost <span> element
const cost = document.createElement("span");
cost.setAttribute("id", "cost_delivery");
cost.classList.add(
"cost",
"delivery",
"currency",
"plus",
"hint",
);
// Initializing the products cost <span> element
const products = document.getElementById("cost");
if (products instanceof HTMLElement) {
// Initialized the products cost <span> element
// Writing the delivery cost <span> element after the products cost <span> element
products.parentElement.insertBefore(
cost,
products.nextElementSibling,
);
} else {
// Not initialized the products cost <span> element
// Initializing the products amount <span> element
const amount = document.getElementById("cost");
if (amount instanceof HTMLElement) {
// Initialized the products amount <span> element
// Writing the delivery cost <span> element after the products amount <span> element
amount.parentElement.insertBefore(
cost,
amount.nextElementSibling,
);
} else {
// Not initialized the products amount <span> element
// Initializing the order <button> element
const order = document.getElementById("cost");
if (order instanceof HTMLButtonElement) {
// Initialized the order <button> element
// Writing the delivery cost <span> element before the order <button> element
order.parentElement.insertBefore(
cost,
order,
);
} else {
// Not initialized the order <button> element
// Initializing the summary first row <div> element
const summary = core.main.querySelector(
"#summary>div.row",
);
if (summary instanceof HTMLElement) {
// Initialized the summary first row <div> element
// Writing the delivery cost <span> element into the summary first row <div> element
summary.appendChild(cost);
}
}
}
}
// Writing delivery cost to the delivery cost <span> element
cost.innerText = json.cost;
}
} else {
// Not received delivery cost
// Deleting the delivery cost <span> element
document.getElementById("cost_delivery")?.remove();
}
if (json.days) {
// Received delivery days
// Initializing the delivery days <span> element
const days = document.getElementById("shipping");
if (days instanceof HTMLElement) {
// Initialized the delivery days <span> element
// Writing delivery days to the delivery days <span> element
days.innerText = json.days;
} else {
// Not initialized the delivery days <span> element
// Initializing the delivery days <span> element
const days = document.createElement("span");
days.setAttribute("id", "shipping");
days.classList.add("delivery", "days", "hint");
// Initializing the delivery cost <span> element
const cost = document.getElementById("cost_delivery");
if (cost instanceof HTMLElement) {
// Initialized the delivery cost <span> element
// Writing the delivery days <span> element after the delivery cost <span> element
cost.parentElement.insertBefore(
days,
cost.nextElementSibling,
);
} else {
// Not initialized the delivery cost <span> element
// Initializing the products cost <span> element
const products = document.getElementById("cost");
if (products instanceof HTMLElement) {
// Initialized the products cost <span> element
// Writing the delivery days <span> element after the products cost <span> element
products.parentElement.insertBefore(
days,
products.nextElementSibling,
);
} else {
// Not initialized the products cost <span> element
// Initializing the products amount <span> element
const amount = document.getElementById("cost");
if (amount instanceof HTMLElement) {
// Initialized the products amount <span> element
// Writing the delivery days <span> element after the products amount <span> element
amount.parentElement.insertBefore(
days,
amount.nextElementSibling,
);
} else {
// Not initialized the products amount <span> element
// Initializing the order <button> element
const order = document.getElementById("cost");
if (order instanceof HTMLButtonElement) {
// Initialized the order <button> element
// Writing the delivery days <span> element before the order <button> element
order.parentElement.insertBefore(
days,
order,
);
} else {
// Not initialized the order <button> element
// Initializing the summary first row <div> element
const summary = core.main.querySelector(
"#summary>div.row",
);
if (summary instanceof HTMLElement) {
// Initialized the summary first row <div> element
// Writing the delivery days <span> element into the summary first row <div> element
summary.appendChild(days);
}
}
}
}
}
// Writing delivery days to the delivery days <span> element
days.innerText = json.days;
}
} else {
// Not received delivery days
// Deleting the delivery days <span> element
document.getElementById("shipping")?.remove();
}
// Dispatching event
document.dispatchEvent(
new CustomEvent("core.delivery.calculated", {
detail: {
json,
},
}),
);
// Exit (success)
resolve(json);
}
},
() => reject(),
);
} catch (e) {
// Exit (fail)
reject(e);
}
},
},
);
// Connecting to the core
if (!core.delivery) core.delivery = delivery;