Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
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;