session start works

This commit is contained in:
aodulov
2025-10-10 12:48:06 +03:00
parent 556df015e8
commit 3c192b136c
51 changed files with 29002 additions and 46 deletions

View File

@@ -0,0 +1,22 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import CreateSession from './CreateSession';
test('renders create session page with a form', () => {
render(<CreateSession />);
// Check for a heading
const headingElement = screen.getByText(/Create a New Session/i);
expect(headingElement).toBeInTheDocument();
// Check for form fields
const topicInput = screen.getByLabelText(/Topic/i);
expect(topicInput).toBeInTheDocument();
const participantsInput = screen.getByLabelText(/Number of Participants/i);
expect(participantsInput).toBeInTheDocument();
// Check for the create button
const createButton = screen.getByRole('button', { name: /Create Session/i });
expect(createButton).toBeInTheDocument();
});

View File

@@ -0,0 +1,48 @@
import React from 'react';
import { Box, Button, Typography, Container } from '@mui/material';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const CreateSession = () => {
const navigate = useNavigate();
const handleCreate = async () => {
try {
const response = await axios.post('http://localhost:8000/sessions');
const { sessionId } = response.data;
navigate(`/session/${sessionId}`);
} catch (error) {
console.error('Error creating session:', error);
}
};
return (
<Container maxWidth="sm">
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Typography component="h1" variant="h5">
Unisono
</Typography>
<Box sx={{ mt: 3 }}>
<Button
type="button"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
onClick={handleCreate}
>
Create a New Session
</Button>
</Box>
</Box>
</Container>
);
};
export default CreateSession;

View File

@@ -0,0 +1,132 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useParams } from 'react-router-dom';
import { Container, Typography, Box, CircularProgress, Alert, TextField, Button } from '@mui/material';
import { useSession, Session, Participant, DesireSet, Decision, SessionState } from '../hooks/useSession';
import { webSocketService } from '../services/websocket';
import DesireForm from '../components/DesireForm';
import ResultsDisplay from '../components/ResultsDisplay';
const SessionPage = () => {
const { sessionId } = useParams<{ sessionId: string }>();
const [session, setSession, sendMessage, clientId] = useSession(sessionId || '');
const [error, setError] = useState<string | null>(null);
const [expectedResponses, setExpectedResponses] = useState(2);
const [topic, setTopic] = useState('');
const handleSetupSession = () => {
sendMessage({ type: 'SETUP_SESSION', payload: { expectedResponses, topic } });
};
const handleSubmitDesires = (desires: { wants: string[], accepts: string[], noGoes: string[] }) => {
if (!session || !clientId) return;
const desireSet: DesireSet = {
participantId: clientId, // Use the clientId from the hook
wants: desires.wants,
accepts: desires.accepts,
noGoes: desires.noGoes,
};
sendMessage({
type: 'SUBMIT_RESPONSE',
payload: { response: desireSet },
});
};
if (!session) {
return <Typography>Loading session...</Typography>;
}
const remainingResponses = session.expectedResponses - session.submittedCount;
const hasSubmittedCurrentParticipant = session.responses && session.responses[clientId];
return (
<Container maxWidth="md">
<Box sx={{ mt: 4 }}>
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
<Typography variant="h4" component="h1" gutterBottom>
Session: {session.topic || session.sessionId}
</Typography>
{session.state === SessionState.SETUP && (
<Box sx={{ mt: 4, p: 3, border: '1px dashed grey', borderRadius: '4px', textAlign: 'center' }}>
<Typography variant="h6" component="p" gutterBottom>
Set Up the Session
</Typography>
<TextField
margin="normal"
fullWidth
id="topic"
label="Session Topic"
name="topic"
autoFocus
value={topic}
onChange={(e) => setTopic(e.target.value)}
/>
<TextField
margin="normal"
required
fullWidth
name="expectedResponses"
label="Number of Expected Responses"
type="number"
id="expectedResponses"
value={expectedResponses}
onChange={(e) => setExpectedResponses(parseInt(e.target.value, 10))}
InputProps={{
inputProps: { min: 1 }
}}
/>
<Button
type="button"
variant="contained"
sx={{ mt: 2 }}
onClick={handleSetupSession}
>
Start Session
</Button>
</Box>
)}
{session.state !== SessionState.SETUP && (
<>
<Typography variant="h6" gutterBottom>
Expected Responses: {session.expectedResponses}
</Typography>
<Typography variant="body1" gutterBottom>
Status: {session.state}
</Typography>
</>
)}
{session.state === SessionState.GATHERING && !hasSubmittedCurrentParticipant && (
<DesireForm onSubmit={handleSubmitDesires} />
)}
{session.state === SessionState.GATHERING && hasSubmittedCurrentParticipant && (
<Box sx={{ mt: 4, p: 3, border: '1px dashed grey', borderRadius: '4px', textAlign: 'center' }}>
<Typography variant="h6" component="p">
Waiting for {remainingResponses} more responses...
</Typography>
<Typography variant="body2" color="text.secondary">
Your desires have been submitted. The results will be calculated once all participants have responded.
</Typography>
</Box>
)}
{session.state === SessionState.HARMONIZING && (
<Box sx={{ mt: 4, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<CircularProgress />
<Typography variant="h6" sx={{ mt: 2 }}>Harmonizing Desires...</Typography>
</Box>
)}
{session.state === SessionState.FINAL && session.finalResult && (
<ResultsDisplay decision={session.finalResult} />
)}
</Box>
</Container>
);
};
export default SessionPage;