Hello from MCP server
import { createRouter, createWebHistory } from "@ionic/vue-router";
import PocketBase from "pocketbase";
import { Preferences } from "@capacitor/preferences";
import { clearAllIndexedDB, deleteDatabase } from "@/dataAccess/deleteDb";
import populateData from "@/lib/populateData";
// Build token for force logout on new builds
const BUILD_TOKEN = "tnfr-preview-4b";
import { RouteRecordRaw } from "vue-router";
import Register from "@/views/Register.vue";
import Login from "@/views/Login.vue";
import Logout from "@/views/Logout.vue";
import OrgCreate from "@/views/OrgCreate.vue";
import OrgJoin from "@/views/OrgJoin.vue";
import OrgView from "@/views/OrgView.vue";
import UserProfile from "@/views/UserProfile.vue";
import OrganizationManage from "@/views/OrganizationManage.vue";
import Editor from "@/views/Editor.vue";
import EditJob from "@/views/EditJob.vue";
import SQL from "@/views/SQL.vue";
import Framework from "@/views/Framework.vue";
import TNFR from "@/views/TNFR.vue";
import PriceList from "@/views/PriceList.vue";
import Directory from "@/views/Directory.vue";
import Home from "@/views/Home.vue";
import CheckHours from "@/views/CheckHours.vue";
import Cart from "@/views/Cart.vue";
import Invoice from "@/views/Invoice.vue";
import Review from "@/views/Review.vue";
import ThemeDesigner from "@/views/ThemeDesigner.vue";
import JobAdjust from "@/views/JobAdjust.vue";
import JobPreview from "@/views/JobPreview.vue";
import MenuTemplateLegacy from "@/views/MenuTemplateLegacy.vue";
import MenuTemplateDev from "@/views/MenuTemplateDev.vue";
import OfferConfirmation from "@/views/OfferConfirmation.vue";
import JobContent from "@/views/JobContent.vue";
import MenuView from "@/views/MenuView.vue";
import Payment from "@/views/Payment.vue";
import NotFound from "@/views/NotFound.vue";
// Use the same API host as the rest of the app
const API_HOST = import.meta.env.VITE_API_HOST;
const pb = new PocketBase(API_HOST);
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "home",
component: Home,
},
// Authentication routes
{
path: "/auth/login",
name: "auth.login",
component: Login,
},
{
path: "/auth/register",
name: "auth.register",
component: Register,
},
{
path: "/auth/logout",
name: "auth.logout",
component: Logout,
},
// Organization routes
{
path: "/organization/create",
name: "organizations.create",
component: OrgCreate,
},
{
path: "/organization/:id",
name: "organizations.view",
component: OrgView,
},
{
path: "/organization/:id/join",
name: "organizations.join",
component: OrgJoin,
},
{
path: "/organization/:id/manage",
name: "organizations.manage",
component: OrganizationManage,
},
// User routes
{
path: "/profile",
name: "user.profile",
component: UserProfile,
},
{
path: "/sql",
name: "sql",
component: SQL,
},
// Editor routes
{
path: "/editor",
name: "editor",
component: Editor,
},
{
path: "/editor/create",
name: "editor.create",
component: Editor,
},
{
path: "/editor/:collection/:id",
name: "editor.collection.record",
component: Editor,
},
{
path: "/editor/:id",
name: "editor.record",
component: Editor,
},
{
path: "/editor/job/:jobId",
name: "editor.job",
component: EditJob,
},
{
path: "/edit-job/:jobId",
name: "edit.job.legacy",
component: EditJob,
},
{
path: "/edit/:jobId",
name: "edit.job",
component: EditJob,
},
// Framework/Dev routes
{
path: "/framework",
name: "framework",
component: Framework,
},
{
path: "/tnfr",
name: "tnfr",
component: TNFR,
},
{
path: "/price-list",
name: "price.list",
component: PriceList,
},
// Main app routes
{
path: "/directory",
name: "directory",
component: Directory,
},
{
path: "/check-hours/:problemId",
name: "check.hours",
component: CheckHours,
},
{
path: "/cart/",
name: "cart",
component: Cart,
},
{
path: "/invoice",
name: "invoice",
component: Invoice,
},
{
path: "/payment",
name: "payment",
component: Payment,
},
{
path: "/review",
name: "review",
component: Review,
},
{
path: "/menu/:jobId",
name: "menu",
component: MenuView,
},
{
path: "/theme-designer",
name: "theme.designer",
component: ThemeDesigner,
},
// Job routes
{
path: "/job/:id/adjust",
name: "job.adjust",
component: JobAdjust,
},
{
path: "/job/:id/preview",
name: "job.preview",
component: JobPreview,
},
{
path: "/job/:id/show/legacy",
name: "job.show.legacy",
component: MenuTemplateLegacy,
},
{
path: "/job/:id/show/dev",
name: "job.show.dev",
component: MenuTemplateDev,
},
{
path: "/job/:jobId/confirm/:tierId",
name: "offers.confirm.job",
component: OfferConfirmation,
},
{
path: "/job/:problemId",
name: "job.content",
component: JobContent,
},
// Catch-all 404
{
path: "/:pathMatch(.*)*",
name: "not-found",
component: NotFound,
},
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
});
const canAccessRoute = (routeName: string) => {
const routePermissions: Record<string, string[]> = {
"organizations.manage": ["admin"],
};
let requiredRoles = [] as string[];
if (Object.keys(routePermissions).includes(routeName)) {
requiredRoles = routePermissions[routeName];
}
if (requiredRoles.length == 0) {
return true;
}
const profiles = pb.authStore.record?.expand?.profiles || [];
for (const profile of profiles) {
if (profile.org == pb.authStore.record?.activeOrg) {
for (const role of profile.roles) {
if (requiredRoles.includes(role)) {
return true;
}
}
}
}
return false;
};
// router.beforeEach(async (to) => {
// const hasAccess = canAccessRoute(to.name as string);
// if (!hasAccess) {
// return false;
// } else {
// return true;
// }
// });
//
// Track if build check has been done this session
let buildCheckDone = false;
router.beforeEach(async (to) => {
// Force logout on new build (only check once per session)
if (!buildCheckDone) {
buildCheckDone = true;
const savedBuild = (await Preferences.get({ key: "buildToken" })).value;
if (savedBuild === null || savedBuild !== BUILD_TOKEN) {
// Save the new build token
await Preferences.set({ key: "buildToken", value: BUILD_TOKEN });
// Force logout if user was logged in
if (pb.authStore.isValid) {
// Preserve relogin keys across forced logout
const reloginEmail = window.localStorage.getItem("relogin_email");
const reloginReturnTo = window.localStorage.getItem("relogin_returnTo");
// Delete SQLite database first (closes connection and deletes)
try {
await deleteDatabase("pricebookPlatform");
} catch (e) {
console.warn("[router] Failed to delete SQLite database:", e);
}
await clearAllIndexedDB();
window.localStorage.clear();
// Restore relogin keys
if (reloginEmail) window.localStorage.setItem("relogin_email", reloginEmail);
if (reloginReturnTo) window.localStorage.setItem("relogin_returnTo", reloginReturnTo);
window.location.reload();
return false;
}
}
}
// Authentication
if (
// make sure the user is authenticated
!pb.authStore.isValid &&
// Avoid an infinite redirect
to.name !== "auth.login" &&
to.name !== "auth.logout" &&
to.name !== "auth.register"
) {
// redirect the user to the register page
return { name: "auth.register" };
}
// Logout
if (to.name == "auth.logout") {
if (pb.authStore.isValid) {
// Preserve relogin keys across logout
const reloginEmail = window.localStorage.getItem("relogin_email");
const reloginReturnTo = window.localStorage.getItem("relogin_returnTo");
// Delete SQLite database first (closes connection and deletes)
try {
await deleteDatabase("pricebookPlatform");
} catch (e) {
console.warn("[router] Failed to delete SQLite database:", e);
}
await clearAllIndexedDB();
window.localStorage.clear();
// Restore relogin keys
if (reloginEmail) window.localStorage.setItem("relogin_email", reloginEmail);
if (reloginReturnTo) window.localStorage.setItem("relogin_returnTo", reloginReturnTo);
window.location.reload();
} else {
// Already logged out, redirect to register
return { name: "auth.register" };
}
}
// Populate Data for authenticated routes (except TNFR routes)
if (
pb.authStore.isValid &&
to.name !== "auth.login" &&
to.name !== "auth.logout" &&
to.name !== "auth.register"
) {
populateData();
return true;
}
});
export default router;