product page and linter
This commit is contained in:
13
.husky/hooks/pre-commit
Executable file
13
.husky/hooks/pre-commit
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
command_name_bun="bun"
|
||||||
|
if ! command -v "$command_name_bun" &> /dev/null; then
|
||||||
|
echo "Command '$command_name_bun' not found. Installing..."
|
||||||
|
npm install -g "$command_name_bun"@latest
|
||||||
|
else
|
||||||
|
"$command_name_bun" lint || exit 1 && cd ..
|
||||||
|
fi
|
||||||
|
|
5
app.vue
5
app.vue
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="main bg-bg-light text-text-light dark:text-text-dark dark:bg-bg-dark">
|
<div
|
||||||
|
class="main bg-bg-light text-text-light dark:text-text-dark dark:bg-bg-dark"
|
||||||
|
>
|
||||||
<UApp>
|
<UApp>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
@ -7,6 +9,7 @@
|
|||||||
</UApp>
|
</UApp>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
@import "@nuxt/ui";
|
@import '@nuxt/ui';
|
||||||
@import "tailwindcss";
|
@import 'tailwindcss';
|
||||||
@import '@iconscout/unicons/css/line.css';
|
@import '@iconscout/unicons/css/line.css';
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
/* fonts */
|
/* fonts */
|
||||||
--font-inter: "Inter", sans-serif;
|
--font-inter: 'Inter', sans-serif;
|
||||||
--font-bounded: "Bounded", sans-serif;
|
--font-bounded: 'Bounded', sans-serif;
|
||||||
|
|
||||||
/* colors */
|
/* colors */
|
||||||
--color-bg-light: #fffefb;
|
--color-bg-light: #fffefb;
|
||||||
@ -16,12 +16,12 @@
|
|||||||
--color-text-light: #1a1a1a;
|
--color-text-light: #1a1a1a;
|
||||||
--color-text-dark: #fffefb;
|
--color-text-dark: #fffefb;
|
||||||
|
|
||||||
--color-block: #E8E7E0;
|
--color-block: #e8e7e0;
|
||||||
|
|
||||||
--color-accent-green-light: #004F3D;
|
--color-accent-green-light: #004f3d;
|
||||||
--color-accent-green-dark: #008567;
|
--color-accent-green-dark: #008567;
|
||||||
|
|
||||||
--color-gray: #6B6B6B;
|
--color-gray: #6b6b6b;
|
||||||
/* button */
|
/* button */
|
||||||
--color-button: #9a7f62;
|
--color-button: #9a7f62;
|
||||||
--color-button-hover: #b7946d;
|
--color-button-hover: #b7946d;
|
||||||
@ -54,23 +54,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.space-25-55-75 {
|
.space-25-55-75 {
|
||||||
@apply space-y-[25px] sm:space-y-[55px] md:space-y-[75px]
|
@apply space-y-[25px] sm:space-y-[55px] md:space-y-[75px];
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-25-55 {
|
.space-25-55 {
|
||||||
@apply space-y-[25px] sm:space-y-[55px]
|
@apply space-y-[25px] sm:space-y-[55px];
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-25-75 {
|
.space-25-75 {
|
||||||
@apply space-y-[25px] sm:space-y-[75px]
|
@apply space-y-[25px] sm:space-y-[75px];
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-55-75 {
|
.space-55-75 {
|
||||||
@apply space-y-[55px] sm:space-y-[75px]
|
@apply space-y-[55px] sm:space-y-[75px];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,51 @@
|
|||||||
/* ===== Base toast style (applies to all toasts) ===== */
|
/* ===== Base toast style (applies to all toasts) ===== */
|
||||||
.Toastify__toast {
|
.Toastify__toast {
|
||||||
font-family: var(--font-inter);
|
font-family: var(--font-inter);
|
||||||
background-color: var(--color-bg-light);
|
background-color: var(--color-bg-light);
|
||||||
border: 2px solid var(--color-block);
|
border: 2px solid var(--color-block);
|
||||||
color: var(--color-bg-dark);
|
color: var(--color-bg-dark);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Base toast style for dark mode ===== */
|
/* ===== Base toast style for dark mode ===== */
|
||||||
.dark .Toastify__toast {
|
.dark .Toastify__toast {
|
||||||
background-color: var(--color-bg-dark);
|
background-color: var(--color-bg-dark);
|
||||||
border: 1px solid var(--color-block);
|
border: 1px solid var(--color-block);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Error toast: red background and white text ===== */
|
/* ===== Error toast: red background and white text ===== */
|
||||||
.Toastify__toast--error {
|
.Toastify__toast--error {
|
||||||
background-color: var(--color-bg-light);
|
background-color: var(--color-bg-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Error toast in dark mode: darker red background ===== */
|
/* ===== Error toast in dark mode: darker red background ===== */
|
||||||
.dark .Toastify__toast--error {
|
.dark .Toastify__toast--error {
|
||||||
background-color: var(--color-bg-dark);
|
background-color: var(--color-bg-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Default progress bar color (used for success and others) ===== */
|
/* ===== Default progress bar color (used for success and others) ===== */
|
||||||
.Toastify__progress-bar {
|
.Toastify__progress-bar {
|
||||||
background-color: var(--color-accent-green-dark);
|
background-color: var(--color-accent-green-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Error toast: custom progress bar color ===== */
|
/* ===== Error toast: custom progress bar color ===== */
|
||||||
.Toastify__toast--error .Toastify__progress-bar {
|
.Toastify__toast--error .Toastify__progress-bar {
|
||||||
background-color: #dc3545;
|
background-color: #dc3545;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Success toast: icon color ===== */
|
/* ===== Success toast: icon color ===== */
|
||||||
.Toastify__toast--success .Toastify__toast-icon svg {
|
.Toastify__toast--success .Toastify__toast-icon svg {
|
||||||
fill: var(--color-accent-green-dark);
|
fill: var(--color-accent-green-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Error toast: icon color ===== */
|
/* ===== Error toast: icon color ===== */
|
||||||
.Toastify__toast--error .Toastify__toast-icon svg {
|
.Toastify__toast--error .Toastify__toast-icon svg {
|
||||||
fill: #dc3545;
|
fill: #dc3545;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Close button color in dark mode ===== */
|
/* ===== Close button color in dark mode ===== */
|
||||||
.dark .Toastify__close-button {
|
.dark .Toastify__close-button {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
23
bun.lock
23
bun.lock
@ -20,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
|
"eslint-plugin-format": "^1.0.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -104,6 +105,12 @@
|
|||||||
|
|
||||||
"@dependents/detective-less": ["@dependents/detective-less@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ=="],
|
"@dependents/detective-less": ["@dependents/detective-less@5.0.1", "", { "dependencies": { "gonzales-pe": "^4.3.0", "node-source-walk": "^7.0.1" } }, "sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ=="],
|
||||||
|
|
||||||
|
"@dprint/formatter": ["@dprint/formatter@0.3.0", "", {}, "sha512-N9fxCxbaBOrDkteSOzaCqwWjso5iAe+WJPsHC021JfHNj2ThInPNEF13ORDKta3llq5D1TlclODCvOvipH7bWQ=="],
|
||||||
|
|
||||||
|
"@dprint/markdown": ["@dprint/markdown@0.17.8", "", {}, "sha512-ukHFOg+RpG284aPdIg7iPrCYmMs3Dqy43S1ejybnwlJoFiW02b+6Bbr5cfZKFRYNP3dKGM86BqHEnMzBOyLvvA=="],
|
||||||
|
|
||||||
|
"@dprint/toml": ["@dprint/toml@0.6.4", "", {}, "sha512-bZXIUjxr0LIuHWshZr/5mtUkOrnh0NKVZEF6ACojW5z7zkJu7s9sV2mMXm8XQDqN4cJzdHYUYzUyEGdfciaLJA=="],
|
||||||
|
|
||||||
"@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
"@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" } }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||||
|
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||||
@ -400,6 +407,8 @@
|
|||||||
|
|
||||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||||
|
|
||||||
|
"@pkgr/core": ["@pkgr/core@0.1.2", "", {}, "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ=="],
|
||||||
|
|
||||||
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
|
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
|
||||||
|
|
||||||
"@poppinss/colors": ["@poppinss/colors@4.1.4", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog=="],
|
"@poppinss/colors": ["@poppinss/colors@4.1.4", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog=="],
|
||||||
@ -1114,10 +1123,16 @@
|
|||||||
|
|
||||||
"eslint-flat-config-utils": ["eslint-flat-config-utils@2.1.0", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-6fjOJ9tS0k28ketkUcQ+kKptB4dBZY2VijMZ9rGn8Cwnn1SH0cZBoPXT8AHBFHxmHcLFQK9zbELDinZ2Mr1rng=="],
|
"eslint-flat-config-utils": ["eslint-flat-config-utils@2.1.0", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-6fjOJ9tS0k28ketkUcQ+kKptB4dBZY2VijMZ9rGn8Cwnn1SH0cZBoPXT8AHBFHxmHcLFQK9zbELDinZ2Mr1rng=="],
|
||||||
|
|
||||||
|
"eslint-formatting-reporter": ["eslint-formatting-reporter@0.0.0", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0" }, "peerDependencies": { "eslint": ">=8.40.0" } }, "sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw=="],
|
||||||
|
|
||||||
"eslint-import-context": ["eslint-import-context@0.1.8", "", { "dependencies": { "get-tsconfig": "^4.10.1", "stable-hash-x": "^0.1.1" }, "peerDependencies": { "unrs-resolver": "^1.0.0" }, "optionalPeers": ["unrs-resolver"] }, "sha512-bq+F7nyc65sKpZGT09dY0S0QrOnQtuDVIfyTGQ8uuvtMIF7oHp6CEP3mouN0rrnYF3Jqo6Ke0BfU/5wASZue1w=="],
|
"eslint-import-context": ["eslint-import-context@0.1.8", "", { "dependencies": { "get-tsconfig": "^4.10.1", "stable-hash-x": "^0.1.1" }, "peerDependencies": { "unrs-resolver": "^1.0.0" }, "optionalPeers": ["unrs-resolver"] }, "sha512-bq+F7nyc65sKpZGT09dY0S0QrOnQtuDVIfyTGQ8uuvtMIF7oHp6CEP3mouN0rrnYF3Jqo6Ke0BfU/5wASZue1w=="],
|
||||||
|
|
||||||
"eslint-merge-processors": ["eslint-merge-processors@2.0.0", "", { "peerDependencies": { "eslint": "*" } }, "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA=="],
|
"eslint-merge-processors": ["eslint-merge-processors@2.0.0", "", { "peerDependencies": { "eslint": "*" } }, "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA=="],
|
||||||
|
|
||||||
|
"eslint-parser-plain": ["eslint-parser-plain@0.1.1", "", {}, "sha512-KRgd6wuxH4U8kczqPp+Oyk4irThIhHWxgFgLDtpgjUGVIS3wGrJntvZW/p6hHq1T4FOwnOtCNkvAI4Kr+mQ/Hw=="],
|
||||||
|
|
||||||
|
"eslint-plugin-format": ["eslint-plugin-format@1.0.1", "", { "dependencies": { "@dprint/formatter": "^0.3.0", "@dprint/markdown": "^0.17.8", "@dprint/toml": "^0.6.4", "eslint-formatting-reporter": "^0.0.0", "eslint-parser-plain": "^0.1.1", "prettier": "^3.4.2", "synckit": "^0.9.2" }, "peerDependencies": { "eslint": "^8.40.0 || ^9.0.0" } }, "sha512-Tdns+CDjS+m7QrM85wwRi2yLae88XiWVdIOXjp9mDII0pmTBQlczPCmjpKnjiUIY3yPZNLqb5Ms/A/JXcBF2Dw=="],
|
||||||
|
|
||||||
"eslint-plugin-import-x": ["eslint-plugin-import-x@4.15.2", "", { "dependencies": { "@typescript-eslint/types": "^8.34.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.8", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", "stable-hash-x": "^0.1.1", "unrs-resolver": "^1.9.0" }, "peerDependencies": { "@typescript-eslint/utils": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-J5gx7sN6DTm0LRT//eP3rVVQ2Yi4hrX0B+DbWxa5er8PZ6JjLo9GUBwogIFvEDdwJaSqZplpQT+haK/cXhb7VQ=="],
|
"eslint-plugin-import-x": ["eslint-plugin-import-x@4.15.2", "", { "dependencies": { "@typescript-eslint/types": "^8.34.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.8", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", "stable-hash-x": "^0.1.1", "unrs-resolver": "^1.9.0" }, "peerDependencies": { "@typescript-eslint/utils": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-J5gx7sN6DTm0LRT//eP3rVVQ2Yi4hrX0B+DbWxa5er8PZ6JjLo9GUBwogIFvEDdwJaSqZplpQT+haK/cXhb7VQ=="],
|
||||||
|
|
||||||
"eslint-plugin-jsdoc": ["eslint-plugin-jsdoc@50.8.0", "", { "dependencies": { "@es-joy/jsdoccomment": "~0.50.2", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.4.1", "escape-string-regexp": "^4.0.0", "espree": "^10.3.0", "esquery": "^1.6.0", "parse-imports-exports": "^0.2.4", "semver": "^7.7.2", "spdx-expression-parse": "^4.0.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg=="],
|
"eslint-plugin-jsdoc": ["eslint-plugin-jsdoc@50.8.0", "", { "dependencies": { "@es-joy/jsdoccomment": "~0.50.2", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.4.1", "escape-string-regexp": "^4.0.0", "espree": "^10.3.0", "esquery": "^1.6.0", "parse-imports-exports": "^0.2.4", "semver": "^7.7.2", "spdx-expression-parse": "^4.0.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg=="],
|
||||||
@ -1168,6 +1183,8 @@
|
|||||||
|
|
||||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
|
||||||
|
|
||||||
"fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="],
|
"fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="],
|
||||||
|
|
||||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||||
@ -1910,6 +1927,10 @@
|
|||||||
|
|
||||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||||
|
|
||||||
|
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
|
||||||
|
|
||||||
|
"prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
|
||||||
|
|
||||||
"pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
|
"pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
|
||||||
|
|
||||||
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
|
"process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
|
||||||
@ -2166,6 +2187,8 @@
|
|||||||
|
|
||||||
"svgstore": ["svgstore@3.0.1", "", { "dependencies": { "cheerio": "v1.0.0-rc.10" } }, "sha512-nL6WTxYnsVl3e0G/mwGEFSnPAWUrzIwHAPOwInD4QUuLDKxaKMnXduf0Ipw3m/g9AldPhp1Y8E/nkReFBukJrA=="],
|
"svgstore": ["svgstore@3.0.1", "", { "dependencies": { "cheerio": "v1.0.0-rc.10" } }, "sha512-nL6WTxYnsVl3e0G/mwGEFSnPAWUrzIwHAPOwInD4QUuLDKxaKMnXduf0Ipw3m/g9AldPhp1Y8E/nkReFBukJrA=="],
|
||||||
|
|
||||||
|
"synckit": ["synckit@0.9.3", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-JJoOEKTfL1urb1mDoEblhD9NhEbWmq9jHEMEnxoC4ujUaZ4itA8vKgwkFAyNClgxplLi9tsUKX+EduK0p/l7sg=="],
|
||||||
|
|
||||||
"system-architecture": ["system-architecture@0.1.0", "", {}, "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA=="],
|
"system-architecture": ["system-architecture@0.1.0", "", {}, "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA=="],
|
||||||
|
|
||||||
"tailwind-config-viewer": ["tailwind-config-viewer@2.0.4", "", { "dependencies": { "@koa/router": "^12.0.1", "commander": "^6.0.0", "fs-extra": "^9.0.1", "koa": "^2.14.2", "koa-static": "^5.0.0", "open": "^7.0.4", "portfinder": "^1.0.26", "replace-in-file": "^6.1.0" }, "peerDependencies": { "tailwindcss": "1 || 2 || 2.0.1-compat || 3" }, "bin": { "tailwind-config-viewer": "cli/index.js", "tailwindcss-config-viewer": "cli/index.js" } }, "sha512-icvcmdMmt9dphvas8wL40qttrHwAnW3QEN4ExJ2zICjwRsPj7gowd1cOceaWG3IfTuM/cTNGQcx+bsjMtmV+cw=="],
|
"tailwind-config-viewer": ["tailwind-config-viewer@2.0.4", "", { "dependencies": { "@koa/router": "^12.0.1", "commander": "^6.0.0", "fs-extra": "^9.0.1", "koa": "^2.14.2", "koa-static": "^5.0.0", "open": "^7.0.4", "portfinder": "^1.0.26", "replace-in-file": "^6.1.0" }, "peerDependencies": { "tailwindcss": "1 || 2 || 2.0.1-compat || 3" }, "bin": { "tailwind-config-viewer": "cli/index.js", "tailwindcss-config-viewer": "cli/index.js" } }, "sha512-icvcmdMmt9dphvas8wL40qttrHwAnW3QEN4ExJ2zICjwRsPj7gowd1cOceaWG3IfTuM/cTNGQcx+bsjMtmV+cw=="],
|
||||||
|
@ -1,105 +1,167 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="dropdownRef">
|
<div ref="dropdownRef">
|
||||||
<div @click="openCart = !openCart" class="relative cursor-pointer">
|
<div class="relative cursor-pointer"
|
||||||
<i class="uil uil-shopping-cart text-[31px]"></i>
|
@click="openCart = !openCart"
|
||||||
<div v-if="productStore.cart.cart_items && productStore.cart.cart_items.length > 0"
|
>
|
||||||
class="w-[15px] h-[15px] rounded-full bg-accent-green-light dark:bg-accent-green-light text-white flex items-center justify-center text-[9px] absolute top-1 right-0">
|
<i class="uil uil-shopping-cart text-[31px]" />
|
||||||
{{ productStore.cart.cart_items.length }}</div>
|
<div
|
||||||
</div>
|
v-if="
|
||||||
<div v-if="openCart" @click.self="openCart = !openCart"
|
productStore.cart.cart_items
|
||||||
class="absolute left-1/2 transform -translate-x-1/2 w-full px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20 right-0 z-50 flex items-center justify-end top-[100px] sm:top-[100px] md:top-[140px]">
|
&& productStore.cart.cart_items.length > 0
|
||||||
<div class="xl:w-[55%] md:w-[90%] w-full px-4 md:px-0">
|
"
|
||||||
<div v-if="productStore.cart.cart_items && productStore.cart.cart_items.length > 0"
|
class="w-[15px] h-[15px] rounded-full bg-accent-green-light dark:bg-accent-green-light text-white flex items-center justify-center text-[9px] absolute top-1 right-0"
|
||||||
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] h-full space-25-55">
|
>
|
||||||
<div>
|
{{ productStore.cart.cart_items.length }}
|
||||||
<!-- product -->
|
</div>
|
||||||
<div v-for="item in productStore.cart.cart_items"
|
|
||||||
class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block">
|
|
||||||
<div class="flex items-center h-[100px] sm:h-[205px]">
|
|
||||||
<div
|
|
||||||
class="min-w-[100px] sm:min-w-[205px] flex items-center justify-center h-[100px] sm:h-[205px]">
|
|
||||||
<img :src="`/api/public/file/${item.picture_uuid}.webp`"
|
|
||||||
alt="" class="max-w-full max-h-full object-contain">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
|
|
||||||
<div class="w-full flex items-center justify-between">
|
|
||||||
<h3
|
|
||||||
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
|
|
||||||
{{ item.name }}
|
|
||||||
</h3>
|
|
||||||
<i @click="productStore.deleteCartItem(item.cart_item_id)"
|
|
||||||
class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"></i>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-[10px]">
|
|
||||||
<p
|
|
||||||
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
|
|
||||||
{{ item.total_price }}
|
|
||||||
</p>
|
|
||||||
<div class="flex items-center gap-[2px] sm:gap-2 text-xl">
|
|
||||||
<div
|
|
||||||
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
|
|
||||||
<i class="uil uil-minus cursor-pointer text-gray dark:text-button-disabled hover:text-gray-200 transition-all"
|
|
||||||
@click="productStore.decrementCartItem(item.cart_item_id)"></i>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="w-5 min-h-5 sm:w-10 sm:min-h-11 text-[10px] sm:text-xl border border-button flex items-center justify-center rounded-[4px]">
|
|
||||||
{{ item.quantity }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
|
|
||||||
<i class="uil uil-plus cursor-pointer hover:text-gray-200 transition-all"
|
|
||||||
@click="productStore.incrementCartItem(item.product_id)"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<h4 class="font-inter text-[12px] leading-[150%] font-bold uppercase sm:text-[24px]">{{
|
|
||||||
$t('total_amount') }}</h4>
|
|
||||||
<p
|
|
||||||
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
|
|
||||||
{{ productStore.cart.total_value }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<UiButtonArrow @click="() => {
|
|
||||||
if (userStore.isLogged) {
|
|
||||||
menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 12))
|
|
||||||
} else {
|
|
||||||
menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))
|
|
||||||
}
|
|
||||||
openCart = false
|
|
||||||
}" class="w-full" type="fill" :arrow="true" :full="true">{{ userStore.isLogged ?
|
|
||||||
$t('to_checkout') : $t('login') }}
|
|
||||||
</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
<div v-else
|
|
||||||
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] flex items-center justify-center">
|
|
||||||
<div
|
|
||||||
class="border border-block inline-flex items-center justify-center h-[140px] sm:h-[200px] text-center rounded-[8px]">
|
|
||||||
<h4
|
|
||||||
class="font-inter text-base leading-[150%] font-bold uppercase sm:text-[20px] px-4 sm:px-10 md:text-xl">
|
|
||||||
{{ $t('empty_cart') }}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="openCart"
|
||||||
|
class="absolute left-1/2 transform -translate-x-1/2 w-full px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20 right-0 z-50 flex items-center justify-end top-[100px] sm:top-[100px] md:top-[140px]"
|
||||||
|
@click.self="openCart = !openCart"
|
||||||
|
>
|
||||||
|
<div class="xl:w-[55%] md:w-[90%] w-full px-4 md:px-0">
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
productStore.cart.cart_items
|
||||||
|
&& productStore.cart.cart_items.length > 0
|
||||||
|
"
|
||||||
|
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] h-full space-25-55"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<!-- product -->
|
||||||
|
<div
|
||||||
|
v-for="item in productStore.cart.cart_items" :key="item.product_id"
|
||||||
|
class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block"
|
||||||
|
>
|
||||||
|
<div class="flex items-center h-[100px] sm:h-[205px]">
|
||||||
|
<div
|
||||||
|
class="min-w-[100px] sm:min-w-[205px] flex items-center justify-center h-[100px] sm:h-[205px]"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${item.picture_uuid}.webp`"
|
||||||
|
alt=""
|
||||||
|
class="max-w-full max-h-full object-contain"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]"
|
||||||
|
>
|
||||||
|
<div class="w-full flex items-center justify-between">
|
||||||
|
<h3
|
||||||
|
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</h3>
|
||||||
|
<i
|
||||||
|
class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"
|
||||||
|
@click="productStore.deleteCartItem(item.cart_item_id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-[10px]">
|
||||||
|
<p
|
||||||
|
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold"
|
||||||
|
>
|
||||||
|
{{ item.total_price }}
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-[2px] sm:gap-2 text-xl">
|
||||||
|
<div
|
||||||
|
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-minus cursor-pointer text-gray dark:text-button-disabled hover:text-gray-200 transition-all"
|
||||||
|
@click="
|
||||||
|
productStore.decrementCartItem(item.cart_item_id)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-5 min-h-5 sm:w-10 sm:min-h-11 text-[10px] sm:text-xl border border-button flex items-center justify-center rounded-[4px]"
|
||||||
|
>
|
||||||
|
{{ item.quantity }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-plus cursor-pointer hover:text-gray-200 transition-all"
|
||||||
|
@click="
|
||||||
|
productStore.incrementCartItem(item.product_id)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h4
|
||||||
|
class="font-inter text-[12px] leading-[150%] font-bold uppercase sm:text-[24px]"
|
||||||
|
>
|
||||||
|
{{ $t("total_amount") }}
|
||||||
|
</h4>
|
||||||
|
<p
|
||||||
|
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold"
|
||||||
|
>
|
||||||
|
{{ productStore.cart.total_value }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<UiButtonArrow
|
||||||
|
class="w-full"
|
||||||
|
type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
:full="true"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (userStore.isLogged) {
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 12),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
openCart = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ userStore.isLogged ? $t("to_checkout") : $t("login") }}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="border border-block inline-flex items-center justify-center h-[140px] sm:h-[200px] text-center rounded-[8px]"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="font-inter text-base leading-[150%] font-bold uppercase sm:text-[20px] px-4 sm:px-10 md:text-xl"
|
||||||
|
>
|
||||||
|
{{ $t("empty_cart") }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import { onClickOutside } from '@vueuse/core'
|
||||||
|
|
||||||
const productStore = useProductStore()
|
const productStore = useProductStore()
|
||||||
const openCart = ref(false);
|
const openCart = ref(false)
|
||||||
|
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const dropdownRef = ref(null);
|
const dropdownRef = ref(null)
|
||||||
onClickOutside(dropdownRef, () => {
|
onClickOutside(dropdownRef, () => {
|
||||||
openCart.value = false
|
openCart.value = false
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,31 +1,64 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2 relative" ref="dropdownRef">
|
<div ref="dropdownRef"
|
||||||
<UButton color="neutral" variant="subtle" trailing-icon="i-lucide-chevron-down"
|
class="flex flex-col gap-2 relative"
|
||||||
|
>
|
||||||
|
<UButton
|
||||||
|
color="neutral"
|
||||||
|
variant="subtle"
|
||||||
|
trailing-icon="i-lucide-chevron-down"
|
||||||
class="bg-bg-light dark:bg-bg-dark m-0 ring-0 text-xl font-medium uppercase cursor-pointer hover:bg-inherit text-text-light dark:text-text-dark"
|
class="bg-bg-light dark:bg-bg-dark m-0 ring-0 text-xl font-medium uppercase cursor-pointer hover:bg-inherit text-text-light dark:text-text-dark"
|
||||||
block @click="isOpen = !isOpen">
|
block
|
||||||
{{ $session.cookieData.value.country.iso_code }}/{{ $session.cookieData.value.currency.iso_code }}
|
@click="isOpen = !isOpen"
|
||||||
|
>
|
||||||
|
{{ $session.cookieData.value.country.iso_code }}/{{
|
||||||
|
$session.cookieData.value.currency.iso_code
|
||||||
|
}}
|
||||||
</UButton>
|
</UButton>
|
||||||
|
|
||||||
<div class="absolute ring-0 top-12 p-0 m-0 border-none w-48 z-50" v-if="isOpen">
|
<div
|
||||||
<div class="border border-button px-4 py-[10px] rounded-[5px] bg-bg-light dark:bg-bg-dark">
|
v-if="isOpen"
|
||||||
|
class="absolute ring-0 top-12 p-0 m-0 border-none w-48 z-50"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="border border-button px-4 py-[10px] rounded-[5px] bg-bg-light dark:bg-bg-dark"
|
||||||
|
>
|
||||||
<div class="p-0 flex flex-col gap-4 bg-bg-light dark:bg-bg-dark">
|
<div class="p-0 flex flex-col gap-4 bg-bg-light dark:bg-bg-dark">
|
||||||
<div class="flex flex-col items-start gap-1">
|
<div class="flex flex-col items-start gap-1">
|
||||||
<p>{{ $t("country") }}</p>
|
<p>{{ $t("country") }}</p>
|
||||||
<div
|
<div
|
||||||
class="w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 space-y-1">
|
class="w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 space-y-1"
|
||||||
<div class="p-0" @click="openDrop('country')">
|
>
|
||||||
<div class="flex items-center gap-2 text-xl font-medium uppercase text-text-light dark:text-text-dark">
|
<div class="p-0"
|
||||||
{{ $session.currentCountryIso }} <span> <i
|
@click="openDrop('country')"
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 text-xl font-medium uppercase text-text-light dark:text-text-dark"
|
||||||
|
>
|
||||||
|
{{ $session.currentCountryIso }}
|
||||||
|
<span>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="dropCountry"
|
<div
|
||||||
class="bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer w-full focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]">
|
v-if="dropCountry"
|
||||||
|
class="bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer w-full focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]"
|
||||||
|
>
|
||||||
<div class="overflow-auto h-[200px] w-full">
|
<div class="overflow-auto h-[200px] w-full">
|
||||||
<p @click="() => { $session.setCountry(item.iso_code); $session.loadSession(); dropCountry = false }"
|
<p
|
||||||
|
v-for="item in menuStore.countries"
|
||||||
|
:key="item.iso_code"
|
||||||
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
||||||
v-for="item in menuStore.countries" :key="item.iso_code">
|
@click="
|
||||||
|
() => {
|
||||||
|
$session.setCountry(item.iso_code);
|
||||||
|
$session.loadSession();
|
||||||
|
dropCountry = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ item?.name }}
|
{{ item?.name }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -35,20 +68,39 @@
|
|||||||
<div class="flex flex-col items-start gap-[6px]">
|
<div class="flex flex-col items-start gap-[6px]">
|
||||||
<p>{{ $t("currency") }}</p>
|
<p>{{ $t("currency") }}</p>
|
||||||
<div
|
<div
|
||||||
class="w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 space-y-1">
|
class="w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 space-y-1"
|
||||||
<div class="p-0" @click="openDrop()">
|
>
|
||||||
<div class="flex items-center gap-2 text-xl font-medium uppercase text-text-light dark:text-text-dark">
|
<div class="p-0"
|
||||||
{{ $session.currentCurrencyIso }}<span> <i
|
@click="openDrop()"
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 text-xl font-medium uppercase text-text-light dark:text-text-dark"
|
||||||
|
>
|
||||||
|
{{ $session.currentCurrencyIso
|
||||||
|
}}<span>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="dropCurrency"
|
<div
|
||||||
class="bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer w-full focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]">
|
v-if="dropCurrency"
|
||||||
|
class="bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer w-full focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]"
|
||||||
|
>
|
||||||
<div class="overflow-auto w-full">
|
<div class="overflow-auto w-full">
|
||||||
<p @click="() => { $session.setCurrency(item.iso_code); $session.loadSession(); dropCurrency = false }"
|
<p
|
||||||
|
v-for="item in menuStore.currencies"
|
||||||
|
:key="item.iso_code"
|
||||||
class="w-full hover:bg-block dark:hover:bg-button pl-1 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
class="w-full hover:bg-block dark:hover:bg-button pl-1 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
||||||
v-for="item in menuStore.currencies" :key="item.iso_code">
|
@click="
|
||||||
|
() => {
|
||||||
|
$session.setCurrency(item.iso_code);
|
||||||
|
$session.loadSession();
|
||||||
|
dropCurrency = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ item?.name }}
|
{{ item?.name }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -62,13 +114,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import { onClickOutside } from '@vueuse/core'
|
||||||
const {$session} = useNuxtApp();
|
|
||||||
|
|
||||||
const isOpen = ref(false);
|
const { $session } = useNuxtApp()
|
||||||
const menuStore = useMenuStore();
|
|
||||||
|
|
||||||
const dropdownRef = ref(null);
|
const isOpen = ref(false)
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
|
||||||
|
const dropdownRef = ref(null)
|
||||||
|
|
||||||
const dropCountry = ref(false)
|
const dropCountry = ref(false)
|
||||||
const dropCurrency = ref(false)
|
const dropCurrency = ref(false)
|
||||||
@ -77,16 +130,16 @@ function openDrop(type?: string) {
|
|||||||
if (type === 'country') {
|
if (type === 'country') {
|
||||||
dropCurrency.value = false
|
dropCurrency.value = false
|
||||||
dropCountry.value = !dropCountry.value
|
dropCountry.value = !dropCountry.value
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
dropCountry.value = false
|
dropCountry.value = false
|
||||||
dropCurrency.value = !dropCurrency.value
|
dropCurrency.value = !dropCurrency.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onClickOutside(dropdownRef, () => {
|
onClickOutside(dropdownRef, () => {
|
||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
dropCurrency.value = false
|
dropCurrency.value = false
|
||||||
dropCountry.value = false
|
dropCountry.value = false
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -4,26 +4,58 @@
|
|||||||
<div class="w-full border-b border-border">
|
<div class="w-full border-b border-border">
|
||||||
<UiContainer class="relative">
|
<UiContainer class="relative">
|
||||||
<div class="hidden h-[120px] w-full items-center gap-[145px] xl:flex">
|
<div class="hidden h-[120px] w-full items-center gap-[145px] xl:flex">
|
||||||
<ul class="flex items-center justify-between gap-5 whitespace-nowrap w-full">
|
<ul
|
||||||
<li v-for="(item, index) in menuStore.menu" @click="menuStore.navigateToItem(item)" :key="item.id"
|
class="flex items-center justify-between gap-5 whitespace-nowrap w-full"
|
||||||
:class="['hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer text-lg transition-all text-inter',
|
>
|
||||||
route.params.id == item.id.toString() ? 'text-accent-green-light dark:text-accent-green-dark font-bold underline' : false]">
|
<li
|
||||||
0{{ index + 1 }} <br />
|
v-for="(item, index) in menuStore.menu"
|
||||||
|
:key="item.id"
|
||||||
|
:class="[
|
||||||
|
'hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer text-lg transition-all text-inter',
|
||||||
|
route.params.id == item.id.toString()
|
||||||
|
? 'text-accent-green-light dark:text-accent-green-dark font-bold underline'
|
||||||
|
: false,
|
||||||
|
]"
|
||||||
|
@click="menuStore.navigateToItem(item)"
|
||||||
|
>
|
||||||
|
0{{ index + 1 }} <br>
|
||||||
{{ item.front_menu_lang[0].name }}
|
{{ item.front_menu_lang[0].name }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<img class="cursor-pointer" :src="isDark ? '/logo-dark.svg' : '/logo.svg'" alt="logo"
|
<img
|
||||||
@click="menuStore.navigateToItem()" />
|
class="cursor-pointer"
|
||||||
|
:src="isDark ? '/logo-dark.svg' : '/logo.svg'"
|
||||||
|
alt="logo"
|
||||||
|
@click="menuStore.navigateToItem()"
|
||||||
|
>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
<div class="w-full flex items-center justify-between">
|
<div class="w-full flex items-center justify-between">
|
||||||
<div class="flex items-center gap-[30px]">
|
<div class="flex items-center gap-[30px]">
|
||||||
<p @click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 13))" class="cursor-pointer">button</p>
|
<p
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 13),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
button
|
||||||
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<i v-if="!userStore.isLogged"
|
<i
|
||||||
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
|
v-if="!userStore.isLogged"
|
||||||
class="uil uil-user text-[31px] cursor-pointer"></i>
|
class="uil uil-user text-[31px] cursor-pointer"
|
||||||
<div v-else class="py-[6px] px-3 border border-block rounded-sm">
|
@click="
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="py-[6px] px-3 border border-block rounded-sm"
|
||||||
|
>
|
||||||
{{ userStore.user }}
|
{{ userStore.user }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,13 +66,16 @@
|
|||||||
<CountryCurrencySelector />
|
<CountryCurrencySelector />
|
||||||
</div>
|
</div>
|
||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
<button @click="menuStore.navigateToShop" :class="[
|
<button
|
||||||
'cursor-pointer transition-all text-inter whitespace-nowrap',
|
:class="[
|
||||||
route.params.id == '5'
|
'cursor-pointer transition-all text-inter whitespace-nowrap',
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark font-bold pb-1 border-b-2'
|
route.params.id == '5'
|
||||||
: 'hover:bg-button-hover bg-button text-white font-medium rounded-xl px-6 py-3'
|
? 'text-accent-green-light dark:text-accent-green-dark font-bold pb-1 border-b-2'
|
||||||
]">
|
: 'hover:bg-button-hover bg-button text-white font-medium rounded-xl px-6 py-3',
|
||||||
{{ $t('eshop') }}
|
]"
|
||||||
|
@click="menuStore.navigateToShop"
|
||||||
|
>
|
||||||
|
{{ $t("eshop") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -48,20 +83,35 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- md -->
|
<!-- md -->
|
||||||
<div class="hidden w-full md:flex md:flex-col xl:hidden items-center justify-center">
|
<div
|
||||||
|
class="hidden w-full md:flex md:flex-col xl:hidden items-center justify-center"
|
||||||
|
>
|
||||||
<div class="w-full border-border border-b">
|
<div class="w-full border-border border-b">
|
||||||
<UiContainer class="h-[116px] flex items-center justify-between">
|
<UiContainer class="h-[116px] flex items-center justify-between">
|
||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<img class="cursor-pointer" :src="isDark ? '/logo-dark.svg' : '/logo.svg'" alt="logo"
|
<img
|
||||||
@click="menuStore.navigateToItem()" />
|
class="cursor-pointer"
|
||||||
|
:src="isDark ? '/logo-dark.svg' : '/logo.svg'"
|
||||||
|
alt="logo"
|
||||||
|
@click="menuStore.navigateToItem()"
|
||||||
|
>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
<div class="flex items-center gap-6">
|
<div class="flex items-center gap-6">
|
||||||
<div class="flex items-center gap-[30px]">
|
<div class="flex items-center gap-[30px]">
|
||||||
<div>
|
<div>
|
||||||
<i v-if="!userStore.isLogged"
|
<i
|
||||||
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
|
v-if="!userStore.isLogged"
|
||||||
class="uil uil-user text-[31px] cursor-pointer"></i>
|
class="uil uil-user text-[31px] cursor-pointer"
|
||||||
<div v-else class="py-[6px] px-3 border border-block rounded-sm">
|
@click="
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="py-[6px] px-3 border border-block rounded-sm"
|
||||||
|
>
|
||||||
{{ userStore.user }}
|
{{ userStore.user }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -72,26 +122,54 @@
|
|||||||
<CountryCurrencySelector />
|
<CountryCurrencySelector />
|
||||||
</div>
|
</div>
|
||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
<i variant="subtle" block class="uil uil-apps text-[33px] cursor-pointer" @click="open = !open"></i>
|
<i
|
||||||
|
variant="subtle"
|
||||||
|
block
|
||||||
|
class="uil uil-apps text-[33px] cursor-pointer"
|
||||||
|
@click="open = !open"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</div>
|
</div>
|
||||||
<UCollapsible :ui="{ content: 'w-full' }" v-model:open="open" class="w-full">
|
<UCollapsible
|
||||||
|
v-model:open="open"
|
||||||
|
:ui="{ content: 'w-full' }"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="w-full border-border border-b pt-6 pb-8">
|
<div class="w-full border-border border-b pt-6 pb-8">
|
||||||
<UiContainer class="flex flex-col gap-[30px]">
|
<UiContainer class="flex flex-col gap-[30px]">
|
||||||
<div v-for="(item, index) in menuStore.menu" :key="index"
|
<div
|
||||||
:class="['flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer', route.params.slug === item.front_menu_lang[0].link_rewrite && 'text-accent-green-light dark:text-accent-green-dark font-bold underline']"
|
v-for="(item, index) in menuStore.menu"
|
||||||
@click="() => { menuStore.navigateToItem(item); open = false; }">
|
:key="index"
|
||||||
|
:class="[
|
||||||
|
'flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer',
|
||||||
|
route.params.slug === item.front_menu_lang[0].link_rewrite
|
||||||
|
&& 'text-accent-green-light dark:text-accent-green-dark font-bold underline',
|
||||||
|
]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
menuStore.navigateToItem(item);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="leading-[70%] text-inter">
|
<div class="leading-[70%] text-inter">
|
||||||
<span class="mr-4">0{{ index + 1 }}</span>
|
<span class="mr-4">0{{ index + 1 }}</span>
|
||||||
{{ item.front_menu_lang[0].name }}
|
{{ item.front_menu_lang[0].name }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
||||||
<svg width="20" height="20" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 26 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
||||||
fill="currentColor" />
|
fill="currentColor"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
@ -101,49 +179,88 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- sm -->
|
<!-- sm -->
|
||||||
<div class="hidden w-full items-center justify-between sm:flex sm:flex-col md:hidden">
|
<div
|
||||||
|
class="hidden w-full items-center justify-between sm:flex sm:flex-col md:hidden"
|
||||||
|
>
|
||||||
<div class="w-full border-border border-b">
|
<div class="w-full border-border border-b">
|
||||||
<UiContainer class="h-[84px] flex items-center justify-between">
|
<UiContainer class="h-[84px] flex items-center justify-between">
|
||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<img class="cursor-pointer" :src="isDark ? '/logo-dark.svg' : '/logo.svg'" alt="logo"
|
<img
|
||||||
@click="menuStore.navigateToItem()" />
|
class="cursor-pointer"
|
||||||
|
:src="isDark ? '/logo-dark.svg' : '/logo.svg'"
|
||||||
|
alt="logo"
|
||||||
|
@click="menuStore.navigateToItem()"
|
||||||
|
>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
<div class="flex items-center gap-6">
|
<div class="flex items-center gap-6">
|
||||||
<div class="flex items-center gap-[30px]">
|
<div class="flex items-center gap-[30px]">
|
||||||
<div>
|
<div>
|
||||||
<i v-if="!userStore.isLogged"
|
<i
|
||||||
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
|
v-if="!userStore.isLogged"
|
||||||
class="uil uil-user text-[31px] cursor-pointer"></i>
|
class="uil uil-user text-[31px] cursor-pointer"
|
||||||
<div v-else class="py-[6px] px-3 border border-block rounded-sm">
|
@click="
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="py-[6px] px-3 border border-block rounded-sm"
|
||||||
|
>
|
||||||
{{ userStore.user }}
|
{{ userStore.user }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CartPopup />
|
<CartPopup />
|
||||||
</div>
|
</div>
|
||||||
<i variant="subtle" block class="uil uil-apps text-[30px] cursor-pointer" @click="open = !open"></i>
|
<i
|
||||||
|
variant="subtle"
|
||||||
|
block
|
||||||
|
class="uil uil-apps text-[30px] cursor-pointer"
|
||||||
|
@click="open = !open"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</div>
|
</div>
|
||||||
<UCollapsible :ui="{ content: 'w-full' }" v-model:open="open" class="w-full">
|
<UCollapsible
|
||||||
|
v-model:open="open"
|
||||||
|
:ui="{ content: 'w-full' }"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="w-full border-border border-b pt-6 pb-8">
|
<div class="w-full border-border border-b pt-6 pb-8">
|
||||||
<UiContainer class="flex flex-col gap-[30px]">
|
<UiContainer class="flex flex-col gap-[30px]">
|
||||||
<div v-for="(item, index) in menuStore.menu" @click="
|
<div
|
||||||
() => {
|
v-for="(item, index) in menuStore.menu"
|
||||||
menuStore.navigateToItem(item);
|
:key="index"
|
||||||
open = false;
|
:class="[
|
||||||
}
|
'flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer',
|
||||||
" :key="index"
|
route.params.slug === item.front_menu_lang[0].link_rewrite
|
||||||
:class="['flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer', route.params.slug === item.front_menu_lang[0].link_rewrite && 'text-accent-green-light dark:text-accent-green-dark font-bold underline']">
|
&& 'text-accent-green-light dark:text-accent-green-dark font-bold underline',
|
||||||
|
]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
menuStore.navigateToItem(item);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="leading-[70%] text-inter">
|
<div class="leading-[70%] text-inter">
|
||||||
<span class="mr-4">0{{ index + 1 }}</span>
|
<span class="mr-4">0{{ index + 1 }}</span>
|
||||||
{{ item.front_menu_lang[0].name }}
|
{{ item.front_menu_lang[0].name }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
||||||
<svg width="20" height="20" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 26 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
||||||
fill="currentColor" />
|
fill="currentColor"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
@ -175,39 +292,74 @@
|
|||||||
<div class="w-full border-border border-b">
|
<div class="w-full border-border border-b">
|
||||||
<UiContainer class="h-[84px] flex items-center justify-between">
|
<UiContainer class="h-[84px] flex items-center justify-between">
|
||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<img class="cursor-pointer" :src="isDark ? '/logo-dark.svg' : '/logo.svg'" alt="logo"
|
<img
|
||||||
@click="menuStore.navigateToItem()" />
|
class="cursor-pointer"
|
||||||
|
:src="isDark ? '/logo-dark.svg' : '/logo.svg'"
|
||||||
|
alt="logo"
|
||||||
|
@click="menuStore.navigateToItem()"
|
||||||
|
>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
<div class="flex items-center gap-6">
|
<div class="flex items-center gap-6">
|
||||||
<div>
|
<div>
|
||||||
<i @click="!userStore.isLogged && menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
|
<i
|
||||||
class="uil uil-user text-[30px] cursor-pointer"></i>
|
class="uil uil-user text-[30px] cursor-pointer"
|
||||||
|
@click="
|
||||||
|
!userStore.isLogged
|
||||||
|
&& menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CartPopup />
|
<CartPopup />
|
||||||
<i variant="subtle" block class="uil uil-apps text-[30px] cursor-pointer" @click="open = !open"></i>
|
<i
|
||||||
|
variant="subtle"
|
||||||
|
block
|
||||||
|
class="uil uil-apps text-[30px] cursor-pointer"
|
||||||
|
@click="open = !open"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</div>
|
</div>
|
||||||
<UCollapsible :ui="{ content: 'w-full' }" v-model:open="open" class="w-full">
|
<UCollapsible
|
||||||
|
v-model:open="open"
|
||||||
|
:ui="{ content: 'w-full' }"
|
||||||
|
class="w-full"
|
||||||
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="w-full border-border border-b pt-6 pb-8">
|
<div class="w-full border-border border-b pt-6 pb-8">
|
||||||
<UiContainer class="flex flex-col gap-[30px]">
|
<UiContainer class="flex flex-col gap-[30px]">
|
||||||
<div v-for="(item, index) in menuStore.menu" @click="
|
<div
|
||||||
() => {
|
v-for="(item, index) in menuStore.menu"
|
||||||
menuStore.navigateToItem(item);
|
:key="index"
|
||||||
open = false;
|
:class="[
|
||||||
}
|
'flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer',
|
||||||
" :key="index"
|
route.params.slug === item.front_menu_lang[0].link_rewrite
|
||||||
:class="['flex items-center justify-between transition-all hover:text-accent-green-light dark:hover:text-accent-green-dark cursor-pointer', route.params.slug === item.front_menu_lang[0].link_rewrite && 'text-accent-green-light dark:text-accent-green-dark font-bold underline']">
|
&& 'text-accent-green-light dark:text-accent-green-dark font-bold underline',
|
||||||
|
]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
menuStore.navigateToItem(item);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="leading-[70%] text-inter">
|
<div class="leading-[70%] text-inter">
|
||||||
<span class="mr-4">0{{ index + 1 }}</span>
|
<span class="mr-4">0{{ index + 1 }}</span>
|
||||||
{{ item.front_menu_lang[0].name }}
|
{{ item.front_menu_lang[0].name }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
<!-- <i class="uil uil-arrow-up-right text-[35px]"></i> -->
|
||||||
<svg width="20" height="20" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 26 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
||||||
fill="currentColor" />
|
fill="currentColor"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
@ -235,26 +387,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
|
||||||
import CartPopup from "./CartPopup.vue";
|
|
||||||
import CountryCurrencySelector from "./CountryCurrencySelector.vue";
|
|
||||||
import LangSwitcher from "./LangSwitcher.vue";
|
|
||||||
|
|
||||||
const menuStore = useMenuStore();
|
<script lang="ts" setup>
|
||||||
const userStore = useUserStore();
|
import CartPopup from './CartPopup.vue'
|
||||||
const productStore = useProductStore();
|
import CountryCurrencySelector from './CountryCurrencySelector.vue'
|
||||||
const open = ref(false);
|
import LangSwitcher from './LangSwitcher.vue'
|
||||||
const colorMode = useColorMode();
|
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const productStore = useProductStore()
|
||||||
|
const open = ref(false)
|
||||||
|
const colorMode = useColorMode()
|
||||||
|
|
||||||
productStore.getCart()
|
productStore.getCart()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const isDark = computed({
|
const isDark = computed({
|
||||||
get() {
|
get() {
|
||||||
return colorMode.value === "dark";
|
return colorMode.value === 'dark'
|
||||||
},
|
},
|
||||||
set(_isDark) {
|
set(_isDark) {
|
||||||
colorMode.preference = _isDark ? "dark" : "light";
|
colorMode.preference = _isDark ? 'dark' : 'light'
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -34,14 +34,20 @@
|
|||||||
/>
|
/>
|
||||||
</defs>
|
</defs>
|
||||||
</svg> -->
|
</svg> -->
|
||||||
<img class="image" src="/block.webp" alt="">
|
<img class="image"
|
||||||
|
src="/block.webp"
|
||||||
|
alt=""
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup></script>
|
<script lang="ts" setup></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.image {
|
.image {
|
||||||
clip-path: path("M0 20C0 8.9543 8.95431 0 20 0H847.666C858.641 0 867.565 8.84318 867.665 19.817L869.815 254.817C869.917 265.934 860.933 275 849.816 275H653C641.954 275 633 283.954 633 295V330C633 341.046 624.046 350 613 350H20C8.95431 350 0 341.046 0 330V20Z");
|
clip-path: path(
|
||||||
|
'M0 20C0 8.9543 8.95431 0 20 0H847.666C858.641 0 867.565 8.84318 867.665 19.817L869.815 254.817C869.917 265.934 860.933 275 849.816 275H653C641.954 275 633 283.954 633 295V330C633 341.046 624.046 350 613 350H20C8.95431 350 0 341.046 0 330V20Z'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
group: 'px-[5px] py-[10px]',
|
group: 'px-[5px] py-[10px]',
|
||||||
item: 'hover:bg-block dark:hover:bg-button rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50',
|
item: 'hover:bg-block dark:hover:bg-button rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50',
|
||||||
}"
|
}"
|
||||||
@update:model-value="setLocale($event); $session.setLanguage($event); $session.loadSession()"
|
@update:model-value="
|
||||||
|
setLocale($event);
|
||||||
|
$session.setLanguage($event);
|
||||||
|
$session.loadSession();
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<template #leading="{ modelValue }">
|
<template #leading="{ modelValue }">
|
||||||
<div class="flex items-center gap-2 text-xl font-medium uppercase">
|
<div class="flex items-center gap-2 text-xl font-medium uppercase">
|
||||||
@ -39,10 +43,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { locale, locales, setLocale } = useI18n();
|
const { locale, locales, setLocale } = useI18n()
|
||||||
const {$session} = useNuxtApp();
|
const { $session } = useNuxtApp()
|
||||||
|
|
||||||
|
|
||||||
const selectedLocaleCode = ref(locale.value);
|
|
||||||
|
|
||||||
|
const selectedLocaleCode = ref(locale.value)
|
||||||
</script>
|
</script>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -2,12 +2,12 @@
|
|||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<div class="flex h-8 w-8 cursor-pointer items-center justify-center">
|
<div class="flex h-8 w-8 cursor-pointer items-center justify-center">
|
||||||
<i
|
<i
|
||||||
@click="isDark = !isDark"
|
|
||||||
:class="[
|
:class="[
|
||||||
'uil text-[32px] cursor-pointer',
|
'uil text-[32px] cursor-pointer',
|
||||||
isDark ? 'uil-moon' : 'uil-sun',
|
isDark ? 'uil-moon' : 'uil-sun',
|
||||||
]"
|
]"
|
||||||
></i>
|
@click="isDark = !isDark"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<div class="size-20" />
|
<div class="size-20" />
|
||||||
@ -16,14 +16,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const colorMode = useColorMode();
|
const colorMode = useColorMode()
|
||||||
|
|
||||||
const isDark = computed({
|
const isDark = computed({
|
||||||
get() {
|
get() {
|
||||||
return colorMode.value === "dark";
|
return colorMode.value === 'dark'
|
||||||
},
|
},
|
||||||
set(_isDark) {
|
set(_isDark) {
|
||||||
colorMode.preference = _isDark ? "dark" : "light";
|
colorMode.preference = _isDark ? 'dark' : 'light'
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,128 +1,168 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-y-[55px] sm:space-y-[75px] md:space-y-[100px]">
|
<UiContainer class="space-y-[55px] sm:space-y-[75px] md:space-y-[100px]">
|
||||||
<div class="space-25-55-75">
|
<div class="space-25-55-75">
|
||||||
<div class="grid sm:grid-cols-7 md:grid-cols-4 xl:grid-cols-2">
|
<div class="grid sm:grid-cols-7 md:grid-cols-4 xl:grid-cols-2">
|
||||||
<h2 class="sm:col-start-2 sm:col-end-8 md:col-end-5 xl:col-start-2 h2-bold-bounded">
|
<h2
|
||||||
{{ component.front_section_lang[0].data.section_1.title }}
|
class="sm:col-start-2 sm:col-end-8 md:col-end-5 xl:col-start-2 h2-bold-bounded"
|
||||||
</h2>
|
>
|
||||||
</div>
|
{{ component.front_section_lang[0].data.section_1.title }}
|
||||||
<div class="space-y-[40px] sm:space-55-75">
|
</h2>
|
||||||
<div v-for="(item, index) in component.front_section_lang[0].data.section_1.text_blocks" :key="index"
|
</div>
|
||||||
class="grid grid-cols-7 md:grid-cols-4 xl:grid-cols-2">
|
<div class="space-y-[40px] sm:space-55-75">
|
||||||
<div class="flex gap-[200px]">
|
<div
|
||||||
<h4 class="h4-uppercase-bold-inter">0{{ index + 1 }}</h4>
|
v-for="(item, index) in component.front_section_lang[0].data.section_1
|
||||||
<h4 class="hidden xl:block h4-uppercase-bold-inter w-full whitespace-nowrap">
|
.text_blocks"
|
||||||
{{ item.block_title }}
|
:key="index"
|
||||||
</h4>
|
class="grid grid-cols-7 md:grid-cols-4 xl:grid-cols-2"
|
||||||
</div>
|
>
|
||||||
<div class="col-start-2 col-end-8 md:col-end-5 space-y-[25px] sm:space-y-[45px] md:space-y-[55px]">
|
<div class="flex gap-[200px]">
|
||||||
<h4 class="xl:hidden h4-uppercase-bold-inter w-full whitespace-nowrap">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ item.block_title }}
|
0{{ index + 1 }}
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ item.block_text }}</p>
|
<h4
|
||||||
</div>
|
class="hidden xl:block h4-uppercase-bold-inter w-full whitespace-nowrap"
|
||||||
</div>
|
>
|
||||||
</div>
|
{{ item.block_title }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="col-start-2 col-end-8 md:col-end-5 space-y-[25px] sm:space-y-[45px] md:space-y-[55px]"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="xl:hidden h4-uppercase-bold-inter w-full whitespace-nowrap"
|
||||||
|
>
|
||||||
|
{{ item.block_title }}
|
||||||
|
</h4>
|
||||||
|
<p>{{ item.block_text }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-25-55-75">
|
</div>
|
||||||
<h2 class="h2-bold-bounded">
|
</div>
|
||||||
{{ component.front_section_lang[0].data.section_2.title }}
|
<div class="space-25-55-75">
|
||||||
</h2>
|
<h2 class="h2-bold-bounded">
|
||||||
<div class="grid sm:grid-cols-2 xl:grid-cols-4 gap-[30px] auto-cols-fr auto-rows-fr">
|
{{ component.front_section_lang[0].data.section_2.title }}
|
||||||
<div class="border border-border rounded-2xl p-8 flex flex-col justify-between gap-[55px]"
|
</h2>
|
||||||
v-for="(item, index) in component.front_section_lang[0].data.section_2.text_blocks" :key="index">
|
<div
|
||||||
<div>
|
class="grid sm:grid-cols-2 xl:grid-cols-4 gap-[30px] auto-cols-fr auto-rows-fr"
|
||||||
<h4 class="h4-uppercase-bold-inter">0{{ index + 1 }}</h4>
|
>
|
||||||
<h4 class="h4-uppercase-bold-inter">{{ item.block_title }}</h4>
|
<div
|
||||||
</div>
|
v-for="(item, index) in component.front_section_lang[0].data.section_2
|
||||||
<p>{{ item.block_text }}</p>
|
.text_blocks"
|
||||||
</div>
|
:key="index"
|
||||||
<div
|
class="border border-border rounded-2xl p-8 flex flex-col justify-between gap-[55px]"
|
||||||
class="row-end-4 sm:row-end-3 col-start-1 col-end-2 xl:row-end-1 xl:col-start-3 xl:col-end-4 flex flex-col gap-[10px] md:gap-[30px]">
|
>
|
||||||
<div class="w-full h-full md:h-[211px] rounded-2xl" :style="{
|
<div>
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
backgroundSize: 'cover',
|
0{{ index + 1 }}
|
||||||
backgroundPosition: 'center',
|
</h4>
|
||||||
}" />
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<div class="w-full h-full md:h-[211px] rounded-2xl" :style="{
|
{{ item.block_title }}
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
</h4>
|
||||||
backgroundSize: 'cover',
|
</div>
|
||||||
backgroundPosition: 'center',
|
<p>{{ item.block_text }}</p>
|
||||||
}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid space-25-55 xl:grid-cols-2">
|
<div
|
||||||
<h2 class="h2-bold-bounded">
|
class="row-end-4 sm:row-end-3 col-start-1 col-end-2 xl:row-end-1 xl:col-start-3 xl:col-end-4 flex flex-col gap-[10px] md:gap-[30px]"
|
||||||
{{ component.front_section_lang[0].data.section_3.title }}
|
>
|
||||||
</h2>
|
<div
|
||||||
<div class="flex flex-col space-25-55">
|
class="w-full h-full md:h-[211px] rounded-2xl"
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data.section_3.text_blocks" :key="index">
|
:style="{
|
||||||
{{ item }}
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
</p>
|
backgroundSize: 'cover',
|
||||||
</div>
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="w-full h-full md:h-[211px] rounded-2xl"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid xl:space-25-55 grid-cols-1 xl:grid-cols-2 xl:gap-[30px]">
|
</div>
|
||||||
<div class="flex flex-col gap-[25px] sm:gap-[55px] md:gap-[75px] xl:justify-between">
|
</div>
|
||||||
<h2 class="h2-bold-bounded">
|
<div class="grid space-25-55 xl:grid-cols-2">
|
||||||
{{ component.front_section_lang[0].data.section_4.title }}
|
<h2 class="h2-bold-bounded">
|
||||||
</h2>
|
{{ component.front_section_lang[0].data.section_3.title }}
|
||||||
<p>{{ component.front_section_lang[0].data.section_4.description }}</p>
|
</h2>
|
||||||
</div>
|
<div class="flex flex-col space-25-55">
|
||||||
<div class="mb-[25px] mt-5 md:mb-[55px] xl:m-0 w-full h-[222px] sm:h-[371px] rounded-2xl" :style="{
|
<p
|
||||||
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
v-for="(item, index) in component.front_section_lang[0].data.section_3
|
||||||
backgroundSize: 'cover',
|
.text_blocks"
|
||||||
backgroundPosition: 'center',
|
:key="index"
|
||||||
}" />
|
>
|
||||||
<p class="xl:col-start-2 xl:col-end-3">{{ component.front_section_lang[0].data.section_4.description_second
|
{{ item }}
|
||||||
}}</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</div>
|
||||||
|
<div class="grid xl:space-25-55 grid-cols-1 xl:grid-cols-2 xl:gap-[30px]">
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-[25px] sm:gap-[55px] md:gap-[75px] xl:justify-between"
|
||||||
|
>
|
||||||
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ component.front_section_lang[0].data.section_4.title }}
|
||||||
|
</h2>
|
||||||
|
<p>{{ component.front_section_lang[0].data.section_4.description }}</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mb-[25px] mt-5 md:mb-[55px] xl:m-0 w-full h-[222px] sm:h-[371px] rounded-2xl"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<p class="xl:col-start-2 xl:col-end-3">
|
||||||
|
{{ component.front_section_lang[0].data.section_4.description_second }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
img: string[]
|
img: string[]
|
||||||
component_name: string
|
component_name: string
|
||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
section_1: {
|
section_1: {
|
||||||
title: string;
|
title: string
|
||||||
text_blocks: [
|
text_blocks: [
|
||||||
{
|
{
|
||||||
block_title: string;
|
block_title: string
|
||||||
block_text: string;
|
block_text: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
};
|
}
|
||||||
section_2: {
|
section_2: {
|
||||||
title: string;
|
title: string
|
||||||
text_blocks: [
|
text_blocks: [
|
||||||
{
|
{
|
||||||
block_title: string;
|
block_title: string
|
||||||
block_text: string;
|
block_text: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
};
|
}
|
||||||
section_3: {
|
section_3: {
|
||||||
title: string;
|
title: string
|
||||||
text_blocks: [];
|
text_blocks: []
|
||||||
};
|
}
|
||||||
section_4: {
|
section_4: {
|
||||||
title: string;
|
title: string
|
||||||
description: string;
|
description: string
|
||||||
description_second: string;
|
description_second: string
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
id_front_section: number
|
id_front_section: number
|
||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,109 +1,150 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-y-[55px] sm:space-y-[75px] md:space-y-[100px]">
|
<UiContainer class="space-y-[55px] sm:space-y-[75px] md:space-y-[100px]">
|
||||||
<div class="grid grid-cols-1 xl:grid-cols-2 gap-[10px] sm:gap-[30px]">
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-[10px] sm:gap-[30px]">
|
||||||
<div class="flex flex-col gap-[10px] sm:gap-[30px]">
|
<div class="flex flex-col gap-[10px] sm:gap-[30px]">
|
||||||
<div
|
|
||||||
class="h-[240px] sm:h-[400px] md:h-[490px] bg-block p-[25px] sm:p-[50px] rounded-2xl flex flex-col justify-between">
|
|
||||||
<div>
|
|
||||||
<h1 class="h1-big text-accent-green-light mb-6 md:mb-10">
|
|
||||||
{{ component.front_section_lang[0].data.title }}
|
|
||||||
</h1>
|
|
||||||
<p class="text-text-light sm:text-xl md:text-2xl font-medium">{{
|
|
||||||
component.front_section_lang[0].data.description }}</p>
|
|
||||||
</div>
|
|
||||||
<UiButtonArrow type="fill" :arrow="true">
|
|
||||||
{{ $t('buy_gold') }}
|
|
||||||
</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-[10px] sm:gap-[30px]">
|
|
||||||
<div class="rounded-2xl h-[155px] sm:h-[225px] md:h-[280px] w-full" :style="{
|
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: 'center',
|
|
||||||
}" />
|
|
||||||
<div class="rounded-2xl h-[155px] sm:h-[225px] md:h-[280px] w-full" :style="{
|
|
||||||
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: 'center',
|
|
||||||
}" />
|
|
||||||
<div class="hidden sm:block xl:hidden h-[225px] md:h-[280px] rounded-2xl w-full border border-block"
|
|
||||||
:style="{
|
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: 'center',
|
|
||||||
}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sm:hidden xl:block h-[326px] md:h-auto min-w-[40%] xl:min-w-[60%] rounded-2xl border border-block"
|
|
||||||
:style="{
|
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: 'center',
|
|
||||||
}" />
|
|
||||||
</div>
|
|
||||||
<div class="grid md:grid-cols-1 xl:grid-cols-2 gap-[20px] md:auto-rows-fr sm:gap-[30px]">
|
|
||||||
<div class="space-25-55-75">
|
|
||||||
<h2 class="h2-bold-bounded">{{ component.front_section_lang[0].data.section_2.title }}</h2>
|
|
||||||
<div class="space-y-[40px] sm:space-y-[50px]">
|
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data.section_2.text_blocks" :key="index">
|
|
||||||
{{ item }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="w-full md:h-full rounded-2xl h-[327px] sm:h-[550px]" :style="{
|
|
||||||
backgroundImage: `url('/api/public/file/${component.img[3]}_l.webp')`,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundPosition: 'center',
|
|
||||||
}" />
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-y-[25px] sm:gap-y-[55px] xl:gap-y-0 gap-x-[30px]">
|
class="h-[240px] sm:h-[400px] md:h-[490px] bg-block p-[25px] sm:p-[50px] rounded-2xl flex flex-col justify-between"
|
||||||
<h2 class="h2-bold-bounded sm:col-start-1 sm:col-end-3">{{
|
>
|
||||||
component.front_section_lang[0].data.section_3.title }}
|
<div>
|
||||||
</h2>
|
<h1 class="h1-big text-accent-green-light mb-6 md:mb-10">
|
||||||
<div v-for="(item, index) in component.front_section_lang[0].data.section_3.text_blocks" :key="index"
|
{{ component.front_section_lang[0].data.title }}
|
||||||
class="flex flex-col justify-between space-25-55">
|
</h1>
|
||||||
<p class="md:px-4 xl:p-0">{{ item }}</p>
|
<p class="text-text-light sm:text-xl md:text-2xl font-medium">
|
||||||
<div class=" rounded-2xl h-[227px] sm:h-[281px]" :style="{
|
{{ component.front_section_lang[0].data.description }}
|
||||||
backgroundImage: `url('/api/public/file/${component.img[index + 4]}_l.webp')`,
|
</p>
|
||||||
backgroundSize: 'cover',
|
</div>
|
||||||
backgroundPosition: 'center',
|
<UiButtonArrow type="fill"
|
||||||
}" />
|
:arrow="true"
|
||||||
</div>
|
>
|
||||||
<div
|
{{ $t("buy_gold") }}
|
||||||
class="sm:col-start-1 sm:col-end-3 xl:col-start-3 xl:col-end-5 flex justify-center xl:items-end xl:justify-end">
|
</UiButtonArrow>
|
||||||
<UiButtonArrow type="fill" :arrow="true">{{ $t('buy_gold') }}</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="flex gap-[10px] sm:gap-[30px]">
|
||||||
|
<div
|
||||||
|
class="rounded-2xl h-[155px] sm:h-[225px] md:h-[280px] w-full"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="rounded-2xl h-[155px] sm:h-[225px] md:h-[280px] w-full"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="hidden sm:block xl:hidden h-[225px] md:h-[280px] rounded-2xl w-full border border-block"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="sm:hidden xl:block h-[326px] md:h-auto min-w-[40%] xl:min-w-[60%] rounded-2xl border border-block"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="grid md:grid-cols-1 xl:grid-cols-2 gap-[20px] md:auto-rows-fr sm:gap-[30px]"
|
||||||
|
>
|
||||||
|
<div class="space-25-55-75">
|
||||||
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ component.front_section_lang[0].data.section_2.title }}
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-[40px] sm:space-y-[50px]">
|
||||||
|
<p
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.section_2.text_blocks"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-full md:h-full rounded-2xl h-[327px] sm:h-[550px]"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[3]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-y-[25px] sm:gap-y-[55px] xl:gap-y-0 gap-x-[30px]"
|
||||||
|
>
|
||||||
|
<h2 class="h2-bold-bounded sm:col-start-1 sm:col-end-3">
|
||||||
|
{{ component.front_section_lang[0].data.section_3.title }}
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data.section_3
|
||||||
|
.text_blocks"
|
||||||
|
:key="index"
|
||||||
|
class="flex flex-col justify-between space-25-55"
|
||||||
|
>
|
||||||
|
<p class="md:px-4 xl:p-0">
|
||||||
|
{{ item }}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="rounded-2xl h-[227px] sm:h-[281px]"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[index + 4]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="sm:col-start-1 sm:col-end-3 xl:col-start-3 xl:col-end-5 flex justify-center xl:items-end xl:justify-end"
|
||||||
|
>
|
||||||
|
<UiButtonArrow type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t("buy_gold")
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
img: string[]
|
img: string[]
|
||||||
component_name: string
|
component_name: string
|
||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
section_2: {
|
section_2: {
|
||||||
title: string
|
title: string
|
||||||
text_blocks: string[]
|
text_blocks: string[]
|
||||||
}
|
}
|
||||||
section_3: {
|
section_3: {
|
||||||
title: string
|
title: string
|
||||||
text_blocks: string[]
|
text_blocks: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id_front_section: number
|
id_front_section: number
|
||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,36 +8,50 @@
|
|||||||
<p>{{ component.front_section_lang[0].data.description }}</p>
|
<p>{{ component.front_section_lang[0].data.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 grid-rows-5 md:grid-rows-3 xl:grid-rows-2 gap-8">
|
<div
|
||||||
<div v-for="(item, index) in component.front_section_lang[0].data.feature_blocks" :key="index" :class="[
|
class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 grid-rows-5 md:grid-rows-3 xl:grid-rows-2 gap-8"
|
||||||
'p-8 rounded-2xl border border-block flex flex-col justify-between gap-4',
|
>
|
||||||
index === 0 && 'bg-block dark:text-bg-dark',
|
<div
|
||||||
index === 1 && 'xl:col-start-2 xl:col-end-3',
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
index === 2 && 'xl:col-start-4 xl:col-end-5',
|
.feature_blocks"
|
||||||
index === 3 &&
|
:key="index"
|
||||||
'md:col-start-1 md:col-end-3 xl:col-start-2 xl:col-end-4',
|
:class="[
|
||||||
]">
|
'p-8 rounded-2xl border border-block flex flex-col justify-between gap-4',
|
||||||
|
index === 0 && 'bg-block dark:text-bg-dark',
|
||||||
|
index === 1 && 'xl:col-start-2 xl:col-end-3',
|
||||||
|
index === 2 && 'xl:col-start-4 xl:col-end-5',
|
||||||
|
index === 3
|
||||||
|
&& 'md:col-start-1 md:col-end-3 xl:col-start-2 xl:col-end-4',
|
||||||
|
]"
|
||||||
|
>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<span>0{{ index + 1 }} <br /></span>{{ item.block_title }}
|
<span>0{{ index + 1 }} <br></span>{{ item.block_title }}
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ item.block_description }}</p>
|
<p>{{ item.block_description }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="sm:text-white xl:row-start-2 md:col-start-1 md:col-end-3 xl:col-end-2 w-full md:h-full flex justify-center xl:items-end">
|
class="sm:text-white xl:row-start-2 md:col-start-1 md:col-end-3 xl:col-end-2 w-full md:h-full flex justify-center xl:items-end"
|
||||||
<UiButtonArrow :arrow="true" type="fill">Zakoupit zlato</UiButtonArrow>
|
>
|
||||||
|
<UiButtonArrow :arrow="true"
|
||||||
|
type="fill"
|
||||||
|
>
|
||||||
|
Zakoupit zlato
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-2xl row-start-4 md:row-start-2 md:col-start-2 md:col-end-3 xl:col-start-4 xl:col-end-5"
|
<div
|
||||||
|
class="rounded-2xl row-start-4 md:row-start-2 md:col-start-2 md:col-end-3 xl:col-start-4 xl:col-end-5"
|
||||||
:style="{
|
:style="{
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundPosition: 'top',
|
backgroundPosition: 'top',
|
||||||
}" />
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { UiButtonArrow } from "#components";
|
import { UiButtonArrow } from '#components'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
@ -61,6 +75,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -5,24 +5,33 @@
|
|||||||
{{ component.front_section_lang[0].data.section_1.title }}
|
{{ component.front_section_lang[0].data.section_1.title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col xl:flex-row gap-12">
|
<div class="flex flex-col xl:flex-row gap-12">
|
||||||
<div class="rounded-2xl h-[255px] sm:h-[435px] md:h-[500px] w-full xl:min-w-[700px]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
class="rounded-2xl h-[255px] sm:h-[435px] md:h-[500px] w-full xl:min-w-[700px]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'bottom',
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'bottom',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
<div class="flex flex-col justify-between space-25-55">
|
<div class="flex flex-col justify-between space-25-55">
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.section_1.sub_title }}
|
{{ component.front_section_lang[0].data.section_1.sub_title }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data.section_1.sub_description" :key="index">
|
<p
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.section_1.sub_description"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.section_1.sub_title_second }}
|
{{
|
||||||
|
component.front_section_lang[0].data.section_1.sub_title_second
|
||||||
|
}}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -33,7 +42,11 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="space-25-55">
|
<div class="space-25-55">
|
||||||
<div class="flex flex-col w-full xl:w-[55%]">
|
<div class="flex flex-col w-full xl:w-[55%]">
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data.section_2.description" :key="index">
|
<p
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.section_2.description"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -45,33 +58,54 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col xl:flex-row gap-12">
|
<div class="flex flex-col xl:flex-row gap-12">
|
||||||
<div class="flex flex-col sm:flex-row gap-3 min-w-[60%]">
|
<div class="flex flex-col sm:flex-row gap-3 min-w-[60%]">
|
||||||
<div class="rounded-2xl h-[230px] sm:h-[300px] w-full xl:h-[770px]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="rounded-2xl h-[230px] sm:h-[300px] w-full xl:h-[770px]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
<div class="rounded-2xl xl:hidden w-full h-[230px] sm:h-[300px] xl:w-full xl:h-[328px]" :style="{
|
backgroundPosition: 'center',
|
||||||
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
}"
|
||||||
backgroundSize: 'cover',
|
/>
|
||||||
backgroundPosition: 'center',
|
<div
|
||||||
}" />
|
class="rounded-2xl xl:hidden w-full h-[230px] sm:h-[300px] xl:w-full xl:h-[328px]"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-between space-25-55 xl:w-[70%]">
|
<div class="flex flex-col justify-between space-25-55 xl:w-[70%]">
|
||||||
<div class="hidden xl:block rounded-2xl max-full min-h-[330px]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
class="hidden xl:block rounded-2xl max-full min-h-[330px]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[2]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
<div class="h-full flex flex-col gap-5 xl:gap-0 justify-between">
|
<div class="h-full flex flex-col gap-5 xl:gap-0 justify-between">
|
||||||
<h4 class="col-start-2 col-end-3 h4-uppercase-bold-inter">
|
<h4 class="col-start-2 col-end-3 h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.section_4.title }}
|
{{ component.front_section_lang[0].data.section_4.title }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p v-if="component.front_section_lang[0].data.section_4.description"
|
<p
|
||||||
v-html="component.front_section_lang[0].data.section_4.description[0]"></p>
|
v-if="
|
||||||
<br />
|
component.front_section_lang[0].data.section_4.description
|
||||||
<p v-if="component.front_section_lang[0].data.section_4.description"
|
"
|
||||||
v-html="component.front_section_lang[0].data.section_4.description[1]"></p>
|
v-html="
|
||||||
|
component.front_section_lang[0].data.section_4.description[0]
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<br>
|
||||||
|
<p
|
||||||
|
v-if="
|
||||||
|
component.front_section_lang[0].data.section_4.description
|
||||||
|
"
|
||||||
|
v-html="
|
||||||
|
component.front_section_lang[0].data.section_4.description[1]
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="col-start-2 col-end-3 h4-uppercase-bold-inter">
|
<h4 class="col-start-2 col-end-3 h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.section_5.title }}
|
{{ component.front_section_lang[0].data.section_5.title }}
|
||||||
@ -119,6 +153,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,27 +14,32 @@
|
|||||||
{{ component.front_section_lang[0].data.main_subtitle }}
|
{{ component.front_section_lang[0].data.main_subtitle }}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-2xl h-[340px] sm:h-[380px] md:min-w-[324px] xl:h-[800px] xl:min-w-[740px] m-0 sm:mx-10 md:m-0"
|
<div
|
||||||
|
class="rounded-2xl h-[340px] sm:h-[380px] md:min-w-[324px] xl:h-[800px] xl:min-w-[740px] m-0 sm:mx-10 md:m-0"
|
||||||
:style="{
|
:style="{
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center',
|
||||||
}"></div>
|
}"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-25-55-75">
|
<div class="space-25-55-75">
|
||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
{{ component.front_section_lang[0].data.story_title }}
|
{{ component.front_section_lang[0].data.story_title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex flex-col-reverse md:flex-row w-full gap-6">
|
<div class="flex flex-col-reverse md:flex-row w-full gap-6">
|
||||||
<div class="rounded-2xl h-[390px] md:h-auto min-w-[40%] xl:min-w-[60%]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="rounded-2xl h-[390px] md:h-auto min-w-[40%] xl:min-w-[60%]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data.story_description" :key="index">
|
<p v-for="(item, index) in component.front_section_lang[0].data.story_description" :key="index">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
<div v-if="index < component.front_section_lang[0].data.story_description.length - 1">
|
</p><div v-if="index < component.front_section_lang[0].data.story_description.length - 1">
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
@ -45,9 +50,11 @@
|
|||||||
{{ component.front_section_lang[0].data.story_subtitle }}
|
{{ component.front_section_lang[0].data.story_subtitle }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex flex-col justify-between xl:max-w-[70%]">
|
<div class="flex flex-col justify-between xl:max-w-[70%]">
|
||||||
<p v-for="(el, indexEl) in component.front_section_lang[0].data.story_sub_description" :key="indexEl">
|
<p v-for="(el, indexEl) in component.front_section_lang[0].data.story_sub_description"
|
||||||
|
:key="indexEl"
|
||||||
|
>
|
||||||
{{ el }}
|
{{ el }}
|
||||||
<div v-if="indexEl < component.front_section_lang[0].data.story_sub_description.length - 1">
|
</p><div v-if="indexEl < component.front_section_lang[0].data.story_sub_description.length - 1">
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
@ -58,7 +65,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
@ -81,6 +87,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,22 +2,32 @@
|
|||||||
<UiContainer class="space-y-[55px] md:space-y-[75px] xl:space-y-[100px]">
|
<UiContainer class="space-y-[55px] md:space-y-[75px] xl:space-y-[100px]">
|
||||||
<div class="space-y-10 sm:space-y-[55px] md:space-y-14">
|
<div class="space-y-10 sm:space-y-[55px] md:space-y-14">
|
||||||
<h1 class="h1 text-center">
|
<h1 class="h1 text-center">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data.title"
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
:key="index"
|
||||||
: '',
|
:class="[
|
||||||
'inline',
|
item.highlight
|
||||||
]">
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="index !== component.front_section_lang[0].data.title.length - 1">
|
<span
|
||||||
</span>
|
v-if="
|
||||||
|
index !== component.front_section_lang[0].data.title.length - 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="h-[180px] sm:h-[330px] md:h-[500px] rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
class="h-[180px] sm:h-[330px] md:h-[500px] rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
<div class="md:w-full xl:w-[70%] space-y-14">
|
<div class="md:w-full xl:w-[70%] space-y-14">
|
||||||
<p>{{ component.front_section_lang[0].data.main_description }}</p>
|
<p>{{ component.front_section_lang[0].data.main_description }}</p>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
@ -29,43 +39,61 @@
|
|||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
{{ component.front_section_lang[0].data.section_1_title }}
|
{{ component.front_section_lang[0].data.section_1_title }}
|
||||||
</h2>
|
</h2>
|
||||||
<p v-html="component.front_section_lang[0].data.section_1_description"></p>
|
<p v-html="component.front_section_lang[0].data.section_1_description" />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid space-25-75 xl:space-0 grid-cols-1 xl:grid-cols-2">
|
<div class="grid space-25-75 xl:space-0 grid-cols-1 xl:grid-cols-2">
|
||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.section_2_title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
.section_2_title"
|
||||||
: '',
|
:key="index"
|
||||||
'inline',
|
:class="[
|
||||||
]">
|
item.highlight
|
||||||
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="index !== component.front_section_lang[0].data.title.length - 1">
|
<span
|
||||||
</span>
|
v-if="
|
||||||
|
index !== component.front_section_lang[0].data.title.length - 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p v-html="component.front_section_lang[0].data.section_2_description"></p>
|
<p v-html="component.front_section_lang[0].data.section_2_description" />
|
||||||
</div>
|
</div>
|
||||||
<div class="space-25-75">
|
<div class="space-25-75">
|
||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
{{ component.front_section_lang[0].data.section_3_title }}
|
{{ component.front_section_lang[0].data.section_3_title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid grid-cols-1 space-25-55 md:space-0 xl:gap-2 md:grid-cols-2">
|
<div
|
||||||
|
class="grid grid-cols-1 space-25-55 md:space-0 xl:gap-2 md:grid-cols-2"
|
||||||
|
>
|
||||||
<div class="space-y-[25px] sm:space-y-[45px]">
|
<div class="space-y-[25px] sm:space-y-[45px]">
|
||||||
<p>{{ component.front_section_lang[0].data.section_3_description }}</p>
|
<p>
|
||||||
|
{{ component.front_section_lang[0].data.section_3_description }}
|
||||||
|
</p>
|
||||||
<div class="">
|
<div class="">
|
||||||
<p v-for="(item, index) in component.front_section_lang[0].data
|
<p
|
||||||
.section_3_items" :key="index">
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.section_3_items"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
{{ index + 1 }}.
|
{{ index + 1 }}.
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[315px] xl:h-full rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="h-[315px] xl:h-full rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 xl:grid-cols-2">
|
<div class="grid grid-cols-1 xl:grid-cols-2">
|
||||||
@ -73,7 +101,9 @@
|
|||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
{{ component.front_section_lang[0].data.section_4_title }}
|
{{ component.front_section_lang[0].data.section_4_title }}
|
||||||
</h2>
|
</h2>
|
||||||
<p v-html="component.front_section_lang[0].data.section_4_description"></p>
|
<p
|
||||||
|
v-html="component.front_section_lang[0].data.section_4_description"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
@ -113,6 +143,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,39 +2,59 @@
|
|||||||
<UiContainer class="space-55-75 xl:!space-y-[100px]">
|
<UiContainer class="space-55-75 xl:!space-y-[100px]">
|
||||||
<div class="space-25-75">
|
<div class="space-25-75">
|
||||||
<h2 class="h2-bold-bounded max-w-[95%]">
|
<h2 class="h2-bold-bounded max-w-[95%]">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.reasons_section_title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
.reasons_section_title"
|
||||||
: '',
|
:key="index"
|
||||||
'inline',
|
:class="[
|
||||||
]">
|
item.highlight
|
||||||
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="
|
<span
|
||||||
index !==
|
v-if="
|
||||||
component.front_section_lang[0].data.reasons_section_title.length - 1
|
index
|
||||||
">
|
!== component.front_section_lang[0].data.reasons_section_title
|
||||||
</span>
|
.length
|
||||||
|
- 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 md:px-10 xl:p-0 gap-8 auto-rows-fr">
|
<div
|
||||||
<div v-for="(item, index) in component.front_section_lang[0].data.reason_blocks" :key="index" :class="[
|
class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 md:px-10 xl:p-0 gap-8 auto-rows-fr"
|
||||||
'p-[25px] rounded-2xl border border-block flex flex-col justify-between gap-20',
|
>
|
||||||
index === 1 && 'xl:col-start-2 xl:col-end-3',
|
<div
|
||||||
index === 2 && 'xl:col-start-4 xl:col-end-5',
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
index === 3 && 'xl:col-start-2 xl:col-end-3',
|
.reason_blocks"
|
||||||
]">
|
:key="index"
|
||||||
|
:class="[
|
||||||
|
'p-[25px] rounded-2xl border border-block flex flex-col justify-between gap-20',
|
||||||
|
index === 1 && 'xl:col-start-2 xl:col-end-3',
|
||||||
|
index === 2 && 'xl:col-start-4 xl:col-end-5',
|
||||||
|
index === 3 && 'xl:col-start-2 xl:col-end-3',
|
||||||
|
]"
|
||||||
|
>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<span>0{{ index + 1 }} <br /></span>{{ item.title }}
|
<span>0{{ index + 1 }} <br></span>{{ item.title }}
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ item.description }}</p>
|
<p>{{ item.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row-end-7 sm:row-auto rounded-2xl flex items-center justify-center min-h-[200px]">
|
<div
|
||||||
<div class="w-full h-full rounded-2xl" :style="{
|
class="row-end-7 sm:row-auto rounded-2xl flex items-center justify-center min-h-[200px]"
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
>
|
||||||
backgroundSize: 'cover',
|
<div
|
||||||
backgroundPosition: 'top',
|
class="w-full h-full rounded-2xl"
|
||||||
}" />
|
:style="{
|
||||||
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'top',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -46,21 +66,39 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="hidden xl:grid grid-cols-2 gap-6">
|
<div class="hidden xl:grid grid-cols-2 gap-6">
|
||||||
<div class="flex flex-col gap-20">
|
<div class="flex flex-col gap-20">
|
||||||
<p>{{ component.front_section_lang[0].data.cta_description_intro }}</p>
|
<p>
|
||||||
<p>{{ component.front_section_lang[0].data.cta_description_details }}</p>
|
{{ component.front_section_lang[0].data.cta_description_intro }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{
|
||||||
|
component.front_section_lang[0].data.cta_description_details
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.main_call_to_action_statement }}
|
{{
|
||||||
|
component.front_section_lang[0].data
|
||||||
|
.main_call_to_action_statement
|
||||||
|
}}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="xl:hidden space-25-55">
|
<div class="xl:hidden space-25-55">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 md:gap-[55px] space-25-55">
|
<div
|
||||||
<p>{{ component.front_section_lang[0].data.cta_description_intro }}</p>
|
class="grid grid-cols-1 md:grid-cols-2 md:gap-[55px] space-25-55"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{{ component.front_section_lang[0].data.cta_description_intro }}
|
||||||
|
</p>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.main_call_to_action_statement }}
|
{{
|
||||||
|
component.front_section_lang[0].data
|
||||||
|
.main_call_to_action_statement
|
||||||
|
}}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ component.front_section_lang[0].data.cta_description_details }}</p>
|
<p>
|
||||||
|
{{ component.front_section_lang[0].data.cta_description_details }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -69,41 +107,61 @@
|
|||||||
{{ component.front_section_lang[0].data.form_section_title }}
|
{{ component.front_section_lang[0].data.form_section_title }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex flex-col md:flex-row gap-8 md:gap-[30px] xl:gap-0">
|
<div class="flex flex-col md:flex-row gap-8 md:gap-[30px] xl:gap-0">
|
||||||
<div class="p-[25px] md:p-[50px] bg-block rounded-2xl space-y-[30px] xl:ml-40 xl:w-[65%]">
|
<div
|
||||||
|
class="p-[25px] md:p-[50px] bg-block rounded-2xl space-y-[30px] xl:ml-40 xl:w-[65%]"
|
||||||
|
>
|
||||||
<div class="flex gap-[30px]">
|
<div class="flex gap-[30px]">
|
||||||
<input :placeholder="$t('first_name')" type="text"
|
<input
|
||||||
class="border border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
:placeholder="$t('first_name')"
|
||||||
<input :placeholder="$t('email')" type="text"
|
type="text"
|
||||||
class="border border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
class="border border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('email')"
|
||||||
|
type="text"
|
||||||
|
class="border border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<textarea :placeholder="$t('form_question')"
|
<textarea
|
||||||
class="border h-[145px] border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
:placeholder="$t('form_question')"
|
||||||
|
class="border h-[145px] border-text-dark placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="w-full flex justify-center sm:justify-start">
|
<div class="w-full flex justify-center sm:justify-start">
|
||||||
<UiButtonArrow type="border">{{
|
<UiButtonArrow type="border">
|
||||||
$t("submit_form")
|
{{
|
||||||
}}</UiButtonArrow>
|
$t("submit_form")
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-[30px] xl:px-[50px] sm:px-10">
|
<div class="space-y-[30px] xl:px-[50px] sm:px-10">
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ $t('contact_info') }}
|
{{ $t("contact_info") }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex flex-col sm:flex-row items-center sm:items-start md:flex-col justify-between gap-[30px]">
|
<div
|
||||||
|
class="flex flex-col sm:flex-row items-center sm:items-start md:flex-col justify-between gap-[30px]"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-gray">{{ $t("phone") }}</p>
|
<p class="text-gray">
|
||||||
|
{{ $t("phone") }}
|
||||||
|
</p>
|
||||||
<p>+420 608 428 782</p>
|
<p>+420 608 428 782</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-gray">{{ $t("email") }}</p>
|
<p class="text-gray">
|
||||||
|
{{ $t("email") }}
|
||||||
|
</p>
|
||||||
<p>web@yourgold.cz</p>
|
<p>web@yourgold.cz</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-gray">{{ $t("office_address") }}</p>
|
<p class="text-gray">
|
||||||
|
{{ $t("office_address") }}
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Floriána Nováka 3 <br />
|
Floriána Nováka 3 <br>
|
||||||
796 01 Prostějov <br />
|
796 01 Prostějov <br>
|
||||||
Czech Republic <br />
|
Czech Republic <br>
|
||||||
CZ 08435456
|
CZ 08435456
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -112,26 +170,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col xl:flex-row xl:h-[130px] gap-[45px]">
|
<div class="flex flex-col xl:flex-row xl:h-[130px] gap-[45px]">
|
||||||
<div class="w-full xl:w-[560px] h-[130px] xl:h-full rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="w-full xl:w-[560px] h-[130px] xl:h-full rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
<div class="flex flex-col h-full justify-between items-stretch space-y-[25px] sm:space-y-[55px] xl:space-y-0">
|
backgroundPosition: 'center',
|
||||||
<p>{{ component.front_section_lang[0].data.closing_inspirational_block }}</p>
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="flex flex-col h-full justify-between items-stretch space-y-[25px] sm:space-y-[55px] xl:space-y-0"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{{
|
||||||
|
component.front_section_lang[0].data.closing_inspirational_block
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
.title"
|
||||||
: '',
|
:key="index"
|
||||||
'inline',
|
:class="[
|
||||||
]">
|
item.highlight
|
||||||
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="
|
<span
|
||||||
index !==
|
v-if="
|
||||||
component.front_section_lang[0].data.reasons_section_title.length - 1
|
index
|
||||||
">
|
!== component.front_section_lang[0].data.reasons_section_title
|
||||||
</span>
|
.length
|
||||||
|
- 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ component.front_section_lang[0].data.final_tagline }}</p>
|
<p>{{ component.front_section_lang[0].data.final_tagline }}</p>
|
||||||
@ -177,6 +252,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,19 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="hasMainCategory" :class="['flex flex-col gap-[25px]', isOpen && 'border-b border-block pb-[10px]']">
|
<div
|
||||||
<div @click="toggle" class="flex items-center justify-between rounded-lg cursor-pointer">
|
v-if="hasMainCategory"
|
||||||
|
:class="[
|
||||||
|
'flex flex-col gap-[25px]',
|
||||||
|
isOpen && 'border-b border-block pb-[10px]',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between rounded-lg cursor-pointer"
|
||||||
|
@click="toggle"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between w-full">
|
<div class="flex items-center justify-between w-full">
|
||||||
<p class="text-lg xl:text-2xl font-extrabold text-black dark:text-white">
|
<p
|
||||||
|
class="text-lg xl:text-2xl font-extrabold text-black dark:text-white"
|
||||||
|
>
|
||||||
{{ mainCategoryName }}
|
{{ mainCategoryName }}
|
||||||
</p>
|
</p>
|
||||||
<span :class="['flex items-center justify-center', isOpen && 'rotate-180', 'transition-all']"><i
|
<span
|
||||||
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"></i></span>
|
:class="[
|
||||||
|
'flex items-center justify-center',
|
||||||
|
isOpen && 'rotate-180',
|
||||||
|
'transition-all',
|
||||||
|
]"
|
||||||
|
><i
|
||||||
|
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
|
||||||
|
/></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="flex flex-col gap-[25px]" v-show="isOpen">
|
<ul v-show="isOpen"
|
||||||
<li @click="$emit('change-category', child)" v-for="child in subcategories" :key="child.id"
|
class="flex flex-col gap-[25px]"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="child in subcategories"
|
||||||
|
:key="child.id"
|
||||||
class="text-base xl:text-lg cursor-pointer flex justify-between items-center"
|
class="text-base xl:text-lg cursor-pointer flex justify-between items-center"
|
||||||
:class="child.id === props.active ? 'text-yellow' : ''">
|
:class="child.id === props.active ? 'text-yellow' : ''"
|
||||||
|
@click="$emit('change-category', child)"
|
||||||
|
>
|
||||||
<span>{{ child.langs[0].Name }}</span>
|
<span>{{ child.langs[0].Name }}</span>
|
||||||
<span>12</span>
|
<span>12</span>
|
||||||
</li>
|
</li>
|
||||||
@ -25,22 +49,34 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
// Define the props
|
// Define the props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: Array,
|
data: Array,
|
||||||
active: Number
|
active: Number,
|
||||||
});
|
})
|
||||||
|
|
||||||
const isOpen = ref(false);
|
defineEmits(['change-category'])
|
||||||
|
|
||||||
|
const isOpen = ref(false)
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
isOpen.value = !isOpen.value;
|
isOpen.value = !isOpen.value
|
||||||
};
|
}
|
||||||
|
|
||||||
// Computed properties
|
// Computed properties
|
||||||
const hasMainCategory = computed(() => props.data && props.data.length > 0 && props.data[0].langs && props.data[0].langs.length > 0);
|
const hasMainCategory = computed(
|
||||||
const mainCategoryName = computed(() => hasMainCategory.value ? props.data[0].langs[0].Name : '');
|
() =>
|
||||||
const subcategories = computed(() => hasMainCategory.value && props.data[0].children ? props.data[0].children : []);
|
props.data
|
||||||
</script>
|
&& props.data.length > 0
|
||||||
|
&& props.data[0].langs
|
||||||
|
&& props.data[0].langs.length > 0,
|
||||||
|
)
|
||||||
|
const mainCategoryName = computed(() =>
|
||||||
|
hasMainCategory.value ? props.data[0].langs[0].Name : '',
|
||||||
|
)
|
||||||
|
const subcategories = computed(() =>
|
||||||
|
hasMainCategory.value && props.data[0].children ? props.data[0].children : [],
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
@ -1,255 +1,462 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer>
|
<UiContainer>
|
||||||
<div class="xl:w-[85%] mx-auto">
|
<div class="xl:w-[85%] mx-auto">
|
||||||
<div class="space-25-55">
|
<div class="space-25-55">
|
||||||
<div class="w-full flex items-center sm:justify-center">
|
<div class="w-full flex items-center sm:justify-center">
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto">
|
class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto"
|
||||||
<div class="sm:px-6 sm:py-3 mx-auto">
|
>
|
||||||
{{ $t("login") }}
|
<div class="sm:px-6 sm:py-3 mx-auto">
|
||||||
</div>
|
{{ $t("login") }}
|
||||||
<div
|
|
||||||
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3">
|
|
||||||
{{ $t("address") }}
|
|
||||||
</div>
|
|
||||||
<div class="sm:px-6 sm:py-3 mx-auto">
|
|
||||||
{{ $t("summary") }}
|
|
||||||
</div>
|
|
||||||
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
|
|
||||||
{{ $t("order_placed") }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[25px] sm:space-y-[30px]">
|
|
||||||
<h2 class="h2-bold-bounded">
|
|
||||||
{{ $t("Account address") }}
|
|
||||||
</h2>
|
|
||||||
<div class="flex flex-col gap-[30px] sm:flex-row">
|
|
||||||
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
|
||||||
<CheckoutInput v-model="checkoutStore.userName" :id="1" disabled>{{ $t("first_name")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.lastName" :id="2" disabled>{{ $t("surname")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.address" :id="3" disabled>{{ $t("address")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.postCode" :id="4" disabled>{{ $t("post_code")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col sm:w-1/2 gap-[30px]">
|
|
||||||
<CheckoutInput v-model="checkoutStore.city" :id="5" disabled>{{ $t("city")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.country" :id="6" disabled>{{ $t("country")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.accountPhoneNumber" :id="7" disabled>{{ $t("phone")
|
|
||||||
}} </CheckoutInput>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[30px]">
|
|
||||||
<h2 class="h2-bold-bounded">
|
|
||||||
{{ $t("Shipping details") }}
|
|
||||||
</h2>
|
|
||||||
<div class="flex flex-col gap-2">
|
|
||||||
<div
|
|
||||||
:class="['flex items-center gap-[10px] relative border border-block rounded-lg h-[50px] sm:h-[67px] w-full', checkoutStore.vUseAccountPhoneNumber && 'px-6']">
|
|
||||||
<div class="flex items-center gap-5 sm:gap-[25px]"
|
|
||||||
v-if="!checkoutStore.vUseAccountPhoneNumber">
|
|
||||||
<div class="flex flex-col items-start gap-[25px]">
|
|
||||||
<div ref="dropdownIsoRef"
|
|
||||||
class="pl-5 sm:pl-[25px] relative w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0">
|
|
||||||
<div class="p-0" @click="dropIso = !dropIso">
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-2 text-base sm:text-xl font-medium uppercase text-text-light dark:text-text-dark">
|
|
||||||
<p class="hidden sm:block">{{ checkoutStore.selectedIso.name }}</p>
|
|
||||||
<p class="sm:hidden">{{ checkoutStore.selectedIso.iso_code }}</p>
|
|
||||||
<span> <i
|
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="dropIso"
|
|
||||||
class="absolute w-[130px] sm:w-full mt-2 left-0 bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]">
|
|
||||||
<div class="overflow-auto h-[200px] w-full overflow-x-hidden">
|
|
||||||
<p @click="() => { checkoutStore.selectedIso = item; dropIso = false; checkoutStore.changePrefix(item.call_prefix as string) }"
|
|
||||||
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
|
||||||
v-for="item in menuStore.countries" :key="item.iso_code">
|
|
||||||
{{ item?.name }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="text-sm sm:text-xl border-r pr-[10px] border-block">{{
|
|
||||||
checkoutStore.currentPrefix }}</p>
|
|
||||||
</div>
|
|
||||||
<input id="phone"
|
|
||||||
:value="checkoutStore.vUseAccountPhoneNumber ? checkoutStore.accountPhoneNumber : checkoutStore.phoneNumber"
|
|
||||||
:disabled="checkoutStore.vUseAccountPhoneNumber" @input="(e) => {
|
|
||||||
if (!checkoutStore.vUseAccountPhoneNumber) {
|
|
||||||
checkoutStore.phoneNumber = (e.target as HTMLInputElement).value;
|
|
||||||
}
|
|
||||||
}" type="tel" placeholder="123 xxxx xxx"
|
|
||||||
class="placeholder:text-sm sm:placeholder:text-xl placeholder:text-gray placeholder:uppercase dark:placeholder:text-bg-light rounded-lg h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-0" />
|
|
||||||
</div>
|
|
||||||
<p v-if="checkoutStore.phoneValidation === false && !checkoutStore.vUseAccountPhoneNumber"
|
|
||||||
class="text-red-500">Invalid phone number</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<input id="checkbox" @change="(event: Event) => {
|
|
||||||
const target = event.target as HTMLInputElement
|
|
||||||
target.checked ? checkoutStore.vUseAccountPhoneNumber = true : checkoutStore.vUseAccountPhoneNumber = false
|
|
||||||
checkoutStore.phoneValidation = null
|
|
||||||
}" type="checkbox" class="border border-button !bg-inherit" />
|
|
||||||
<p>{{ $t('use_account_phone') }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[30px] h-full">
|
|
||||||
<h2 class="h2-bold-bounded">
|
|
||||||
{{ $t("Select delivery address") }}
|
|
||||||
</h2>
|
|
||||||
<div
|
|
||||||
class="flex flex-col md:flex-row items-center justify-center gap-[10px] sm:gap-[25px] md:h-[225px]">
|
|
||||||
<div class="w-full sm:w-[500px] flex flex-col gap-4 h-full">
|
|
||||||
<div v-for="(item, index) in checkoutStore.addressesList" :key="index"
|
|
||||||
:class="['flex min-h-[200px] md:h-full flex-col py-[15px] px-[25px] gap-[15px] rounded-lg border-2', checkoutStore.activeAddress === item ? 'border-button' : 'border-block']">
|
|
||||||
<div
|
|
||||||
:class="['flex flex-col justify-between gap-[10px] h-full', checkoutStore.activeAddress !== item && 'text-gray dark:text-button-disabled']">
|
|
||||||
<span>{{ item.address.name }} {{ item.address.surname }}</span>
|
|
||||||
<span>{{ item.address.street }}</span>
|
|
||||||
<span>{{ item.address.postcode }} {{ item.address.city }}</span>
|
|
||||||
<span>{{ item.address.country_iso }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2 border-t pt-[15px] border-block">
|
|
||||||
<input id="checkbox" :checked="checkoutStore.activeAddress ? true : false" @change="(event: Event) => {
|
|
||||||
const target = event.target as HTMLInputElement
|
|
||||||
target.checked ? checkoutStore.activeAddress = item : checkoutStore.activeAddress = null;
|
|
||||||
checkoutStore.isOpen = false;
|
|
||||||
}" type="checkbox" class="border border-button !bg-inherit" />
|
|
||||||
<p>{{ $t('choose_default_address') }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="uppercase">{{ $t("or") }}</p>
|
|
||||||
<div @click="() => {
|
|
||||||
checkoutStore.isOpen = !checkoutStore.isOpen
|
|
||||||
checkoutStore.activeAddress = null
|
|
||||||
}"
|
|
||||||
:class="['cursor-pointer w-full sm:w-[500px] py-[15px] px-[25px] rounded-lg border-2 flex flex-col items-center justify-center min-h-[200px] md:h-full', checkoutStore.isOpen ? 'border-button text-button' : 'text-gray border-block ']">
|
|
||||||
<h4
|
|
||||||
:class="['font-inter text-base leading-[150%] uppercase text-[16px] sm:text-[20px] border-b', checkoutStore.isOpen ? 'border-button' : 'border-gray']">
|
|
||||||
{{ $t("add_new_address") }}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="checkoutStore.isOpen"
|
|
||||||
class="flex flex-col items-center gap-[30px] justify-center w-full">
|
|
||||||
<div class="flex flex-col gap-[30px] xl:flex-row w-full">
|
|
||||||
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
|
||||||
<CheckoutInput v-model="checkoutStore.vNewAddressName" :placeholder="$t('first_name')"
|
|
||||||
:id="8">{{ $t("first_name") }}
|
|
||||||
</CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.vNewAddressAddress" :placeholder="$t('address')"
|
|
||||||
:id="9">{{ $t("address") }}
|
|
||||||
</CheckoutInput>
|
|
||||||
<CheckoutInput v-model="checkoutStore.vNewAddressCity" :placeholder="$t('city')"
|
|
||||||
:id="10">{{ $t("city") }}
|
|
||||||
</CheckoutInput>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
|
||||||
<CheckoutInput v-model="checkoutStore.vNewAddressSurname" :placeholder="$t('surname')"
|
|
||||||
:id="11">{{ $t("surname") }}
|
|
||||||
</CheckoutInput>
|
|
||||||
<div class="space-y-[15px]">
|
|
||||||
<p class="pl-6">
|
|
||||||
{{ $t("country") }}
|
|
||||||
</p>
|
|
||||||
<div ref="dropdownCountryRef"
|
|
||||||
class="relative w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0">
|
|
||||||
<div class="border border-block placeholder:text-gray dark:placeholder:text-button-disabled rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2 flex items-center justify-start"
|
|
||||||
@click="dropCountry = !dropCountry">
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-2 text-base sm:text-xl font-medium uppercase text-text-light dark:text-text-dark">
|
|
||||||
{{ checkoutStore.vNewAddressCountry ?
|
|
||||||
checkoutStore.vNewAddressCountry.name : '-' }} <span> <i
|
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="dropCountry"
|
|
||||||
class="absolute z-50 w-full mt-2 left-0 bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]">
|
|
||||||
<div class="overflow-auto h-[200px] w-full">
|
|
||||||
<p @click="() => { checkoutStore.vNewAddressCountry = item; dropCountry = false }"
|
|
||||||
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
|
||||||
v-for="item in menuStore.countries" :key="item.iso_code">
|
|
||||||
{{ item?.name }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<CheckoutInput v-model="checkoutStore.vNewAddressCode" :placeholder="$t('post_code')"
|
|
||||||
:id="13">{{ $t("post_code") }}
|
|
||||||
</CheckoutInput>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span v-if="addressValidation === false" class="text-red"> {{
|
|
||||||
$t("Remember to select a shipping address") }}</span>
|
|
||||||
<div class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap">
|
|
||||||
<button @click="checkoutStore.uploadAddress()"
|
|
||||||
:class="['h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px] bg-button text-text-dark group-hover:bg-button-hover']">
|
|
||||||
{{ $t("add_new_address") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<div class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap">
|
|
||||||
<button @click="checkoutStore.sendForm()" :disabled="!checkoutStore.activeAddress"
|
|
||||||
:class="['h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px]', checkoutStore.activeAddress ? 'bg-button text-text-dark group-hover:bg-button-hover' : ' bg-button-disabled text-gray']">
|
|
||||||
{{ $t("continue") }}
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
:class="['flex h-[40px] w-[40px] items-center justify-center rounded-[10px] p-2.5 transition-all sm:h-[50px] sm:w-[50px] md:h-[65px] md:w-[65px] md:rounded-[15px]', checkoutStore.activeAddress ? 'bg-button text-text-dark group-hover:bg-button-hover' : ' bg-button-disabled text-gray']">
|
|
||||||
<svg class="" width=" 26" height="26" viewBox="0 0 26 26" fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path
|
|
||||||
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
|
||||||
fill="currentColor" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3"
|
||||||
|
>
|
||||||
|
{{ $t("address") }}
|
||||||
|
</div>
|
||||||
|
<div class="sm:px-6 sm:py-3 mx-auto">
|
||||||
|
{{ $t("summary") }}
|
||||||
|
</div>
|
||||||
|
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
|
||||||
|
{{ $t("order_placed") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="space-y-[25px] sm:space-y-[30px]">
|
||||||
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ $t("Account address") }}
|
||||||
|
</h2>
|
||||||
|
<div class="flex flex-col gap-[30px] sm:flex-row">
|
||||||
|
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
||||||
|
<CheckoutInput :id="1"
|
||||||
|
v-model="checkoutStore.userName"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("first_name") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput :id="2"
|
||||||
|
v-model="checkoutStore.lastName"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("surname") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput :id="3"
|
||||||
|
v-model="checkoutStore.address"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("address") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput :id="4"
|
||||||
|
v-model="checkoutStore.postCode"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("post_code") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:w-1/2 gap-[30px]">
|
||||||
|
<CheckoutInput :id="5"
|
||||||
|
v-model="checkoutStore.city"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("city") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput :id="6"
|
||||||
|
v-model="checkoutStore.country"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("country") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput
|
||||||
|
:id="7"
|
||||||
|
v-model="checkoutStore.accountPhoneNumber"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ $t("phone") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[30px]">
|
||||||
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ $t("Shipping details") }}
|
||||||
|
</h2>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'flex items-center gap-[10px] relative border border-block rounded-lg h-[50px] sm:h-[67px] w-full',
|
||||||
|
checkoutStore.vUseAccountPhoneNumber && 'px-6',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="!checkoutStore.vUseAccountPhoneNumber"
|
||||||
|
class="flex items-center gap-5 sm:gap-[25px]"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col items-start gap-[25px]">
|
||||||
|
<div
|
||||||
|
ref="dropdownIsoRef"
|
||||||
|
class="pl-5 sm:pl-[25px] relative w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0"
|
||||||
|
>
|
||||||
|
<div class="p-0"
|
||||||
|
@click="dropIso = !dropIso"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 text-base sm:text-xl font-medium uppercase text-text-light dark:text-text-dark"
|
||||||
|
>
|
||||||
|
<p class="hidden sm:block">
|
||||||
|
{{ checkoutStore.selectedIso.name }}
|
||||||
|
</p>
|
||||||
|
<p class="sm:hidden">
|
||||||
|
{{ checkoutStore.selectedIso.iso_code }}
|
||||||
|
</p>
|
||||||
|
<span>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="dropIso"
|
||||||
|
class="absolute w-[130px] sm:w-full mt-2 left-0 bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="overflow-auto h-[200px] w-full overflow-x-hidden"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
v-for="item in menuStore.countries"
|
||||||
|
:key="item.iso_code"
|
||||||
|
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
checkoutStore.selectedIso = item;
|
||||||
|
dropIso = false;
|
||||||
|
checkoutStore.changePrefix(
|
||||||
|
item.call_prefix as string,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item?.name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm sm:text-xl border-r pr-[10px] border-block">
|
||||||
|
{{ checkoutStore.currentPrefix }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
id="phone"
|
||||||
|
:value="
|
||||||
|
checkoutStore.vUseAccountPhoneNumber
|
||||||
|
? checkoutStore.accountPhoneNumber
|
||||||
|
: checkoutStore.phoneNumber
|
||||||
|
"
|
||||||
|
:disabled="checkoutStore.vUseAccountPhoneNumber"
|
||||||
|
type="tel"
|
||||||
|
placeholder="123 xxxx xxx"
|
||||||
|
class="placeholder:text-sm sm:placeholder:text-xl placeholder:text-gray placeholder:uppercase dark:placeholder:text-bg-light rounded-lg h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-0"
|
||||||
|
@input="
|
||||||
|
(e) => {
|
||||||
|
if (!checkoutStore.vUseAccountPhoneNumber) {
|
||||||
|
checkoutStore.phoneNumber = (
|
||||||
|
e.target as HTMLInputElement
|
||||||
|
).value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
v-if="
|
||||||
|
checkoutStore.phoneValidation === false
|
||||||
|
&& !checkoutStore.vUseAccountPhoneNumber
|
||||||
|
"
|
||||||
|
class="text-red-500"
|
||||||
|
>
|
||||||
|
Invalid phone number
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
id="checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
class="border border-button !bg-inherit"
|
||||||
|
@change="
|
||||||
|
(event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
target.checked
|
||||||
|
? (checkoutStore.vUseAccountPhoneNumber = true)
|
||||||
|
: (checkoutStore.vUseAccountPhoneNumber = false);
|
||||||
|
checkoutStore.phoneValidation = null;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p>{{ $t("use_account_phone") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[30px] h-full">
|
||||||
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ $t("Select delivery address") }}
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
class="flex flex-col md:flex-row items-center justify-center gap-[10px] sm:gap-[25px] md:h-[225px]"
|
||||||
|
>
|
||||||
|
<div class="w-full sm:w-[500px] flex flex-col gap-4 h-full">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in checkoutStore.addressesList"
|
||||||
|
:key="index"
|
||||||
|
:class="[
|
||||||
|
'flex min-h-[200px] md:h-full flex-col py-[15px] px-[25px] gap-[15px] rounded-lg border-2',
|
||||||
|
checkoutStore.activeAddress === item
|
||||||
|
? 'border-button'
|
||||||
|
: 'border-block',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'flex flex-col justify-between gap-[10px] h-full',
|
||||||
|
checkoutStore.activeAddress !== item
|
||||||
|
&& 'text-gray dark:text-button-disabled',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<span>{{ item.address.name }} {{ item.address.surname }}</span>
|
||||||
|
<span>{{ item.address.street }}</span>
|
||||||
|
<span>{{ item.address.postcode }} {{ item.address.city }}</span>
|
||||||
|
<span>{{ item.address.country_iso }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 border-t pt-[15px] border-block"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="checkbox"
|
||||||
|
:checked="checkoutStore.activeAddress ? true : false"
|
||||||
|
type="checkbox"
|
||||||
|
class="border border-button !bg-inherit"
|
||||||
|
@change="
|
||||||
|
(event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
target.checked
|
||||||
|
? (checkoutStore.activeAddress = item)
|
||||||
|
: (checkoutStore.activeAddress = null);
|
||||||
|
checkoutStore.isOpen = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p>{{ $t("choose_default_address") }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="uppercase">
|
||||||
|
{{ $t("or") }}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'cursor-pointer w-full sm:w-[500px] py-[15px] px-[25px] rounded-lg border-2 flex flex-col items-center justify-center min-h-[200px] md:h-full',
|
||||||
|
checkoutStore.isOpen
|
||||||
|
? 'border-button text-button'
|
||||||
|
: 'text-gray border-block ',
|
||||||
|
]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
checkoutStore.isOpen = !checkoutStore.isOpen;
|
||||||
|
checkoutStore.activeAddress = null;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
:class="[
|
||||||
|
'font-inter text-base leading-[150%] uppercase text-[16px] sm:text-[20px] border-b',
|
||||||
|
checkoutStore.isOpen ? 'border-button' : 'border-gray',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ $t("add_new_address") }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="checkoutStore.isOpen"
|
||||||
|
class="flex flex-col items-center gap-[30px] justify-center w-full"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-[30px] xl:flex-row w-full">
|
||||||
|
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
||||||
|
<CheckoutInput
|
||||||
|
:id="8"
|
||||||
|
v-model="checkoutStore.vNewAddressName"
|
||||||
|
:placeholder="$t('first_name')"
|
||||||
|
>
|
||||||
|
{{ $t("first_name") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput
|
||||||
|
:id="9"
|
||||||
|
v-model="checkoutStore.vNewAddressAddress"
|
||||||
|
:placeholder="$t('address')"
|
||||||
|
>
|
||||||
|
{{ $t("address") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<CheckoutInput
|
||||||
|
:id="10"
|
||||||
|
v-model="checkoutStore.vNewAddressCity"
|
||||||
|
:placeholder="$t('city')"
|
||||||
|
>
|
||||||
|
{{ $t("city") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col sm:w-1/2 gap-[25px] sm:gap-[30px]">
|
||||||
|
<CheckoutInput
|
||||||
|
:id="11"
|
||||||
|
v-model="checkoutStore.vNewAddressSurname"
|
||||||
|
:placeholder="$t('surname')"
|
||||||
|
>
|
||||||
|
{{ $t("surname") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("country") }}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
ref="dropdownCountryRef"
|
||||||
|
class="relative w-full ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="border border-block placeholder:text-gray dark:placeholder:text-button-disabled rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2 flex items-center justify-start"
|
||||||
|
@click="dropCountry = !dropCountry"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 text-base sm:text-xl font-medium uppercase text-text-light dark:text-text-dark"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
checkoutStore.vNewAddressCountry
|
||||||
|
? checkoutStore.vNewAddressCountry.name
|
||||||
|
: "-"
|
||||||
|
}}
|
||||||
|
<span>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="dropCountry"
|
||||||
|
class="absolute z-50 w-full mt-2 left-0 bg-bg-light dark:bg-bg-dark rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0 border border-button py-[10px] px-[5px]"
|
||||||
|
>
|
||||||
|
<div class="overflow-auto h-[200px] w-full">
|
||||||
|
<p
|
||||||
|
v-for="item in menuStore.countries"
|
||||||
|
:key="item.iso_code"
|
||||||
|
class="w-full hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
checkoutStore.vNewAddressCountry = item;
|
||||||
|
dropCountry = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item?.name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CheckoutInput
|
||||||
|
:id="13"
|
||||||
|
v-model="checkoutStore.vNewAddressCode"
|
||||||
|
:placeholder="$t('post_code')"
|
||||||
|
>
|
||||||
|
{{ $t("post_code") }}
|
||||||
|
</CheckoutInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span v-if="addressValidation === false"
|
||||||
|
class="text-red"
|
||||||
|
>
|
||||||
|
{{ $t("Remember to select a shipping address") }}</span>
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
:class="[
|
||||||
|
'h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px] bg-button text-text-dark group-hover:bg-button-hover',
|
||||||
|
]"
|
||||||
|
@click="checkoutStore.uploadAddress()"
|
||||||
|
>
|
||||||
|
{{ $t("add_new_address") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div
|
||||||
|
class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
:disabled="!checkoutStore.activeAddress"
|
||||||
|
:class="[
|
||||||
|
'h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px]',
|
||||||
|
checkoutStore.activeAddress
|
||||||
|
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
||||||
|
: ' bg-button-disabled text-gray',
|
||||||
|
]"
|
||||||
|
@click="checkoutStore.sendForm()"
|
||||||
|
>
|
||||||
|
{{ $t("continue") }}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
:class="[
|
||||||
|
'flex h-[40px] w-[40px] items-center justify-center rounded-[10px] p-2.5 transition-all sm:h-[50px] sm:w-[50px] md:h-[65px] md:w-[65px] md:rounded-[15px]',
|
||||||
|
checkoutStore.activeAddress
|
||||||
|
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
||||||
|
: ' bg-button-disabled text-gray',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class=""
|
||||||
|
width=" 26"
|
||||||
|
height="26"
|
||||||
|
viewBox="0 0 26 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CheckoutInput from '../ui/CheckoutInput.vue';
|
import { onClickOutside } from '@vueuse/core'
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import CheckoutInput from '../ui/CheckoutInput.vue'
|
||||||
|
|
||||||
const checkoutStore = useCheckoutStore();
|
const checkoutStore = useCheckoutStore()
|
||||||
const userStore = useUserStore()
|
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
const dropIso = ref(false)
|
const dropIso = ref(false)
|
||||||
const dropCountry = ref(false)
|
const dropCountry = ref(false)
|
||||||
|
|
||||||
const addressValidation = ref<null | boolean>(null);
|
const addressValidation = ref<null | boolean>(null)
|
||||||
|
|
||||||
const dropdownIsoRef = ref(null);
|
const dropdownIsoRef = ref(null)
|
||||||
const dropdownCountryRef = ref(null);
|
const dropdownCountryRef = ref(null)
|
||||||
onClickOutside(dropdownIsoRef, () => {
|
onClickOutside(dropdownIsoRef, () => {
|
||||||
dropIso.value = false
|
dropIso.value = false
|
||||||
});
|
})
|
||||||
|
|
||||||
onClickOutside(dropdownCountryRef, () => {
|
onClickOutside(dropdownCountryRef, () => {
|
||||||
dropCountry.value = false
|
dropCountry.value = false
|
||||||
});
|
})
|
||||||
|
|
||||||
checkoutStore.getCheckout()
|
checkoutStore.getCheckout()
|
||||||
checkoutStore.getAddressList()
|
checkoutStore.getAddressList()
|
||||||
|
@ -1,75 +1,93 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer>
|
<UiContainer>
|
||||||
<div class="xl:w-[85%] mx-auto space-25-55">
|
<div class="xl:w-[85%] mx-auto space-25-55">
|
||||||
<div class="space-25-55">
|
<div class="space-25-55">
|
||||||
<div class="w-full flex items-center sm:justify-center">
|
<div class="w-full flex items-center sm:justify-center">
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto">
|
class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto"
|
||||||
<div class="sm:px-6 sm:py-3 mx-auto">
|
>
|
||||||
{{ $t("login") }}
|
<div class="sm:px-6 sm:py-3 mx-auto">
|
||||||
</div>
|
{{ $t("login") }}
|
||||||
<div class="sm:px-6 sm:py-3 mx-auto">
|
|
||||||
{{ $t("address") }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3">
|
|
||||||
{{ $t("summary") }}
|
|
||||||
</div>
|
|
||||||
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
|
|
||||||
{{ $t("order_placed") }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-3 gap-[30px]">
|
<div class="sm:px-6 sm:py-3 mx-auto">
|
||||||
<div class="col-start-1 col-end-3 space-y-5">
|
{{ $t("address") }}
|
||||||
<h4 class="h4-uppercase-bold-inter">Seznam produktů</h4>
|
|
||||||
<div class="border-2 border-block rounded-2xl p-[50px] space-25-55">
|
|
||||||
<div v-for="(item, index) in checkoutStore.products" :key="index">
|
|
||||||
<div class="flex items-center h-[150px]">
|
|
||||||
<div class="min-w-[150px] flex items-center justify-center h-[150px]">
|
|
||||||
<img :src="`/api/public/file/${item.picture_uuid}.webp`"
|
|
||||||
alt="" class="max-w-full max-h-full object-contain">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
|
|
||||||
<div class="w-full flex items-center justify-between">
|
|
||||||
<h3
|
|
||||||
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
|
|
||||||
{{ item.name }}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full justify-between gap-[10px]">
|
|
||||||
<p
|
|
||||||
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
|
|
||||||
{{ item.total_price }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="">
|
|
||||||
<div class="space-y-5">
|
|
||||||
<h4 class="h4-uppercase-bold-inter">Adresa účtu</h4>
|
|
||||||
<div class="border-2 border-block rounded-2xl px-2 py-3 flex flex-col gap-1">
|
|
||||||
<span>{{ checkoutStore.defaultAddress?.address.name }} {{
|
|
||||||
checkoutStore.defaultAddress?.address.surname }}</span>
|
|
||||||
<span>{{ checkoutStore.defaultAddress?.address.street }}</span>
|
|
||||||
<span>{{ checkoutStore.defaultAddress?.address.postcode }} {{
|
|
||||||
checkoutStore.defaultAddress?.address.city }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3"
|
||||||
|
>
|
||||||
|
{{ $t("summary") }}
|
||||||
|
</div>
|
||||||
|
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
|
||||||
|
{{ $t("order_placed") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</div>
|
||||||
|
<div class="grid grid-cols-3 gap-[30px]">
|
||||||
|
<div class="col-start-1 col-end-3 space-y-5">
|
||||||
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
|
Seznam produktů
|
||||||
|
</h4>
|
||||||
|
<div class="border-2 border-block rounded-2xl p-[50px] space-25-55">
|
||||||
|
<div v-for="(item, index) in checkoutStore.products"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<div class="flex items-center h-[150px]">
|
||||||
|
<div
|
||||||
|
class="min-w-[150px] flex items-center justify-center h-[150px]"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${item.picture_uuid}.webp`"
|
||||||
|
alt=""
|
||||||
|
class="max-w-full max-h-full object-contain"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]"
|
||||||
|
>
|
||||||
|
<div class="w-full flex items-center justify-between">
|
||||||
|
<h3
|
||||||
|
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full justify-between gap-[10px]">
|
||||||
|
<p
|
||||||
|
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold"
|
||||||
|
>
|
||||||
|
{{ item.total_price }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<div class="space-y-5">
|
||||||
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
|
Adresa účtu
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="border-2 border-block rounded-2xl px-2 py-3 flex flex-col gap-1"
|
||||||
|
>
|
||||||
|
<span>{{ checkoutStore.defaultAddress?.address.name }}
|
||||||
|
{{ checkoutStore.defaultAddress?.address.surname }}</span>
|
||||||
|
<span>{{ checkoutStore.defaultAddress?.address.street }}</span>
|
||||||
|
<span>{{ checkoutStore.defaultAddress?.address.postcode }}
|
||||||
|
{{ checkoutStore.defaultAddress?.address.city }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const checkoutStore = useCheckoutStore();
|
const checkoutStore = useCheckoutStore()
|
||||||
const productStore = useProductStore()
|
|
||||||
|
|
||||||
checkoutStore.getUserCart()
|
checkoutStore.getUserCart()
|
||||||
checkoutStore.getDeliveryOptions()
|
checkoutStore.getDeliveryOptions()
|
||||||
|
@ -1,72 +1,91 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-y-[45px]">
|
<UiContainer class="space-y-[45px]">
|
||||||
<div class="xl:w-[70%] space-y-[25px]">
|
<div class="xl:w-[70%] space-y-[25px]">
|
||||||
<h1 class="h1">{{ component.front_section_lang[0].data.title }}</h1>
|
<h1 class="h1">
|
||||||
<p v-html="component.front_section_lang[0].data.description"></p>
|
{{ component.front_section_lang[0].data.title }}
|
||||||
|
</h1>
|
||||||
|
<p v-html="component.front_section_lang[0].data.description" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col md:flex-row gap-8 md:gap-[30px] xl:gap-0">
|
||||||
|
<div
|
||||||
|
class="p-[25px] md:p-[50px] bg-block rounded-2xl space-y-[30px] xl:ml-40 xl:w-[65%]"
|
||||||
|
>
|
||||||
|
<div class="flex gap-[30px]">
|
||||||
|
<input
|
||||||
|
:placeholder="$t('first_name')"
|
||||||
|
type="text"
|
||||||
|
class="border border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('email')"
|
||||||
|
type="text"
|
||||||
|
class="border border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col md:flex-row gap-8 md:gap-[30px] xl:gap-0">
|
<textarea
|
||||||
<div class="p-[25px] md:p-[50px] bg-block rounded-2xl space-y-[30px] xl:ml-40 xl:w-[65%]">
|
:placeholder="$t('form_question')"
|
||||||
<div class="flex gap-[30px]">
|
class="border h-[276px] border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button"
|
||||||
<input :placeholder="$t('first_name')" type="text"
|
/>
|
||||||
class="border border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
|
||||||
<input :placeholder="$t('email')" type="text"
|
|
||||||
class="border border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
|
||||||
</div>
|
|
||||||
<textarea :placeholder="$t('form_question')"
|
|
||||||
class="border h-[276px] border-button placeholder:text-button rounded-lg px-3 py-1.5 w-full focus:outline-none focus:ring-0 focus:border-2 text-button" />
|
|
||||||
|
|
||||||
<div class="w-full flex justify-center sm:justify-start">
|
<div class="w-full flex justify-center sm:justify-start">
|
||||||
<UiButtonArrow type="border">{{
|
<UiButtonArrow type="border">
|
||||||
$t("submit_form")
|
{{ $t("submit_form") }}
|
||||||
}}</UiButtonArrow>
|
</UiButtonArrow>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[30px] xl:px-[50px] sm:px-10">
|
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
|
||||||
{{ $t('contact_info') }}
|
|
||||||
</h4>
|
|
||||||
<div
|
|
||||||
class="flex flex-col sm:flex-row items-center sm:items-start md:flex-col justify-between gap-[15px] sm:gap-[30px]">
|
|
||||||
<div>
|
|
||||||
<p class="text-gray">{{ $t("phone") }}</p>
|
|
||||||
<p>+420 608 428 782</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="text-gray">{{ $t("email") }}</p>
|
|
||||||
<p>web@yourgold.cz</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="text-gray">{{ $t("office_address") }}</p>
|
|
||||||
<p>
|
|
||||||
Floriána Nováka 3 <br />
|
|
||||||
796 01 Prostějov <br />
|
|
||||||
Czech Republic <br />
|
|
||||||
CZ 08435456
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</div>
|
||||||
|
<div class="space-y-[30px] xl:px-[50px] sm:px-10">
|
||||||
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
|
{{ $t("contact_info") }}
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="flex flex-col sm:flex-row items-center sm:items-start md:flex-col justify-between gap-[15px] sm:gap-[30px]"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p class="text-gray">
|
||||||
|
{{ $t("phone") }}
|
||||||
|
</p>
|
||||||
|
<p>+420 608 428 782</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-gray">
|
||||||
|
{{ $t("email") }}
|
||||||
|
</p>
|
||||||
|
<p>web@yourgold.cz</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-gray">
|
||||||
|
{{ $t("office_address") }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Floriána Nováka 3 <br>
|
||||||
|
796 01 Prostějov <br>
|
||||||
|
Czech Republic <br>
|
||||||
|
CZ 08435456
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
img: string[]
|
img: string[]
|
||||||
component_name: string
|
component_name: string
|
||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
title: string;
|
title: string
|
||||||
description: string;
|
description: string
|
||||||
}
|
}
|
||||||
id_front_section: number
|
id_front_section: number
|
||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
</script>
|
||||||
</script>
|
|
||||||
|
@ -1,32 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex gap-24">
|
<div class="flex gap-24">
|
||||||
<div class="price-container">
|
<div class="price-container">
|
||||||
<div class="slider" v-html="duplicatedContent">
|
<div class="slider"
|
||||||
|
v-html="duplicatedContent"
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
let res = "<span class=\"text-base sm:text-lg font-bold\">CZK price (to EUR). Kč 25,1720<span class=\"text-accent-green-light dark:text-accent-green-dark\"> Kč 0,0180 (0.07%) </span></span><span class=\"text-base sm:text-lg font-bold\">Gold price on market. 2 929,7250 €<span class=\"text-[#B72D2D]\"> -6,9560 € (-0.24%) </span></span><span class=\"text-base sm:text-lg font-bold\">Silver price on market. 31,5280 €<span class=\"text-accent-green-light dark:text-accent-green-dark\"> 0,1690 € (0.54%) </span></span><span class=\"text-base sm:text-lg font-bold\">PLN price (to EUR). zł 4,2660<span class=\"text-[#B72D2D]\"> zł -0,0050 (-0.12%) </span></span>"
|
const res
|
||||||
|
= '<span class="text-base sm:text-lg font-bold">CZK price (to EUR). Kč 25,1720<span class="text-accent-green-light dark:text-accent-green-dark"> Kč 0,0180 (0.07%) </span></span><span class="text-base sm:text-lg font-bold">Gold price on market. 2 929,7250 €<span class="text-[#B72D2D]"> -6,9560 € (-0.24%) </span></span><span class="text-base sm:text-lg font-bold">Silver price on market. 31,5280 €<span class="text-accent-green-light dark:text-accent-green-dark"> 0,1690 € (0.54%) </span></span><span class="text-base sm:text-lg font-bold">PLN price (to EUR). zł 4,2660<span class="text-[#B72D2D]"> zł -0,0050 (-0.12%) </span></span>'
|
||||||
const productStore = useProductStore()
|
const productStore = useProductStore()
|
||||||
const activeElement = ref(1);
|
|
||||||
productStore.getModules()
|
productStore.getModules()
|
||||||
|
|
||||||
// Computed property to duplicate the content
|
// Computed property to duplicate the content
|
||||||
const duplicatedContent = computed(() => {
|
const duplicatedContent = computed(() => {
|
||||||
const originalContent = res || '';
|
const originalContent = res || ''
|
||||||
return originalContent + originalContent + originalContent + originalContent;
|
return originalContent + originalContent + originalContent + originalContent
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
const changeActive = (item: number) => {
|
|
||||||
activeElement.value = item;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.price-container {
|
.price-container {
|
||||||
/* display: flex; */
|
/* display: flex; */
|
||||||
|
@ -2,44 +2,84 @@
|
|||||||
<div class="border-t border-border pt-[75px]">
|
<div class="border-t border-border pt-[75px]">
|
||||||
<UiContainer class="flex flex-col gap-24">
|
<UiContainer class="flex flex-col gap-24">
|
||||||
<div
|
<div
|
||||||
class="grid grid-cols-1 md:grid-cols-2 gap-[75px] xl:gap-0 xl:grid-cols-none xl:grid-flow-col auto-cols-max justify-between">
|
class="grid grid-cols-1 md:grid-cols-2 gap-[75px] xl:gap-0 xl:grid-cols-none xl:grid-flow-col auto-cols-max justify-between"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(item, key) in contact" :key="key" class="flex flex-col gap-[25px] sm:gap-8 max-w-[280px]">
|
<div
|
||||||
<h3 v-if="key == 'header'" class="h4-uppercase-bold-inter">{{ item }}</h3>
|
v-for="(item, key) in contact"
|
||||||
<div v-else class="transition-all text-inter">{{ item }}</div>
|
:key="key"
|
||||||
|
class="flex flex-col gap-[25px] sm:gap-8 max-w-[280px]"
|
||||||
|
>
|
||||||
|
<h3 v-if="key == 'header'"
|
||||||
|
class="h4-uppercase-bold-inter"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</h3>
|
||||||
|
<div v-else
|
||||||
|
class="transition-all text-inter"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="text-red-500">
|
||||||
|
arina - doadj tu icone i style
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href="/lei_certificate_aurrie.pdf"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>{{ $t("Footer.Lei") }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="(section, index) in docs" :key="index" class="flex flex-col gap-[25px] sm:gap-8 max-w-[280px]">
|
<div
|
||||||
<h3 class="h4-uppercase-bold-inter">{{ section.translation }}</h3>
|
v-for="(section, index) in docs"
|
||||||
<div v-for="(item, key) in section.data" :key="key">
|
:key="index"
|
||||||
<div class="cursor-pointer hover:text-text-light/80 dark:hover:text-text-dark/70 transition-all text-inter">
|
class="flex flex-col gap-[25px] sm:gap-8 max-w-[280px]"
|
||||||
<a target="_blank" :href="`/api/public/document/${item.name}`">{{ item.translation }}</a>
|
>
|
||||||
|
<h3 class="h4-uppercase-bold-inter">
|
||||||
|
{{ section.translation }}
|
||||||
|
</h3>
|
||||||
|
<div v-for="(item, key) in section.data"
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="cursor-pointer hover:text-text-light/80 dark:hover:text-text-dark/70 transition-all text-inter"
|
||||||
|
>
|
||||||
|
<a target="_blank"
|
||||||
|
:href="`/api/public/document/${item.name}`"
|
||||||
|
>{{
|
||||||
|
item.translation
|
||||||
|
}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ClientOnly v-if="!colorMode?.forced">
|
<ClientOnly v-if="!colorMode?.forced">
|
||||||
<img class="cursor-pointer w-[70%] sm:w-[50%] xl:w-[30%]"
|
<img
|
||||||
:src="isDark ? '/logo-footer-dark.svg' : '/logo-footer.svg'" alt="logo" @click="menuStore.navigateToItem()" />
|
class="cursor-pointer w-[70%] sm:w-[50%] xl:w-[30%]"
|
||||||
|
:src="isDark ? '/logo-footer-dark.svg' : '/logo-footer.svg'"
|
||||||
|
alt="logo"
|
||||||
|
@click="menuStore.navigateToItem()"
|
||||||
|
>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { GenericResponse, Footer } from '~/types';
|
import type { GenericResponse, Footer } from '~/types'
|
||||||
|
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore()
|
||||||
const colorMode = useColorMode();
|
const colorMode = useColorMode()
|
||||||
|
|
||||||
const { data } = await useMyFetch<GenericResponse<Footer>>('/api/public/front/footer', {});
|
|
||||||
|
|
||||||
|
const { data } = await useMyFetch<GenericResponse<Footer>>(
|
||||||
|
'/api/public/front/footer',
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
|
||||||
const contact = ref(data.data.contact)
|
const contact = ref(data.data.contact)
|
||||||
const docs = ref(data.data.docs)
|
const docs = ref(data.data.docs)
|
||||||
|
|
||||||
|
const isDark = computed(() => colorMode.value === 'dark')
|
||||||
const isDark = computed(() => colorMode.value === "dark");
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,25 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer>
|
<UiContainer>
|
||||||
<div class="space-25-55">
|
<div class="space-25-55">
|
||||||
<h2 class="h2-bold-bounded">{{ component.front_section_lang[0].data.title }}</h2>
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ component.front_section_lang[0].data.title }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="flex flex-col gap-10">
|
<div class="flex flex-col gap-10">
|
||||||
<div v-for="(item, index) in component.front_section_lang[0].data.faq" :key="index"
|
<div
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data.faq"
|
||||||
|
:key="index"
|
||||||
|
class="flex gap-8 sm:gap-20 md:gap-40 xl:gap-60 cursor-pointer"
|
||||||
@click="active = active === index ? 0 : index"
|
@click="active = active === index ? 0 : index"
|
||||||
class="flex gap-8 sm:gap-20 md:gap-40 xl:gap-60 cursor-pointer">
|
>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<span v-if="index + 1 < 10">0</span>{{ index + 1 }}
|
<span v-if="index + 1 < 10">0</span>{{ index + 1 }}
|
||||||
</h4>
|
</h4>
|
||||||
<div :class="[
|
<div
|
||||||
'flex justify-between w-full transition-all duration-300 gap-2 sm:gap-10 md:gap-2',
|
:class="[
|
||||||
active === index && 'pb-10 border-b border-bg-dark dark:border-bg-light',
|
'flex justify-between w-full transition-all duration-300 gap-2 sm:gap-10 md:gap-2',
|
||||||
]">
|
active === index
|
||||||
|
&& 'pb-10 border-b border-bg-dark dark:border-bg-light',
|
||||||
|
]"
|
||||||
|
>
|
||||||
<div class="max-w-[1200px] flex flex-col gap-6">
|
<div class="max-w-[1200px] flex flex-col gap-6">
|
||||||
<h4 :class="[
|
<h4
|
||||||
'h4-uppercase-bold-inter transition-colors duration-300',
|
:class="[
|
||||||
active === index &&
|
'h4-uppercase-bold-inter transition-colors duration-300',
|
||||||
'text-accent-green-light dark:text-accent-green-dark',
|
active === index
|
||||||
]">
|
&& 'text-accent-green-light dark:text-accent-green-dark',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
@ -30,21 +40,36 @@
|
|||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<svg class="min-w-5 h-5 dark:text-bg-light" viewBox="0 0 20 21" fill="none"
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
class="min-w-5 h-5 dark:text-bg-light"
|
||||||
<path :d="active === index
|
viewBox="0 0 20 21"
|
||||||
? 'M1.29289 17.4628L0.585786 18.1699L2 19.5841L2.70711 18.877L1.29289 17.4628ZM19.9706 1.19936C19.9706 0.647074 19.5228 0.199359 18.9706 0.199359L9.97056 0.19936C9.41828 0.199359 8.97056 0.647075 8.97056 1.19936C8.97056 1.75164 9.41828 2.19936 9.97056 2.19936L17.9706 2.19936L17.9706 10.1994C17.9706 10.7516 18.4183 11.1994 18.9706 11.1994C19.5228 11.1994 19.9706 10.7516 19.9706 10.1994L19.9706 1.19936ZM2 18.1699L2.70711 18.877L19.6777 1.90647L18.9706 1.19936L18.2635 0.492253L1.29289 17.4628L2 18.1699Z'
|
fill="none"
|
||||||
: 'M2.7364 1.49211L2.0293 0.785005L0.615083 2.19922L1.32219 2.90633L2.7364 1.49211ZM18.9999 20.1698C19.5521 20.1698 19.9999 19.7221 19.9999 19.1698L19.9999 10.1698C19.9999 9.6175 19.5521 9.16978 18.9999 9.16978C18.4476 9.16978 17.9999 9.6175 17.9999 10.1698L17.9999 18.1698L9.99986 18.1698C9.44758 18.1698 8.99986 18.6175 8.99986 19.1698C8.99986 19.7221 9.44757 20.1698 9.99986 20.1698L18.9999 20.1698ZM2.0293 2.19922L1.32219 2.90633L18.2928 19.8769L18.9999 19.1698L19.707 18.4627L2.7364 1.49211L2.0293 2.19922Z'
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
" fill="currentColor" />
|
>
|
||||||
|
<path
|
||||||
|
:d="
|
||||||
|
active === index
|
||||||
|
? 'M1.29289 17.4628L0.585786 18.1699L2 19.5841L2.70711 18.877L1.29289 17.4628ZM19.9706 1.19936C19.9706 0.647074 19.5228 0.199359 18.9706 0.199359L9.97056 0.19936C9.41828 0.199359 8.97056 0.647075 8.97056 1.19936C8.97056 1.75164 9.41828 2.19936 9.97056 2.19936L17.9706 2.19936L17.9706 10.1994C17.9706 10.7516 18.4183 11.1994 18.9706 11.1994C19.5228 11.1994 19.9706 10.7516 19.9706 10.1994L19.9706 1.19936ZM2 18.1699L2.70711 18.877L19.6777 1.90647L18.9706 1.19936L18.2635 0.492253L1.29289 17.4628L2 18.1699Z'
|
||||||
|
: 'M2.7364 1.49211L2.0293 0.785005L0.615083 2.19922L1.32219 2.90633L2.7364 1.49211ZM18.9999 20.1698C19.5521 20.1698 19.9999 19.7221 19.9999 19.1698L19.9999 10.1698C19.9999 9.6175 19.5521 9.16978 18.9999 9.16978C18.4476 9.16978 17.9999 9.6175 17.9999 10.1698L17.9999 18.1698L9.99986 18.1698C9.44758 18.1698 8.99986 18.6175 8.99986 19.1698C8.99986 19.7221 9.44757 20.1698 9.99986 20.1698L18.9999 20.1698ZM2.0293 2.19922L1.32219 2.90633L18.2928 19.8769L18.9999 19.1698L19.707 18.4627L2.7364 1.49211L2.0293 2.19922Z'
|
||||||
|
"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="h4-uppercase-bold-inter sm:text-start md:text-center xl:text-start xl:ml-66">
|
<h4
|
||||||
<span v-for="(item, index) in component.front_section_lang [0].data.sub_title" :key="index" :class="{
|
class="h4-uppercase-bold-inter sm:text-start md:text-center xl:text-start xl:ml-66"
|
||||||
'text-accent-green-light dark:text-accent-green-dark':
|
>
|
||||||
item.highlight,
|
<span
|
||||||
}">
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.sub_title"
|
||||||
|
:key="index"
|
||||||
|
:class="{
|
||||||
|
'text-accent-green-light dark:text-accent-green-dark':
|
||||||
|
item.highlight,
|
||||||
|
}"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
@ -63,26 +88,25 @@ defineProps<{
|
|||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
title: string;
|
title: string
|
||||||
faq: [
|
faq: [
|
||||||
{
|
{
|
||||||
label: string;
|
label: string
|
||||||
content: string;
|
content: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
sub_title: [
|
sub_title: [
|
||||||
{
|
{
|
||||||
text: string;
|
text: string
|
||||||
highlight: boolean;
|
highlight: boolean
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
}
|
}
|
||||||
id_front_section: number
|
id_front_section: number
|
||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
|
const active = ref<number>(0)
|
||||||
const active = ref<number>(0);
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,42 +1,64 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-y-[30px] xl:space-y-[55px]">
|
<UiContainer class="space-y-[30px] xl:space-y-[55px]">
|
||||||
<div class="flex flex-col xl:flex-row items-stretch w-full h-full gap-5">
|
<div class="flex flex-col xl:flex-row items-stretch w-full h-full gap-5">
|
||||||
<div class="flex flex-col justify-between items-center space-25-55 xl:gap-4 w-auto h-auto">
|
<div
|
||||||
|
class="flex flex-col justify-between items-center space-25-55 xl:gap-4 w-auto h-auto"
|
||||||
|
>
|
||||||
<h1 class="h1">
|
<h1 class="h1">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data.title"
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
:key="index"
|
||||||
: '',
|
:class="[
|
||||||
'inline',
|
item.highlight
|
||||||
]">
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="index !== component.front_section_lang[0].data.title.length - 1">
|
<span
|
||||||
</span>
|
v-if="
|
||||||
|
index !== component.front_section_lang[0].data.title.length - 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.sub_title" :key="index" :class="{
|
<span
|
||||||
'text-accent-green-light dark:text-accent-green-dark':
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
item.highlight,
|
.sub_title"
|
||||||
}">
|
:key="index"
|
||||||
|
:class="{
|
||||||
|
'text-accent-green-light dark:text-accent-green-dark':
|
||||||
|
item.highlight,
|
||||||
|
}"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
<p>{{ component.front_section_lang[0].data.description }}</p>
|
<p>{{ component.front_section_lang[0].data.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full xl:max-w-[570px] h-[390px] sm:h-[506px] block rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
class="w-full xl:max-w-[570px] h-[390px] sm:h-[506px] block rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col xl:flex-row items-stretch w-full h-full gap-5">
|
<div class="flex flex-col xl:flex-row items-stretch w-full h-full gap-5">
|
||||||
<div class="w-full xl:max-w-[570px] h-[225px] block rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="w-full xl:max-w-[570px] h-[225px] block rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
<div class="flex flex-col justify-between items-center space-25-55 xl:gap-4 w-auto h-auto">
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="flex flex-col justify-between items-center space-25-55 xl:gap-4 w-auto h-auto"
|
||||||
|
>
|
||||||
<p>{{ component.front_section_lang[0].data.description_second }}</p>
|
<p>{{ component.front_section_lang[0].data.description_second }}</p>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.sub_title_second }}
|
{{ component.front_section_lang[0].data.sub_title_second }}
|
||||||
@ -73,5 +95,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
@ -5,35 +5,54 @@
|
|||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.main_title }}
|
{{ component.front_section_lang[0].data.main_title }}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="w-full h-full flex flex-col items-stretch gap-4 xl:flex-row space-25-55 xl:!space-y-0">
|
<div
|
||||||
<div class="flex flex-col space-y-[55px] xl:space-y-0 xl:justify-between">
|
class="w-full h-full flex flex-col items-stretch gap-4 xl:flex-row space-25-55 xl:!space-y-0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col space-y-[55px] xl:space-y-0 xl:justify-between"
|
||||||
|
>
|
||||||
<p>{{ component.front_section_lang[0].data.main_description }}</p>
|
<p>{{ component.front_section_lang[0].data.main_description }}</p>
|
||||||
<p>{{ component.front_section_lang[0].data.section_title }}</p>
|
<p>{{ component.front_section_lang[0].data.section_title }}</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="" v-for="(item, index) in component.front_section_lang[0].data
|
<li
|
||||||
.section_items" :key="index">
|
v-for="(item, index) in component.front_section_lang[0].data
|
||||||
|
.section_items"
|
||||||
|
:key="index"
|
||||||
|
class=""
|
||||||
|
>
|
||||||
<span>{{ index + 1 }}. </span>{{ item }}
|
<span>{{ index + 1 }}. </span>{{ item }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full xl:max-w-[690px] h-[200px] sm:h-[390px] block rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
class="w-full xl:max-w-[690px] h-[200px] sm:h-[390px] block rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-center w-[60%] mx-auto">
|
<div class="flex items-center justify-center w-[60%] mx-auto">
|
||||||
<div class="flex flex-col items-center p-3 sm:p-6 md:p-8 xl:p-11 border border-block rounded-2xl gap-5">
|
<div
|
||||||
<h4 class="h4-uppercase-bold-inter text-accent-green-light dark:text-accent-green-dark">
|
class="flex flex-col items-center p-3 sm:p-6 md:p-8 xl:p-11 border border-block rounded-2xl gap-5"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="h4-uppercase-bold-inter text-accent-green-light dark:text-accent-green-dark"
|
||||||
|
>
|
||||||
20 {{ $t("years") }}
|
20 {{ $t("years") }}
|
||||||
</h4>
|
</h4>
|
||||||
<img class="dark:hidden"
|
<img
|
||||||
|
class="dark:hidden"
|
||||||
:src="`/api/public/file/${component.img[2]}_l.webp`"
|
:src="`/api/public/file/${component.img[2]}_l.webp`"
|
||||||
alt="" />
|
alt=""
|
||||||
<img class="hidden dark:block"
|
>
|
||||||
|
<img
|
||||||
|
class="hidden dark:block"
|
||||||
:src="`/api/public/file/${component.img[3]}_l.webp`"
|
:src="`/api/public/file/${component.img[3]}_l.webp`"
|
||||||
alt="" />
|
alt=""
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,13 +62,19 @@
|
|||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
{{ component.front_section_lang[0].data.info_title }}
|
{{ component.front_section_lang[0].data.info_title }}
|
||||||
</h4>
|
</h4>
|
||||||
<div v-html="component.front_section_lang[0].data.info_description_second" class=""></div>
|
<div
|
||||||
|
class=""
|
||||||
|
v-html="component.front_section_lang[0].data.info_description_second"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full xl:max-w-[690px] h-[170px] sm:h-[360px] block rounded-2xl" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
class="w-full xl:max-w-[690px] h-[170px] sm:h-[360px] block rounded-2xl"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
@ -77,6 +102,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,15 +2,22 @@
|
|||||||
<UiContainer>
|
<UiContainer>
|
||||||
<div class="space-25-55-75 max-w-[1000px] mx-auto">
|
<div class="space-25-55-75 max-w-[1000px] mx-auto">
|
||||||
<h1 class="h2-bold-bounded">
|
<h1 class="h2-bold-bounded">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data.title"
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
:key="index"
|
||||||
: '',
|
:class="[
|
||||||
'inline',
|
item.highlight
|
||||||
]">
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="index !== component.front_section_lang[0].data.title.length - 1">
|
<span
|
||||||
</span>
|
v-if="
|
||||||
|
index !== component.front_section_lang[0].data.title.length - 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
<h4 class="h4-uppercase-bold-inter">
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
@ -21,7 +28,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
@ -41,6 +48,5 @@
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-25-75">
|
<UiContainer class="space-25-75">
|
||||||
<h2 class="h2-bold-bounded">
|
<h2 class="h2-bold-bounded">
|
||||||
<span v-for="(item, index) in component.front_section_lang[0].data.main_title" :key="index" :class="[
|
<span
|
||||||
item.highlight
|
v-for="(item, index) in component.front_section_lang[0].data.main_title"
|
||||||
? 'text-accent-green-light dark:text-accent-green-dark'
|
:key="index"
|
||||||
: '',
|
:class="[
|
||||||
'inline',
|
item.highlight
|
||||||
]">
|
? 'text-accent-green-light dark:text-accent-green-dark'
|
||||||
|
: '',
|
||||||
|
'inline',
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
<span v-if="index !== component.front_section_lang[0].data.main_title.length - 1">
|
<span
|
||||||
</span>
|
v-if="
|
||||||
|
index !== component.front_section_lang[0].data.main_title.length - 1
|
||||||
|
"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@ -22,17 +29,27 @@
|
|||||||
|
|
||||||
<!-- products -->
|
<!-- products -->
|
||||||
<div class="space-25-55-75 flex flex-col items-center">
|
<div class="space-25-55-75 flex flex-col items-center">
|
||||||
<div :class="[
|
<div
|
||||||
'sm:mx-[50px] md:mx-0 xl:mx-[92px] flex items-stretch',
|
:class="[
|
||||||
itemCount === 1 ? 'justify-center' : 'justify-between gap-2',
|
'sm:mx-[50px] md:mx-0 xl:mx-[92px] flex items-stretch',
|
||||||
]">
|
itemCount === 1 ? 'justify-center' : 'justify-between gap-2',
|
||||||
<div v-for="(item, index) in productStore.productList" :key="index"
|
]"
|
||||||
class="w-[200px] sm:w-[260px] md:w-[290px] sm:py-5 sm:px-[15px] py-[15px] px-[10px] bg-block rounded-2xl flex flex-col items-center gap-5 sm:gap-7">
|
>
|
||||||
<img :src="`/api/public/file/${item.cover_picture_uuid}.webp`" alt="pics"
|
<div
|
||||||
class="max-h-[150px] sm:max-h-[180px] md:max-h-[205px]" />
|
v-for="(item, index) in productStore.productList"
|
||||||
|
:key="index"
|
||||||
|
class="w-[200px] sm:w-[260px] md:w-[290px] sm:py-5 sm:px-[15px] py-[15px] px-[10px] bg-block rounded-2xl flex flex-col items-center gap-5 sm:gap-7"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${item.cover_picture_uuid}.webp`"
|
||||||
|
alt="pics"
|
||||||
|
class="max-h-[150px] sm:max-h-[180px] md:max-h-[205px]"
|
||||||
|
>
|
||||||
<div class="flex flex-col justify-between h-full">
|
<div class="flex flex-col justify-between h-full">
|
||||||
<div class="flex flex-col gap-[10px] sm:gap-[15px] w-full">
|
<div class="flex flex-col gap-[10px] sm:gap-[15px] w-full">
|
||||||
<h3 class="text-[13px] sm:text-base md:text-lg text-xl font-bold leading-[150%] text-bg-dark">
|
<h3
|
||||||
|
class="text-[13px] sm:text-base md:text-lg text-xl font-bold leading-[150%] text-bg-dark"
|
||||||
|
>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-[10px] sm:text-[12px] text-sm text-bg-dark">
|
<p class="text-[10px] sm:text-[12px] text-sm text-bg-dark">
|
||||||
@ -43,20 +60,33 @@
|
|||||||
<p class="text-accent-green-light text-bold-24">
|
<p class="text-accent-green-light text-bold-24">
|
||||||
{{ item.formatted_price }}
|
{{ item.formatted_price }}
|
||||||
</p>
|
</p>
|
||||||
<button @click="productStore.incrementCartItem(item.id)"
|
<button
|
||||||
class="w-9 h-9 md:w-12 md:h-12 rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center">
|
class="w-9 h-9 md:w-12 md:h-12 rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center"
|
||||||
<i class="uil uil-shopping-cart text-[25px] md:text-[24px] text-bg-light"></i>
|
@click="productStore.incrementCartItem(item.id)"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-shopping-cart text-[25px] md:text-[24px] text-bg-light"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UiButtonArrow @click="menuStore.navigateToShop" :arrow="true" class="mx-auto" type="fill">{{ $t('eshop') }}</UiButtonArrow>
|
<UiButtonArrow
|
||||||
|
:arrow="true"
|
||||||
|
class="mx-auto"
|
||||||
|
type="fill"
|
||||||
|
@click="menuStore.navigateToShop"
|
||||||
|
>
|
||||||
|
{{ $t("eshop") }}
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- calculator-block -->
|
<!-- calculator-block -->
|
||||||
<div class="flex flex-col xl:flex-row items-stretch gap-6 sm:gap-2 pt-5 sm:p-0 space-25-55">
|
<div
|
||||||
|
class="flex flex-col xl:flex-row items-stretch gap-6 sm:gap-2 pt-5 sm:p-0 space-25-55"
|
||||||
|
>
|
||||||
<div class="flex flex-col space-y-[55px] sm:justify-between">
|
<div class="flex flex-col space-y-[55px] sm:justify-between">
|
||||||
<div class="space-25-55">
|
<div class="space-25-55">
|
||||||
<p>{{ component.front_section_lang[0].data.section_description }}</p>
|
<p>{{ component.front_section_lang[0].data.section_description }}</p>
|
||||||
@ -71,7 +101,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- calculator -->
|
<!-- calculator -->
|
||||||
<div class="w-full md:min-w-[680px] p-[25px] md:p-[50px] border border-button rounded-2xl block">
|
<div
|
||||||
|
class="w-full md:min-w-[680px] p-[25px] md:p-[50px] border border-button rounded-2xl block"
|
||||||
|
>
|
||||||
<h2 class="h2-bold-bounded text-center mb-10 sm:mb-20">
|
<h2 class="h2-bold-bounded text-center mb-10 sm:mb-20">
|
||||||
{{ component.front_section_lang[0].data.calculator_title }}
|
{{ component.front_section_lang[0].data.calculator_title }}
|
||||||
</h2>
|
</h2>
|
||||||
@ -79,35 +111,61 @@
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<p>{{ $t("monthly_savings") }}</p>
|
<p>{{ $t("monthly_savings") }}</p>
|
||||||
<p class="text-accent-green-light dark:text-accent-green-dark font-bold">
|
<p
|
||||||
{{ store.monthlySavings }} {{ menuStore.selectedCurrency?.sign }}
|
class="text-accent-green-light dark:text-accent-green-dark font-bold"
|
||||||
|
>
|
||||||
|
{{ store.monthlySavings }}
|
||||||
|
{{ menuStore.selectedCurrency?.sign }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input v-model="store.monthlySavings" type="range" max="600" :min="store.minValue"
|
<input
|
||||||
class="w-full accent-button cursor-pointer" @mouseup="store.getCalculator()"
|
v-model="store.monthlySavings"
|
||||||
@touchend="store.getCalculator()" />
|
type="range"
|
||||||
|
max="600"
|
||||||
|
:min="store.minValue"
|
||||||
|
class="w-full accent-button cursor-pointer"
|
||||||
|
@mouseup="store.getCalculator()"
|
||||||
|
@touchend="store.getCalculator()"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<p>{{ $t("storage_period_years") }}</p>
|
<p>{{ $t("storage_period_years") }}</p>
|
||||||
<p class="text-accent-green-light dark:text-accent-green-dark font-bold">
|
<p
|
||||||
|
class="text-accent-green-light dark:text-accent-green-dark font-bold"
|
||||||
|
>
|
||||||
{{ store.storagePeriod }}
|
{{ store.storagePeriod }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input v-model="store.storagePeriod" type="range" max="20" class="w-full accent-button cursor-pointer"
|
<input
|
||||||
@mouseup="store.getCalculator()" @touchend="store.getCalculator()" />
|
v-model="store.storagePeriod"
|
||||||
|
type="range"
|
||||||
|
max="20"
|
||||||
|
class="w-full accent-button cursor-pointer"
|
||||||
|
@mouseup="store.getCalculator()"
|
||||||
|
@touchend="store.getCalculator()"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-start sm:flex-row gap-6 sm:gap-1 justify-between sm:items-center">
|
<div
|
||||||
|
class="flex flex-col items-start sm:flex-row gap-6 sm:gap-1 justify-between sm:items-center"
|
||||||
|
>
|
||||||
<div class="">
|
<div class="">
|
||||||
<p>{{ $t("expected_savings_value") }}</p>
|
<p>{{ $t("expected_savings_value") }}</p>
|
||||||
<h2 class="h2-bold-bounded text-accent-green-light dark:text-accent-green-dark">
|
<h2
|
||||||
|
class="h2-bold-bounded text-accent-green-light dark:text-accent-green-dark"
|
||||||
|
>
|
||||||
{{ menuStore.selectedCurrency?.sign }} {{ store.totalInvestment }}
|
{{ menuStore.selectedCurrency?.sign }} {{ store.totalInvestment }}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<UiButtonArrow :arrow="true" type="fill" class="mx-auto sm:m-0">{{
|
<UiButtonArrow :arrow="true"
|
||||||
component.front_section_lang[0].data.button
|
type="fill"
|
||||||
}}</UiButtonArrow>
|
class="mx-auto sm:m-0"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
component.front_section_lang[0].data.button
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -142,34 +200,33 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
|
||||||
const store = useStore();
|
const itemCount = ref(4)
|
||||||
const menuStore = useMenuStore();
|
const productStore = useProductStore()
|
||||||
|
|
||||||
const itemCount = ref(4);
|
|
||||||
const productStore = useProductStore();
|
|
||||||
|
|
||||||
async function updateItemCount() {
|
async function updateItemCount() {
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth
|
||||||
if (width >= 1800) itemCount.value = 5;
|
if (width >= 1800) itemCount.value = 5
|
||||||
else if (width >= 1200) itemCount.value = 4;
|
else if (width >= 1200) itemCount.value = 4
|
||||||
else if (width >= 768) itemCount.value = 3;
|
else if (width >= 768) itemCount.value = 3
|
||||||
else if (width >= 640) itemCount.value = 2;
|
else if (width >= 640) itemCount.value = 2
|
||||||
else itemCount.value = 1;
|
else itemCount.value = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(itemCount, async () => {
|
watch(itemCount, async () => {
|
||||||
await productStore.getList(itemCount.value);
|
await productStore.getList(itemCount.value)
|
||||||
});
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await updateItemCount();
|
await updateItemCount()
|
||||||
window.addEventListener("resize", updateItemCount);
|
window.addEventListener('resize', updateItemCount)
|
||||||
});
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("resize", updateItemCount);
|
window.removeEventListener('resize', updateItemCount)
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,96 +1,151 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer v-if="!userStore.vCodeVerify" class="flex py-20 sm:py-14">
|
<UiContainer v-if="!userStore.vCodeVerify"
|
||||||
<div class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" :style="{
|
class="flex py-20 sm:py-14"
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
>
|
||||||
backgroundSize: 'cover',
|
<div
|
||||||
backgroundPosition: 'center',
|
class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]"
|
||||||
}" />
|
:style="{
|
||||||
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12 ">
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
<div class="space-25-55">
|
backgroundSize: 'cover',
|
||||||
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
backgroundPosition: 'center',
|
||||||
<h2 class="h2-bold-bounded">{{ $t('login') }}</h2>
|
}"
|
||||||
<button @click="menuStore.navigateToItem()"
|
/>
|
||||||
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer">{{
|
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
|
||||||
$t('back_to_home') }}</button>
|
<div class="space-25-55">
|
||||||
</div>
|
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
||||||
<div class="space-y-[15px]">
|
<h2 class="h2-bold-bounded">
|
||||||
<p class="pl-6">{{ $t('email') }}</p>
|
{{ $t("login") }}
|
||||||
<input v-model="userStore.email" :placeholder="$t('email')" type="text"
|
</h2>
|
||||||
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
<button
|
||||||
</div>
|
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
|
||||||
<div class="space-y-[15px]">
|
@click="menuStore.navigateToItem()"
|
||||||
<p class="pl-6">{{ $t('password') }}</p>
|
>
|
||||||
<input v-model="userStore.password" :placeholder="$t('placeholder_password')" type="text"
|
{{ $t("back_to_home") }}
|
||||||
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="text-button hover:text-button-hover transition-all font-medium mt-[30px] cursor-pointer">{{
|
|
||||||
$t('forgot_password_question')
|
|
||||||
}}</p>
|
|
||||||
<div class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full">
|
|
||||||
<UiButtonArrow @click="userStore.logIn()" type="fill" :arrow="true">{{ $t('login') }}</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[25px] sm:mt-[30px] w-full flex justify-center gap-3">
|
|
||||||
<p class="cursor-pointer hover:underline transition-all">{{
|
|
||||||
$t('no_account')
|
|
||||||
}}</p>
|
|
||||||
<p class="text-button cursor-pointer hover:text-button-hover">{{
|
|
||||||
$t('sign_up_now')
|
|
||||||
}}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("email") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
v-model="userStore.email"
|
||||||
|
:placeholder="$t('email')"
|
||||||
|
type="text"
|
||||||
|
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("password") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
v-model="userStore.password"
|
||||||
|
:placeholder="$t('placeholder_password')"
|
||||||
|
type="text"
|
||||||
|
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="text-button hover:text-button-hover transition-all font-medium mt-[30px] cursor-pointer"
|
||||||
|
>
|
||||||
|
{{ $t("forgot_password_question") }}
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full"
|
||||||
|
>
|
||||||
|
<UiButtonArrow type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
@click="userStore.logIn()"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t("login")
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
<div class="mt-[25px] sm:mt-[30px] w-full flex justify-center gap-3">
|
||||||
|
<p class="cursor-pointer hover:underline transition-all">
|
||||||
|
{{ $t("no_account") }}
|
||||||
|
</p>
|
||||||
|
<p class="text-button cursor-pointer hover:text-button-hover">
|
||||||
|
{{ $t("sign_up_now") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
|
|
||||||
<UiContainer v-if="userStore.vCodeVerify" class="flex py-20 sm:py-14">
|
<UiContainer v-if="userStore.vCodeVerify"
|
||||||
<div class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" :style="{
|
class="flex py-20 sm:py-14"
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
>
|
||||||
backgroundSize: 'cover',
|
<div
|
||||||
backgroundPosition: 'center',
|
class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]"
|
||||||
}" />
|
:style="{
|
||||||
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12 ">
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
<div class="space-25-55">
|
backgroundSize: 'cover',
|
||||||
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
backgroundPosition: 'center',
|
||||||
<h2 class="h2-bold-bounded">{{ $t('verify_login') }}</h2>
|
}"
|
||||||
<button @click="menuStore.navigateToItem()"
|
/>
|
||||||
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer">{{
|
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
|
||||||
$t('back_to_home') }}</button>
|
<div class="space-25-55">
|
||||||
</div>
|
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
||||||
<div class="space-y-[30px]">
|
<h2 class="h2-bold-bounded">
|
||||||
<p>{{ $t('send_code') }} <span class="text-button font-semibold">{{ userStore.email }}</span> {{
|
{{ $t("verify_login") }}
|
||||||
$t('by_email') }}
|
</h2>
|
||||||
</p>
|
<button
|
||||||
<div class="space-y-[15px]">
|
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
|
||||||
<p class="pl-6">{{ $t('code') }}</p>
|
@click="menuStore.navigateToItem()"
|
||||||
<input v-model="userStore.vCode" :placeholder="$t('code')" type="text"
|
>
|
||||||
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
{{ $t("back_to_home") }}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="py-[25px] sm:py-12 flex justify-center w-full">
|
|
||||||
<UiButtonArrow @click="userStore.sendFormCode(true)" type="fill" :arrow="true">{{ $t('confirm') }}
|
|
||||||
</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="space-y-[30px]">
|
||||||
|
<p>
|
||||||
|
{{ $t("send_code") }}
|
||||||
|
<span class="text-button font-semibold">{{ userStore.email }}</span>
|
||||||
|
{{ $t("by_email") }}
|
||||||
|
</p>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("code") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
v-model="userStore.vCode"
|
||||||
|
:placeholder="$t('code')"
|
||||||
|
type="text"
|
||||||
|
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-[25px] sm:py-12 flex justify-center w-full">
|
||||||
|
<UiButtonArrow
|
||||||
|
type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
@click="userStore.sendFormCode(true)"
|
||||||
|
>
|
||||||
|
{{ $t("confirm") }}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
img: string[]
|
img: string[]
|
||||||
component_name: string
|
component_name: string
|
||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {}
|
||||||
}
|
id_front_section: number
|
||||||
id_front_section: number
|
id_lang: number
|
||||||
id_lang: number
|
}[]
|
||||||
}[]
|
}
|
||||||
}
|
}>()
|
||||||
}>();
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,43 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="flex flex-wrap items-center justify-between gap-[30px] sm:gap-y-[55px] xl:gap-y-[100px]">
|
<UiContainer
|
||||||
<div class="w-full flex flex-col gap-[25px] xl:max-w-[48%] md:mx-10 xl:m-0"
|
class="flex flex-wrap items-center justify-between gap-[30px] sm:gap-y-[55px] xl:gap-y-[100px]"
|
||||||
v-for="(item, index) in component.front_section_lang[0].data" :key="index">
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in component.front_section_lang[0].data"
|
||||||
|
:key="index"
|
||||||
|
class="w-full flex flex-col gap-[25px] xl:max-w-[48%] md:mx-10 xl:m-0"
|
||||||
|
>
|
||||||
<!-- xl -->
|
<!-- xl -->
|
||||||
<div class="hidden xl:flex xl:h-[330px] flex-col justify-between">
|
<div class="hidden xl:flex xl:h-[330px] flex-col justify-between">
|
||||||
<div class="space-y-[55px]">
|
<div class="space-y-[55px]">
|
||||||
<h2 class="h2-bold-bounded">{{ item.title }}</h2>
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ item.title }}
|
||||||
|
</h2>
|
||||||
<p>{{ item.description }}</p>
|
<p>{{ item.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="h4-uppercase-bold-inter">{{ item.sub_title }}</h4>
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
|
{{ item.sub_title }}
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- sm/md -->
|
<!-- sm/md -->
|
||||||
<div class="xl:hidden flex flex-col gap-y-[25px] sm:gap-y-[55px]">
|
<div class="xl:hidden flex flex-col gap-y-[25px] sm:gap-y-[55px]">
|
||||||
<h2 class="h2-bold-bounded">{{ item.title }}</h2>
|
<h2 class="h2-bold-bounded">
|
||||||
|
{{ item.title }}
|
||||||
|
</h2>
|
||||||
<p>{{ item.description }}</p>
|
<p>{{ item.description }}</p>
|
||||||
<h4 class="h4-uppercase-bold-inter">{{ item.sub_title }}</h4>
|
<h4 class="h4-uppercase-bold-inter">
|
||||||
|
{{ item.sub_title }}
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<UiImgWrapper :src="`/api/public/file/${component.img[index]}_l.webp`">
|
<UiImgWrapper :src="`/api/public/file/${component.img[index]}_l.webp`">
|
||||||
<template #button>
|
<template #button>
|
||||||
<UiButtonArrow :arrow="true">{{ item.title }}</UiButtonArrow>
|
<UiButtonArrow :arrow="true">
|
||||||
|
{{ item.title }}
|
||||||
|
</UiButtonArrow>
|
||||||
</template>
|
</template>
|
||||||
</UiImgWrapper>
|
</UiImgWrapper>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Map block with same layout rules -->
|
<!-- Map block with same layout rules -->
|
||||||
<div class="w-full xl:max-w-[48%] md:mx-10 xl:m-0 flex flex-col gap-4 items-center">
|
<div
|
||||||
|
class="w-full xl:max-w-[48%] md:mx-10 xl:m-0 flex flex-col gap-4 items-center"
|
||||||
|
>
|
||||||
<h1 class="text-sm sm:text-xl uppercase">
|
<h1 class="text-sm sm:text-xl uppercase">
|
||||||
Jsme tu pro vás napříč Evropou
|
Jsme tu pro vás napříč Evropou
|
||||||
</h1>
|
</h1>
|
||||||
<MapBlock />
|
<MapBlock />
|
||||||
<div class="flex items-center gap-4 w-full justify-end">
|
<div class="flex items-center gap-4 w-full justify-end">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="w-3 h-3 rounded-[2.8px] bg-button"></div>
|
<div class="w-3 h-3 rounded-[2.8px] bg-button" />
|
||||||
<p>Partners</p>
|
<p>Partners</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="w-3 h-3 rounded-[2.8px] bg-block"></div>
|
<div class="w-3 h-3 rounded-[2.8px] bg-block" />
|
||||||
<p>Customers</p>
|
<p>Customers</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,6 +81,6 @@ type Component = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: Component;
|
component: Component
|
||||||
}>();
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,15 +10,22 @@
|
|||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center',
|
||||||
}" />
|
}"
|
||||||
<div class="flex flex-col items-center space-y-[30px] sm:flex-row sm:items-start md:space-y-0 xl:items-center">
|
/>
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center space-y-[30px] sm:flex-row sm:items-start md:space-y-0 xl:items-center"
|
||||||
|
>
|
||||||
<h3 class="h4-uppercase-bold-inter sm:min-w-[45%]">
|
<h3 class="h4-uppercase-bold-inter sm:min-w-[45%]">
|
||||||
{{ component.front_section_lang[0].data.title_second }}
|
{{ component.front_section_lang[0].data.title_second }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex w-full items-start justify-center sm:justify-end">
|
<div class="flex w-full items-start justify-center sm:justify-end">
|
||||||
<UiButtonArrow :arrow="true" type="fill">{{
|
<UiButtonArrow :arrow="true"
|
||||||
component.front_section_lang[0].data.button
|
type="fill"
|
||||||
}}</UiButtonArrow>
|
>
|
||||||
|
{{
|
||||||
|
component.front_section_lang[0].data.button
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -44,7 +51,5 @@ defineProps<{
|
|||||||
id_lang: number
|
id_lang: number
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="space-y-[40px] sm:space-y-[55px] md:space-y-[75px]">
|
<UiContainer class="space-y-[40px] sm:space-y-[55px] md:space-y-[75px]">
|
||||||
<div :class="[
|
<div
|
||||||
'sm:mx-[50px] md:mx-0 xl:mx-[92px] flex items-stretch',
|
:class="[
|
||||||
itemCount === 1 ? 'justify-center' : 'justify-between gap-2',
|
'sm:mx-[50px] md:mx-0 xl:mx-[92px] flex items-stretch',
|
||||||
]">
|
itemCount === 1 ? 'justify-center' : 'justify-between gap-2',
|
||||||
|
]"
|
||||||
|
>
|
||||||
<!-- product -->
|
<!-- product -->
|
||||||
<div v-for="(item, index) in productStore.productList" :key="index"
|
<div
|
||||||
class="w-[200px] sm:w-[260px] md:w-[290px] sm:py-5 sm:px-[15px] py-[15px] px-[10px] bg-block rounded-2xl flex flex-col items-center gap-5 sm:gap-7">
|
v-for="(item, index) in productStore.productList"
|
||||||
<img :src="`/api/public/file/${item.cover_picture_uuid}.webp`" alt="pics"
|
:key="index"
|
||||||
class="max-h-[150px] sm:max-h-[180px] md:max-h-[205px]" />
|
class="w-[200px] sm:w-[260px] md:w-[290px] sm:py-5 sm:px-[15px] py-[15px] px-[10px] bg-block rounded-2xl flex flex-col items-center gap-5 sm:gap-7"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${item.cover_picture_uuid}.webp`"
|
||||||
|
alt="pics"
|
||||||
|
class="max-h-[150px] sm:max-h-[180px] md:max-h-[205px]"
|
||||||
|
>
|
||||||
<div class="flex flex-col justify-between h-full">
|
<div class="flex flex-col justify-between h-full">
|
||||||
<div class="flex flex-col gap-[10px] sm:gap-[15px] w-full">
|
<div class="flex flex-col gap-[10px] sm:gap-[15px] w-full">
|
||||||
<h3 class="text-[13px] sm:text-base md:text-lg text-xl font-bold leading-[150%] text-bg-dark">
|
<h3
|
||||||
|
class="text-[13px] sm:text-base md:text-lg text-xl font-bold leading-[150%] text-bg-dark"
|
||||||
|
>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-[10px] sm:text-[12px] text-sm text-bg-dark">
|
<p class="text-[10px] sm:text-[12px] text-sm text-bg-dark">
|
||||||
@ -22,26 +32,38 @@
|
|||||||
<p class="text-accent-green-light text-bold-24">
|
<p class="text-accent-green-light text-bold-24">
|
||||||
{{ item.formatted_price }}
|
{{ item.formatted_price }}
|
||||||
</p>
|
</p>
|
||||||
<button @click="productStore.incrementCartItem(item.id)"
|
<button
|
||||||
class="w-9 h-9 md:w-12 md:h-12 rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center">
|
class="w-9 h-9 md:w-12 md:h-12 rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center"
|
||||||
<i class="uil uil-shopping-cart text-[25px] md:text-[24px] text-bg-light"></i>
|
@click="productStore.incrementCartItem(item.id)"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-shopping-cart text-[25px] md:text-[24px] text-bg-light"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-6 md:flex-row items-center justify-between">
|
<div class="flex flex-col gap-6 md:flex-row items-center justify-between">
|
||||||
<h3 class="h4-uppercase-bold-inter w-full text-center md:text-start xl:max-w-[50%]">
|
<h3
|
||||||
|
class="h4-uppercase-bold-inter w-full text-center md:text-start xl:max-w-[50%]"
|
||||||
|
>
|
||||||
Zlato je jistota, která nepodléhá času. Udělejte dnes rozhodnutí, které
|
Zlato je jistota, která nepodléhá času. Udělejte dnes rozhodnutí, které
|
||||||
vás ochrání zítra
|
vás ochrání zítra
|
||||||
</h3>
|
</h3>
|
||||||
<UiButtonArrow @click="menuStore.navigateToShop" type="fill" :arrow="true">{{ $t('eshop') }}</UiButtonArrow>
|
<UiButtonArrow
|
||||||
|
type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
@click="menuStore.navigateToShop"
|
||||||
|
>
|
||||||
|
{{ $t("eshop") }}
|
||||||
|
</UiButtonArrow>
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
@ -52,32 +74,31 @@ defineProps<{
|
|||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
}
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
|
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
const itemCount = ref(4);
|
const itemCount = ref(4)
|
||||||
const productStore = useProductStore();
|
const productStore = useProductStore()
|
||||||
|
|
||||||
async function updateItemCount() {
|
async function updateItemCount() {
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth
|
||||||
if (width >= 1800) itemCount.value = 5;
|
if (width >= 1800) itemCount.value = 5
|
||||||
else if (width >= 1200) itemCount.value = 4;
|
else if (width >= 1200) itemCount.value = 4
|
||||||
else if (width >= 768) itemCount.value = 3;
|
else if (width >= 768) itemCount.value = 3
|
||||||
else if (width >= 640) itemCount.value = 2;
|
else if (width >= 640) itemCount.value = 2
|
||||||
else itemCount.value = 1;
|
else itemCount.value = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(itemCount, async () => {
|
watch(itemCount, async () => {
|
||||||
await productStore.getList(itemCount.value);
|
await productStore.getList(itemCount.value)
|
||||||
});
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await updateItemCount();
|
await updateItemCount()
|
||||||
window.addEventListener("resize", updateItemCount);
|
window.addEventListener('resize', updateItemCount)
|
||||||
});
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("resize", updateItemCount);
|
window.removeEventListener('resize', updateItemCount)
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,36 +1,67 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div>
|
||||||
class="w-[150px] sm:w-[260px] md:w-[330px] px-2 py-3 sm:py-5 sm:px-[15px] bg-block rounded-2xl flex flex-col items-center gap-[15px] sm:gap-[50px]">
|
<nuxt-link
|
||||||
<img :src="`/api/public/file/${props.product?.cover_picture_uuid}.webp`" alt="Product Image"
|
:to="{
|
||||||
class="h-[95px] sm:h-[180px] md:h-[205px] rounded-[5px]"
|
name: `id-slug___${$i18n.locale}`,
|
||||||
onerror="this.onerror=null; this.src='/photo.svg';" />
|
params: {
|
||||||
|
id: menuStore.getProductMenu()?.id,
|
||||||
|
slug: menuStore.getProductMenu()?.front_menu_lang.at(0)?.link_rewrite,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
prod_id: props.product?.id,
|
||||||
|
name: props.product?.link_rewrite,
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-[150px] sm:w-[260px] md:w-[330px] px-2 py-3 sm:py-5 sm:px-[15px] bg-block rounded-2xl flex flex-col items-center gap-[15px] sm:gap-[50px]"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${props.product?.cover_picture_uuid}.webp`"
|
||||||
|
alt="Product Image"
|
||||||
|
class="h-[95px] sm:h-[180px] md:h-[205px] rounded-[5px]"
|
||||||
|
onerror="this.onerror=null; this.src='/photo.svg';"
|
||||||
|
>
|
||||||
|
|
||||||
<div class="flex flex-col justify-between h-full w-full gap-[7px] sSm:gap-[15px]">
|
<div
|
||||||
<div class="flex flex-col gap-[7px] sm:gap-[15px] w-full">
|
class="flex flex-col justify-between h-full w-full gap-[7px] sSm:gap-[15px]"
|
||||||
<h3 class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] text-bg-dark">
|
>
|
||||||
{{ props.product?.name }}
|
<div class="flex flex-col gap-[7px] sm:gap-[15px] w-full">
|
||||||
</h3>
|
<h3
|
||||||
<p class="text-[9px] sm:text-[12px] text-sm text-bg-dark">
|
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] text-bg-dark"
|
||||||
{{ props.product?.tax_name }}
|
>
|
||||||
</p>
|
{{ props.product?.name }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-[9px] sm:text-[12px] text-sm text-bg-dark">
|
||||||
|
{{ props.product?.tax_name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<p
|
||||||
|
class="text-accent-green-light font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold"
|
||||||
|
>
|
||||||
|
{{ props.product?.formatted_price }}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="w-[22px] h-[22px] sm:w-9 sm:h-9 md:w-12 md:h-12 rounded-[5px] text-bg-light sm:rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center p-1"
|
||||||
|
@click.self="productStore.incrementCartItem(props.product?.id)"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-shopping-cart text-lg sm:text-2xl md:text-[31px] cursor-pointer"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between">
|
</nuxt-link>
|
||||||
<p class="text-accent-green-light font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
|
|
||||||
{{ props.product?.formatted_price }}
|
|
||||||
</p>
|
|
||||||
<button @click="productStore.incrementCartItem(props.product?.id)"
|
|
||||||
class="w-[22px] h-[22px] sm:w-9 sm:h-9 md:w-12 md:h-12 rounded-[5px] text-bg-light sm:rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center p-1">
|
|
||||||
<i class="uil uil-shopping-cart text-lg sm:text-2xl md:text-[31px] cursor-pointer"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
product: Object,
|
product: Object,
|
||||||
});
|
})
|
||||||
|
|
||||||
const productStore = useProductStore()
|
const productStore = useProductStore()
|
||||||
|
const menuStore = useMenuStore()
|
||||||
</script>
|
</script>
|
||||||
|
274
components/section/ProductBlock.vue
Normal file
274
components/section/ProductBlock.vue
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<UiContainer>
|
||||||
|
<transition>
|
||||||
|
<div
|
||||||
|
v-if="showPopup && curImage"
|
||||||
|
ref="dropdownRef"
|
||||||
|
tabindex="0"
|
||||||
|
class="fixed top-0 left-0 bg-[#000000cc] w-screen h-screen z-50 flex items-center justify-center cursor-pointer"
|
||||||
|
@keyup.esc="showPopup = false"
|
||||||
|
@keyup.left="goLeft"
|
||||||
|
@keyup.right="goRight"
|
||||||
|
@click.self="showPopup = false"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="border border-white p-4 rounded-2xl shadow-2xl bg-white cursor-auto"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${curImage}_l.webp`"
|
||||||
|
class="max-h-[80vh] object-contain"
|
||||||
|
alt=""
|
||||||
|
@load="focusOnImgLoad"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="absolute top-8 p-8 right-8 text-4xl rotate-45 text-white"
|
||||||
|
@click="showPopup = false"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
<div class="flex w-full gap-1">
|
||||||
|
<div class="w-[50%] min-w-150px">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div
|
||||||
|
v-for="image in product.picture_uuids"
|
||||||
|
:key="image"
|
||||||
|
class="flex justify-center h-20 cursor-pointer"
|
||||||
|
@click="curImage = image"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${image}_m.webp`"
|
||||||
|
:alt="product.name"
|
||||||
|
srcset=""
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="cursor-pointer"
|
||||||
|
@click="showPopup = true"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${curImage}_m.webp`"
|
||||||
|
class="w-72"
|
||||||
|
alt=""
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-[50%]">
|
||||||
|
<h1 class="font-bold text-2xl">
|
||||||
|
{{ product.name }}
|
||||||
|
</h1>
|
||||||
|
<div>
|
||||||
|
<span class="mx-4">Product reference:</span><span>{{ product.reference }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="my-4"
|
||||||
|
v-html="product.description"
|
||||||
|
/>
|
||||||
|
<div class="my-12">
|
||||||
|
<div class="text-2xl font-bold">
|
||||||
|
<span class="mx-4">Price:</span><span>{{ formatedPrice }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<span class="mx-4">Tax information:</span><span>{{ product.tax_name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="font-bold">
|
||||||
|
<span class="mx-4">Buy out price:</span><span>{{ formatedBuyOutPrice }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
:disabled="!product.sale_active"
|
||||||
|
class="btn disabled:bg-gray-500 bg-button text-white px-4 py-4 rounded-2xl cursor-pointer"
|
||||||
|
@click="productStore.incrementCartItem(product.id)"
|
||||||
|
>
|
||||||
|
Add to cart
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-4">
|
||||||
|
<div class="w-1/2 flex cursor-pointer">
|
||||||
|
<div v-for="rel in product.recommendations"
|
||||||
|
:key="rel.id"
|
||||||
|
>
|
||||||
|
<nuxt-link
|
||||||
|
:to="{
|
||||||
|
name: `id-slug___${$i18n.locale}`,
|
||||||
|
params: {
|
||||||
|
id: menuStore.getProductMenu()?.id,
|
||||||
|
slug: menuStore.getProductMenu()?.front_menu_lang[0]
|
||||||
|
.link_rewrite,
|
||||||
|
},
|
||||||
|
query: { prod_id: rel?.id, name: rel?.link_rewrite },
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="w-1/3">
|
||||||
|
{{ rel.name }}
|
||||||
|
<img
|
||||||
|
:src="`/api/public/file/${rel.cover_picture_uuid}_m.webp`"
|
||||||
|
class="h-24"
|
||||||
|
alt=""
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2">
|
||||||
|
<div
|
||||||
|
v-for="feature in product.features"
|
||||||
|
:key="feature.feature"
|
||||||
|
class="flex gap-4 justify-around border-b"
|
||||||
|
>
|
||||||
|
<span class="mx-4">{{ feature.feature }}:</span>
|
||||||
|
<span class="mx-4">
|
||||||
|
{{ feature.value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { GenericResponse, ProductItem } from '~/types'
|
||||||
|
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
const { $session } = useNuxtApp()
|
||||||
|
const productStore = useProductStore()
|
||||||
|
const dropdownRef = ref()
|
||||||
|
|
||||||
|
// const addToCart = (p: ProductItem) => {
|
||||||
|
// alert('add to cart product: ' + p.name)
|
||||||
|
// }
|
||||||
|
|
||||||
|
const formatPrice = (p: number) => {
|
||||||
|
const formatdecimal = new Intl.NumberFormat(
|
||||||
|
$session.cookieData.value.country.iso_code,
|
||||||
|
{
|
||||||
|
style: 'decimal',
|
||||||
|
maximumFractionDigits: $session.cookieData.value.currency.precision,
|
||||||
|
},
|
||||||
|
).format(p)
|
||||||
|
return $session.cookieData.value.currency.suffix
|
||||||
|
? $session.cookieData.value.currency.sign + ' ' + formatdecimal
|
||||||
|
: formatdecimal + ' ' + $session.cookieData.value.currency.sign
|
||||||
|
}
|
||||||
|
|
||||||
|
const focusOnImgLoad = () => {
|
||||||
|
dropdownRef.value.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatedPrice = computed(() => {
|
||||||
|
return formatPrice(product.value.price)
|
||||||
|
})
|
||||||
|
|
||||||
|
const formatedBuyOutPrice = computed(() => {
|
||||||
|
return formatPrice(product.value.buyout_price)
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
// if (!route.query?.prod_id) {
|
||||||
|
// throw createError({
|
||||||
|
// statusCode: 404,
|
||||||
|
// statusMessage: 'Not Found',
|
||||||
|
// fatal: true
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
const getProduct = async (): Promise<ProductItem> => {
|
||||||
|
if (route.query?.prod_id) {
|
||||||
|
const data = await useMyFetch<GenericResponse<ProductItem>>(
|
||||||
|
`/api/public/product/${route.query?.prod_id}`,
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
// await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
return data.data
|
||||||
|
}
|
||||||
|
return {} as ProductItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const product = ref(await getProduct())
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.query?.prod_id,
|
||||||
|
async () => {
|
||||||
|
const data = await getProduct()
|
||||||
|
product.value = data
|
||||||
|
if (curImage.value != data.picture_uuids[0]) {
|
||||||
|
curImage.value = data.cover_picture_uuid
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch($session.cookieData, async () => {
|
||||||
|
const oldId = product.value.id
|
||||||
|
const data = await getProduct()
|
||||||
|
product.value = data
|
||||||
|
if (oldId != data.id) {
|
||||||
|
curImage.value = data.cover_picture_uuid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const showPopup = ref(false)
|
||||||
|
|
||||||
|
const curImage = ref(product.value.cover_picture_uuid)
|
||||||
|
|
||||||
|
watch(showPopup, (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
document.body.style.overflow = 'hidden'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.body.style.overflow = 'unset'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const goLeft = () => {
|
||||||
|
if (!curImage.value) return
|
||||||
|
const index = product.value.picture_uuids.indexOf(curImage.value)
|
||||||
|
if (index > 0) {
|
||||||
|
curImage.value = product.value.picture_uuids[index - 1]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curImage.value
|
||||||
|
= product.value.picture_uuids[product.value.picture_uuids.length - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const goRight = () => {
|
||||||
|
if (!curImage.value) return
|
||||||
|
const index = product.value.picture_uuids.indexOf(curImage.value)
|
||||||
|
if (index < product.value.picture_uuids.length - 1) {
|
||||||
|
curImage.value = product.value.picture_uuids[index + 1]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curImage.value = product.value.picture_uuids[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INSERT INTO `front_page` (`created_at`, `updated_at`, `name`, `is_default`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','0','13');
|
||||||
|
* INSERT INTO `front_menu` (`created_at`, `updated_at`, `active`, `position_id`, `id_front_page`, `is_default`, `is_root`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','1','1','13','0','0','13');
|
||||||
|
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Product','2','13','product');
|
||||||
|
* INSERT INTO `front_menu_lang` (`link_rewrite`, `id_front_menu`, `id_lang`, `name`) VALUES ('produkt','13','1','Produkt');
|
||||||
|
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Produkt','3','13','produkt');
|
||||||
|
* INSERT INTO `front_section` (`id`, `created_at`, `updated_at`, `name`, `img`, `component_name`, `is_no_lang`) VALUES ('32','2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','[]','ProductBlock','1');
|
||||||
|
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','1','32');
|
||||||
|
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','2','4');
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.v-enter-active,
|
||||||
|
.v-leave-active {
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-enter-from,
|
||||||
|
.v-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,164 +1,253 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="flex py-[15px] xl:py-20 sm:py-0">
|
<UiContainer class="flex py-[15px] xl:py-20 sm:py-0">
|
||||||
<div class="hidden xl:block rounded-2xl min-w-[40%] h-[830px]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
class="hidden xl:block rounded-2xl min-w-[40%] h-[830px]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12 ">
|
backgroundPosition: 'center',
|
||||||
<div class="space-25-55">
|
}"
|
||||||
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
/>
|
||||||
<h2 class="h2-bold-bounded">{{ $t('sign_up') }}</h2>
|
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
|
||||||
<button @click="menuStore.navigateToItem()"
|
<div class="space-25-55">
|
||||||
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer">{{
|
<div class="flex flex-wrap-reverse gap-y-4 justify-between">
|
||||||
$t('back_to_home') }}</button>
|
<h2 class="h2-bold-bounded">
|
||||||
</div>
|
{{ $t("sign_up") }}
|
||||||
<div class="space-y-[25px] sm:space-y-[30px]">
|
</h2>
|
||||||
<p>{{ $t('current_information') }}</p>
|
<button
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-[30px]">
|
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
|
||||||
<div class="space-y-[15px]">
|
@click="menuStore.navigateToItem()"
|
||||||
<p class="pl-6">{{ $t('first_name') }}</p>
|
>
|
||||||
<input :placeholder="$t('first_name')" type="text"
|
{{ $t("back_to_home") }}
|
||||||
class="text-sm sm:text-xl border border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
</button>
|
||||||
</div>
|
|
||||||
<div class="space-y-[15px]">
|
|
||||||
<p class="pl-6">{{ $t('last_name') }}</p>
|
|
||||||
<input :placeholder="$t('last_name')" type="text"
|
|
||||||
class="text-sm sm:text-xl border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[15px]">
|
|
||||||
<p class="pl-6">{{ $t('email') }}</p>
|
|
||||||
<input :placeholder="$t('email')" type="text"
|
|
||||||
class="text-sm sm:text-xl border border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[15px]" ref="dropdownRef">
|
|
||||||
<p class="pl-6">{{ $t('phone') }}</p>
|
|
||||||
<div class="flex items-center border-2 border-block rounded-lg">
|
|
||||||
<div
|
|
||||||
class="relative z-50 bg-inherit ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0">
|
|
||||||
<div class="px-[25px]" @click="dropCountry = !dropCountry">
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-2 text-sm sm:text-xl uppercase text-text-light dark:text-text-dark">
|
|
||||||
<span :class="[dropCountry && 'rotate-180', 'transition-all']"> <i
|
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
|
||||||
<p class="text-sm sm:text-xl">
|
|
||||||
{{ menuStore.selectedPhoneCountry.iso_code }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="dropCountry"
|
|
||||||
class="mt-2 absolute bg-bg-light dark:bg-bg-dark rounded-[5px] ring-0 cursor-pointer w-[130px] sm:w-full border border-button py-[10px] px-[5px] overflow-hidden">
|
|
||||||
<div class="overflow-y-auto h-[200px] w-full">
|
|
||||||
<p v-for="item in menuStore.countries" :key="item.iso_code"
|
|
||||||
@click="() => { menuStore.selectedPhoneCountry = item; dropCountry = false }"
|
|
||||||
class="w-full truncate whitespace-nowrap overflow-hidden hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
|
||||||
:title="item.name">
|
|
||||||
{{ item.name }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<p class="text-sm sm:text-xl font-normal">{{ menuStore.selectedPhoneCountry.call_prefix
|
|
||||||
}}</p>
|
|
||||||
<input id="phone" :placeholder="$t('phone')" type="text"
|
|
||||||
class="text-sm sm:text-xl placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[15px]">
|
|
||||||
<p class="pl-6">{{ $t('account_type') }}</p>
|
|
||||||
<USelect v-model="selectedType"
|
|
||||||
:items="component.front_section_lang && component.front_section_lang[0].data.account_types"
|
|
||||||
value-key="name" :searchable="false" :ui="{
|
|
||||||
base: 'bg-inherit ring-0 cursor-pointer w-auto focus:ring-0 outline-none focus-visible:ring-0 h-[50px] sm:h-[67px] w-full p-0',
|
|
||||||
trailing: 'hidden w-full',
|
|
||||||
viewport: 'ring-0 min-w-full',
|
|
||||||
content: 'bg-bg-light dark:bg-bg-dark ring-0 border border-button',
|
|
||||||
leading:
|
|
||||||
'left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 p-0 w-full',
|
|
||||||
group: 'px-[5px] py-[10px]',
|
|
||||||
item: 'hover:bg-block dark:hover:bg-button rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 min-w-full',
|
|
||||||
}">
|
|
||||||
<template #leading="{ modelValue }">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between gap-2 uppercase text-sm sm:text-xl border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 w-full h-[50px] sm:h-[67px]">
|
|
||||||
<p class="truncate whitespace-nowrap">
|
|
||||||
{{component.front_section_lang &&
|
|
||||||
component.front_section_lang[0].data.account_types.find((item) => item.name
|
|
||||||
=== modelValue)?.name}}
|
|
||||||
</p>
|
|
||||||
<span> <i
|
|
||||||
class="uil uil-angle-down text-2xl font-light cursor-pointer"></i></span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #item="{ item }">
|
|
||||||
<div class="flex items-center gap-2 cursor-pointer min-w-full">
|
|
||||||
<p
|
|
||||||
class="truncate whitespace-nowrap text-sm sm:text-xl font-medium uppercase text-text-light dark:text-text-dark opacity-100">
|
|
||||||
{{ item.name }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</USelect>
|
|
||||||
</div>
|
|
||||||
<div class="space-y-[15px]">
|
|
||||||
<p class="pl-6">{{ $t('partner_code') }}</p>
|
|
||||||
<input :placeholder="$t('placeholder_password')" type="text"
|
|
||||||
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full">
|
|
||||||
<UiButtonArrow type="fill" :arrow="true">{{ $t('sign_up') }}</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[25px] sm:mt-[30px] w-full flex justify-center gap-3">
|
|
||||||
<p class="cursor-pointer hover:underline transition-all">{{
|
|
||||||
$t('is_account')
|
|
||||||
}}</p>
|
|
||||||
<p @click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
|
|
||||||
class="text-button cursor-pointer hover:text-button-hover">{{
|
|
||||||
$t('login')
|
|
||||||
}}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="space-y-[25px] sm:space-y-[30px]">
|
||||||
|
<p>{{ $t("current_information") }}</p>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-[30px]">
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("first_name") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('first_name')"
|
||||||
|
type="text"
|
||||||
|
class="text-sm sm:text-xl border border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("last_name") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('last_name')"
|
||||||
|
type="text"
|
||||||
|
class="text-sm sm:text-xl border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("email") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('email')"
|
||||||
|
type="text"
|
||||||
|
class="text-sm sm:text-xl border border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div ref="dropdownRef"
|
||||||
|
class="space-y-[15px]"
|
||||||
|
>
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("phone") }}
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center border-2 border-block rounded-lg">
|
||||||
|
<div
|
||||||
|
class="relative z-50 bg-inherit ring-0 cursor-pointer focus:ring-0 outline-none focus-visible:ring-0"
|
||||||
|
>
|
||||||
|
<div class="px-[25px]"
|
||||||
|
@click="dropCountry = !dropCountry"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 text-sm sm:text-xl uppercase text-text-light dark:text-text-dark"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
:class="[dropCountry && 'rotate-180', 'transition-all']"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
|
<p class="text-sm sm:text-xl">
|
||||||
|
{{ menuStore.selectedPhoneCountry.iso_code }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="dropCountry"
|
||||||
|
class="mt-2 absolute bg-bg-light dark:bg-bg-dark rounded-[5px] ring-0 cursor-pointer w-[130px] sm:w-full border border-button py-[10px] px-[5px] overflow-hidden"
|
||||||
|
>
|
||||||
|
<div class="overflow-y-auto h-[200px] w-full">
|
||||||
|
<p
|
||||||
|
v-for="item in menuStore.countries"
|
||||||
|
:key="item.iso_code"
|
||||||
|
class="w-full truncate whitespace-nowrap overflow-hidden hover:bg-block dark:hover:bg-button pl-2 py-2 text-base text-text-light dark:text-text-dark rounded-[5px]"
|
||||||
|
:title="item.name"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
menuStore.selectedPhoneCountry = item;
|
||||||
|
dropCountry = false;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm sm:text-xl font-normal">
|
||||||
|
{{ menuStore.selectedPhoneCountry.call_prefix }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
id="phone"
|
||||||
|
:placeholder="$t('phone')"
|
||||||
|
type="text"
|
||||||
|
class="text-sm sm:text-xl placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("account_type") }}
|
||||||
|
</p>
|
||||||
|
<USelect
|
||||||
|
v-model="selectedType"
|
||||||
|
:items="
|
||||||
|
component.front_section_lang
|
||||||
|
&& component.front_section_lang[0].data.account_types
|
||||||
|
"
|
||||||
|
value-key="name"
|
||||||
|
:searchable="false"
|
||||||
|
:ui="{
|
||||||
|
base: 'bg-inherit ring-0 cursor-pointer w-auto focus:ring-0 outline-none focus-visible:ring-0 h-[50px] sm:h-[67px] w-full p-0',
|
||||||
|
trailing: 'hidden w-full',
|
||||||
|
viewport: 'ring-0 min-w-full',
|
||||||
|
content:
|
||||||
|
'bg-bg-light dark:bg-bg-dark ring-0 border border-button',
|
||||||
|
leading:
|
||||||
|
'left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 p-0 w-full',
|
||||||
|
group: 'px-[5px] py-[10px]',
|
||||||
|
item: 'hover:bg-block dark:hover:bg-button rounded-[5px] data-highlighted:not-data-disabled:before:bg-button/50 min-w-full',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #leading="{ modelValue }">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-2 uppercase text-sm sm:text-xl border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 w-full h-[50px] sm:h-[67px]"
|
||||||
|
>
|
||||||
|
<p class="truncate whitespace-nowrap">
|
||||||
|
{{
|
||||||
|
component.front_section_lang
|
||||||
|
&& component.front_section_lang[0].data.account_types.find(
|
||||||
|
(item) => item.name === modelValue,
|
||||||
|
)?.name
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<span>
|
||||||
|
<i
|
||||||
|
class="uil uil-angle-down text-2xl font-light cursor-pointer"
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #item="{ item }">
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-2 cursor-pointer min-w-full"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="truncate whitespace-nowrap text-sm sm:text-xl font-medium uppercase text-text-light dark:text-text-dark opacity-100"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</USelect>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("partner_code") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('placeholder_password')"
|
||||||
|
type="text"
|
||||||
|
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full"
|
||||||
|
>
|
||||||
|
<UiButtonArrow type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t("sign_up")
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
<div class="mt-[25px] sm:mt-[30px] w-full flex justify-center gap-3">
|
||||||
|
<p class="cursor-pointer hover:underline transition-all">
|
||||||
|
{{ $t("is_account") }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="text-button cursor-pointer hover:text-button-hover"
|
||||||
|
@click="
|
||||||
|
menuStore.navigateToItem(
|
||||||
|
menuStore.menuItems?.find((item) => item.id === 11),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ $t("login") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import { onClickOutside } from '@vueuse/core'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
img: string[]
|
img: string[]
|
||||||
component_name: string
|
component_name: string
|
||||||
is_no_lang: boolean
|
is_no_lang: boolean
|
||||||
page_name: string
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
account_types: {
|
account_types: {
|
||||||
id: number,
|
id: number
|
||||||
name: string
|
name: string
|
||||||
}[]
|
|
||||||
}
|
|
||||||
id_front_section: number
|
|
||||||
id_lang: number
|
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}>();
|
id_front_section: number
|
||||||
|
id_lang: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
}>()
|
||||||
|
|
||||||
const menuStore = useMenuStore()
|
const menuStore = useMenuStore()
|
||||||
const dropdownRef = ref(null);
|
const dropdownRef = ref(null)
|
||||||
const dropCountry = ref()
|
const dropCountry = ref()
|
||||||
|
|
||||||
const selectedType = ref()
|
const selectedType = ref()
|
||||||
if (props.component.front_section_lang)
|
if (props.component.front_section_lang)
|
||||||
selectedType.value = props.component.front_section_lang[0].data.account_types[0].name
|
selectedType.value
|
||||||
|
= props.component.front_section_lang[0].data.account_types[0].name
|
||||||
|
|
||||||
onClickOutside(dropdownRef, () => {
|
onClickOutside(dropdownRef, () => {
|
||||||
dropCountry.value = false
|
dropCountry.value = false
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,41 +1,62 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiContainer class="flex py-10 sm:py-14 gap-10">
|
<UiContainer class="flex py-10 sm:py-14 gap-10">
|
||||||
<div class="hidden xl:block rounded-2xl min-w-[50%] h-[830px]" :style="{
|
<div
|
||||||
backgroundImage: `url('/api/files/${component.image_collection}/${component.section_id}/${component.section_img[0]}?thumb=1200x0')`,
|
class="hidden xl:block rounded-2xl min-w-[50%] h-[830px]"
|
||||||
backgroundSize: 'cover',
|
:style="{
|
||||||
backgroundPosition: 'center',
|
backgroundImage: `url('/api/files/${component.image_collection}/${component.section_id}/${component.section_img[0]}?thumb=1200x0')`,
|
||||||
}" />
|
backgroundSize: 'cover',
|
||||||
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12 ">
|
backgroundPosition: 'center',
|
||||||
<div class="space-y-[55px]">
|
}"
|
||||||
<div class="flex flex-col-reverse sm:flex-row justify-between items-start gap-7 sm:items-center">
|
/>
|
||||||
<h2 class="h2-bold-bounded">{{ $t('reset_password') }}</h2>
|
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
|
||||||
<button
|
<div class="space-y-[55px]">
|
||||||
class="whitespace-nowrap h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer">{{
|
<div
|
||||||
$t('back_to_home') }}</button>
|
class="flex flex-col-reverse sm:flex-row justify-between items-start gap-7 sm:items-center"
|
||||||
</div>
|
>
|
||||||
<div class="space-y-[30px]">
|
<h2 class="h2-bold-bounded">
|
||||||
<p>{{ component.section_lang_data.reset_password_description }}</p>
|
{{ $t("reset_password") }}
|
||||||
<div class="space-y-[15px]">
|
</h2>
|
||||||
<p class="pl-6">{{ $t('email') }}</p>
|
<button
|
||||||
<input :placeholder="$t('email')" type="text"
|
class="whitespace-nowrap h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
|
||||||
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
>
|
||||||
</div>
|
{{ $t("back_to_home") }}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
<div class="pt-[25px] sm:pt-12 flex justify-center w-full">
|
|
||||||
<UiButtonArrow type="fill" :arrow="true">{{ $t('confirm') }}</UiButtonArrow>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
<div class="space-y-[30px]">
|
||||||
|
<p>{{ component.section_lang_data.reset_password_description }}</p>
|
||||||
|
<div class="space-y-[15px]">
|
||||||
|
<p class="pl-6">
|
||||||
|
{{ $t("email") }}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
:placeholder="$t('email')"
|
||||||
|
type="text"
|
||||||
|
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pt-[25px] sm:pt-12 flex justify-center w-full">
|
||||||
|
<UiButtonArrow type="fill"
|
||||||
|
:arrow="true"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t("confirm")
|
||||||
|
}}
|
||||||
|
</UiButtonArrow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ component: Component }>();
|
defineProps<{ component: Component }>()
|
||||||
type Component = {
|
type Component = {
|
||||||
image_collection: string;
|
image_collection: string
|
||||||
section_id: string;
|
section_id: string
|
||||||
section_img: string;
|
section_img: string
|
||||||
section_lang_data: {
|
section_lang_data: {
|
||||||
reset_password_description: string
|
reset_password_description: string
|
||||||
};
|
}
|
||||||
};</script>
|
}
|
||||||
|
</script>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<SectionShopPageCurrencyRatesBar
|
<!-- <SectionShopPageCurrencyRatesBar
|
||||||
class="mb-[25px] sm:mb-[55px] xl:mb-[75px]"
|
class="mb-[25px] sm:mb-[55px] xl:mb-[75px]"
|
||||||
/>
|
/> -->
|
||||||
<UiContainer>
|
<UiContainer>
|
||||||
<div class="flex flex-col gap-[25px] sm:gap-10 xl:flex-row">
|
<div class="flex flex-col gap-[25px] sm:gap-10 xl:flex-row">
|
||||||
<!-- button to open categories -->
|
<!-- button to open categories -->
|
||||||
@ -15,7 +15,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Transition>
|
<Transition>
|
||||||
<div v-if="openCategories" class="min-w-[250px] px-5 sm:p-0 xl:hidden">
|
<div v-if="openCategories"
|
||||||
|
class="min-w-[250px] px-5 sm:p-0 xl:hidden"
|
||||||
|
>
|
||||||
<h1
|
<h1
|
||||||
class="font-bounded leading-[140%] font-bold text-[24px] mb-[25px]"
|
class="font-bounded leading-[140%] font-bold text-[24px] mb-[25px]"
|
||||||
>
|
>
|
||||||
@ -65,8 +67,8 @@
|
|||||||
visibleFeatures[item.feature] && 'rotate-180',
|
visibleFeatures[item.feature] && 'rotate-180',
|
||||||
'transition-all',
|
'transition-all',
|
||||||
]"
|
]"
|
||||||
><i
|
><i
|
||||||
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
|
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
|
||||||
/></span>
|
/></span>
|
||||||
</span>
|
</span>
|
||||||
<ul
|
<ul
|
||||||
@ -84,7 +86,7 @@
|
|||||||
:value="`${filter.parent}.${filter.value_id}`"
|
:value="`${filter.parent}.${filter.value_id}`"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="border-button !bg-inherit"
|
class="border-button !bg-inherit"
|
||||||
/>
|
>
|
||||||
<label
|
<label
|
||||||
:for="`${filter.value_id}`"
|
:for="`${filter.value_id}`"
|
||||||
class="cursor-pointer flex items-center justify-between w-full text-base"
|
class="cursor-pointer flex items-center justify-between w-full text-base"
|
||||||
@ -155,8 +157,8 @@
|
|||||||
visibleFeatures[item.feature] && 'rotate-180',
|
visibleFeatures[item.feature] && 'rotate-180',
|
||||||
'transition-all',
|
'transition-all',
|
||||||
]"
|
]"
|
||||||
><i
|
><i
|
||||||
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
|
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
|
||||||
/></span>
|
/></span>
|
||||||
</span>
|
</span>
|
||||||
<ul
|
<ul
|
||||||
@ -178,7 +180,7 @@
|
|||||||
:value="`${filter.parent}.${filter.value_id}`"
|
:value="`${filter.parent}.${filter.value_id}`"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="border-button !bg-inherit"
|
class="border-button !bg-inherit"
|
||||||
/>
|
>
|
||||||
<label
|
<label
|
||||||
:for="`${filter.value_id}`"
|
:for="`${filter.value_id}`"
|
||||||
class="cursor-pointer flex items-center justify-between w-full"
|
class="cursor-pointer flex items-center justify-between w-full"
|
||||||
@ -219,7 +221,7 @@
|
|||||||
<img
|
<img
|
||||||
class="max-w-[150px] mx-auto"
|
class="max-w-[150px] mx-auto"
|
||||||
:src="`/api/public/file/${component.img[0]}_m.webp')`"
|
:src="`/api/public/file/${component.img[0]}_m.webp')`"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -227,7 +229,7 @@
|
|||||||
v-if="products.length < 1"
|
v-if="products.length < 1"
|
||||||
class="grid gap-12 pt-32 pb-16 md:grid-cols-2 2xl:grid-cols-3"
|
class="grid gap-12 pt-32 pb-16 md:grid-cols-2 2xl:grid-cols-3"
|
||||||
>
|
>
|
||||||
<TheProductSkeleton v-for="index in 6" :key="index" />
|
<!-- <TheProductSkeleton v-for="index in 6" :key="index" /> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- products -->
|
<!-- products -->
|
||||||
@ -243,7 +245,9 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="reachedEnd" class="w-full flex justify-center">
|
<div v-if="reachedEnd"
|
||||||
|
class="w-full flex justify-center"
|
||||||
|
>
|
||||||
<p>
|
<p>
|
||||||
{{ $t("FrontTranslations", "You reached end of the list.") }}
|
{{ $t("FrontTranslations", "You reached end of the list.") }}
|
||||||
</p>
|
</p>
|
||||||
@ -252,296 +256,306 @@
|
|||||||
</div>
|
</div>
|
||||||
</UiContainer>
|
</UiContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from 'vue'
|
||||||
import Product from "./Product.vue";
|
import Product from './Product.vue'
|
||||||
|
import CategoryTree from './CategoryTree.vue'
|
||||||
import type {
|
import type {
|
||||||
Feature,
|
Feature,
|
||||||
GenericResponse,
|
GenericResponse,
|
||||||
GenericResponseChildren,
|
GenericResponseChildren,
|
||||||
GenericResponseItems,
|
GenericResponseItems,
|
||||||
ProductType,
|
ProductType,
|
||||||
} from "~/types";
|
} from '~/types'
|
||||||
import CategoryTree from "./CategoryTree.vue";
|
|
||||||
const { $session } = useNuxtApp();
|
const { $session } = useNuxtApp()
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => $session.cookieData,
|
() => $session.cookieData,
|
||||||
async () => await getProducts(),
|
async () => await getProducts(),
|
||||||
{ deep: true }
|
{ deep: true },
|
||||||
);
|
)
|
||||||
defineProps<{
|
defineProps<{
|
||||||
component: {
|
component: {
|
||||||
id: number;
|
id: number
|
||||||
name: string;
|
name: string
|
||||||
img: string[];
|
img: string[]
|
||||||
component_name: string;
|
component_name: string
|
||||||
is_no_lang: boolean;
|
is_no_lang: boolean
|
||||||
page_name: string;
|
page_name: string
|
||||||
front_section_lang: {
|
front_section_lang: {
|
||||||
data: {
|
data: {
|
||||||
title: string;
|
title: string
|
||||||
description: string;
|
description: string
|
||||||
};
|
}
|
||||||
id_front_section: number;
|
id_front_section: number
|
||||||
id_lang: number;
|
id_lang: number
|
||||||
}[];
|
}[]
|
||||||
};
|
}
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
const openCategories = ref(false);
|
const openCategories = ref(false)
|
||||||
const isInfo = ref<boolean>(true);
|
const isInfo = ref<boolean>(true)
|
||||||
const selectedFilters = ref<any>([]);
|
const selectedFilters = ref<any>([])
|
||||||
const categoryId = ref<number>(1);
|
const categoryId = ref<number>(1)
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false)
|
||||||
const reachedEnd = ref(false);
|
const reachedEnd = ref(false)
|
||||||
|
|
||||||
const loadingElement = ref<HTMLElement | null>(null);
|
const loadingElement = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
const page = ref(1);
|
const page = ref(1)
|
||||||
const elems = ref(12);
|
const elems = ref(12)
|
||||||
const maxElements = ref(0);
|
const maxElements = ref(0)
|
||||||
|
|
||||||
const products = ref([] as ProductType[]);
|
const products = ref([] as ProductType[])
|
||||||
async function getProducts() {
|
async function getProducts() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
||||||
`/api/public/products/category/${categoryId.value}?p=${page.value}&elems=${elems.value}`,
|
`/api/public/products/category/${categoryId.value}?p=${page.value}&elems=${elems.value}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
products.value = data.items;
|
products.value = data.items
|
||||||
maxElements.value = data.items_count + 1;
|
maxElements.value = data.items_count + 1
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getProducts error:", error);
|
catch (error) {
|
||||||
|
console.error('getProducts error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = ref([] as Feature[]);
|
const filters = ref([] as Feature[])
|
||||||
async function getCategory() {
|
async function getCategory() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<object>>(
|
const { data } = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/products/category/1/classification`,
|
`/api/public/products/category/1/classification`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
filters.value = data as Feature[];
|
filters.value = data as Feature[]
|
||||||
filters.value.forEach((el: Feature) => {
|
filters.value.forEach((el: Feature) => {
|
||||||
const parentId = el.feature_id;
|
const parentId = el.feature_id
|
||||||
el.feature_values.forEach((el) => {
|
el.feature_values.forEach((el) => {
|
||||||
el.parent = parentId;
|
el.parent = parentId
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getCategory error:", error);
|
catch (error) {
|
||||||
|
console.error('getCategory error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const categoriesList = ref();
|
const categoriesList = ref()
|
||||||
async function getCategoryTree() {
|
async function getCategoryTree() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponseChildren<ProductType[]>>(
|
const { data } = await useMyFetch<GenericResponseChildren<ProductType[]>>(
|
||||||
`/api/public/categories/tree`,
|
`/api/public/categories/tree`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
categoriesList.value = data.children;
|
categoriesList.value = data.children
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getCategory error:", error);
|
catch (error) {
|
||||||
|
console.error('getCategory error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getProducts();
|
getProducts()
|
||||||
getCategory();
|
getCategory()
|
||||||
getCategoryTree();
|
getCategoryTree()
|
||||||
|
|
||||||
const closeElement = () => {
|
const closeElement = () => {
|
||||||
isInfo.value = false;
|
isInfo.value = false
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener("scroll", scrollEvent);
|
window.addEventListener('scroll', scrollEvent)
|
||||||
});
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener("scroll", scrollEvent);
|
window.removeEventListener('scroll', scrollEvent)
|
||||||
});
|
})
|
||||||
|
|
||||||
async function scrollEvent() {
|
async function scrollEvent() {
|
||||||
const maxScrollY =
|
const maxScrollY
|
||||||
window.scrollY ||
|
= window.scrollY
|
||||||
document.documentElement.scrollHeight -
|
|| document.documentElement.scrollHeight
|
||||||
document.documentElement.clientHeight;
|
- document.documentElement.clientHeight
|
||||||
|
|
||||||
if (
|
if (
|
||||||
window.scrollY >= maxScrollY - 500 &&
|
window.scrollY >= maxScrollY - 500
|
||||||
!reachedEnd.value &&
|
&& !reachedEnd.value
|
||||||
!loading.value
|
&& !loading.value
|
||||||
) {
|
) {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
await loadMoreProducts();
|
await loadMoreProducts()
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filters.value.forEach((item) => {
|
filters.value.forEach((item) => {
|
||||||
visibleFeatures[item.feature] = false;
|
visibleFeatures[item.feature] = false
|
||||||
});
|
})
|
||||||
|
|
||||||
const visibleFeatures = reactive<Record<string, boolean>>({});
|
const visibleFeatures = reactive<Record<string, boolean>>({})
|
||||||
function toggleFeature(feature: string) {
|
function toggleFeature(feature: string) {
|
||||||
if (feature in visibleFeatures) {
|
if (feature in visibleFeatures) {
|
||||||
visibleFeatures[feature] = !visibleFeatures[feature];
|
visibleFeatures[feature] = !visibleFeatures[feature]
|
||||||
} else {
|
}
|
||||||
visibleFeatures[feature] = true;
|
else {
|
||||||
|
visibleFeatures[feature] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FilteredQueryString extends URLSearchParams {
|
class FilteredQueryString extends URLSearchParams {
|
||||||
override append(name: string, value: string): void {
|
override append(name: string, value: string): void {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
super.append(name, value);
|
super.append(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadMoreProducts() {
|
async function loadMoreProducts() {
|
||||||
const qParams = new FilteredQueryString();
|
const qParams = new FilteredQueryString()
|
||||||
|
|
||||||
page.value = page.value + 1;
|
page.value = page.value + 1
|
||||||
|
|
||||||
qParams.append("p", `${page.value}`);
|
qParams.append('p', `${page.value}`)
|
||||||
qParams.append("elems", `${elems.value}`);
|
qParams.append('elems', `${elems.value}`)
|
||||||
qParams.append(
|
qParams.append(
|
||||||
"features",
|
'features',
|
||||||
selectedFilters.value.length > 0 ? selectedFilters.value : null
|
selectedFilters.value.length > 0 ? selectedFilters.value : null,
|
||||||
);
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
||||||
`/api/public/products/category/${categoryId.value}?${qParams.toString()}`,
|
`/api/public/products/category/${categoryId.value}?${qParams.toString()}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
maxElements.value = data.items_count;
|
maxElements.value = data.items_count
|
||||||
|
|
||||||
if (data.items) {
|
if (data.items) {
|
||||||
products.value.push(...(data.items as ProductType[]));
|
products.value.push(...(data.items as ProductType[]))
|
||||||
} else {
|
}
|
||||||
reachedEnd.value = true;
|
else {
|
||||||
|
reachedEnd.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (products.value.length >= maxElements.value) {
|
if (products.value.length >= maxElements.value) {
|
||||||
reachedEnd.value = true;
|
reachedEnd.value = true
|
||||||
}
|
}
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getCategory error:", error);
|
catch (error) {
|
||||||
|
console.error('getCategory error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeCategory = (item: any) => {
|
const changeCategory = (item: any) => {
|
||||||
categoryId.value = item.id;
|
categoryId.value = item.id
|
||||||
};
|
}
|
||||||
|
|
||||||
watch(selectedFilters, async (newQuestion: string) => {
|
watch(selectedFilters, async (newQuestion: string) => {
|
||||||
if (newQuestion) {
|
if (newQuestion) {
|
||||||
page.value = 1;
|
page.value = 1
|
||||||
reachedEnd.value = false;
|
reachedEnd.value = false
|
||||||
loadingElement.value?.scrollIntoView();
|
loadingElement.value?.scrollIntoView()
|
||||||
|
|
||||||
const qParams = new FilteredQueryString();
|
const qParams = new FilteredQueryString()
|
||||||
|
|
||||||
qParams.append("p", `${page.value}`);
|
qParams.append('p', `${page.value}`)
|
||||||
qParams.append("elems", `${elems.value}`);
|
qParams.append('elems', `${elems.value}`)
|
||||||
qParams.append(
|
qParams.append(
|
||||||
"features",
|
'features',
|
||||||
selectedFilters.value.length > 0 ? selectedFilters.value : null
|
selectedFilters.value.length > 0 ? selectedFilters.value : null,
|
||||||
);
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
||||||
`/api/public/products/category/1?${qParams.toString()}`,
|
`/api/public/products/category/1?${qParams.toString()}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
products.value = data.items;
|
products.value = data.items
|
||||||
maxElements.value = data.items_count;
|
maxElements.value = data.items_count
|
||||||
} catch (error) {
|
}
|
||||||
console.error("selectedFilters error:", error);
|
catch (error) {
|
||||||
|
console.error('selectedFilters error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
watch(categoryId, async (newCategoryId) => {
|
watch(categoryId, async (newCategoryId) => {
|
||||||
if (newCategoryId) {
|
if (newCategoryId) {
|
||||||
page.value = 1;
|
page.value = 1
|
||||||
reachedEnd.value = false;
|
reachedEnd.value = false
|
||||||
loadingElement.value?.scrollIntoView();
|
loadingElement.value?.scrollIntoView()
|
||||||
|
|
||||||
const qParams = new FilteredQueryString();
|
const qParams = new FilteredQueryString()
|
||||||
qParams.append("p", `${page.value}`);
|
qParams.append('p', `${page.value}`)
|
||||||
qParams.append("elems", `${elems.value}`);
|
qParams.append('elems', `${elems.value}`)
|
||||||
qParams.append(
|
qParams.append(
|
||||||
"features",
|
'features',
|
||||||
selectedFilters.value.length > 0 ? selectedFilters.value : null
|
selectedFilters.value.length > 0 ? selectedFilters.value : null,
|
||||||
);
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
const { data } = await useMyFetch<GenericResponseItems<ProductType[]>>(
|
||||||
`api/public/products/category/${newCategoryId}?${qParams.toString()}`,
|
`api/public/products/category/${newCategoryId}?${qParams.toString()}`,
|
||||||
{
|
{
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
products.value = data.items;
|
products.value = data.items
|
||||||
maxElements.value = data.items_count;
|
maxElements.value = data.items_count
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getCategory error:", error);
|
catch (error) {
|
||||||
|
console.error('getCategory error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -1,26 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap">
|
<div
|
||||||
<button :class="[
|
class="group flex cursor-pointer items-center justify-start gap-2 whitespace-nowrap"
|
||||||
'h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px]',
|
>
|
||||||
type === 'fill'
|
<button
|
||||||
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
:class="[
|
||||||
: type === 'border'
|
'h-[40px] cursor-pointer min-w-40 rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px]',
|
||||||
? 'border-button text-button group-hover:border-button-hover group-hover:text-button-hover border'
|
type === 'fill'
|
||||||
: 'border-button text-button dark:border-block dark:text-block group-hover:border-button-hover group-hover:text-button-hover border',
|
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
||||||
full && 'w-full'
|
: type === 'border'
|
||||||
]">
|
? 'border-button text-button group-hover:border-button-hover group-hover:text-button-hover border'
|
||||||
|
: 'border-button text-button dark:border-block dark:text-block group-hover:border-button-hover group-hover:text-button-hover border',
|
||||||
|
full && 'w-full',
|
||||||
|
]"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</button>
|
</button>
|
||||||
<div v-if="arrow" :class="[
|
<div
|
||||||
'flex h-[40px] w-[40px] items-center justify-center rounded-[10px] p-2.5 transition-all sm:h-[50px] sm:w-[50px] md:h-[65px] md:w-[65px] md:rounded-[15px]',
|
v-if="arrow"
|
||||||
type === 'fill'
|
:class="[
|
||||||
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
'flex h-[40px] w-[40px] items-center justify-center rounded-[10px] p-2.5 transition-all sm:h-[50px] sm:w-[50px] md:h-[65px] md:w-[65px] md:rounded-[15px]',
|
||||||
: 'border-button text-button dark:border-block dark:text-block group-hover:border-button-hover group-hover:text-button-hover border',
|
type === 'fill'
|
||||||
]">
|
? 'bg-button text-text-dark group-hover:bg-button-hover'
|
||||||
<svg class="" width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
: 'border-button text-button dark:border-block dark:text-block group-hover:border-button-hover group-hover:text-button-hover border',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class=""
|
||||||
|
width="26"
|
||||||
|
height="26"
|
||||||
|
viewBox="0 0 26 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
d="M25.1274 1.87258C25.1274 1.3203 24.6797 0.872582 24.1274 0.872584L15.1274 0.872583C14.5751 0.872583 14.1274 1.3203 14.1274 1.87258C14.1274 2.42487 14.5751 2.87258 15.1274 2.87258L23.1274 2.87258L23.1274 10.8726C23.1274 11.4249 23.5751 11.8726 24.1274 11.8726C24.6797 11.8726 25.1274 11.4249 25.1274 10.8726L25.1274 1.87258ZM1.5 24.5L2.20711 25.2071L24.8345 2.57969L24.1274 1.87258L23.4203 1.16548L0.792893 23.7929L1.5 24.5Z"
|
||||||
fill="currentColor" />
|
fill="currentColor"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -37,5 +52,5 @@ defineProps({
|
|||||||
full: {
|
full: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,57 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="space-y-[15px]">
|
<div class="space-y-[15px]">
|
||||||
<p :for="`base-input-${id}`" class="pl-6">
|
<p :for="`base-input-${id}`"
|
||||||
<slot />
|
class="pl-6"
|
||||||
</p>
|
>
|
||||||
<div class="flex flex-col">
|
<slot />
|
||||||
<div class="flex relative">
|
</p>
|
||||||
<input :id="`base-input-${id}`" :value="modelValue" :type="!isPasswordVisible ? type : 'text'"
|
<div class="flex flex-col">
|
||||||
:placeholder="placeholder" :disabled="disabled"
|
<div class="flex relative">
|
||||||
@input="$emit('update:modelValue', ($event.target as HTMLInputElement).value)"
|
<input
|
||||||
@focus="$emit('focus')" @blur="$emit('blur')"
|
:id="`base-input-${id}`"
|
||||||
class="border border-block placeholder:text-gray dark:placeholder:text-button-disabled rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2" />
|
:value="modelValue"
|
||||||
<i v-if="disabled"
|
:type="!isPasswordVisible ? type : 'text'"
|
||||||
class="uil uil-lock-alt text-[22px] absolute right-6 top-1/2 -translate-y-1/2 text-gray" />
|
:placeholder="placeholder"
|
||||||
|
:disabled="disabled"
|
||||||
|
class="border border-block placeholder:text-gray dark:placeholder:text-button-disabled rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
|
||||||
|
@input="
|
||||||
|
$emit(
|
||||||
|
'update:modelValue',
|
||||||
|
($event.target as HTMLInputElement).value,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
@focus="$emit('focus')"
|
||||||
|
@blur="$emit('blur')"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
v-if="disabled"
|
||||||
|
class="uil uil-lock-alt text-[22px] absolute right-6 top-1/2 -translate-y-1/2 text-gray"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="type === 'password'" class="order-2 ml-1.5 cursor-pointer" :title="!isPasswordVisible ? $t('show_password') : $t('hide_password')
|
<div
|
||||||
" @click="isPasswordVisible = !isPasswordVisible">
|
v-if="type === 'password'"
|
||||||
<FaceObserver class="ml-4 text-xl leading-6" :isPasswordVisible="isPasswordVisible" />
|
class="order-2 ml-1.5 cursor-pointer"
|
||||||
</div>
|
:title="
|
||||||
|
!isPasswordVisible ? $t('show_password') : $t('hide_password')
|
||||||
|
"
|
||||||
|
@click="isPasswordVisible = !isPasswordVisible"
|
||||||
|
>
|
||||||
|
<FaceObserver
|
||||||
|
class="ml-4 text-xl leading-6"
|
||||||
|
:is-password-visible="isPasswordVisible"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- <p class="mt-2 text-xs text-red-600">{{ validationText }}</p> -->
|
||||||
|
|
||||||
<!-- <p class="mt-2 text-xs text-red-600">{{ validationText }}</p> -->
|
<!-- <p v-if="!validation && validation != null" class="mt-2 text-xs text-red-600">
|
||||||
|
|
||||||
<!-- <p v-if="!validation && validation != null" class="mt-2 text-xs text-red-600">
|
|
||||||
{{ validationText }}
|
{{ validationText }}
|
||||||
</p> -->
|
</p> -->
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
|
||||||
import FaceObserver from './FaceObserver.vue';
|
|
||||||
|
|
||||||
defineEmits(["update:modelValue", "focus", "blur"]);
|
<script setup lang="ts">
|
||||||
|
import FaceObserver from './FaceObserver.vue'
|
||||||
|
|
||||||
|
defineEmits(['update:modelValue', 'focus', 'blur'])
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
modelValue?: string | any;
|
modelValue?: string | undefined
|
||||||
modelModifiers?: object;
|
modelModifiers?: object
|
||||||
id: number;
|
id: number
|
||||||
type?: string;
|
type?: string
|
||||||
disabled?: boolean;
|
disabled?: boolean
|
||||||
placeholder?: string;
|
placeholder?: string
|
||||||
validation?: boolean | null;
|
validation?: boolean | null
|
||||||
validationText?: string;
|
validationText?: string
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
const isPasswordVisible = ref(false);
|
|
||||||
|
|
||||||
|
const isPasswordVisible = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
input:-webkit-autofill,
|
input:-webkit-autofill,
|
||||||
input:-webkit-autofill:hover,
|
input:-webkit-autofill:hover,
|
||||||
input:-webkit-autofill:focus,
|
input:-webkit-autofill:focus,
|
||||||
input:-webkit-autofill:active {
|
input:-webkit-autofill:active {
|
||||||
transition: background-color 5000s ease-in-out 0s;
|
transition: background-color 5000s ease-in-out 0s;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<UContainer
|
<UContainer
|
||||||
class="mx-auto w-full max-w-[380px] px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20">
|
class="mx-auto w-full max-w-[380px] px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20"
|
||||||
<slot />
|
>
|
||||||
</UContainer>
|
<slot />
|
||||||
|
</UContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup></script>
|
<script lang="ts" setup></script>
|
||||||
|
@ -1,15 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg v-if="isPasswordVisible" xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 -960 960 960" width="16px" fill="#000000"><path d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z"/></svg>
|
<svg
|
||||||
<svg v-else xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 -960 960 960" width="16px" fill="#000000"><path d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"/></svg>
|
v-if="isPasswordVisible"
|
||||||
</template>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="16px"
|
||||||
<script>
|
viewBox="0 -960 960 960"
|
||||||
export default {
|
width="16px"
|
||||||
props: {
|
fill="#000000"
|
||||||
isPasswordVisible: {
|
>
|
||||||
type: Boolean,
|
<path
|
||||||
required: true
|
d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z"
|
||||||
}
|
/>
|
||||||
}
|
</svg>
|
||||||
};
|
<svg
|
||||||
</script>
|
v-else
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 -960 960 960"
|
||||||
|
width="16px"
|
||||||
|
fill="#000000"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M480-320q75 0 127.5-52.5T660-500q0-75-52.5-127.5T480-680q-75 0-127.5 52.5T300-500q0 75 52.5 127.5T480-320Zm0-72q-45 0-76.5-31.5T372-500q0-45 31.5-76.5T480-608q45 0 76.5 31.5T588-500q0 45-31.5 76.5T480-392Zm0 192q-146 0-266-81.5T40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200Zm0-300Zm0 220q113 0 207.5-59.5T832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
isPasswordVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@ -1,29 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="hidden md:block">
|
<div class="hidden md:block">
|
||||||
<svg width="100%" height="100%" viewBox="0 0 870 350" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg
|
||||||
<defs>
|
width="100%"
|
||||||
<clipPath id="customClip">
|
height="100%"
|
||||||
<path
|
viewBox="0 0 870 350"
|
||||||
d="M20 0.5H847.666C858.366 0.5 867.067 9.12193 867.165 19.8213L869.315 254.821C869.415 265.66 860.656 274.5 849.816 274.5H653C641.678 274.5 632.5 283.678 632.5 295V330C632.5 340.77 623.77 349.5 613 349.5H20C9.23045 349.5 0.5 340.77 0.5 330V20C0.5 9.23045 9.23045 0.5 20 0.5Z" />
|
fill="none"
|
||||||
</clipPath>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
</defs>
|
>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="customClip">
|
||||||
|
<path
|
||||||
|
d="M20 0.5H847.666C858.366 0.5 867.067 9.12193 867.165 19.8213L869.315 254.821C869.415 265.66 860.656 274.5 849.816 274.5H653C641.678 274.5 632.5 283.678 632.5 295V330C632.5 340.77 623.77 349.5 613 349.5H20C9.23045 349.5 0.5 340.77 0.5 330V20C0.5 9.23045 9.23045 0.5 20 0.5Z"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
|
||||||
<image :href="src" clip-path="url(#customClip)" preserveAspectRatio="xMidYMid slice" width="100%"
|
<image
|
||||||
height="100%" />
|
:href="src"
|
||||||
|
clip-path="url(#customClip)"
|
||||||
|
preserveAspectRatio="xMidYMid slice"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
/>
|
||||||
|
|
||||||
<foreignObject x="640" y="285" width="calc(100% - 640px - 1px)" height="calc(100% - 285px)">
|
<foreignObject
|
||||||
<slot name="button" />
|
x="640"
|
||||||
</foreignObject>
|
y="285"
|
||||||
</svg>
|
width="calc(100% - 640px - 1px)"
|
||||||
</div>
|
height="calc(100% - 285px)"
|
||||||
<div class="block md:hidden">
|
>
|
||||||
<img :src="src" width="100%" height="100%" class="object-contain rounded-2xl my-4" />
|
<slot name="button" />
|
||||||
<div class="flex justify-center">
|
</foreignObject>
|
||||||
<slot name="button" />
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="block md:hidden">
|
||||||
|
<img
|
||||||
|
:src="src"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
class="object-contain rounded-2xl my-4"
|
||||||
|
>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<slot name="button" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ src: string }>()
|
defineProps<{ src: string }>()
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { ofetch } from "ofetch";
|
import { ofetch } from 'ofetch'
|
||||||
|
|
||||||
export interface RequestOptions<T> extends RequestInit {
|
export interface RequestOptions<T> extends RequestInit {
|
||||||
onErrorOccured?: (error: Error, statusCode: number) => void;
|
onErrorOccured?: (error: Error, statusCode: number) => void
|
||||||
onSuccess?: (data: T, statusCode: number) => void;
|
onSuccess?: (data: T, statusCode: number) => void
|
||||||
onStart?: () => void;
|
onStart?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,50 +23,52 @@ export interface RequestOptions<T> extends RequestInit {
|
|||||||
*/
|
*/
|
||||||
export const useMyFetch = async <T>(
|
export const useMyFetch = async <T>(
|
||||||
url: string,
|
url: string,
|
||||||
options?: RequestOptions<T>
|
options?: RequestOptions<T>,
|
||||||
): Promise<T> => {
|
): Promise<T> => {
|
||||||
if (options?.onStart) options.onStart();
|
if (options?.onStart) options.onStart()
|
||||||
let response = null;
|
let response = null
|
||||||
try {
|
try {
|
||||||
const event = useRequestEvent();
|
const event = useRequestEvent()
|
||||||
|
|
||||||
if (options == null) options = {};
|
if (options == null) options = {}
|
||||||
|
|
||||||
options.credentials = "include";
|
options.credentials = 'include'
|
||||||
|
|
||||||
if (import.meta.server) {
|
if (import.meta.server) {
|
||||||
const api_uri =
|
const api_uri
|
||||||
event?.node.req.headers["api-uri"] || "http://localhost:4000";
|
= event?.node.req.headers['api-uri'] || 'http://localhost:4000'
|
||||||
url = api_uri + url;
|
url = api_uri + url
|
||||||
options.headers = event?.headers;
|
options.headers = event?.headers
|
||||||
}
|
}
|
||||||
|
|
||||||
response = await ofetch.raw(url, options);
|
response = await ofetch.raw(url, options)
|
||||||
if (import.meta.server && !event?.handled) {
|
if (import.meta.server && !event?.handled) {
|
||||||
for (const cookie of response.headers.getSetCookie()) {
|
for (const cookie of response.headers.getSetCookie()) {
|
||||||
event?.headers.set("Cookie", cookie);
|
event?.headers.set('Cookie', cookie)
|
||||||
event?.node.res.setHeader("set-cookie", cookie);
|
event?.node.res.setHeader('set-cookie', cookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle errors if any
|
// handle errors if any
|
||||||
if (!response.ok && typeof options.onErrorOccured == "function") {
|
if (!response.ok && typeof options.onErrorOccured == 'function') {
|
||||||
options.onErrorOccured(new Error(response.statusText), response.status);
|
options.onErrorOccured(new Error(response.statusText), response.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle success to be able clearly marked that request has finished
|
// handle success to be able clearly marked that request has finished
|
||||||
if (response.ok && typeof options.onSuccess == "function") {
|
if (response.ok && typeof options.onSuccess == 'function') {
|
||||||
options.onSuccess(response._data, response.status);
|
options.onSuccess(response._data, response.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response._data as T;
|
return response._data as T
|
||||||
} catch (e) {
|
|
||||||
// handle errors if any
|
|
||||||
if (typeof options?.onErrorOccured == "function") {
|
|
||||||
options.onErrorOccured(e as Error, response?.status || 500);
|
|
||||||
} else {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
return {} as T;
|
|
||||||
}
|
}
|
||||||
};
|
catch (e) {
|
||||||
|
// handle errors if any
|
||||||
|
if (typeof options?.onErrorOccured == 'function') {
|
||||||
|
options.onErrorOccured(e as Error, response?.status || 500)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
return {} as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
12
error.vue
12
error.vue
@ -1,8 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-10 text-center">
|
<div class="p-10 text-center">
|
||||||
<h1 class="text-3xl font-bold">Error {{ error?.statusCode }}</h1>
|
<h1 class="text-3xl font-bold">
|
||||||
<p class="mt-4 text-gray-600">{{ error?.statusMessage }}</p>
|
Error {{ error?.statusCode }}
|
||||||
<NuxtLink to="/" class="mt-6 text-blue-500 underline">Go back home</NuxtLink>
|
</h1>
|
||||||
|
<p class="mt-4 text-gray-600">
|
||||||
|
{{ error?.statusMessage }}
|
||||||
|
</p>
|
||||||
|
<NuxtLink to="/"
|
||||||
|
class="mt-6 text-blue-500 underline"
|
||||||
|
>Go back home</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,5 +1,21 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import withNuxt from "./.nuxt/eslint.config.mjs";
|
import { createConfigForNuxt } from '@nuxt/eslint-config'
|
||||||
|
|
||||||
export default withNuxt();
|
export default createConfigForNuxt({
|
||||||
// Your custom configs here
|
features: {
|
||||||
|
stylistic: true,
|
||||||
|
typescript: true,
|
||||||
|
},
|
||||||
|
}).override('nuxt/vue/rules', {
|
||||||
|
rules: {
|
||||||
|
'vue/first-attribute-linebreak': 'off',
|
||||||
|
'vue/no-v-html': 'off',
|
||||||
|
'vue/html-closing-bracket-newline': 'off',
|
||||||
|
'vue/html-self-closing': 'off',
|
||||||
|
'vue/max-attributes-per-line': 'off',
|
||||||
|
},
|
||||||
|
}).override('nuxt/stylistic', {
|
||||||
|
rules: {
|
||||||
|
'no-useless-escape': 'off',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"welcome": "Welcome to Nuxt 3"
|
|
||||||
}
|
|
@ -1,9 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="bg-bg-light dark:bg-bg-dark text-text-light dark:text-text-dark font-inter flex min-h-screen flex-col overflow-hidden">
|
class="bg-bg-light dark:bg-bg-dark text-text-light dark:text-text-dark font-inter flex min-h-[calc(100vh-50px)] flex-col overflow-hidden"
|
||||||
|
>
|
||||||
<HeaderBlock />
|
<HeaderBlock />
|
||||||
<div
|
<div
|
||||||
class="flex-1 py-[25px] sm:py-[55px] md:py-[75px] space-y-[55px] sm:space-y-[75px] md:space-y-[100px] text-inter">
|
class="flex py-[25px] sm:py-[55px] md:py-[75px] space-y-[55px] sm:space-y-[75px] md:space-y-[100px] text-inter min-h-[inherit] flex-col justify-between"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<!-- <FooterBlock /> -->
|
<!-- <FooterBlock /> -->
|
||||||
@ -12,7 +14,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import FooterBlock from "~/components/section/FooterBlock.vue";
|
// import FooterBlock from "~/components/section/FooterBlock.vue";
|
||||||
useHead({
|
// useHead({
|
||||||
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.png" }],
|
// link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.png" }],
|
||||||
});
|
// });
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,47 +1,34 @@
|
|||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
compatibilityDate: "2024-11-01",
|
|
||||||
devtools: { enabled: false },
|
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
"@pinia/nuxt",
|
'@pinia/nuxt',
|
||||||
"@nuxt/eslint",
|
'@nuxt/eslint',
|
||||||
"@nuxt/ui",
|
'@nuxt/ui',
|
||||||
"@nuxtjs/i18n",
|
'@nuxtjs/i18n',
|
||||||
"@pinia/nuxt",
|
'@pinia/nuxt',
|
||||||
],
|
],
|
||||||
|
devtools: { enabled: false },
|
||||||
i18n: {
|
|
||||||
locales: [
|
|
||||||
{ code: "pl", name: "Polski", icon: "circle-flags:pl" },
|
|
||||||
{ code: "en", name: "English", icon: "circle-flags:gb" },
|
|
||||||
{ code: "cs", name: "Čeština", icon: "circle-flags:cz" },
|
|
||||||
],
|
|
||||||
lazy: true,
|
|
||||||
defaultLocale: "en",
|
|
||||||
strategy: "prefix",
|
|
||||||
bundle: {
|
|
||||||
optimizeTranslationDirective: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
css: [
|
css: [
|
||||||
"@/assets/main.css",
|
'@/assets/main.css',
|
||||||
"vue3-toastify/dist/index.css",
|
'vue3-toastify/dist/index.css',
|
||||||
"@/assets/toastify-custom.css",
|
'@/assets/toastify-custom.css',
|
||||||
],
|
],
|
||||||
|
ui: {},
|
||||||
|
compatibilityDate: '2024-11-01',
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()],
|
plugins: [tailwindcss()],
|
||||||
build: {
|
build: {
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
allowedHosts: ["arina.ma-al.pl", "marek.ma-al.pl"],
|
allowedHosts: ['arina.ma-al.pl', 'marek.ma-al.pl'],
|
||||||
watch: {
|
watch: {
|
||||||
ignored: ["**/backend/pb_data/**"],
|
ignored: ['**/backend/pb_data/**'],
|
||||||
},
|
},
|
||||||
hmr: {
|
hmr: {
|
||||||
host: "127.0.0.1",
|
host: '127.0.0.1',
|
||||||
clientPort: 3000, // useful if proxying
|
clientPort: 3000, // useful if proxying
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -49,13 +36,26 @@ export default defineNuxtConfig({
|
|||||||
typescript: {
|
typescript: {
|
||||||
tsConfig: {
|
tsConfig: {
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
typeRoots: ["./types", "./node_modules/@types"],
|
typeRoots: ['./types', './node_modules/@types'],
|
||||||
},
|
},
|
||||||
include: ["./types"],
|
include: ['./types'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ui: {},
|
|
||||||
icon: {
|
i18n: {
|
||||||
localApiEndpoint: "/___nuxt_icon",
|
locales: [
|
||||||
|
{ code: 'pl', name: 'Polski', icon: 'circle-flags:pl' },
|
||||||
|
{ code: 'en', name: 'English', icon: 'circle-flags:gb' },
|
||||||
|
{ code: 'cs', name: 'Čeština', icon: 'circle-flags:cz' },
|
||||||
|
],
|
||||||
|
lazy: true,
|
||||||
|
defaultLocale: 'en',
|
||||||
|
strategy: 'prefix',
|
||||||
|
bundle: {
|
||||||
|
optimizeTranslationDirective: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
icon: {
|
||||||
|
localApiEndpoint: '/___nuxt_icon',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
"dev": "nuxt dev --host 0.0.0.0",
|
"dev": "nuxt dev --host 0.0.0.0",
|
||||||
"generate": "nuxt generate",
|
"generate": "nuxt generate",
|
||||||
"preview": "nuxt preview --host 0.0.0.0",
|
"preview": "nuxt preview --host 0.0.0.0",
|
||||||
"postinstall": "nuxt prepare"
|
"postinstall": "nuxt prepare",
|
||||||
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconscout/unicons": "^4.2.0",
|
"@iconscout/unicons": "^4.2.0",
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<component :is="component.componentInstance" v-for="component in componentsList" :key="component.name"
|
<component
|
||||||
:component="component.component" />
|
:is="component.componentInstance"
|
||||||
|
v-for="component in componentsList"
|
||||||
|
:key="component.name"
|
||||||
|
:component="component.component"
|
||||||
|
/>
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -12,8 +16,7 @@ import ScrollTrigger from 'gsap/ScrollTrigger'
|
|||||||
gsap.registerPlugin(ScrollTrigger)
|
gsap.registerPlugin(ScrollTrigger)
|
||||||
|
|
||||||
watch(useColorMode(), (color) => {
|
watch(useColorMode(), (color) => {
|
||||||
console.log(color);
|
console.log(color)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -21,21 +24,21 @@ onMounted(() => {
|
|||||||
'h1',
|
'h1',
|
||||||
{
|
{
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
zoom: 0.95
|
zoom: 0.95,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
duration: 1,
|
duration: 1,
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
ease: 'power2.out',
|
ease: 'power2.out',
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ScrollTrigger.create({
|
ScrollTrigger.create({
|
||||||
trigger: 'h1',
|
trigger: 'h1',
|
||||||
start: 'top 80%',
|
start: 'top 80%',
|
||||||
onEnter: () => anim.restart(), // play when scrolling down
|
onEnter: () => anim.restart(), // play when scrolling down
|
||||||
onEnterBack: () => anim.restart(), // play again when scrolling up
|
onEnterBack: () => anim.restart(), // play again when scrolling up
|
||||||
})
|
})
|
||||||
|
|
||||||
const animh2 = gsap.fromTo(
|
const animh2 = gsap.fromTo(
|
||||||
@ -48,31 +51,27 @@ onMounted(() => {
|
|||||||
// opacity: 1,
|
// opacity: 1,
|
||||||
// duration: 1,
|
// duration: 1,
|
||||||
ease: 'power2.out',
|
ease: 'power2.out',
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ScrollTrigger.create({
|
ScrollTrigger.create({
|
||||||
trigger: 'h2',
|
trigger: 'h2',
|
||||||
start: 'top 80%',
|
start: 'top 80%',
|
||||||
onEnter: () => animh2.restart(), // play when scrolling down
|
onEnter: () => animh2.restart(), // play when scrolling down
|
||||||
onEnterBack: () => animh2.restart(), // play again when scrolling up
|
onEnterBack: () => animh2.restart(), // play again when scrolling up
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
const route = useRoute();
|
const store = useStore()
|
||||||
const store = useStore();
|
const menuStore = useMenuStore()
|
||||||
const menuStore = useMenuStore();
|
await store.getSections(route.params.id)
|
||||||
await store.getSections(route.params.id);
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
menuStore.openMenu = false;
|
menuStore.openMenu = false
|
||||||
});
|
})
|
||||||
|
|
||||||
useHead(menuStore.headMeta);
|
useHead(menuStore.headMeta)
|
||||||
|
|
||||||
const componentsList = await store.getComponents(route.params.id)
|
const componentsList = await store.getComponents(route.params.id)
|
||||||
|
</script>
|
||||||
</script>
|
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<component :is="component.componentInstance" v-for="component in componentsList" :key="component.name"
|
<component
|
||||||
:component="component.component" />
|
:is="component.componentInstance"
|
||||||
|
v-for="component in componentsList"
|
||||||
|
:key="component.name"
|
||||||
|
:component="component.component"
|
||||||
|
/>
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore()
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
|
|
||||||
route.params.id = menuStore.defaultMenu.id;
|
route.params.id = menuStore.defaultMenu.id
|
||||||
route.params.slug = menuStore.defaultMenu.link_rewrite;
|
route.params.slug = menuStore.defaultMenu.link_rewrite
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
await store.getSections(route.params.id);
|
await store.getSections(route.params.id)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
menuStore.openMenu = false;
|
menuStore.openMenu = false
|
||||||
});
|
})
|
||||||
|
|
||||||
useHead(menuStore.headMeta);
|
useHead(menuStore.headMeta)
|
||||||
const componentsList = await store.getComponents(route.params.id);
|
const componentsList = await store.getComponents(route.params.id)
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,30 +1,26 @@
|
|||||||
import type { VueI18n } from "vue-i18n";
|
import type { VueI18n } from 'vue-i18n'
|
||||||
import type { RouteLocation, Router } from "vue-router";
|
import type { RouteLocation, Router } from 'vue-router'
|
||||||
import type { CookieData, GenericResponse } from "~/types";
|
import type { CookieData, GenericResponse } from '~/types'
|
||||||
|
|
||||||
|
|
||||||
// Extend the NuxtApp type
|
// Extend the NuxtApp type
|
||||||
declare module '#app' {
|
declare module '#app' {
|
||||||
interface NuxtApp {
|
interface NuxtApp {
|
||||||
$session: Session;
|
$session: Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$session: Session;
|
$session: Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Session {
|
export class Session {
|
||||||
|
cookieData = ref({} as CookieData)
|
||||||
cookieData = ref({} as CookieData);
|
|
||||||
urlParams = new URLSearchParams()
|
urlParams = new URLSearchParams()
|
||||||
currentLanguageIso = ref("" as string)
|
currentLanguageIso = ref('' as string)
|
||||||
currentCountryIso = ref("" as string)
|
currentCountryIso = ref('' as string)
|
||||||
currentCurrencyIso = ref("" as string)
|
currentCurrencyIso = ref('' as string)
|
||||||
|
|
||||||
route = {} as RouteLocation
|
route = {} as RouteLocation
|
||||||
router = {} as Router
|
router = {} as Router
|
||||||
@ -37,30 +33,43 @@ export class Session {
|
|||||||
this.router = router
|
this.router = router
|
||||||
this.i18n = i18n
|
this.i18n = i18n
|
||||||
|
|
||||||
|
this.setLanguage(
|
||||||
this.setLanguage(this.route.query?.lang_iso ? this.route.query?.lang_iso as string : unref(i18n.locale))
|
this.route.query?.lang_iso
|
||||||
this.setCountry(this.route.query?.country_iso ? this.route.query?.country_iso as string : "")
|
? (this.route.query?.lang_iso as string)
|
||||||
this.setCurrency(this.route.query?.currency_iso ? this.route.query?.currency_iso as string : "")
|
: unref(i18n.locale),
|
||||||
|
)
|
||||||
|
this.setCountry(
|
||||||
|
this.route.query?.country_iso
|
||||||
|
? (this.route.query?.country_iso as string)
|
||||||
|
: '',
|
||||||
|
)
|
||||||
|
this.setCurrency(
|
||||||
|
this.route.query?.currency_iso
|
||||||
|
? (this.route.query?.currency_iso as string)
|
||||||
|
: '',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async loadSession() {
|
async loadSession() {
|
||||||
if (this.sessionOngoing) return
|
if (this.sessionOngoing) return
|
||||||
this.sessionOngoing = true
|
this.sessionOngoing = true
|
||||||
this.setQueryParams()
|
this.setQueryParams()
|
||||||
const { data } = await useMyFetch<GenericResponse<CookieData>>(`/api/public/cookie?${this.urlParams.toString()}`, {
|
const { data } = await useMyFetch<GenericResponse<CookieData>>(
|
||||||
headers: {
|
`/api/public/cookie?${this.urlParams.toString()}`,
|
||||||
"Content-Type": "application/json",
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
onErrorOccured: (_, status) => {
|
||||||
|
throw new Error(`HTTP error: ${status}`)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
)
|
||||||
throw new Error(`HTTP error: ${status}`);
|
this.cookieData.value = data
|
||||||
},
|
|
||||||
});
|
|
||||||
this.cookieData.value = data;
|
|
||||||
this.currentCountryIso.value = this.cookieData.value.country.iso_code
|
this.currentCountryIso.value = this.cookieData.value.country.iso_code
|
||||||
this.currentLanguageIso.value = this.cookieData.value.language.iso_code
|
this.currentLanguageIso.value = this.cookieData.value.language.iso_code
|
||||||
this.currentCurrencyIso.value = this.cookieData.value.currency.iso_code
|
this.currentCurrencyIso.value = this.cookieData.value.currency.iso_code
|
||||||
setTimeout(() => this.sessionOngoing = false, 2000)
|
setTimeout(() => (this.sessionOngoing = false), 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
setLanguage(iso: string) {
|
setLanguage(iso: string) {
|
||||||
@ -77,56 +86,53 @@ export class Session {
|
|||||||
|
|
||||||
setQueryParams() {
|
setQueryParams() {
|
||||||
if (this.currentLanguageIso.value.length > 0) {
|
if (this.currentLanguageIso.value.length > 0) {
|
||||||
this.urlParams.set("lang_iso", this.currentLanguageIso.value)
|
this.urlParams.set('lang_iso', this.currentLanguageIso.value)
|
||||||
} else {
|
}
|
||||||
this.urlParams.delete("lang_iso")
|
else {
|
||||||
|
this.urlParams.delete('lang_iso')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentCountryIso.value.length > 0) {
|
if (this.currentCountryIso.value.length > 0) {
|
||||||
this.urlParams.set("country_iso", this.currentCountryIso.value)
|
this.urlParams.set('country_iso', this.currentCountryIso.value)
|
||||||
} else {
|
}
|
||||||
this.urlParams.delete("country_iso")
|
else {
|
||||||
|
this.urlParams.delete('country_iso')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.currentCurrencyIso.value.length > 0) {
|
if (this.currentCurrencyIso.value.length > 0) {
|
||||||
this.urlParams.set("currency_iso", this.currentCurrencyIso.value)
|
this.urlParams.set('currency_iso', this.currentCurrencyIso.value)
|
||||||
} else {
|
}
|
||||||
this.urlParams.delete("currency_iso")
|
else {
|
||||||
|
this.urlParams.delete('currency_iso')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(async (nuxtApp) => {
|
||||||
|
const loaded = [] as Array<string>
|
||||||
|
|
||||||
|
const { $i18n: i18n } = nuxtApp as unknown as { $i18n: VueI18n }
|
||||||
|
const { $router: router } = nuxtApp as unknown as { $router: Router }
|
||||||
|
|
||||||
|
i18n.onBeforeLanguageSwitch = async (_, newLocale) => {
|
||||||
|
if (loaded.includes(newLocale)) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
loaded.push(newLocale)
|
||||||
|
const { data } = await useMyFetch<GenericResponse<object>>(
|
||||||
|
'/api/public/front/translation',
|
||||||
|
)
|
||||||
|
|
||||||
|
i18n.setLocaleMessage(newLocale, data)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error('❌ Failed to load translation for locale:', newLocale)
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default defineNuxtPlugin(async (nuxtApp) => {
|
|
||||||
const loaded = [] as Array<string>;
|
|
||||||
|
|
||||||
const { $i18n: i18n } = nuxtApp as unknown as { $i18n: VueI18n };
|
|
||||||
const { $router: router } = nuxtApp as unknown as { $router: Router };
|
|
||||||
|
|
||||||
i18n.onBeforeLanguageSwitch = async (_, newLocale) => {
|
|
||||||
if (loaded.includes(newLocale)) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
loaded.push(newLocale);
|
|
||||||
const { data } = await useMyFetch<GenericResponse<object>>(
|
|
||||||
"/api/public/front/translation"
|
|
||||||
);
|
|
||||||
|
|
||||||
i18n.setLocaleMessage(newLocale, data);
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error("❌ Failed to load translation for locale:", newLocale);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const session = new Session(i18n, router)
|
const session = new Session(i18n, router)
|
||||||
|
|
||||||
await session.loadSession();
|
await session.loadSession()
|
||||||
nuxtApp.provide("session", session);
|
nuxtApp.provide('session', session)
|
||||||
|
})
|
||||||
});
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { defineNuxtPlugin } from "#app";
|
import { defineNuxtPlugin } from '#app'
|
||||||
|
|
||||||
export default defineNuxtPlugin(async () => {
|
export default defineNuxtPlugin(async () => {
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore()
|
||||||
await menuStore.loadMenu();
|
await menuStore.loadMenu()
|
||||||
await menuStore.getLocales();
|
await menuStore.getLocales()
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
await store.getMinValue();
|
await store.getMinValue()
|
||||||
await store.getCalculator();
|
await store.getCalculator()
|
||||||
});
|
})
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as Vue3Toastify from "vue3-toastify";
|
import * as Vue3Toastify from 'vue3-toastify'
|
||||||
import "vue3-toastify/dist/index.css";
|
import 'vue3-toastify/dist/index.css'
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
nuxtApp.vueApp.use(Vue3Toastify.default, { autoClose: 2000 });
|
nuxtApp.vueApp.use(Vue3Toastify.default, { autoClose: 2000 })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
provide: { toast: Vue3Toastify.toast },
|
provide: { toast: Vue3Toastify.toast },
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
11878
pnpm-lock.yaml
generated
11878
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/lei_certificate_aurrie.pdf
Normal file
BIN
public/lei_certificate_aurrie.pdf
Normal file
Binary file not shown.
@ -1,96 +1,98 @@
|
|||||||
import type { GenericResponse, GenericResponseItems, UserCart } from "~/types";
|
import { validation } from '../utils/validation'
|
||||||
import type { AddressesList, UserAddressOfficial } from "~/types/checkout";
|
import { REGEX_PHONE } from '../utils/regex'
|
||||||
import { validation } from "../utils/validation";
|
import type { GenericResponse, GenericResponseItems, UserCart } from '~/types'
|
||||||
import { REGEX_PHONE } from "../utils/regex";
|
import type { AddressesList, UserAddressOfficial } from '~/types/checkout'
|
||||||
import type { CartProduct } from "~/types/product";
|
import type { CartProduct } from '~/types/product'
|
||||||
|
|
||||||
export const useCheckoutStore = defineStore("checkoutStore", () => {
|
export const useCheckoutStore = defineStore('checkoutStore', () => {
|
||||||
const { $toast } = useNuxtApp();
|
const { $toast } = useNuxtApp()
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore()
|
||||||
const selectedIso = ref(menuStore.selectedCountry);
|
const selectedIso = ref(menuStore.selectedCountry)
|
||||||
const showSummary = ref(false);
|
const showSummary = ref(false)
|
||||||
|
|
||||||
// get address list
|
// get address list
|
||||||
const addressesList = ref<AddressesList[]>();
|
const addressesList = ref<AddressesList[]>()
|
||||||
const activeAddress = ref<AddressesList | null>();
|
const activeAddress = ref<AddressesList | null>()
|
||||||
async function getAddressList() {
|
async function getAddressList() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<AddressesList[]>>(
|
const { data } = await useMyFetch<GenericResponse<AddressesList[]>>(
|
||||||
`/api/restricted/user/addresses`,
|
`/api/restricted/user/addresses`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
addressesList.value = data;
|
addressesList.value = data
|
||||||
activeAddress.value = addressesList.value[0];
|
activeAddress.value = addressesList.value[0]
|
||||||
} catch (error) {
|
}
|
||||||
console.error("restrictedAddress error:", error);
|
catch (error) {
|
||||||
|
console.error('restrictedAddress error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user data
|
// get user data
|
||||||
const userName = ref("");
|
const userName = ref('')
|
||||||
const lastName = ref("");
|
const lastName = ref('')
|
||||||
const address = ref("");
|
const address = ref('')
|
||||||
const postCode = ref("");
|
const postCode = ref('')
|
||||||
const city = ref("");
|
const city = ref('')
|
||||||
const country = ref("");
|
const country = ref('')
|
||||||
const phoneNumber = ref("");
|
const phoneNumber = ref('')
|
||||||
const accountPhoneNumber = ref("");
|
const accountPhoneNumber = ref('')
|
||||||
async function getUserData() {
|
async function getUserData() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<UserAddressOfficial>>(
|
const { data } = await useMyFetch<GenericResponse<UserAddressOfficial>>(
|
||||||
`/api/restricted/user/address/official`,
|
`/api/restricted/user/address/official`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
userName.value = data.address.name;
|
userName.value = data.address.name
|
||||||
lastName.value = data.address.surname;
|
lastName.value = data.address.surname
|
||||||
address.value = data.address.street;
|
address.value = data.address.street
|
||||||
postCode.value = data.address.postcode;
|
postCode.value = data.address.postcode
|
||||||
city.value = data.address.city;
|
city.value = data.address.city
|
||||||
country.value = data.address.country.country_lang[0].name;
|
country.value = data.address.country.country_lang[0].name
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getUserData error:", error);
|
catch (error) {
|
||||||
|
console.error('getUserData error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// upload new address
|
// upload new address
|
||||||
const vNewAddressName = ref("");
|
const vNewAddressName = ref('')
|
||||||
const vNewAddressSurname = ref("");
|
const vNewAddressSurname = ref('')
|
||||||
const vNewAddressAddress = ref("");
|
const vNewAddressAddress = ref('')
|
||||||
const vNewAddressCode = ref("");
|
const vNewAddressCode = ref('')
|
||||||
const vNewAddressCity = ref("");
|
const vNewAddressCity = ref('')
|
||||||
const vNewAddressCountry = ref();
|
const vNewAddressCountry = ref()
|
||||||
const vUseAccountPhoneNumber = ref(false);
|
const vUseAccountPhoneNumber = ref(false)
|
||||||
const isOpen = ref<boolean>(false);
|
const isOpen = ref<boolean>(false)
|
||||||
async function uploadAddress() {
|
async function uploadAddress() {
|
||||||
try {
|
try {
|
||||||
const res = await useMyFetch<GenericResponse<object>>(
|
const res = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/restricted/user/address`,
|
`/api/restricted/user/address`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
address: {
|
address: {
|
||||||
@ -106,59 +108,61 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
|
|||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
$toast.success("Address successfully added", {
|
$toast.success('Address successfully added', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
isOpen.value = false;
|
isOpen.value = false
|
||||||
getAddressList();
|
getAddressList()
|
||||||
} else {
|
|
||||||
$toast.error("Failed to add address. Please try again.", {
|
|
||||||
autoClose: 5000,
|
|
||||||
dangerouslyHTMLString: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
else {
|
||||||
console.error("uploadAddress error:", error);
|
$toast.error('Failed to add address. Please try again.', {
|
||||||
|
autoClose: 5000,
|
||||||
|
dangerouslyHTMLString: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('uploadAddress error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentPrefix = ref<string | number>(
|
const currentPrefix = ref<string | number>(
|
||||||
menuStore.selectedCountry.call_prefix
|
menuStore.selectedCountry.call_prefix,
|
||||||
);
|
)
|
||||||
const changePrefix = (item: string) => {
|
const changePrefix = (item: string) => {
|
||||||
currentPrefix.value = item;
|
currentPrefix.value = item
|
||||||
};
|
}
|
||||||
const phoneValidation = ref<boolean | null>(null);
|
const phoneValidation = ref<boolean | null>(null)
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore()
|
||||||
// send form
|
// send form
|
||||||
async function sendForm() {
|
async function sendForm() {
|
||||||
let phoneNum = vUseAccountPhoneNumber.value
|
const phoneNum = vUseAccountPhoneNumber.value
|
||||||
? accountPhoneNumber.value
|
? accountPhoneNumber.value
|
||||||
: `${currentPrefix.value}${phoneNumber.value}`.replaceAll(" ", "").trim();
|
: `${currentPrefix.value}${phoneNumber.value}`.replaceAll(' ', '').trim()
|
||||||
// if (vUseAccountPhoneNumber.value) {
|
// if (vUseAccountPhoneNumber.value) {
|
||||||
// phoneNum = phoneNumber.value;
|
// phoneNum = phoneNumber.value;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
phoneValidation.value = validation(phoneNum, 1, 49, REGEX_PHONE);
|
phoneValidation.value = validation(phoneNum, 1, 49, REGEX_PHONE)
|
||||||
if (!phoneValidation.value && !vUseAccountPhoneNumber.value) {
|
if (!phoneValidation.value && !vUseAccountPhoneNumber.value) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await useMyFetch<GenericResponse<object>>(
|
const res = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/restricted/cart/checkout/delivery`,
|
`/api/restricted/cart/checkout/delivery`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
address: {
|
address: {
|
||||||
@ -176,154 +180,160 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
|
|||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
$toast.success("Form successfully sent", {
|
$toast.success('Form successfully sent', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
// redirectToSummary();
|
// redirectToSummary();
|
||||||
showSummary.value = true;
|
showSummary.value = true
|
||||||
} else {
|
}
|
||||||
$toast.error("Failed to send form. Please try again.", {
|
else {
|
||||||
|
$toast.error('Failed to send form. Please try again.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
}
|
||||||
console.error("uploadAddress error:", error);
|
catch (error) {
|
||||||
|
console.error('uploadAddress error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeActive = (item: any) => {
|
const changeActive = (item: any) => {
|
||||||
activeAddress.value = item;
|
activeAddress.value = item
|
||||||
};
|
}
|
||||||
|
|
||||||
async function getCheckout() {
|
async function getCheckout() {
|
||||||
try {
|
try {
|
||||||
const res = await useMyFetch<GenericResponse<object>>(
|
await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/restricted/cart/checkout`,
|
`/api/restricted/cart/checkout`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
} catch (error) {
|
}
|
||||||
console.error("uploadAddress error:", error);
|
catch (error) {
|
||||||
|
console.error('uploadAddress error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user cart
|
// get user cart
|
||||||
const products = ref<CartProduct[]>();
|
const products = ref<CartProduct[]>()
|
||||||
const fullPrice = ref();
|
const fullPrice = ref()
|
||||||
const fullProductsPrice = ref();
|
const fullProductsPrice = ref()
|
||||||
async function getUserCart() {
|
async function getUserCart() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<UserCart>>(
|
const { data } = await useMyFetch<GenericResponse<UserCart>>(
|
||||||
`/api/public/user/cart`,
|
`/api/public/user/cart`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
products.value = data.cart_items;
|
products.value = data.cart_items
|
||||||
fullPrice.value = data.total_value;
|
fullPrice.value = data.total_value
|
||||||
fullProductsPrice.value = data.total_value;
|
fullProductsPrice.value = data.total_value
|
||||||
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value);
|
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value)
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getUserCart error:", error);
|
catch (error) {
|
||||||
|
console.error('getUserCart error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get delivery options
|
// get delivery options
|
||||||
const deliveryOption = ref();
|
const deliveryOption = ref()
|
||||||
const currentDelivery = ref();
|
const currentDelivery = ref()
|
||||||
const shippingPrice = ref();
|
const shippingPrice = ref()
|
||||||
async function getDeliveryOptions() {
|
async function getDeliveryOptions() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<
|
const { data } = await useMyFetch<
|
||||||
GenericResponseItems<{
|
GenericResponseItems<{
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
country_iso: string;
|
country_iso: string
|
||||||
country_name: string;
|
country_name: string
|
||||||
delivery_supplier_id: number;
|
delivery_supplier_id: number
|
||||||
delivery_supplier_name: string;
|
delivery_supplier_name: string
|
||||||
id: number;
|
id: number
|
||||||
shippment_price: string;
|
shippment_price: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
}>
|
}>
|
||||||
>(`/api/restricted/cart/checkout/delivery-options`, {
|
>(`/api/restricted/cart/checkout/delivery-options`, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
console.log(data);
|
console.log(data)
|
||||||
deliveryOption.value = data.items;
|
deliveryOption.value = data.items
|
||||||
currentDelivery.value = data.items[0];
|
currentDelivery.value = data.items[0]
|
||||||
shippingPrice.value = data.items[0].shippment_price;
|
shippingPrice.value = data.items[0].shippment_price
|
||||||
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value);
|
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value)
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getUserCart error:", error);
|
catch (error) {
|
||||||
|
console.error('getUserCart error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultAddress = ref();
|
const defaultAddress = ref()
|
||||||
async function getDefAddress() {
|
async function getDefAddress() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<
|
const { data } = await useMyFetch<
|
||||||
GenericResponse<{
|
GenericResponse<{
|
||||||
addresses: [
|
addresses: [
|
||||||
{
|
{
|
||||||
is_default: string;
|
is_default: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
}>
|
}>
|
||||||
>(`/api/public/user`, {
|
>(`/api/public/user`, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
defaultAddress.value = data.addresses.find(
|
defaultAddress.value = data.addresses.find(
|
||||||
(el: any) => el.is_default === true
|
(el: any) => el.is_default === true,
|
||||||
);
|
)
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getUserCart error:", error);
|
catch (error) {
|
||||||
|
console.error('getUserCart error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,5 +381,5 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
|
|||||||
getUserCart,
|
getUserCart,
|
||||||
getDeliveryOptions,
|
getDeliveryOptions,
|
||||||
getDefAddress,
|
getDefAddress,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useStore } from './store'
|
||||||
import type {
|
import type {
|
||||||
Country,
|
Country,
|
||||||
Currency,
|
Currency,
|
||||||
@ -6,146 +7,159 @@ import type {
|
|||||||
GenericResponseItems,
|
GenericResponseItems,
|
||||||
Language,
|
Language,
|
||||||
UIFrontMenu,
|
UIFrontMenu,
|
||||||
} from "~/types";
|
} from '~/types'
|
||||||
import { useStore } from "./store";
|
import { useMyFetch } from '#imports'
|
||||||
import { useMyFetch } from "#imports";
|
|
||||||
// import { useSession } from "~/plugins/01_i18n";
|
|
||||||
|
|
||||||
|
|
||||||
function buildTreeRecursive(
|
function buildTreeRecursive(
|
||||||
data: (FrontMenu | UIFrontMenu)[],
|
data: (FrontMenu | UIFrontMenu)[],
|
||||||
parentId: number
|
parentId: number,
|
||||||
): UIFrontMenu[] {
|
): UIFrontMenu[] {
|
||||||
const children = data.filter(
|
const children = data.filter(
|
||||||
(item): item is UIFrontMenu =>
|
(item): item is UIFrontMenu =>
|
||||||
item.id_parent === parentId && !item.is_default
|
item.id_parent === parentId && !item.is_default,
|
||||||
);
|
)
|
||||||
|
|
||||||
return children.map((item) => ({
|
return children.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
children: buildTreeRecursive(data, item.id),
|
children: buildTreeRecursive(data, item.id),
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMenuStore = defineStore("menuStore", () => {
|
export const useMenuStore = defineStore('menuStore', () => {
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
const { $i18n } = useNuxtApp();
|
const { $i18n } = useNuxtApp()
|
||||||
// const session = useSession();
|
// const session = useSession();
|
||||||
const { $session } = useNuxtApp();
|
const { $session } = useNuxtApp()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
|
|
||||||
const openMenu = ref(false);
|
const openMenu = ref(false)
|
||||||
const openDropDown = ref(false);
|
const openDropDown = ref(false)
|
||||||
|
|
||||||
const defaultMenu = ref();
|
const defaultMenu = ref()
|
||||||
|
|
||||||
|
|
||||||
const menu = ref([] as UIFrontMenu[]);
|
|
||||||
const menuItems = ref([] as FrontMenu[]);
|
|
||||||
|
|
||||||
|
const menu = ref([] as UIFrontMenu[])
|
||||||
|
const menuItems = ref([] as FrontMenu[])
|
||||||
|
|
||||||
// curr/country
|
// curr/country
|
||||||
const selectedCountry = ref({} as Country);
|
const selectedCountry = ref({} as Country)
|
||||||
const selectedPhoneCountry = ref({} as Country);
|
const selectedPhoneCountry = ref({} as Country)
|
||||||
const selectedCurrency = ref({} as Currency);
|
const selectedCurrency = ref({} as Currency)
|
||||||
const selectedLanguage = ref({} as Language);
|
const selectedLanguage = ref({} as Language)
|
||||||
|
|
||||||
|
const countries = ref([] as Country[])
|
||||||
const countries = ref([] as Country[]);
|
const currencies = ref([] as Currency[])
|
||||||
const currencies = ref([] as Currency[]);
|
const languages = ref([] as Language[])
|
||||||
const languages = ref([] as Language[]);
|
|
||||||
|
|
||||||
const getLocales = async () => {
|
const getLocales = async () => {
|
||||||
const { data: countriesList } = await useMyFetch<GenericResponse<Country[]>>(`/api/public/country/list`);
|
const { data: countriesList } = await useMyFetch<
|
||||||
countries.value = countriesList;
|
GenericResponse<Country[]>
|
||||||
selectedCountry.value = countriesList.find((country) => country.iso_code === $session.currentCountryIso.value) as Country;
|
>(`/api/public/country/list`)
|
||||||
selectedPhoneCountry.value = countriesList.find((country) => country.iso_code === $session.currentCountryIso.value) as Country;
|
countries.value = countriesList
|
||||||
|
selectedCountry.value = countriesList.find(
|
||||||
|
country => country.iso_code === $session.currentCountryIso.value,
|
||||||
|
) as Country
|
||||||
|
selectedPhoneCountry.value = countriesList.find(
|
||||||
|
country => country.iso_code === $session.currentCountryIso.value,
|
||||||
|
) as Country
|
||||||
|
|
||||||
|
const { data: currenciesList } = await useMyFetch<
|
||||||
|
GenericResponseItems<Currency[]>
|
||||||
|
>(`/api/public/currencies`)
|
||||||
|
currencies.value = currenciesList.items
|
||||||
|
selectedCurrency.value = currenciesList.items.find(
|
||||||
|
currency => currency.iso_code === $session.currentCurrencyIso.value,
|
||||||
|
) as Currency
|
||||||
|
|
||||||
const { data: currenciesList } = await useMyFetch<GenericResponseItems<Currency[]>>(`/api/public/currencies`)
|
const { data: languagesList } = await useMyFetch<
|
||||||
currencies.value = currenciesList.items;
|
GenericResponseItems<Language[]>
|
||||||
selectedCurrency.value = currenciesList.items.find((currency) => currency.iso_code === $session.currentCurrencyIso.value) as Currency;
|
>(`/api/public/languages`)
|
||||||
|
languages.value = languagesList.items
|
||||||
const { data: languagesList } = await useMyFetch<GenericResponseItems<Language[]>>(`/api/public/languages`)
|
selectedLanguage.value = languagesList.items.find(
|
||||||
languages.value = languagesList.items;
|
language => language.iso_code === $session.currentLanguageIso.value,
|
||||||
selectedLanguage.value = languagesList.items.find((language) => language.iso_code === $session.currentLanguageIso.value) as Language;
|
) as Language
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const loadMenu = async () => {
|
const loadMenu = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { data } = await useMyFetch<GenericResponse<FrontMenu[]>>(
|
const { data } = await useMyFetch<GenericResponse<FrontMenu[]>>(
|
||||||
`/api/public/front/menu`,
|
`/api/public/front/menu`,
|
||||||
{
|
{
|
||||||
onErrorOccured: (err, status) => {
|
onErrorOccured: (err, status) => {
|
||||||
console.log(err, status);
|
console.log(err, status)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
menuItems.value = data;
|
menuItems.value = data
|
||||||
|
|
||||||
const root = data.find((item) => item.is_root) as UIFrontMenu;
|
const root = data.find(item => item.is_root) as UIFrontMenu
|
||||||
defaultMenu.value = data.find((item) => item.is_default);
|
defaultMenu.value = data.find(item => item.is_default)
|
||||||
if (root) {
|
if (root) {
|
||||||
menu.value = buildTreeRecursive(data, root.id);
|
menu.value = buildTreeRecursive(data, root.id)
|
||||||
} else {
|
}
|
||||||
console.warn("Root menu item not found");
|
else {
|
||||||
menu.value = [];
|
console.warn('Root menu item not found')
|
||||||
|
menu.value = []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
};
|
catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const navigateToItem = (item?: UIFrontMenu) => {
|
const navigateToItem = (item?: UIFrontMenu) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
router.push({
|
router.push({
|
||||||
params: { slug: item.front_menu_lang[0].link_rewrite, id: item.id },
|
params: { slug: item.front_menu_lang[0].link_rewrite, id: item.id },
|
||||||
name: `id-slug___${$i18n.locale.value}`,
|
name: `id-slug___${$i18n.locale.value}`,
|
||||||
});
|
})
|
||||||
openDropDown.value = false;
|
openDropDown.value = false
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
router.push({
|
router.push({
|
||||||
params: {
|
params: {
|
||||||
slug: defaultMenu.value.front_menu_lang[0].link_rewrite,
|
slug: defaultMenu.value.front_menu_lang[0].link_rewrite,
|
||||||
id: defaultMenu.value.id,
|
id: defaultMenu.value.id,
|
||||||
},
|
},
|
||||||
name: `id-slug___${$i18n.locale.value}`,
|
name: `id-slug___${$i18n.locale.value}`,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function navigateToShop() {
|
|
||||||
navigateToItem(menuItems.value?.find((item) => item.id === 5));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFirstImage = (size: "l" | "m" | "s" = "m", needbaseurl: boolean) => {
|
function navigateToShop() {
|
||||||
const req = useRequestEvent();
|
navigateToItem(menuItems.value?.find(item => item.id === 5))
|
||||||
const url = useRequestURL();
|
}
|
||||||
|
|
||||||
|
function getProductMenu() {
|
||||||
|
return menuItems.value?.find(item => item.id === 13)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFirstImage = (size: 'l' | 'm' | 's' = 'm', needbaseurl: boolean) => {
|
||||||
|
const req = useRequestEvent()
|
||||||
|
const url = useRequestURL()
|
||||||
// let img = "";
|
// let img = "";
|
||||||
const img: string[] = []
|
const img: string[] = []
|
||||||
for (const s in store.components) {
|
for (const s in store.components) {
|
||||||
if (store.components[s].front_section.img.length === 0) continue;
|
if (store.components[s].front_section.img.length === 0) continue
|
||||||
img.push(`/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp`)
|
img.push(
|
||||||
if (img.length > 0) break;;
|
`/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp`,
|
||||||
|
)
|
||||||
|
if (img.length > 0) break
|
||||||
}
|
}
|
||||||
if (img.length > 0) {
|
if (img.length > 0) {
|
||||||
if (needbaseurl) {
|
if (needbaseurl) {
|
||||||
return `${req?.headers.get("x-forwarded-proto") || url.protocol}://${req?.headers.get("x-forwarded-host") || url.host || req?.headers.get("host")}${img[0]}`;
|
return `${req?.headers.get('x-forwarded-proto') || url.protocol}://${req?.headers.get('x-forwarded-host') || url.host || req?.headers.get('host')}${img[0]}`
|
||||||
}
|
}
|
||||||
return img[0];
|
return img[0]
|
||||||
}
|
}
|
||||||
return "";
|
return ''
|
||||||
};
|
}
|
||||||
|
|
||||||
const headMeta = computed(() => {
|
const headMeta = computed(() => {
|
||||||
const item = menuItems.value?.find(
|
const item = menuItems.value?.find(
|
||||||
(item) => item.id.toString() === route.params.id
|
item => item.id.toString() === route.params.id,
|
||||||
);
|
)
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: item?.front_menu_lang[0].meta_title,
|
title: item?.front_menu_lang[0].meta_title,
|
||||||
@ -154,59 +168,66 @@ export const useMenuStore = defineStore("menuStore", () => {
|
|||||||
},
|
},
|
||||||
link: [
|
link: [
|
||||||
// { rel: "manifest", href: "/api/manifest.json" }
|
// { rel: "manifest", href: "/api/manifest.json" }
|
||||||
|
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.png' },
|
||||||
],
|
],
|
||||||
script:[
|
script: [
|
||||||
{src:"https://leiadmin.com/leitag.js?lei=894500UT83EISNNA8D04&color=dark"}
|
{
|
||||||
|
src: 'https://leiadmin.com/leitag.js?lei=894500UT83EISNNA8D04&color=dark',
|
||||||
|
defer: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
meta: [
|
meta: [
|
||||||
{
|
{
|
||||||
hid: "description",
|
hid: 'description',
|
||||||
name: "description",
|
name: 'description',
|
||||||
content: item?.front_menu_lang[0].meta_description,
|
content: item?.front_menu_lang[0].meta_description,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "og:title",
|
property: 'og:title',
|
||||||
content: item?.front_menu_lang[0].meta_title,
|
content: item?.front_menu_lang[0].meta_title,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "og:description",
|
property: 'og:description',
|
||||||
content: item?.front_menu_lang[0].meta_description,
|
content: item?.front_menu_lang[0].meta_description,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "og:image",
|
property: 'og:image',
|
||||||
content: getFirstImage("m", true),
|
content: getFirstImage('m', true),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "twitter:title",
|
property: 'twitter:title',
|
||||||
content: item?.front_menu_lang[0].meta_title,
|
content: item?.front_menu_lang[0].meta_title,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "twitter:description",
|
property: 'twitter:description',
|
||||||
content: item?.front_menu_lang[0].meta_description,
|
content: item?.front_menu_lang[0].meta_description,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: "twitter:image",
|
property: 'twitter:image',
|
||||||
content: getFirstImage("m", true),
|
content: getFirstImage('m', true),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
|
||||||
|
|
||||||
const preload = getFirstImage("l", false);
|
|
||||||
if (preload) {
|
|
||||||
meta.link.push({ rel: "preload", as: "image", href: preload } as never);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta;
|
const preload = getFirstImage('l', false)
|
||||||
|
if (preload) {
|
||||||
|
meta.link.push({ rel: 'preload', as: 'image', href: preload } as never)
|
||||||
|
}
|
||||||
|
|
||||||
});
|
return meta
|
||||||
|
})
|
||||||
|
|
||||||
// watches
|
// watches
|
||||||
watch(() => $session.cookieData, async () => {
|
watch(
|
||||||
await getLocales();
|
() => $session.cookieData,
|
||||||
await loadMenu();
|
async () => {
|
||||||
await store.getMinValue();
|
await getLocales()
|
||||||
await store.getCalculator();
|
await loadMenu()
|
||||||
}, { deep: true });
|
await store.getMinValue()
|
||||||
|
await store.getCalculator()
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
menu,
|
menu,
|
||||||
@ -226,5 +247,6 @@ export const useMenuStore = defineStore("menuStore", () => {
|
|||||||
loadMenu,
|
loadMenu,
|
||||||
navigateToItem,
|
navigateToItem,
|
||||||
getLocales,
|
getLocales,
|
||||||
};
|
getProductMenu,
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import { useMyFetch } from "#imports";
|
import { useMyFetch } from '#imports'
|
||||||
import type {
|
import type {
|
||||||
CartItem,
|
|
||||||
GenericResponse,
|
GenericResponse,
|
||||||
GenericResponseChildren,
|
GenericResponseChildren,
|
||||||
GenericResponseItems,
|
GenericResponseItems,
|
||||||
UserCart,
|
UserCart,
|
||||||
} from "~/types";
|
} from '~/types'
|
||||||
import type { Product } from "~/types/product";
|
import type { Product } from '~/types/product'
|
||||||
|
|
||||||
export const useProductStore = defineStore("productStore", () => {
|
export const useProductStore = defineStore('productStore', () => {
|
||||||
const { $toast } = useNuxtApp();
|
const { $toast } = useNuxtApp()
|
||||||
const productList = ref<Product[]>();
|
const productList = ref<Product[]>()
|
||||||
const modules = ref();
|
const modules = ref()
|
||||||
|
|
||||||
async function getList(count: number, categoryId = 1) {
|
async function getList(count: number, categoryId = 1) {
|
||||||
try {
|
try {
|
||||||
@ -19,21 +18,22 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
`/api/public/products/category/${categoryId}?p=1&elems=${count}`,
|
`/api/public/products/category/${categoryId}?p=1&elems=${count}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
// await navigateTo("/error", { replace: true });
|
// await navigateTo("/error", { replace: true });
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
productList.value = data.items;
|
productList.value = data.items
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,20 +43,21 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
`/api/public/module/e_shop`,
|
`/api/public/module/e_shop`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
modules.value = data.children.find(
|
modules.value = data.children.find(
|
||||||
(item: { id: number; name: string }) =>
|
(item: { id: number, name: string }) =>
|
||||||
item.name === "currency_rates_bar"
|
item.name === 'currency_rates_bar',
|
||||||
);
|
)
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,34 +66,36 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
const res = await useMyFetch<GenericResponse<object>>(
|
const res = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/user/cart/item/add/${id}/1`,
|
`/api/public/user/cart/item/add/${id}/1`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
$toast.success("Item successfully added to your cart.", {
|
$toast.success('Item successfully added to your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
getCart();
|
getCart()
|
||||||
} else {
|
|
||||||
$toast.error("Failed to add item to cart. Please try again.", {
|
|
||||||
autoClose: 5000,
|
|
||||||
dangerouslyHTMLString: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
else {
|
||||||
$toast.error("An unexpected error occurred while updating your cart.", {
|
$toast.error('Failed to add item to cart. Please try again.', {
|
||||||
|
autoClose: 5000,
|
||||||
|
dangerouslyHTMLString: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
$toast.error('An unexpected error occurred while updating your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
console.error("incrementCartItem error:", error);
|
console.error('incrementCartItem error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,34 +104,36 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
const res = await useMyFetch<GenericResponse<object>>(
|
const res = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/user/cart/item/subtract/${id}/1`,
|
`/api/public/user/cart/item/subtract/${id}/1`,
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
$toast.success("Item successfully removed from your cart.", {
|
$toast.success('Item successfully removed from your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
getCart();
|
getCart()
|
||||||
} else {
|
|
||||||
$toast.error("Failed to removed item from cart. Please try again.", {
|
|
||||||
autoClose: 5000,
|
|
||||||
dangerouslyHTMLString: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
else {
|
||||||
$toast.error("An unexpected error occurred while updating your cart.", {
|
$toast.error('Failed to removed item from cart. Please try again.', {
|
||||||
|
autoClose: 5000,
|
||||||
|
dangerouslyHTMLString: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
$toast.error('An unexpected error occurred while updating your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
console.error("decrementCartItem error:", error);
|
console.error('decrementCartItem error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,55 +142,58 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
const res = await useMyFetch<GenericResponse<object>>(
|
const res = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/user/cart/item/${id}`,
|
`/api/public/user/cart/item/${id}`,
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
$toast.success("Item successfully removed from your cart.", {
|
$toast.success('Item successfully removed from your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
getCart();
|
getCart()
|
||||||
} else {
|
|
||||||
$toast.error("Failed to removed item from cart. Please try again.", {
|
|
||||||
autoClose: 5000,
|
|
||||||
dangerouslyHTMLString: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
else {
|
||||||
$toast.error("An unexpected error occurred while updating your cart.", {
|
$toast.error('Failed to removed item from cart. Please try again.', {
|
||||||
|
autoClose: 5000,
|
||||||
|
dangerouslyHTMLString: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
$toast.error('An unexpected error occurred while updating your cart.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
console.error("deleteCartItem error:", error);
|
console.error('deleteCartItem error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cart = ref({} as UserCart);
|
const cart = ref({} as UserCart)
|
||||||
async function getCart() {
|
async function getCart() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<UserCart>>(
|
const { data } = await useMyFetch<GenericResponse<UserCart>>(
|
||||||
`/api/public/user/cart`,
|
`/api/public/user/cart`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
cart.value = data;
|
cart.value = data
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,5 +207,5 @@ export const useProductStore = defineStore("productStore", () => {
|
|||||||
decrementCartItem,
|
decrementCartItem,
|
||||||
deleteCartItem,
|
deleteCartItem,
|
||||||
getCart,
|
getCart,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,65 +1,66 @@
|
|||||||
import { useMyFetch } from "#imports";
|
import { useMyFetch } from '#imports'
|
||||||
import type {
|
import type {
|
||||||
componentsListType,
|
componentsListType,
|
||||||
GenericResponse,
|
GenericResponse,
|
||||||
PlanPrediction,
|
PlanPrediction,
|
||||||
} from "~/types";
|
} from '~/types'
|
||||||
import type { FrontPageSection } from "~/types/frontSection";
|
import type { FrontPageSection } from '~/types/frontSection'
|
||||||
|
|
||||||
export const useStore = defineStore("store", () => {
|
export const useStore = defineStore('store', () => {
|
||||||
const currentPageID = ref("");
|
const currentPageID = ref('')
|
||||||
const { $toast } = useNuxtApp();
|
|
||||||
|
|
||||||
// calculator
|
// calculator
|
||||||
const monthlySavings = ref(137);
|
const monthlySavings = ref(137)
|
||||||
const storagePeriod = ref(10);
|
const storagePeriod = ref(10)
|
||||||
const totalInvestment: Ref<number> = ref(0);
|
const totalInvestment: Ref<number> = ref(0)
|
||||||
const minValue = ref();
|
const minValue = ref()
|
||||||
|
|
||||||
const components = ref({} as FrontPageSection[]);
|
const components = ref({} as FrontPageSection[])
|
||||||
|
|
||||||
const getSections = async (id: string) => {
|
const getSections = async (id: string) => {
|
||||||
const { data } = await useMyFetch<GenericResponse<FrontPageSection[]>>(
|
const { data } = await useMyFetch<GenericResponse<FrontPageSection[]>>(
|
||||||
`/api/public/front/sections/${id}`
|
`/api/public/front/sections/${id}`,
|
||||||
);
|
)
|
||||||
components.value = data;
|
components.value = data
|
||||||
};
|
}
|
||||||
|
|
||||||
async function getComponents(): Promise<componentsListType[]> {
|
async function getComponents(): Promise<componentsListType[]> {
|
||||||
try {
|
try {
|
||||||
const children = components.value;
|
const children = components.value
|
||||||
|
|
||||||
if (!children || !Array.isArray(children)) {
|
if (!children || !Array.isArray(children)) {
|
||||||
console.warn("No components available in store.");
|
console.warn('No components available in store.')
|
||||||
return [];
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentsList = [] as componentsListType[];
|
const componentsList = [] as componentsListType[]
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
const componentName = child.front_section.component_name;
|
const componentName = child.front_section.component_name
|
||||||
if (!componentName) continue;
|
if (!componentName) continue
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const componentInstance = (
|
const componentInstance = (
|
||||||
await import(`@/components/section/${componentName}.vue`)
|
await import(`@/components/section/${componentName}.vue`)
|
||||||
).default;
|
).default
|
||||||
|
|
||||||
const nonReactiveComponent = markRaw(componentInstance);
|
const nonReactiveComponent = markRaw(componentInstance)
|
||||||
componentsList.push({
|
componentsList.push({
|
||||||
name: componentName,
|
name: componentName,
|
||||||
component: child.front_section,
|
component: child.front_section,
|
||||||
componentInstance: nonReactiveComponent,
|
componentInstance: nonReactiveComponent,
|
||||||
});
|
})
|
||||||
} catch (error) {
|
}
|
||||||
console.error(`Failed to load component ${componentName}`, error);
|
catch (error) {
|
||||||
|
console.error(`Failed to load component ${componentName}`, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return componentsList;
|
return componentsList
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to process components list", error);
|
|
||||||
}
|
}
|
||||||
return [];
|
catch (error) {
|
||||||
|
console.error('Failed to process components list', error)
|
||||||
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCalculator() {
|
async function getCalculator() {
|
||||||
@ -68,37 +69,39 @@ export const useStore = defineStore("store", () => {
|
|||||||
`/api/public/plan-prediction/easy/calculate?monthly_deposit=${monthlySavings.value}&years=${storagePeriod.value}`,
|
`/api/public/plan-prediction/easy/calculate?monthly_deposit=${monthlySavings.value}&years=${storagePeriod.value}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
totalInvestment.value = data.total_investement_value;
|
totalInvestment.value = data.total_investement_value
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMinValue() {
|
async function getMinValue() {
|
||||||
try {
|
try {
|
||||||
const { data } = await useMyFetch<GenericResponse<number>>(
|
const { data } = await useMyFetch<GenericResponse<number>>(
|
||||||
"/api/public/plan-prediction/free/minimum",
|
'/api/public/plan-prediction/free/minimum',
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
minValue.value = data;
|
minValue.value = data
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,5 +116,5 @@ export const useStore = defineStore("store", () => {
|
|||||||
getComponents,
|
getComponents,
|
||||||
getSections,
|
getSections,
|
||||||
getMinValue,
|
getMinValue,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import type { GenericResponse } from "~/types";
|
import type { GenericResponse } from '~/types'
|
||||||
import type { Customer } from "~/types/user";
|
import type { Customer } from '~/types/user'
|
||||||
|
|
||||||
export const useUserStore = defineStore("userStore", () => {
|
export const useUserStore = defineStore('userStore', () => {
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore()
|
||||||
const checkoutStore = useCheckoutStore();
|
const checkoutStore = useCheckoutStore()
|
||||||
|
|
||||||
const { $toast } = useNuxtApp();
|
const { $toast } = useNuxtApp()
|
||||||
|
|
||||||
const fullUserData = ref<Customer | null>(null);
|
const fullUserData = ref<Customer | null>(null)
|
||||||
const isLogged = ref<boolean>(true);
|
const isLogged = ref<boolean>(true)
|
||||||
const user = ref<string | null>(null);
|
const user = ref<string | null>(null)
|
||||||
|
|
||||||
async function checkIsLogged() {
|
async function checkIsLogged() {
|
||||||
try {
|
try {
|
||||||
@ -18,120 +18,128 @@ export const useUserStore = defineStore("userStore", () => {
|
|||||||
`/api/public/user`,
|
`/api/public/user`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: async (_, status) => {
|
onErrorOccured: async (_, status) => {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
statusMessage: `HTTP error: ${status}`,
|
statusMessage: `HTTP error: ${status}`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if ("loggedin" in data && data.loggedin === true) {
|
if ('loggedin' in data && data.loggedin === true) {
|
||||||
isLogged.value = true;
|
isLogged.value = true
|
||||||
user.value = `${data.first_name} ${data.last_name}` as any;
|
user.value = `${data.first_name} ${data.last_name}` as string
|
||||||
fullUserData.value = data;
|
fullUserData.value = data
|
||||||
checkoutStore.accountPhoneNumber = fullUserData.value.phone_number;
|
checkoutStore.accountPhoneNumber = fullUserData.value.phone_number
|
||||||
} else {
|
|
||||||
isLogged.value = false;
|
|
||||||
user.value = null;
|
|
||||||
fullUserData.value = null;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
else {
|
||||||
console.error("checkIsLogged error:", error);
|
isLogged.value = false
|
||||||
|
user.value = null
|
||||||
|
fullUserData.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('checkIsLogged error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// login
|
// login
|
||||||
const email = ref();
|
const email = ref()
|
||||||
const password = ref();
|
const password = ref()
|
||||||
const vLogin = ref<boolean>(true);
|
const vLogin = ref<boolean>(true)
|
||||||
const vCodeVerify = ref<boolean>(false);
|
const vCodeVerify = ref<boolean>(false)
|
||||||
const vCode = ref<number | null>(null);
|
const vCode = ref<number | null>(null)
|
||||||
async function logIn() {
|
async function logIn() {
|
||||||
try {
|
try {
|
||||||
const data = await useMyFetch<GenericResponse<object>>(
|
const data = await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/user/session/start`,
|
`/api/public/user/session/start`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
mail: email.value,
|
mail: email.value,
|
||||||
password: password.value,
|
password: password.value,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
if (data.status === 200 || data.status === 201) {
|
if (data.status === 200 || data.status === 201) {
|
||||||
console.log(vCodeVerify.value);
|
console.log(vCodeVerify.value)
|
||||||
|
|
||||||
$toast.success("Code successfully sent to your email", {
|
$toast.success('Code successfully sent to your email', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
vLogin.value = false;
|
vLogin.value = false
|
||||||
vCodeVerify.value = true;
|
vCodeVerify.value = true
|
||||||
} else {
|
}
|
||||||
$toast.error("Failed to sent code to your email. Please try again.", {
|
else {
|
||||||
|
$toast.error('Failed to sent code to your email. Please try again.', {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
store.minValue = data;
|
store.minValue = data
|
||||||
} catch (error) {
|
}
|
||||||
console.error("getList error:", error);
|
catch (error) {
|
||||||
|
console.error('getList error:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendFormCode = async (redirect?: boolean) => {
|
const sendFormCode = async (redirect?: boolean) => {
|
||||||
try {
|
try {
|
||||||
const data = await useMyFetch<GenericResponse<object>>(
|
await useMyFetch<GenericResponse<object>>(
|
||||||
`/api/public/user/session/confirm`,
|
`/api/public/user/session/confirm`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
code: vCode.value,
|
code: vCode.value,
|
||||||
mail: email.value,
|
mail: email.value,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
onErrorOccured: (_, status) => {
|
onErrorOccured: (_, status) => {
|
||||||
throw new Error(`HTTP error: ${status}`);
|
throw new Error(`HTTP error: ${status}`)
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
await checkIsLogged();
|
await checkIsLogged()
|
||||||
|
|
||||||
if (isLogged.value) {
|
if (isLogged.value) {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
console.log(isLogged.value);
|
console.log(isLogged.value)
|
||||||
menuStore.navigateToItem();
|
menuStore.navigateToItem()
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// window.location.href = atob(redirect);
|
// window.location.href = atob(redirect);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
useNuxtApp().$toast.error(`Error occurred: Failed to confirm code`, {
|
useNuxtApp().$toast.error(`Error occurred: Failed to confirm code`, {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e)
|
||||||
useNuxtApp().$toast.error(`Invalid code provided`, {
|
useNuxtApp().$toast.error(`Invalid code provided`, {
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
dangerouslyHTMLString: true,
|
dangerouslyHTMLString: true,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLogged,
|
isLogged,
|
||||||
@ -144,5 +152,5 @@ export const useUserStore = defineStore("userStore", () => {
|
|||||||
logIn,
|
logIn,
|
||||||
checkIsLogged,
|
checkIsLogged,
|
||||||
sendFormCode,
|
sendFormCode,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
export interface AddressesList {
|
export interface AddressesList {
|
||||||
address: {
|
address: {
|
||||||
city: string;
|
city: string
|
||||||
country_iso: string;
|
country_iso: string
|
||||||
name: string;
|
name: string
|
||||||
postcode: string;
|
postcode: string
|
||||||
street: string;
|
street: string
|
||||||
surname: string;
|
surname: string
|
||||||
};
|
}
|
||||||
address_id: number;
|
address_id: number
|
||||||
alias: string;
|
alias: string
|
||||||
customer_id: number;
|
customer_id: number
|
||||||
is_default: boolean;
|
is_default: boolean
|
||||||
is_official: boolean;
|
is_official: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserAddressOfficial {
|
export interface UserAddressOfficial {
|
||||||
address: {
|
address: {
|
||||||
name: string;
|
name: string
|
||||||
surname: string;
|
surname: string
|
||||||
street: string;
|
street: string
|
||||||
postcode: string;
|
postcode: string
|
||||||
city: string;
|
city: string
|
||||||
country: {
|
country: {
|
||||||
country_lang: [
|
country_lang: [
|
||||||
{
|
{
|
||||||
name: string;
|
name: string
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
export interface Footer {
|
export interface Footer {
|
||||||
data: {
|
data: {
|
||||||
contact: Contact
|
contact: Contact
|
||||||
docs: FooterDoc[]
|
docs: FooterDoc[]
|
||||||
}
|
}
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Contact {
|
export interface Contact {
|
||||||
header: string
|
header: string
|
||||||
ownerAddress: string
|
ownerAddress: string
|
||||||
ownerMail: string
|
ownerMail: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FooterDoc {
|
export interface FooterDoc {
|
||||||
footer_section: string
|
footer_section: string
|
||||||
translation: string
|
translation: string
|
||||||
data: FooterPdf[]
|
data: FooterPdf[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FooterPdf {
|
export interface FooterPdf {
|
||||||
name: string
|
name: string
|
||||||
translation: string
|
translation: string
|
||||||
guest_avaliable: boolean
|
guest_avaliable: boolean
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ export interface FrontMenuLang {
|
|||||||
link_rewrite: string
|
link_rewrite: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface UIFrontMenu extends FrontMenu {
|
export interface UIFrontMenu extends FrontMenu {
|
||||||
children?: UIFrontMenu[];
|
children?: UIFrontMenu[]
|
||||||
}
|
}
|
||||||
|
185
types/index.ts
185
types/index.ts
@ -1,71 +1,68 @@
|
|||||||
import type { DefineComponent } from "vue";
|
import type { DefineComponent } from 'vue'
|
||||||
import type { FrontSection } from "~/types/frontSection";
|
import type { FrontSection } from '~/types/frontSection'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type componentsListType = {
|
export type componentsListType = {
|
||||||
name: string;
|
name: string
|
||||||
component: FrontSection;
|
component: FrontSection
|
||||||
componentInstance: DefineComponent;
|
componentInstance: DefineComponent
|
||||||
};
|
|
||||||
|
|
||||||
export type PartnersList = {
|
|
||||||
country_iso: string;
|
|
||||||
country_name: string;
|
|
||||||
total: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FeatureValue = {
|
|
||||||
parent: number;
|
|
||||||
products_with_value: number;
|
|
||||||
value: string;
|
|
||||||
value_id: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Feature = {
|
|
||||||
feature: string;
|
|
||||||
feature_id: number;
|
|
||||||
feature_values: FeatureValue[];
|
|
||||||
products_with_feature: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ProductType = {
|
|
||||||
applied_tax_rate: number;
|
|
||||||
cover_picture_uuid: string;
|
|
||||||
description: string;
|
|
||||||
formatted_price: string;
|
|
||||||
id: number;
|
|
||||||
in_stock: number;
|
|
||||||
is_sale_active: boolean;
|
|
||||||
link_rewrite: string;
|
|
||||||
name: string;
|
|
||||||
price: number;
|
|
||||||
tax_name: string;
|
|
||||||
cart_item_id?: number;
|
|
||||||
product_id?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Country {
|
|
||||||
iso_code: string;
|
|
||||||
currency_iso_code: string;
|
|
||||||
call_prefix: string;
|
|
||||||
need_postcode: boolean;
|
|
||||||
postcode_format: string;
|
|
||||||
is_default: boolean;
|
|
||||||
active: boolean;
|
|
||||||
name: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PartnersList = {
|
||||||
|
country_iso: string
|
||||||
|
country_name: string
|
||||||
|
total: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FeatureValue = {
|
||||||
|
parent: number
|
||||||
|
products_with_value: number
|
||||||
|
value: string
|
||||||
|
value_id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Feature = {
|
||||||
|
feature: string
|
||||||
|
feature_id: number
|
||||||
|
feature_values: FeatureValue[]
|
||||||
|
products_with_feature: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProductType = {
|
||||||
|
applied_tax_rate: number
|
||||||
|
cover_picture_uuid: string
|
||||||
|
description: string
|
||||||
|
formatted_price: string
|
||||||
|
id: number
|
||||||
|
in_stock: number
|
||||||
|
is_sale_active: boolean
|
||||||
|
link_rewrite: string
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
tax_name: string
|
||||||
|
cart_item_id?: number
|
||||||
|
product_id?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Country {
|
||||||
|
iso_code: string
|
||||||
|
currency_iso_code: string
|
||||||
|
call_prefix: string
|
||||||
|
need_postcode: boolean
|
||||||
|
postcode_format: string
|
||||||
|
is_default: boolean
|
||||||
|
active: boolean
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface Currency {
|
export interface Currency {
|
||||||
iso_code: string;
|
iso_code: string
|
||||||
name: string;
|
name: string
|
||||||
UpdatedAt: string;
|
UpdatedAt: string
|
||||||
iso_code_num: number;
|
iso_code_num: number
|
||||||
precision: number;
|
precision: number
|
||||||
sign: string;
|
sign: string
|
||||||
active: boolean;
|
active: boolean
|
||||||
suffix: boolean;
|
suffix: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Language {
|
export interface Language {
|
||||||
@ -80,50 +77,54 @@ export interface Language {
|
|||||||
active: boolean
|
active: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CookieData { country: Country, currency: Currency, language: Language }
|
export interface CookieData {
|
||||||
|
country: Country
|
||||||
|
currency: Currency
|
||||||
|
language: Language
|
||||||
|
}
|
||||||
|
|
||||||
export interface CartItem {
|
export interface CartItem {
|
||||||
cart_item_id: number;
|
cart_item_id: number
|
||||||
link_rewrite: string;
|
link_rewrite: string
|
||||||
name: string;
|
name: string
|
||||||
picture_uuid: string;
|
picture_uuid: string
|
||||||
product_id: number;
|
product_id: number
|
||||||
quantity: number;
|
quantity: number
|
||||||
single_item_price: number;
|
single_item_price: number
|
||||||
total_price: number;
|
total_price: number
|
||||||
}
|
|
||||||
export interface UserCart {
|
|
||||||
cart_items: CartItem[];
|
|
||||||
id: number;
|
|
||||||
checkout_in_progress: boolean;
|
|
||||||
currency_iso: string;
|
|
||||||
total_value: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenericResponse<Data> {
|
export interface GenericResponse<Data> {
|
||||||
data: Data;
|
data: Data
|
||||||
message?: string;
|
message?: string
|
||||||
status: number;
|
status: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenericResponseItems<Data> {
|
export interface GenericResponseItems<Data> {
|
||||||
data: { items: Data; items_count: number };
|
data: { items: Data, items_count: number }
|
||||||
message?: string;
|
message?: string
|
||||||
status: number;
|
status: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GenericResponseChildren<Data> {
|
export interface GenericResponseChildren<Data> {
|
||||||
data: { children: Data; items_count: number };
|
data: { children: Data, items_count: number }
|
||||||
message?: string;
|
message?: string
|
||||||
status: number;
|
status: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
InvestmentPiece,
|
InvestmentPiece,
|
||||||
PlanPrediction,
|
PlanPrediction,
|
||||||
PeriodToFirstPiece,
|
PeriodToFirstPiece,
|
||||||
} from "./planPrediction";
|
} from './planPrediction'
|
||||||
export type { Product } from "./product";
|
export type {
|
||||||
export type { FrontMenu, FrontMenuLang, UIFrontMenu } from "./frontMenu";
|
Product,
|
||||||
export type {Contact, Footer, FooterDoc, FooterPdf} from './footer'
|
ProductItem,
|
||||||
|
CategoryProductItem,
|
||||||
|
FeatureProductItem,
|
||||||
|
RecommendationProductItem,
|
||||||
|
CartProduct,
|
||||||
|
UserCart,
|
||||||
|
} from './product'
|
||||||
|
export type { FrontMenu, FrontMenuLang, UIFrontMenu } from './frontMenu'
|
||||||
|
export type { Contact, Footer, FooterDoc, FooterPdf } from './footer'
|
||||||
|
@ -37,4 +37,4 @@ export interface PeriodToFirstPiece {
|
|||||||
years: number
|
years: number
|
||||||
months: number
|
months: number
|
||||||
days: number
|
days: number
|
||||||
}
|
}
|
||||||
|
101
types/product.ts
101
types/product.ts
@ -1,32 +1,85 @@
|
|||||||
export interface Product {
|
export interface Product {
|
||||||
id: number;
|
id: number
|
||||||
link_rewrite: string;
|
link_rewrite: string
|
||||||
name: string;
|
name: string
|
||||||
cover_picture_uuid: string;
|
cover_picture_uuid: string
|
||||||
description: string;
|
description: string
|
||||||
price: number;
|
price: number
|
||||||
formatted_price: string;
|
formatted_price: string
|
||||||
in_stock: number;
|
in_stock: number
|
||||||
is_sale_active: boolean;
|
is_sale_active: boolean
|
||||||
applied_tax_rate: number;
|
applied_tax_rate: number
|
||||||
tax_name: string;
|
tax_name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CartProduct {
|
export interface CartProduct {
|
||||||
cart_item_id: number;
|
cart_item_id: number
|
||||||
link_rewrite: string;
|
link_rewrite: string
|
||||||
name: string;
|
name: string
|
||||||
picture_uuid: string;
|
picture_uuid: string
|
||||||
product_id: number;
|
product_id: number
|
||||||
quantity: number;
|
quantity: number
|
||||||
single_item_price: number;
|
single_item_price: number
|
||||||
total_price: number;
|
total_price: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserCart {
|
export interface UserCart {
|
||||||
cart_items: CartProduct[];
|
cart_items: CartProduct[]
|
||||||
checkout_in_progress: boolean;
|
checkout_in_progress: boolean
|
||||||
currency_iso: string;
|
currency_iso: string
|
||||||
id: number;
|
id: number
|
||||||
total_value: number;
|
total_value: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductItem {
|
||||||
|
id: number
|
||||||
|
cover_picture_uuid: string
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
applied_tax_rate: number
|
||||||
|
tax_name: string
|
||||||
|
buyout_price: number
|
||||||
|
buyout_price_reduction: number
|
||||||
|
sale_active: boolean
|
||||||
|
in_stock: number
|
||||||
|
reference: string
|
||||||
|
description: string
|
||||||
|
description_short: string
|
||||||
|
link_rewrite: string
|
||||||
|
meta_title: string
|
||||||
|
meta_description: string
|
||||||
|
weight: number
|
||||||
|
features: FeatureProductItem[]
|
||||||
|
categories: CategoryProductItem[]
|
||||||
|
picture_uuids: string[]
|
||||||
|
video_uuids: string[]
|
||||||
|
recommendations: RecommendationProductItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeatureProductItem {
|
||||||
|
feature_id: number
|
||||||
|
feature: string
|
||||||
|
value_id: number
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryProductItem {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
link_rewrite: string
|
||||||
|
parent_id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecommendationProductItem {
|
||||||
|
id: number
|
||||||
|
link_rewrite: string
|
||||||
|
name: string
|
||||||
|
cover_picture_uuid: string
|
||||||
|
description: string
|
||||||
|
price: number
|
||||||
|
formatted_price: string
|
||||||
|
in_stock: number
|
||||||
|
is_sale_active: boolean
|
||||||
|
applied_tax_rate: number
|
||||||
|
tax_name: string
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,49 @@
|
|||||||
export interface Customer {
|
export interface Customer {
|
||||||
active: boolean;
|
active: boolean
|
||||||
agreed_for_newsletter: boolean;
|
agreed_for_newsletter: boolean
|
||||||
bank_accounts: {
|
bank_accounts: {
|
||||||
bank_currency_iso: string;
|
bank_currency_iso: string
|
||||||
bank_name: string;
|
bank_name: string
|
||||||
customer_id: number;
|
customer_id: number
|
||||||
iban: string;
|
iban: string
|
||||||
swift: string;
|
swift: string
|
||||||
verified: boolean;
|
verified: boolean
|
||||||
}[];
|
}[]
|
||||||
birthday_date: string;
|
birthday_date: string
|
||||||
communication_languag_id: number;
|
communication_languag_id: number
|
||||||
document_verified: boolean;
|
document_verified: boolean
|
||||||
documents: {
|
documents: {
|
||||||
file: string;
|
file: string
|
||||||
id: number;
|
id: number
|
||||||
name: string;
|
name: string
|
||||||
size: number;
|
size: number
|
||||||
typ: string;
|
typ: string
|
||||||
}[];
|
}[]
|
||||||
email: string;
|
email: string
|
||||||
entity: {
|
entity: {
|
||||||
city: string;
|
city: string
|
||||||
country_iso: string;
|
country_iso: string
|
||||||
customer_id: number;
|
customer_id: number
|
||||||
extra_enitity_id: string;
|
extra_enitity_id: string
|
||||||
name: string;
|
name: string
|
||||||
national_court_register_number: string;
|
national_court_register_number: string
|
||||||
postcode: string;
|
postcode: string
|
||||||
statistical_number: string;
|
statistical_number: string
|
||||||
street: string;
|
street: string
|
||||||
vat_number: string;
|
vat_number: string
|
||||||
web_pages_list: string;
|
web_pages_list: string
|
||||||
}[];
|
}[]
|
||||||
first_name: string;
|
first_name: string
|
||||||
is_entity: boolean;
|
is_entity: boolean
|
||||||
is_partner: boolean;
|
is_partner: boolean
|
||||||
is_root: boolean;
|
is_root: boolean
|
||||||
last_name: string;
|
last_name: string
|
||||||
metadata: {
|
metadata: {
|
||||||
id: number;
|
id: number
|
||||||
metadata: string;
|
metadata: string
|
||||||
type: string;
|
type: string
|
||||||
}[];
|
}[]
|
||||||
partner_code: string;
|
partner_code: string
|
||||||
phone_number: string;
|
phone_number: string
|
||||||
taxes_country_iso: string;
|
taxes_country_iso: string
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,26 @@ const REGEX_EMAIL = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i,
|
|||||||
// Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character
|
// Minimum eight characters, at least one uppercase letter, one lowercase letter, one number and one special character
|
||||||
// REGEX_PASSWORD = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
|
// REGEX_PASSWORD = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
|
||||||
// REGEX_PASSWORD = /^(?=.*[A-Za-z])(?=.*\d)(?=.*\W)[A-Za-z\d^\S]{8,}$/,
|
// REGEX_PASSWORD = /^(?=.*[A-Za-z])(?=.*\d)(?=.*\W)[A-Za-z\d^\S]{8,}$/,
|
||||||
REGEX_PASSWORD = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W)[A-Za-z\d^\S]{8,}$/),
|
REGEX_PASSWORD = new RegExp(
|
||||||
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W)[A-Za-z\d^\S]{8,}$/,
|
||||||
|
),
|
||||||
REGEX_CODE = /.{6}/,
|
REGEX_CODE = /.{6}/,
|
||||||
// REGEX_PHONE = /^\+?[1-9][0-9]{7,14}$/,
|
// REGEX_PHONE = /^\+?[1-9][0-9]{7,14}$/,
|
||||||
REGEX_PHONE = new RegExp(/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im),
|
REGEX_PHONE = new RegExp(
|
||||||
|
/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im,
|
||||||
|
),
|
||||||
REGEX_DATE = /^[+-]?\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/,
|
REGEX_DATE = /^[+-]?\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/,
|
||||||
|
|
||||||
// Only numbers
|
// Only numbers
|
||||||
REGEX_ONLYNUMBERS = /^[0-9]*$/,
|
REGEX_ONLYNUMBERS = /^[0-9]*$/,
|
||||||
|
|
||||||
// Number (price)
|
// Number (price)
|
||||||
REGEX_NUMBER = /^(?!0*[.,]0*$|[.,]0*$|0*$)\d+[,.]?\d{0,2}$/,
|
REGEX_NUMBER = /^(?!0*[.,]0*$|[.,]0*$|0*$)\d+[,.]?\d{0,2}$/,
|
||||||
REGEX_NUMBER_WITH_ZERO = /^[0-9]{1,10}([.][0-9]{1,2})?$/,
|
REGEX_NUMBER_WITH_ZERO = /^[0-9]{1,10}([.][0-9]{1,2})?$/,
|
||||||
REGEX_URL = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/
|
REGEX_URL
|
||||||
|
= /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/
|
||||||
|
|
||||||
// URL
|
// URL
|
||||||
|
|
||||||
// REGEX_URL = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/
|
// REGEX_URL = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/
|
||||||
|
|
||||||
export {
|
export {
|
||||||
REGEX_EMAIL,
|
REGEX_EMAIL,
|
||||||
@ -31,4 +34,3 @@ export {
|
|||||||
REGEX_DATE,
|
REGEX_DATE,
|
||||||
REGEX_URL,
|
REGEX_URL,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
const validation = function (item:string, min:number, max:number, regEx = /.*/) {
|
const validation = function (
|
||||||
if (
|
item: string,
|
||||||
item == undefined ||
|
min: number,
|
||||||
item.length < min ||
|
max: number,
|
||||||
item.length > max ||
|
regEx = /.*/,
|
||||||
!regEx.test(item)
|
) {
|
||||||
) return false;
|
if (
|
||||||
else return true;
|
item == undefined
|
||||||
};
|
|| item.length < min
|
||||||
|
|| item.length > max
|
||||||
|
|| !regEx.test(item)
|
||||||
export { validation };
|
)
|
||||||
|
return false
|
||||||
|
else return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export { validation }
|
||||||
|
Reference in New Issue
Block a user