Features: Empty out storefront
This commit is contained in:
parent
7cf133dccf
commit
9129211f76
103 changed files with 0 additions and 7803 deletions
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>%EVIBES_PROJECT_NAME%</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
4105
storefront/package-lock.json
generated
4105
storefront/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"name": "evibes-frontend",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.13.8",
|
||||
"@vue/apollo-composable": "^4.2.2",
|
||||
"@vueuse/core": "^13.2.0",
|
||||
"element-plus": "^2.9.11",
|
||||
"graphql": "^16.11.0",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"pinia": "^3.0.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^11.1.4",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"sass": "^1.83.0",
|
||||
"sass-loader": "^16.0.4",
|
||||
"vite": "^6.2.4",
|
||||
"vite-plugin-vue-devtools": "^7.7.2"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
|
|
@ -1,39 +0,0 @@
|
|||
<script setup>
|
||||
import { RouterView } from 'vue-router'
|
||||
import {onMounted} from "vue";
|
||||
import {useRefresh} from "@/composables/auth";
|
||||
import {useCompanyInfo} from "@/composables/company";
|
||||
import {useLanguages} from "@/composables/languages/index.js";
|
||||
import BaseHeader from "@/components/base/base-header.vue";
|
||||
import BaseFooter from "@/components/base/base-footer.vue";
|
||||
|
||||
const { refresh } = useRefresh();
|
||||
const { getCompanyInfo } = useCompanyInfo();
|
||||
const { getLanguages } = useLanguages();
|
||||
|
||||
onMounted(async () => {
|
||||
await refresh()
|
||||
await getCompanyInfo()
|
||||
await getLanguages()
|
||||
|
||||
setInterval(async () => {
|
||||
await refresh()
|
||||
}, 600000)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="main" id="top">
|
||||
<base-header />
|
||||
<RouterView v-slot="{ Component }">
|
||||
<Transition name="opacity" mode="out-in">
|
||||
<component :is="Component" />
|
||||
</Transition>
|
||||
</RouterView>
|
||||
<base-footer />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
import { setContext } from '@apollo/client/link/context'
|
||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY} from "@/config/index.js";
|
||||
import {computed} from "vue";
|
||||
import { useAuthStore } from "@/stores/auth.js";
|
||||
|
||||
const httpLink = createHttpLink({
|
||||
uri: 'https://api.' + import.meta.env.EVIBES_BASE_DOMAIN + '/graphql/',
|
||||
});
|
||||
|
||||
const userLocale = computed(() => {
|
||||
return localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY)
|
||||
});
|
||||
|
||||
export const createApolloClient = () => {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const accessToken = computed(() => {
|
||||
return authStore.accessToken
|
||||
})
|
||||
|
||||
const authLink = setContext((_, { headers }) => {
|
||||
const baseHeaders = {
|
||||
...headers,
|
||||
"Accept-language": userLocale.value ? userLocale.value : DEFAULT_LOCALE,
|
||||
};
|
||||
|
||||
if (accessToken.value) {
|
||||
baseHeaders["X-EVIBES-AUTH"] = `Bearer ${accessToken.value}`;
|
||||
}
|
||||
|
||||
return { headers: baseHeaders };
|
||||
})
|
||||
|
||||
return new ApolloClient({
|
||||
link: authLink.concat(httpLink),
|
||||
cache: new InMemoryCache(),
|
||||
defaultOptions: {
|
||||
watchQuery: {
|
||||
fetchPolicy: 'cache-and-network',
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<svg width="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M19.7071 5.70711C20.0976 5.31658 20.0976 4.68342 19.7071 4.29289C19.3166 3.90237 18.6834 3.90237 18.2929 4.29289L14.032 8.55382C13.4365 8.20193 12.7418 8 12 8C9.79086 8 8 9.79086 8 12C8 12.7418 8.20193 13.4365 8.55382 14.032L4.29289 18.2929C3.90237 18.6834 3.90237 19.3166 4.29289 19.7071C4.68342 20.0976 5.31658 20.0976 5.70711 19.7071L9.96803 15.4462C10.5635 15.7981 11.2582 16 12 16C14.2091 16 16 14.2091 16 12C16 11.2582 15.7981 10.5635 15.4462 9.96803L19.7071 5.70711ZM12.518 10.0677C12.3528 10.0236 12.1792 10 12 10C10.8954 10 10 10.8954 10 12C10 12.1792 10.0236 12.3528 10.0677 12.518L12.518 10.0677ZM11.482 13.9323L13.9323 11.482C13.9764 11.6472 14 11.8208 14 12C14 13.1046 13.1046 14 12 14C11.8208 14 11.6472 13.9764 11.482 13.9323ZM15.7651 4.8207C14.6287 4.32049 13.3675 4 12 4C9.14754 4 6.75717 5.39462 4.99812 6.90595C3.23268 8.42276 2.00757 10.1376 1.46387 10.9698C1.05306 11.5985 1.05306 12.4015 1.46387 13.0302C1.92276 13.7326 2.86706 15.0637 4.21194 16.3739L5.62626 14.9596C4.4555 13.8229 3.61144 12.6531 3.18002 12C3.6904 11.2274 4.77832 9.73158 6.30147 8.42294C7.87402 7.07185 9.81574 6 12 6C12.7719 6 13.5135 6.13385 14.2193 6.36658L15.7651 4.8207ZM12 18C11.2282 18 10.4866 17.8661 9.78083 17.6334L8.23496 19.1793C9.37136 19.6795 10.6326 20 12 20C14.8525 20 17.2429 18.6054 19.002 17.0941C20.7674 15.5772 21.9925 13.8624 22.5362 13.0302C22.947 12.4015 22.947 11.5985 22.5362 10.9698C22.0773 10.2674 21.133 8.93627 19.7881 7.62611L18.3738 9.04043C19.5446 10.1771 20.3887 11.3469 20.8201 12C20.3097 12.7726 19.2218 14.2684 17.6986 15.5771C16.1261 16.9282 14.1843 18 12 18Z"
|
||||
fill="#000000"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="24" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill="none">
|
||||
<path fill="#000000" fill-rule="evenodd" d="M3.415 10.242c-.067-.086-.13-.167-.186-.242a16.806 16.806 0 011.803-2.025C6.429 6.648 8.187 5.5 10 5.5c1.813 0 3.57 1.148 4.968 2.475A16.816 16.816 0 0116.771 10a16.9 16.9 0 01-1.803 2.025C13.57 13.352 11.813 14.5 10 14.5c-1.813 0-3.57-1.148-4.968-2.475a16.799 16.799 0 01-1.617-1.783zm15.423-.788L18 10l.838.546-.002.003-.003.004-.01.016-.037.054a17.123 17.123 0 01-.628.854 18.805 18.805 0 01-1.812 1.998C14.848 14.898 12.606 16.5 10 16.5s-4.848-1.602-6.346-3.025a18.806 18.806 0 01-2.44-2.852 6.01 6.01 0 01-.037-.054l-.01-.016-.003-.004-.001-.002c0-.001-.001-.001.837-.547l-.838-.546.002-.003.003-.004.01-.016a6.84 6.84 0 01.17-.245 18.804 18.804 0 012.308-2.66C5.151 5.1 7.394 3.499 10 3.499s4.848 1.602 6.346 3.025a18.803 18.803 0 012.44 2.852l.037.054.01.016.003.004.001.002zM18 10l.838-.546.355.546-.355.546L18 10zM1.162 9.454L2 10l-.838.546L.807 10l.355-.546zM9 10a1 1 0 112 0 1 1 0 01-2 0zm1-3a3 3 0 100 6 3 3 0 000-6z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1 KiB |
|
|
@ -1,7 +0,0 @@
|
|||
@mixin hover {
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
$font_default: '', sans-serif;
|
||||
|
||||
$white: #ffffff;
|
||||
$black: #000000;
|
||||
$error: #f13838;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
@use "modules/normalize";
|
||||
@use "modules/transitions";
|
||||
@use "global/mixins";
|
||||
@use "global/variables";
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
@use "../global/variables" as *;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
overflow-x: hidden;
|
||||
font-family: $font_default;
|
||||
}
|
||||
|
||||
#app {
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input, textarea, button {
|
||||
font-family: $font_default;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1500px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 1680px) {
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
.container {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
.opacity-enter-active,
|
||||
.opacity-leave-active {
|
||||
transition: 0.3s ease all;
|
||||
}
|
||||
.opacity-enter-from,
|
||||
.opacity-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fromTop-enter-active,
|
||||
.fromTop-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.fromTop-enter-from,
|
||||
.fromTop-leave-to {
|
||||
transform: translateY(-3rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fromLeft-enter-active,
|
||||
.fromLeft-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.fromLeft-enter-from,
|
||||
.fromLeft-leave-to {
|
||||
transform: translateX(-3rem);
|
||||
opacity: 0;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<template>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="footer_wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<template>
|
||||
<header class="header">
|
||||
<div class="container">
|
||||
<div class="header__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted} from "vue";
|
||||
import {useCategories} from "@/composables/categories";
|
||||
|
||||
const { categories, loading, getCategories } = useCategories();
|
||||
|
||||
onMounted(async () => {
|
||||
await getCategories()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleContactUs()" class="form">
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.name')"
|
||||
:rules="[required]"
|
||||
v-model="name"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'email'"
|
||||
:placeholder="t('fields.email')"
|
||||
:rules="[required]"
|
||||
v-model="email"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.phoneNumber')"
|
||||
:rules="[required]"
|
||||
v-model="phoneNumber"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.subject')"
|
||||
:rules="[required]"
|
||||
v-model="subject"
|
||||
/>
|
||||
<ui-textarea
|
||||
:placeholder="t('fields.message')"
|
||||
:rules="[required]"
|
||||
v-model="message"
|
||||
/>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.send') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {required} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import UiTextarea from "@/components/ui/ui-textarea.vue";
|
||||
import {useContactUs} from "@/composables/contact/index.js";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const name = ref('')
|
||||
const email = ref('')
|
||||
const phoneNumber = ref('')
|
||||
const subject = ref('')
|
||||
const message = ref('')
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
required(name.value) === true &&
|
||||
required(email.value) === true &&
|
||||
required(phoneNumber.value) === true &&
|
||||
required(subject.value) === true &&
|
||||
required(message.value) === true
|
||||
)
|
||||
})
|
||||
|
||||
const { contactUs, loading } = useContactUs();
|
||||
|
||||
async function handleContactUs() {
|
||||
await contactUs(
|
||||
name.value,
|
||||
email.value,
|
||||
phoneNumber.value,
|
||||
subject.value,
|
||||
message.value,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleDeposit()" class="form">
|
||||
<div class="form__box">
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="''"
|
||||
v-model="amount"
|
||||
:numberOnly="true"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="''"
|
||||
v-model="amount"
|
||||
:numberOnly="true"
|
||||
/>
|
||||
</div>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.topUp') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import {computed, ref} from "vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useDeposit} from "@/composables/user/useDeposit.js";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const amount = ref('')
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
amount.value >= 5 && amount.value <= 500
|
||||
)
|
||||
})
|
||||
|
||||
const onlyNumbersKeypress = (event) => {
|
||||
if (!/\d/.test(event.key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const { deposit, loading } = useDeposit();
|
||||
|
||||
async function handleDeposit() {
|
||||
await deposit(amount.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
&__box {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleLogin()" class="form">
|
||||
<ui-input
|
||||
:type="'email'"
|
||||
:placeholder="t('fields.email')"
|
||||
:rules="[isEmail]"
|
||||
v-model="email"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.password')"
|
||||
:rules="[required]"
|
||||
v-model="password"
|
||||
/>
|
||||
<ui-checkbox
|
||||
v-model="isStayLogin"
|
||||
>
|
||||
{{ t('checkboxes.remember') }}
|
||||
</ui-checkbox>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.signIn') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {isEmail, required} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import UiCheckbox from "@/components/ui/ui-checkbox.vue";
|
||||
import {useLogin} from "@/composables/auth";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const isStayLogin = ref(false)
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
isEmail(email.value) === true &&
|
||||
required(password.value) === true
|
||||
)
|
||||
})
|
||||
|
||||
const { login, loading } = useLogin();
|
||||
|
||||
async function handleLogin() {
|
||||
await login(email.value, password.value, isStayLogin.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleReset()" class="form">
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.newPassword')"
|
||||
:rules="[isPasswordValid]"
|
||||
v-model="password"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.confirmNewPassword')"
|
||||
:rules="[compareStrings]"
|
||||
v-model="confirmPassword"
|
||||
/>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.save') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {isPasswordValid,} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import {useNewPassword} from "@/composables/auth";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const password = ref('')
|
||||
const confirmPassword = ref('')
|
||||
|
||||
const compareStrings = (v) => {
|
||||
if (v === password.value) return true
|
||||
return t('errors.compare')
|
||||
}
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
isPasswordValid(password.value) === true &&
|
||||
compareStrings(confirmPassword.value) === true
|
||||
)
|
||||
})
|
||||
|
||||
const { newPassword, loading } = useNewPassword();
|
||||
|
||||
async function handleReset() {
|
||||
await newPassword(
|
||||
password.value,
|
||||
confirmPassword.value,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleRegister()" class="form">
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.firstName')"
|
||||
:rules="[required]"
|
||||
v-model="firstName"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.lastName')"
|
||||
:rules="[required]"
|
||||
v-model="lastName"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.phoneNumber')"
|
||||
:rules="[required]"
|
||||
v-model="phoneNumber"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'email'"
|
||||
:placeholder="t('fields.email')"
|
||||
:rules="[isEmail]"
|
||||
v-model="email"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.password')"
|
||||
:rules="[isPasswordValid]"
|
||||
v-model="password"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.confirmPassword')"
|
||||
:rules="[compareStrings]"
|
||||
v-model="confirmPassword"
|
||||
/>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.signUp') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {isEmail, isPasswordValid, required} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import {useRegister} from "@/composables/auth/index.js";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const firstName = ref('')
|
||||
const lastName = ref('')
|
||||
const phoneNumber = ref('')
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const confirmPassword = ref('')
|
||||
|
||||
const compareStrings = (v) => {
|
||||
if (v === password.value) return true
|
||||
return t('errors.compare')
|
||||
}
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
required(firstName.value) === true &&
|
||||
required(lastName.value) === true &&
|
||||
required(phoneNumber.value) === true &&
|
||||
isEmail(email.value) === true &&
|
||||
isPasswordValid(password.value) === true &&
|
||||
compareStrings(confirmPassword.value) === true
|
||||
)
|
||||
})
|
||||
|
||||
const { register, loading } = useRegister();
|
||||
|
||||
async function handleRegister() {
|
||||
await register(
|
||||
firstName.value,
|
||||
lastName.value,
|
||||
phoneNumber.value,
|
||||
email.value,
|
||||
password.value,
|
||||
confirmPassword.value
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<template>
|
||||
<form @submit.prevent="handleReset()" class="form">
|
||||
<ui-input
|
||||
:type="'email'"
|
||||
:placeholder="t('fields.email')"
|
||||
:rules="[isEmail]"
|
||||
v-model="email"
|
||||
/>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isDisabled="!isFormValid"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.sendLink') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {isEmail} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import {usePasswordReset} from "@/composables/auth";
|
||||
|
||||
const {t} = useI18n()
|
||||
|
||||
const email = ref('')
|
||||
|
||||
const isFormValid = computed(() => {
|
||||
return (
|
||||
isEmail(email.value) === true
|
||||
)
|
||||
})
|
||||
|
||||
const { resetPassword, loading } = usePasswordReset();
|
||||
|
||||
async function handleReset() {
|
||||
await resetPassword(email.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
<template>
|
||||
<form class="form" @submit.prevent="handleUpdate()">
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.firstName')"
|
||||
:rules="[required]"
|
||||
v-model="firstName"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.lastName')"
|
||||
:rules="[required]"
|
||||
v-model="lastName"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'email'"
|
||||
:placeholder="t('fields.email')"
|
||||
:rules="[isEmail]"
|
||||
v-model="email"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'text'"
|
||||
:placeholder="t('fields.phoneNumber')"
|
||||
:rules="[required]"
|
||||
v-model="phoneNumber"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.newPassword')"
|
||||
:rules="[isPasswordValid]"
|
||||
v-model="password"
|
||||
/>
|
||||
<ui-input
|
||||
:type="'password'"
|
||||
:placeholder="t('fields.confirmNewPassword')"
|
||||
:rules="[compareStrings]"
|
||||
v-model="confirmPassword"
|
||||
/>
|
||||
<ui-button
|
||||
class="form__button"
|
||||
:isLoading="loading"
|
||||
>
|
||||
{{ t('buttons.save') }}
|
||||
</ui-button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {isEmail, isPasswordValid, required} from "@/core/rules/textFieldRules.js";
|
||||
import {computed, ref, watchEffect} from "vue";
|
||||
import UiInput from "@/components/ui/ui-input.vue";
|
||||
import UiButton from "@/components/ui/ui-button.vue";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import {useUserUpdating} from "@/composables/user";
|
||||
|
||||
const {t} = useI18n()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const userFirstName = computed(() => authStore.user?.firstName)
|
||||
const userLastName = computed(() => authStore.user?.lastName)
|
||||
const userEmail = computed(() => authStore.user?.email)
|
||||
const userPhoneNumber = computed(() => authStore.user?.phoneNumber)
|
||||
|
||||
const firstName = ref('')
|
||||
const lastName = ref('')
|
||||
const email = ref('')
|
||||
const phoneNumber = ref('')
|
||||
const password = ref('')
|
||||
const confirmPassword = ref('')
|
||||
|
||||
const compareStrings = (v) => {
|
||||
if (v === password.value) return true
|
||||
return t('errors.compare')
|
||||
}
|
||||
|
||||
const { updateUser, loading } = useUserUpdating();
|
||||
|
||||
watchEffect(() => {
|
||||
firstName.value = userFirstName.value || ''
|
||||
lastName.value = userLastName.value || ''
|
||||
email.value = userEmail.value || ''
|
||||
phoneNumber.value = userPhoneNumber.value || ''
|
||||
})
|
||||
|
||||
async function handleUpdate() {
|
||||
await updateUser(
|
||||
firstName.value,
|
||||
lastName.value,
|
||||
email.value,
|
||||
phoneNumber.value,
|
||||
password.value,
|
||||
confirmPassword.value,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<template>
|
||||
<button
|
||||
class="button"
|
||||
:disabled="isDisabled"
|
||||
:class="[{active: isLoading}]"
|
||||
type="submit"
|
||||
>
|
||||
<ui-loader class="button__loader" v-if="isLoading" />
|
||||
<slot v-else />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import UiLoader from "@/components/ui/ui-loader.vue";
|
||||
|
||||
const props = defineProps({
|
||||
isDisabled: Boolean,
|
||||
isLoading: Boolean
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.button {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: 0.2s;
|
||||
border: 1px solid $black;
|
||||
background-color: $white;
|
||||
padding-block: 5px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
z-index: 1;
|
||||
|
||||
color: $black;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
|
||||
&:hover, &.active {
|
||||
background-color: $black;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: rgba($black, 0.5);
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&:disabled:hover, &.active {
|
||||
background-color: rgba($black, 0.5);
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&__loader {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<input
|
||||
:id="'checkbox' + id"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
:value="modelValue"
|
||||
@input="onInput"
|
||||
:checked="modelValue"
|
||||
>
|
||||
<label :for="'checkbox' + id" class="checkbox__label">
|
||||
<slot />
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const $emit = defineEmits()
|
||||
const props = defineProps({
|
||||
id: [Number, String],
|
||||
modelValue: Boolean
|
||||
})
|
||||
|
||||
const onInput = (event) => {
|
||||
$emit('update:modelValue', event.target.checked);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.checkbox {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
|
||||
&__label {
|
||||
color: #2B2B2B;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.12px;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox + .checkbox__label::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
border: 1px solid $black;
|
||||
margin-right: 10px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 50% 50%;
|
||||
}
|
||||
|
||||
.checkbox:checked + .checkbox__label::before {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2f6b4f' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
.checkbox + .checkbox__label {
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<div class="block__inner">
|
||||
<input
|
||||
:placeholder="placeholder"
|
||||
:type="isPasswordVisible"
|
||||
:value="modelValue"
|
||||
@input="onInput"
|
||||
@keydown="numberOnly ? onlyNumbersKeydown($event) : null"
|
||||
class="block__input"
|
||||
>
|
||||
<button
|
||||
@click.prevent="setPasswordVisible"
|
||||
class="block__eyes"
|
||||
v-if="type === 'password'"
|
||||
>
|
||||
<img v-if="isPasswordVisible === 'password'" src="@icons/eyeClosed.svg" alt="eye" loading="lazy">
|
||||
<img v-else src="@icons/eyeOpened.svg" alt="eye" loading="lazy">
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="!validate" class="block__error">{{ errorMessage }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
|
||||
const $emit = defineEmits()
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
placeholder: String,
|
||||
isError: Boolean,
|
||||
error: String,
|
||||
modelValue: [String, Number],
|
||||
rules: Array,
|
||||
numberOnly: Boolean
|
||||
})
|
||||
|
||||
const isPasswordVisible = ref(props.type)
|
||||
const setPasswordVisible = () => {
|
||||
if (isPasswordVisible.value === 'password') {
|
||||
isPasswordVisible.value = 'text'
|
||||
return
|
||||
}
|
||||
isPasswordVisible.value = 'password'
|
||||
}
|
||||
|
||||
const onlyNumbersKeydown = (event) => {
|
||||
if (!/^\d$/.test(event.key) &&
|
||||
!['ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Tab', 'Home', 'End'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
const validate = ref(true)
|
||||
const errorMessage = ref('')
|
||||
const onInput = (e) => {
|
||||
let value = e.target.value;
|
||||
|
||||
if (props.numberOnly) {
|
||||
const newValue = value.replace(/\D/g, '');
|
||||
if (newValue !== value) {
|
||||
e.target.value = newValue;
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
let result = true
|
||||
|
||||
props.rules?.forEach((rule) => {
|
||||
result = rule((e.target).value)
|
||||
|
||||
if (result !== true) {
|
||||
errorMessage.value = String(result)
|
||||
result = false
|
||||
}
|
||||
})
|
||||
|
||||
validate.value = result
|
||||
|
||||
return $emit('update:modelValue', (e.target).value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.block {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
|
||||
&__inner {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__input {
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid $black;
|
||||
background-color: $white;
|
||||
|
||||
color: #1f1f1f;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
|
||||
&::placeholder {
|
||||
color: #2B2B2B;
|
||||
}
|
||||
}
|
||||
|
||||
&__eyes {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: transparent;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
&__error {
|
||||
color: $error;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
animation: fadeInUp 0.3s ease;
|
||||
|
||||
@keyframes fadeInUp {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
<template>
|
||||
<div class="loader">
|
||||
<li class="loader__dots" id="dot-1"></li>
|
||||
<li class="loader__dots" id="dot-2"></li>
|
||||
<li class="loader__dots" id="dot-3"></li>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.loader {
|
||||
display: flex;
|
||||
gap: 0.6em;
|
||||
list-style: none;
|
||||
|
||||
&__dots {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
#dot-1 {
|
||||
animation: loader-1 0.6s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes loader-1 {
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.3em);
|
||||
}
|
||||
}
|
||||
|
||||
#dot-2 {
|
||||
animation: loader-2 0.6s 0.3s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes loader-2 {
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.3em);
|
||||
}
|
||||
}
|
||||
|
||||
#dot-3 {
|
||||
animation: loader-3 0.6s 0.6s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes loader-3 {
|
||||
50% {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.3em);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<textarea
|
||||
:placeholder="placeholder"
|
||||
:value="modelValue"
|
||||
@input="onInput"
|
||||
class="block__textarea"
|
||||
/>
|
||||
<p v-if="!validate" class="block__error">{{ errorMessage }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
|
||||
const $emit = defineEmits()
|
||||
const props = defineProps({
|
||||
placeholder: String,
|
||||
isError: Boolean,
|
||||
error: String,
|
||||
modelValue: [String, Number],
|
||||
rules: Array
|
||||
})
|
||||
|
||||
const validate = ref(true)
|
||||
const errorMessage = ref('')
|
||||
const onInput = (e) => {
|
||||
let result = true
|
||||
|
||||
props.rules?.forEach((rule) => {
|
||||
result = rule((e.target).value)
|
||||
|
||||
if (result !== true) {
|
||||
errorMessage.value = String(result)
|
||||
result = false
|
||||
}
|
||||
})
|
||||
|
||||
validate.value = result
|
||||
|
||||
return $emit('update:modelValue', (e.target).value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.block {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
|
||||
&__textarea {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
resize: none;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid $black;
|
||||
background-color: $white;
|
||||
|
||||
color: #1f1f1f;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
|
||||
&::placeholder {
|
||||
color: #2B2B2B;
|
||||
}
|
||||
}
|
||||
|
||||
&__error {
|
||||
color: $error;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
animation: fadeInUp 0.3s ease;
|
||||
|
||||
@keyframes fadeInUp {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
export * from './useLogin';
|
||||
export * from './useLogout';
|
||||
export * from './useNewPassword';
|
||||
export * from './usePasswordReset';
|
||||
export * from './useRefresh';
|
||||
export * from './useRegister';
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {LOGIN} from "@/graphql/mutations/auth.js";
|
||||
import {ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import translations from "@/core/helpers/translations.js";
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
LOCALE_STORAGE_LOCALE_KEY,
|
||||
LOCALE_STORAGE_REFRESH_KEY,
|
||||
LOCALE_STORAGE_STAY_LOGIN_KEY
|
||||
} from "@/config/index.js";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {usePendingOrder} from "@/composables/orders";
|
||||
import {useWishlist} from "@/composables/wishlist";
|
||||
|
||||
export function useLogin() {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const authStore = useAuthStore()
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: loginMutation } = useMutation(LOGIN);
|
||||
|
||||
const { getPendingOrder } = usePendingOrder();
|
||||
const { getWishlist } = useWishlist();
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function login(
|
||||
email,
|
||||
password,
|
||||
isStayLogin
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await loginMutation({
|
||||
email,
|
||||
password
|
||||
});
|
||||
|
||||
if (isStayLogin) {
|
||||
localStorage.setItem(LOCALE_STORAGE_STAY_LOGIN_KEY, 'remember')
|
||||
}
|
||||
|
||||
if (response.data?.obtainJwtToken) {
|
||||
authStore.setUser({
|
||||
user: response.data.obtainJwtToken.user,
|
||||
accessToken: response.data.obtainJwtToken.accessToken
|
||||
});
|
||||
|
||||
localStorage.setItem(LOCALE_STORAGE_REFRESH_KEY, response.data.obtainJwtToken.refreshToken)
|
||||
|
||||
ElNotification({
|
||||
message: t('popup.success.login'),
|
||||
type: 'success'
|
||||
})
|
||||
|
||||
await router.push({
|
||||
name: 'home',
|
||||
params: {
|
||||
locale: localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE
|
||||
}
|
||||
})
|
||||
|
||||
if (response.data.obtainJwtToken.user.language !== translations.currentLocale) {
|
||||
translations.switchLanguage(response.data.obtainJwtToken.user.language, router, route)
|
||||
}
|
||||
|
||||
await getPendingOrder(response.data.obtainJwtToken.user.email);
|
||||
await getWishlist();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useLogin error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
login,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
LOCALE_STORAGE_LOCALE_KEY,
|
||||
LOCALE_STORAGE_REFRESH_KEY,
|
||||
LOCALE_STORAGE_STAY_LOGIN_KEY
|
||||
} from "@/config/index.js";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
export function useLogout() {
|
||||
const authStore = useAuthStore()
|
||||
const router = useRouter()
|
||||
|
||||
async function logout() {
|
||||
authStore.setUser({
|
||||
user: null,
|
||||
accessToken: null
|
||||
})
|
||||
|
||||
localStorage.removeItem(LOCALE_STORAGE_REFRESH_KEY)
|
||||
localStorage.removeItem(LOCALE_STORAGE_STAY_LOGIN_KEY)
|
||||
|
||||
await router.push({
|
||||
name: 'home',
|
||||
params: {
|
||||
locale: localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
logout
|
||||
};
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {NEW_PASSWORD} from "@/graphql/mutations/auth.js";
|
||||
import {computed, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY} from "@/config/index.js";
|
||||
|
||||
export function useNewPassword() {
|
||||
const {t} = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const { mutate: newPasswordMutation } = useMutation(NEW_PASSWORD);
|
||||
|
||||
const token = computed(() =>
|
||||
route.query.token ? (route.query.token) : undefined,
|
||||
);
|
||||
const uid = computed(() =>
|
||||
route.query.uid ? (route.query.uid) : undefined,
|
||||
);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function newPassword(
|
||||
password,
|
||||
confirmPassword
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await newPasswordMutation({
|
||||
password,
|
||||
confirmPassword,
|
||||
token: token.value,
|
||||
uid: uid.value
|
||||
});
|
||||
|
||||
if (response.data?.confirmResetPassword.success) {
|
||||
ElNotification({
|
||||
message: t('popup.success.newPassword'),
|
||||
type: 'success'
|
||||
})
|
||||
|
||||
await router.push({
|
||||
name: 'home',
|
||||
params: {
|
||||
locale: localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useNewPassword error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
newPassword,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {RESET_PASSWORD} from "@/graphql/mutations/auth.js";
|
||||
import {ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
|
||||
export function usePasswordReset() {
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: resetPasswordMutation } = useMutation(RESET_PASSWORD);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function resetPassword(
|
||||
email
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await resetPasswordMutation({
|
||||
email
|
||||
});
|
||||
|
||||
if (response.data?.resetPassword.success) {
|
||||
ElNotification({
|
||||
message: t('popup.success.reset'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("usePasswordReset error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
resetPassword,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {REFRESH} from "@/graphql/mutations/auth.js";
|
||||
import {computed, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import {LOCALE_STORAGE_REFRESH_KEY} from "@/config/index.js";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import translations from "@/core/helpers/translations.js";
|
||||
import {usePendingOrder} from "@/composables/orders";
|
||||
import {useWishlist} from "@/composables/wishlist";
|
||||
|
||||
export function useRefresh() {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const authStore = useAuthStore()
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: refreshMutation } = useMutation(REFRESH);
|
||||
|
||||
const { getPendingOrder } = usePendingOrder();
|
||||
const { getWishlist } = useWishlist();
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function refresh() {
|
||||
loading.value = true;
|
||||
|
||||
const refreshToken = computed(() => localStorage.getItem(LOCALE_STORAGE_REFRESH_KEY))
|
||||
|
||||
if (!refreshToken.value) return
|
||||
|
||||
try {
|
||||
const response = await refreshMutation({
|
||||
refreshToken: refreshToken.value
|
||||
});
|
||||
|
||||
if (response.data?.refreshJwtToken) {
|
||||
authStore.setUser({
|
||||
user: response.data.refreshJwtToken.user,
|
||||
accessToken: response.data.refreshJwtToken.accessToken
|
||||
})
|
||||
|
||||
if (response.data.refreshJwtToken.user.language !== translations.currentLocale) {
|
||||
translations.switchLanguage(response.data.refreshJwtToken.user.language, router, route)
|
||||
}
|
||||
|
||||
localStorage.setItem(LOCALE_STORAGE_REFRESH_KEY, response.data.refreshJwtToken.refreshToken)
|
||||
|
||||
await getPendingOrder(response.data.refreshJwtToken.user.email);
|
||||
await getWishlist();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useRefresh error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
refresh,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {REGISTER} from "@/graphql/mutations/auth.js";
|
||||
import {h, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMailClient} from "@/composables/utils";
|
||||
|
||||
export function useRegister() {
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: registerMutation } = useMutation(REGISTER);
|
||||
|
||||
const { mailClientUrl, detectMailClient, openMailClient } = useMailClient();
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function register(
|
||||
firstName,
|
||||
lastName,
|
||||
phoneNumber,
|
||||
email,
|
||||
password,
|
||||
confirmPassword
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await registerMutation({
|
||||
firstName,
|
||||
lastName,
|
||||
phoneNumber,
|
||||
email,
|
||||
password,
|
||||
confirmPassword
|
||||
});
|
||||
|
||||
if (response.data?.createUser?.success) {
|
||||
detectMailClient(email);
|
||||
|
||||
ElNotification({
|
||||
message: h('div', [
|
||||
h('p', t('popup.success.register')),
|
||||
mailClientUrl.value ? h(
|
||||
'button',
|
||||
{
|
||||
style: {
|
||||
marginTop: '10px',
|
||||
padding: '6px 12px',
|
||||
backgroundColor: '#000000',
|
||||
color: '#fff',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
onClick: () => {
|
||||
openMailClient()
|
||||
}
|
||||
},
|
||||
t('buttons.goEmail')
|
||||
) : ''
|
||||
]),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useRegister error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
register,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './usePosts'
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import {GET_POST_BY_SLUG} from "@/graphql/queries/blog.js";
|
||||
import {computed} from "vue";
|
||||
|
||||
export function usePostbySlug() {
|
||||
const { result, loading, error, load } = useLazyQuery(GET_POST_BY_SLUG);
|
||||
|
||||
const post = computed(() => result.value?.posts.edges[0].node ?? []);
|
||||
|
||||
if (error.value) {
|
||||
console.error("usePostbySlug error:", error.value);
|
||||
}
|
||||
|
||||
const getPost = (slug) => {
|
||||
return load(null, { slug });
|
||||
};
|
||||
|
||||
return {
|
||||
post,
|
||||
loading,
|
||||
error,
|
||||
getPost
|
||||
};
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import { GET_POSTS } from "@/graphql/queries/blog.js";
|
||||
import {computed} from "vue";
|
||||
|
||||
export function usePosts() {
|
||||
const { result, loading, error, load } = useLazyQuery(GET_POSTS);
|
||||
|
||||
const posts = computed(() => result.value?.posts.edges ?? []);
|
||||
|
||||
if (error.value) {
|
||||
console.error("usePosts error:", error.value);
|
||||
}
|
||||
|
||||
return {
|
||||
posts,
|
||||
loading,
|
||||
error,
|
||||
getPosts: load
|
||||
};
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export * from './useCategories'
|
||||
export * from './useCategorybySlug'
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import {computed} from "vue";
|
||||
import {GET_CATEGORIES} from "@/graphql/queries/categories.js";
|
||||
|
||||
export function useCategories() {
|
||||
const { result, loading, error, load } = useLazyQuery(GET_CATEGORIES);
|
||||
|
||||
const categories = computed(() => result.value?.categories.edges ?? []);
|
||||
|
||||
if (error.value) {
|
||||
console.error("useCategories error:", error.value);
|
||||
}
|
||||
|
||||
return {
|
||||
categories,
|
||||
loading,
|
||||
error,
|
||||
getCategories: load
|
||||
};
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import {computed} from "vue";
|
||||
import {GET_CATEGORY_BY_SLUG} from "@/graphql/queries/categories.js";
|
||||
|
||||
export function usePostbySlug() {
|
||||
const { result, loading, error, load } = useLazyQuery(GET_CATEGORY_BY_SLUG);
|
||||
|
||||
const category = computed(() => result.value?.categories.edges[0].node ?? []);
|
||||
|
||||
if (error.value) {
|
||||
console.error("usePostbySlug error:", error.value);
|
||||
}
|
||||
|
||||
const getCategory = (slug) => {
|
||||
return load(null, { slug });
|
||||
};
|
||||
|
||||
return {
|
||||
category,
|
||||
loading,
|
||||
error,
|
||||
getCategory
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './useCompanyInfo';
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import {useLazyQuery} from "@vue/apollo-composable";
|
||||
import {GET_COMPANY_INFO} from "@/graphql/queries/company.js";
|
||||
import {useCompanyStore} from "@/stores/company.js";
|
||||
import {watchEffect} from "vue";
|
||||
|
||||
export function useCompanyInfo() {
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
const { result, loading, error, load } = useLazyQuery(GET_COMPANY_INFO);
|
||||
|
||||
if (error.value) {
|
||||
console.error("useCompanyInfo error:", error.value);
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (result.value?.parameters) {
|
||||
companyStore.setCompanyInfo(result.value.parameters);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
getCompanyInfo: load
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './useContactUs'
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {CONTACT_US} from "@/graphql/mutations/contact.js";
|
||||
|
||||
export function useContactUs() {
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: contactUsMutation } = useMutation(CONTACT_US);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function contactUs(
|
||||
name,
|
||||
email,
|
||||
phoneNumber,
|
||||
subject,
|
||||
message
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await contactUsMutation({
|
||||
name,
|
||||
email,
|
||||
phoneNumber,
|
||||
subject,
|
||||
message
|
||||
});
|
||||
|
||||
if (response.data?.contactUs.received) {
|
||||
ElNotification({
|
||||
message: t('popup.success.contactUs'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useContactUs error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
contactUs,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export * from './useLanguageSwitch.js'
|
||||
export * from './useLanguages'
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {computed, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import translations from "@/core/helpers/translations.js";
|
||||
import {SWITCH_LANGUAGE} from "@/graphql/mutations/languages.js";
|
||||
|
||||
export function useLanguageSwitch() {
|
||||
const authStore = useAuthStore()
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: languageSwitchMutation } = useMutation(SWITCH_LANGUAGE);
|
||||
|
||||
const accessToken = computed(() => authStore.accessToken)
|
||||
const userUuid = computed(() => authStore.user?.uuid)
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function switchLanguage(
|
||||
locale
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
translations.switchLanguage(locale)
|
||||
if (accessToken.value) {
|
||||
const response = await languageSwitchMutation(
|
||||
userUuid.value,
|
||||
locale
|
||||
);
|
||||
|
||||
if (response.data?.updateUser) {
|
||||
authStore.setUser({
|
||||
user: response.data.updateUser.user,
|
||||
accessToken: accessToken.value
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useLanguageSet error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
switchLanguage,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import {watchEffect} from "vue";
|
||||
import {GET_LANGUAGES} from "@/graphql/queries/languages.js";
|
||||
import {useLanguageStore} from "@/stores/languages.js";
|
||||
import {SUPPORTED_LOCALES} from "@/config/index.js";
|
||||
|
||||
export function useLanguages() {
|
||||
const languageStore = useLanguageStore()
|
||||
|
||||
const { result, loading, error, load } = useLazyQuery(GET_LANGUAGES);
|
||||
|
||||
if (error.value) {
|
||||
console.error("useLanguages error:", error.value);
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (result.value?.languages) {
|
||||
languageStore.setLanguages(
|
||||
result.value.languages.filter((locale) =>
|
||||
SUPPORTED_LOCALES.some(supportedLocale =>
|
||||
supportedLocale.code === locale.code
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
getLanguages: load
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './usePendingOrder';
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {GET_ORDERS} from "@/graphql/queries/orders.js";
|
||||
import {useCartStore} from "@/stores/cart.js";
|
||||
|
||||
export function usePendingOrder() {
|
||||
const cartStore = useCartStore()
|
||||
|
||||
const { mutate: pendingOrderMutation } = useMutation(GET_ORDERS);
|
||||
|
||||
async function getPendingOrder(userEmail) {
|
||||
const response = await pendingOrderMutation({
|
||||
status: "PENDING",
|
||||
userEmail
|
||||
});
|
||||
|
||||
if (!response.errors) {
|
||||
cartStore.setCurrentOrders(response.data.orders.edges[0].node)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getPendingOrder
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './useProducts'
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import { useLazyQuery } from "@vue/apollo-composable";
|
||||
import {computed} from "vue";
|
||||
import {GET_PRODUCT_BY_SLUG} from "@/graphql/queries/products.js";
|
||||
|
||||
export function useProductbySlug() {
|
||||
const { result, loading, error, load } = useLazyQuery(GET_PRODUCT_BY_SLUG);
|
||||
|
||||
const product = computed(() => result.value?.products.edges[0].node ?? []);
|
||||
|
||||
if (error.value) {
|
||||
console.error("useProductbySlug error:", error.value);
|
||||
}
|
||||
|
||||
const getProduct = (slug) => {
|
||||
return load(null, { slug });
|
||||
};
|
||||
|
||||
return {
|
||||
product,
|
||||
loading,
|
||||
error,
|
||||
getProduct
|
||||
};
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
import { ref } from 'vue';
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import {GET_PRODUCTS} from "@/graphql/queries/products.js";
|
||||
|
||||
export function useProducts() {
|
||||
const products = ref([]);
|
||||
const pageInfo = ref([]);
|
||||
const loading = ref(false);
|
||||
|
||||
const getProducts = async (params = {}) => {
|
||||
loading.value = true;
|
||||
|
||||
const defaults = {
|
||||
first: 12
|
||||
};
|
||||
|
||||
const variables = {};
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
variables[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
Object.entries(defaults).forEach(([key, value]) => {
|
||||
if (!(key in variables)) {
|
||||
variables[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const { onResult } = useQuery(GET_PRODUCTS, variables);
|
||||
|
||||
onResult(result => {
|
||||
if (result.data && result.data.products) {
|
||||
products.value = result.data.products.edges;
|
||||
pageInfo.value = result.data.products.pageInfo;
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('useProducts error:', error);
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
products,
|
||||
pageInfo,
|
||||
loading,
|
||||
getProducts
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export * from './useUserUpdating';
|
||||
export * from './useUserActivation';
|
||||
export * from '../languages/useLanguageSwitch.js';
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {DEPOSIT} from "@/graphql/mutations/deposit.js";
|
||||
|
||||
export function useDeposit() {
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: depositMutation } = useMutation(DEPOSIT);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function deposit(
|
||||
amount
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await depositMutation(
|
||||
amount
|
||||
);
|
||||
|
||||
if (response.data?.deposit) {
|
||||
window.open(response.data.deposit.transaction.process.url)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useDeposit error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
deposit,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {computed, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useRoute} from "vue-router";
|
||||
import {ACTIVATE_USER} from "@/graphql/mutations/user.js";
|
||||
|
||||
export function useUserActivation() {
|
||||
const {t} = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const { mutate: userActivationMutation } = useMutation(ACTIVATE_USER);
|
||||
|
||||
const token = computed(() =>
|
||||
route.query.token ? (route.query.token) : undefined,
|
||||
);
|
||||
const uid = computed(() =>
|
||||
route.query.uid ? (route.query.uid) : undefined,
|
||||
);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function activateUser() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await userActivationMutation({
|
||||
token: token.value,
|
||||
uid: uid.value
|
||||
});
|
||||
|
||||
if (response.data?.activateUser) {
|
||||
ElNotification({
|
||||
message: t("popup.activationSuccess"),
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useUserActivation error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
activateUser,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {computed, ref} from "vue";
|
||||
import {ElNotification} from "element-plus";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import translations from "@/core/helpers/translations.js";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {useLogout} from "@/composables/auth";
|
||||
import {UPDATE_USER} from "@/graphql/mutations/user.js";
|
||||
|
||||
export function useUserUpdating() {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const authStore = useAuthStore()
|
||||
const {t} = useI18n();
|
||||
|
||||
const { mutate: userUpdatingMutation } = useMutation(UPDATE_USER);
|
||||
|
||||
const { logout } = useLogout();
|
||||
|
||||
const accessToken = computed(() => authStore.accessToken)
|
||||
const userUuid = computed(() => authStore.user?.uuid)
|
||||
const userEmail = computed(() => authStore.user?.email)
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
async function updateUser(
|
||||
firstName,
|
||||
lastName,
|
||||
email,
|
||||
phoneNumber,
|
||||
password,
|
||||
confirmPassword
|
||||
) {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const fields = {
|
||||
uuid: userUuid.value,
|
||||
firstName,
|
||||
lastName,
|
||||
email,
|
||||
phoneNumber,
|
||||
password,
|
||||
confirmPassword
|
||||
};
|
||||
|
||||
const params = Object.fromEntries(
|
||||
Object.entries(fields).filter(([_, value]) =>
|
||||
value !== undefined && value !== null && value !== ''
|
||||
)
|
||||
);
|
||||
|
||||
// if (('password' in params && !('passwordConfirm' in params)) ||
|
||||
// (!('password' in params) && 'passwordConfirm' in params)) {
|
||||
// ElNotification({
|
||||
// title: t('popup.errors.main'),
|
||||
// message: t('popup.errors.noDataToUpdate'),
|
||||
// type: 'error'
|
||||
// });
|
||||
// }
|
||||
|
||||
if (Object.keys(params).length === 0) {
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: t('popup.errors.noDataToUpdate'),
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
const response = await userUpdatingMutation(
|
||||
params
|
||||
);
|
||||
|
||||
if (response.data?.updateUser) {
|
||||
if (userEmail.value !== email) {
|
||||
await logout()
|
||||
|
||||
ElNotification({
|
||||
message: t("popup.success.confirmEmail"),
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
authStore.setUser({
|
||||
user: response.data.updateUser.user,
|
||||
accessToken: accessToken.value
|
||||
})
|
||||
|
||||
ElNotification({
|
||||
message: t("popup.successUpdate"),
|
||||
type: "success"
|
||||
});
|
||||
|
||||
if (response.data.updateUser.user.language !== translations.currentLocale) {
|
||||
translations.switchLanguage(response.data.updateUser.user.language, router, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useUserUpdating error:", error);
|
||||
|
||||
const errorMessage = error.graphQLErrors?.[0]?.message ||
|
||||
error.message ||
|
||||
t('popup.errors.defaultError');
|
||||
|
||||
ElNotification({
|
||||
title: t('popup.errors.main'),
|
||||
message: errorMessage,
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
updateUser,
|
||||
loading
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './useMainClient';
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
import { ref } from 'vue';
|
||||
|
||||
export function useMailClient() {
|
||||
const mailClientUrl = ref(null);
|
||||
|
||||
const mailClients = {
|
||||
'gmail.com': 'https://mail.google.com/',
|
||||
'outlook.com': 'https://outlook.live.com/',
|
||||
'icloud.com': 'https://www.icloud.com/mail/',
|
||||
'yahoo.com': 'https://mail.yahoo.com/',
|
||||
'mail.ru': 'https://e.mail.ru/inbox/',
|
||||
'yandex.ru': 'https://mail.yandex.ru/',
|
||||
'proton.me': 'https://account.proton.me/mail',
|
||||
'fastmail.com': 'https://fastmail.com/'
|
||||
};
|
||||
|
||||
function detectMailClient(email) {
|
||||
mailClientUrl.value = null;
|
||||
|
||||
if (!email) return;
|
||||
|
||||
const domain = email.split('@')[1];
|
||||
|
||||
Object.entries(mailClients).forEach((el) => {
|
||||
if (domain === el[0]) mailClientUrl.value = el[1];
|
||||
});
|
||||
|
||||
return mailClientUrl.value;
|
||||
}
|
||||
|
||||
function openMailClient() {
|
||||
if (mailClientUrl.value) {
|
||||
window.open(mailClientUrl.value);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
mailClientUrl,
|
||||
detectMailClient,
|
||||
openMailClient
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './useWishlist';
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import {useMutation} from "@vue/apollo-composable";
|
||||
import {GET_WISHLIST} from "@/graphql/queries/wishlist.js";
|
||||
import {useWishlistStore} from "@/stores/wishlist.js";
|
||||
|
||||
export function useWishlist() {
|
||||
const wishlistStore = useWishlistStore()
|
||||
|
||||
const { mutate: wishlistMutation } = useMutation(GET_WISHLIST);
|
||||
|
||||
async function getWishlist() {
|
||||
const response = await wishlistMutation();
|
||||
|
||||
if (!response.errors) {
|
||||
wishlistStore.setWishlist(response.data.wishlists.edges[0].node)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getWishlist
|
||||
};
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// APP
|
||||
|
||||
export const APP_NAME = import.meta.env.EVIBES_PROJECT_NAME
|
||||
|
||||
export const APP_NAME_KEY = APP_NAME.toLowerCase()
|
||||
|
||||
|
||||
|
||||
// LOCALES
|
||||
|
||||
export const SUPPORTED_LOCALES = [
|
||||
{
|
||||
code: 'en-gb',
|
||||
default: true
|
||||
}
|
||||
]
|
||||
|
||||
export const DEFAULT_LOCALE = SUPPORTED_LOCALES.find(locale => locale.default)?.code || 'en-gb'
|
||||
|
||||
|
||||
|
||||
// LOCAL STORAGE
|
||||
|
||||
export const LOCALE_STORAGE_LOCALE_KEY = `${APP_NAME_KEY}-user-locale`;
|
||||
|
||||
export const LOCALE_STORAGE_REFRESH_KEY = `${APP_NAME_KEY}-refresh`;
|
||||
|
||||
export const LOCALE_STORAGE_STAY_LOGIN_KEY = `${APP_NAME_KEY}-remember`;
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
export async function loadLocaleMessages(locale) {
|
||||
try {
|
||||
const messages = await import(`../locales/${locale}.json`)
|
||||
return messages.default || messages
|
||||
} catch (error) {
|
||||
console.error(`Не удалось загрузить локаль: ${locale}`, error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export function getLocaleFilename(localeCode, localesConfig) {
|
||||
const localeInfo = localesConfig.find(locale => locale.code === localeCode)
|
||||
return localeInfo?.file || `${localeCode}.json`
|
||||
}
|
||||
|
||||
export async function loadAllLocaleMessages(supportedLocales) {
|
||||
const messages = {}
|
||||
|
||||
for (const locale of supportedLocales) {
|
||||
try {
|
||||
const localeMessages = await import(`../../locales/${locale.code}.json`)
|
||||
messages[locale.code] = localeMessages.default || localeMessages
|
||||
} catch (error) {
|
||||
console.error(`Не удалось загрузить локаль: ${locale.code}`, error)
|
||||
messages[locale.code] = {}
|
||||
}
|
||||
}
|
||||
|
||||
return messages
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
import i18n from '@/core/plugins/i18n.config';
|
||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES} from "@/config/index.js";
|
||||
|
||||
const translations = {
|
||||
get currentLocale() {
|
||||
return i18n.global.locale.value
|
||||
},
|
||||
|
||||
set currentLocale(newLocale) {
|
||||
i18n.global.locale.value = newLocale
|
||||
},
|
||||
|
||||
switchLanguage(newLocale, router = null, route = null) {
|
||||
translations.currentLocale = newLocale
|
||||
|
||||
document.querySelector('html').setAttribute('lang', newLocale)
|
||||
|
||||
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, newLocale)
|
||||
|
||||
if (router && route) {
|
||||
const newRoute = {
|
||||
...route,
|
||||
params: {
|
||||
...route.params,
|
||||
locale: newLocale
|
||||
}
|
||||
};
|
||||
|
||||
router.push(newRoute).catch(err => {
|
||||
if (err.name !== 'NavigationDuplicated') {
|
||||
console.error('Navigation error:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
isLocaleSupported(locale) {
|
||||
if (locale) {
|
||||
return SUPPORTED_LOCALES.some(supportedLocale => supportedLocale.code === locale);
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
getUserLocale() {
|
||||
const locale =
|
||||
window.navigator.language ||
|
||||
DEFAULT_LOCALE.code
|
||||
|
||||
return {
|
||||
locale: locale,
|
||||
localeNoRegion: locale.split('-')[0]
|
||||
}
|
||||
},
|
||||
|
||||
getPersistedLocale() {
|
||||
const persistedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY)
|
||||
|
||||
if (translations.isLocaleSupported(persistedLocale)) {
|
||||
return persistedLocale
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
||||
guessDefaultLocale() {
|
||||
const userPersistedLocale = translations.getPersistedLocale()
|
||||
if (userPersistedLocale) {
|
||||
return userPersistedLocale
|
||||
}
|
||||
|
||||
const userPreferredLocale = translations.getUserLocale()
|
||||
|
||||
if (translations.isLocaleSupported(userPreferredLocale.locale)) {
|
||||
return userPreferredLocale.locale
|
||||
}
|
||||
|
||||
if (translations.isLocaleSupported(userPreferredLocale.localeNoRegion)) {
|
||||
return userPreferredLocale.localeNoRegion
|
||||
}
|
||||
|
||||
return DEFAULT_LOCALE.code
|
||||
},
|
||||
|
||||
async routeMiddleware(to, _from, next) {
|
||||
const paramLocale = to.params.locale
|
||||
|
||||
if (!translations.isLocaleSupported(paramLocale)) {
|
||||
return next(translations.guessDefaultLocale())
|
||||
}
|
||||
|
||||
await translations.switchLanguage(paramLocale)
|
||||
|
||||
return next()
|
||||
},
|
||||
|
||||
i18nRoute(to) {
|
||||
return {
|
||||
...to,
|
||||
params: {
|
||||
locale: translations.currentLocale,
|
||||
...to.params
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default translations
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import { createI18n } from 'vue-i18n'
|
||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES} from "@/config/index.js";
|
||||
import {loadAllLocaleMessages} from "@/core/helpers/i18n-utils.js";
|
||||
|
||||
const savedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY)
|
||||
const currentLocale = savedLocale && SUPPORTED_LOCALES.some(locale => locale.code === savedLocale)
|
||||
? savedLocale
|
||||
: DEFAULT_LOCALE
|
||||
|
||||
if (!savedLocale) {
|
||||
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, DEFAULT_LOCALE)
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: currentLocale,
|
||||
fallbackLocale: DEFAULT_LOCALE,
|
||||
allowComposition: true,
|
||||
legacy: false,
|
||||
globalInjection: true,
|
||||
messages: {}
|
||||
})
|
||||
|
||||
export async function setupI18n() {
|
||||
const messages = await loadAllLocaleMessages(SUPPORTED_LOCALES)
|
||||
|
||||
Object.keys(messages).forEach(locale => {
|
||||
i18n.global.setLocaleMessage(locale, messages[locale])
|
||||
})
|
||||
|
||||
return i18n
|
||||
}
|
||||
|
||||
export default i18n
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
import i18n from '@/core/plugins/i18n.config'
|
||||
|
||||
const isEmail = (email) => {
|
||||
if (!email) return required(email);
|
||||
if (/.+@.+\..+/.test(email)) return true
|
||||
const { t } = i18n.global
|
||||
return t('errors.mail')
|
||||
}
|
||||
|
||||
const required = (text) => {
|
||||
if (text) return true
|
||||
const { t } = i18n.global
|
||||
return t('errors.required')
|
||||
}
|
||||
|
||||
const isPasswordValid = (pass) => {
|
||||
const { t } = i18n.global
|
||||
|
||||
if (pass.length < 8) {
|
||||
return t('errors.needMin')
|
||||
}
|
||||
|
||||
if (!/[a-z]/.test(pass)) {
|
||||
return t('errors.needLower')
|
||||
}
|
||||
|
||||
if (!/[A-Z]/.test(pass)) {
|
||||
return t('errors.needUpper')
|
||||
}
|
||||
|
||||
if (!/\d/.test(pass)) {
|
||||
return t('errors.needNumber')
|
||||
}
|
||||
|
||||
if (!/[#.?!@$%^&*'()_+=:;"'/>.<,|\-]/.test(pass)) {
|
||||
return t('errors.needSpecial')
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export { required, isEmail, isPasswordValid }
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const CATEGORY_FRAGMENT = gql`
|
||||
fragment Category on CategoryType {
|
||||
name
|
||||
uuid
|
||||
image
|
||||
description
|
||||
slug
|
||||
}
|
||||
`
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const COMPANY_FRAGMENT = gql`
|
||||
fragment Company on ConfigType {
|
||||
companyAddress
|
||||
companyName
|
||||
companyPhoneNumber
|
||||
emailFrom
|
||||
emailHostUser
|
||||
projectName
|
||||
}
|
||||
`
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const LANGUAGES_FRAGMENT = gql`
|
||||
fragment Languages on LanguageType {
|
||||
code
|
||||
flag
|
||||
name
|
||||
}
|
||||
`
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {PRODUCT_FRAGMENT} from "@/graphql/fragments/products.fragment.js";
|
||||
|
||||
export const ORDER_FRAGMENT = gql`
|
||||
fragment Order on OrderType {
|
||||
totalPrice
|
||||
uuid
|
||||
status
|
||||
buyTime
|
||||
totalPrice
|
||||
humanReadableId
|
||||
orderProducts {
|
||||
edges {
|
||||
node {
|
||||
uuid
|
||||
notifications
|
||||
attributes
|
||||
quantity
|
||||
status
|
||||
product {
|
||||
...Product
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${PRODUCT_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const PRODUCT_FRAGMENT = gql`
|
||||
fragment Product on ProductType {
|
||||
uuid
|
||||
name
|
||||
price
|
||||
quantity
|
||||
slug
|
||||
category {
|
||||
name
|
||||
}
|
||||
images {
|
||||
edges {
|
||||
node {
|
||||
image
|
||||
}
|
||||
}
|
||||
}
|
||||
attributeGroups {
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
uuid
|
||||
attributes {
|
||||
name
|
||||
uuid
|
||||
values {
|
||||
value
|
||||
uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const USER_FRAGMENT = gql`
|
||||
fragment User on UserType {
|
||||
avatar
|
||||
uuid
|
||||
attributes
|
||||
language
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
phoneNumber
|
||||
balance {
|
||||
amount
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {PRODUCT_FRAGMENT} from "@/graphql/fragments/products.fragment.js";
|
||||
|
||||
export const WISHLIST_FRAGMENT = gql`
|
||||
fragment Wishlist on WishlistType {
|
||||
uuid
|
||||
products {
|
||||
edges {
|
||||
node {
|
||||
...Product
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${PRODUCT_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {USER_FRAGMENT} from "@/graphql/fragments/user.fragment.js";
|
||||
|
||||
export const REGISTER = gql`
|
||||
mutation register(
|
||||
$firstName: String!,
|
||||
$lastName: String!,
|
||||
$email: String!,
|
||||
$phoneNumber: String!,
|
||||
$password: String!,
|
||||
$confirmPassword: String!
|
||||
) {
|
||||
createUser(
|
||||
firstName: $firstName,
|
||||
lastName: $lastName,
|
||||
email: $email,
|
||||
phoneNumber: $phoneNumber,
|
||||
password: $password,
|
||||
confirmPassword: $confirmPassword
|
||||
) {
|
||||
success
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const LOGIN = gql`
|
||||
mutation login(
|
||||
$email: String!,
|
||||
$password: String!
|
||||
) {
|
||||
obtainJwtToken(
|
||||
email: $email,
|
||||
password: $password
|
||||
) {
|
||||
accessToken
|
||||
refreshToken
|
||||
user {
|
||||
...User
|
||||
}
|
||||
}
|
||||
}
|
||||
${USER_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REFRESH = gql`
|
||||
mutation refresh(
|
||||
$refreshToken: String!
|
||||
) {
|
||||
refreshJwtToken(
|
||||
refreshToken: $refreshToken
|
||||
) {
|
||||
accessToken
|
||||
refreshToken
|
||||
user {
|
||||
...User
|
||||
}
|
||||
}
|
||||
}
|
||||
${USER_FRAGMENT}
|
||||
`
|
||||
|
||||
export const RESET_PASSWORD = gql`
|
||||
mutation resetPassword(
|
||||
$email: String!,
|
||||
) {
|
||||
resetPassword(
|
||||
email: $email,
|
||||
) {
|
||||
success
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const NEW_PASSWORD = gql`
|
||||
mutation confirmResetPassword(
|
||||
$password: String!,
|
||||
$confirmPassword: String!,
|
||||
$token: String!,
|
||||
$uid: String!,
|
||||
) {
|
||||
confirmResetPassword(
|
||||
password: $password,
|
||||
confirmPassword: $confirmPassword,
|
||||
token: $token,
|
||||
uid: $uid
|
||||
) {
|
||||
success
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {ORDER_FRAGMENT} from "@/graphql/fragments/orders.fragment.js";
|
||||
|
||||
export const ADD_TO_CART = gql`
|
||||
mutation addToCart(
|
||||
$orderUuid: String!,
|
||||
$productUuid: String!
|
||||
) {
|
||||
addOrderProduct(
|
||||
orderUuid: $orderUuid,
|
||||
productUuid: $productUuid
|
||||
) {
|
||||
order {
|
||||
...Order
|
||||
}
|
||||
}
|
||||
}
|
||||
${ORDER_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REMOVE_FROM_CART = gql`
|
||||
mutation removeFromCart(
|
||||
$orderUuid: String!,
|
||||
$productUuid: String!
|
||||
) {
|
||||
removeOrderProduct(
|
||||
orderUuid: $orderUuid,
|
||||
productUuid: $productUuid
|
||||
) {
|
||||
order {
|
||||
...Order
|
||||
}
|
||||
}
|
||||
}
|
||||
${ORDER_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REMOVE_KIND_FROM_CART = gql`
|
||||
mutation removeKindFromCart(
|
||||
$orderUuid: String!,
|
||||
$productUuid: String!
|
||||
) {
|
||||
removeOrderProductsOfAKind(
|
||||
orderUuid: $orderUuid,
|
||||
productUuid: $productUuid
|
||||
) {
|
||||
order {
|
||||
...Order
|
||||
}
|
||||
}
|
||||
}
|
||||
${ORDER_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REMOVE_ALL_FROM_CART = gql`
|
||||
mutation removeAllFromCart(
|
||||
$orderUuid: String!
|
||||
) {
|
||||
removeAllOrderProducts(
|
||||
orderUuid: $orderUuid
|
||||
) {
|
||||
order {
|
||||
...Order
|
||||
}
|
||||
}
|
||||
}
|
||||
${ORDER_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const CONTACT_US = gql`
|
||||
mutation contactUs(
|
||||
$name: String!,
|
||||
$email: String!,
|
||||
$phoneNumber: String,
|
||||
$subject: String!,
|
||||
$message: String!,
|
||||
) {
|
||||
contactUs(
|
||||
name: $name,
|
||||
email: $email,
|
||||
phoneNumber: $phoneNumber,
|
||||
subject: $subject,
|
||||
message: $message
|
||||
) {
|
||||
error
|
||||
received
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const DEPOSIT = gql`
|
||||
mutation deposit(
|
||||
$amount: Number!
|
||||
) {
|
||||
contactUs(
|
||||
amount: $amount,
|
||||
) {
|
||||
error
|
||||
received
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import gql from "graphql-tag";
|
||||
|
||||
export const SWITCH_LANGUAGE = gql`
|
||||
mutation setlanguage(
|
||||
$uuid: UUID!,
|
||||
$language: String,
|
||||
) {
|
||||
updateUser(
|
||||
uuid: $uuid,
|
||||
language: $language
|
||||
) {
|
||||
user {
|
||||
...User
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const ACTIVATE_USER = gql`
|
||||
mutation activateUser(
|
||||
$token: String!,
|
||||
$uid: String!
|
||||
) {
|
||||
activateUser(
|
||||
token: $token,
|
||||
uid: $uid
|
||||
) {
|
||||
success
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const UPDATE_USER = gql`
|
||||
mutation updateUser(
|
||||
$uuid: UUID!,
|
||||
$firstName: String,
|
||||
$lastName: String,
|
||||
$email: String,
|
||||
$phoneNumber: String,
|
||||
$password: String,
|
||||
$confirmPassword: String,
|
||||
) {
|
||||
updateUser(
|
||||
uuid: $uuid,
|
||||
firstName: $firstName,
|
||||
lastName: $lastName,
|
||||
email: $email,
|
||||
phoneNumber: $phoneNumber,
|
||||
password: $password,
|
||||
confirmPassword: $confirmPassword,
|
||||
) {
|
||||
user {
|
||||
...User
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {WISHLIST_FRAGMENT} from "@/graphql/fragments/wishlist.fragment.js";
|
||||
|
||||
export const ADD_TO_WISHLIST = gql`
|
||||
mutation addToWishlist(
|
||||
$wishlistUuid: String!,
|
||||
$productUuid: String!
|
||||
) {
|
||||
addWishlistProduct(
|
||||
wishlistUuid: $wishlistUuid,
|
||||
productUuid: $productUuid
|
||||
) {
|
||||
wishlist {
|
||||
...Wishlist
|
||||
}
|
||||
}
|
||||
}
|
||||
${WISHLIST_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REMOVE_FROM_WISHLIST = gql`
|
||||
mutation removeFromWishlist(
|
||||
$wishlistUuid: String!,
|
||||
$productUuid: String!
|
||||
) {
|
||||
removeWishlistProduct(
|
||||
wishlistUuid: $wishlistUuid,
|
||||
productUuid: $productUuid
|
||||
) {
|
||||
wishlist {
|
||||
...Wishlist
|
||||
}
|
||||
}
|
||||
}
|
||||
${WISHLIST_FRAGMENT}
|
||||
`
|
||||
|
||||
export const REMOVE_ALL_FROM_WISHLIST = gql`
|
||||
mutation removeAllFromWishlist(
|
||||
$wishlistUuid: String!
|
||||
) {
|
||||
removeAllWishlistProducts(
|
||||
wishlistUuid: $wishlistUuid
|
||||
) {
|
||||
wishlist {
|
||||
...Wishlist
|
||||
}
|
||||
}
|
||||
}
|
||||
${WISHLIST_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
export const GET_POSTS = gql`
|
||||
query getPosts {
|
||||
posts {
|
||||
edges {
|
||||
node {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const GET_POST_BY_SLUG = gql`
|
||||
query getPostBySlug(
|
||||
$slug: String!
|
||||
) {
|
||||
posts(
|
||||
slug: $slug
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {CATEGORY_FRAGMENT} from "@/graphql/fragments/categories.fragment.js";
|
||||
|
||||
export const GET_CATEGORIES = gql`
|
||||
query getCategories {
|
||||
categories {
|
||||
edges {
|
||||
node {
|
||||
...Category
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${CATEGORY_FRAGMENT}
|
||||
`
|
||||
|
||||
export const GET_CATEGORY_BY_SLUG = gql`
|
||||
query getCategoryBySlug(
|
||||
$slug: String!
|
||||
) {
|
||||
categories(
|
||||
slug: $slug
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
...Category
|
||||
filterableAttributes {
|
||||
possibleValues
|
||||
attributeName
|
||||
}
|
||||
minMaxPrices {
|
||||
maxPrice
|
||||
minPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${CATEGORY_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {COMPANY_FRAGMENT} from "@/graphql/fragments/company.fragment.js";
|
||||
|
||||
export const GET_COMPANY_INFO = gql`
|
||||
query getCompanyInfo {
|
||||
parameters {
|
||||
...Company
|
||||
}
|
||||
}
|
||||
${COMPANY_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {LANGUAGES_FRAGMENT} from "@/graphql/fragments/languages.fragment.js";
|
||||
|
||||
export const GET_LANGUAGES = gql`
|
||||
query getLanguages {
|
||||
languages {
|
||||
...Languages
|
||||
}
|
||||
}
|
||||
${LANGUAGES_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {ORDER_FRAGMENT} from "@/graphql/fragments/orders.fragment.js";
|
||||
|
||||
export const GET_ORDERS = gql`
|
||||
query getOrders(
|
||||
$status: String!,
|
||||
$userEmail: String!
|
||||
) {
|
||||
orders(
|
||||
status: $status,
|
||||
orderBy: "-buyTime",
|
||||
userEmail: $userEmail
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
...Order
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${ORDER_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {PRODUCT_FRAGMENT} from "@/graphql/fragments/products.fragment.js";
|
||||
|
||||
export const GET_PRODUCTS = gql`
|
||||
query getProducts(
|
||||
$after: String,
|
||||
$first: Int,
|
||||
$categorySlugs: String,
|
||||
$orderBy: String,
|
||||
$minPrice: Decimal,
|
||||
$maxPrice: Decimal,
|
||||
$name: String
|
||||
) {
|
||||
products(
|
||||
after: $after,
|
||||
first: $first,
|
||||
categorySlugs: $categorySlugs,
|
||||
orderBy: $orderBy,
|
||||
minPrice: $minPrice,
|
||||
maxPrice: $maxPrice,
|
||||
name: $name
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
...Product
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
${PRODUCT_FRAGMENT}
|
||||
`
|
||||
|
||||
export const GET_PRODUCT_BY_SLUG = gql`
|
||||
query getProductBySlug(
|
||||
$slug: String!
|
||||
) {
|
||||
products(
|
||||
slug: $slug
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
...Product
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${PRODUCT_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import gql from 'graphql-tag'
|
||||
import {WISHLIST_FRAGMENT} from "@/graphql/fragments/wishlist.fragment.js";
|
||||
|
||||
export const GET_WISHLIST = gql`
|
||||
query getWishlist {
|
||||
wishlists {
|
||||
edges {
|
||||
node {
|
||||
...Wishlist
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${WISHLIST_FRAGMENT}
|
||||
`
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
{
|
||||
"buttons": {
|
||||
"signIn": "Sign In",
|
||||
"signUp": "Sign Up",
|
||||
"addToCart": "Add To Cart",
|
||||
"send": "Send",
|
||||
"goEmail": "Take me to my inbox",
|
||||
"logout": "Log Out",
|
||||
"buy": "Buy Now",
|
||||
"save": "Save",
|
||||
"sendLink": "Send link",
|
||||
"topUp": "Top up"
|
||||
},
|
||||
"errors": {
|
||||
"required": "This field is required!",
|
||||
"mail": "Email must be valid!",
|
||||
"compare": "Passwords don't match!",
|
||||
"needLower": "Please include lowercase letter.",
|
||||
"needUpper": "Please include uppercase letter.",
|
||||
"needNumber": "Please include number.",
|
||||
"needMin": "Min. 8 characters",
|
||||
"needSpecial": "Please include a special character: #.?!$%^&*'()_+=:;\"'/>.<,|\\-",
|
||||
"pageNotFound": "Page not found"
|
||||
},
|
||||
"fields": {
|
||||
"search": "Search Cards",
|
||||
"name": "Name",
|
||||
"firstName": "First name",
|
||||
"lastName": "Last name",
|
||||
"phoneNumber": "Phone number",
|
||||
"email": "Email",
|
||||
"subject": "Subject",
|
||||
"message": "Your message",
|
||||
"password": "Password",
|
||||
"newPassword": "New password",
|
||||
"confirmPassword": "Confirm password",
|
||||
"confirmNewPassword": "Confirm new password"
|
||||
},
|
||||
"checkboxes": {
|
||||
"remember": "Remember me"
|
||||
},
|
||||
"popup": {
|
||||
"errors": {
|
||||
"main": "Error!",
|
||||
"defaultError": "Something went wrong..",
|
||||
"noDataToUpdate": "There is no data to update."
|
||||
},
|
||||
"success": {
|
||||
"login": "Sign in successes",
|
||||
"register": "Account successfully created. Please confirm your Email before Sign In!",
|
||||
"confirmEmail": "Verification E-mail link successfully sent!",
|
||||
"reset": "If specified email exists in our system, we will send a password recovery email!",
|
||||
"newPassword": "You have successfully changed your password!",
|
||||
"contactUs": "Your message was sent successfully!"
|
||||
},
|
||||
"addToCart": "{product} has been added to the cart!",
|
||||
"addToCartLimit": "Total quantity limit is {quantity}!",
|
||||
"failAdd": "Please log in to make a purchase",
|
||||
"activationSuccess": "E-mail successfully verified. Please Sign In!",
|
||||
"successUpdate": "Profile successfully updated!",
|
||||
|
||||
"payment": "Your purchase is being processed! Please stand by",
|
||||
"successCheckout": "Order purchase successful!",
|
||||
"addToWishlist": "{product} has been added to the wishlist!"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
import '@/assets/styles/global/fonts.scss'
|
||||
import '@/assets/styles/main.scss'
|
||||
import {createApp, h, provide} from 'vue'
|
||||
import { DefaultApolloClient } from '@vue/apollo-composable'
|
||||
import { createApolloClient } from './apollo'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import {setupI18n} from "@/core/plugins/i18n.config.js";
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
|
||||
const pinia = createPinia()
|
||||
const i18n = await setupI18n()
|
||||
|
||||
const app = createApp({
|
||||
setup() {
|
||||
const apolloClient = createApolloClient()
|
||||
|
||||
provide(DefaultApolloClient, apolloClient)
|
||||
},
|
||||
render: () => h(App)
|
||||
})
|
||||
|
||||
app
|
||||
.use(pinia)
|
||||
.use(i18n)
|
||||
.use(router)
|
||||
.use(ElementPlus)
|
||||
|
||||
app.mount('#app')
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<template>
|
||||
<div class="blog">
|
||||
<div class="container">
|
||||
<div class="blog__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {usePosts} from "@/composables/blog";
|
||||
import {onMounted} from "vue";
|
||||
|
||||
const { posts, loading, getPosts } = usePosts();
|
||||
|
||||
onMounted(async () => {
|
||||
await getPosts()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useUserActivation} from "@/composables/user";
|
||||
import DepositForm from "@/components/forms/deposit-form.vue";
|
||||
import LoginForm from "@/components/forms/login-form.vue";
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const { activateUser } = useUserActivation();
|
||||
|
||||
onMounted( async () => {
|
||||
if (route.name === "activate-user") {
|
||||
await activateUser()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<div class="post">
|
||||
<div class="container">
|
||||
<div class="post__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, onMounted} from "vue";
|
||||
import {usePostbySlug} from "@/composables/blog/usePostBySlug.js";
|
||||
import {useRoute} from "vue-router";
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const slug = computed(() => route.params.postSlug)
|
||||
|
||||
const { post, loading, getPost } = usePostbySlug();
|
||||
|
||||
onMounted(async () => {
|
||||
await getPost(slug.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<div class="product">
|
||||
<div class="container">
|
||||
<div class="product__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, onMounted} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useProductbySlug} from "@/composables/products/useProductBySlug.js";
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const slug = computed(() => route.params.productSlug)
|
||||
|
||||
const { product, loading, getProduct } = useProductbySlug();
|
||||
|
||||
onMounted(async () => {
|
||||
await getProduct(slug.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<template>
|
||||
<div class="profile">
|
||||
<div class="container">
|
||||
<div class="profile__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.profile {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<template>
|
||||
<div class="store">
|
||||
<div class="container">
|
||||
<div class="store__wrapper">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted} from "vue";
|
||||
import {useProducts} from "@/composables/products/index.js";
|
||||
|
||||
const { products, pageInfo, loading, getProducts } = useProducts();
|
||||
|
||||
onMounted(async () => {
|
||||
await getProducts({})
|
||||
console.log('products:', products)
|
||||
console.log('pageInfo:', pageInfo)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.store {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
import {createRouter, createWebHistory, RouterView} from 'vue-router'
|
||||
import HomePage from "@/pages/home-page.vue";
|
||||
import translation from "@/core/helpers/translations.js";
|
||||
import {APP_NAME} from "@/config/index.js";
|
||||
import NewPasswordForm from "@/components/forms/new-password-form.vue";
|
||||
import BlogPage from "@/pages/blog-page.vue";
|
||||
import PostPage from "@/pages/post-page.vue";
|
||||
import ProfilePage from "@/pages/profile-page.vue";
|
||||
import {useAuthStore} from "@/stores/auth.js";
|
||||
import RegisterForm from "@/components/forms/register-form.vue";
|
||||
import LoginForm from "@/components/forms/login-form.vue";
|
||||
import ResetPasswordForm from "@/components/forms/reset-password-form.vue";
|
||||
import StorePage from "@/pages/store-page.vue";
|
||||
import ProductPage from "@/pages/product-page.vue";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/:locale?',
|
||||
component: RouterView,
|
||||
beforeEnter: translation.routeMiddleware,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'home',
|
||||
component: HomePage,
|
||||
meta: {
|
||||
title: "Home"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'activate-user',
|
||||
name: 'activate-user',
|
||||
component: HomePage,
|
||||
meta: {
|
||||
title: 'Home'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'reset-password',
|
||||
name: 'reset-password',
|
||||
component: NewPasswordForm,
|
||||
meta: {
|
||||
title: 'New Password'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
name: 'register',
|
||||
component: RegisterForm,
|
||||
meta: {
|
||||
title: 'Register',
|
||||
requiresGuest: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
name: 'login',
|
||||
component: LoginForm,
|
||||
meta: {
|
||||
title: 'Login',
|
||||
requiresGuest: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'forgot-password',
|
||||
name: 'forgot-password',
|
||||
component: ResetPasswordForm,
|
||||
meta: {
|
||||
title: 'Forgot Password',
|
||||
requiresGuest: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'blog',
|
||||
name: 'blog',
|
||||
component: BlogPage,
|
||||
meta: {
|
||||
title: 'Blog'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'blog/post/:postSlug',
|
||||
name: 'blog-post',
|
||||
component: PostPage,
|
||||
meta: {
|
||||
title: 'Post'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'store',
|
||||
name: 'store',
|
||||
component: StorePage,
|
||||
meta: {
|
||||
title: 'Store'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'product/:productSlug',
|
||||
name: 'product',
|
||||
component: ProductPage,
|
||||
meta: {
|
||||
title: 'Product'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
name: 'profile',
|
||||
component: ProfilePage,
|
||||
meta: {
|
||||
title: 'Profile',
|
||||
requiresAuth: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
scrollBehavior() {
|
||||
document.querySelector('#top').scrollIntoView({ behavior: 'smooth' })
|
||||
return {
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const authStore = useAuthStore();
|
||||
const isAuthenticated = authStore.accessToken
|
||||
|
||||
document.title = to.meta.title ? `${APP_NAME} | ` + to.meta?.title : APP_NAME
|
||||
|
||||
if (to.meta.requiresAuth && !isAuthenticated) {
|
||||
return next({
|
||||
name: 'home',
|
||||
query: { redirect: to.fullPath }
|
||||
});
|
||||
}
|
||||
|
||||
if (to.meta.requiresGuest && isAuthenticated) {
|
||||
return next({ name: 'home' });
|
||||
}
|
||||
|
||||
next();
|
||||
})
|
||||
|
||||
export default router
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import {defineStore} from "pinia";
|
||||
import {ref} from "vue";
|
||||
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const user = ref(null);
|
||||
const accessToken = ref(null);
|
||||
|
||||
const setUser = (payload) => {
|
||||
user.value = payload.user
|
||||
accessToken.value = payload.accessToken
|
||||
}
|
||||
|
||||
return { user, accessToken, setUser }
|
||||
})
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import {defineStore} from "pinia";
|
||||
import {ref} from "vue";
|
||||
|
||||
export const useCartStore = defineStore('cart', () => {
|
||||
const currentOrder = ref({});
|
||||
const setCurrentOrders = (order) => {
|
||||
currentOrder.value = order
|
||||
};
|
||||
|
||||
return {
|
||||
currentOrder,
|
||||
setCurrentOrders
|
||||
}
|
||||
})
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useCompanyStore = defineStore('company', () => {
|
||||
const companyInfo = ref([]);
|
||||
const setCompanyInfo = (payload) => {
|
||||
companyInfo.value = payload
|
||||
};
|
||||
|
||||
return {
|
||||
companyInfo,
|
||||
setCompanyInfo
|
||||
}
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue