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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2,272 changes: 1,251 additions & 1,021 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function App() {
const isDark = theme === "dark";

return (
<Router>
<Router future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
<ScrollToTop>
<LoadingProvider>
<div
Expand Down
43 changes: 43 additions & 0 deletions client/src/components/ErrorBoundary.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}

static getDerivedStateFromError(error) {
return { hasError: true, error };
}

componentDidCatch(error, errorInfo) {
console.error('ErrorBoundary caught an error:', error, errorInfo);
}

render() {
if (this.state.hasError) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="text-center p-8">
<h1 className="text-2xl font-bold text-gray-800 mb-4">
Something went wrong
</h1>
<p className="text-gray-600 mb-4">
There was an error loading the application.
</p>
<button
onClick={() => window.location.reload()}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Reload Page
</button>
</div>
</div>
);
}

return this.props.children;
}
}

export default ErrorBoundary;
2 changes: 1 addition & 1 deletion client/src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import NewsletterSubscribeInput from "./NewsletterSubscribeInput";
const Footer = () => {
const [visitorCount, setVisitorCount] = useState(0);
useEffect(() => {
fetch(`${import.meta.env.VITE_SERVER_API}/api/v1/auth/`)
fetch(`${import.meta.env.VITE_SERVER_API}/api/v1/auth`)
.then(async res => {
const data = await res.json();
setVisitorCount(data.visitorCount); // Set state here
Expand Down
13 changes: 12 additions & 1 deletion client/src/context/QuestionContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,20 @@ export function QuestionsProvider({ children }) {
const [sort, setSort] = useState("latest");

const API = import.meta.env.VITE_SERVER_API;
const token = localStorage.getItem("token");
const [token, setToken] = useState(localStorage.getItem("token"));
const userId = getUserIdFromToken(token);

// Listen for token changes
useEffect(() => {
const handleStorageChange = () => {
const newToken = localStorage.getItem("token");
setToken(newToken);
};

window.addEventListener('storage', handleStorageChange);
return () => window.removeEventListener('storage', handleStorageChange);
}, []);

const getAuthHeader = () =>
token ? { Authorization: `Bearer ${token}` } : {};

Expand Down
80 changes: 39 additions & 41 deletions client/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,57 +9,55 @@ import { ThemeProvider } from "./context/ThemeContext.jsx";
import { AuthProvider } from "./store/auth.jsx";
import { PopupProvider } from "./context/PopupContext.jsx";
import { QuestionsProvider } from "./context/QuestionContext.jsx";
import ErrorBoundary from "./components/ErrorBoundary.jsx";

// Toast notifications
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css"; // Correct import path

ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ThemeProvider>
<AuthProvider>
<PopupProvider>
<QuestionsProvider>
<App />
<ToastContainer
position="top-right"
autoClose={2500}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="dark"
/>
</QuestionsProvider>
</PopupProvider>
</AuthProvider>
</ThemeProvider>
<ErrorBoundary>
<ThemeProvider>
<AuthProvider>
<PopupProvider>
<QuestionsProvider>
<App />
<ToastContainer
position="top-right"
autoClose={2500}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="dark"
/>
</QuestionsProvider>
</PopupProvider>
</AuthProvider>
</ThemeProvider>
</ErrorBoundary>
</React.StrictMode>
);

// ✅ Register service worker for PWA support
if ("serviceWorker" in navigator) {
// Only register in production (Netlify, etc.)
if (import.meta.env.MODE === "production") {
window.addEventListener("load", () => {
const swUrl = `${window.location.origin}/service-worker.js`;
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
console.log("✅ Service Worker registered with scope:", registration.scope);
})
.catch((error) => {
console.error("❌ Service Worker registration failed:", error);
// Optional fallback
navigator.serviceWorker
.register("./service-worker.js")
.then((fallbackRegistration) => {
console.log("✅ Fallback SW registered with scope:", fallbackRegistration.scope);
})
.catch((err) => console.error("Fallback SW failed:", err));
// ✅ Register service worker for PWA support (only in production)
if (import.meta.env.PROD && "serviceWorker" in navigator) {
window.addEventListener("load", () => {
// Use the correct base path based on environment
const swUrl = `${window.location.origin}/service-worker.js`;
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
console.log("Service Worker registered with scope:", registration.scope);
})
.catch((error) => {
console.error("Service Worker registration failed:", error);
// Fallback to relative path
navigator.serviceWorker.register('./service-worker.js').then(fallbackRegistration => {
console.log("Service Worker registered with fallback:", fallbackRegistration.scope);
});
});
} else {
Expand Down
Loading