feat: add fake auth store

This commit is contained in:
Sergey Krylov 2025-02-05 06:17:40 +03:00
parent 4004d8aa2e
commit 2ea16d8d12
12 changed files with 152 additions and 20 deletions

View File

@ -6,13 +6,15 @@
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
"preview": "vite preview",
"lint": "eslint"
},
"dependencies": {
"@vee-validate/zod": "^4.15.0",
"vee-validate": "^4.15.0",
"vue": "3.5.13",
"vue-router": "4.5.0",
"vuex": "^4.0.2",
"zod": "^3.24.1"
},
"devDependencies": {

13
pnpm-lock.yaml generated
View File

@ -20,6 +20,9 @@ importers:
vue-router:
specifier: 4.5.0
version: 4.5.0(vue@3.5.13(typescript@5.7.3))
vuex:
specifier: ^4.0.2
version: 4.0.2(vue@3.5.13(typescript@5.7.3))
zod:
specifier: ^3.24.1
version: 3.24.1
@ -945,6 +948,11 @@ packages:
typescript:
optional: true
vuex@4.0.2:
resolution: {integrity: sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==}
peerDependencies:
vue: ^3.0.2
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@ -1769,6 +1777,11 @@ snapshots:
optionalDependencies:
typescript: 5.7.3
vuex@4.0.2(vue@3.5.13(typescript@5.7.3)):
dependencies:
'@vue/devtools-api': 6.6.4
vue: 3.5.13(typescript@5.7.3)
which@2.0.2:
dependencies:
isexe: 2.0.0

View File

@ -9,7 +9,7 @@
</router-link>
</li>
<li>
<router-link to="/">
<router-link :to="PAGE_URL[PAGE.HELP]">
Помощь
</router-link>
</li>
@ -17,16 +17,29 @@
<a href="#">Сообщения</a>
</li>
<li>
<a href="#">Выход</a>
<a
href="#"
@click.prevent="onExit"
>
Выход
</a>
</li>
</ul>
</nav>
</template>
<script>
export default {
<script setup>
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import { PAGE, PAGE_URL } from '../router';
}
const store = useStore();
const router = useRouter();
const onExit = () => {
store.dispatch('auth/logout');
router.push({name: PAGE.AUTH});
}
</script>
<style lang="scss" scoped>

View File

@ -1,9 +1,12 @@
import { useStore } from 'vuex';
import * as z from 'zod';
import { useField, useForm } from 'vee-validate';
import { toTypedSchema } from '@vee-validate/zod';
import { computed, watch } from 'vue';
import router, { PAGE } from '../router';
const useLoginForm = () => {
const store = useStore();
const schema = z.object({
email: z
.string()
@ -23,8 +26,9 @@ const useLoginForm = () => {
validationSchema: toTypedSchema(schema)
});
const onSubmit = handleSubmit((values) => {
console.log(values);
const onSubmit = handleSubmit(async (values) => {
await store.dispatch('auth/login', values);
await router.push({name: PAGE.HOME});
})
const {value: email, errorMessage: eError, handleBlur: eBlur} = useField('email');

View File

@ -2,7 +2,9 @@ import { createApp } from 'vue'
import './style.css';
import App from './App.vue'
import router from './router';
import store from './store';
createApp(App)
.use(router)
.use(store)
.mount('#app');

View File

@ -1,28 +1,43 @@
import { createRouter, createWebHistory } from 'vue-router'
import store from '../store';
export enum PAGE {
HOME= 'Home',
AUTH = 'Auth',
HELP = 'Help'
}
export const PAGE_URL: Record<PAGE, string> = {
[PAGE.HOME]: '/',
[PAGE.AUTH]: '/auth',
[PAGE.HELP]: '/help'
}
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
path: PAGE_URL[PAGE.HOME],
name: PAGE.HOME,
component: () => import('../views/HomePage.vue'),
meta: {
layout: 'main'
layout: 'main',
auth: true,
},
},
{
path: '/help',
name: 'Help',
component: () => import('../views/Help.vue'),
path: PAGE_URL[PAGE.HELP],
name: PAGE.HELP,
component: () => import('../views/HelpPage.vue'),
meta: {
layout: 'main'
layout: 'main',
auth: true,
},
},
{
path: '/auth',
name: 'Auth',
component: () => import('../views/Auth.vue'),
path: PAGE_URL[PAGE.AUTH],
name: PAGE.AUTH,
component: () => import('../views/AuthPage.vue'),
meta: {
layout: 'auth'
layout: 'auth',
}
},
]
@ -32,5 +47,18 @@ const router = createRouter({
routes,
});
router.beforeEach((to, from, next) => {
const requiredAuth = to.meta.auth;
if (!requiredAuth) {
return next();
}
if (store.getters['auth/iseAuth']) {
next();
} else {
next('/auth?message=auth-required');
}
})
export default router;

15
src/store/index.ts Normal file
View File

@ -0,0 +1,15 @@
import { createLogger, createStore } from 'vuex'
import authModule from './modules/auth.module.ts';
const isDev = process.env.NODE_ENV === 'development';
const store = createStore({
plugins: [
isDev && createLogger()
].filter(Boolean),
modules: {
auth: authModule
},
})
export default store;

View File

@ -0,0 +1,49 @@
import type { Module } from 'vuex';
const LOCAL_STORAGE_KEY = 'jwt-token';
const authModule: Module<any, any> = {
namespaced: true,
state: {
token: localStorage.getItem(LOCAL_STORAGE_KEY)
},
mutations: {
setToken(state, payload) {
state.token = payload;
localStorage.setItem(LOCAL_STORAGE_KEY, payload)
},
removeToken(state) {
state.token = null;
localStorage.removeItem(LOCAL_STORAGE_KEY)
},
},
actions: {
async login(context, payload) {
const { commit } = context;
const token = await new Promise((res) => {
setTimeout(() => {
const token = payload.email + payload.password;
res(token);
}, 1500)
});
commit('setToken', token);
},
logout(context) {
const { commit } = context;
commit('removeToken');
}
},
getters: {
token: (state) => {
return state.token;
},
iseAuth: (state) => {
return Boolean(state.token)
}
}
}
export default authModule;

6
src/vuex.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare module "vuex" {
export * from "vuex/types/index.d.ts";
export * from "vuex/types/helpers.d.ts";
export * from "vuex/types/logger.d.ts";
export * from "vuex/types/vue.d.ts";
}