diff --git a/frontend/src/components/CreatePollForm.tsx b/frontend/src/components/CreatePollForm.tsx index 1cb76c5..1d6524b 100644 --- a/frontend/src/components/CreatePollForm.tsx +++ b/frontend/src/components/CreatePollForm.tsx @@ -50,8 +50,14 @@ const CreatePollForm = () => { optionTwo: optionTwo, userId: user.id, }), - ); - navigate('/'); // Redirect to home page after form submission + ) + .unwrap() + .then(() => { + navigate('/'); // Redirect to home page after form submission + }) + .catch(error => { + console.error('Failed to create poll', error); + }); }; // Render form for creating a new poll diff --git a/frontend/src/components/SignupForm.tsx b/frontend/src/components/SignupForm.tsx index b87db3d..75f79df 100644 --- a/frontend/src/components/SignupForm.tsx +++ b/frontend/src/components/SignupForm.tsx @@ -10,11 +10,67 @@ const SignupForm = () => { const [password, setPassword] = useState(''); const [name, setName] = useState(''); const [avatarUrl, setAvatarUrl] = useState(''); + const [errors, setErrors] = useState({ + username: '', + password: '', + name: '', + }); const dispatch: AppDispatch = useDispatch(); const navigate = useNavigate(); + const validateField = (field: string, value: string) => { + switch (field) { + case 'username': + if (!value.trim()) return 'Username is required'; + return ''; + case 'password': + if (value.length < 6) + return 'Password must be at least 6 characters long'; + return ''; + case 'name': + if (!value.trim()) return 'Name is required'; + return ''; + default: + return ''; + } + }; + + const handleChange = (field: string, value: string) => { + const error = validateField(field, value); + setErrors(prev => ({ ...prev, [field]: error })); + switch (field) { + case 'username': + setUsername(value); + break; + case 'password': + setPassword(value); + break; + case 'name': + setName(value); + break; + case 'avatarUrl': + setAvatarUrl(value); + break; + default: + break; + } + }; + const handleSignup = async (event: React.FormEvent) => { event.preventDefault(); + const usernameError = validateField('username', username); + const passwordError = validateField('password', password); + const nameError = validateField('name', name); + + if (usernameError || passwordError || nameError) { + setErrors({ + username: usernameError, + password: passwordError, + name: nameError, + }); + return; // prevent submission if errors + } + dispatch(registerUser({ username, password, name, avatar_url: avatarUrl })) .unwrap() .then(() => { @@ -38,7 +94,9 @@ const SignupForm = () => { label="Username" variant="outlined" value={username} - onChange={e => setUsername(e.target.value)} + onChange={e => handleChange('username', e.target.value)} + error={!!errors.username} + helperText={errors.username} required sx={{ mb: 2 }} /> @@ -48,7 +106,9 @@ const SignupForm = () => { type="password" variant="outlined" value={password} - onChange={e => setPassword(e.target.value)} + onChange={e => handleChange('password', e.target.value)} + error={!!errors.password} + helperText={errors.password} required sx={{ mb: 2 }} /> @@ -57,7 +117,9 @@ const SignupForm = () => { label="Name" variant="outlined" value={name} - onChange={e => setName(e.target.value)} + onChange={e => handleChange('name', e.target.value)} + error={!!errors.name} + helperText={errors.name} required sx={{ mb: 2 }} /> diff --git a/frontend/src/features/pollSlice.ts b/frontend/src/features/pollSlice.ts index 9f5950d..1971181 100644 --- a/frontend/src/features/pollSlice.ts +++ b/frontend/src/features/pollSlice.ts @@ -159,7 +159,13 @@ const pollSlice = createSlice({ .addCase(addNewPoll.fulfilled, (state, action) => { state.status = 'succeeded'; if (action.payload) { - state.polls[action.payload.id] = action.payload; + // Add a new field `votes` initialized as an empty list to the payload + const newPoll = { + ...action.payload, // Spread existing payload properties + votes: [], // Initialize votes as an empty list + }; + // Assign the new poll object to the state.polls under the specific id + state.polls[action.payload.id] = newPoll; } }) .addCase(addNewPoll.rejected, (state, action) => { diff --git a/frontend/src/features/usersSlice.ts b/frontend/src/features/usersSlice.ts index a4cc6db..17f7c8d 100644 --- a/frontend/src/features/usersSlice.ts +++ b/frontend/src/features/usersSlice.ts @@ -3,10 +3,11 @@ import { fetchUsers as fetchUsersApi, loginUser as loginUserApi, registerUser as registerUserApi, - clearToken + clearToken, } from '../server/api'; import { jwtDecode } from 'jwt-decode'; import { RootState } from '../app/store'; +import { addNewPoll, voteOnPoll } from './pollSlice'; // Define the user interface for the state export interface User { @@ -184,6 +185,25 @@ export const usersSlice = createSlice({ state.currentUser = action.payload; state.status = 'succeeded'; state.error = undefined; + }) + // POLL & VOTE UPDATES + .addCase(addNewPoll.fulfilled, (state, action) => { + const userId = action.payload.userId; + state.users = state.users.map(user => { + if (user.id === userId) { + return { ...user, pollCount: (user.pollCount || 0) + 1 }; + } + return user; + }); + }) + .addCase(voteOnPoll.fulfilled, (state, action) => { + const userId = action.payload.userId; + state.users = state.users.map(user => { + if (user.id === userId) { + return { ...user, voteCount: (user.voteCount || 0) + 1 }; + } + return user; + }); }); }, });