Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion backend/functions/server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import finCompareRoute from "../Endpoints/finance/finCompareRoute.js";
// Import new services
import peAnalysisRoute from '../Endpoints/services/peAnalysisService.js';
import aiWorkflowRoute from '../Endpoints/services/aiWorkflowService.js';

import helmet from "helmet";
dotenv.config();

const mongoURI = process.env.MONGO_URI;
Expand All @@ -50,6 +50,7 @@ const allowedOrigins = [
];

app.use(
helmet(),
cors({
origin: function (origin, callback) {
// ✅ Allow undefined origins (like Postman, curl, or internal requests)
Expand Down
12 changes: 0 additions & 12 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,10 @@ export default {
isTyping: false,
messageVisible: false,
showLoadingPage: false,
isInitialLoad: true,
logoClicked: false,
};
},
async mounted() {
if (this.isInitialLoad) {
this.showLoadingPage = true;
this.loadingStartTime = Date.now();

const minLoadingTime = 1200;
setTimeout(() => {
this.showLoadingPage = false;
this.isInitialLoad = false;
}, minLoadingTime);
}

this.displayedMessage = "Hello! Welcome to FinBud.";
document.addEventListener("click", this.handleClickOutside);

Expand Down
32 changes: 22 additions & 10 deletions frontend/src/components/Basic/NavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -466,25 +466,37 @@ export default {

const savedLang = localStorage.getItem("language");
if (savedLang) this.$i18n.locale = savedLang;
const routeNeedsAuth =
this.$route.meta.requiresAuth || this.$route.path === "/chat-view";

// Always fetch current user data to ensure we have the latest info
await this.$store.dispatch("users/fetchCurrentUser");
if (routeNeedsAuth && !this.$store.state.users.authChecked) {
await this.$store.dispatch("users/fetchCurrentUser");
}
// // Always fetch current user data to ensure we have the latest info
// await this.$store.dispatch("users/fetchCurrentUser");

// Debug logging
const userData = this.$store.getters["users/currentUser"];
console.log("NavBar - User data loaded:", userData);
console.log("NavBar - Display name:", this.profileName);
console.log("NavBar - Profile image:", this.profileImage);
// // Debug logging
// const userData = this.$store.getters["users/currentUser"];
// console.log("NavBar - User data loaded:", userData);
// console.log("NavBar - Display name:", this.profileName);
// console.log("NavBar - Profile image:", this.profileImage);

const storedDarkMode = localStorage.getItem("darkMode");
this.isDarkMode = storedDarkMode === "true";
document.documentElement.classList.toggle("dark-mode", this.isDarkMode);
document.body.classList.toggle("dark-mode", this.isDarkMode);

if (this.isAuthenticated) {
this.$store.dispatch("finCoin/fetchFinCoinBalance");
if (this.$store.getters["users/isAuthenticated"]) {
const run = () => this.$store.dispatch("finCoin/fetchFinCoinBalance");

if ("requestIdleCallback" in window) {
window.requestIdleCallback(run);
} else {
setTimeout(run, 300);
}
}
document.addEventListener('click', this.closeDropdowns);

document.addEventListener("click", this.closeDropdowns);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
Expand Down
89 changes: 42 additions & 47 deletions frontend/src/router/index.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
import { createRouter, createWebHistory } from "vue-router";
import store from "@/store";
import LoginView from "@/views/Authentication/LoginPage.vue";
import SignUp from "@/views/Authentication/SignUpPage.vue";
import Home from "@/views/Home/HomePage.vue";
import ChatPage from "@/views/Chat/ChatPage.vue";
import SideBar from "@/components/Basic/SideBar.vue";
import PricingPage from "@/views/Unused/PricingPage.vue";
import AboutTechnologyPage from "@/views/Overview/AboutTechnologyPage.vue";
import StockSimulator from "@/views/FinInvest/StockSimulatorPage.vue";
import RiskAnalysis from "@/views/FinManage/RiskAnalysisPage.vue";
import GoalPage from "@/views/FinManage/GoalPage.vue";
import MarketDataCenter from "@/views/FinManage/SuperInvestorMarketDataCenter.vue";
import ProfilePage from "@/views/Home/ProfilePage.vue";
import MortgageCalc from "@/views/FinManage/MortgageCalculatorPage.vue";
import SuperInvestors from "@/views/FinManage/SuperInvestorsPage.vue";
import InvestorDetail from "@/views/FinManage/SuperInvestorsInvestorsDetail.vue";
import ForgotPassword from "@/views/Authentication/ForgotPasswordPage.vue";
import InvestmentCalculator from "@/views/FinManage/InvestmentCalculatorPage.vue";
import FundLetterPage from "@/views/FinInvest/FundLetterPage.vue";
import NotificationCenter from "@/views/Home/NotificationCenter.vue";
import SubscriptionPage from "@/views/Subscription/SubscriptionPage.vue";

import CalculatorsPage from "@/views/FinManage/CalculatorsPage.vue";
const LoginView = () => import("@/views/Authentication/LoginPage.vue");
const SignUp = () => import("@/views/Authentication/SignUpPage.vue");
const Home = () => import("@/views/Home/HomePage.vue");
const ChatPage = () => import("@/views/Chat/ChatPage.vue");
const SideBar = () => import("@/components/Basic/SideBar.vue");
const PricingPage = () => import("@/views/Unused/PricingPage.vue");
const AboutTechnologyPage = () =>
import("@/views/Overview/AboutTechnologyPage.vue");
const StockSimulator = () => import("@/views/FinInvest/StockSimulatorPage.vue");
const RiskAnalysis = () => import("@/views/FinManage/RiskAnalysisPage.vue");
const GoalPage = () => import("@/views/FinManage/GoalPage.vue");
const MarketDataCenter = () =>
import("@/views/FinManage/SuperInvestorMarketDataCenter.vue");
const ProfilePage = () => import("@/views/Home/ProfilePage.vue");
const MortgageCalc = () =>
import("@/views/FinManage/MortgageCalculatorPage.vue");
const SuperInvestors = () =>
import("@/views/FinManage/SuperInvestorsPage.vue");
const InvestorDetail = () =>
import("@/views/FinManage/SuperInvestorsInvestorsDetail.vue");
const ForgotPassword = () =>
import("@/views/Authentication/ForgotPasswordPage.vue");
const FundLetterPage = () => import("@/views/FinInvest/FundLetterPage.vue");
const NotificationCenter = () =>
import("@/views/Home/NotificationCenter.vue");
const SubscriptionPage = () =>
import("@/views/Subscription/SubscriptionPage.vue");
const CalculatorsPage = () =>
import("@/views/FinManage/CalculatorsPage.vue");

const routes = [
{
Expand All @@ -30,8 +38,8 @@ const routes = [
component: Home,
},
{
path: "/*",
component: 404,
path: "/:pathMatch(.*)*",
redirect: "/",
},
{
path: "/login",
Expand All @@ -50,6 +58,7 @@ const routes = [
default: ChatPage,
sidebar: SideBar,
},
meta: { requiresAuth: true },
},
{
path: "/tech",
Expand Down Expand Up @@ -80,6 +89,7 @@ const routes = [
path: "/goal",
name: "GoalPage",
component: GoalPage,
meta: { requiresAuth: true },
},
{
path: "/market",
Expand All @@ -90,6 +100,7 @@ const routes = [
path: "/profile",
name: "Profile",
component: ProfilePage,
meta: { requiresAuth: true },
},
{
path: "/calculators",
Expand Down Expand Up @@ -128,6 +139,7 @@ const routes = [
path: "/notifications",
name: "NotificationCenter",
component: NotificationCenter,
meta: { requiresAuth: true },
},
{
path: "/subscribe",
Expand All @@ -141,35 +153,18 @@ const router = createRouter({
routes,
});

// Add navigation guard
router.beforeEach(async (to, from, next) => {
console.log(
"Router guard - navigating to:",
to.path,
"requires auth:",
to.meta.requiresAuth
);
const needsAuth = Boolean(to.meta.requiresAuth);

if (!store.getters["users/isAuthenticated"]) {
if (needsAuth && !store.state.users.authChecked) {
await store.dispatch("users/fetchCurrentUser");
}

console.log(
"Router guard - authenticated:",
store.getters["users/isAuthenticated"]
);

// Check if route requires authentication
if (to.meta.requiresAuth && !store.getters["users/isAuthenticated"]) {
console.log(
"Router guard - redirecting to login with redirect:",
to.fullPath
);
// Redirect to login page
next({ name: "Login", query: { redirect: to.fullPath } });
} else {
next();
if (needsAuth && !store.getters["users/isAuthenticated"]) {
return next({ name: "Login", query: { redirect: to.fullPath } });
}

next();
});

export default router;
export default router;
8 changes: 7 additions & 1 deletion netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@
NODE_VERSION = "20"
NPM_FLAGS = "--legacy-peer-deps"
NODE_OPTIONS = "--no-warnings"

[[headers]]
for = "/*" # Applies to all paths; you can scope to specific routes like "/api/*" if needed
[headers.values]
Content-Security-Policy = "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self' https: data:; connect-src 'self' https:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self';"
X-Content-Type-Options = "nosniff"
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
Loading