Debuggler LogoDebuggler
All challenges
The Aggressive Table RowLists / TablesRadix UI & Shadcn
import { useState, useEffect } from "react";

const INITIAL_DATA = [
  { id: 1, name: "Marketing Campaign", status: "Active" },
  { id: 2, name: "Q3 Financials", status: "Draft" },
  { id: 3, name: "Website Redesign", status: "Active" }
];

export default function App() {
  const [projects, setProjects] = useState(INITIAL_DATA);
  const [activeProject, setActiveProject] = useState(null);

  useEffect(() => {
    const b = document.body;
    b.style.background = "#fafafa"; b.style.margin = "0";
    return () => { b.style.background = ""; b.style.margin = ""; };
  }, []);

  const handleDelete = (id) => {
    // BUG FIX NEEDED: e.stopPropagation() should be called in the onClick handler
    // Currently, clicking delete bubbles up to the row, triggering setActiveProject
    setProjects(prev => prev.filter(p => p.id !== id));
  };

  if (activeProject) {
    return (
      <div style={styles.page}>
        <div data-testid="detail-view" style={styles.card}>
          <button data-testid="back-btn" onClick={() => setActiveProject(null)} style={styles.backBtn}>← Back to list</button>
          <h1 style={styles.h1}>{activeProject.name} Details</h1>
          <p style={styles.sub}>Status: {activeProject.status}</p>
        </div>
      </div>
    );
  }

  return (
    <div style={styles.page}>
      <div style={styles.card}>
        <h1 style={styles.h1}>Projects</h1>
        <div style={styles.list}>
          {projects.map(project => (
            <div 
              key={project.id} 
              data-testid={`row-${project.id}`}
              onClick={() => setActiveProject(project)} 
              style={styles.row}
            >
              <div>
                <div style={styles.rowTitle}>{project.name}</div>
                <div style={styles.rowSub}>{project.status}</div>
              </div>
              <button 
                data-testid={`delete-btn-${project.id}`}
                // BUG: Missing e.stopPropagation()
                onClick={(e) => {
                  handleDelete(project.id);
                }} 
                style={styles.deleteBtn}
              >
                Delete
              </button>
            </div>
          ))}
          {projects.length === 0 && <p style={styles.empty}>No projects left.</p>}
        </div>
      </div>
    </div>
  );
}

const styles = {
  page: { display: "flex", justifyContent: "center", padding: "40px 20px", fontFamily: "system-ui, sans-serif" },
  card: { background: "#fff", borderRadius: 12, padding: "24px", width: "100%", maxWidth: 480, boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1)" },
  h1: { margin: "0 0 20px", fontSize: 20, fontWeight: 600, color: "#111827" },
  sub: { margin: 0, fontSize: 15, color: "#4B5563" },
  backBtn: { background: "none", border: "none", color: "#4F46E5", cursor: "pointer", padding: 0, marginBottom: 16, fontSize: 14, fontWeight: 500 },
  list: { display: "flex", flexDirection: "column", gap: 12 },
  row: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "16px", border: "1px solid #E5E7EB", borderRadius: 8, cursor: "pointer", transition: "border-color 0.2s" },
  rowTitle: { fontSize: 15, fontWeight: 500, color: "#111827", marginBottom: 4 },
  rowSub: { fontSize: 13, color: "#6B7280" },
  deleteBtn: { background: "#FEE2E2", color: "#EF4444", border: "none", padding: "6px 12px", borderRadius: 6, fontSize: 13, fontWeight: 500, cursor: "pointer" },
  empty: { textAlign: "center", color: "#6B7280", padding: 20 }
};

Clicking 'Delete' on a project removes it, but also abruptly navigates you to its detail view. Fix the event bubbling.

After you fix it

  • Clicking Delete should remove the project without navigating.
  • Clicking the rest of the row should still navigate to the detail view.

Click "Run checks" to verify your solution.