{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "report-card",
  "title": "CodeRabbit Report Card",
  "author": "Ray <hello@ramonclaudio.com>",
  "description": "Display component for CodeRabbit reports with expandable cards, status badges, and markdown rendering. Supports Daily Standup, Sprint Report, and Release Notes formats.",
  "dependencies": [
    "react",
    "lucide-react",
    "react-markdown"
  ],
  "registryDependencies": [
    "button",
    "badge",
    "card",
    "https://coderabbit-shadcn-registry.vercel.app/r/types.json",
    "https://coderabbit-shadcn-registry.vercel.app/r/branding.json"
  ],
  "files": [
    {
      "path": "registry/default/components/report-card/report-card.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport ReactMarkdown from 'react-markdown'\nimport {\n  ChevronRight,\n  Clock,\n  ExternalLink,\n  Trash2,\n  XCircle,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from '@/components/ui/card'\nimport {\n  CodeRabbitIcon,\n  CodeRabbitLogo,\n} from '@/registry/default/ui/branding'\nimport type { StoredReport } from '@/registry/default/lib/types'\n\nexport interface CodeRabbitReportCardProps {\n  reports: StoredReport[]\n  onDelete?: (id: string) => void\n  isDeleting?: boolean\n}\n\nexport function CodeRabbitReportCard({\n  reports,\n  onDelete,\n  isDeleting = false,\n}: CodeRabbitReportCardProps) {\n  const [expandedReportId, setExpandedReportId] = React.useState<string | null>(\n    null,\n  )\n\n  if (reports.length === 0) {\n    return (\n      <Card>\n        <CardHeader>\n          <CardTitle>Recent Reports</CardTitle>\n          <CardDescription>No reports generated yet</CardDescription>\n        </CardHeader>\n      </Card>\n    )\n  }\n\n  return (\n    <Card>\n      <CardHeader>\n        <CardTitle>Recent Reports</CardTitle>\n        <CardDescription>\n          View your generated activity reports ({reports.length})\n        </CardDescription>\n      </CardHeader>\n      <CardContent>\n        <div className=\"space-y-4\">\n          {reports.map((report) => {\n            const isExpanded = expandedReportId === report.id\n\n            return (\n              <div\n                key={report.id}\n                className=\"group border rounded-lg p-5 hover:shadow-md hover:border-primary/20 transition-all duration-200\"\n              >\n                <div\n                  className=\"flex items-start justify-between gap-4 cursor-pointer\"\n                  onClick={() => {\n                    if (\n                      report.status === 'completed' &&\n                      report.results.length > 0\n                    ) {\n                      setExpandedReportId(isExpanded ? null : report.id)\n                    }\n                  }}\n                >\n                  <div className=\"space-y-2 flex-1 min-w-0\">\n                    <div className=\"flex items-center gap-3 flex-wrap\">\n                      <CodeRabbitIcon className=\"h-4 w-4 shrink-0\" />\n                      <Badge variant=\"secondary\" className=\"text-xs\">\n                        CodeRabbit\n                      </Badge>\n                      <h3 className=\"text-base font-semibold truncate\">\n                        {report.promptTemplate || 'Custom Report'}\n                      </h3>\n                      {report.status === 'pending' && (\n                        <>\n                          <Clock className=\"h-4 w-4 text-yellow-500 shrink-0 animate-pulse\" />\n                          <Badge\n                            variant=\"outline\"\n                            className=\"border-yellow-500 text-yellow-500\"\n                          >\n                            Pending\n                          </Badge>\n                        </>\n                      )}\n                      {report.status === 'completed' && (\n                        <Badge\n                          variant=\"outline\"\n                          className=\"border-green-500 text-green-500\"\n                        >\n                          Completed\n                        </Badge>\n                      )}\n                      {report.status === 'failed' && (\n                        <>\n                          <XCircle className=\"h-4 w-4 text-destructive shrink-0\" />\n                          <Badge variant=\"destructive\">Failed</Badge>\n                        </>\n                      )}\n                    </div>\n                    <div className=\"flex items-center gap-3 text-xs text-muted-foreground flex-wrap\">\n                      <span>\n                        {new Date(\n                          report.fromDate + 'T00:00:00',\n                        ).toLocaleDateString('en-US', {\n                          month: 'short',\n                          day: 'numeric',\n                          year: 'numeric',\n                        })}{' '}\n                        -{' '}\n                        {new Date(\n                          report.toDate + 'T00:00:00',\n                        ).toLocaleDateString('en-US', {\n                          month: 'short',\n                          day: 'numeric',\n                          year: 'numeric',\n                        })}\n                      </span>\n                    </div>\n                  </div>\n\n                  <div className=\"flex items-center gap-2\">\n                    {onDelete && (\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        className=\"h-8 w-8 text-muted-foreground hover:text-destructive\"\n                        onClick={(e) => {\n                          e.stopPropagation()\n                          onDelete(report.id)\n                        }}\n                        disabled={isDeleting}\n                      >\n                        <Trash2 className=\"h-4 w-4\" />\n                      </Button>\n                    )}\n                    {report.status === 'completed' &&\n                      report.results.length > 0 && (\n                        <ChevronRight\n                          className={`h-5 w-5 text-muted-foreground shrink-0 transition-all duration-200 ${\n                            isExpanded\n                              ? 'rotate-90'\n                              : 'group-hover:translate-x-1'\n                          }`}\n                        />\n                      )}\n                  </div>\n                </div>\n\n                {/* Error Display */}\n                {report.status === 'failed' && report.error && (\n                  <div className=\"mt-3 p-3 bg-destructive/10 border border-destructive/20 rounded text-sm text-destructive\">\n                    {report.error}\n                  </div>\n                )}\n\n                {/* Report Results */}\n                {isExpanded && report.status === 'completed' && (\n                  <div className=\"mt-6 space-y-4\">\n                    {report.results.map((result, idx) => {\n                      // Check if this is Daily Standup format (has PR Link markers)\n                      const isDailyStandup =\n                        result.report.includes('**PR Link:**')\n\n                      if (isDailyStandup) {\n                        return (\n                          <DailyStandupView\n                            key={idx}\n                            group={result.group}\n                            report={result.report}\n                          />\n                        )\n                      }\n\n                      // Sprint Report / Release Notes - check if we can extract PR-level details\n                      const hasMultiplePRs =\n                        (result.report.match(/\\[#\\d+\\]/g) || []).length > 1\n\n                      if (hasMultiplePRs) {\n                        return (\n                          <MultiPRView\n                            key={idx}\n                            group={result.group}\n                            report={result.report}\n                          />\n                        )\n                      }\n\n                      // Fallback: single card with full markdown\n                      return (\n                        <MarkdownReportView\n                          key={idx}\n                          group={result.group}\n                          report={result.report}\n                        />\n                      )\n                    })}\n                  </div>\n                )}\n              </div>\n            )\n          })}\n        </div>\n      </CardContent>\n    </Card>\n  )\n}\n\nfunction DailyStandupView({\n  group,\n  report,\n}: {\n  group: string\n  report: string\n}) {\n  const prs = report\n    .split(/(?=^- \\*\\*PR Link:\\*\\*)/m)\n    .filter((pr: string) => pr.trim())\n\n  return (\n    <div className=\"space-y-4\">\n      <h4 className=\"font-semibold text-lg mb-4\">{group}</h4>\n      <div className=\"space-y-4\">\n        {prs.map((pr: string, prIdx: number) => {\n          const prLinkMatch = pr.match(/\\*\\*PR Link:\\*\\*\\s*\\[(.*?)\\]\\((.*?)\\)/)\n          const summaryMatch = pr.match(/\\*\\*Summary:\\*\\*\\s*(.*?)(?=\\n|$)/)\n          const nextStepsMatch = pr.match(/\\*\\*Next Steps:\\*\\*\\s*(.*?)(?=\\n|$)/)\n\n          const prNumberMatch =\n            prLinkMatch?.[1]?.match(/#(\\d+)/) ||\n            prLinkMatch?.[2]?.match(/\\/pull\\/(\\d+)/)\n          const prNumber = prNumberMatch?.[1]\n\n          const prTitle =\n            prLinkMatch?.[1]?.replace(/#\\d+:?\\s*/, '') ||\n            `Pull Request ${prIdx + 1}`\n          const prUrl = prLinkMatch?.[2]\n          const summary = summaryMatch?.[1]\n          const nextSteps = nextStepsMatch?.[1]\n\n          return (\n            <div\n              key={prIdx}\n              className=\"border rounded-lg p-5 hover:shadow-sm hover:border-primary/20 transition-all duration-200 space-y-4\"\n            >\n              {/* Header */}\n              <div className=\"space-y-3\">\n                <div className=\"flex items-start justify-between gap-3\">\n                  <div className=\"flex items-center gap-3 flex-wrap flex-1 min-w-0\">\n                    {prNumber && (\n                      <Badge\n                        variant=\"secondary\"\n                        className=\"font-mono text-xs shrink-0\"\n                      >\n                        PR #{prNumber}\n                      </Badge>\n                    )}\n                    {prUrl ? (\n                      <a\n                        href={prUrl}\n                        target=\"_blank\"\n                        rel=\"noopener noreferrer\"\n                        className=\"text-base font-semibold hover:text-primary transition-colors truncate group/link inline-flex items-center gap-2\"\n                      >\n                        <span className=\"truncate\">{prTitle}</span>\n                        <ExternalLink className=\"h-4 w-4 opacity-0 group-hover/link:opacity-100 transition-opacity shrink-0\" />\n                      </a>\n                    ) : (\n                      <h4 className=\"text-base font-semibold truncate\">\n                        {prTitle}\n                      </h4>\n                    )}\n                  </div>\n                </div>\n                {summary && (\n                  <p className=\"text-sm text-muted-foreground leading-relaxed\">\n                    {summary}\n                  </p>\n                )}\n              </div>\n\n              {/* Next Steps */}\n              {nextSteps && (\n                <div className=\"pt-4 border-t space-y-2\">\n                  <div className=\"flex items-center gap-2\">\n                    <div className=\"h-1.5 w-1.5 rounded-full bg-amber-500\" />\n                    <p className=\"text-xs font-semibold text-muted-foreground uppercase tracking-wider\">\n                      Next Steps\n                    </p>\n                  </div>\n                  <p className=\"text-sm text-muted-foreground leading-relaxed pl-3.5\">\n                    {nextSteps}\n                  </p>\n                </div>\n              )}\n\n              {/* Footer */}\n              <div className=\"pt-3 border-t flex items-center justify-end gap-1.5 text-xs text-muted-foreground\">\n                <span>Powered by</span>\n                <a\n                  href=\"https://coderabbit.ai\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"hover:opacity-70 transition-opacity\"\n                >\n                  <CodeRabbitLogo className=\"h-3.5\" />\n                </a>\n              </div>\n            </div>\n          )\n        })}\n      </div>\n    </div>\n  )\n}\n\nfunction MultiPRView({ group, report }: { group: string; report: string }) {\n  const sections: Array<{ title: string; content: string }> = []\n  const lines = report.split('\\n')\n  let currentSection: { title: string; content: string } | null = null\n\n  lines.forEach((line: string) => {\n    const prMatch = line.match(/\\[#(\\d+)\\]\\((.*?)\\)/)\n    if (prMatch) {\n      if (currentSection) {\n        sections.push(currentSection)\n      }\n      currentSection = {\n        title: line,\n        content: '',\n      }\n    } else if (currentSection) {\n      currentSection.content += line + '\\n'\n    }\n  })\n\n  if (currentSection) {\n    sections.push(currentSection)\n  }\n\n  if (sections.length === 0) {\n    return <MarkdownReportView group={group} report={report} />\n  }\n\n  return (\n    <div className=\"space-y-4\">\n      <h4 className=\"font-semibold text-lg mb-4\">{group}</h4>\n      <div className=\"space-y-4\">\n        {sections.map((section, sectionIdx) => {\n          const prMatch = section.title.match(/\\[#(\\d+)\\]\\((.*?)\\)/)\n          const titleMatch = section.title.match(/\\[#\\d+\\]\\(.*?\\):?\\s*(.*)/)\n\n          const prNumber = prMatch?.[1]\n          const prUrl = prMatch?.[2]\n          const prTitle = titleMatch?.[1]?.trim() || `Pull Request #${prNumber}`\n\n          return (\n            <Card\n              key={sectionIdx}\n              className=\"group hover:shadow-lg hover:border-primary/20 transition-all duration-200\"\n            >\n              <CardHeader className=\"pb-4 bg-card\">\n                <div className=\"flex items-start justify-between gap-3\">\n                  <div className=\"flex-1 space-y-2\">\n                    <div className=\"flex items-center gap-2\">\n                      {prNumber && (\n                        <Badge\n                          variant=\"secondary\"\n                          className=\"font-mono text-xs px-2 py-0.5\"\n                        >\n                          PR #{prNumber}\n                        </Badge>\n                      )}\n                    </div>\n                    <CardTitle className=\"text-base leading-tight\">\n                      {prUrl ? (\n                        <Button\n                          variant=\"link\"\n                          className=\"h-auto p-0 text-base font-semibold text-foreground hover:text-primary inline-flex items-center gap-1.5 group/link\"\n                          asChild\n                        >\n                          <a\n                            href={prUrl}\n                            target=\"_blank\"\n                            rel=\"noopener noreferrer\"\n                          >\n                            <span>{prTitle}</span>\n                            <ExternalLink className=\"h-3.5 w-3.5 opacity-0 -translate-x-1 group-hover/link:opacity-100 group-hover/link:translate-x-0 transition-all\" />\n                          </a>\n                        </Button>\n                      ) : (\n                        prTitle\n                      )}\n                    </CardTitle>\n                  </div>\n                </div>\n              </CardHeader>\n\n              {section.content.trim() && (\n                <CardContent className=\"pt-0\">\n                  <MarkdownContent content={section.content} />\n                </CardContent>\n              )}\n\n              <CardFooter className=\"border-t py-3 px-6 justify-end\">\n                <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n                  <span>Powered by</span>\n                  <Button variant=\"link\" size=\"sm\" className=\"h-auto p-0\" asChild>\n                    <a\n                      href=\"https://coderabbit.ai\"\n                      target=\"_blank\"\n                      rel=\"noopener noreferrer\"\n                    >\n                      <CodeRabbitLogo className=\"h-3.5\" />\n                    </a>\n                  </Button>\n                </div>\n              </CardFooter>\n            </Card>\n          )\n        })}\n      </div>\n    </div>\n  )\n}\n\nfunction MarkdownReportView({\n  group,\n  report,\n}: {\n  group: string\n  report: string\n}) {\n  return (\n    <div className=\"space-y-4\">\n      <h4 className=\"font-semibold text-lg mb-4\">{group}</h4>\n      <Card className=\"hover:shadow-lg hover:border-primary/20 transition-all duration-200\">\n        <CardContent className=\"py-6\">\n          <MarkdownContent content={report} fullReport />\n        </CardContent>\n        <CardFooter className=\"border-t py-3 px-6 justify-end\">\n          <div className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n            <span>Powered by</span>\n            <Button variant=\"link\" size=\"sm\" className=\"h-auto p-0\" asChild>\n              <a\n                href=\"https://coderabbit.ai\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n              >\n                <CodeRabbitLogo className=\"h-3.5\" />\n              </a>\n            </Button>\n          </div>\n        </CardFooter>\n      </Card>\n    </div>\n  )\n}\n\nfunction MarkdownContent({\n  content,\n  fullReport = false,\n}: {\n  content: string\n  fullReport?: boolean\n}) {\n  return (\n    <ReactMarkdown\n      components={{\n        h1: ({ children }) =>\n          fullReport ? (\n            <CardTitle className=\"text-xl mb-6 pb-3 border-b\">\n              {children}\n            </CardTitle>\n          ) : (\n            <h1 className=\"text-xl font-bold mb-4\">{children}</h1>\n          ),\n        h2: ({ children }) =>\n          fullReport ? (\n            <div className=\"mt-6 mb-3\">\n              <div className=\"flex items-center gap-2 mb-2\">\n                <div className=\"h-1.5 w-1.5 rounded-full bg-primary\" />\n                <h2 className=\"text-base font-semibold uppercase tracking-wider text-muted-foreground text-xs\">\n                  {children}\n                </h2>\n              </div>\n            </div>\n          ) : (\n            <h2 className=\"text-lg font-semibold mt-4 mb-2\">{children}</h2>\n          ),\n        h3: ({ children }) => (\n          <h3 className=\"text-sm font-semibold mt-4 mb-2 text-foreground/90\">\n            {children}\n          </h3>\n        ),\n        p: ({ children }) => (\n          <p className=\"text-sm leading-relaxed mb-3 text-muted-foreground\">\n            {children}\n          </p>\n        ),\n        ul: ({ children }) => (\n          <ul className={`space-y-2 mb-4 ${fullReport ? 'ml-3' : ''}`}>\n            {children}\n          </ul>\n        ),\n        li: ({ children }) => (\n          <li className=\"text-sm leading-relaxed list-none flex items-start gap-2.5\">\n            <span className=\"text-primary mt-1.5 text-xs\">▸</span>\n            <span className=\"flex-1\">{children}</span>\n          </li>\n        ),\n        strong: ({ children }) => (\n          <strong className=\"font-semibold text-foreground\">{children}</strong>\n        ),\n        a: ({ href, children }) => (\n          <Button\n            variant=\"link\"\n            className=\"h-auto p-0 text-sm font-medium inline-flex items-center gap-1 group/link\"\n            asChild\n          >\n            <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n              {children}\n              <ExternalLink className=\"h-3 w-3 opacity-0 group-hover/link:opacity-100 transition-opacity\" />\n            </a>\n          </Button>\n        ),\n        em: ({ children }) => (\n          <em className=\"text-muted-foreground/80 not-italic text-xs\">\n            {children}\n          </em>\n        ),\n        code: ({ children }) => (\n          <code className=\"bg-muted px-1.5 py-0.5 rounded text-xs font-mono border border-border/50\">\n            {children}\n          </code>\n        ),\n        blockquote: ({ children }) => (\n          <blockquote className=\"border-l-2 border-primary/50 pl-4 py-2 my-4 bg-muted/30 rounded-r\">\n            {children}\n          </blockquote>\n        ),\n      }}\n    >\n      {content}\n    </ReactMarkdown>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "reports",
    "components"
  ],
  "type": "registry:component"
}