From 327ab8592a08489d9b2978ce28a652e25263858d Mon Sep 17 00:00:00 2001 From: tylen Date: Sun, 2 Nov 2025 01:15:02 +0200 Subject: [PATCH] add attendance --- backend/src/user.py | 58 +++++++++++++++++++++++- frontend/src/components/Attendance.tsx | 42 +++++++++++++++++ frontend/src/components/InitialSetup.tsx | 23 ++++++++-- frontend/src/utils/fetchUser.tsx | 52 ++++++++++++++++++++- 4 files changed, 168 insertions(+), 7 deletions(-) diff --git a/backend/src/user.py b/backend/src/user.py index 2b85c48..132e58b 100644 --- a/backend/src/user.py +++ b/backend/src/user.py @@ -77,7 +77,6 @@ def registerUserEndpoints(app, database): def validate_token(): data = request.json token = data.get('token') - user_name = data.get('userName') query = "SELECT * FROM sessions WHERE Token=%s" try: result = database.query(query, params=(token,)) @@ -85,3 +84,60 @@ def registerUserEndpoints(app, database): return jsonify(userName=result[0][1], tokenValid=True), 200 except Exception as e: return jsonify(success=False, message=str(e)), 500 + + @app.route('/users/attendance', methods=['PUT']) + def update_attendance(): + data = request.json + token = data.get('token') + attendance_status = data.get('attendance') # Get attendance status from the request data + + if attendance_status is None: + return jsonify(success=False, message="Attendance status is required"), 400 + + query_session = "SELECT * FROM sessions WHERE Token=%s" + try: + result = database.query(query_session, params=(token,)) + if not result: + return jsonify(success=False, message="Token is invalid or expired"), 401 + + user_name = result[0][1] + attendance_query = "UPDATE users SET Attendance = %s WHERE Name = %s" + update_result = database.query(attendance_query, params=(attendance_status, user_name)) + + return jsonify(success=True, message="Attendance updated successfully"), 200 + + except Exception as e: + return jsonify(success=False, message=str(e)), 500 + + @app.route('/users/attendance', methods=['GET']) + def get_attendance(): + token = request.args.get('token') + + if not token: + return jsonify(success=False, message="Token is required"), 400 + + query_session = "SELECT * FROM sessions WHERE Token=%s" + + try: + result = database.query(query_session, params=(token,)) + if not result: + return jsonify(success=False, message="Token is invalid or expired"), 401 + + user_name = result[0][1] + + attendance_query = "SELECT Attendance FROM users WHERE Name = %s" + attendance_result = database.query(attendance_query, params=(user_name,)) + + if not attendance_result: + return jsonify(success=False, message="User not found"), 404 + + attendance_status = attendance_result[0][0] + + return jsonify(success=True, attendance=bool(attendance_status)), 200 + + except Exception as e: + return jsonify(success=False, message=str(e)), 500 + + + + diff --git a/frontend/src/components/Attendance.tsx b/frontend/src/components/Attendance.tsx index e69de29..f95c358 100644 --- a/frontend/src/components/Attendance.tsx +++ b/frontend/src/components/Attendance.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import useFetchUser from '../utils/fetchUser'; + +const ApologyMessage: React.FC = () => { + const { updateAttendance } = useFetchUser() + const handleButtonClick = async () => { + await updateAttendance(true) + window.location.reload(); + }; + + return ( +
+

+ Нам очень жаль, что ты в этот раз не будешь с нами... Но может ты еще поменяешь свое мнение +

+ +
+ ); +}; + +const styles = { + container: { + position: 'fixed' as 'fixed', + top: 0, + left: 0, + width: '100vw', + height: '100vh', + backgroundColor: 'rgba(0, 0, 0, 1)', + display: 'flex', + flexDirection: 'column' as 'column', + justifyContent: 'center', + alignItems: 'center', + color: '#fff', + zIndex: 1000, + overflow: 'hidden', + } +} + +// Export the component +export default ApologyMessage; diff --git a/frontend/src/components/InitialSetup.tsx b/frontend/src/components/InitialSetup.tsx index 997162f..e8e1d70 100644 --- a/frontend/src/components/InitialSetup.tsx +++ b/frontend/src/components/InitialSetup.tsx @@ -3,6 +3,7 @@ import { useCookies } from 'react-cookie'; import { GUESTS } from '../constants/constants'; import useFetchUser from '../utils/fetchUser'; // Import your custom hook import { useNotification } from '../NotificationContext'; +import ApologyMessage from './Attendance'; const InitialSetup = () => { const [cookie, setCookie] = useCookies(); @@ -11,8 +12,9 @@ const InitialSetup = () => { const [isSubmitted, setIsSubmitted] = useState(false); const [password, setPassword] = useState(''); const [isPasswordSet, setIsPasswordSet] = useState(false); // To track if password is set + const [userAttendance, setUserAttendance] = useState(null); - const { userSet, passwordCreate, signUser, validToken } = useFetchUser(); // Destructure functions from the hook + const { userSet, passwordCreate, signUser, validToken, getAttendance } = useFetchUser(); // Destructure functions from the hook const notify = useNotification(); const checkUserPassword = async (name: string) => { @@ -32,8 +34,16 @@ const InitialSetup = () => { setIsSubmitted(isTokenValid); }; + const getUserAttendance = async () => { + const attendance = await getAttendance() + setUserAttendance(attendance) + } + useEffect(() => { - if (cookie.apiToken !== undefined) validateToken(); + if (cookie.apiToken !== undefined) { + getUserAttendance() + validateToken(); + } }, [cookie.apiToken]); @@ -54,13 +64,18 @@ const InitialSetup = () => { } validateToken() }; - - if (isSubmitted) { + if (isSubmitted && userAttendance !== false) { console.log('Selected', selectedName); return null; // or you can redirect to another component or page } + if (userAttendance == false) { + return ( + + ) + } + return (

Выбери себя

diff --git a/frontend/src/utils/fetchUser.tsx b/frontend/src/utils/fetchUser.tsx index 5b8c8a1..d40ad40 100644 --- a/frontend/src/utils/fetchUser.tsx +++ b/frontend/src/utils/fetchUser.tsx @@ -3,7 +3,7 @@ import { API_URL } from '../constants/constants'; import { hashPassword } from './hashPassword'; const useFetchUser = () => { - const [, setApiCookie] = useCookies(['apiToken']); + const [apiCookie, setApiCookie] = useCookies(['apiToken']); const [, setUserNameCookie] = useCookies(['userName']) const userSet = async (userName: string): Promise => { @@ -108,7 +108,55 @@ const useFetchUser = () => { } } - return { userSet, passwordCreate, signUser, validToken }; + const updateAttendance = async (attendanceStatus: boolean): Promise => { + const token = apiCookie.apiToken + try { + const response = await fetch(`${API_URL}/users/attendance`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + token, + attendance: attendanceStatus, + }), + }); + + if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); + const data = await response.json(); + + if (!data.success) throw new Error(data.message); + + return true; // Attendance updated successfully + } catch (error) { + console.error('Error updating attendance:', error); + return false; // Attendance update failed + } + } + + const getAttendance = async (): Promise => { + const token = apiCookie.apiToken + try { + const response = await fetch(`${API_URL}/users/attendance?token=${encodeURIComponent(token)}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }); + + if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); + const data = await response.json(); + + if (!data.success) throw new Error(data.message); + + return data.attendance; // Returns attendance status (true/false) + } catch (error) { + console.error('Error retrieving attendance:', error); + return null; // In case of error or if attendance status is not found + } + } + + return { userSet, passwordCreate, signUser, validToken, updateAttendance, getAttendance }; }; export default useFetchUser;