Skip to content

Commit db39cb3

Browse files
committed
Merge branch 'dev' into feature/ellie
2 parents 5641074 + 98498ab commit db39cb3

21 files changed

+427
-146
lines changed

demo-app/src/client/Components/FunctionalReducerCounter.tsx

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,22 @@ type CounterAction =
2121
| { type: 'DECREMENT' }
2222
| { type: 'DOUBLE' }
2323
| { type: 'RESET' }
24-
| { type: 'ADD'; payload: number };
24+
| { type: 'ADD'; payload: number }
25+
| { type: 'SET_STATE'; payload: CounterState };
2526

26-
// New secondary reducer state and action types
2727
type SecondaryCounterState = {
2828
count: number;
2929
multiplier: number;
3030
lastOperation: string;
31+
history: number[];
3132
};
3233

3334
type SecondaryCounterAction =
3435
| { type: 'MULTIPLY' }
3536
| { type: 'DIVIDE' }
3637
| { type: 'SET_MULTIPLIER'; payload: number }
37-
| { type: 'RESET' };
38+
| { type: 'RESET' }
39+
| { type: 'SET_STATE'; payload: SecondaryCounterState };
3840

3941
function counterReducer(state: CounterState, action: CounterAction, step: number): CounterState {
4042
switch (action.type) {
@@ -72,12 +74,16 @@ function counterReducer(state: CounterState, action: CounterAction, step: number
7274
history: [...state.history, state.count + action.payload],
7375
lastAction: `ADD ${action.payload}`,
7476
};
77+
case 'SET_STATE':
78+
return {
79+
...action.payload,
80+
lastAction: 'SET_STATE',
81+
};
7582
default:
7683
return state;
7784
}
7885
}
7986

80-
// New secondary reducer function
8187
function secondaryCounterReducer(
8288
state: SecondaryCounterState,
8389
action: SecondaryCounterAction,
@@ -87,26 +93,35 @@ function secondaryCounterReducer(
8793
return {
8894
...state,
8995
count: state.count * state.multiplier,
96+
history: [...state.history, state.count * state.multiplier],
9097
lastOperation: `Multiplied by ${state.multiplier}`,
9198
};
9299
case 'DIVIDE':
93100
return {
94101
...state,
95102
count: state.count / state.multiplier,
103+
history: [...state.history, state.count / state.multiplier],
96104
lastOperation: `Divided by ${state.multiplier}`,
97105
};
98106
case 'SET_MULTIPLIER':
99107
return {
100108
...state,
101109
multiplier: action.payload,
110+
history: [...state.history],
102111
lastOperation: `Set multiplier to ${action.payload}`,
103112
};
104113
case 'RESET':
105114
return {
106115
count: 0,
107116
multiplier: 2,
117+
history: [],
108118
lastOperation: 'Reset',
109119
};
120+
case 'SET_STATE':
121+
return {
122+
...action.payload,
123+
lastOperation: 'SET_STATE',
124+
};
110125
default:
111126
return state;
112127
}
@@ -125,7 +140,6 @@ function FunctionalReducerCounter({
125140
const [lastClickTime, setLastClickTime] = useState<Date | null>(null);
126141
const [averageTimeBetweenClicks, setAverageTimeBetweenClicks] = useState<number>(0);
127142

128-
// First reducer
129143
const [state, dispatch] = useReducer(
130144
(state: CounterState, action: CounterAction) => counterReducer(state, action, step),
131145
{
@@ -135,10 +149,10 @@ function FunctionalReducerCounter({
135149
},
136150
);
137151

138-
// Second reducer
139152
const [secondaryState, secondaryDispatch] = useReducer(secondaryCounterReducer, {
140153
count: initialCount,
141154
multiplier: 2,
155+
history: [],
142156
lastOperation: 'none',
143157
});
144158

@@ -152,7 +166,6 @@ function FunctionalReducerCounter({
152166
>
153167
<h2>{title}</h2>
154168

155-
{/* Primary Counter Section */}
156169
<div className='counter-value'>
157170
<h3>Primary Counter: {state.count}</h3>
158171
</div>
@@ -166,7 +179,6 @@ function FunctionalReducerCounter({
166179
</div>
167180

168181
<div className='counter-info'>
169-
<h4>Last Action: {state.lastAction}</h4>
170182
<h4>History:</h4>
171183
<div className='history-list'>
172184
{state.history.map((value, index) => (
@@ -178,7 +190,6 @@ function FunctionalReducerCounter({
178190
</div>
179191
</div>
180192

181-
{/* Secondary Counter Section */}
182193
<div
183194
className='secondary-counter'
184195
style={{ marginTop: '2rem', borderTop: '1px solid #ccc', paddingTop: '1rem' }}
@@ -201,8 +212,16 @@ function FunctionalReducerCounter({
201212
<button onClick={() => secondaryDispatch({ type: 'RESET' })}>Reset</button>
202213
</div>
203214
<div className='counter-info'>
204-
<h4>Last Operation: {secondaryState.lastOperation}</h4>
205215
<h4>Current Multiplier: {secondaryState.multiplier}</h4>
216+
<h4>History:</h4>
217+
<div className='history-list'>
218+
{secondaryState.history.map((value, index) => (
219+
<span key={index}>
220+
{value}
221+
{index < secondaryState.history.length - 1 ? ' → ' : ''}
222+
</span>
223+
))}
224+
</div>
206225
</div>
207226
</div>
208227
</div>

demo-app/src/client/Components/FunctionalStateCounter.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ function FunctionalStateCounter({
8080
</div>
8181

8282
<div className='counter-info'>
83-
<h4>Last Action: {lastAction}</h4>
8483
<h4>History:</h4>
8584
<div className='history-list'>
8685
{history.map((value, index) => (

demo-app/src/client/Components/Home.tsx

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,74 @@
11
import React from 'react';
2+
import { useTheme } from '../../contexts/ThemeContext';
3+
import { useAuth } from '../../contexts/AuthContext';
24

35
function Home(): JSX.Element {
6+
const { theme } = useTheme();
7+
const { user, login, logout } = useAuth();
8+
49
return (
5-
<div className='about'>
10+
<div
11+
className='about'
12+
style={{
13+
backgroundColor: theme.backgroundColor,
14+
color: theme.textColor,
15+
}}
16+
>
617
<h2>REACTIME - DEMO APP</h2>
18+
19+
{user ? (
20+
<div>
21+
<p>Welcome, {user.username}!</p>
22+
<button
23+
onClick={logout}
24+
style={{
25+
backgroundColor: theme.primaryColor,
26+
color: theme.backgroundColor,
27+
padding: '8px 16px',
28+
border: 'none',
29+
borderRadius: '4px',
30+
cursor: 'pointer',
31+
}}
32+
>
33+
Logout
34+
</button>
35+
</div>
36+
) : (
37+
<div>
38+
<p>Please log in:</p>
39+
<button
40+
onClick={() => login('testUser')}
41+
style={{
42+
backgroundColor: theme.primaryColor,
43+
color: theme.backgroundColor,
44+
padding: '8px 16px',
45+
border: 'none',
46+
borderRadius: '4px',
47+
cursor: 'pointer',
48+
}}
49+
>
50+
Login as Test User
51+
</button>
52+
<button
53+
onClick={() => login('admin')}
54+
style={{
55+
backgroundColor: theme.secondaryColor,
56+
color: theme.backgroundColor,
57+
padding: '8px 16px',
58+
border: 'none',
59+
borderRadius: '4px',
60+
marginLeft: '8px',
61+
cursor: 'pointer',
62+
}}
63+
>
64+
Login as Admin
65+
</button>
66+
</div>
67+
)}
68+
769
<p>
870
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
9-
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
10-
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
11-
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
12-
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
13-
</p>
14-
<p>
15-
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
16-
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
17-
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
18-
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
19-
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
71+
ut labore et dolore magna aliqua..."
2072
</p>
2173
</div>
2274
);

demo-app/src/client/Components/ReducerCounter.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ class ReducerCounter extends Component<CounterProps, CounterState> {
123123
</div>
124124

125125
<div className='counter-info'>
126-
<h4>Last Action: {this.state.lastAction}</h4>
127126
<h4>History:</h4>
128127
<div className='history-list'>
129128
{this.state.history.map((value, index) => (
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { useTheme } from '../../contexts/ThemeContext';
3+
4+
const ThemeToggle = (): JSX.Element => {
5+
const { theme, toggleTheme } = useTheme();
6+
7+
return (
8+
<button
9+
onClick={toggleTheme}
10+
style={{
11+
backgroundColor: theme.primaryColor,
12+
color: theme.backgroundColor,
13+
padding: '8px 16px',
14+
border: 'none',
15+
borderRadius: '4px',
16+
cursor: 'pointer',
17+
position: 'fixed',
18+
top: '10px',
19+
right: '10px',
20+
}}
21+
>
22+
Toggle Theme
23+
</button>
24+
);
25+
};
26+
27+
export default ThemeToggle;

demo-app/src/client/Router.tsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
// src/client/Router.tsx
12
import * as React from 'react';
23
import * as ReactDOM from 'react-dom';
34
import { createRoot } from 'react-dom/client';
45
import { BrowserRouter, Routes, Route } from 'react-router-dom';
6+
import { ThemeProvider } from '../contexts/ThemeContext';
7+
import { AuthProvider } from '../contexts/AuthContext';
58
import Nav from './Components/Nav';
69
import Board from './Components/Board';
710
import Home from './Components/Home';
811
import Buttons from './Components/Buttons';
912
import ReducerCounter from './Components/ReducerCounter';
1013
import FunctionalReducerCounter from './Components/FunctionalReducerCounter';
11-
// import ButtonsWithMoreHooks from './Components/ButtonsWithMoreHooks';
1214
import FunctionalStateCounter from './Components/FunctionalStateCounter';
15+
import ThemeToggle from './Components/ThemeToggle';
1316

1417
const domNode = document.getElementById('root');
18+
if (!domNode) throw new Error('Root element not found');
1519
const root = createRoot(domNode);
1620

1721
const CounterPage = () => (
@@ -41,21 +45,18 @@ const CounterPage = () => (
4145
);
4246

4347
root.render(
44-
<BrowserRouter key='BrowserRouter'>
45-
<Nav key='Nav' />
46-
<Routes key='Routes'>
47-
<Route path='/' element={<Home key='Home' />} />
48-
<Route path='/tictactoe' element={<Board key='Board' />} />
49-
{/* Switch between the two "buttons" paths below via commenting/uncommenting to alternate between
50-
the public facing Buttons page and the fiber node hooks research page "ButtonsWithMoreHooks" */}
51-
<Route path='/buttons' element={<Buttons key='Buttons' />} />
52-
{/* <Route path='/buttons' element={<ButtonsWithMoreHooks key='ButtonsWithMoreHooks'/>} /> */}
53-
<Route path='/reducer' element={<CounterPage key='CounterPage' />} />
54-
</Routes>
55-
</BrowserRouter>,
56-
57-
/** Comment out everything above this and uncomment the line below as ButtonsWithMoreHooks import statement to skip all of the
58-
* router components and make fiber node hooks research easier */
59-
60-
// <ButtonsWithMoreHooks/>
48+
<AuthProvider>
49+
<ThemeProvider>
50+
<BrowserRouter>
51+
<ThemeToggle />
52+
<Nav />
53+
<Routes>
54+
<Route path='/' element={<Home />} />
55+
<Route path='/tictactoe' element={<Board />} />
56+
<Route path='/buttons' element={<Buttons />} />
57+
<Route path='/reducer' element={<CounterPage />} />
58+
</Routes>
59+
</BrowserRouter>
60+
</ThemeProvider>
61+
</AuthProvider>,
6162
);

demo-app/src/contexts/AuthContext.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React, { createContext, useState, useContext } from 'react';
2+
3+
type User = {
4+
username: string;
5+
isAdmin: boolean;
6+
} | null;
7+
8+
type AuthContextType = {
9+
user: User;
10+
login: (username: string) => void;
11+
logout: () => void;
12+
};
13+
14+
export const AuthContext = createContext<AuthContextType>({
15+
user: null,
16+
login: () => {},
17+
logout: () => {},
18+
});
19+
20+
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
21+
const [user, setUser] = useState<User>(null);
22+
23+
const login = (username: string) => {
24+
setUser({
25+
username,
26+
isAdmin: username === 'admin',
27+
});
28+
};
29+
30+
const logout = () => {
31+
setUser(null);
32+
};
33+
34+
return <AuthContext.Provider value={{ user, login, logout }}>{children}</AuthContext.Provider>;
35+
};
36+
37+
export const useAuth = () => useContext(AuthContext);

0 commit comments

Comments
 (0)