Minor UI improvements

This commit is contained in:
AG
2025-10-15 07:44:57 +03:00
parent e361a278ef
commit 9096e7db38
3 changed files with 65 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Button, SxProps, Theme } from '@mui/material';
import { Button, SxProps, Theme, Snackbar, Alert } from '@mui/material';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
@@ -10,10 +10,15 @@ interface CopyLinkButtonProps {
const CopyLinkButton: React.FC<CopyLinkButtonProps> = ({ linkToCopy, sx }) => {
const [copied, setCopied] = useState(false);
const [alertOpen, setAlertOpen] = useState(false);
const [alertMessage, setAlertMessage] = useState('');
const [alertSeverity, setAlertSeverity] = useState<'error' | 'warning' | 'info' | 'success'>('error');
const handleCopy = async () => {
if (!navigator.clipboard || !navigator.clipboard.writeText) {
alert('Clipboard API not supported in this browser. Please copy the link manually:' + linkToCopy);
setAlertMessage('Clipboard API not supported in this browser. Please copy the link manually.');
setAlertSeverity('warning');
setAlertOpen(true);
console.warn('Clipboard API not supported.');
return;
}
@@ -21,13 +26,25 @@ const CopyLinkButton: React.FC<CopyLinkButtonProps> = ({ linkToCopy, sx }) => {
try {
await navigator.clipboard.writeText(linkToCopy);
setCopied(true);
setAlertMessage('Link copied to clipboard!');
setAlertSeverity('success');
setAlertOpen(true);
console.log('Link copied to clipboard:', linkToCopy);
} catch (err) {
console.error('Failed to copy link:', err);
alert('Failed to copy the link. Please try again or copy manually.');
setAlertMessage('Failed to copy the link. Please try again or copy manually.');
setAlertSeverity('error');
setAlertOpen(true);
}
};
const handleCloseAlert = (event?: React.SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setAlertOpen(false);
};
useEffect(() => {
let timer: NodeJS.Timeout;
if (copied) {
@@ -39,19 +56,26 @@ const CopyLinkButton: React.FC<CopyLinkButtonProps> = ({ linkToCopy, sx }) => {
}, [copied]);
return (
<Button
variant="outlined"
onClick={handleCopy}
startIcon={copied ? <CheckCircleOutlineIcon color="success" /> : <ContentCopyIcon />}
color={copied ? "success" : "primary"}
sx={{
minWidth: 120,
textTransform: 'none',
...(sx ? sx : {}),
}}
>
{copied ? 'Copied!' : 'Copy Link'}
</Button>
<>
<Button
variant="outlined"
onClick={handleCopy}
startIcon={copied ? <CheckCircleOutlineIcon color="success" /> : <ContentCopyIcon />}
color={copied ? "success" : "primary"}
sx={{
minWidth: 120,
textTransform: 'none',
...(sx ? sx : {}),
}}
>
{copied ? 'Copied!' : 'Copy Link'}
</Button>
<Snackbar open={alertOpen} autoHideDuration={6000} onClose={handleCloseAlert} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} sx={{ mt: 8 }}>
<Alert onClose={handleCloseAlert} severity={alertSeverity} sx={{ width: '100%' }}>
{alertMessage}
</Alert>
</Snackbar>
</>
);
};

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { TextField, Button, Box, Typography } from '@mui/material';
import { TextField, Button, Box, Typography, Snackbar, Alert } from '@mui/material';
interface DesireFormProps {
onSubmit: (desires: { wants: string[], accepts: string[], noGoes: string[], afraidToAsk: string }) => void;
@@ -10,6 +10,16 @@ const DesireForm: React.FC<DesireFormProps> = ({ onSubmit }) => {
const [accepts, setAccepts] = useState('');
const [noGoes, setNoGoes] = useState('');
const [afraidToAsk, setAfraidToAsk] = useState('');
const [alertOpen, setAlertOpen] = useState(false);
const [alertMessage, setAlertMessage] = useState('');
const [alertSeverity, setAlertSeverity] = useState<'error' | 'warning' | 'info' | 'success'>('error');
const handleCloseAlert = (event?: React.SyntheticEvent | Event, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setAlertOpen(false);
};
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
@@ -19,7 +29,9 @@ const DesireForm: React.FC<DesireFormProps> = ({ onSubmit }) => {
// FR-020: The system MUST require a user to enter at least one desire in at least one of the three categories
if (parsedWants.length === 0 && parsedAccepts.length === 0 && parsedNoGoes.length === 0 && afraidToAsk.length === 0) {
alert('Please enter at least one desire in any category.');
setAlertMessage('Please enter at least one desire in any category.');
setAlertSeverity('error');
setAlertOpen(true);
return;
}
@@ -27,7 +39,9 @@ const DesireForm: React.FC<DesireFormProps> = ({ onSubmit }) => {
const allItems = [...parsedWants, ...parsedAccepts, ...parsedNoGoes];
const uniqueItems = new Set(allItems);
if (allItems.length !== uniqueItems.size) {
alert('You have conflicting desires (same item in different categories). Please resolve.');
setAlertMessage('You have conflicting desires (same item in different categories). Please resolve.');
setAlertSeverity('error');
setAlertOpen(true);
return;
}
@@ -40,7 +54,7 @@ const DesireForm: React.FC<DesireFormProps> = ({ onSubmit }) => {
};
return (
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 3 }}>
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 3, display: 'flex', flexDirection: 'column' }}>
<Typography variant="h6" gutterBottom>What You Want</Typography>
<TextField
multiline
@@ -91,12 +105,16 @@ const DesireForm: React.FC<DesireFormProps> = ({ onSubmit }) => {
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
sx={{ mt: 3, mb: 2, textTransform: 'none', alignSelf: 'flex-start' }}
>
Submit Desires
</Button>
<Snackbar open={alertOpen} autoHideDuration={6000} onClose={handleCloseAlert} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} sx={{ mt: 8 }}>
<Alert onClose={handleCloseAlert} severity={alertSeverity} sx={{ width: '100%' }}>
{alertMessage}
</Alert>
</Snackbar>
</Box>
);
};

View File

@@ -112,7 +112,7 @@ const SessionPage = () => {
<Button
type="button"
variant="contained"
sx={{ mt: 2 }}
sx={{ mt: 2, textTransform: 'none' }}
onClick={handleSetupSession}
>
Start Session