Compare commits

..

No commits in common. "dadb094017e2549b8af045cfe189163e1f84fced" and "c2e6f81775a573c756516dd1015bbc6b002476d3" have entirely different histories.

8 changed files with 100 additions and 133 deletions

View File

@ -264,15 +264,6 @@ nav ul {
justify-content: space-around; /* Space the items evenly */ justify-content: space-around; /* Space the items evenly */
} }
nav ul li p {
color: white;
text-decoration: none;
}
nav ul li p:hover {
text-decoration: underline;
}
nav li { nav li {
display: inline; display: inline;
} }

View File

@ -10,17 +10,6 @@ import { FullScreenLoading } from './components/Loading';
function App() { function App() {
const [isNavOpen, setIsNavOpen] = useState(false); const [isNavOpen, setIsNavOpen] = useState(false);
const handleLogout = () => {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const cookieName = cookie.split("=")[0].trim();
// Set the cookie's expiration date to the past to delete it
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`;
}
window.location.reload();
};
const toggleNav = () => { const toggleNav = () => {
setIsNavOpen(!isNavOpen); setIsNavOpen(!isNavOpen);
}; };
@ -46,9 +35,6 @@ function App() {
<li> <li>
<a href="#program">Программа</a> <a href="#program">Программа</a>
</li> </li>
<li>
<button onClick={() => handleLogout()}>Выйти</button>
</li>
</ul> </ul>
</nav> </nav>

View File

@ -2,7 +2,7 @@
import React, { createContext, useContext, useState } from 'react'; import React, { createContext, useContext, useState } from 'react';
export type NotificationType = 'success' | 'error'; type NotificationType = 'success' | 'error';
interface NotificationContextType { interface NotificationContextType {
notify: (message: string, type: NotificationType) => void; notify: (message: string, type: NotificationType) => void;

View File

@ -1,51 +1,17 @@
import { useCookies } from "react-cookie"; import { useCookies } from "react-cookie";
import CenteredContainer from "./ChildrenContainer"; import CenteredContainer from "./ChildrenContainer";
import useFetchUser from "../utils/fetchUser"; import useFetchUser from "../utils/fetchUser";
import type React from "react";
import ApologyMessage from "./Attendance";
import { useState } from "react";
const Attendance: React.FC = () => { function Greeting() {
const { updateAttendance, getAttendance } = useFetchUser() const [cookie] = useCookies<string>(['userName'])
const [attendance, setAttendance] = useState<boolean | null>(null) const userName = cookie.userName;
const fetchAttendance = async () => { const { updateAttendance } = useFetchUser()
const is = await getAttendance()
setAttendance(is)
}
fetchAttendance()
const handleUpdate = async (status: boolean) => { const handleUpdate = async (status: boolean) => {
await updateAttendance(status) await updateAttendance(status)
window.location.reload(); window.location.reload();
} }
if (attendance == false) {
return (<ApologyMessage/>)
}
return (
<>
{attendance == null && (
<>
<h3>Присоеденишься?</h3>
<p>(Можно и потом ответить)</p>
<button style={localStyles.buttonOk} onClick={() => handleUpdate(true)}>Да!</button>
<button style={localStyles.buttonNok} onClick={() => handleUpdate(false)}>Не смогу в этот раз</button>
</>
)}
{attendance == true && (
<>
<h3>Круто! Ты с нами!</h3>
<p>Если все же по разным обстоятельствам ты не сможешь/не захочешь, то всегда можно передумать</p>
<button style={localStyles.buttonNok} onClick={() => handleUpdate(false)}>Все же никак</button>
</>)}
</>)
}
function Greeting() {
const [cookie] = useCookies<string>(['userName'])
const userName = cookie.userName;
return ( return (
<> <>
<CenteredContainer> <CenteredContainer>
@ -58,9 +24,11 @@ function Greeting() {
Приглашаем тебя отпраздновать предстоящий Новый Год <b>2025-2026</b> с нами в сосновой избе, в которой, ко всему прочему, будет праздноваться годовщина нашей жизни в ней! Приглашаем тебя отпраздновать предстоящий Новый Год <b>2025-2026</b> с нами в сосновой избе, в которой, ко всему прочему, будет праздноваться годовщина нашей жизни в ней!
Наши двери открыты с <b>30.12.2025</b>. Праздник обычно длится до <b>01.01.2025</b>, но если тебе или твоим спутникам будет безумно плохо, то можно остаться и до второго числа. Наши двери открыты с <b>30.12.2025</b>. Праздник обычно длится до <b>01.01.2025</b>, но если тебе или твоим спутникам будет безумно плохо, то можно остаться и до второго числа.
<h3>Присоеденишься?</h3>
<p>(Можно и потом ответить)</p>
<button style={localStyles.buttonOk} onClick={() => handleUpdate(true)}>Да!</button>
<button style={localStyles.buttonNok}onClick={() => handleUpdate(false)}>Не смогу в этот раз</button>
</p> </p>
<Attendance/>
</CenteredContainer> </CenteredContainer>
</> </>
) )

View File

@ -1,5 +1,5 @@
import useFetchHosting from "../utils/fetchHosting"; import useFetchHosting from "../utils/fetchHosting";
import { useNotification, type NotificationType } from "../NotificationContext"; import { useNotification } from "../NotificationContext";
import { useCookies } from "react-cookie"; import { useCookies } from "react-cookie";
import CenteredContainer from "./ChildrenContainer"; import CenteredContainer from "./ChildrenContainer";
import { useState } from "react"; import { useState } from "react";
@ -9,16 +9,16 @@ interface ReserveButtonProps {
update: (name: string, id: number) => void, update: (name: string, id: number) => void,
unreserve: (token: string, id: number) => void, unreserve: (token: string, id: number) => void,
reservedBy: string, reservedBy: string,
notify: (message: string, type: NotificationType) => void,
id: number, id: number,
} }
const ReserveButton: React.FC<ReserveButtonProps> = (props) => { const ReserveButton: React.FC<ReserveButtonProps> = (props) => {
const { reservedBy, update, id, unreserve, notify } = props; const { reservedBy, update, id, unreserve } = props;
const [cookie] = useCookies<string>(['userName']) const [cookie] = useCookies<string>(['userName'])
const [tokenCookie] = useCookies<string>(['apiToken']) const [tokenCookie] = useCookies<string>(['apiToken'])
const userName = cookie.userName; const userName = cookie.userName;
const isReserved = reservedBy !== ''; const isReserved = reservedBy !== '';
const notify = useNotification();
const handleReserve = async (name: string) => { const handleReserve = async (name: string) => {
try { try {
@ -50,33 +50,68 @@ const ReserveButton: React.FC<ReserveButtonProps> = (props) => {
); );
}; };
interface CreateHostingFormProps {
createHosting: (token: string, name: string, capacity: number) => void,
}
const Hosting = () => { const CreateHostingForm: React.FC<CreateHostingFormProps> = (props) => {
const { data, error, loading, update, unreserveHosting, createHosting } = useFetchHosting(); const { createHosting } = props;
const [name, setName] = useState(''); const [name, setName] = useState('');
const [capacity, setCapacity] = useState(''); const [capacity, setCapacity] = useState('');
const [tokenCookie] = useCookies<string>(['apiToken']) const [tokenCookie] = useCookies<string>(['apiToken'])
const notify = useNotification(); const notify = useNotification();
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { const handleSubmit = async () => {
event.preventDefault(); // Prevent the default form submission
if (!name || !capacity) { if (!name || !capacity) {
notify('Надо заполнить все поля', 'error'); notify('Надо заполнить все поля', 'error')
return; return
} }
try { try {
await createHosting(tokenCookie.apiToken, name, Number(capacity)); await createHosting(tokenCookie.apiToken, name, Number(capacity)); // Call the existing hook
// Reset form fields // Reset form fields
setName(''); setName('');
setCapacity(''); setCapacity('');
notify('Удалось создать!', 'success'); notify('Удалось создать!', 'success')
} catch (error) { } catch (error) {
notify(`Не удалось создать: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error'); notify(`Не удалось создать: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error'); // Capture any error message
} }
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Размещение:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</label>
</div>
<div>
<label>
Спальных мест:
<input
type="number"
value={capacity}
onChange={(e) => setCapacity(e.target.value)}
required
/>
</label>
</div>
<button type="submit" onClick={() => handleSubmit()}>
{'Создать размещение'}
</button>
</form>
);
}; };
const Hosting = () => {
const { data, error, loading, update, unreserveHosting, createHosting } = useFetchHosting();
return ( return (
<> <>
<CenteredContainer> <CenteredContainer>
@ -107,7 +142,7 @@ const Hosting = () => {
<td>{item.name}</td> <td>{item.name}</td>
<td>{item.capacity}</td> <td>{item.capacity}</td>
<td> <td>
<ReserveButton update={update} reservedBy={item.reservedBy} id={item.id} unreserve={unreserveHosting} notify={notify} /> <ReserveButton update={update} reservedBy={item.reservedBy} id={item.id} unreserve={unreserveHosting} />
</td> </td>
</tr> </tr>
))} ))}
@ -117,34 +152,7 @@ const Hosting = () => {
</div> </div>
)} )}
Если вы хотите организовать себе свои спальные места и хотите, чтобы остальные это видели, вы можете добавить свое месо в таблицу. Если вы хотите организовать себе свои спальные места и хотите, чтобы остальные это видели, вы можете добавить свое месо в таблицу.
<form onSubmit={handleSubmit}> <CreateHostingForm createHosting={createHosting}/>
<div>
<label>
Размещение:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
required
/>
</label>
</div>
<div>
<label>
Спальных мест:
<input
type="number"
value={capacity}
onChange={(e) => setCapacity(e.target.value)}
required
/>
</label>
</div>
<button type="submit">
{'Создать размещение'}
</button>
</form>
</CenteredContainer> </CenteredContainer>
<br /> <br />
</> </>

View File

@ -3,6 +3,7 @@ import { useCookies } from 'react-cookie';
import { GUESTS } from '../constants/constants'; import { GUESTS } from '../constants/constants';
import useFetchUser from '../utils/fetchUser'; // Import your custom hook import useFetchUser from '../utils/fetchUser'; // Import your custom hook
import { useNotification } from '../NotificationContext'; import { useNotification } from '../NotificationContext';
import ApologyMessage from './Attendance';
import {Loading} from './Loading'; import {Loading} from './Loading';
const InitialSetup = () => { const InitialSetup = () => {
@ -12,8 +13,9 @@ const InitialSetup = () => {
const [isSubmitted, setIsSubmitted] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false);
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [isPasswordSet, setIsPasswordSet] = useState(false); // To track if password is set const [isPasswordSet, setIsPasswordSet] = useState(false); // To track if password is set
const [userAttendance, setUserAttendance] = useState<boolean | null>(null);
const { userSet, passwordCreate, signUser, validToken, isLoading } = useFetchUser(); // Destructure functions from the hook const { userSet, passwordCreate, signUser, validToken, getAttendance, isLoading } = useFetchUser(); // Destructure functions from the hook
const notify = useNotification(); const notify = useNotification();
const checkUserPassword = async (name: string) => { const checkUserPassword = async (name: string) => {
@ -33,8 +35,14 @@ const InitialSetup = () => {
setIsSubmitted(isTokenValid); setIsSubmitted(isTokenValid);
}; };
const getUserAttendance = async () => {
const attendance = await getAttendance()
setUserAttendance(attendance)
}
useEffect(() => { useEffect(() => {
if (cookie.apiToken !== undefined) { if (cookie.apiToken !== undefined) {
getUserAttendance()
validateToken(); validateToken();
} }
}, [cookie.apiToken]); }, [cookie.apiToken]);
@ -58,11 +66,16 @@ const InitialSetup = () => {
validateToken() validateToken()
}; };
if (isSubmitted) { if (isSubmitted && userAttendance !== false) {
console.log('Selected', selectedName); console.log('Selected', selectedName);
return null; // or you can redirect to another component or page return null; // or you can redirect to another component or page
} }
if (userAttendance == false) {
return (
<ApologyMessage/>
)
}
if (isLoading) { if (isLoading) {
return ( return (

View File

@ -71,6 +71,7 @@ const useFetchHosting = () => {
}; };
const createHosting = async (token: string, name: string, capacity: number) => { const createHosting = async (token: string, name: string, capacity: number) => {
setLoading(true);
setError(null); setError(null);
try { try {
const response = await fetch(`${API_URL}/hosting/create`, { const response = await fetch(`${API_URL}/hosting/create`, {
@ -83,13 +84,13 @@ const useFetchHosting = () => {
if (!response.ok) { // Check for non-200 responses if (!response.ok) { // Check for non-200 responses
const errorText = await response.text(); // Capture the response text for further insights const errorText = await response.text(); // Capture the response text for further insights
console.log(`Error ${response.status}: ${errorText}`)
throw new Error(`Error ${response.status}: ${errorText}`); throw new Error(`Error ${response.status}: ${errorText}`);
} }
// Optional: Fetch the updated data after reservation // Optional: Fetch the updated data after reservation
await fetchData(); await fetchData();
} finally { } finally {
setLoading(false);
} }
}; };

View File

@ -114,28 +114,6 @@ const useFetchUser = () => {
} }
} }
const getAttendance = async (): Promise<boolean | null> => {
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
} catch (error) {
console.error('Error retrieving attendance:', error);
return null
}
}
const updateAttendance = async (attendanceStatus: boolean): Promise<boolean> => { const updateAttendance = async (attendanceStatus: boolean): Promise<boolean> => {
const token = apiCookie.apiToken const token = apiCookie.apiToken
try { try {
@ -162,6 +140,28 @@ const useFetchUser = () => {
} }
} }
const getAttendance = async (): Promise<boolean | null> => {
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, isLoading }; return { userSet, passwordCreate, signUser, validToken, updateAttendance, getAttendance, isLoading };
}; };