Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3f63538
Add font family in one var
OscarFava Oct 8, 2025
38523d0
Merge remote-tracking branch 'origin/develop' into ofava/vidsol-217-g…
OscarFava Oct 13, 2025
ef31ae7
Add custom MUI colors
OscarFava Oct 13, 2025
e43fb97
Clean theme provider and buttons
OscarFava Oct 13, 2025
d12a043
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
c145636
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
de6bccd
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
940ba11
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
a70eeae
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
4e87903
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
f8a8ec4
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
181ebd3
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
101a7dc
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
87d8d53
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
0d2cf2a
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
4f9a4fd
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
e5de09a
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
6a982f9
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
61f1129
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
f78355e
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
42b6c38
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
8db4cf5
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
d48b723
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
1792941
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 13, 2025
5dfed61
Fix test
OscarFava Oct 14, 2025
91f5baa
Fix deprecated
OscarFava Oct 15, 2025
3183b98
Add default font
OscarFava Oct 15, 2025
129dcde
Fix testing
OscarFava Oct 15, 2025
9b6519e
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
92f4367
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
41106dc
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
e170aeb
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
5b6fade
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
5ed4809
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
1a60234
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
db03a2c
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
5ca89ad
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
c33c15f
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
f52967a
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
c1c9b91
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
30b440a
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
1654453
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
a3174fb
Commit screenshot file: integration-tests/tests/visualComparisons.spe…
github-actions[bot] Oct 15, 2025
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
63 changes: 34 additions & 29 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import './css/App.css';
import './css/index.css';
import { CssBaseline, ThemeProvider } from '@mui/material';
import Room from './pages/MeetingRoom/index';
import GoodBye from './pages/GoodBye/index';
import WaitingRoom from './pages/WaitingRoom';
Expand All @@ -11,38 +12,42 @@ import { PublisherProvider } from './Context/PublisherProvider';
import RedirectToWaitingRoom from './components/RedirectToWaitingRoom';
import UnsupportedBrowserPage from './pages/UnsupportedBrowserPage';
import RoomContext from './Context/RoomContext';
import customTheme from './utils/customTheme/customTheme';

const App = () => {
return (
<Router>
<Routes>
<Route element={<RoomContext />}>
<Route
path="/waiting-room/:roomName"
element={
<PreviewPublisherProvider>
<WaitingRoom />
</PreviewPublisherProvider>
}
/>
<Route
path="/room/:roomName"
element={
<SessionProvider>
<RedirectToWaitingRoom>
<PublisherProvider>
<Room />
</PublisherProvider>
</RedirectToWaitingRoom>
</SessionProvider>
}
/>
</Route>
<Route path="/goodbye" element={<GoodBye />} />
<Route path="*" element={<LandingPage />} />
<Route path="/unsupported-browser" element={<UnsupportedBrowserPage />} />
</Routes>
</Router>
<ThemeProvider theme={customTheme}>
<CssBaseline />
<Router>
<Routes>
<Route element={<RoomContext />}>
<Route
path="/waiting-room/:roomName"
element={
<PreviewPublisherProvider>
<WaitingRoom />
</PreviewPublisherProvider>
}
/>
<Route
path="/room/:roomName"
element={
<SessionProvider>
<RedirectToWaitingRoom>
<PublisherProvider>
<Room />
</PublisherProvider>
</RedirectToWaitingRoom>
</SessionProvider>
}
/>
</Route>
<Route path="/goodbye" element={<GoodBye />} />
<Route path="*" element={<LandingPage />} />
<Route path="/unsupported-browser" element={<UnsupportedBrowserPage />} />
</Routes>
</Router>
</ThemeProvider>
);
};

Expand Down
129 changes: 53 additions & 76 deletions frontend/src/components/WaitingRoom/UserNameInput/UserNameInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { TextField, Button, InputAdornment } from '@mui/material';
import React, { Dispatch, MouseEvent, ReactElement, SetStateAction, useState } from 'react';
import { PersonOutline } from '@mui/icons-material';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import useUserContext from '../../../hooks/useUserContext';
Expand All @@ -15,24 +14,6 @@ export type UserNameInputProps = {
setUsername: Dispatch<SetStateAction<string>>;
};

declare module '@mui/material/styles' {
interface Palette {
blue: Palette['primary'];
}

interface PaletteOptions {
blue?: PaletteOptions['primary'];
}
}

const theme = createTheme({
palette: {
blue: {
main: 'rgba(26,115,232,.9)',
},
},
});

/**
* UsernameInput Component
*
Expand Down Expand Up @@ -94,66 +75,62 @@ const UsernameInput = ({ username, setUsername }: UserNameInputProps): ReactElem
};

return (
<ThemeProvider theme={theme}>
<form className="flex w-full flex-col justify-center px-6 md:relative md:top-[-48px] md:max-w-[480px]">
<div className="mt-4 flex flex-col items-center justify-end">
<div className="mb-2 font-sans text-[28px] leading-8">{t('waitingRoom.title')}</div>
<div className="flex w-full flex-col content-end py-2 text-lg decoration-solid md:max-w-[480px]">
<p className="truncate">{roomName}</p>
</div>
<div className="mt-6 font-sans text-[24px] leading-8">
{t('waitingRoom.user.input.label')}
</div>
<div className="mb-5 flex w-full flex-wrap items-center justify-center">
<TextField
size="small"
margin="dense"
placeholder={t('waitingRoom.user.input.placeholder')}
onChange={onChangeParticipantName}
sx={{
display: 'flex',
width: '100%',
maxWidth: '212px',
marginTop: '20px',
paddingLeft: '0px',
}}
required
id="user-name"
name="Name"
error={isUserNameInvalid}
autoComplete="Name"
autoFocus
value={username}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PersonOutline />
</InputAdornment>
),
inputProps: { maxLength: 60 },
}}
/>
</div>
<Button
onClick={handleJoinClick}
variant="contained"
color="primary"
<form className="flex w-full flex-col justify-center px-6 md:relative md:top-[-48px] md:max-w-[480px]">
<div className="mt-4 flex flex-col items-center justify-end">
<div className="mb-2 text-[28px] leading-8">{t('waitingRoom.title')}</div>
<div className="flex w-full flex-col content-end py-2 text-lg decoration-solid md:max-w-[480px]">
<p className="truncate">{roomName}</p>
</div>
<div className="mt-6 text-[24px] leading-8">{t('waitingRoom.user.input.label')}</div>
<div className="mb-5 flex w-full flex-wrap items-center justify-center">
<TextField
size="small"
margin="dense"
placeholder={t('waitingRoom.user.input.placeholder')}
onChange={onChangeParticipantName}
sx={{
width: '117px',
borderRadius: '24px',
color: 'white',
textTransform: 'none',
fontSize: '14px',
height: '48px',
display: 'flex',
width: '100%',
maxWidth: '212px',
marginTop: '20px',
paddingLeft: '0px',
}}
required
id="user-name"
name="Name"
error={isUserNameInvalid}
autoComplete="Name"
autoFocus
value={username}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PersonOutline />
</InputAdornment>
),
inputProps: { maxLength: 60 },
}}
disabled={!username}
type="submit"
>
{t('button.join')}
</Button>
/>
</div>
</form>
</ThemeProvider>
<Button
onClick={handleJoinClick}
variant="contained"
color="primary"
sx={{
width: '117px',
borderRadius: '24px',
color: 'white',
textTransform: 'none',
fontSize: '14px',
height: '48px',
}}
disabled={!username}
type="submit"
>
{t('button.join')}
</Button>
</div>
</form>
);
};

Expand Down
118 changes: 118 additions & 0 deletions frontend/src/utils/customTheme/customTheme.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { describe, it, expect } from 'vitest';
import customTheme, { colors, fonts, shadows, rgba } from './customTheme';

describe('customTheme', () => {
describe('shadows object', () => {
it('should have all shadow levels defined', () => {
expect(shadows.level1).toContain('0 3px 1px -2px rgba(0,0,0,0.2)');
expect(shadows.level2).toContain('0 2px 4px -1px rgba(0,0,0,0.2)');
expect(shadows.level3).toContain('0 5px 5px -3px rgba(0,0,0,0.2)');
});
});

describe('rgba helper function', () => {
it('should convert hex to rgba correctly', () => {
expect(rgba('#FF0000', 0.5)).toBe('rgba(255, 0, 0, 0.5)');
expect(rgba('#000000', 1)).toBe('rgba(0, 0, 0, 1)');
expect(rgba('#FFFFFF', 0.26)).toBe('rgba(255, 255, 255, 0.26)');
});

it('should handle hex colors with hash', () => {
expect(rgba('#3E007E', 0.04)).toBe('rgba(62, 0, 126, 0.04)');
});
});

describe('MUI theme object', () => {
it('should have correct palette colors', () => {
expect(customTheme.palette.primary.main).toBe(colors.primary);
expect(customTheme.palette.primary.contrastText).toBe(colors.onPrimary);
expect(customTheme.palette.background.default).toBe(colors.background);
expect(customTheme.palette.text.primary).toBe(colors.onBackground);
});

it('should have typography configured', () => {
expect(customTheme.typography.fontFamily).toBe(fonts.family);
});

it('should be in light mode', () => {
expect(customTheme.palette.mode).toBe('light');
});

it('should have correct button primary styles', () => {
const primaryButton = customTheme.components?.MuiButton?.styleOverrides?.containedPrimary;

if (
typeof primaryButton === 'object' &&
primaryButton !== null &&
'backgroundColor' in primaryButton &&
'color' in primaryButton &&
'boxShadow' in primaryButton
) {
expect((primaryButton as { backgroundColor: string }).backgroundColor).toBe(colors.primary);
expect((primaryButton as { color: string }).color).toBe(colors.onPrimary);
expect((primaryButton as { boxShadow: string }).boxShadow).toBe(shadows.level1);
}
});
});

describe('theme structure validation', () => {
it('should have all required theme properties', () => {
expect(customTheme.palette).toBeDefined();
expect(customTheme.components).toBeDefined();
expect(customTheme.typography).toBeDefined();
});

it('should have component overrides for major components', () => {
const { components } = customTheme;
expect(components?.MuiAppBar).toBeDefined();
expect(components?.MuiPaper).toBeDefined();
expect(components?.MuiTextField).toBeDefined();
expect(components?.MuiTooltip).toBeDefined();
});
});

describe('color consistency', () => {
it('should use consistent primary color across components', () => {
const buttonPrimary = customTheme.components?.MuiButton?.styleOverrides?.containedPrimary;
const outlinedPrimary = customTheme.components?.MuiButton?.styleOverrides?.outlinedPrimary;
const textPrimary = customTheme.components?.MuiButton?.styleOverrides?.textPrimary;

if (
typeof buttonPrimary === 'object' &&
buttonPrimary !== null &&
'backgroundColor' in buttonPrimary &&
typeof outlinedPrimary === 'object' &&
outlinedPrimary !== null &&
'color' in outlinedPrimary &&
typeof textPrimary === 'object' &&
textPrimary !== null &&
'color' in textPrimary
) {
expect((buttonPrimary as { backgroundColor: string }).backgroundColor).toBe(colors.primary);
expect((outlinedPrimary as { color: string }).color).toBe(colors.primary);
expect((textPrimary as { color: string }).color).toBe(colors.primary);
}
});

it('should use consistent surface colors', () => {
const appBar = customTheme.components?.MuiAppBar?.styleOverrides?.root;
const paper = customTheme.components?.MuiPaper?.styleOverrides?.root;

if (
typeof appBar === 'object' &&
appBar !== null &&
typeof paper === 'object' &&
paper !== null
) {
if (typeof appBar === 'object' && appBar !== null && 'backgroundColor' in appBar) {
expect((appBar as { backgroundColor: string }).backgroundColor).toBe(colors.surface);
}
if (typeof paper === 'object' && paper !== null && 'backgroundColor' in paper) {
expect((paper as { backgroundColor: string }).backgroundColor).toBe(
colors.surfaceContainer
);
}
}
});
});
});
Loading
Loading