diff --git a/frontend/src/components/CopyLinkButton.tsx b/frontend/src/components/CopyLinkButton.tsx index 787e097..35e0e0c 100644 --- a/frontend/src/components/CopyLinkButton.tsx +++ b/frontend/src/components/CopyLinkButton.tsx @@ -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 = ({ 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 = ({ 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 = ({ linkToCopy, sx }) => { }, [copied]); return ( - + <> + + + + {alertMessage} + + + ); }; diff --git a/frontend/src/components/DesireForm.tsx b/frontend/src/components/DesireForm.tsx index 118ee78..d9c19fd 100644 --- a/frontend/src/components/DesireForm.tsx +++ b/frontend/src/components/DesireForm.tsx @@ -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 = ({ 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 = ({ 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 = ({ 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 = ({ onSubmit }) => { }; return ( - + What You Want = ({ onSubmit }) => { + + + {alertMessage} + + ); }; diff --git a/frontend/src/pages/SessionPage.tsx b/frontend/src/pages/SessionPage.tsx index 3e4689c..ce17002 100644 --- a/frontend/src/pages/SessionPage.tsx +++ b/frontend/src/pages/SessionPage.tsx @@ -112,7 +112,7 @@ const SessionPage = () => {