feat(auth): enforce login route with global middleware
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onBeforeUnmount, onMounted } from "vue";
|
||||
import CrmAuthLoading from "~~/app/components/workspace/auth/CrmAuthLoading.vue";
|
||||
import CrmAuthLoginForm from "~~/app/components/workspace/auth/CrmAuthLoginForm.vue";
|
||||
import CrmCalendarPanel from "~~/app/components/workspace/calendar/CrmCalendarPanel.vue";
|
||||
import CrmCommunicationsContextSidebar from "~~/app/components/workspace/communications/CrmCommunicationsContextSidebar.vue";
|
||||
import CrmCommunicationsListSidebar from "~~/app/components/workspace/communications/CrmCommunicationsListSidebar.vue";
|
||||
@@ -13,7 +12,6 @@ import meQuery from "~~/graphql/operations/me.graphql?raw";
|
||||
import chatMessagesQuery from "~~/graphql/operations/chat-messages.graphql?raw";
|
||||
import dashboardQuery from "~~/graphql/operations/dashboard.graphql?raw";
|
||||
import getClientTimelineQuery from "~~/graphql/operations/get-client-timeline.graphql?raw";
|
||||
import loginMutation from "~~/graphql/operations/login.graphql?raw";
|
||||
import logoutMutation from "~~/graphql/operations/logout.graphql?raw";
|
||||
import logPilotNoteMutation from "~~/graphql/operations/log-pilot-note.graphql?raw";
|
||||
import createCalendarEventMutation from "~~/graphql/operations/create-calendar-event.graphql?raw";
|
||||
@@ -533,10 +531,6 @@ const chatArchivingId = ref("");
|
||||
const chatThreadPickerOpen = ref(false);
|
||||
const commPinToggling = ref(false);
|
||||
const selectedChatId = ref("");
|
||||
const loginPhone = ref("");
|
||||
const loginPassword = ref("");
|
||||
const loginError = ref<string | null>(null);
|
||||
const loginBusy = ref(false);
|
||||
let pilotBackgroundPoll: ReturnType<typeof setInterval> | null = null;
|
||||
const lifecycleNowMs = ref(Date.now());
|
||||
let lifecycleClock: ReturnType<typeof setInterval> | null = null;
|
||||
@@ -898,23 +892,7 @@ async function loadMe() {
|
||||
const authResolved = ref(false);
|
||||
|
||||
async function bootstrapSession() {
|
||||
try {
|
||||
await loadMe();
|
||||
if (!authMe.value) {
|
||||
stopCrmRealtime();
|
||||
pilotMessages.value = [];
|
||||
chatConversations.value = [];
|
||||
clientTimelineItems.value = [];
|
||||
telegramConnectStatus.value = "not_connected";
|
||||
telegramConnections.value = [];
|
||||
telegramConnectUrl.value = "";
|
||||
return;
|
||||
}
|
||||
await Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData(), loadTelegramConnectStatus()]);
|
||||
if (process.client) {
|
||||
startCrmRealtime();
|
||||
}
|
||||
} catch {
|
||||
const resetAuthState = () => {
|
||||
stopCrmRealtime();
|
||||
authMe.value = null;
|
||||
pilotMessages.value = [];
|
||||
@@ -923,6 +901,26 @@ async function bootstrapSession() {
|
||||
telegramConnectStatus.value = "not_connected";
|
||||
telegramConnections.value = [];
|
||||
telegramConnectUrl.value = "";
|
||||
};
|
||||
|
||||
try {
|
||||
await loadMe();
|
||||
if (!authMe.value) {
|
||||
resetAuthState();
|
||||
if (process.client) {
|
||||
await navigateTo("/login", { replace: true });
|
||||
}
|
||||
return;
|
||||
}
|
||||
await Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData(), loadTelegramConnectStatus()]);
|
||||
if (process.client) {
|
||||
startCrmRealtime();
|
||||
}
|
||||
} catch {
|
||||
resetAuthState();
|
||||
if (process.client) {
|
||||
await navigateTo("/login", { replace: true });
|
||||
}
|
||||
} finally {
|
||||
authResolved.value = true;
|
||||
}
|
||||
@@ -963,25 +961,6 @@ async function archiveChatConversation(id: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function login() {
|
||||
loginError.value = null;
|
||||
loginBusy.value = true;
|
||||
try {
|
||||
await gqlFetch<{ login: { ok: boolean } }>(loginMutation, {
|
||||
phone: loginPhone.value,
|
||||
password: loginPassword.value,
|
||||
});
|
||||
await loadMe();
|
||||
startPilotBackgroundPolling();
|
||||
startCrmRealtime();
|
||||
await Promise.all([loadPilotMessages(), loadChatConversations(), refreshCrmData(), loadTelegramConnectStatus()]);
|
||||
} catch (e: any) {
|
||||
loginError.value = e?.data?.message || e?.message || "Login failed";
|
||||
} finally {
|
||||
loginBusy.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
await gqlFetch<{ logout: { ok: boolean } }>(logoutMutation);
|
||||
stopCrmRealtime();
|
||||
@@ -996,6 +975,9 @@ async function logout() {
|
||||
telegramConnectStatus.value = "not_connected";
|
||||
telegramConnections.value = [];
|
||||
telegramConnectUrl.value = "";
|
||||
if (process.client) {
|
||||
await navigateTo("/login", { replace: true });
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshCrmData() {
|
||||
@@ -4781,18 +4763,7 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
||||
|
||||
<template>
|
||||
<div class="h-[100dvh] overflow-hidden bg-base-200/35">
|
||||
<CrmAuthLoading v-if="!authResolved" />
|
||||
|
||||
<CrmAuthLoginForm
|
||||
v-else-if="!authMe"
|
||||
:phone="loginPhone"
|
||||
:password="loginPassword"
|
||||
:error="loginError"
|
||||
:busy="loginBusy"
|
||||
@update:phone="loginPhone = $event"
|
||||
@update:password="loginPassword = $event"
|
||||
@submit="login"
|
||||
/>
|
||||
<CrmAuthLoading v-if="!authResolved || !authMe" />
|
||||
|
||||
<template v-else>
|
||||
<div class="grid h-full min-h-0 grid-cols-1 gap-0 lg:grid-cols-[320px_minmax(0,1fr)]">
|
||||
|
||||
Reference in New Issue
Block a user