Перейти к содержанию

Роутер

Все компоненты написаны, теперь нужно понять, в какой момент какой компонент выводить пользователю, для этого воспользуемся роутером.

helpers/router.js
import { createRouter, createWebHistory } from 'vue-router'

import { useAuthStore, useInfoStore } from '@/stores';
import { fetchWrapper } from '@/helpers';
import { DefaultLayout } from '@/layouts';
import { InfoView, SurveyView, LoginView } from '@/views';

const baseUrl = `${import.meta.env.VITE_API_URL}`;
let lastCheckFetchWasFrom = '';

export const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/login',
      component: DefaultLayout,
      props: {showTitle: true},
      children: [
        {
          path: '',
          name: 'Login',
          component: LoginView,
        },
      ],
    },
    {
      path: '/info',
      component: DefaultLayout,
      props: {showLogout: true},
      children: [
        {
          path: '',
          name: 'Info',
          component: InfoView,
        },
      ],
    },
    {
      path: '/survey',
      component: DefaultLayout,
      props: {showTitle: true, showGroupName: true, showLogout: true},
      children: [
        {
          path: '',
          name: 'Survey',
          component: SurveyView,
        },
      ],
    },
  ],
});


router.beforeEach(async (to) => {
  const publicPages = ['/login'];
  const authRequired = !publicPages.includes(to.path);
  const auth = useAuthStore();
  const info = useInfoStore();

  if (auth.access && (to.path !== '/survey' && to.path !== '/info')) {
    return {
      path: '/survey',
      query: to.query,
    };
  }

  else if (authRequired && !auth.access) {
    auth.returnUrl = to.fullPath;
    return {
      path: '/login',
      query: to.query,
    };
  }

  else if (to.path === '/survey') {
    try {
      const data = await fetchWrapper.get(`${baseUrl}/api/survey/user/check/`);
      lastCheckFetchWasFrom = '/survey';

      if (data.is_first_course !== true) {
        info.setText('Опрос только для первокурсников!');
        return { path: '/info' }
      } else if (data.is_faculty_active !== true) {
        info.setText('Опрос для вашего факультета ещё закрыт!');
        return { path: '/info' };
      } else if (data.has_adapters !== true) {
        info.setText('Не удалось получить информацию о ваших адаптерах!');
        return { path: '/info' };
      } else if (data.is_done === true) {
        info.setText('Опрос пройден!\nСпасибо 💙');
        return { path: '/info' };
      } else {
        info.removeText();
      }

    } catch(error) {
      info.setText('Ошибка при запросе информации для опроса');
      return { path: '/info' };
    }
  }

  else if (to.path === '/info') {
    if (lastCheckFetchWasFrom !== '/survey') {
      try {
        const data = await fetchWrapper.get(`${baseUrl}/api/survey/user/check/`);
        lastCheckFetchWasFrom = '/info';

        if (data.is_first_course !== true) {
          info.setText('Опрос только для первокурсников!');
        } else if (data.is_faculty_active !== true) {
          info.setText('Опрос для вашего факультета ещё закрыт!');
        } else if (data.has_adapters !== true) {
          info.setText('Не удалось получить информацию о ваших адаптерах!');
        } else if (data.is_done === true) {
          info.setText('Опрос пройден!\nСпасибо 💙');
        } else {
          info.removeText();
          return {path: '/survey'};
        }

      } catch (error) {
        info.setText('Ошибка при запросе информации для опроса');
      }
    }
  }
});

Здесь в routes мы объявим наши маршруты и укажем, какой основной компонент выводить, с какими пропами и с какими дочерними компонентами.

В нашем приложении будет только три маршрута, в соответствии с количеством представлений (которые мы и будем передавать как дочерние компоненты).

Для каждого маршрута основным компонентом будет являться макет Default, для которого нужно в пропах указать, что нужно отображать.

Помимо объявления маршрутов здесь нам также нужно вызвать функцию роутера beforeEach, которая перед перенаправлением пользователя на нужный маршрут выполнит необходимые для нас действия, которые в итоге могут изменить маршрут.

В ней мы укажем страницу /login как доступную без авторизации, а остальные - только с авторизацией.

Если пользователь без авторизации попытается перейти на любую страницу, отличную от /login, будем перенаправлять его на авторизацию.
И наоборот, если авторизованный пользователь решит перейти на страницу авторизации, перенаправим его на страницу прохождения опроса.

Если пользователь переход на страницу прохождения опроса, нужно проверить, может ли этот пользователь его проходить.

Для этого отправим запрос на бэкенд и запросим статусы пользователя. Пройдём через каждый из них и при несоблюдении обновим текст в хранилище на соответствующий и переведём его на информационную страницу.

Если все условия соблюдены, позволим перейти на страницу опроса.

Кроме того, нам также нужно проверять эти условия и на информационной странице, чтобы в случае изменения информации в БД или в случае исправления ошибки пользователь при обновлении страницы был переведён на страницу опроса.

Чтобы не происходило две проверки подряд, будем хранить в переменной lastCheckFetchWasFrom маршрут страницы, с которой в последний раз была запущена проверка, и не будем повторно запускать проверку при перенаправлении со страницы опроса на информационную страницу.