animations in testimonial section#496
Conversation
|
CodeAnt AI is reviewing your PR. |
|
@ArshiBansal is attempting to deploy a commit to the Karan Mani Tripathi 's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Technical Review
Hi @ArshiBansal! Thank you for your contribution to DoubtDesk.
The code changes look good. Before we can complete the technical review, approve, and merge this pull request, we have one final requirement for all contributors: Please star the DoubtDesk repository.
Once you have starred the repository, please drop a comment here saying "done" (or we will automatically detect it) and we will proceed with approving and merging your PR. Thank you.
WalkthroughThis PR adds a testimonials marquee feature to the landing page. A new ChangesTestimonials Marquee Feature
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
There was a problem hiding this comment.
Technical Review
Hi @ArshiBansal! Thank you for your contribution to DoubtDesk.
The code changes look good. Before we can complete the technical review, approve, and merge this pull request, we have one final requirement for all contributors: Please star the DoubtDesk repository.
Once you have starred the repository, please drop a comment here saying "done" (or we will automatically detect it) and we will proceed with approving and merging your PR. Thank you.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/page.tsx (1)
376-397:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTestimonialsMarquee component is not integrated.
The testimonials section still uses the old grid layout instead of the new
TestimonialsMarqueecomponent created in this PR. The PR objectives state "Integrates the marquee and review form into the homepage Testimonials section," but the marquee component is not being used here.🔄 Proposed integration of TestimonialsMarquee
+import TestimonialsMarquee from "`@/components/TestimonialsMarquee`"; + // ... rest of imports export default function Home() { // ... existing code const testimonials = [ { name: "Aarav Sharma", role: "B.Tech Student", text: "DoubtDesk made it so easy to clear my doubts during exam prep. The AI explanations are super clear.", }, { name: "Neha Verma", role: "CS Student", text: "No more messy WhatsApp groups. Everything is structured and easy to follow.", }, { name: "Rohit Mehta", role: "Teaching Assistant", text: "Analytics help me understand where students struggle the most.", }, ]; // ... existing code return ( // ... existing JSX {/* Testimonials Section */} <section id="testimonials" className="scroll-mt-20 px-4 sm:px-6 lg:px-8 py-20 relative z-10 border-t border-slate-200/60 dark:border-zinc-900 bg-slate-100/40 dark:bg-black/20 transition-colors duration-500" > <div className="max-w-7xl mx-auto space-y-16"> <div className="text-center space-y-3"> <div className={`${staatliches.className} text-sm tracking-[0.14em] text-blue-600 dark:text-blue-400 uppercase`} > Testimonials </div> <h3 className="text-3xl sm:text-4xl font-extrabold text-slate-900 dark:text-slate-100 tracking-tight transition-colors duration-300"> What students say </h3> <p className="text-base text-slate-600 dark:text-zinc-400 max-w-md mx-auto transition-colors duration-300"> Real feedback from learners and educators </p> </div> - <div className="grid md:grid-cols-3 gap-6"> - {testimonials.map((t, index) => ( - <div - key={t.name} - style={{ animationDelay: `${index * 200}ms` }} - className="p-6 rounded-3xl border border-slate-200/80 dark:border-zinc-800/80 bg-white dark:bg-zinc-900/40 backdrop-blur-md hover:border-blue-400 dark:hover:border-zinc-700 hover:bg-slate-50 dark:hover:bg-zinc-900/60 transition-all duration-500 flex flex-col justify-between shadow-sm dark:shadow-none hover:shadow-xl hover:-translate-y-1 animate-in fade-in slide-in-from-bottom-6 fill-mode-both" - > - <p className="text-slate-600 dark:text-slate-300 text-sm leading-relaxed italic transition-colors duration-300"> - "{t.text}" - </p> - - <div className="mt-6 pt-4 border-t border-slate-100 dark:border-zinc-800/60 flex flex-col"> - <div className="text-slate-950 dark:text-slate-100 font-bold tracking-tight transition-colors duration-300"> - {t.name} - </div> - <div className="text-xs font-medium text-slate-400 dark:text-zinc-500 mt-0.5 transition-colors duration-300"> - {t.role} - </div> - </div> - </div> - ))} - </div> + <TestimonialsMarquee testimonials={testimonials} /> </div> </section>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/page.tsx` around lines 376 - 397, Replace the manual grid mapping of testimonials in the page component with the new TestimonialsMarquee component: import TestimonialsMarquee, remove the block that maps testimonials.map(...) (the div with className "grid md:grid-cols-3 gap-6" and its children), and render <TestimonialsMarquee testimonials={testimonials} /> in its place ensuring you pass the testimonials array prop; also remove any duplicate styling wrapper that is no longer needed and keep any surrounding section/container markup intact.
🧹 Nitpick comments (4)
src/components/TestimonialsMarquee.tsx (2)
49-53: ⚡ Quick winKey generation may cause collisions with duplicate names.
Using
${testimonial.name}-${index}for keys can produce collisions if the testimonials array contains duplicate names. While unlikely, this could cause React rendering issues.🔑 Proposed improvement for unique keys
If testimonials have unique IDs, use those:
- <TestimonialCard - key={`${testimonial.name}-${index}`} - testimonial={testimonial} - /> + <TestimonialCard + key={testimonial.id ?? `${testimonial.name}-${testimonial.role}-${index}`} + testimonial={testimonial} + />Or include more fields to ensure uniqueness:
<TestimonialCard - key={`${testimonial.name}-${index}`} + key={`${testimonial.name}-${testimonial.role}-${index}`} testimonial={testimonial} />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/TestimonialsMarquee.tsx` around lines 49 - 53, The key prop on the mapped duplicatedTestimonials currently uses `${testimonial.name}-${index}` which can collide for duplicate names; update the mapping in the duplicatedTestimonials => TestimonialCard render to use a truly unique identifier (prefer testimonial.id if available) or compose a more unique key (e.g., combine testimonial.id or email with index or timestamp) and set that as the key prop on TestimonialCard so keys are stable and unique across renders.
13-17: ⚡ Quick winAdd empty state handling.
The component doesn't handle the case when
testimonialsis empty or undefined, which could result in an empty marquee or runtime errors.🛡️ Proposed empty state handling
export default function TestimonialsMarquee({ testimonials, }: { testimonials: Testimonial[]; }) { + if (!testimonials || testimonials.length === 0) { + return null; + } + const duplicatedTestimonials = [...testimonials, ...testimonials];As per coding guidelines, **/*.tsx files must be reviewed for missing loading/error states.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/TestimonialsMarquee.tsx` around lines 13 - 17, The TestimonialsMarquee component does not handle empty or undefined testimonials, which can produce an empty marquee or runtime errors; update the TestimonialsMarquee function to guard the testimonials prop (e.g., if (!testimonials || testimonials.length === 0) ...) and return a sensible empty state UI or null/placeholder (a short message or skeleton) so downstream code that maps or renders items (inside TestimonialsMarquee) never runs against undefined/empty arrays; ensure the guard is added before any map/iteration or marquee logic in TestimonialsMarquee.src/app/page.tsx (1)
115-131: 💤 Low valueTestimonials data lacks rating field.
The testimonials data array doesn't include the optional
ratingfield that theTestimonialCardcomponent supports. Consider adding ratings to showcase the star display feature.⭐ Example with ratings added
const testimonials = [ { name: "Aarav Sharma", role: "B.Tech Student", text: "DoubtDesk made it so easy to clear my doubts during exam prep. The AI explanations are super clear.", + rating: 5, }, { name: "Neha Verma", role: "CS Student", text: "No more messy WhatsApp groups. Everything is structured and easy to follow.", + rating: 5, }, { name: "Rohit Mehta", role: "Teaching Assistant", text: "Analytics help me understand where students struggle the most.", + rating: 4, }, ];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/page.tsx` around lines 115 - 131, The testimonials array used to render TestimonialCard instances is missing the optional rating property, so add a numeric rating (e.g., 1–5) to each testimonial object in the testimonials constant (the objects for "Aarav Sharma", "Neha Verma", "Rohit Mehta") so TestimonialCard can display stars; ensure the property name is exactly rating and matches the prop expected by TestimonialCard and that any mapping/prop-passing code that spreads or selects fields (where testimonials are mapped into <TestimonialCard ... />) continues to pass the rating through.src/components/TestimonialCard.tsx (1)
16-16: ⚡ Quick winFixed width may limit responsive behavior.
The card uses a fixed width of
320pxwhich prevents it from adapting to smaller containers. Consider usingmax-w-[320px] w-fullto allow the card to shrink on smaller screens while maintaining a maximum width.📱 Proposed responsive improvement
- <div className="w-[320px] flex-shrink-0 rounded-3xl border border-slate-200 dark:border-zinc-800 bg-white dark:bg-zinc-900/40 p-6 shadow-sm"> + <div className="w-full max-w-[320px] flex-shrink-0 rounded-3xl border border-slate-200 dark:border-zinc-800 bg-white dark:bg-zinc-900/40 p-6 shadow-sm">As per coding guidelines, **/*.tsx files must be reviewed for responsive design considerations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/TestimonialCard.tsx` at line 16, The TestimonialCard div uses a fixed width ("w-[320px]") which prevents shrinking; update the className on the root div in the TestimonialCard component to use responsive sizing (replace "w-[320px]" with "max-w-[320px] w-full" in the className string) so the card keeps a 320px max but can shrink on smaller screens.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/TestimonialCard.tsx`:
- Around line 21-27: The star-rating output in TestimonialCard uses
testimonial.rating to render star spans but has no accessible label; update the
container (the div rendering the stars) to include an accessible label (e.g.,
aria-label or role="img" with aria-label) that exposes the rating value and
scale (for example: "Rating: X out of 5") so screen readers announce the meaning
and value; keep the conditional using testimonial.rating and preserve the
Array.from mapping of spans but ensure the aria-label references
testimonial.rating (and optional max value) to provide semantic context.
In `@src/components/TestimonialsMarquee.tsx`:
- Around line 6-11: Duplicate Testimonial interface is defined in multiple
components; extract the interface named Testimonial into a single shared type
file (e.g., export interface Testimonial { name: string; role: string; text:
string; rating?: number }) and remove the local definitions, then update the
components that reference Testimonial (TestimonialsMarquee and TestimonialCard)
to import the shared Testimonial type instead of declaring it inline.
- Around line 47-56: The marquee only pauses on hover; make it
keyboard-accessible by adding a focused/keyboard-controlled pause state:
introduce a local state (e.g., paused) in TestimonialsMarquee and apply it to
the marquee animation logic, make the outer container (the element with
className "marquee-container") focusable (tabIndex=0), add onFocus={() =>
setPaused(true)} and onBlur={() => setPaused(false)}, and handle onKeyDown on
that same element to toggle or set paused when Space or Enter is pressed; also
add an accessible label (aria-label) describing the control and ensure
TestimonialCard rendering (duplicatedTestimonials map) continues to use the same
keys. Ensure the pause state is the single source of truth for stopping the
marquee animation.
---
Outside diff comments:
In `@src/app/page.tsx`:
- Around line 376-397: Replace the manual grid mapping of testimonials in the
page component with the new TestimonialsMarquee component: import
TestimonialsMarquee, remove the block that maps testimonials.map(...) (the div
with className "grid md:grid-cols-3 gap-6" and its children), and render
<TestimonialsMarquee testimonials={testimonials} /> in its place ensuring you
pass the testimonials array prop; also remove any duplicate styling wrapper that
is no longer needed and keep any surrounding section/container markup intact.
---
Nitpick comments:
In `@src/app/page.tsx`:
- Around line 115-131: The testimonials array used to render TestimonialCard
instances is missing the optional rating property, so add a numeric rating
(e.g., 1–5) to each testimonial object in the testimonials constant (the objects
for "Aarav Sharma", "Neha Verma", "Rohit Mehta") so TestimonialCard can display
stars; ensure the property name is exactly rating and matches the prop expected
by TestimonialCard and that any mapping/prop-passing code that spreads or
selects fields (where testimonials are mapped into <TestimonialCard ... />)
continues to pass the rating through.
In `@src/components/TestimonialCard.tsx`:
- Line 16: The TestimonialCard div uses a fixed width ("w-[320px]") which
prevents shrinking; update the className on the root div in the TestimonialCard
component to use responsive sizing (replace "w-[320px]" with "max-w-[320px]
w-full" in the className string) so the card keeps a 320px max but can shrink on
smaller screens.
In `@src/components/TestimonialsMarquee.tsx`:
- Around line 49-53: The key prop on the mapped duplicatedTestimonials currently
uses `${testimonial.name}-${index}` which can collide for duplicate names;
update the mapping in the duplicatedTestimonials => TestimonialCard render to
use a truly unique identifier (prefer testimonial.id if available) or compose a
more unique key (e.g., combine testimonial.id or email with index or timestamp)
and set that as the key prop on TestimonialCard so keys are stable and unique
across renders.
- Around line 13-17: The TestimonialsMarquee component does not handle empty or
undefined testimonials, which can produce an empty marquee or runtime errors;
update the TestimonialsMarquee function to guard the testimonials prop (e.g., if
(!testimonials || testimonials.length === 0) ...) and return a sensible empty
state UI or null/placeholder (a short message or skeleton) so downstream code
that maps or renders items (inside TestimonialsMarquee) never runs against
undefined/empty arrays; ensure the guard is added before any map/iteration or
marquee logic in TestimonialsMarquee.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e139874f-20e5-4ae0-b467-8b1852a02974
📒 Files selected for processing (3)
src/app/page.tsxsrc/components/TestimonialCard.tsxsrc/components/TestimonialsMarquee.tsx
|
CodeAnt AI finished reviewing your PR. |
|
Hi @ArshiBansal! Thanks for your work on this. Before we can merge, please address the following:
Once these are fixed, the PR will be automatically evaluated again. Let us know if you need any help! |
User description
Description
Adds an enhanced testimonials experience by introducing a horizontally scrolling marquee for displaying user reviews and a review submission form for collecting new testimonials.
Changes Made
-> Infinite scrolling testimonial cards.
-> Pause-on-hover functionality for improved readability.
-> Responsive behavior across desktop and mobile devices.
->Enter their name.
-> Select a role (Student, Teacher, Admin, Other).
-> Provide an optional rating.
-> Submit a testimonial message.
Related Issue
Closes #464
Type of Change
Screenshots (if UI change)
How Has This Been Tested?
npm run devChecklist
npm run dev)anytypes)mainCodeAnt-AI Description
Add a scrolling testimonial display with star ratings
What Changed
Impact
✅ More visible social proof✅ Easier reading of customer reviews✅ Smoother testimonial viewing on mobile💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.
Summary by CodeRabbit