From c2e6f81775a573c756516dd1015bbc6b002476d3 Mon Sep 17 00:00:00 2001 From: tylen Date: Sun, 2 Nov 2025 15:42:34 +0200 Subject: [PATCH] finalize hosting --- backend/src/hosting.py | 45 +++++++++++++++++++ frontend/src/components/Hosting.tsx | 68 +++++++++++++++++++++++++++-- frontend/src/utils/fetchHosting.tsx | 49 +++++++++++---------- 3 files changed, 135 insertions(+), 27 deletions(-) diff --git a/backend/src/hosting.py b/backend/src/hosting.py index 8f95d07..0789b31 100644 --- a/backend/src/hosting.py +++ b/backend/src/hosting.py @@ -99,3 +99,48 @@ def registerHostingEndpoints(app, database): except Exception as e: return jsonify(success=False, message=str(e)), 500 + @app.route('/hosting/create', methods=['POST']) + def create_and_reserve_item(): + token = request.json.get('token') + name = request.json.get('name') # Name of the item to create + capacity = request.json.get('capacity') # Capacity of the item + + if not token: + return jsonify(success=False, message="Token is required"), 400 + if not name: + return jsonify(success=False, message="Забыл имя"), 400 + if capacity is None: + return jsonify(success=False, message="Забыл количество мест"), 400 + + query_session = "SELECT * FROM sessions WHERE Token=%s" + + try: + # Verify user by token + 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] # Assuming user name is in the second column of session result + + # Check if the item already exists + item_check_query = "SELECT * FROM hosting WHERE Name = %s" + item_check_result = database.query(item_check_query, params=(name,)) + + if item_check_result: # If an item with the same name already exists + return jsonify(success=False, message="Уже существует"), 400 + + # Insert the new item and reserve it for the user + insert_query = """ + INSERT INTO hosting (Name, Capacity, reservedBy) + VALUES (%s, %s, %s) + """ + params = (name, capacity, user_name) # Reserve the item to the user + database.query(insert_query, params=params) + + return jsonify(success=True, message="Создано"), 201 + + except Exception as e: + return jsonify(success=False, message=str(e)), 500 + + + diff --git a/frontend/src/components/Hosting.tsx b/frontend/src/components/Hosting.tsx index 755efc4..4cab4f1 100644 --- a/frontend/src/components/Hosting.tsx +++ b/frontend/src/components/Hosting.tsx @@ -2,6 +2,7 @@ import useFetchHosting from "../utils/fetchHosting"; import { useNotification } from "../NotificationContext"; import { useCookies } from "react-cookie"; import CenteredContainer from "./ChildrenContainer"; +import { useState } from "react"; interface ReserveButtonProps { @@ -49,9 +50,68 @@ const ReserveButton: React.FC = (props) => { ); }; -function Hosting() { +interface CreateHostingFormProps { + createHosting: (token: string, name: string, capacity: number) => void, +} - const { data, error, loading, update, unreserveHosting } = useFetchHosting(); +const CreateHostingForm: React.FC = (props) => { + const { createHosting } = props; + const [name, setName] = useState(''); + const [capacity, setCapacity] = useState(''); + const [tokenCookie] = useCookies(['apiToken']) + const notify = useNotification(); + + const handleSubmit = async () => { + if (!name || !capacity) { + notify('Надо заполнить все поля', 'error') + return + } + try { + await createHosting(tokenCookie.apiToken, name, Number(capacity)); // Call the existing hook + + // Reset form fields + setName(''); + setCapacity(''); + notify('Удалось создать!', 'success') + } catch (error) { + notify(`Не удалось создать: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error'); // Capture any error message + } + } + + return ( +
+
+ +
+
+ +
+ +
+ ); +}; + + +const Hosting = () => { + const { data, error, loading, update, unreserveHosting, createHosting } = useFetchHosting(); return ( <> @@ -91,10 +151,12 @@ function Hosting() {

Таблицу можно скроллить

)} + Если вы хотите организовать себе свои спальные места и хотите, чтобы остальные это видели, вы можете добавить свое месо в таблицу. +

); -} +}; export default Hosting; \ No newline at end of file diff --git a/frontend/src/utils/fetchHosting.tsx b/frontend/src/utils/fetchHosting.tsx index a373031..674b674 100644 --- a/frontend/src/utils/fetchHosting.tsx +++ b/frontend/src/utils/fetchHosting.tsx @@ -2,29 +2,6 @@ import { useState, useEffect } from 'react'; import type { Hosting } from '../types'; import { API_URL } from '../constants/constants'; -// const mockData: Hosting = { -// 1: { -// reservedBy: "", -// name: "Матрац 160см", -// capacity: 2 -// }, -// 2: { -// reservedBy: "", -// name: "Кровать 120см", -// capacity: 2 -// }, -// 3: { -// reservedBy: "", -// name: "Матрац 90см", -// capacity: 1 -// }, -// 4: { -// reservedBy: "", -// name: "Диван", -// capacity: 1 -// }, -// }; - const useFetchHosting = () => { const [data, setData] = useState(null); const [error, setError] = useState(null); @@ -93,12 +70,36 @@ const useFetchHosting = () => { } }; + const createHosting = async (token: string, name: string, capacity: number) => { + setLoading(true); + setError(null); + try { + const response = await fetch(`${API_URL}/hosting/create`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ token, name, capacity }) + }); + + if (!response.ok) { // Check for non-200 responses + const errorText = await response.text(); // Capture the response text for further insights + throw new Error(`Error ${response.status}: ${errorText}`); + } + + // Optional: Fetch the updated data after reservation + await fetchData(); + } finally { + setLoading(false); + } + }; + useEffect(() => { fetchData(); // Initial fetch on mount }, []); - return { data, error, loading, refetch: fetchData, update: updateData, unreserveHosting}; + return { data, error, loading, refetch: fetchData, update: updateData, unreserveHosting, createHosting}; }; export default useFetchHosting;