Skip to content

Commit

Permalink
feat(time-preferences): add time grid for users to select study time (#6
Browse files Browse the repository at this point in the history
)

1. Add a button to ProfilePage to jump to time-preferences page.
2. Add a whole time-preference page for time preference selection.

---------

Co-authored-by: ZL Asica <[email protected]>
  • Loading branch information
WelldoneM and ZL-Asica authored Oct 16, 2024
1 parent 611cf0f commit 7fa131c
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import GroupsPage from '@components/GroupsPage';
import HomePage from '@components/HomePage';
import EditProfile from '@components/Profile/EditProfile';
import ProfilePage from '@components/Profile/ProfilePage';
import TimePreferencesPage from '@components/Profile/TimePreferencesPage';
import { ThemeProvider } from '@mui/material/styles';
import { theme } from '@utils/theme';
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
Expand All @@ -25,6 +26,7 @@ const AppContent = ({ currentPage, setCurrentPage }) => {
{/* <Route path="messages" element={<div>TBD</div>} /> */}
<Route path="profile/:id" element={<ProfilePage />} />
<Route path="edit-profile" element={<EditProfile />} />
<Route path="time-preferences" element={<TimePreferencesPage />} />
</Routes>
</div>
{!isEditProfilePage && <Footer currentPage={currentPage} setCurrentPage={setCurrentPage} />}
Expand Down
24 changes: 20 additions & 4 deletions src/components/Profile/ProfilePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export default function ProfilePage() {
setSignOutDialogOpen(true);
};

const handleTimePreferencesClick = () => {
navigate('/time-preferences'); // Navigates to the Time Preferences page
};

if (loading) {
return <CircularProgress />;
}
Expand Down Expand Up @@ -81,7 +85,11 @@ export default function ProfilePage() {
/>
</InfoSection>

<ActionButtons onEditClick={handleEditClick} onSignOutClick={handleSignOutDialogOpen} />
<ActionButtons
onEditClick={handleEditClick}
onSignOutClick={handleSignOutDialogOpen}
onTimePreferencesClick={handleTimePreferencesClick}
/>
<SignOutDialog open={signOutDialogOpen} onClose={() => setSignOutDialogOpen(false)} />
</Box>
);
Expand Down Expand Up @@ -139,7 +147,7 @@ const ContentBox = ({ icon: IconComponent, title, content, isCourses = false })

const CustomDivider = () => <Divider sx={{ my: 1 }} />;

const ActionButtons = ({ onEditClick, onSignOutClick }) => (
const ActionButtons = ({ onEditClick, onSignOutClick, onTimePreferencesClick }) => (
<Box
sx={{
display: 'flex',
Expand All @@ -149,13 +157,21 @@ const ActionButtons = ({ onEditClick, onSignOutClick }) => (
mt: 4,
}}
>
<Button variant="contained" onClick={onEditClick} sx={{ mb: 2, width: '150px' }}>
<Button variant="contained" onClick={onEditClick} sx={{ mb: 2, width: '250px' }}>
Edit Profile
</Button>
<Button
variant="contained"
color="primary"
sx={{ mb: 2, width: '250px' }}
onClick={onTimePreferencesClick}
>
Time Preferences
</Button>
<Button
variant="contained"
color="secondary"
sx={{ width: '150px', backgroundColor: 'secondary.main' }}
sx={{ width: '150px', backgroundColor: 'secondary.main', mt: 2 }}
onClick={onSignOutClick}
>
Sign Out
Expand Down
160 changes: 160 additions & 0 deletions src/components/Profile/TimePreferencesGrid.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, { useState } from 'react';

import {
Box,
Paper,
Typography,
Select,
MenuItem,
FormControl,
InputLabel,
Switch,
FormControlLabel,
useTheme,
} from '@mui/material';

// Generate 12-hour clock with AM/PM
const hours = Array.from({ length: 24 }, (_, i) => {
const hour = i % 12 || 12;
return `${hour} ${i < 12 ? 'AM' : 'PM'}`;
});

const weekdays = ['M', 'T', 'W', 'Th', 'F'];
const weekendDays = ['Sa', 'Su'];

const TimePreferencesGrid = ({ selectedTimes, setSelectedTimes }) => {
const [noEarlierThan, setNoEarlierThan] = useState(8); // Time index for "No earlier than"
const [noLaterThan, setNoLaterThan] = useState(20); // Time index for "No later than"
const [includeWeekends, setIncludeWeekends] = useState(false); // Toggle for showing weekends

const handleSlotClick = (day, hour) => {
const slot = `${day}-${hour}`;
setSelectedTimes((prev) =>
prev.includes(slot) ? prev.filter((time) => time !== slot) : [...prev, slot],
);
};

const theme = useTheme();

// Handle filtering the displayed hours based on the selected limits
const filteredHours = hours.slice(noEarlierThan, noLaterThan + 1);

return (
<Box sx={{ maxWidth: 800, margin: 'auto', padding: 3 }}>
{/* No Earlier Than and No Later Than selectors */}
<Box sx={{ display: 'flex', justifyContent: 'space-between', marginBottom: 2 }}>
<FormControl sx={{ minWidth: 120 }}>
<InputLabel>No earlier than</InputLabel>
<Select
value={noEarlierThan}
label="No earlier than"
onChange={(e) => setNoEarlierThan(e.target.value)}
>
{hours.map((hour, index) => (
<MenuItem key={hour} value={index}>
{hour}
</MenuItem>
))}
</Select>
</FormControl>

<FormControl sx={{ minWidth: 120 }}>
<InputLabel>No later than</InputLabel>
<Select
value={noLaterThan}
label="No later than"
onChange={(e) => setNoLaterThan(e.target.value)}
>
{hours.map((hour, index) => (
<MenuItem key={hour} value={index}>
{hour}
</MenuItem>
))}
</Select>
</FormControl>
</Box>

{/* Toggle for Weekends */}
<Box sx={{ display: 'flex', justifyContent: 'center', marginBottom: 2 }}>
<FormControlLabel
control={
<Switch
checked={includeWeekends}
onChange={(e) => setIncludeWeekends(e.target.checked)}
color="primary"
/>
}
label="Include Weekends"
/>
</Box>

{/* Time Grid */}
<Box
sx={{
display: 'grid',
gridTemplateColumns: `repeat(${includeWeekends ? weekdays.length + weekendDays.length + 1 : weekdays.length + 1}, 1fr)`,
gap: 1,
}}
>
<Box /> {/* Empty cell for alignment */}
{weekdays.map((day) => (
<Typography key={day} variant="subtitle1" align="center">
{day}
</Typography>
))}
{includeWeekends &&
weekendDays.map((day) => (
<Typography key={day} variant="subtitle1" align="center">
{day}
</Typography>
))}
{filteredHours.map((hour) => (
<React.Fragment key={hour}>
<Typography variant="subtitle2" align="center" sx={{ whiteSpace: 'nowrap' }}>
{hour}
</Typography>
{weekdays.map((day) => {
const slot = `${day}-${hour}`;
const isSelected = selectedTimes.includes(slot);

return (
<Paper
key={slot}
onClick={() => handleSlotClick(day, hour)}
sx={{
width: '100%',
height: 30,
backgroundColor: isSelected ? theme.palette.primary.main : 'white',
cursor: 'pointer',
border: '0.5px solid grey',
}}
/>
);
})}
{includeWeekends &&
weekendDays.map((day) => {
const slot = `${day}-${hour}`;
const isSelected = selectedTimes.includes(slot);

return (
<Paper
key={slot}
onClick={() => handleSlotClick(day, hour)}
sx={{
width: '100%',
height: 30,
backgroundColor: isSelected ? theme.palette.primary.main : 'white',
cursor: 'pointer',
border: '0.5px solid grey',
}}
/>
);
})}
</React.Fragment>
))}
</Box>
</Box>
);
};

export default React.memo(TimePreferencesGrid);
29 changes: 29 additions & 0 deletions src/components/Profile/TimePreferencesPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useState } from 'react';

import { Box, Typography, Button } from '@mui/material';

import TimePreferencesGrid from './TimePreferencesGrid';

export default function TimePreferencesPage() {
const [selectedTimes, setSelectedTimes] = useState([]);

const handleSavePreferences = () => {
console.log('Selected Times:', selectedTimes);
};

return (
<Box sx={{ maxWidth: 800, margin: 'auto', padding: 3, alignItems: 'center' }}>
<Typography variant="h4" align="center" gutterBottom>
Time Preferences
</Typography>

<TimePreferencesGrid selectedTimes={selectedTimes} setSelectedTimes={setSelectedTimes} />

<Box sx={{ display: 'flex', justifyContent: 'center', marginTop: 2 }}>
<Button variant="contained" onClick={handleSavePreferences}>
Save Preferences
</Button>
</Box>
</Box>
);
}

0 comments on commit 7fa131c

Please sign in to comment.