You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
5.4 KiB
193 lines
5.4 KiB
import { createRouter, createWebHistory } from 'vue-router'
|
|
import {
|
|
TOKEN_KEY,
|
|
PARTICIPANT_COMPETITION_SLUG_KEY,
|
|
pathIsReviewerZone,
|
|
readReviewerSession,
|
|
} from '../config/api'
|
|
import { useAdminAuthStore } from '../stores/adminAuth'
|
|
import {
|
|
adminDynamicRoutesRegistered,
|
|
registerAdminDynamicRoutes,
|
|
} from './admin/registerDynamicRoutes'
|
|
|
|
import './admin/routeMeta'
|
|
|
|
const MainLayout = () => import('../layouts/MainLayout.vue')
|
|
|
|
function participantRootRedirect() {
|
|
const t = localStorage.getItem(TOKEN_KEY)
|
|
const s = localStorage.getItem(PARTICIPANT_COMPETITION_SLUG_KEY)
|
|
if (s) {
|
|
return t
|
|
? { name: 'participant-apply', params: { slug: s }, replace: true as const }
|
|
: { name: 'participant-login', params: { slug: s }, replace: true as const }
|
|
}
|
|
return { path: '/c', replace: true as const }
|
|
}
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(import.meta.env.BASE_URL),
|
|
routes: [
|
|
{
|
|
path: '/',
|
|
redirect: participantRootRedirect,
|
|
},
|
|
{
|
|
path: '/c',
|
|
name: 'participant-landing',
|
|
component: () => import('../views/ParticipantLandingView.vue'),
|
|
},
|
|
{
|
|
path: '/c/:slug/login',
|
|
name: 'participant-login',
|
|
component: () => import('../views/LoginView.vue'),
|
|
meta: { guestOnly: true },
|
|
},
|
|
{
|
|
path: '/c/:slug/review/login',
|
|
name: 'reviewer-login',
|
|
component: () => import('../views/reviewer/ReviewerLoginView.vue'),
|
|
meta: { guestReviewerOnly: true },
|
|
},
|
|
{
|
|
path: '/c/:slug/review',
|
|
component: () => import('../layouts/ReviewerLayout.vue'),
|
|
meta: { requiresReviewerAuth: true },
|
|
children: [
|
|
{
|
|
path: 'applications/:id(\\d+)',
|
|
name: 'reviewer-application-detail',
|
|
component: () => import('../views/reviewer/ReviewerApplicationDetailView.vue'),
|
|
},
|
|
{
|
|
path: '',
|
|
name: 'reviewer-projects',
|
|
component: () => import('../views/reviewer/ReviewerProjectsView.vue'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: '/c/:slug',
|
|
component: MainLayout,
|
|
meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
redirect: (to) => ({
|
|
name: 'participant-apply',
|
|
params: { slug: to.params.slug as string },
|
|
}),
|
|
},
|
|
{
|
|
path: 'apply',
|
|
name: 'participant-apply',
|
|
component: () => import('../views/ApplyView.vue'),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: '/app',
|
|
redirect: () => {
|
|
const s = localStorage.getItem(PARTICIPANT_COMPETITION_SLUG_KEY)
|
|
return s ? { name: 'participant-apply', params: { slug: s } } : { path: '/c' }
|
|
},
|
|
},
|
|
{
|
|
path: '/app/apply',
|
|
redirect: () => {
|
|
const s = localStorage.getItem(PARTICIPANT_COMPETITION_SLUG_KEY)
|
|
return s ? { name: 'participant-apply', params: { slug: s } } : { path: '/c' }
|
|
},
|
|
},
|
|
{
|
|
path: '/admin/login',
|
|
name: 'admin-login',
|
|
component: () => import('../views/admin/AdminLoginView.vue'),
|
|
},
|
|
{
|
|
path: '/admin',
|
|
name: 'AdminLayout',
|
|
component: () => import('../layouts/AdminLayout.vue'),
|
|
children: [],
|
|
},
|
|
],
|
|
})
|
|
|
|
router.beforeEach(async (to) => {
|
|
const slugRaw = to.params.slug != null ? String(to.params.slug).trim() : ''
|
|
if (!pathIsReviewerZone(to.path) && slugRaw) {
|
|
localStorage.setItem(PARTICIPANT_COMPETITION_SLUG_KEY, slugRaw)
|
|
}
|
|
|
|
const participantToken = localStorage.getItem(TOKEN_KEY)
|
|
|
|
if (pathIsReviewerZone(to.path)) {
|
|
const { token: reviewerToken, competitionSlug: reviewerSlug } = readReviewerSession()
|
|
|
|
if (to.name === 'reviewer-login') {
|
|
if (reviewerToken && reviewerSlug !== '' && reviewerSlug === slugRaw) {
|
|
return { name: 'reviewer-projects', params: { slug: slugRaw }, replace: true }
|
|
}
|
|
return true
|
|
}
|
|
|
|
if (to.matched.some((r) => r.meta.requiresReviewerAuth === true)) {
|
|
if (!reviewerToken || reviewerSlug !== slugRaw) {
|
|
return {
|
|
name: 'reviewer-login',
|
|
params: { slug: slugRaw },
|
|
query: slugRaw ? { redirect: to.fullPath } : {},
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
if (to.path.startsWith('/admin')) {
|
|
const adminAuth = useAdminAuthStore()
|
|
|
|
if (to.name === 'admin-login' || to.path === '/admin/login') {
|
|
if (adminAuth.isAuthenticated) {
|
|
if (!adminDynamicRoutesRegistered()) {
|
|
await registerAdminDynamicRoutes(router)
|
|
}
|
|
return { name: 'admin-competitions-list', replace: true }
|
|
}
|
|
return true
|
|
}
|
|
|
|
if (!adminAuth.isAuthenticated) {
|
|
return { path: '/admin/login', query: { redirect: to.fullPath } }
|
|
}
|
|
|
|
if (!adminDynamicRoutesRegistered()) {
|
|
await registerAdminDynamicRoutes(router)
|
|
return { ...to, replace: true }
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
if (to.matched.some((r) => r.meta.requiresAuth) && !participantToken) {
|
|
const slug = to.params.slug != null ? String(to.params.slug) : ''
|
|
if (slug) {
|
|
return { name: 'participant-login', params: { slug }, query: { redirect: to.fullPath } }
|
|
}
|
|
return { path: '/c', query: { redirect: to.fullPath } }
|
|
}
|
|
|
|
if (to.meta.guestOnly && participantToken) {
|
|
const slug = to.params.slug != null ? String(to.params.slug) : ''
|
|
if (slug) {
|
|
return { name: 'participant-apply', params: { slug }, replace: true }
|
|
}
|
|
return participantRootRedirect()
|
|
}
|
|
|
|
return true
|
|
})
|
|
|
|
export default router
|