-
-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bug: Improved the feedback form UI issue #61 #75
Changes from all commits
4b9cb52
4fc423e
f4c60cb
3873877
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ import { useState } from "react"; | |||||||||||||||
import { motion } from "framer-motion"; | ||||||||||||||||
import { useInView } from "react-intersection-observer"; | ||||||||||||||||
import chess from "../../assets/img/chess.gif"; | ||||||||||||||||
import { FaStar } from "react-icons/fa6"; | ||||||||||||||||
|
||||||||||||||||
const FeedbackForm = () => { | ||||||||||||||||
const { ref, inView } = useInView({ | ||||||||||||||||
|
@@ -18,11 +19,28 @@ const FeedbackForm = () => { | |||||||||||||||
const [email, setEmail] = useState(""); | ||||||||||||||||
const [feedback, setFeedback] = useState(""); | ||||||||||||||||
const [submitted, setSubmitted] = useState(false); | ||||||||||||||||
|
||||||||||||||||
const [rating, setRating] = useState(null); | ||||||||||||||||
|
||||||||||||||||
const [hover, setHover] = useState(null); | ||||||||||||||||
const [totalStars, setTotalStars] = useState(5); | ||||||||||||||||
Comment on lines
+23
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider optimizing The new state variables for const [rating, setRating] = useState(null);
const [hover, setHover] = useState(null);
const totalStars = 5; // Changed from useState to a constant This optimization is beneficial because |
||||||||||||||||
const [error, setError] = useState(null); | ||||||||||||||||
const [isLoading, setIsLoading] = useState(false); | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
const handleSubmit = async (e) => { | ||||||||||||||||
e.preventDefault(); | ||||||||||||||||
|
||||||||||||||||
console.log(`Name: ${name}, Email: ${email}, Feedback: ${feedback}, rating: ${rating}`); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid logging sensitive user information to the console Logging personal information such as names, emails, and feedback to the console can lead to security and privacy concerns, especially if the console output is exposed in production environments. Consider removing the |
||||||||||||||||
setSubmitted(true); | ||||||||||||||||
setTimeout(() => { | ||||||||||||||||
setName(""); | ||||||||||||||||
setEmail(""); | ||||||||||||||||
setFeedback(""); | ||||||||||||||||
setRating(null); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reset the hover state after form submission When resetting the form fields after submission, consider also resetting the Apply this change to reset the hover state: setName("");
setEmail("");
setFeedback("");
setRating(null);
+setHover(null);
setSubmitted(false); 📝 Committable suggestion
Suggested change
|
||||||||||||||||
setSubmitted(false); | ||||||||||||||||
}, 3000); | ||||||||||||||||
Comment on lines
+34
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security concern and incomplete state reset
console.log(`Feedback submitted with rating: ${rating}`);
setRating(null);
setHover(null); // Add this line Logging sensitive information can lead to security vulnerabilities if logs are exposed. Additionally, resetting the |
||||||||||||||||
|
||||||||||||||||
setIsLoading(true); | ||||||||||||||||
try { | ||||||||||||||||
const response = await fetch(`${API_URL}/feedback/create`, { | ||||||||||||||||
|
@@ -55,6 +73,7 @@ const FeedbackForm = () => { | |||||||||||||||
} finally { | ||||||||||||||||
setIsLoading(false); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
return ( | ||||||||||||||||
|
@@ -65,13 +84,13 @@ const FeedbackForm = () => { | |||||||||||||||
initial="hidden" | ||||||||||||||||
animate={inView ? "visible" : "hidden"} | ||||||||||||||||
variants={animationVariants} | ||||||||||||||||
className="lg:grid lg:grid-cols-2 lg:gap-8" | ||||||||||||||||
className="lg:grid lg:grid-cols-2 lg:gap-8 lg:items-center" | ||||||||||||||||
> | ||||||||||||||||
<div className="mb-8 lg:mb-0 relative"> | ||||||||||||||||
<h2 className="text-3xl font-extrabold text-[#004D43] sm:text-4xl"> | ||||||||||||||||
We Value Your Feedback | ||||||||||||||||
<h2 className="text-5xl font-black text-[#004D43]"> | ||||||||||||||||
We value Your Feedback! | ||||||||||||||||
</h2> | ||||||||||||||||
<p className="mt-4 text-lg text-gray-700 pb-3"> | ||||||||||||||||
<p className="mt-1 text-lg text-gray-700 pb-3"> | ||||||||||||||||
Your thoughts help us improve. Share your experience and | ||||||||||||||||
suggestions with us! | ||||||||||||||||
</p> | ||||||||||||||||
|
@@ -84,69 +103,98 @@ const FeedbackForm = () => { | |||||||||||||||
</div> | ||||||||||||||||
</div> | ||||||||||||||||
|
||||||||||||||||
<div className="mt-8 lg:mt-0"> | ||||||||||||||||
<form onSubmit={handleSubmit} className="space-y-6"> | ||||||||||||||||
<div className="bg-[#004D43] rounded-xl p-3 pt-4 h-fit"> | ||||||||||||||||
<form onSubmit={handleSubmit} className="space-y-4"> | ||||||||||||||||
<div> | ||||||||||||||||
<label | ||||||||||||||||
{/* <label | ||||||||||||||||
htmlFor="name" | ||||||||||||||||
className="block text-sm font-medium text-[#004D43]" | ||||||||||||||||
className="block text-sm font-medium text-white" | ||||||||||||||||
> | ||||||||||||||||
Name | ||||||||||||||||
</label> | ||||||||||||||||
</label> */} | ||||||||||||||||
Comment on lines
+109
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Restore labels for form inputs to improve accessibility Commenting out the labels for the Also applies to: 87-92, 104-109 |
||||||||||||||||
<input | ||||||||||||||||
type="text" | ||||||||||||||||
id="name" | ||||||||||||||||
value={name} | ||||||||||||||||
placeholder="Name" | ||||||||||||||||
onChange={(e) => setName(e.target.value)} | ||||||||||||||||
required | ||||||||||||||||
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-[#004D43] focus:border-[#004D43]" | ||||||||||||||||
/> | ||||||||||||||||
</div> | ||||||||||||||||
<div> | ||||||||||||||||
<label | ||||||||||||||||
{/* <label | ||||||||||||||||
htmlFor="email" | ||||||||||||||||
className="block text-sm font-medium text-[#004D43]" | ||||||||||||||||
> | ||||||||||||||||
</label> | ||||||||||||||||
</label> */} | ||||||||||||||||
<input | ||||||||||||||||
type="email" | ||||||||||||||||
id="email" | ||||||||||||||||
placeholder="Email" | ||||||||||||||||
value={email} | ||||||||||||||||
onChange={(e) => setEmail(e.target.value)} | ||||||||||||||||
required | ||||||||||||||||
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-[#004D43] focus:border-[#004D43]" | ||||||||||||||||
/> | ||||||||||||||||
</div> | ||||||||||||||||
<div> | ||||||||||||||||
<label | ||||||||||||||||
{/* <label | ||||||||||||||||
htmlFor="feedback" | ||||||||||||||||
className="block text-sm font-medium text-[#004D43]" | ||||||||||||||||
> | ||||||||||||||||
Feedback | ||||||||||||||||
</label> | ||||||||||||||||
</label> */} | ||||||||||||||||
<textarea | ||||||||||||||||
id="feedback" | ||||||||||||||||
placeholder="Your valuable feedback here" | ||||||||||||||||
rows="4" | ||||||||||||||||
value={feedback} | ||||||||||||||||
onChange={(e) => setFeedback(e.target.value)} | ||||||||||||||||
required | ||||||||||||||||
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-[#004D43] focus:border-[#004D43]" | ||||||||||||||||
className="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-[#004D43] focus:border-[#004D43] resize-none" | ||||||||||||||||
Comment on lines
+106
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve form accessibility While the styling changes and added placeholders enhance the form's appearance, commenting out the labels (lines 109-114, 126-131, 143-148) negatively impacts accessibility. Consider these options:
<label htmlFor="name" className="sr-only">Name</label>
<input
type="text"
id="name"
value={name}
placeholder="Name"
// ... other props
/>
<input
type="text"
id="name"
value={name}
placeholder="Name"
aria-label="Name"
// ... other props
/> These changes will ensure that screen readers can properly convey the purpose of each form field to users with visual impairments. |
||||||||||||||||
></textarea> | ||||||||||||||||
</div> | ||||||||||||||||
<div className="flex flex-row justify-center gap-2"> | ||||||||||||||||
{[...Array(totalStars)].map((star, index) => { | ||||||||||||||||
const currentRating = index + 1; | ||||||||||||||||
return ( | ||||||||||||||||
<label key={index}> | ||||||||||||||||
<input | ||||||||||||||||
type="radio" | ||||||||||||||||
name="rating" | ||||||||||||||||
value={currentRating} | ||||||||||||||||
onChange={() => setRating(currentRating)} | ||||||||||||||||
/> | ||||||||||||||||
<span | ||||||||||||||||
className="star" | ||||||||||||||||
style={{ | ||||||||||||||||
color: | ||||||||||||||||
currentRating <= (hover || rating) ? "#ffc107" : "#e4e5e9" | ||||||||||||||||
}} | ||||||||||||||||
onMouseEnter={() => setHover(currentRating)} | ||||||||||||||||
onMouseLeave={() => setHover(null)} | ||||||||||||||||
> | ||||||||||||||||
<FaStar /> | ||||||||||||||||
</span> | ||||||||||||||||
</label> | ||||||||||||||||
); | ||||||||||||||||
})} | ||||||||||||||||
</div> | ||||||||||||||||
Comment on lines
+159
to
+184
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance accessibility and usability of star rating component The star rating component is a good addition, but it needs improvements for accessibility and usability:
<input
type="radio"
name="rating"
value={currentRating}
onChange={() => setRating(currentRating)}
aria-label={`Rate ${currentRating} out of ${totalStars} stars`}
/>
<span
className="star"
style={{
color: currentRating <= (hover || rating) ? "#ffc107" : "#e4e5e9"
}}
onMouseEnter={() => setHover(currentRating)}
onMouseLeave={() => setHover(null)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
setRating(currentRating);
}
}}
tabIndex={0}
role="button"
>
<FaStar />
</span>
These changes will significantly improve the accessibility and usability of the star rating component. |
||||||||||||||||
<div> | ||||||||||||||||
<button | ||||||||||||||||
type="submit" | ||||||||||||||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-[#004D43] hover:bg-[#003d35] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#004D43]" | ||||||||||||||||
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-[#09342e] hover:bg-[#072d28] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#004D43]" | ||||||||||||||||
> | ||||||||||||||||
{isLoading ? "Submitting..." : "Submit Feedback"} | ||||||||||||||||
</button> | ||||||||||||||||
</div> | ||||||||||||||||
</form> | ||||||||||||||||
{submitted && ( | ||||||||||||||||
<motion.div | ||||||||||||||||
initial={{ opacity: 0, y: -10 }} | ||||||||||||||||
animate={{ opacity: 1, y: 0 }} | ||||||||||||||||
initial={{ opacity: 0, y: -10, display:"none", height:0 }} | ||||||||||||||||
animate={{ opacity: 1, y: 0, display: "block", height: "auto" }} | ||||||||||||||||
Comment on lines
+196
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve animation of feedback confirmation message The current animation approach using <motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
className="mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded"
>
Thank you for your feedback!
</motion.div> Also, consider wrapping this component with Framer Motion's import { AnimatePresence } from 'framer-motion';
// In your JSX
<AnimatePresence>
{submitted && (
<motion.div
// ... animation props as above
>
Thank you for your feedback!
</motion.div>
)}
</AnimatePresence> This approach provides a smoother animation without causing layout shifts. |
||||||||||||||||
className="mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded" | ||||||||||||||||
> | ||||||||||||||||
Thank you for your feedback! | ||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simplify
totalStars
to a constantSince
totalStars
represents a fixed value andsetTotalStars
is not used, you can replace the state variable with a constant to reduce unnecessary state management.Apply this diff to simplify:
📝 Committable suggestion