Skip to content
Merged
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: 3 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
/.react-router/
/build/
**/+types/

# Sentry Config File
.env.sentry-build-plugin
14 changes: 14 additions & 0 deletions client/app/components/ErrorButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function ErrorButton() {
return (
<button
onClick={() => {
throw new Error('This is a test error from the ErrorButton component');
}}
className='mt-4 inline-block px-4 py-2 bg-red-600 text-white rounded hover:bg-red-500 transition-colors'
>
Break the world
</button>
);
}

export default ErrorButton;
10 changes: 8 additions & 2 deletions client/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration, useNavigation } from 'react-router';
import * as Sentry from '@sentry/react';
import { Provider } from 'react-redux';
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration, useNavigation } from 'react-router';

import type { Route } from './+types/routes';
import './app.css';
import { store } from './store/store';
import { LoadingOverlay } from './components/LoadingOverlay';
import { store } from './store/store';

export const links: Route.LinksFunction = () => [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
Expand Down Expand Up @@ -48,6 +49,11 @@ export default function App() {
);
}

const SENTRY_DSN = import.meta.env.VITE_SENTRY_DSN as string;
if (SENTRY_DSN) {
Sentry.init({ dsn: SENTRY_DSN, sendDefaultPii: true });
}

export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = 'Oops!';
let details = 'An unexpected error occurred.';
Expand Down
8 changes: 6 additions & 2 deletions client/app/store/authSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createSlice, createAsyncThunk, type PayloadAction } from '@reduxjs/toolkit';
import { authService, type User, type RegisterData, type LoginData } from '../services/auth';
import { createAsyncThunk, createSlice, type PayloadAction } from '@reduxjs/toolkit';
import * as Sentry from '@sentry/react';
import { authService, type LoginData, type RegisterData, type User } from '../services/auth';

export interface AuthState {
user: User | null;
Expand Down Expand Up @@ -34,6 +35,7 @@ export const loginUser = createAsyncThunk('auth/login', async (data: LoginData,
const response = await authService.login(data);
return response.data;
} catch (error) {
Sentry.captureException(error);
return rejectWithValue((error as Error).message);
}
});
Expand All @@ -42,6 +44,7 @@ export const logoutUser = createAsyncThunk('auth/logout', async (_, { rejectWith
try {
await authService.logout();
} catch (error) {
Sentry.captureException(error);
return rejectWithValue((error as Error).message);
}
});
Expand All @@ -51,6 +54,7 @@ export const fetchProfile = createAsyncThunk('auth/profile', async (_, { rejectW
const user = await authService.getProfile();
return user;
} catch (error) {
Sentry.captureException(error);
return rejectWithValue((error as Error).message);
}
});
Expand Down
10 changes: 8 additions & 2 deletions client/app/welcome/welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useEffect, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../store/hooks';
import { logoutUser } from '../store/authSlice';
import { Link } from 'react-router';
import ErrorButton from '../components/ErrorButton';
import { gamesService, type Game, type UserStats } from '../services/games';
import { logoutUser } from '../store/authSlice';
import { useAppDispatch, useAppSelector } from '../store/hooks';

export function Welcome() {
const dispatch = useAppDispatch();
Expand Down Expand Up @@ -72,6 +73,11 @@ export function Welcome() {
>
Logout
</button>
{import.meta.env.DEV && (
<div className='text-center mt-3'>
<ErrorButton />
</div>
)}
</div>
</div>

Expand Down
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"@react-router/node": "7.12.0",
"@react-router/serve": "7.12.0",
"@reduxjs/toolkit": "^2.11.2",
"@sentry/react": "^10.43.0",
"@sentry/vite-plugin": "^5.1.1",
"chai": "^6.2.2",
"isbot": "^5.1.31",
"mocha": "^11.7.5",
Expand Down
15 changes: 13 additions & 2 deletions client/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { reactRouter } from '@react-router/dev/vite';
import { sentryVitePlugin } from '@sentry/vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import os from 'os';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import os from 'os';

// Helper function to get the first network IP
function getNetworkIP() {
Expand All @@ -27,11 +28,21 @@ const serverUrl =
: (process.env.VITE_SERVER_URL ?? `http://localhost:${serverPort}`);

export default defineConfig({
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
plugins: [
tailwindcss(),
reactRouter(),
tsconfigPaths(),
sentryVitePlugin({ org: '42vienna', project: 'red-tetris' }),
],

envDir: '..',

server: {
host: '0.0.0.0', // Allow external connections
port: clientPort,
},

define: { 'import.meta.env.VITE_SERVER_URL': JSON.stringify(serverUrl) },

build: { sourcemap: true },
});
Loading
Loading