Skip to content

Commit

Permalink
Check-In Frontend
Browse files Browse the repository at this point in the history
create/update/retrive
  • Loading branch information
dhrumilp12 committed Jun 18, 2024
1 parent 6097ccf commit 381454c
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 3 deletions.
5 changes: 5 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Navbar from './Components/navBar';
import ChatInterface from './Components/chatInterface';
import MoodLogging from './Components/moodLogging';
import MoodLogs from './Components/moodLogs';
import CheckInForm from './Components/checkInForm';
import CheckInsList from './Components/checkInsList';
import { CssBaseline, Box } from '@mui/material';
import { UserContext } from './Components/userContext';

Expand All @@ -30,6 +32,9 @@ function App() {
<Route path="/user/profile/:userId" element={<UserProfile />} />
<Route path="/user/mood_logging" element={<MoodLogging />} />
<Route path="/user/mood_logs" element={<MoodLogs />} />
<Route path="/user/check_in" element={<CheckInForm userId={user?.userId} checkInId="" update={false} />} />
<Route path="/user/check_in/:checkInId" element={<CheckInForm userId={user?.userId} update={true} />} />
<Route path="/user/check_ins/:userId" element={<CheckInsList />} />
</Routes>
</Layout>

Expand Down
90 changes: 90 additions & 0 deletions client/src/Components/checkInForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState } from 'react';
import axios from 'axios';
import PropTypes from 'prop-types';
import {
Button,
Checkbox,
FormControl,
FormControlLabel,
InputLabel,
MenuItem,
Select,
TextField,
Box,
Tooltip,
} from '@mui/material';


function CheckInForm({ userId, checkInId, update }) {
const [checkInTime, setCheckInTime] = useState('');
const [frequency, setFrequency] = useState('daily');
const [notify, setNotify] = useState(false);


const handleSubmit = async (event) => {
event.preventDefault();
const url = update ? `/api/checkIn/update/${checkInId}` : '/api/checkIn/schedule';
const method = update ? 'patch' : 'post';
const data = { user_id: userId, check_in_time: checkInTime, frequency, notify };
console.log('Submitting:', data);
try {
const response = await axios[method](url, data);
console.log('Success:', response.data.message);
// Optionally reset form or handle next steps
} catch (error) {
console.error('Error:', error.response?.data || error);
}
};

return (
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 4, padding: 3, borderRadius: 2, boxShadow: 3 }}>
<TextField
id="datetime-local"
label="Check-in Time"
type="datetime-local"
fullWidth
value={checkInTime}
onChange={e => setCheckInTime(e.target.value)}
sx={{ marginBottom: 3 }}
InputLabelProps={{
shrink: true,
}}
required
helperText="Select the date and time for your check-in."
/>
<FormControl fullWidth sx={{ marginBottom: 3 }}>
<InputLabel id="frequency-label">Frequency</InputLabel>
<Select
labelId="frequency-label"
id="frequency"
value={frequency}
label="Frequency"
onChange={e => setFrequency(e.target.value)}
>
<MenuItem value="daily">Daily</MenuItem>
<MenuItem value="weekly">Weekly</MenuItem>
<MenuItem value="monthly">Monthly</MenuItem>
</Select>
<Tooltip title="Choose how often you want the check-ins to occur">
<i className="fas fa-info-circle" />
</Tooltip>
</FormControl>
<FormControlLabel
control={<Checkbox checked={notify} onChange={e => setNotify(e.target.checked)} color="primary" />}
label="Notify me"
sx={{ marginBottom: 2 }}
/>
<Button type="submit" fullWidth variant="contained" color="primary" sx={{ mt: 2, mb: 2, padding: '10px 0' }}>
{update ? 'Update Check-In' : 'Schedule Check-In'}
</Button>
</Box>
);
}

CheckInForm.propTypes = {
userId: PropTypes.string.isRequired,
checkInId: PropTypes.string,
update: PropTypes.bool.isRequired,
};

export default CheckInForm;
68 changes: 68 additions & 0 deletions client/src/Components/checkInsList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useState, useEffect} from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import { List, ListItem, ListItemText, Paper, Typography } from '@mui/material';

function CheckInsList() {
const { userId } = useParams(); // Assuming 'user' has 'userId'
const [checkIns, setCheckIns] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');

useEffect(() => {
const fetchCheckIns = async () => {
if (!userId) {
setError('User not logged in');
return;
}
setLoading(true);
try {
const response = await axios.get(`/api/checkIn/retrieveAll?user_id=${userId}`);
console.log("API Response:", response.data); // Confirm what you receive

// Validate if data is an array and has the correct structure
if (Array.isArray(response.data) && response.data.every(item => item._id && item._id.$oid && item.check_in_time && item.check_in_time.$date)) {
const formattedCheckIns = response.data.map(checkIn => ({
...checkIn,
_id: checkIn._id.$oid,
check_in_time: new Date(checkIn.check_in_time.$date).toLocaleString(), // Convert date from MongoDB format to a readable string
}));
setCheckIns(formattedCheckIns);
} else {
console.error('Data received is not in expected array format:', response.data);
setError('Unexpected data format');
}
setLoading(false);
} catch (err) {
console.error("Error during fetch:", err);
setError(err.message);
setLoading(false);
}
};

fetchCheckIns();
}, [userId]);


if (!userId) return <Typography variant="h6">Please log in to see your check-ins.</Typography>;
if (loading) return <Typography variant="h6">Loading...</Typography>;
if (error) return <Typography variant="h6">Error: {error}</Typography>;

return (
<Paper style={{ margin: 16, padding: 16 }}>
<Typography variant="h5" style={{ marginBottom: 16 }}>Your Check-Ins</Typography>
<List>
{checkIns.length > 0 ? checkIns.map(checkIn => (
<ListItem key={checkIn._id} divider>
<ListItemText
primary={`Check-In Time: ${checkIn.check_in_time}`}
secondary={`Frequency: ${checkIn.frequency}`}
/>
</ListItem>
)) : <ListItem><ListItemText primary="No check-ins found" /></ListItem>}
</List>
</Paper>
);
}

export default CheckInsList;
6 changes: 5 additions & 1 deletion client/src/Components/sideBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import DeckIcon from '@mui/icons-material/Deck';
import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'; // Icon for mood logging
import ListAltIcon from '@mui/icons-material/ListAlt'; // Icon for mood logs
import ExitToAppIcon from '@mui/icons-material/ExitToApp';
import EventAvailableIcon from '@mui/icons-material/EventAvailable';
import ScheduleIcon from '@mui/icons-material/Schedule';
import { UserContext } from './userContext';
import { NavLink, useLocation } from 'react-router-dom';

const drawerWidth = 230;

function Sidebar() {
const { logout } = useContext(UserContext);
const { logout, user } = useContext(UserContext);
const location = useLocation(); // This hook returns the location object that represents the current URL.

const isActive = (path) => location.pathname === path; // This function checks if the current path is the same as the path passed as an argument.
Expand Down Expand Up @@ -40,6 +42,8 @@ function Sidebar() {
{ text: "Mind Chat", icon: <DeckIcon />, path: "/" },
{ text: "Track Your Vibes", icon: <InsertEmoticonIcon />, path: "/user/mood_logging" },
{ text: "Mood Logs", icon: <ListAltIcon />, path: "/user/mood_logs" },
{ text: "Schedule Check-In", icon: <ScheduleIcon />, path: "/user/check_in" }, // New item for check-in page
{ text: "Check-In Reporting", icon: <EventAvailableIcon />, path: `/user/check_ins/${user?.userId}` } // Dynamically inserting userId
].map((item) => (
<NavLink to={item.path} key={item.text} style={{ textDecoration: 'none', color: 'inherit' }}>
<ListItem button sx={{
Expand Down
1 change: 1 addition & 0 deletions client/src/Components/userContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const UserProvider = ({ children }) => {
useEffect(() => {
const savedUser = localStorage.getItem('user');
if (savedUser) {
console.log('Loaded user from storage:', savedUser);
setUser(JSON.parse(savedUser));
}
}, []);
Expand Down
47 changes: 45 additions & 2 deletions server/routes/checkIn.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from flask import Blueprint, request, jsonify
from flask import Blueprint, request, jsonify, current_app,Response
from datetime import datetime, timedelta
from pydantic import ValidationError
from models.check_in import CheckIn, Frequency
from dotenv import load_dotenv
from services.azure_mongodb import MongoDBClient
from bson import ObjectId
from bson import ObjectId,json_util
from pymongo import ReturnDocument
from bson.errors import InvalidId
from .scheduler_main import scheduler
Expand Down Expand Up @@ -95,6 +95,49 @@ def update_check_in(check_in_id):
except Exception as e:
return jsonify({'error': str(e)}), 500

@checkIn_routes.get('/checkIn/retrieve/<check_in_id>')
def retrieve_check_in(check_in_id):
try:
check_in = db.check_ins.find_one({'_id': ObjectId(check_in_id)})
if check_in:
return jsonify(check_in), 200
else:
return jsonify({'message': 'Check-in not found'}), 404
except InvalidId:
return jsonify({'error': 'Invalid check-in ID format'}), 400
except Exception as e:
return jsonify({'error': str(e)}), 500

@checkIn_routes.delete('/checkIn/delete/<check_in_id>')
def delete_check_in(check_in_id):
try:
result = db.check_ins.delete_one({'_id': ObjectId(check_in_id)})
if result.deleted_count:
return jsonify({'message': 'Check-in deleted successfully'}), 200
else:
return jsonify({'message': 'Check-in not found'}), 404
except InvalidId:
return jsonify({'error': 'Invalid check-in ID format'}), 400
except Exception as e:
return jsonify({'error': str(e)}), 500

@checkIn_routes.get('/checkIn/retrieveAll')
def retrieve_all_check_ins():
user_id = request.args.get('user_id')
if not user_id:
return jsonify({'error': 'User ID is required'}), 400

try:
check_ins = db.check_ins.find({'user_id': user_id})
check_ins_list = list(check_ins) # Convert the cursor to a list
if check_ins_list:
return Response(json_util.dumps(check_ins_list), mimetype='application/json'), 200
else:
return jsonify({'message': 'No check-ins found for the user'}), 404
except Exception as e:
current_app.logger.error(f'Error retrieving check-ins: {str(e)}')
return jsonify({'error': str(e)}), 500


@checkIn_routes.get('/checkIn/missed')
def check_missed_check_ins():
Expand Down

0 comments on commit 381454c

Please sign in to comment.