develop #8
|
@ -23,7 +23,6 @@
|
|||
"source.fixAll.eslint",
|
||||
"source.fixAll.stylelint"
|
||||
],
|
||||
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
|
@ -61,11 +60,6 @@
|
|||
"terminal.integrated.enableImages": true,
|
||||
"figma.autocompleteBlocks": true,
|
||||
"figma.assetExportDirectory": "src/assets",
|
||||
"editor.codeActionsOnSave": [
|
||||
"source.addMissingImports",
|
||||
"source.organizeImports",
|
||||
"source.fixAll.eslint"
|
||||
],
|
||||
"gitlens.gitCommands.skipConfirmations": ["fetch:command", "switch:command"],
|
||||
"diffEditor.ignoreTrimWhitespace": false,
|
||||
"svg.preview.mode": "svg",
|
||||
|
@ -78,8 +72,5 @@
|
|||
"workbench.tree.indent": 16,
|
||||
"window.zoomLevel": -1,
|
||||
"git.ignoreRebaseWarning": true,
|
||||
"editor.largeFileOptimizations": false,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
}
|
||||
"editor.largeFileOptimizations": false
|
||||
}
|
||||
|
|
|
@ -2,4 +2,8 @@ HOST="127.0.0.1"
|
|||
DB_USER="root"
|
||||
DB_PASSWORD="root"
|
||||
PORT ="3306"
|
||||
DATABASE="floranet"
|
||||
DATABASE="floranet"
|
||||
BASE_URL =http://localhost:9100
|
||||
|
||||
CLIENT_ID="Ab5vEddhdvdJhLUkXtTiS2pe43W6PD1JNKns7XMnlw8FvC31H2VYakyVEHvuFBi2b543QIHiPh8j4FLF"
|
||||
SECRET_KEY="EAxLf05kp08cvbLgZrqjwdx-NXnhQtnP4Y0B4LHAM_7T9-HOh4RaNTirinWfTV8GR6DJWg9djry5yHfO"
|
|
@ -0,0 +1,146 @@
|
|||
const db = require("../../db/db");
|
||||
const paypal = require('paypal-rest-sdk');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
class PaymentController {
|
||||
async Create(req, res) {
|
||||
|
||||
//parâmetros para retornar os produtos que serão comprados
|
||||
const products = req.body.products
|
||||
//parameters to return price
|
||||
const price = req.body.price
|
||||
let productsIds = ''
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
productsIds += `${products[i]}${i === products.length - 1 ? '' : '-'}`
|
||||
}
|
||||
|
||||
//json for checkout
|
||||
var payReq = JSON.stringify({
|
||||
'intent': 'sale',
|
||||
'redirect_urls': {
|
||||
'return_url': `${process.env.BASE_URL}/checkout/success?productsIds=${productsIds}`,
|
||||
'cancel_url': `${process.env.BASE_URL}/checkout/error`
|
||||
},
|
||||
'payer': {
|
||||
'payment_method': 'paypal'
|
||||
},
|
||||
'transactions': [{
|
||||
'amount': {
|
||||
'total': price,
|
||||
'currency': 'EUR'
|
||||
},
|
||||
'description': 'This is the payment transaction description.'
|
||||
}]
|
||||
});
|
||||
|
||||
//Starting checkout process and returning sandbox url
|
||||
try {
|
||||
let urlRedirect
|
||||
urlRedirect = await new Promise(async (resolve, reject) => {
|
||||
paypal.payment.create(payReq, function (error, payment) {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
//capture HATEOAS links
|
||||
var links = {};
|
||||
payment.links.forEach(function (linkObj) {
|
||||
links[linkObj.rel] = {
|
||||
'href': linkObj.href,
|
||||
'method': linkObj.method
|
||||
};
|
||||
})
|
||||
//if redirect url present, redirect user
|
||||
if (links.hasOwnProperty('approval_url')) {
|
||||
resolve(links['approval_url'].href)
|
||||
} else {
|
||||
console.error('no redirect URI present');
|
||||
}
|
||||
}
|
||||
});
|
||||
}).then(res => res)
|
||||
if (urlRedirect) {
|
||||
return res.status(200).send({
|
||||
data: urlRedirect
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
return res.status(422).send({
|
||||
data: {
|
||||
message: "Error when starting payment"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async Success(req, res) {
|
||||
//Parameters for validating payment and purchased products
|
||||
const paramns = JSON.parse(req.body.data)
|
||||
const custumer = paramns.custumer
|
||||
const productsIds = paramns.productsIds
|
||||
const productsArray = productsIds.split('-')
|
||||
const products = productsArray.map(Number)
|
||||
const _products = await db.getProducts();
|
||||
const productsFilter = _products[0].filter((item) => {
|
||||
if (products.includes(item.id)) {
|
||||
return item
|
||||
}
|
||||
});
|
||||
|
||||
const paymentId = paramns.paymentId;
|
||||
const payerId = { 'payer_id': paramns.PayerID };
|
||||
|
||||
const jsonOrderData = JSON.stringify({
|
||||
"paymentId": paymentId,
|
||||
"custumer": custumer,
|
||||
"products": productsFilter
|
||||
})
|
||||
|
||||
fs.writeFileSync('order.json', jsonOrderData, 'utf-8')
|
||||
const contentOrder = fs.readFileSync('order.json', 'utf-8');
|
||||
//API validation and data
|
||||
paypal.payment.execute(paymentId, payerId, async function (error, payment) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return res.status(422).send({
|
||||
data: {
|
||||
message: "payment not successful"
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (payment.state == 'approved') {
|
||||
await db.orderData_put(contentOrder);
|
||||
return res.status(200).send({
|
||||
data: {
|
||||
id: payment.id,
|
||||
email: payment.payer.payer_info.email,
|
||||
message: "payment completed successfully",
|
||||
products: productsFilter
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return res.status(422).send({
|
||||
data: {
|
||||
message: "payment not successful"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
/* return res.status(200).send({
|
||||
data: {
|
||||
menssage: "sucesso"
|
||||
}
|
||||
}) */
|
||||
}
|
||||
|
||||
Cancel(req, res) {
|
||||
return res.status(200).send({
|
||||
data: {
|
||||
menssage: "cancelado"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new PaymentController();
|
|
@ -1,4 +1,4 @@
|
|||
const db = require("../db/db");
|
||||
const db = require("../../db/db");
|
||||
|
||||
const productsJson = require("./products.json")
|
||||
|
||||
|
@ -7,28 +7,14 @@ class ProductController {
|
|||
|
||||
const params = req.query;
|
||||
const _products = await db.getProducts(params.dateExpired, params.postalCode);
|
||||
let productsFilter = _products[0];
|
||||
let productsFilter = _products[0]
|
||||
|
||||
if (Number(params.recommend)) {
|
||||
productsFilter = productsFilter.filter(item => item.recommend == Number(params.recommend))
|
||||
productsFilter = productsFilter.filter(item => item.recommend == params.recommend)
|
||||
}
|
||||
if (params.type) {
|
||||
productsFilter = productsFilter.filter(item => item.type === params.type)
|
||||
}
|
||||
/*if (params.postalCode) {
|
||||
productsFilter = productsFilter.filter(item => item.postalCode === params.postalCode)
|
||||
}
|
||||
if (params.dateExpired) {
|
||||
const dateSearch = new Date(params.dateExpired);
|
||||
productsFilter = productsFilter.filter(item => {
|
||||
const dateProduct = new Date(item.dateExpired);
|
||||
if (dateProduct >= dateSearch) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
}*/
|
||||
console.log(productsFilter.length);
|
||||
|
||||
|
||||
if (params.minPrice && !params.maxPrice) {
|
||||
productsFilter = productsFilter.filter(item => {
|
||||
|
@ -105,6 +91,7 @@ class ProductController {
|
|||
products: products
|
||||
}) */
|
||||
|
||||
|
||||
return res.status(200).send({
|
||||
data: productsFilter
|
||||
})
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
const db = require("../../db/db");
|
||||
|
||||
class ProvincesController {
|
||||
async findAll(req, res) {
|
||||
const params = req.query;
|
||||
const tmpProvinces = await db.getProvinces();
|
||||
|
||||
let provinces = [];
|
||||
|
||||
tmpProvinces.forEach(element => {
|
||||
provinces = [...provinces,{
|
||||
code: element.id,
|
||||
name: element.name
|
||||
}];
|
||||
})
|
||||
|
||||
return res.status(200).send({
|
||||
data: provinces
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new ProvincesController();
|
36
api/db/db.js
36
api/db/db.js
|
@ -12,17 +12,47 @@ async function connect() {
|
|||
|
||||
const mysql = require("mysql2/promise");
|
||||
const connection = await mysql.createConnection("mysql://" + user + ":" + password + "@" + host + ":" + port + "/" + database + "");
|
||||
console.log("Connected to MySQL!");
|
||||
global.connection = connection;
|
||||
return connection;
|
||||
}
|
||||
|
||||
//Procedure for get products
|
||||
async function getProducts(dateExpired, postalCode) {
|
||||
console.log("Query in table MySQL!");
|
||||
const conn = await connect();
|
||||
const [rows] = await conn.query(`CALL catalogue_get("${dateExpired}", "${postalCode}")`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
//Procedure for create transactions, do not carry out any manipulation at the bank
|
||||
async function orderData_put(jsonOrderData) {
|
||||
const conn = await connect();
|
||||
console.log(jsonOrderData);
|
||||
const [rows] = await conn.query(`CALL orderData_put(?)`, [jsonOrderData], (err, results) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log('Result:', results);
|
||||
}
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
|
||||
module.exports = { getProducts }
|
||||
//Procedure for get transactions, do not carry out any manipulation at the bank
|
||||
async function orderData_get() {
|
||||
const conn = await connect();
|
||||
const [rows] = await conn.query(`CALL orderData_get()`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
async function getProvinces() {
|
||||
const conn = await connect();
|
||||
const [rows] = await conn.query(`SELECT p.id, p.name, c.code, c.country
|
||||
FROM vn.province p
|
||||
JOIN vn.country c ON c.id = p.countryFk
|
||||
WHERE c.country IN('España', 'Francia', 'Portugal')`);
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
module.exports = { getProducts, orderData_get, orderData_put, getProvinces }
|
23
api/index.js
23
api/index.js
|
@ -1,7 +1,16 @@
|
|||
const cors = require('cors');
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const productController = require('./controller/product.controller');
|
||||
const paypal = require('paypal-rest-sdk');
|
||||
const productController = require('./controller/product/product.controller');
|
||||
const paymengtController = require('./controller/payment/payment.controller');
|
||||
const provincesController = require('./controller/provinces/provinces.controller');
|
||||
|
||||
paypal.configure({
|
||||
'mode': 'sandbox',
|
||||
'client_id': process.env.CLIENT_ID,
|
||||
'client_secret': process.env.SECRET_KEY
|
||||
});
|
||||
|
||||
const app = express();
|
||||
const port = 9999;
|
||||
|
@ -11,8 +20,16 @@ const corsOptions = {
|
|||
origin: allowedOrigins,
|
||||
optionsSuccessStatus: 200,
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
express.urlencoded({
|
||||
extended: true,
|
||||
}),
|
||||
);
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
const indexPath = path.join(__dirname, './', 'index.html');
|
||||
res.sendFile(indexPath);
|
||||
|
@ -21,6 +38,10 @@ app.get('/', (req, res) => {
|
|||
//Products
|
||||
app.get('/api/products', productController.findAll);
|
||||
app.get('/api/products/:id', productController.findById);
|
||||
app.post('/api/payment/', paymengtController.Create)
|
||||
app.post('/api/payment/success', paymengtController.Success)
|
||||
app.get('/api/payment/cancel', paymengtController.Cancel)
|
||||
app.get('/api/provinces', provincesController.findAll)
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server listening at http://localhost:${port}`);
|
||||
|
|
|
@ -8,8 +8,5 @@
|
|||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2"
|
||||
}
|
||||
"license": "ISC"
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
"@vueuse/core": "^10.7.0",
|
||||
"axios": "^1.2.1",
|
||||
"express": "^4.18.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"mysql2": "^3.7.0",
|
||||
"paypal-rest-sdk": "^1.8.1",
|
||||
"pinia": "^2.0.11",
|
||||
"quasar": "^2.6.0",
|
||||
"vee-validate": "^4.12.2",
|
||||
|
@ -54,9 +56,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz",
|
||||
"integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==",
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
|
||||
"integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
|
@ -133,9 +135,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@faker-js/faker": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.3.1.tgz",
|
||||
"integrity": "sha512-FdgpFxY6V6rLZE9mmIBb9hM0xpfvQOSNOLnzolzKwsE1DH+gC7lEKV1p1IbR0lAYyvYd5a4u3qWJzowUkw1bIw==",
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.0.tgz",
|
||||
"integrity": "sha512-htW87352wzUCdX1jyUQocUcmAaFqcR/w082EC8iP/gtkF0K+aKcBp0hR5Arb7dzR8tQ1TrhE9DNa5EbJELm84w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -149,13 +151,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.13",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
||||
"integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.1",
|
||||
"debug": "^4.1.1",
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -176,9 +178,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
|
||||
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@intlify/bundle-utils": {
|
||||
|
@ -206,12 +208,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "9.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.9.0.tgz",
|
||||
"integrity": "sha512-C7UXPymDIOlMGSNjAhNLtKgzITc/8BjINK5gNKXg8GiWCTwL6n3MWr55czksxn8RM5wTMz0qcLOFT+adtaVQaA==",
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.9.1.tgz",
|
||||
"integrity": "sha512-qsV15dg7jNX2faBRyKMgZS8UcFJViWEUPLdzZ9UR0kQZpFVeIpc0AG7ZOfeP7pX2T9SQ5jSiorq/tii9nkkafA==",
|
||||
"dependencies": {
|
||||
"@intlify/message-compiler": "9.9.0",
|
||||
"@intlify/shared": "9.9.0"
|
||||
"@intlify/message-compiler": "9.9.1",
|
||||
"@intlify/shared": "9.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
|
@ -221,11 +223,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@intlify/message-compiler": {
|
||||
"version": "9.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.9.0.tgz",
|
||||
"integrity": "sha512-yDU/jdUm9KuhEzYfS+wuyja209yXgdl1XFhMlKtXEgSFTxz4COZQCRXXbbH8JrAjMsaJ7bdoPSLsKlY6mXG2iA==",
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.9.1.tgz",
|
||||
"integrity": "sha512-zTvP6X6HeumHOXuAE1CMMsV6tTX+opKMOxO1OHTCg5N5Sm/F7d8o2jdT6W6L5oHUsJ/vvkGefHIs7Q3hfowmsA==",
|
||||
"dependencies": {
|
||||
"@intlify/shared": "9.9.0",
|
||||
"@intlify/shared": "9.9.1",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -236,9 +238,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@intlify/shared": {
|
||||
"version": "9.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.9.0.tgz",
|
||||
"integrity": "sha512-1ECUyAHRrzOJbOizyGufYP2yukqGrWXtkmTu4PcswVnWbkcjzk3YQGmJ0bLkM7JZ0ZYAaohLGdYvBYnTOGYJ9g==",
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.9.1.tgz",
|
||||
"integrity": "sha512-b3Pta1nwkz5rGq434v0psHwEwHGy1pYCttfcM22IE//K9owbpkEvFptx9VcuRAxjQdrO2If249cmDDjBu5wMDA==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
|
@ -336,9 +338,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@quasar/app-vite": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@quasar/app-vite/-/app-vite-1.7.1.tgz",
|
||||
"integrity": "sha512-cs3ix7w8f7884JiTp3EW6auZ9R+Fg4qoPxEZ7VRGOrSsUg5oQtR/i91jeQk4Z96J/JUOqtcKqdqbzN4fzaFyIg==",
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@quasar/app-vite/-/app-vite-1.7.3.tgz",
|
||||
"integrity": "sha512-pnDInCFP9M1d7lJzS8UkiFq8bGWdekLz8Gu+NLI9UAxruIM9QVlSD4hUmWptTQXaVEvYlDnqfW3LOr57B8eVtw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@quasar/render-ssr-error": "^1.0.3",
|
||||
|
@ -579,9 +581,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
"version": "4.17.41",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
|
||||
"integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
|
||||
"version": "4.17.42",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.42.tgz",
|
||||
"integrity": "sha512-ckM3jm2bf/MfB3+spLPWYPUH573plBFwpOhqQ2WottxYV85j1HQFlxmnTq57X1yHY9awZPig06hL/cLMgNWHIQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
|
@ -600,9 +602,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/filewriter": {
|
||||
"version": "0.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.32.tgz",
|
||||
"integrity": "sha512-Kpi2GXQyYJdjL8mFclL1eDgihn1SIzorMZjD94kdPZh9E4VxGOeyjPxi5LpsM4Zku7P0reqegZTt2GxhmA9VBg==",
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz",
|
||||
"integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/har-format": {
|
||||
|
@ -624,9 +626,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.10.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.8.tgz",
|
||||
"integrity": "sha512-f8nQs3cLxbAFc00vEU59yf9UyGUftkPaLGfvbVOIDdx2i1b8epBqj2aNGyP19fiyXWvlmZ7qC1XLjAzw/OKIeA==",
|
||||
"version": "20.11.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.13.tgz",
|
||||
"integrity": "sha512-5G4zQwdiQBSWYTDAH1ctw2eidqdhMJaNsiIDKHFr55ihz5Trl2qqR8fdrT732yPBho5gkNxXm67OxWFBqX9aPg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
|
@ -677,12 +679,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@vee-validate/zod": {
|
||||
"version": "4.12.4",
|
||||
"resolved": "https://registry.npmjs.org/@vee-validate/zod/-/zod-4.12.4.tgz",
|
||||
"integrity": "sha512-iNFhkBfGkre2b+eBXgBpNlNVStxDrI59sJUbzBr01EjyTkFOUgc/0wPJrhY/kBp+0pnGzNi04jklJaKfNK2ibg==",
|
||||
"version": "4.12.5",
|
||||
"resolved": "https://registry.npmjs.org/@vee-validate/zod/-/zod-4.12.5.tgz",
|
||||
"integrity": "sha512-hUjvXaa4HHvlZeosucViIDOUikQmyKaXXuL6P8LR1ETOUrBV6ntTsafJGvRYtwhXosoLYuolUD6Km737okK4Gg==",
|
||||
"dependencies": {
|
||||
"type-fest": "^4.8.3",
|
||||
"vee-validate": "4.12.4",
|
||||
"vee-validate": "4.12.5",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
},
|
||||
|
@ -709,49 +711,49 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.7.tgz",
|
||||
"integrity": "sha512-hhCaE3pTMrlIJK7M/o3Xf7HV8+JoNTGOQ/coWS+V+pH6QFFyqtoXqQzpqsNp7UK17xYKua/MBiKj4e1vgZOBYw==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.15.tgz",
|
||||
"integrity": "sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/shared": "3.4.7",
|
||||
"@vue/shared": "3.4.15",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.7.tgz",
|
||||
"integrity": "sha512-qDKBAIurCTub4n/6jDYkXwgsFuriqqmmLrIq1N2QDfYJA/mwiwvxi09OGn28g+uDdERX9NaKDLji0oTjE3sScg==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz",
|
||||
"integrity": "sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.4.7",
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/compiler-core": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.7.tgz",
|
||||
"integrity": "sha512-Gec6CLkReVswDYjQFq79O5rktri4R7TsD/VPCiUoJw40JhNNxaNJJa8mrQrWoJluW4ETy6QN0NUyC/JO77OCOw==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz",
|
||||
"integrity": "sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/compiler-core": "3.4.7",
|
||||
"@vue/compiler-dom": "3.4.7",
|
||||
"@vue/compiler-ssr": "3.4.7",
|
||||
"@vue/shared": "3.4.7",
|
||||
"@vue/compiler-core": "3.4.15",
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/compiler-ssr": "3.4.15",
|
||||
"@vue/shared": "3.4.15",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss": "^8.4.33",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.7.tgz",
|
||||
"integrity": "sha512-PvYeSOvnCkST5mGS0TLwEn5w+4GavtEn6adcq8AspbHaIr+mId5hp7cG3ASy3iy8b+LuXEG2/QaV/nj5BQ/Aww==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz",
|
||||
"integrity": "sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.7",
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
|
@ -760,57 +762,57 @@
|
|||
"integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA=="
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.7.tgz",
|
||||
"integrity": "sha512-F539DO0ogH0+L8F9Pnw7cjqibcmSOh5UTk16u5f4MKQ8fraqepI9zdh+sozPX6VmEHOcjo8qw3Or9ZcFFw4SZA==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.15.tgz",
|
||||
"integrity": "sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.7.tgz",
|
||||
"integrity": "sha512-QMMsWRQaD3BpGyjjChthpl4Mji4Fjx1qfdufsXlDkKU3HV+hWNor2z+29F+E1MmVcP0ZfRZUfqYgtsQoL7IGwQ==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.15.tgz",
|
||||
"integrity": "sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.4.7",
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/reactivity": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.7.tgz",
|
||||
"integrity": "sha512-XwegyUY1rw8zxsX1Z36vwYcqo+uOgih5ti7y9vx+pPFhNdSQmN4LqK2RmSeAJG1oKV8NqSUmjpv92f/x6h0SeQ==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz",
|
||||
"integrity": "sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.4.7",
|
||||
"@vue/shared": "3.4.7",
|
||||
"@vue/runtime-core": "3.4.15",
|
||||
"@vue/shared": "3.4.15",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.7.tgz",
|
||||
"integrity": "sha512-3bWnYLEkLLhkDWqvNk7IvbQD4UcxvFKxELBiOO2iG3m6AniFIsBWfHOO5tLVQnjdWkODu4rq0GipmfEenVAK5Q==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.15.tgz",
|
||||
"integrity": "sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.4.7",
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/compiler-ssr": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.4.7"
|
||||
"vue": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.7.tgz",
|
||||
"integrity": "sha512-G+i4glX1dMJk88sbJEcQEGWRQnVm9eIY7CcQbO5dpdsD9SF8jka3Mr5OqZYGjczGN1+D6EUwdu6phcmcx9iuPA=="
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g=="
|
||||
},
|
||||
"node_modules/@vueuse/core": {
|
||||
"version": "10.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.7.1.tgz",
|
||||
"integrity": "sha512-74mWHlaesJSWGp1ihg76vAnfVq9NTv1YT0SYhAQ6zwFNdBkkP+CKKJmVOEHcdSnLXCXYiL5e7MaewblfiYLP7g==",
|
||||
"version": "10.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.7.2.tgz",
|
||||
"integrity": "sha512-AOyAL2rK0By62Hm+iqQn6Rbu8bfmbgaIMXcE3TSr7BdQ42wnSFlwIdPjInO62onYsEMK/yDMU8C6oGfDAtZ2qQ==",
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "^0.0.20",
|
||||
"@vueuse/metadata": "10.7.1",
|
||||
"@vueuse/shared": "10.7.1",
|
||||
"@vueuse/metadata": "10.7.2",
|
||||
"@vueuse/shared": "10.7.2",
|
||||
"vue-demi": ">=0.14.6"
|
||||
},
|
||||
"funding": {
|
||||
|
@ -843,17 +845,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vueuse/metadata": {
|
||||
"version": "10.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.7.1.tgz",
|
||||
"integrity": "sha512-jX8MbX5UX067DYVsbtrmKn6eG6KMcXxLRLlurGkZku5ZYT3vxgBjui2zajvUZ18QLIjrgBkFRsu7CqTAg18QFw==",
|
||||
"version": "10.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.7.2.tgz",
|
||||
"integrity": "sha512-kCWPb4J2KGrwLtn1eJwaJD742u1k5h6v/St5wFe8Quih90+k2a0JP8BS4Zp34XUuJqS2AxFYMb1wjUL8HfhWsQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/shared": {
|
||||
"version": "10.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.7.1.tgz",
|
||||
"integrity": "sha512-v0jbRR31LSgRY/C5i5X279A/WQjD6/JsMzGa+eqt658oJ75IvQXAeONmwvEMrvJQKnRElq/frzBR7fhmWY5uLw==",
|
||||
"version": "10.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.7.2.tgz",
|
||||
"integrity": "sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==",
|
||||
"dependencies": {
|
||||
"vue-demi": ">=0.14.6"
|
||||
},
|
||||
|
@ -920,9 +922,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
|
||||
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
|
||||
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
|
@ -1109,9 +1111,9 @@
|
|||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.16",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
|
||||
"integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
|
||||
"version": "10.4.17",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz",
|
||||
"integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1128,9 +1130,9 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"browserslist": "^4.21.10",
|
||||
"caniuse-lite": "^1.0.30001538",
|
||||
"fraction.js": "^4.3.6",
|
||||
"browserslist": "^4.22.2",
|
||||
"caniuse-lite": "^1.0.30001578",
|
||||
"fraction.js": "^4.3.7",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
|
@ -1146,9 +1148,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -1286,9 +1288,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.22.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz",
|
||||
"integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==",
|
||||
"version": "4.22.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz",
|
||||
"integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1305,8 +1307,8 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001565",
|
||||
"electron-to-chromium": "^1.4.601",
|
||||
"caniuse-lite": "^1.0.30001580",
|
||||
"electron-to-chromium": "^1.4.648",
|
||||
"node-releases": "^2.0.14",
|
||||
"update-browserslist-db": "^1.0.13"
|
||||
},
|
||||
|
@ -1345,7 +1347,6 @@
|
|||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
|
@ -1392,9 +1393,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001576",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz",
|
||||
"integrity": "sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==",
|
||||
"version": "1.0.30001581",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz",
|
||||
"integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1948,9 +1949,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.625",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.625.tgz",
|
||||
"integrity": "sha512-DENMhh3MFgaPDoXWrVIqSPInQoLImywfCwrSmVl3cf9QHzoZSiutHwGaB/Ql3VkqcQV30rzgdM+BjKqBAJxo5Q==",
|
||||
"version": "1.4.651",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.651.tgz",
|
||||
"integrity": "sha512-jjks7Xx+4I7dslwsbaFocSwqBbGHQmuXBJUK9QBZTIrzPq3pzn6Uf2szFSP728FtLYE3ldiccmlkOM/zhGKCpA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/elementtree": {
|
||||
|
@ -2461,9 +2462,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.19.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.19.2.tgz",
|
||||
"integrity": "sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==",
|
||||
"version": "9.21.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.21.0.tgz",
|
||||
"integrity": "sha512-B3NgZRtbi9kSl7M0x/PqhSMk7ULJUwWxQpTvM8b2Z6gNTORK0YSt5v1vzwY84oMs/2+3BWH5XmTepaQebcJwfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
|
@ -2471,7 +2472,7 @@
|
|||
"nth-check": "^2.1.1",
|
||||
"postcss-selector-parser": "^6.0.13",
|
||||
"semver": "^7.5.4",
|
||||
"vue-eslint-parser": "^9.3.1",
|
||||
"vue-eslint-parser": "^9.4.2",
|
||||
"xml-name-validator": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2764,9 +2765,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
|
||||
"integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz",
|
||||
"integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
|
@ -2896,9 +2897,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.4",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
@ -2956,6 +2957,11 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs": {
|
||||
"version": "0.0.1-security",
|
||||
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
|
||||
"integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w=="
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
|
@ -3256,9 +3262,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
|
||||
"integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz",
|
||||
"integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
|
@ -3859,15 +3865,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
|
||||
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
|
@ -4076,9 +4078,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.7.0.tgz",
|
||||
"integrity": "sha512-c45jA3Jc1X8yJKzrWu1GpplBKGwv/wIV6ITZTlCSY7npF2YfJR+6nMP5e+NTQhUeJPSyOQAbGDCGEHbAl8HN9w==",
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.1.tgz",
|
||||
"integrity": "sha512-3njoWAAhGBYy0tWBabqUQcLtczZUxrmmtc2vszQUekg3kTJyZ5/IeLC3Fo04u6y6Iy5Sba7pIIa2P/gs8D3ZeQ==",
|
||||
"dependencies": {
|
||||
"denque": "^2.1.0",
|
||||
"generate-function": "^2.3.1",
|
||||
|
@ -4104,14 +4106,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2/node_modules/lru-cache": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz",
|
||||
"integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==",
|
||||
"engines": {
|
||||
"node": ">=16.14"
|
||||
}
|
||||
},
|
||||
"node_modules/named-placeholders": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
|
||||
|
@ -4431,6 +4425,26 @@
|
|||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"node_modules/paypal-rest-sdk": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/paypal-rest-sdk/-/paypal-rest-sdk-1.8.1.tgz",
|
||||
"integrity": "sha512-Trj2GuPn10GqpICAxQh5wjxuDT7rq7DMOkvyatz05wI5xPGmqXN7UC0WfDSF9WSBs4YdcWZP0g+nY+sOdaFggw==",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "^0.2.3",
|
||||
"semver": "^5.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= v0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/paypal-rest-sdk/node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
|
@ -4642,9 +4656,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/quasar": {
|
||||
"version": "2.14.2",
|
||||
"resolved": "https://registry.npmjs.org/quasar/-/quasar-2.14.2.tgz",
|
||||
"integrity": "sha512-f5KliWtM5BEuFsDU4yvuP+dlVIWZNrGu5VpWFsxzjpoykcP4B2HIOUiCl3mx2NCqERHd4Ts0aeioRkt9TTeExA==",
|
||||
"version": "2.14.3",
|
||||
"resolved": "https://registry.npmjs.org/quasar/-/quasar-2.14.3.tgz",
|
||||
"integrity": "sha512-7WzbtZxykLn2ic5oNpepZ2ZjDVpmxyVD4KC9rWe+Ia+4Er61svGr4jOuttN+Ok7IerLSCmKIRyjQMgasF60rFA==",
|
||||
"engines": {
|
||||
"node": ">= 10.18.1",
|
||||
"npm": ">= 6.13.4",
|
||||
|
@ -4970,9 +4984,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.69.7",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz",
|
||||
"integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==",
|
||||
"version": "1.70.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz",
|
||||
"integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
|
@ -5013,6 +5027,18 @@
|
|||
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/semver/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
|
@ -5089,14 +5115,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
|
||||
"integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
|
||||
"integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.1",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0"
|
||||
"has-property-descriptors": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
@ -5478,9 +5505,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.9.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.9.0.tgz",
|
||||
"integrity": "sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==",
|
||||
"version": "4.10.2",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
|
||||
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
|
@ -5622,9 +5649,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vee-validate": {
|
||||
"version": "4.12.4",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.12.4.tgz",
|
||||
"integrity": "sha512-rqSjMdl0l/RiGKywKhkXttUKwDlQOoxTxe31uMQiMlwK4Hbtlvr3OcQvpREp/qPTARxNKudKWCUVW/mfzuxUVQ==",
|
||||
"version": "4.12.5",
|
||||
"resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-4.12.5.tgz",
|
||||
"integrity": "sha512-rvaDfLPSLwTk+mf016XWE4drB8yXzOsKXiKHTb9gNXNLTtQSZ0Ww26O0/xbIFQe+n3+u8Wv1Y8uO/aLDX4fxOg==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.5.1",
|
||||
"type-fest": "^4.8.3"
|
||||
|
@ -5634,9 +5661,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "2.9.16",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.16.tgz",
|
||||
"integrity": "sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==",
|
||||
"version": "2.9.17",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.9.17.tgz",
|
||||
"integrity": "sha512-XxcRzra6d7xrKXH66jZUgb+srThoPu+TLJc06GifUyKq9JmjHkc1Numc8ra0h56rju2jfVWw3B3fs5l3OFMvUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.14.27",
|
||||
|
@ -5671,15 +5698,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.4.7",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.7.tgz",
|
||||
"integrity": "sha512-4urmkWpudekq0CPNMO7p6mBGa9qmTXwJMO2r6CT4EzIJVG7WoSReiysiNb7OSi/WI113oX0Srn9Rz1k/DCXKFQ==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.15.tgz",
|
||||
"integrity": "sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.7",
|
||||
"@vue/compiler-sfc": "3.4.7",
|
||||
"@vue/runtime-dom": "3.4.7",
|
||||
"@vue/server-renderer": "3.4.7",
|
||||
"@vue/shared": "3.4.7"
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/compiler-sfc": "3.4.15",
|
||||
"@vue/runtime-dom": "3.4.15",
|
||||
"@vue/server-renderer": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
|
@ -5696,9 +5723,9 @@
|
|||
"integrity": "sha512-4fdRMXO6FHzmE7H4soAph6QmPg3sL/RiGdd+axuxuU07f02LNMns0jMM88fmt1bvSbN+2Wyd8raho6p6nXUzag=="
|
||||
},
|
||||
"node_modules/vue-eslint-parser": {
|
||||
"version": "9.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.0.tgz",
|
||||
"integrity": "sha512-7KsNBb6gHFA75BtneJsoK/dbZ281whUIwFYdQxA68QrCrGMXYzUMbPDHGcOQ0OocIVKrWSKWXZ4mL7tonCXoUw==",
|
||||
"version": "9.4.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz",
|
||||
"integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
|
@ -5720,12 +5747,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue-i18n": {
|
||||
"version": "9.9.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.9.0.tgz",
|
||||
"integrity": "sha512-xQ5SxszUAqK5n84N+uUyHH/PiQl9xZ24FOxyAaNonmOQgXeN+rD9z/6DStOpOxNFQn4Cgcquot05gZc+CdOujA==",
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.9.1.tgz",
|
||||
"integrity": "sha512-xyQ4VspLdNSPTKBFBPWa1tvtj+9HuockZwgFeD2OhxxXuC2CWeNvV4seu2o9+vbQOyQbhAM5Ez56oxUrrnTWdw==",
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "9.9.0",
|
||||
"@intlify/shared": "9.9.0",
|
||||
"@intlify/core-base": "9.9.1",
|
||||
"@intlify/shared": "9.9.1",
|
||||
"@vue/devtools-api": "^6.5.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "floranet",
|
||||
"version": "0.0.1",
|
||||
"description": "A floranet app",
|
||||
"productName": "Floranet App",
|
||||
"productName": "Floranet",
|
||||
"author": "user",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -22,7 +22,9 @@
|
|||
"@vueuse/core": "^10.7.0",
|
||||
"axios": "^1.2.1",
|
||||
"express": "^4.18.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"mysql2": "^3.7.0",
|
||||
"paypal-rest-sdk": "^1.8.1",
|
||||
"pinia": "^2.0.11",
|
||||
"quasar": "^2.6.0",
|
||||
"vee-validate": "^4.12.2",
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<script>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { defineComponent, onBeforeMount, ref, watch } from "vue";
|
||||
|
||||
import { fullCurrentDate } from "src/constants/date";
|
||||
import { invertDate } from "src/functions/invertDate";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { defineComponent, ref } from "vue";
|
||||
import IconCalendar from "../icons/IconCalendar.vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -19,27 +21,45 @@ export default defineComponent({
|
|||
const formStore = useFormStore();
|
||||
const { availability } = storeToRefs(formStore);
|
||||
|
||||
const proxyDate = ref(fullCurrentDate);
|
||||
const [year, month, day] = fullCurrentDate.replaceAll("/", "-").split("-");
|
||||
const currentDate = `${day}-${month}-${year}`;
|
||||
const proxyDate = ref(invertDate(currentDate));
|
||||
|
||||
function updateProxy() {
|
||||
proxyDate.value = fullCurrentDate;
|
||||
proxyDate.value = invertDate(currentDate);
|
||||
}
|
||||
|
||||
function optionsValidDates(date) {
|
||||
return date >= fullCurrentDate;
|
||||
}
|
||||
|
||||
function save() {
|
||||
availability.value.date = proxyDate.value;
|
||||
setValues({ date: proxyDate.value });
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
setValues({ date: invertDate(proxyDate.value) });
|
||||
});
|
||||
|
||||
watch(proxyDate, (newProxy) => {
|
||||
setValues({ date: invertDate(newProxy) });
|
||||
});
|
||||
|
||||
const locale = {
|
||||
days: "Domingo_Lunes_Martes_Miércoles_Jueves_Viernes_Sábado".split("_"),
|
||||
daysShort: "Dom_Lun_Mar_Mié_Jue_Vie_Sáb".split("_"),
|
||||
months:
|
||||
"Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre".split(
|
||||
"_"
|
||||
),
|
||||
monthsShort: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Sep_Oct_Nov_Dic".split("_"),
|
||||
firstDayOfWeek: 1,
|
||||
format24h: false,
|
||||
pluralDay: "dias",
|
||||
};
|
||||
|
||||
return {
|
||||
availability,
|
||||
proxyDate,
|
||||
locale,
|
||||
updateProxy,
|
||||
optionsValidDates,
|
||||
save,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -58,19 +78,14 @@ export default defineComponent({
|
|||
>
|
||||
<q-date
|
||||
v-model="proxyDate"
|
||||
v-bind="calendarAttrs"
|
||||
:options="optionsValidDates"
|
||||
mask="DD-MM-YYYY"
|
||||
:locale="locale"
|
||||
today-btn
|
||||
mask="YYYY-MM-DD"
|
||||
>
|
||||
<div class="row items-center justify-end q-gutter-sm">
|
||||
<q-btn label="Cancel" color="primary" flat v-close-popup />
|
||||
<q-btn
|
||||
label="OK"
|
||||
color="primary"
|
||||
flat
|
||||
@click="save"
|
||||
v-close-popup
|
||||
/>
|
||||
<q-btn label="OK" color="primary" flat v-close-popup />
|
||||
</div>
|
||||
</q-date>
|
||||
</q-popup-proxy>
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
<script>
|
||||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import { Field, useForm } from "vee-validate";
|
||||
import { defineComponent, watch } from "vue";
|
||||
|
||||
import { quasarNotify } from "src/functions/quasarNotify";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { availabilitySchema } from "src/utils/zod/schemas/availabilitySchema";
|
||||
import IconPostalCode from "../icons/IconPostalCode.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PostalCodeEx",
|
||||
components: { IconPostalCode, Field },
|
||||
setup() {
|
||||
const formStore = useFormStore();
|
||||
const validationSchema = toTypedSchema(
|
||||
availabilitySchema.pick({ date: true })
|
||||
);
|
||||
const { errors, values, handleSubmit } = useForm({
|
||||
validationSchema,
|
||||
initialValues: {
|
||||
date: "",
|
||||
},
|
||||
});
|
||||
|
||||
watch(values, (newValues) => {
|
||||
formStore.$patch({
|
||||
availability: {
|
||||
postalCode: newValues.date,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
watch(errors, (newErrors) => {
|
||||
if (newErrors.date) {
|
||||
quasarNotify({ message: newErrors.date, type: "erro" });
|
||||
}
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit(formStore.registerAvailability);
|
||||
|
||||
return {
|
||||
postalCode,
|
||||
postalCodeAttrs,
|
||||
errors,
|
||||
onBlur,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="custom-input-el postal-code">
|
||||
<IconPostalCode />
|
||||
|
||||
<div class="custom-block-content">
|
||||
<p class="custom-head-paragraph">¿Dónde?</p>
|
||||
<!-- <p class="custom-main-paragraph">código postal</p> -->
|
||||
<Field />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,62 +0,0 @@
|
|||
<script>
|
||||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import { Field, useForm } from "vee-validate";
|
||||
import { defineComponent, watch } from "vue";
|
||||
|
||||
import { quasarNotify } from "src/functions/quasarNotify";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { availabilitySchema } from "src/utils/zod/schemas/availabilitySchema";
|
||||
import IconPostalCode from "../icons/IconPostalCode.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PostalCodeEx",
|
||||
components: { IconPostalCode, Field },
|
||||
setup() {
|
||||
const formStore = useFormStore();
|
||||
const validationSchema = toTypedSchema(
|
||||
availabilitySchema.pick({ postalCode: true })
|
||||
);
|
||||
const { errors, values, handleSubmit } = useForm({
|
||||
validationSchema,
|
||||
initialValues: {
|
||||
postalCode: "",
|
||||
},
|
||||
});
|
||||
|
||||
watch(values, (newValues) => {
|
||||
formStore.$patch({
|
||||
availability: {
|
||||
postalCode: newValues.postalCode,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
watch(errors, (newErrors) => {
|
||||
if (newErrors.postalCode) {
|
||||
quasarNotify({ message: newErrors.postalCode, type: "erro" });
|
||||
}
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit(formStore.registerAvailability);
|
||||
|
||||
return {
|
||||
postalCode,
|
||||
postalCodeAttrs,
|
||||
errors,
|
||||
onBlur,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="custom-input-el postal-code">
|
||||
<IconPostalCode />
|
||||
|
||||
<div class="custom-block-content">
|
||||
<p class="custom-head-paragraph">¿Dónde?</p>
|
||||
<!-- <p class="custom-main-paragraph">código postal</p> -->
|
||||
<Field />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,47 +1,13 @@
|
|||
<script>
|
||||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useForm } from "vee-validate";
|
||||
import { defineComponent, watch } from "vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
import { quasarNotify } from "src/functions/quasarNotify";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { availabilitySchema } from "src/utils/zod/schemas/availabilitySchema";
|
||||
import IconPostalCode from "../icons/IconPostalCode.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "postal-code",
|
||||
components: { IconPostalCode },
|
||||
setup() {
|
||||
const formStore = useFormStore();
|
||||
const { availability } = storeToRefs(formStore);
|
||||
const validationSchema = toTypedSchema(
|
||||
availabilitySchema.pick({ postalCode: true }).partial()
|
||||
);
|
||||
const { errors, defineField, values } = useForm({
|
||||
validationSchema,
|
||||
initialValues: {
|
||||
postalCode: availability.value.postalCode,
|
||||
},
|
||||
});
|
||||
const [postalCode, postalCodeAttrs] = defineField("postalCode");
|
||||
const onBlur = () => {
|
||||
availability.value.postalCode = postalCode.value;
|
||||
};
|
||||
availability.value.postalCode = values.postalCode;
|
||||
|
||||
watch(errors, (newErrors) => {
|
||||
if (newErrors.postalCode) {
|
||||
quasarNotify({ message: newErrors.postalCode, type: "erro" });
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
postalCode,
|
||||
postalCodeAttrs,
|
||||
errors,
|
||||
onBlur,
|
||||
};
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -54,17 +20,6 @@ export default defineComponent({
|
|||
<p class="custom-head-paragraph">¿Dónde?</p>
|
||||
|
||||
<slot></slot>
|
||||
<!-- <q-input
|
||||
borderless
|
||||
class="custom-main-paragraph"
|
||||
v-model="postalCode"
|
||||
v-bind="postalCodeAttrs"
|
||||
:error="!!errors.postalCode"
|
||||
placeholder="código postal"
|
||||
mask="#####"
|
||||
@blur="onBlur"
|
||||
dense
|
||||
/> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -10,7 +10,7 @@ export default defineComponent({
|
|||
const formStore = useFormStore();
|
||||
const { sortProductFilters } = storeToRefs(formStore);
|
||||
|
||||
async function handleOrder(order) {
|
||||
function handleOrder(order) {
|
||||
sortProductFilters.value.order = order;
|
||||
sortProductFilters.value.isOpenOrderFilter = false;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ export default defineComponent({
|
|||
:class="isOpenNav && 'mobile-nav'"
|
||||
>
|
||||
<send-banner
|
||||
left-text="ENVÍO GRATIS a partir de 60€ | Compra el sábado hasta 14h y entrega el domingo"
|
||||
left-text="ENVÍO GRATIS"
|
||||
right-text="Envíos 24-48 h a toda España, Portugal y sur de Francia"
|
||||
mobile-text="ENVÍO GRATIS a partir de 60€"
|
||||
mobile-text="ENVÍO GRATIS"
|
||||
v-if="!isOpenNav"
|
||||
/>
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ export default defineComponent({
|
|||
<template>
|
||||
<q-header class="header-container transparent">
|
||||
<send-banner
|
||||
left-text="ENVÍO GRATIS a partir de 60€ | Compra el sábado hasta 14h y entrega el domingo"
|
||||
left-text="ENVÍO GRATIS"
|
||||
right-text="Envíos 24-48 h a toda España, Portugal y sur de Francia"
|
||||
mobile-text="ENVÍO GRATIS a partir de 60€"
|
||||
mobile-text="ENVÍO GRATIS"
|
||||
class="remove-mobile"
|
||||
/>
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
import { computed, defineComponent } from "vue";
|
||||
|
||||
import IconCart from "components/icons/IconCart.vue";
|
||||
import IconHamburger from "components/icons/IconHamburger.vue";
|
||||
|
||||
import { useLocalStorage } from "src/hooks/useLocalStorage";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useCartStore } from "src/stores/cart";
|
||||
import { useMobileStore } from "stores/mobileNav";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -14,14 +15,15 @@ export default defineComponent({
|
|||
IconHamburger,
|
||||
},
|
||||
setup() {
|
||||
const { getItem } = useLocalStorage();
|
||||
const cartStore = useCartStore();
|
||||
const { cart } = storeToRefs(cartStore);
|
||||
|
||||
const mobileStore = useMobileStore();
|
||||
const { handleOpenMobileNav } = mobileStore;
|
||||
|
||||
const cartLength = getItem("cart").length;
|
||||
const currentLength = computed(() => cart.value.length);
|
||||
|
||||
return { handleOpenMobileNav, cartLength };
|
||||
return { handleOpenMobileNav, currentLength };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -38,11 +40,11 @@ export default defineComponent({
|
|||
<RouterLink
|
||||
class="user-area-link cart"
|
||||
to="/checkout"
|
||||
v-if="cartLength > 0"
|
||||
v-if="currentLength > 0"
|
||||
>
|
||||
<icon-cart />
|
||||
<span class="cart-count" :class="cartLength > 0 && 'active'">
|
||||
{{ cartLength }}
|
||||
<span class="cart-count" :class="currentLength > 0 && 'active'">
|
||||
{{ currentLength }}
|
||||
</span>
|
||||
</RouterLink>
|
||||
|
||||
|
|
|
@ -87,8 +87,7 @@ export default defineComponent({
|
|||
Regala un verano lleno de flores y plantas
|
||||
</h1>
|
||||
|
||||
<p class="carousel-header-paragraph">
|
||||
</p>
|
||||
<!-- <p class="carousel-header-paragraph"></p> -->
|
||||
</header>
|
||||
|
||||
<form @submit="onSubmit" class="carousel-content-body">
|
||||
|
@ -99,7 +98,7 @@ export default defineComponent({
|
|||
class="custom-date-input"
|
||||
v-model="calendar"
|
||||
v-bind="calendarAttrs"
|
||||
:error="!!errors.date"
|
||||
:error="false"
|
||||
placeholder="Elige una fecha"
|
||||
mask="##/##/####"
|
||||
dense
|
||||
|
@ -114,7 +113,7 @@ export default defineComponent({
|
|||
class="custom-main-paragraph"
|
||||
v-model="postalCode"
|
||||
v-bind="postalCodeAttrs"
|
||||
:error="!!errors.postalCode"
|
||||
:error="false"
|
||||
placeholder="código postal"
|
||||
mask="#####"
|
||||
dense
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
<template>
|
||||
<StripeCheckout
|
||||
ref="checkoutRef"
|
||||
mode="payment"
|
||||
:pk="pK"
|
||||
:line-items="cartItems"
|
||||
:success-url="successURL"
|
||||
:cancel-url="cancelURL"
|
||||
@loading="(v) => (loading = v)"
|
||||
style="display: none"
|
||||
/>
|
||||
|
||||
<slot></slot>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { defineComponent, ref, toRefs } from "vue";
|
||||
|
||||
import { useCartStore } from "src/stores/cart";
|
||||
import { onUpdated } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "StripeCheckoutComponent",
|
||||
components: {},
|
||||
props: {
|
||||
submitLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
onSubmit: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
cartItems: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup({ submitLoading, cartItems }) {
|
||||
const cartStore = useCartStore();
|
||||
const { checkoutRef } = storeToRefs(cartStore);
|
||||
|
||||
const loading = toRefs(submitLoading);
|
||||
const pK = ref(
|
||||
"pk_test_51OZaJdIK1lTlG93d2y0B81n4XrjvjQwqfIUZ7ggb9wEBa1e4h34GlYFYPwjtGl3OUT7DJZlVNX9EMXaCdOBkIC3T007mLnfvCu"
|
||||
);
|
||||
|
||||
onUpdated(() => {
|
||||
console.log(checkoutRef.value);
|
||||
console.log(cartItems);
|
||||
});
|
||||
|
||||
return {
|
||||
pK,
|
||||
loading,
|
||||
checkoutRef,
|
||||
successURL: ref("/checkout/success"),
|
||||
cancelURL: ref("/checkout/cancel"),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
|
@ -20,8 +20,6 @@ export default defineComponent({
|
|||
const nextSwiperBtn = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
// console.log('Montado!');
|
||||
|
||||
swiperContainer.value =
|
||||
document.querySelector("swiper-container").shadowRoot;
|
||||
prevSwiperBtn.value = swiperContainer.value.querySelector(
|
||||
|
@ -40,11 +38,9 @@ export default defineComponent({
|
|||
return {
|
||||
screenWidth,
|
||||
handlePrev() {
|
||||
// console.log('Prev click');
|
||||
prevSwiperBtn.value.click();
|
||||
},
|
||||
handleNext() {
|
||||
// console.log('Next click');
|
||||
nextSwiperBtn.value.click();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -33,10 +33,7 @@ export default defineComponent({
|
|||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isNew: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isNew: String,
|
||||
size: {
|
||||
type: String,
|
||||
default: "md-card",
|
||||
|
@ -54,10 +51,8 @@ export default defineComponent({
|
|||
const isLoaded = ref(false);
|
||||
const isError = ref(false);
|
||||
const percent = +discount / 100;
|
||||
//const priceWithoutLetter = ~~price?.replaceAll("€", "");
|
||||
const priceWithoutLetter = price;
|
||||
const finalValue = ~~(priceWithoutLetter - priceWithoutLetter * percent);
|
||||
console.log(price);
|
||||
|
||||
const onLoad = () => {
|
||||
isLoaded.value = true;
|
||||
|
|
|
@ -6,9 +6,7 @@ export default defineComponent({
|
|||
name: "chat-component",
|
||||
components: { IconChat },
|
||||
setup() {
|
||||
const handleClick = () => {
|
||||
console.log("click");
|
||||
};
|
||||
const handleClick = () => {};
|
||||
return { handleClick };
|
||||
},
|
||||
});
|
||||
|
|
|
@ -18,7 +18,6 @@ export default defineComponent({
|
|||
|
||||
function closeNav() {
|
||||
isOpenNav.value = false;
|
||||
console.log("foi click");
|
||||
}
|
||||
|
||||
watch(isOpenNav, (newValue) => {
|
||||
|
|
|
@ -129,7 +129,7 @@ export default defineComponent({
|
|||
class="custom-date-input"
|
||||
v-model="calendar"
|
||||
v-bind="calendarAttrs"
|
||||
:error="!!errors.date"
|
||||
:error="false"
|
||||
placeholder="Elige una fecha"
|
||||
mask="##/##/####"
|
||||
dense
|
||||
|
@ -142,7 +142,7 @@ export default defineComponent({
|
|||
class="custom-main-paragraph"
|
||||
v-model="postalCode"
|
||||
v-bind="postalCodeAttrs"
|
||||
:error="!!errors.postalCode"
|
||||
:error="false"
|
||||
placeholder="código postal"
|
||||
mask="#####"
|
||||
dense
|
||||
|
|
|
@ -30,7 +30,6 @@ export default defineComponent({
|
|||
const [terms, termsAttrs] = defineField("terms");
|
||||
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
console.log(values);
|
||||
handleQuestionData(values);
|
||||
handleReset();
|
||||
if (!terms.value) {
|
||||
|
|
|
@ -321,8 +321,29 @@ body {
|
|||
margin-bottom: -14px;
|
||||
}
|
||||
|
||||
//! QUASAR
|
||||
.error-message {
|
||||
min-height: 525px !important;
|
||||
color: $primary;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
& h1 {
|
||||
font-size: $font-40;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $med-md) {
|
||||
min-height: 400px !important;
|
||||
|
||||
& h1 {
|
||||
line-height: 1.2;
|
||||
font-size: $font-28;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! QUASAR
|
||||
.q-virtual-scroll__content .q-item .q-item__label {
|
||||
font-family: $font-questrial;
|
||||
font-size: $font-14;
|
||||
|
|
|
@ -2,21 +2,20 @@ import { toTypedSchema } from "@vee-validate/zod";
|
|||
import { useForm } from "vee-validate";
|
||||
import { computed, reactive, ref } from "vue";
|
||||
|
||||
import { apiBack } from "src/boot/axios";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { checkoutSchema } from "src/utils/zod/schemas";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useLocalStorage } from "./useLocalStorage";
|
||||
|
||||
export function useCheckoutForm() {
|
||||
const { getItem } = useLocalStorage();
|
||||
const { push } = useRouter()
|
||||
const { addItem, getItem, removeItem } = useLocalStorage();
|
||||
|
||||
const formStore = useFormStore();
|
||||
const { handleCheckoutData } = formStore;
|
||||
const { meta, errors, handleSubmit, defineField, resetForm } = useForm({
|
||||
validationSchema: toTypedSchema(checkoutSchema),
|
||||
initialValues: {
|
||||
paymentMethod: "stripe",
|
||||
paymentMethod: "paypal",
|
||||
terms: false,
|
||||
},
|
||||
});
|
||||
|
@ -36,6 +35,11 @@ export function useCheckoutForm() {
|
|||
const [paymentMethod, paymentMethodAttrs] = defineField("paymentMethod");
|
||||
const [terms, termsAttrs] = defineField("terms");
|
||||
|
||||
|
||||
|
||||
//TODO hacer el await de las provincias
|
||||
//const provinceOptions = getProvinces();
|
||||
|
||||
const provinceOptions = ref([
|
||||
{ code: "01", name: "Araba/Álava" },
|
||||
{ code: "02", name: "Albacete" },
|
||||
|
@ -90,7 +94,6 @@ export function useCheckoutForm() {
|
|||
{ code: "51", name: "Ceuta" },
|
||||
{ code: "52", name: "Melilla" },
|
||||
]);
|
||||
|
||||
const stepActive = reactive({ data: 1 });
|
||||
const stepList = reactive({
|
||||
data: [
|
||||
|
@ -122,27 +125,90 @@ export function useCheckoutForm() {
|
|||
return step;
|
||||
});
|
||||
});
|
||||
const isError = ref(false);
|
||||
const onError = () => {
|
||||
isError.value = true;
|
||||
};
|
||||
|
||||
const handleClickStep = (value) => {
|
||||
stepActive["data"] = value;
|
||||
};
|
||||
|
||||
const checkoutBlock = ref(true);
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
handleCheckoutData(values);
|
||||
stepList.data[2].active = true;
|
||||
checkoutBlock.value = false;
|
||||
resetForm();
|
||||
const cart = getItem("cart");
|
||||
const availability = getItem("availability");
|
||||
const totalPrice = computed(() => {
|
||||
return cart?.reduce((acc, { price }) => {
|
||||
if (price) {
|
||||
//const priceWithoutLetter = price?.replace("€", "");
|
||||
return +price + acc;
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
const cart = getItem("cart");
|
||||
const totalPrice = ref(0)
|
||||
totalPrice.value = cart?.reduce((acc, { price }) => {
|
||||
if (price) {
|
||||
const priceWithoutLetter = price?.replace("€", "");
|
||||
return +priceWithoutLetter + acc;
|
||||
const isLoadingSubmit = ref(false);
|
||||
const isErrorSubmit = ref(false);
|
||||
|
||||
const onSuccess = async (values) => {
|
||||
isLoadingSubmit.value = true;
|
||||
stepsFormated.value[1].active = true;
|
||||
|
||||
try {
|
||||
const productsId = cart.map((item) => item.id);
|
||||
|
||||
const cartItensData = cart.map((item) => {
|
||||
const { id, message, ...rest } = item;
|
||||
|
||||
if (message) {
|
||||
return { id, message };
|
||||
}
|
||||
|
||||
return { id, message: "" };
|
||||
});
|
||||
|
||||
const deliveryData = {
|
||||
customerData: {
|
||||
custumerName: `${values.name} ${values.surname}`,
|
||||
email: values.senderEmail,
|
||||
custumerPhone: values.phone,
|
||||
},
|
||||
itemData: cartItensData,
|
||||
deliveryData: {
|
||||
dated: availability.dateExpired,
|
||||
deliveryName: values.senderName,
|
||||
address: values.address,
|
||||
postalCode: availability.postalCode,
|
||||
deliveryPhone: values.senderPhone,
|
||||
deliveryMessage: values.senderNotes,
|
||||
},
|
||||
};
|
||||
addItem("costumer", deliveryData);
|
||||
|
||||
const productData = {
|
||||
products: productsId,
|
||||
price: totalPrice.value.toFixed(2).toString(),
|
||||
};
|
||||
|
||||
const {
|
||||
data: { data },
|
||||
} = await apiBack.post("payment", productData);
|
||||
|
||||
isLoadingSubmit.value = false;
|
||||
location.href = data;
|
||||
removeItem("cart");
|
||||
removeItem("availability");
|
||||
} catch (error) {
|
||||
console.error(`FATAL ERROR ::: ${error}`);
|
||||
|
||||
isErrorSubmit.value = true;
|
||||
isLoadingSubmit.value = false;
|
||||
} finally {
|
||||
handleCheckoutData(values);
|
||||
resetForm();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(onSuccess);
|
||||
|
||||
return {
|
||||
handleClickStep,
|
||||
|
@ -152,11 +218,13 @@ export function useCheckoutForm() {
|
|||
checkoutBlock,
|
||||
cart,
|
||||
totalPrice,
|
||||
isError,
|
||||
onError,
|
||||
formState: {
|
||||
meta,
|
||||
errors,
|
||||
onSubmit,
|
||||
submitLoading: ref(false),
|
||||
isLoadingSubmit,
|
||||
},
|
||||
fields: {
|
||||
name,
|
||||
|
@ -189,4 +257,4 @@ export function useCheckoutForm() {
|
|||
termsAttrs,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,22 +1,39 @@
|
|||
import { LocalStorage } from "quasar";
|
||||
|
||||
export function useLocalStorage() {
|
||||
/**
|
||||
* Adds an item to localStorage.
|
||||
* @param {string} key - The key of the item to be added.
|
||||
* @param {*} value - The value of the item to be added.
|
||||
*/
|
||||
const addItem = (key, value) => {
|
||||
LocalStorage.set(`@${key}`, value);
|
||||
const stringifyValue = JSON.stringify(value);
|
||||
|
||||
LocalStorage.set(`@${key}`, stringifyValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves an item from the local storage based on the provided key.
|
||||
*
|
||||
* @param {string} key - The key of the item to retrieve.
|
||||
* @returns {Object|Array} - The retrieved item from the local storage. If the key is "availability", it returns an object, otherwise it returns an array.
|
||||
*/
|
||||
const getItem = (key) => {
|
||||
const data = JSON.parse(LocalStorage.getItem(`@${key}`));
|
||||
|
||||
|
||||
return (data || []);
|
||||
if (key === "availability") return data || {};
|
||||
return data || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an item from local storage.
|
||||
*
|
||||
* @param {string} key - The key of the item to remove.
|
||||
*/
|
||||
const removeItem = (key) => {
|
||||
LocalStorage.remove(`@${key}`);
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
addItem,
|
||||
getItem,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { toTypedSchema } from "@vee-validate/zod";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useForm } from "vee-validate";
|
||||
import { ref, watch } from "vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
import { invertDate } from "src/functions/invertDate";
|
||||
|
@ -12,38 +12,45 @@ import { useModalStore } from "src/stores/modalStore";
|
|||
import { useRangePriceStore } from "src/stores/rangePrice";
|
||||
import { availabilitySchema } from "src/utils/zod/schemas";
|
||||
import { rangePriceSchema } from "src/utils/zod/schemas/rangePriceSchema";
|
||||
import { useLocalStorage } from "./useLocalStorage";
|
||||
|
||||
/**
|
||||
* Custom hook for managing the postal and calendar functionality.
|
||||
* Custom hook for managing postal calendar functionality.
|
||||
*
|
||||
* @param {Object} options - The options for the hook.
|
||||
* @param {string} options.modalItem - The modal item isOpenAvailability || isOpenFilters.
|
||||
* @param {string} options.type - The type of the hook. home || product || availability || filter
|
||||
* @returns {Object} - The hook functions and data.
|
||||
* @param {string} options.modalItem - The modal item.
|
||||
* @param {string} options.type - The type of the calendar.
|
||||
* @returns {Object} - The hook functions and properties.
|
||||
*/
|
||||
export function usePostalCalendar({ modalItem = "", type = "home" }) {
|
||||
const route = useRoute();
|
||||
const { push } = useRouter()
|
||||
const { push, go } = useRouter();
|
||||
const { addItem, getItem, removeItem } = useLocalStorage();
|
||||
|
||||
const rangePriceStore = useRangePriceStore();
|
||||
const { rangeValue } = storeToRefs(rangePriceStore);
|
||||
|
||||
const modalStore = useModalStore();
|
||||
const { openModal } = modalStore
|
||||
|
||||
const formStore = useFormStore();
|
||||
const { sortProductFilters } = storeToRefs(formStore);
|
||||
const { sortProductFilters, availability: availabilityForm } =
|
||||
storeToRefs(formStore);
|
||||
|
||||
const cartStore = useCartStore();
|
||||
const { addToCart, getProducts } = cartStore;
|
||||
const { products, homeSection } = storeToRefs(cartStore);
|
||||
const { products, cart } = storeToRefs(cartStore);
|
||||
|
||||
const min = 0;
|
||||
const max = 200;
|
||||
const category = ref(route.path.split("/")[2])
|
||||
const category = ref(route.path.split("/")[2]);
|
||||
const availability = ref(getItem("availability"));
|
||||
const isAvailabilityEmpty = computed(() => {
|
||||
return Object.keys(availability.value).length === 0;
|
||||
});
|
||||
|
||||
const { handleSubmit, handleReset, defineField, errors, setValues } = useForm(
|
||||
{
|
||||
validateOnMount: false,
|
||||
validationSchema: toTypedSchema(
|
||||
type !== "filter" ? availabilitySchema : rangePriceSchema
|
||||
),
|
||||
|
@ -55,129 +62,206 @@ export function usePostalCalendar({ modalItem = "", type = "home" }) {
|
|||
postalCode: "",
|
||||
date: "",
|
||||
},
|
||||
initialTouched: {
|
||||
date: false,
|
||||
postalCode: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
const [calendar, calendarAttrs] = defineField("date");
|
||||
const [postalCode, postalCodeAttrs] = defineField("postalCode");
|
||||
const [priceRange, priceRangeAttrs] = defineField("range");
|
||||
|
||||
const options = {
|
||||
validateOnBlur: false,
|
||||
validateOnChange: false,
|
||||
validateOnInput: false,
|
||||
validateOnModelUpdate: false,
|
||||
};
|
||||
const [calendar, calendarAttrs] = defineField("date", options);
|
||||
const [postalCode, postalCodeAttrs] = defineField("postalCode", options);
|
||||
const [priceRange, priceRangeAttrs] = defineField("range", options);
|
||||
const [dedication, dedicationAttrs] = defineField("dedication");
|
||||
|
||||
watch(errors, (newErrors) => {
|
||||
const errorsObj = {
|
||||
postalCode: () =>
|
||||
quasarNotify({ message: newErrors.postalCode, type: "erro" }),
|
||||
date: () => quasarNotify({ message: newErrors.date, type: "erro" }),
|
||||
range: () => quasarNotify({ message: newErrors.range, type: "erro" }),
|
||||
dedication: () =>
|
||||
quasarNotify({ message: newErrors.dedication, type: "erro" }),
|
||||
const hasErrors = {
|
||||
range: newErrors.range,
|
||||
dedication: newErrors.dedication,
|
||||
};
|
||||
const keys = Object.keys(newErrors);
|
||||
keys.forEach((key) => {
|
||||
errorsObj[key]();
|
||||
});
|
||||
for (const [field, hasError] of Object.entries(hasErrors)) {
|
||||
if (hasError) {
|
||||
quasarNotify({ message: newErrors[field], type: "erro" });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
[() => route.path, () => sortProductFilters.value],
|
||||
([newPath]) => {
|
||||
const categoryPath = newPath.split("/")[2];
|
||||
category.value = categoryPath;
|
||||
}
|
||||
);
|
||||
watch([() => route.path, () => sortProductFilters.value], ([newPath]) => {
|
||||
const categoryPath = newPath.split("/")[2];
|
||||
category.value = categoryPath;
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit((values) => {
|
||||
const postalAndDateParams = {
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
const removeCart = () => {
|
||||
removeItem("cart");
|
||||
cart.value = [];
|
||||
};
|
||||
|
||||
const onSuccess = async (values) => {
|
||||
const handleAvailability = async () => {
|
||||
addItem("availability", {
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
removeCart();
|
||||
availabilityForm.value.dateExpired = invertDate(values.date);
|
||||
availabilityForm.value.postalCode = values.postalCode;
|
||||
|
||||
await getProducts({
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
};
|
||||
|
||||
const categoryObj = {
|
||||
plantas: "Floranet Plantas",
|
||||
ramos: "Floranet Ramos",
|
||||
};
|
||||
const handleHome = async () => {
|
||||
console.log(type);
|
||||
|
||||
const objVal = {
|
||||
home: async () => {
|
||||
console.log(type);
|
||||
addItem("availability", {
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
availabilityForm.value.dateExpired = invertDate(values.date);
|
||||
availabilityForm.value.postalCode = values.postalCode;
|
||||
removeCart();
|
||||
|
||||
await getProducts(
|
||||
{
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
},
|
||||
() => homeSection.value.scrollIntoView()
|
||||
);
|
||||
},
|
||||
product: async () => {
|
||||
console.log(type);
|
||||
const callback = async () => {
|
||||
await push("/categoria/all");
|
||||
};
|
||||
|
||||
await getProducts(postalAndDateParams);
|
||||
|
||||
const hasProduct = products.value.data.some((item) => {
|
||||
const date = new Date(item.dateExpired);
|
||||
const day = date.getDate();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
const dateExpired = `${day}/${month}/${year}`;
|
||||
|
||||
const id = +route.path.split('/')[2];
|
||||
|
||||
return item.postalCode === values.postalCode && item.id === id && values.date <= dateExpired
|
||||
});
|
||||
|
||||
if (!hasProduct) {
|
||||
push('/categoria/ramos')
|
||||
quasarNotify({ message: 'Seleccione una nueva fecha y un nuevo código postal.', type: 'warning' })
|
||||
|
||||
setTimeout(() => {
|
||||
openModal({ modal: 'availability' })
|
||||
}, 2000)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
addToCart(products.value.current, dedication)
|
||||
},
|
||||
availability: async () => {
|
||||
console.log(type);
|
||||
|
||||
await getProducts({
|
||||
await getProducts(
|
||||
{
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
},
|
||||
filter: async () => {
|
||||
console.log(type);
|
||||
|
||||
rangeValue.value.max = values.range.max;
|
||||
rangeValue.value.min = values.range.min;
|
||||
|
||||
const params = {
|
||||
type: categoryObj[category.value],
|
||||
minPrice: values.range.min,
|
||||
maxPrice: values.range.max,
|
||||
};
|
||||
|
||||
await getProducts(params);
|
||||
},
|
||||
default: () => {
|
||||
console.error(
|
||||
`INVALID TYPE! TYPE: ${type}, ONLY HOME, PRODUCT AND FILTER ARE VALID!`
|
||||
);
|
||||
},
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
objVal[type]() || objVal["default"]();
|
||||
|
||||
const handleProduct = async () => {
|
||||
console.log(type);
|
||||
|
||||
addItem("availability", {
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
removeCart();
|
||||
availabilityForm.value.dateExpired = invertDate(values.date);
|
||||
availabilityForm.value.postalCode = values.postalCode;
|
||||
|
||||
await getProducts({
|
||||
postalCode: values.postalCode,
|
||||
dateExpired: invertDate(values.date),
|
||||
});
|
||||
|
||||
const hasProduct = computed(() => {
|
||||
return products.value.data.some((item) => {
|
||||
const date = new Date(item.dateExpired);
|
||||
const day = date.getDate();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const year = date.getFullYear();
|
||||
const dateExpired = `${day}/${month}/${year}`;
|
||||
const dateSelected = values.date.replaceAll("-", "/");
|
||||
|
||||
const id = +route.path.split("/")[2];
|
||||
|
||||
console.log(item.postalCode === values.postalCode);
|
||||
console.log(item.id === id);
|
||||
console.log(dateSelected <= dateExpired);
|
||||
|
||||
return (
|
||||
item.postalCode === values.postalCode &&
|
||||
item.id === id &&
|
||||
dateSelected <= dateExpired
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
if (!hasProduct.value) {
|
||||
quasarNotify({
|
||||
message: "Código postal y fecha de caducidad añadidos con éxito",
|
||||
type: "success",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// go();
|
||||
addToCart(products.value.current, dedication);
|
||||
};
|
||||
|
||||
const handleFilter = async () => {
|
||||
console.log(type);
|
||||
|
||||
rangeValue.value.max = values.range.max;
|
||||
rangeValue.value.min = values.range.min;
|
||||
|
||||
const params = {
|
||||
type: categoryObj[category.value],
|
||||
minPrice: values.range.min,
|
||||
maxPrice: values.range.max,
|
||||
};
|
||||
console.log(params);
|
||||
|
||||
if (category.value === "all") {
|
||||
params.postalCode = availability.value.postalCode;
|
||||
params.dateExpired = availability.value.dateExpired;
|
||||
|
||||
const { type, ...rest } = params;
|
||||
await getProducts({ ...rest });
|
||||
return;
|
||||
}
|
||||
|
||||
getProducts(params);
|
||||
};
|
||||
|
||||
const handleDefault = () => {
|
||||
console.error(
|
||||
`INVALID TYPE! TYPE: ${type}, ONLY HOME, PRODUCT AND FILTER ARE VALID!`
|
||||
);
|
||||
};
|
||||
|
||||
const handlers = {
|
||||
availability: handleAvailability,
|
||||
home: handleHome,
|
||||
product: handleProduct,
|
||||
filter: handleFilter,
|
||||
default: handleDefault,
|
||||
};
|
||||
|
||||
const handler = handlers[type] || handlers.default;
|
||||
await handler();
|
||||
|
||||
if (modalItem) {
|
||||
modalStore[modalItem] = false;
|
||||
}
|
||||
handleReset();
|
||||
});
|
||||
};
|
||||
|
||||
const onError = ({ values, errors, results }) => {
|
||||
const hasErrors = {
|
||||
postalCode: !!errors.postalCode,
|
||||
date: !!errors.date,
|
||||
};
|
||||
for (const [field, hasError] of Object.entries(hasErrors)) {
|
||||
if (hasError) {
|
||||
quasarNotify({ message: errors[field], type: "erro" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(onSuccess, onError);
|
||||
|
||||
return {
|
||||
onSubmit,
|
||||
setValues,
|
||||
handleReset,
|
||||
modalStore,
|
||||
isAvailabilityEmpty,
|
||||
fields: {
|
||||
calendar,
|
||||
calendarAttrs,
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import { storeToRefs } from "pinia";
|
||||
import { useCartStore } from "src/stores/cart";
|
||||
import { useModalStore } from "src/stores/modalStore";
|
||||
import { watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { usePostalCalendar } from "./usePostalCalendar";
|
||||
|
||||
export function useProductPage() {
|
||||
const route = useRoute();
|
||||
|
||||
const {
|
||||
fields: { dedication, dedicationAttrs },
|
||||
} = usePostalCalendar({ modalItem: "isOpenAvailability" });
|
||||
|
||||
const modalStore = useModalStore();
|
||||
const { openModal } = modalStore;
|
||||
|
||||
const cartStore = useCartStore();
|
||||
const { getProduct, getProducts } = cartStore;
|
||||
const { products, featuredProducts, addCartLoadingBtn } =
|
||||
storeToRefs(cartStore);
|
||||
|
||||
watch(
|
||||
() => products.value.current?.type,
|
||||
(newCategory) => {
|
||||
getProducts({
|
||||
// type: newCategory,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
(newId) => {
|
||||
getProduct(newId);
|
||||
}
|
||||
);
|
||||
|
||||
const checkImageValidity = (imageLink) => {
|
||||
const validExtensions = [".jpg", ".jpeg", ".png"];
|
||||
|
||||
if (imageLink) {
|
||||
const extension = imageLink.substring(imageLink.lastIndexOf("."));
|
||||
return validExtensions.includes(extension.toLowerCase());
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return { checkImageValidity, openModal }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { defineComponent, onBeforeMount, onUpdated, ref, watch } from "vue";
|
||||
import { computed, defineComponent, onBeforeMount, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import SortSelect from "src/components/@inputs/SortSelect.vue";
|
||||
|
@ -13,6 +13,9 @@ import Card from "src/components/ui/Card.vue";
|
|||
import Container from "src/components/ui/Container.vue";
|
||||
import Modal from "src/components/ui/Modal.vue";
|
||||
|
||||
import { quasarNotify } from "src/functions/quasarNotify";
|
||||
import { useLocalStorage } from "src/hooks/useLocalStorage";
|
||||
import { usePostalCalendar } from "src/hooks/usePostalCalendar";
|
||||
import { useCartStore } from "src/stores/cart";
|
||||
import { useFormStore } from "src/stores/forms";
|
||||
import { useMobileStore } from "src/stores/mobileNav";
|
||||
|
@ -34,6 +37,10 @@ export default defineComponent({
|
|||
setup() {
|
||||
const route = useRoute();
|
||||
|
||||
const { getItem } = useLocalStorage();
|
||||
|
||||
const { isAvailabilityEmpty } = usePostalCalendar({});
|
||||
|
||||
const mobileStore = useMobileStore();
|
||||
const { screenWidth } = storeToRefs(mobileStore);
|
||||
|
||||
|
@ -41,29 +48,19 @@ export default defineComponent({
|
|||
const { openModal } = modalStore;
|
||||
|
||||
const formStore = useFormStore();
|
||||
const { availability, sortProductFilters } = storeToRefs(formStore);
|
||||
const { sortProductFilters, availability } = storeToRefs(formStore);
|
||||
|
||||
const cartStore = useCartStore();
|
||||
const { products } = storeToRefs(cartStore);
|
||||
const { getProducts } = cartStore;
|
||||
|
||||
const monthTest = ref("");
|
||||
const isOpenOrder = ref(false);
|
||||
const availabilityStoraged = ref(getItem("availability"));
|
||||
const isNotAllCategory = computed(() => {
|
||||
return route.path.split("/")[2] !== "all";
|
||||
});
|
||||
const datePostalCode = ref({});
|
||||
|
||||
const monthES = {
|
||||
0: "Enero",
|
||||
1: "Febrero",
|
||||
2: "Marzo",
|
||||
3: "Abril",
|
||||
4: "Mayo",
|
||||
5: "Junio",
|
||||
6: "Julio",
|
||||
7: "Agosto",
|
||||
8: "Septiembre",
|
||||
9: "Octubre",
|
||||
10: "Noviembre",
|
||||
11: "Diciembre",
|
||||
};
|
||||
const orderText = {
|
||||
"lowest-price": "menor precio",
|
||||
"highest-price": "mayor precio",
|
||||
|
@ -74,12 +71,32 @@ export default defineComponent({
|
|||
plantas: "Floranet Plantas",
|
||||
ramos: "Floranet Ramos",
|
||||
};
|
||||
const dateExpiredMonth = computed(
|
||||
() =>
|
||||
availability.value.dateExpired?.split("-")[1] ||
|
||||
availabilityStoraged.value.dateExpired?.split("-")[1]
|
||||
);
|
||||
const dateExpiredDay = computed(
|
||||
() =>
|
||||
availability.value.dateExpired?.split("-")[2] ||
|
||||
availabilityStoraged.value.dateExpired?.split("-")[2]
|
||||
);
|
||||
|
||||
watch(availability, (newDate) => {
|
||||
const [_day, month, _year] = newDate.date.split("/");
|
||||
monthTest.value = monthES[+month - 1];
|
||||
console.log(monthTest.value);
|
||||
});
|
||||
const months = {
|
||||
"01": "Enero",
|
||||
"02": "Febrero",
|
||||
"03": "Marzo",
|
||||
"04": "Abril",
|
||||
"05": "Mayo",
|
||||
"06": "Junio",
|
||||
"07": "Julio",
|
||||
"08": "Agosto",
|
||||
"09": "Septiembre",
|
||||
10: "Octubre",
|
||||
11: "Noviembre",
|
||||
12: "Diciembre",
|
||||
};
|
||||
const currentMonth = months[dateExpiredMonth.value];
|
||||
|
||||
watch(
|
||||
[() => route.path, () => sortProductFilters.value.order],
|
||||
|
@ -87,14 +104,29 @@ export default defineComponent({
|
|||
const categoryPath = newPath.split("/")[2];
|
||||
sortProductFilters.value.category = categoryPath;
|
||||
|
||||
const params = {
|
||||
type: categoryObj[categoryPath],
|
||||
};
|
||||
const params = {};
|
||||
|
||||
if (categoryPath !== "all") {
|
||||
params.type = categoryObj[categoryPath];
|
||||
}
|
||||
if (categoryPath === "all") {
|
||||
params.dateExpired = availabilityStoraged.value.dateExpired;
|
||||
params.postalCode = availabilityStoraged.value.postalCode;
|
||||
}
|
||||
|
||||
const paramsObj = {
|
||||
"lowest-price": () => (params.lowPrice = 1),
|
||||
"highest-price": () => (params.bigPrice = 1),
|
||||
latest: () => (params.isNew = 1),
|
||||
recommended: () => (params.recommend = 1),
|
||||
"lowest-price": () => {
|
||||
params.lowPrice = 1;
|
||||
},
|
||||
"highest-price": () => {
|
||||
params.bigPrice = 1;
|
||||
},
|
||||
latest: () => {
|
||||
params.isNew = 1;
|
||||
},
|
||||
recommended: () => {
|
||||
params.recommend = 1;
|
||||
},
|
||||
};
|
||||
if (newOrder) {
|
||||
paramsObj[newOrder]();
|
||||
|
@ -104,19 +136,35 @@ export default defineComponent({
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
datePostalCode.value = isNotAllCategory.value
|
||||
? availability.value
|
||||
: availabilityStoraged.value;
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const categoryPath = route.path.split("/")[2];
|
||||
|
||||
await getProducts({
|
||||
type: categoryObj[categoryPath],
|
||||
});
|
||||
});
|
||||
if (categoryPath !== "all") {
|
||||
await getProducts({
|
||||
type: categoryObj[categoryPath],
|
||||
});
|
||||
datePostalCode.value = availability.value;
|
||||
|
||||
onUpdated(() => {
|
||||
console.groupCollapsed("%c Updated!", "color: green;");
|
||||
console.log(sortProductFilters.value);
|
||||
console.log(availability.value);
|
||||
console.groupEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
await getProducts(availabilityStoraged.value);
|
||||
datePostalCode.value = availabilityStoraged.value;
|
||||
if (isAvailabilityEmpty.value) {
|
||||
quasarNotify({
|
||||
message: "Debes seleccionar una fecha y código postal",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function openOrderFilter() {
|
||||
|
@ -128,12 +176,17 @@ export default defineComponent({
|
|||
openOrderFilter,
|
||||
openModal,
|
||||
sortProductFilters,
|
||||
availability,
|
||||
isOpenOrder,
|
||||
screenWidth,
|
||||
modalStore,
|
||||
orderText,
|
||||
products,
|
||||
isNotAllCategory,
|
||||
availabilityStoraged,
|
||||
currentMonth,
|
||||
dateExpiredDay,
|
||||
datePostalCode,
|
||||
availability,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@ -144,12 +197,10 @@ export default defineComponent({
|
|||
<section class="products-section">
|
||||
<header class="products-section-header">
|
||||
<Container>
|
||||
<div class="product-header-content">
|
||||
<div class="product-header-content" v-if="isNotAllCategory">
|
||||
<h3 class="product-header-title subtitle">
|
||||
{{ sortProductFilters.category }} para obsequiar
|
||||
</h3>
|
||||
<p class="product-header-paragraph">
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="product-header-filters">
|
||||
|
@ -158,11 +209,15 @@ export default defineComponent({
|
|||
<p class="filter-paragraph availability">
|
||||
Disponibilidad para:
|
||||
<span
|
||||
v-if="availability.date && availability.postalCode"
|
||||
v-if="
|
||||
datePostalCode.dateExpired && datePostalCode.postalCode
|
||||
"
|
||||
class="green-text"
|
||||
>
|
||||
25 Julio en
|
||||
{{ availability.postalCode.replace("-", "") }}</span
|
||||
{{ dateExpiredDay }} {{ currentMonth }} en
|
||||
{{
|
||||
availability.postalCode || datePostalCode.postalCode
|
||||
}}</span
|
||||
>
|
||||
</p>
|
||||
|
||||
|
@ -232,8 +287,8 @@ export default defineComponent({
|
|||
</Container>
|
||||
</div>
|
||||
|
||||
<footer class="products-section-footer">
|
||||
<RouterLink class="btn rounded outlined" to="/">
|
||||
<footer class="products-section-footer" v-if="isNotAllCategory">
|
||||
<RouterLink class="btn rounded outlined" to="/categoria/all">
|
||||
Ver todos los diseños <IconArrowCircleFilledRight />
|
||||
</RouterLink>
|
||||
</footer>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<q-page class="checkout-error-page error-message">
|
||||
<container>
|
||||
<h1>¡Uy! Algo ha ido mal durante el proceso de compra.</h1>
|
||||
</container>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Container from "src/components/ui/Container.vue";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CheckoutErrorPage",
|
||||
components: { Container },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.checkout-error-page {
|
||||
}
|
||||
</style>
|
|
@ -20,7 +20,9 @@ export default defineComponent({
|
|||
checkoutBlock,
|
||||
cart,
|
||||
totalPrice,
|
||||
formState: { errors, meta, onSubmit, submitLoading },
|
||||
isError,
|
||||
onError,
|
||||
formState: { errors, meta, onSubmit, isLoadingSubmit },
|
||||
fields: {
|
||||
name,
|
||||
nameAttrs,
|
||||
|
@ -57,11 +59,6 @@ export default defineComponent({
|
|||
if (cart.length === 0) return push("/");
|
||||
});
|
||||
|
||||
const isError = ref(false);
|
||||
const onError = () => {
|
||||
isError.value = true;
|
||||
};
|
||||
|
||||
return {
|
||||
handleClickStep,
|
||||
onSubmit,
|
||||
|
@ -74,7 +71,7 @@ export default defineComponent({
|
|||
stepList,
|
||||
cart,
|
||||
step: ref(1),
|
||||
submitLoading,
|
||||
isLoadingSubmit,
|
||||
successURL: ref(""),
|
||||
cancelURL: ref(""),
|
||||
meta,
|
||||
|
@ -439,10 +436,18 @@ export default defineComponent({
|
|||
<q-radio
|
||||
v-model="paymentMethod"
|
||||
v-bind="paymentMethodAttrs"
|
||||
val="stripe"
|
||||
val="paypal"
|
||||
color="primary"
|
||||
>
|
||||
<p>Stripe <a href="#">¿Qué es Stripe?</a></p>
|
||||
<p>
|
||||
Paypal
|
||||
<!-- <a
|
||||
href="https://www.paypal.com/br/digital-wallet/how-paypal-works"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>¿Qué es Paypal?</a
|
||||
> -->
|
||||
</p>
|
||||
</q-radio>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -455,7 +460,13 @@ export default defineComponent({
|
|||
</p>
|
||||
</q-checkbox>
|
||||
|
||||
<q-btn flat class="btn" type="submit" form="checkout-form">
|
||||
<q-btn
|
||||
flat
|
||||
class="btn"
|
||||
type="submit"
|
||||
form="checkout-form"
|
||||
:loading="isLoadingSubmit"
|
||||
>
|
||||
PROCEDER AL PAGO
|
||||
</q-btn>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
<script>
|
||||
import { apiBack } from "src/boot/axios";
|
||||
import { useCheckoutForm } from "src/hooks/useCheckoutForm";
|
||||
import { useLocalStorage } from "src/hooks/useLocalStorage";
|
||||
import { defineComponent, onBeforeMount, reactive, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CheckoutSuccessPage",
|
||||
setup() {
|
||||
const { query } = useRoute();
|
||||
const { push } = useRouter();
|
||||
const { getItem, removeItem } = useLocalStorage();
|
||||
console.log(query);
|
||||
const costumerData = getItem("costumer");
|
||||
|
||||
const productsPurchased = reactive({ data: [] });
|
||||
const totalPrice = ref();
|
||||
|
||||
async function getSuccessData() {
|
||||
try {
|
||||
productsPurchased.data = await new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const {
|
||||
data: { data },
|
||||
} = await apiBack.post("payment/success", {
|
||||
// params: query,
|
||||
data: JSON.stringify({ customer: costumerData, ...query }),
|
||||
});
|
||||
resolve(data.products);
|
||||
removeItem("costumer");
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}).then((res) => res);
|
||||
|
||||
totalPrice.value = await productsPurchased.data.reduce(
|
||||
(acc, { price }) => acc + Number(price),
|
||||
0
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(`FATAL ERROR ::: ${error}`);
|
||||
push("/checkout/error");
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const queryObj = {
|
||||
paymentId: query.paymentId,
|
||||
productsIds: query.productsIds,
|
||||
PayerID: query.PayerID,
|
||||
};
|
||||
for (const [_, value] of Object.entries(queryObj)) {
|
||||
if (!value) return push("/");
|
||||
}
|
||||
|
||||
await getSuccessData();
|
||||
console.log(productsPurchased.data);
|
||||
});
|
||||
|
||||
const { isError, onError } = useCheckoutForm();
|
||||
const steppers = [
|
||||
{
|
||||
value: 1,
|
||||
name: "Paso 1",
|
||||
description: "Datos de facturación",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: "Paso 2",
|
||||
description: "Confirmación",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
name: "Paso 3",
|
||||
description: "Pago",
|
||||
active: true,
|
||||
},
|
||||
];
|
||||
|
||||
return { isError, onError, steppers, productsPurchased, totalPrice };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-page class="success-container">
|
||||
<div class="checkout-steps">
|
||||
<div
|
||||
v-for="({ active, description, name, value }, i) in steppers"
|
||||
class="step-item-container"
|
||||
:key="i"
|
||||
>
|
||||
<div class="step-item">
|
||||
<div class="circle-step-container">
|
||||
<span class="border-step" :class="[i == 0 && 'transparent']" />
|
||||
|
||||
<div class="circle-step" :class="active && 'active'">
|
||||
<span class="step-value">{{ value }}</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="border-step"
|
||||
:class="[i == steppers.length - 1 && 'transparent']"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="step-content">
|
||||
<div class="title">
|
||||
<h4>{{ name }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<p>{{ description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="checkout-success" id="success-block">
|
||||
<h6 class="checkout-success-title green-text">
|
||||
Has efectuado la siguiente compra
|
||||
</h6>
|
||||
|
||||
<div class="checkout-success-body">
|
||||
<div class="checkout-success-content">
|
||||
<ul class="checkout-success-list">
|
||||
<li
|
||||
v-for="({ name, price, image }, index) in productsPurchased.data"
|
||||
:key="index"
|
||||
class="checkout-success-item"
|
||||
>
|
||||
<div class="checkout-item-content">
|
||||
<div class="checkout-product-details">
|
||||
<img
|
||||
:src="isError ? '../assets/empty-img.jpg' : image"
|
||||
:alt="name"
|
||||
class="checkout-product-img"
|
||||
@error="onError"
|
||||
/>
|
||||
|
||||
<p class="checkout-product-title">
|
||||
{{ name }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="checkout-product-price">{{ price }}€</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<footer class="checkout-success-footer">
|
||||
<p class="checkout-success-paragraph">Total</p>
|
||||
<p class="checkout-success-paragraph">{{ totalPrice }}€</p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.success-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.checkout-steps {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.step-item-container {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.border-step {
|
||||
width: 90px;
|
||||
height: 1px;
|
||||
background-color: $primary-dark;
|
||||
}
|
||||
|
||||
.circle-step-container {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
.circle-step {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 1px solid $primary-dark;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
user-select: none;
|
||||
.step-value {
|
||||
font-family: $font-questrial;
|
||||
color: $primary-dark;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
&.active {
|
||||
background-color: $primary-dark;
|
||||
.step-value {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: $font-questrial;
|
||||
h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: $text-default;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
p {
|
||||
font-size: 0.875rem;
|
||||
color: $text-default;
|
||||
font-family: $font-lora;
|
||||
}
|
||||
}
|
||||
|
||||
.checkout-success {
|
||||
width: min(100%, 499px);
|
||||
margin: 122px auto 0;
|
||||
text-align: center;
|
||||
& .checkout-success-title {
|
||||
margin-bottom: 26px;
|
||||
}
|
||||
& .checkout-success-body {
|
||||
& .checkout-success-content {
|
||||
background-color: $secondary-5;
|
||||
padding: 30px 46px 42px 38px;
|
||||
border-radius: 5px 5px 0px 0px;
|
||||
& .checkout-success-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 28px;
|
||||
& .checkout-success-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
& .checkout-item-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
min-height: 61px;
|
||||
& .checkout-product-details {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
& .checkout-product-img {
|
||||
object-fit: cover;
|
||||
width: 54px;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
& .checkout-product-title {
|
||||
font-size: $font-12;
|
||||
line-height: 21px;
|
||||
letter-spacing: 0.24px;
|
||||
font-family: $font-questrial;
|
||||
color: $text-default;
|
||||
}
|
||||
}
|
||||
|
||||
& .checkout-product-price {
|
||||
color: $text-muted-one;
|
||||
font-family: $font-roboto;
|
||||
font-size: $font-12;
|
||||
line-height: 21px;
|
||||
letter-spacing: 0.24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $med-lg) {
|
||||
padding-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
& .checkout-success-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: $secondary-40;
|
||||
border-radius: 0px 0px 5px 5px;
|
||||
padding: 14px 46px 7px 36px;
|
||||
|
||||
& .checkout-success-paragraph {
|
||||
font-family: $font-lora;
|
||||
letter-spacing: 0.32px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
color: $text-muted-one;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,21 +0,0 @@
|
|||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ExamplePage",
|
||||
components: {},
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam rerum omnis
|
||||
repellat. Harum ducimus nulla repellendus neque officia eveniet corporis
|
||||
odio sequi animi ut, non incidunt est error esse aperiam?
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -62,8 +62,7 @@ export default defineComponent({
|
|||
Diseños de ramos más vendidos
|
||||
</h3>
|
||||
|
||||
<p class="products-header-paragraph section-paragraph">
|
||||
</p>
|
||||
<p class="products-header-paragraph section-paragraph"></p>
|
||||
</header>
|
||||
|
||||
<div class="products-body">
|
||||
|
@ -85,7 +84,7 @@ export default defineComponent({
|
|||
</template>
|
||||
</Container>
|
||||
|
||||
<RouterLink class="btn rounded outlined" to="/">
|
||||
<RouterLink class="btn rounded outlined" to="/categoria/all">
|
||||
Ver todos los diseños <IconArrowCircleFilledRight />
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
@ -97,8 +96,7 @@ export default defineComponent({
|
|||
Nuestra selección de plantas para el verano
|
||||
</h3>
|
||||
|
||||
<p class="products-selection-paragraph section-paragraph">
|
||||
</p>
|
||||
<p class="products-selection-paragraph section-paragraph"></p>
|
||||
</header>
|
||||
|
||||
<div class="products-selection-body">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useMeta } from "quasar";
|
||||
import { defineComponent, onBeforeMount, ref, watch } from "vue";
|
||||
import { computed, defineComponent, onBeforeMount, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import IconArrowCircleFilledLeft from "components/icons/IconArrowCircleFilledLeft.vue";
|
||||
|
@ -18,8 +18,10 @@ import Card from "components/ui/Card.vue";
|
|||
import Container from "components/ui/Container.vue";
|
||||
import Modal from "components/ui/Modal.vue";
|
||||
|
||||
import { useLocalStorage } from "src/hooks/useLocalStorage";
|
||||
import { usePostalCalendar } from "src/hooks/usePostalCalendar";
|
||||
import { useCartStore } from "stores/cart";
|
||||
import { useFormStore } from "stores/forms";
|
||||
import { useModalStore } from "stores/modalStore";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -41,28 +43,48 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const { getItem } = useLocalStorage();
|
||||
|
||||
const formStore = useFormStore();
|
||||
const { availability: availabilityForm } = storeToRefs(formStore);
|
||||
|
||||
const availability = ref(getItem("availability"));
|
||||
const filteredAvailabilityForm = computed(() => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(availabilityForm.value).filter(
|
||||
([key, value]) => value !== ""
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
const isAvailabilityEmpty = computed(() => {
|
||||
return (
|
||||
Object.keys(filteredAvailabilityForm.value || availability.value)
|
||||
.length === 0
|
||||
);
|
||||
});
|
||||
|
||||
const {
|
||||
handleReset,
|
||||
fields: { dedication, dedicationAttrs },
|
||||
} = usePostalCalendar({ modalItem: "isOpenAvailability" });
|
||||
} = usePostalCalendar({ modalItem: "isOpenAvailability", type: "product" });
|
||||
|
||||
const modalStore = useModalStore();
|
||||
const { openModal } = modalStore;
|
||||
|
||||
const cartStore = useCartStore();
|
||||
const { getProduct, getProducts } = cartStore;
|
||||
const { products, featuredProducts, addCartLoadingBtn } =
|
||||
storeToRefs(cartStore);
|
||||
const { getProduct, getProducts, addToCart } = cartStore;
|
||||
const { products, addCartLoadingBtn } = storeToRefs(cartStore);
|
||||
|
||||
onBeforeMount(() => {
|
||||
getProduct(route.params.id);
|
||||
onBeforeMount(async () => {
|
||||
await getProduct(route.params.id);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => products.value.current?.type,
|
||||
(newCategory) => {
|
||||
getProducts({
|
||||
// type: newCategory,
|
||||
type: newCategory,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -74,33 +96,34 @@ export default defineComponent({
|
|||
}
|
||||
);
|
||||
|
||||
useMeta(() => ({
|
||||
title: `${products.value.current?.title}`,
|
||||
titleTemplate: (title) => `${title} - FloraNet`,
|
||||
meta: {
|
||||
description: {
|
||||
name: "description",
|
||||
content: `${products.value.current?.description}`,
|
||||
},
|
||||
keywords: {
|
||||
name: "keywords",
|
||||
content: `${products.value.current?.title}`,
|
||||
},
|
||||
equiv: {
|
||||
"http-equiv": "Content-Type",
|
||||
content: "text/html; charset=UTF-8",
|
||||
},
|
||||
ogTitle: {
|
||||
property: "og:title",
|
||||
template(ogTitle) {
|
||||
return `${ogTitle} - FloraNet`;
|
||||
useMeta(() => {
|
||||
return {
|
||||
title: "FloraNet",
|
||||
meta: {
|
||||
description: {
|
||||
name: "description",
|
||||
content: `${products.value.current?.description}`,
|
||||
},
|
||||
keywords: {
|
||||
name: "keywords",
|
||||
content: `${products.value.current?.title}`,
|
||||
},
|
||||
equiv: {
|
||||
"http-equiv": "Content-Type",
|
||||
content: "text/html; charset=UTF-8",
|
||||
},
|
||||
ogTitle: {
|
||||
property: "og:title",
|
||||
template(ogTitle) {
|
||||
return `${ogTitle} - FloraNet`;
|
||||
},
|
||||
},
|
||||
noscript: {
|
||||
default: "This is content for browsers with no JS (or disabled JS)",
|
||||
},
|
||||
},
|
||||
noscript: {
|
||||
default: "This is content for browsers with no JS (or disabled JS)",
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
});
|
||||
|
||||
const checkImageValidity = (imageLink) => {
|
||||
const validExtensions = [".jpg", ".jpeg", ".png"];
|
||||
|
@ -113,15 +136,28 @@ export default defineComponent({
|
|||
return true;
|
||||
};
|
||||
|
||||
const addModal = () => {
|
||||
if (!isAvailabilityEmpty.value) {
|
||||
addToCart(products.value.current, dedication);
|
||||
return;
|
||||
}
|
||||
openModal({ modal: "availability" });
|
||||
};
|
||||
|
||||
const handlePagClick = () => {
|
||||
handleReset();
|
||||
};
|
||||
|
||||
return {
|
||||
addModal,
|
||||
openModal,
|
||||
handlePagClick,
|
||||
checkImageValidity,
|
||||
slide: ref(1),
|
||||
fullscreen: ref(false),
|
||||
dedication,
|
||||
dedicationAttrs,
|
||||
products,
|
||||
featuredProducts,
|
||||
addCartLoadingBtn,
|
||||
};
|
||||
},
|
||||
|
@ -156,9 +192,9 @@ export default defineComponent({
|
|||
<span class="green-text" style="display: inline-flex">
|
||||
{{ products.current?.id }}
|
||||
<q-skeleton
|
||||
v-if="!products.current?.id"
|
||||
width="100px"
|
||||
type="text"
|
||||
v-if="!products.current?.id"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
|
@ -168,9 +204,9 @@ export default defineComponent({
|
|||
<span class="green-text">
|
||||
{{ products.current?.type }}
|
||||
<q-skeleton
|
||||
v-if="!products.current?.type"
|
||||
type="text"
|
||||
width="50px"
|
||||
v-if="!products.current?.type"
|
||||
/>
|
||||
</span>
|
||||
</p>
|
||||
|
@ -182,10 +218,10 @@ export default defineComponent({
|
|||
<p class="product-price green-text">
|
||||
{{ products.current?.price }}€
|
||||
<q-skeleton
|
||||
v-if="!products.current?.price"
|
||||
type="text"
|
||||
height="90px"
|
||||
width="80px"
|
||||
v-if="!products.current?.price"
|
||||
/>
|
||||
</p>
|
||||
<p class="product-delivery green-text">Envío Gratuito</p>
|
||||
|
@ -227,7 +263,7 @@ export default defineComponent({
|
|||
color="primary"
|
||||
class="btn sm-btn"
|
||||
label="AÑADIR AL CARRITO"
|
||||
@click="openModal({ modal: 'availability' })"
|
||||
@click="addModal"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -254,7 +290,7 @@ export default defineComponent({
|
|||
color="white"
|
||||
class="btn outlined rounded sm-btn product-pag-item product-prev-btn"
|
||||
:to="`${+$route.params.id - 1}`"
|
||||
@click="products.current.value = undefined"
|
||||
@click="handlePagClick"
|
||||
>
|
||||
<IconArrowCircleFilledLeft />
|
||||
|
||||
|
@ -271,6 +307,7 @@ export default defineComponent({
|
|||
color="white"
|
||||
class="btn outlined rounded sm-btn product-pag-item product-next-btn"
|
||||
:to="`${+$route.params.id + 1}`"
|
||||
@click="handlePagClick"
|
||||
>
|
||||
<div class="btn-pag-paragraphs">
|
||||
<p class="btn-paragraph-top green-text">Siguiente producto</p>
|
||||
|
@ -293,8 +330,7 @@ export default defineComponent({
|
|||
Quizás también te gusten estos ramos
|
||||
</h3>
|
||||
|
||||
<p class="like-another-paragraph">
|
||||
</p>
|
||||
<p class="like-another-paragraph"></p>
|
||||
</header>
|
||||
|
||||
<Container cardContainer class="no-padding">
|
||||
|
@ -361,6 +397,7 @@ export default defineComponent({
|
|||
height: 396px;
|
||||
& .q-carousel__navigation {
|
||||
bottom: -83px;
|
||||
display: block;
|
||||
& .q-carousel__navigation-inner {
|
||||
gap: 12px;
|
||||
& .q-carousel__thumbnail {
|
||||
|
|
|
@ -26,6 +26,11 @@ const routes = [
|
|||
name: "Plantas",
|
||||
component: () => import("pages/CategoryPage.vue"),
|
||||
},
|
||||
{
|
||||
path: "all",
|
||||
name: "All",
|
||||
component: () => import("pages/CategoryPage.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -37,7 +42,17 @@ const routes = [
|
|||
path: "",
|
||||
name: "Checkout",
|
||||
component: () => import("pages/CheckoutPage.vue"),
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "success",
|
||||
name: "CheckoutSuccess",
|
||||
component: () => import("pages/CheckoutSuccessPage.vue"),
|
||||
},
|
||||
{
|
||||
path: "error",
|
||||
name: "CheckoutError",
|
||||
component: () => import("pages/CheckoutErrorPage.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,40 +1,55 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { defineStore, storeToRefs } from "pinia";
|
||||
import { computed, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { apiBack } from "src/boot/axios";
|
||||
import { quasarNotify } from "src/functions/quasarNotify";
|
||||
import { useLocalStorage } from "src/hooks/useLocalStorage";
|
||||
import { useFormStore } from "./forms";
|
||||
|
||||
export const useCartStore = defineStore("cart", () => {
|
||||
const { push } = useRouter();
|
||||
const { addItem, getItem, removeItem } = useLocalStorage()
|
||||
const { addItem, getItem } = useLocalStorage();
|
||||
|
||||
const formStore = useFormStore();
|
||||
const { availability: availabilityForm } = storeToRefs(formStore);
|
||||
|
||||
//! Elements
|
||||
const checkoutRef = ref(null);
|
||||
const homeSection = ref(null);
|
||||
|
||||
const initialValues = [{
|
||||
id: null,
|
||||
name: "",
|
||||
price: null,
|
||||
image: "",
|
||||
description: "",
|
||||
dateExpired: "",
|
||||
isNew: null,
|
||||
type: "",
|
||||
postalCode: "",
|
||||
order_position: null,
|
||||
recommend: null
|
||||
}]
|
||||
const initialValues = [
|
||||
{
|
||||
id: null,
|
||||
name: "",
|
||||
price: null,
|
||||
image: "",
|
||||
description: "",
|
||||
dateExpired: "",
|
||||
isNew: null,
|
||||
type: "",
|
||||
postalCode: "",
|
||||
order_position: null,
|
||||
recommend: null,
|
||||
},
|
||||
];
|
||||
|
||||
//! Variables
|
||||
const cart = ref([]);
|
||||
|
||||
(() => {
|
||||
cart.value = getItem('cart');
|
||||
})()
|
||||
|
||||
const cart = ref(getItem("cart"));
|
||||
const availability = ref(getItem("availability"));
|
||||
const filteredAvailabilityForm = computed(() => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(availabilityForm.value).filter(
|
||||
([key, value]) => value !== ""
|
||||
)
|
||||
);
|
||||
});
|
||||
const isAvailabilityEmpty = computed(() => {
|
||||
return (
|
||||
Object.keys(filteredAvailabilityForm.value || availability.value)
|
||||
.length === 0
|
||||
);
|
||||
});
|
||||
const addCartLoadingBtn = ref(false);
|
||||
const routeId = ref(null);
|
||||
const products = ref({
|
||||
|
@ -43,44 +58,8 @@ export const useCartStore = defineStore("cart", () => {
|
|||
current: initialValues,
|
||||
next: initialValues,
|
||||
});
|
||||
const featuredProducts = ref({
|
||||
page: undefined,
|
||||
productsPerPage: undefined,
|
||||
products: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* Transforms options object into params object.
|
||||
*
|
||||
* @param {Object} options - The options object.
|
||||
* @param {number} options.itens - The items array.
|
||||
* @param {boolean} options.featured - The featured flag.
|
||||
* @param {number} options.page - The page number.
|
||||
* @param {string} options.type - The type name.
|
||||
* @param {string} options.postalCode - The postal code.
|
||||
* @param {string} options.dateExpired - The expiration date.
|
||||
* @param {number} options.minPrice - The minimum price.
|
||||
* @param {number} options.maxPrice - The maximum price.
|
||||
* @param {number} options.bigPrice - The big price.
|
||||
* @param {number} options.lowPrice - The low price.
|
||||
* @param {boolean} options.isNew - The new flag.
|
||||
* @returns {Object} - The params object.
|
||||
*/
|
||||
function transformOptionsToParams(
|
||||
options = {
|
||||
postalCode: undefined,
|
||||
dateExpired: undefined,
|
||||
type: undefined,
|
||||
minPrice: undefined,
|
||||
maxPrice: undefined,
|
||||
bigPrice: undefined,
|
||||
lowPrice: undefined,
|
||||
isNew: undefined,
|
||||
order_crescent: undefined,
|
||||
order_descending: undefined,
|
||||
recommend: undefined,
|
||||
}
|
||||
) {
|
||||
function transformOptionsToParams(options = {}) {
|
||||
const optionsObj = {
|
||||
postalCode: options.postalCode,
|
||||
dateExpired: options.dateExpired,
|
||||
|
@ -105,24 +84,7 @@ export const useCartStore = defineStore("cart", () => {
|
|||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches products based on the provided options.
|
||||
*
|
||||
* @param {Object} options - The options for fetching products.
|
||||
* @param {number} options.itens - The items to fetch.
|
||||
* @param {boolean} options.featured - Whether to fetch only featured products.
|
||||
* @param {number} options.page - The page number to fetch.
|
||||
* @param {string} options.type - The type of products to fetch.
|
||||
* @param {string} options.postalCode - The postal code for filtering products.
|
||||
* @param {string} options.dateExpired - The expiration date for filtering products.
|
||||
* @param {number} options.minPrice - The minimum price for filtering products.
|
||||
* @param {number} options.maxPrice - The maximum price for filtering products.
|
||||
* @param {number} options.bigPrice - The big price for filtering products.
|
||||
* @param {number} options.lowPrice - The low price for filtering products.
|
||||
* @param {boolean} options.isNew - Whether to fetch only new products.
|
||||
* @param {Function} navigate - The navigation function to call after fetching products.
|
||||
* @returns {Promise<void>} - A promise that resolves when the products are fetched.
|
||||
*/
|
||||
const isEmpty = ref(false);
|
||||
async function getProducts(
|
||||
options = {
|
||||
postalCode: undefined,
|
||||
|
@ -137,16 +99,17 @@ export const useCartStore = defineStore("cart", () => {
|
|||
order_descending: undefined,
|
||||
recommend: undefined,
|
||||
},
|
||||
scrollIntoView = () => { }
|
||||
callback
|
||||
) {
|
||||
const params = transformOptionsToParams(options);
|
||||
console.log(params);
|
||||
|
||||
try {
|
||||
const { data: { data } } = await apiBack.get("products", { params });
|
||||
|
||||
const {
|
||||
data: { data },
|
||||
} = await apiBack.get("products", { params });
|
||||
|
||||
if (data.length === 0) {
|
||||
isEmpty.value = true;
|
||||
return quasarNotify({
|
||||
message:
|
||||
"No hay productos disponibles para la fecha y el código postal seleccionados",
|
||||
|
@ -154,10 +117,11 @@ export const useCartStore = defineStore("cart", () => {
|
|||
});
|
||||
}
|
||||
|
||||
isEmpty.value = false;
|
||||
products.value.data = data;
|
||||
|
||||
if (scrollIntoView) {
|
||||
scrollIntoView();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
console.groupCollapsed("%c PRODUCTS FETCHED!", "color: green;");
|
||||
|
@ -182,17 +146,6 @@ export const useCartStore = defineStore("cart", () => {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a product by its ID and updates the cart state.
|
||||
*
|
||||
* @param {string} id - The ID of the product to fetch.
|
||||
* @param {object} options - Additional options for the product fetch.
|
||||
* @param {string} options.type - The type of the product.
|
||||
* @param {string} options.postalCode - The postal code for location-based filtering.
|
||||
* @param {string} options.dateExpired - The expiration date for time-based filtering.
|
||||
* @param {boolean} debug - Flag indicating whether to enable debug mode.
|
||||
* @returns {Promise<void>} - A promise that resolves when the product is fetched and the cart state is updated.
|
||||
*/
|
||||
async function getProduct(
|
||||
id,
|
||||
options = {
|
||||
|
@ -220,14 +173,14 @@ export const useCartStore = defineStore("cart", () => {
|
|||
};
|
||||
|
||||
return result[res.status].data[0];
|
||||
})
|
||||
});
|
||||
|
||||
products.value.prev = prev;
|
||||
products.value.current = current;
|
||||
products.value.next = next;
|
||||
|
||||
if (!current) {
|
||||
push({ name: "NotFound" })
|
||||
push({ name: "NotFound" });
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
|
@ -250,92 +203,48 @@ export const useCartStore = defineStore("cart", () => {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves featured products based on the provided options.
|
||||
*
|
||||
* @param {Object} options - The options for retrieving featured products.
|
||||
* @param {number} options.itens - The number of items to retrieve.
|
||||
* @param {number} options.featured - The flag indicating if the products should be featured.
|
||||
* @param {number} [options.page] - The page number for pagination.
|
||||
* @param {string} [options.type] - The type of the products.
|
||||
* @param {string} [options.postalCode] - The postal code for location-based filtering.
|
||||
* @param {string} [options.dateExpired] - The expiration date for filtering.
|
||||
* @param {number} [options.minPrice] - The minimum price for filtering.
|
||||
* @param {number} [options.maxPrice] - The maximum price for filtering.
|
||||
* @param {number} [options.bigPrice] - The big price for filtering.
|
||||
* @param {number} [options.lowPrice] - The low price for filtering.
|
||||
* @param {boolean} [options.isNew] - The flag indicating if the products are new.
|
||||
* @returns {Promise<void>} - A promise that resolves when the featured products are retrieved.
|
||||
*/
|
||||
async function getFeaturedProducts(
|
||||
options = {
|
||||
postalCode: undefined,
|
||||
dateExpired: undefined,
|
||||
type: undefined,
|
||||
minPrice: undefined,
|
||||
maxPrice: undefined,
|
||||
bigPrice: undefined,
|
||||
lowPrice: undefined,
|
||||
isNew: undefined,
|
||||
order_crescent: undefined,
|
||||
order_descending: undefined,
|
||||
recommend: 1,
|
||||
},
|
||||
debug = false
|
||||
) {
|
||||
try {
|
||||
const params = transformOptionsToParams(options);
|
||||
async function addToCart(product, message) {
|
||||
const params = transformOptionsToParams(
|
||||
availabilityForm.value || availability.value
|
||||
);
|
||||
await getProducts(params);
|
||||
|
||||
(async () => {
|
||||
const {
|
||||
data: { data },
|
||||
} = await apiBack.get("products", { params });
|
||||
featuredProducts.value = data[0];
|
||||
|
||||
if (debug) {
|
||||
console.groupCollapsed(
|
||||
"%c FEATURED PRODUCTS FETCHED!",
|
||||
"color: green;"
|
||||
);
|
||||
console.table(data.products);
|
||||
console.groupEnd();
|
||||
}
|
||||
})();
|
||||
} catch (err) {
|
||||
new Error(`FATAL ERROR ::: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adiciona um produto ao carrinho.
|
||||
* @param {Object} product - O produto a ser adicionado.
|
||||
* @param {string} dedication - A dedicação associada ao produto.
|
||||
*/
|
||||
function addToCart(product, dedication) {
|
||||
const existingProduct = cart.value.find(p => p.id === product.id);
|
||||
console.log(existingProduct)
|
||||
|
||||
if (!existingProduct) {
|
||||
const arr = [...cart.value];
|
||||
arr.push(product);
|
||||
console.log(arr)
|
||||
addItem("cart", JSON.stringify(arr));
|
||||
quasarNotify({ message: 'Producto añadido al carrito.', type: 'success' })
|
||||
return
|
||||
}
|
||||
quasarNotify({
|
||||
message: "Este producto ya está en el carrito",
|
||||
type: "info",
|
||||
const hasCurrentProduct = computed(() => {
|
||||
return cart.value.find((p) => p.id === product.id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an item from the cart by its ID.
|
||||
* @param {number} id - The ID of the item to be removed.
|
||||
*/
|
||||
function removeFromCart(id) {
|
||||
const newArrRemovedItem = cart.value.filter((p) => id !== p.id);
|
||||
addItem("cart", JSON.stringify(newArrRemovedItem))
|
||||
if (isEmpty.value) {
|
||||
push("/");
|
||||
return quasarNotify({
|
||||
message:
|
||||
"No hay productos disponibles para la fecha y el código postal seleccionados",
|
||||
type: "erro",
|
||||
});
|
||||
}
|
||||
if (!products.value.data.some((item) => item.id === product.id)) {
|
||||
push("/");
|
||||
return quasarNotify({
|
||||
message:
|
||||
"Este producto no está disponible en su zona, intente añadir un nuevo código postal",
|
||||
type: "erro",
|
||||
});
|
||||
}
|
||||
|
||||
if (hasCurrentProduct.value) {
|
||||
return quasarNotify({
|
||||
message: "Este producto ya está en el carrito",
|
||||
type: "info",
|
||||
});
|
||||
}
|
||||
|
||||
const arr = [...cart.value];
|
||||
arr.push({ ...product, message: message.value });
|
||||
cart.value = arr;
|
||||
addItem("cart", arr);
|
||||
quasarNotify({
|
||||
message: "Producto añadido al carrito.",
|
||||
type: "success",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -345,12 +254,9 @@ export const useCartStore = defineStore("cart", () => {
|
|||
cart,
|
||||
addCartLoadingBtn,
|
||||
products,
|
||||
featuredProducts,
|
||||
|
||||
getFeaturedProducts,
|
||||
getProducts,
|
||||
addToCart,
|
||||
removeFromCart,
|
||||
getProduct,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ export const useFormStore = defineStore("forms", {
|
|||
terms: false,
|
||||
},
|
||||
availability: {
|
||||
date: "",
|
||||
dateExpired: "",
|
||||
postalCode: "",
|
||||
},
|
||||
checkout: {
|
||||
|
@ -34,28 +34,23 @@ export const useFormStore = defineStore("forms", {
|
|||
senderEmail: "",
|
||||
senderPhone: "",
|
||||
senderNotes: "",
|
||||
paymentMethod: "credit",
|
||||
paymentMethod: "paypal",
|
||||
terms: false,
|
||||
},
|
||||
}),
|
||||
|
||||
actions: {
|
||||
handleQuestionData(values) {
|
||||
console.log(values);
|
||||
this.question = values;
|
||||
},
|
||||
|
||||
handleAvailabilityData(values) {
|
||||
console.log(values);
|
||||
this.availability = values;
|
||||
},
|
||||
|
||||
registerAvailability() {
|
||||
console.log(this.availability);
|
||||
},
|
||||
registerAvailability() {},
|
||||
|
||||
handleCheckoutData(values) {
|
||||
// console.log(values);
|
||||
this.checkout = values;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -23,8 +23,7 @@ export const useModalStore = defineStore("modal", () => {
|
|||
isOpenAvailability: () => "Contenido modal availability",
|
||||
isOpenFilters: () => "Contenido modal filters",
|
||||
};
|
||||
console.log(availability.value);
|
||||
console.log(isModal[content]());
|
||||
isModal[content]()
|
||||
}
|
||||
|
||||
return { openModal, handleSubmit, isOpenAvailability, isOpenFilters };
|
||||
|
|
|
@ -8,7 +8,6 @@ export const useRangePriceStore = defineStore("range-price", () => {
|
|||
});
|
||||
|
||||
function handlePriceRange({ min, max }) {
|
||||
console.log({ min, max });
|
||||
rangeValue.min = min;
|
||||
rangeValue.max = max;
|
||||
}
|
||||
|
|
|
@ -21,16 +21,18 @@ const checkoutObjVal = {
|
|||
phone: z
|
||||
.string({ required_error: M.requiredMessage })
|
||||
.refine(handlePhoneVal, M.phoneMessage),
|
||||
senderName: z.string().regex(justOneWord, M.nameMessage),
|
||||
senderName: z.string().regex(justLetters, M.nameMessage),
|
||||
senderCifNif: z
|
||||
.string()
|
||||
.length(9, "El código postal debe tener 9 caracteres numéricos válidos"),
|
||||
senderEmail: z.string().email(M.emailMessage),
|
||||
senderPhone: z.string().refine(handlePhoneVal, M.phoneMessage),
|
||||
senderNotes: z.string(),
|
||||
paymentMethod: z.enum(["credit", "stripe"], {
|
||||
required_error: "Seleccione uno de los métodos de pago!",
|
||||
}),
|
||||
paymentMethod: z
|
||||
.enum(["credit", "paypal"], {
|
||||
required_error: "Seleccione uno de los métodos de pago!",
|
||||
})
|
||||
.default("paypal"),
|
||||
terms: z.boolean().refine((val) => {
|
||||
return val === true;
|
||||
}, "Acepte las condiciones antes de continuar con la compra"),
|
||||
|
|
|
@ -2,9 +2,7 @@ import { z } from "zod";
|
|||
|
||||
const rangePriceObj = {
|
||||
range: z.object({
|
||||
min: z
|
||||
.number()
|
||||
.refine((n) => n > 0, "El valor mínimo debe ser superior a cero"),
|
||||
min: z.number(),
|
||||
max: z.number(),
|
||||
}),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue