← back to kumarnadar__VGEOSL10

Function bodies 234 total

All specs Real LLM only Function bodies
handleCreate function · typescript · L34-L51 (18 LOC)
src/components/create-rock-dialog.tsx
  async function handleCreate() {
    if (!title.trim() || !quarterId || !user) return

    await supabase.from('rocks').insert({
      title: title.trim(),
      owner_id: user.id,
      group_id: groupId,
      quarter_id: quarterId,
      target_completion_date: targetDate || null,
      notes: notes || null,
    })

    setTitle('')
    setTargetDate('')
    setNotes('')
    setOpen(false)
    mutate(`rocks-${groupId}-${quarterId}`)
  }
CreateRockIdeaDialog function · typescript · L17-L84 (68 LOC)
src/components/create-rock-idea-dialog.tsx
export function CreateRockIdeaDialog({ groupId }: CreateRockIdeaDialogProps) {
  const [open, setOpen] = useState(false)
  const [description, setDescription] = useState('')
  const [suggestedOwner, setSuggestedOwner] = useState<string | null>(null)
  const [priorityColor, setPriorityColor] = useState<string>('green')
  const [comments, setComments] = useState('')
  const supabase = createClient()

  async function handleCreate() {
    if (!description.trim()) return

    await supabase.from('rock_ideas').insert({
      group_id: groupId,
      description: description.trim(),
      suggested_owner_id: suggestedOwner,
      priority_color: priorityColor,
      comments: comments || null,
    })

    setDescription('')
    setSuggestedOwner(null)
    setPriorityColor('green')
    setComments('')
    setOpen(false)
    mutate('rock-ideas')
  }

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button>New Rock Idea</Button>
      </DialogTri
handleCreate function · typescript · L25-L42 (18 LOC)
src/components/create-rock-idea-dialog.tsx
  async function handleCreate() {
    if (!description.trim()) return

    await supabase.from('rock_ideas').insert({
      group_id: groupId,
      description: description.trim(),
      suggested_owner_id: suggestedOwner,
      priority_color: priorityColor,
      comments: comments || null,
    })

    setDescription('')
    setSuggestedOwner(null)
    setPriorityColor('green')
    setComments('')
    setOpen(false)
    mutate('rock-ideas')
  }
CreateTodoDialog function · typescript · L17-L72 (56 LOC)
src/components/create-todo-dialog.tsx
export function CreateTodoDialog({ groupId, sourceIssueId }: CreateTodoDialogProps) {
  const [open, setOpen] = useState(false)
  const [description, setDescription] = useState('')
  const [assignedTo, setAssignedTo] = useState<string | null>(null)
  const [dueDate, setDueDate] = useState(() => {
    const d = new Date()
    d.setDate(d.getDate() + 7)
    return d.toISOString().split('T')[0]
  })
  const supabase = createClient()

  async function handleCreate() {
    if (!description.trim() || !assignedTo || !dueDate) return

    await supabase.from('todos').insert({
      group_id: groupId,
      description: description.trim(),
      assigned_to_id: assignedTo,
      due_date: dueDate,
      source_issue_id: sourceIssueId || null,
    })

    setDescription('')
    setAssignedTo(null)
    setOpen(false)
    mutate(`todos-${groupId}`)
  }

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button variant="outline" size="sm">New To-Do</Bu
handleCreate function · typescript · L28-L43 (16 LOC)
src/components/create-todo-dialog.tsx
  async function handleCreate() {
    if (!description.trim() || !assignedTo || !dueDate) return

    await supabase.from('todos').insert({
      group_id: groupId,
      description: description.trim(),
      assigned_to_id: assignedTo,
      due_date: dueDate,
      source_issue_id: sourceIssueId || null,
    })

    setDescription('')
    setAssignedTo(null)
    setOpen(false)
    mutate(`todos-${groupId}`)
  }
DashboardCard function · typescript · L36-L76 (41 LOC)
src/components/dashboard-grid.tsx
export function DashboardCard({ title, value, subtitle, icon, accent, progress, href, onClick }: DashboardCardProps) {
  const borderClass = accent ? `border-l-4 ${accentBorderMap[accent]}` : ''
  const progressBarColor = accent ? accentProgressMap[accent] : 'bg-primary'
  const isClickable = !!(href || onClick)

  const cardContent = (
    <Card className={`card-hover animate-fade-in h-full ${borderClass} ${isClickable ? 'cursor-pointer group' : ''}`}>
      <CardHeader className="pb-2">
        <div className="flex items-center justify-between">
          <CardTitle className="text-sm font-medium text-muted-foreground">{title}</CardTitle>
          <div className="flex items-center gap-1">
            {icon && <span className="text-muted-foreground">{icon}</span>}
            {href && <ArrowUpRight className="h-4 w-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity" />}
          </div>
        </div>
      </CardHeader>
      <CardContent>
        <p classN
RocksByGroupTable function · typescript · L87-L142 (56 LOC)
src/components/dashboard-grid.tsx
export function RocksByGroupTable({ data }: { data: RocksByGroupRow[] }) {
  return (
    <Card className="card-hover animate-fade-in">
      <CardHeader>
        <CardTitle className="text-base">Rocks by Group</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="table-striped overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="border-b">
                <th className="text-left py-2 font-medium">Group</th>
                <th className="text-right py-2 font-medium">Total</th>
                <th className="text-right py-2 font-medium">On Track</th>
                <th className="text-right py-2 font-medium">Off Track</th>
                <th className="text-right py-2 font-medium">% On Track</th>
              </tr>
            </thead>
            <tbody>
              {data.map((row) => (
                <tr key={row.groupName} className="border-b hover:bg-muted/50">
                  <td className="p
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
RocksByPersonTable function · typescript · L153-L198 (46 LOC)
src/components/dashboard-grid.tsx
export function RocksByPersonTable({ data }: { data: RocksByPersonRow[] }) {
  return (
    <Card className="card-hover animate-fade-in">
      <CardHeader>
        <CardTitle className="text-base">Rocks by Person</CardTitle>
      </CardHeader>
      <CardContent>
        <div className="table-striped overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="border-b">
                <th className="text-left py-2 font-medium">Person</th>
                <th className="text-right py-2 font-medium">Total</th>
                <th className="text-right py-2 font-medium">On Track</th>
                <th className="text-right py-2 font-medium">Off Track</th>
              </tr>
            </thead>
            <tbody>
              {data.map((row) => (
                <tr key={row.personName} className="border-b hover:bg-muted/50">
                  <td className="py-2">
                    {row.groupId && row.ownerId ? (
             
EmptyState function · typescript · L14-L27 (14 LOC)
src/components/empty-state.tsx
export function EmptyState({ icon, title, description, action }: EmptyStateProps) {
  return (
    <div className="flex flex-col items-center justify-center py-16 px-4 animate-fade-in">
      <div className="flex h-16 w-16 items-center justify-center rounded-full bg-primary/10 text-primary mb-4">
        {icon}
      </div>
      <h3 className="text-lg font-semibold mb-1">{title}</h3>
      <p className="text-sm text-muted-foreground text-center max-w-sm mb-4">{description}</p>
      {action && (
        <Button onClick={action.onClick}>{action.label}</Button>
      )}
    </div>
  )
}
FilterChip function · typescript · L11-L25 (15 LOC)
src/components/filter-chip.tsx
export function FilterChip({ label, value, onClear }: FilterChipProps) {
  return (
    <span className="inline-flex items-center gap-1 rounded-full bg-primary/10 text-primary px-3 py-1 text-sm animate-fade-in">
      <span className="text-muted-foreground text-xs">{label}:</span>
      <span className="font-medium">{value}</span>
      <button
        onClick={onClear}
        className="ml-1 rounded-full hover:bg-primary/20 p-0.5 transition-colors"
        aria-label={`Clear ${label} filter`}
      >
        <X className="h-3 w-3" />
      </button>
    </span>
  )
}
FocusTable function · typescript · L30-L152 (123 LOC)
src/components/focus-table.tsx
export function FocusTable({ snapshot, readOnly = false, showOwner = false, ownerName }: FocusTableProps) {
  const supabase = createClient()
  const [newSubject, setNewSubject] = useState('')
  const items = snapshot?.focus_items?.sort((a: any, b: any) => (a.sort_order || 0) - (b.sort_order || 0)) || []

  async function updateItem(itemId: string, field: string, value: any) {
    const updateValue = field === 'prospect_value' ? (value ? Number(value) : null) : (value || null)
    await supabase.from('focus_items').update({ [field]: updateValue }).eq('id', itemId)
    mutate(`focus-${snapshot.user_id}-${snapshot.group_id}-${snapshot.week_date}`)
    mutate(`group-focus-${snapshot.group_id}-${snapshot.week_date}`)
  }

  async function addItem() {
    if (!newSubject.trim() || !snapshot) return
    const maxOrder = items.reduce((max: number, i: any) => Math.max(max, i.sort_order || 0), -1)
    await supabase.from('focus_items').insert({
      snapshot_id: snapshot.id,
      company_subj
updateItem function · typescript · L35-L40 (6 LOC)
src/components/focus-table.tsx
  async function updateItem(itemId: string, field: string, value: any) {
    const updateValue = field === 'prospect_value' ? (value ? Number(value) : null) : (value || null)
    await supabase.from('focus_items').update({ [field]: updateValue }).eq('id', itemId)
    mutate(`focus-${snapshot.user_id}-${snapshot.group_id}-${snapshot.week_date}`)
    mutate(`group-focus-${snapshot.group_id}-${snapshot.week_date}`)
  }
addItem function · typescript · L42-L52 (11 LOC)
src/components/focus-table.tsx
  async function addItem() {
    if (!newSubject.trim() || !snapshot) return
    const maxOrder = items.reduce((max: number, i: any) => Math.max(max, i.sort_order || 0), -1)
    await supabase.from('focus_items').insert({
      snapshot_id: snapshot.id,
      company_subject: newSubject.trim(),
      sort_order: maxOrder + 1,
    })
    setNewSubject('')
    mutate(`focus-${snapshot.user_id}-${snapshot.group_id}-${snapshot.week_date}`)
  }
deleteItem function · typescript · L54-L57 (4 LOC)
src/components/focus-table.tsx
  async function deleteItem(itemId: string) {
    await supabase.from('focus_items').delete().eq('id', itemId)
    mutate(`focus-${snapshot.user_id}-${snapshot.group_id}-${snapshot.week_date}`)
  }
IssueBoard function · typescript · L16-L129 (114 LOC)
src/components/issue-board.tsx
export function IssueBoard({ groupId, showClosed = true }: IssueBoardProps) {
  const supabase = createClient()
  const [expandedId, setExpandedId] = useState<string | null>(null)

  const { data: issues, isLoading } = useSWR(`issues-${groupId}`, async () => {
    const { data, error } = await supabase
      .from('issues')
      .select('*, raised_by_user:profiles!raised_by(full_name), assigned_to:profiles!assigned_to_id(full_name)')
      .eq('group_id', groupId)
      .eq('is_archived', false)
      .order('priority', { ascending: true, nullsFirst: false })
      .order('created_at', { ascending: false })
    if (error) throw error
    return data
  }, { refreshInterval: 30000 })

  async function updateStatus(issueId: string, status: string) {
    const updates: any = { status }
    if (status === 'closed') updates.closed_at = new Date().toISOString()
    await supabase.from('issues').update(updates).eq('id', issueId)
    mutate(`issues-${groupId}`)
  }

  async function updateReso
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
updateStatus function · typescript · L32-L37 (6 LOC)
src/components/issue-board.tsx
  async function updateStatus(issueId: string, status: string) {
    const updates: any = { status }
    if (status === 'closed') updates.closed_at = new Date().toISOString()
    await supabase.from('issues').update(updates).eq('id', issueId)
    mutate(`issues-${groupId}`)
  }
updateResolution function · typescript · L39-L42 (4 LOC)
src/components/issue-board.tsx
  async function updateResolution(issueId: string, notes: string) {
    await supabase.from('issues').update({ resolution_notes: notes }).eq('id', issueId)
    mutate(`issues-${groupId}`)
  }
IssueDetailDialog function · typescript · L19-L127 (109 LOC)
src/components/issue-detail-dialog.tsx
export function IssueDetailDialog({ issue, groupId, open, onOpenChange }: IssueDetailDialogProps) {
  const supabase = createClient()
  const [status, setStatus] = useState(issue?.status || 'open')
  const [resolution, setResolution] = useState(issue?.resolution_notes || '')

  // Reset state when issue changes
  if (issue && status !== issue.status && !open) {
    setStatus(issue.status)
    setResolution(issue.resolution_notes || '')
  }

  async function handleStatusChange(newStatus: string) {
    setStatus(newStatus)
    const updates: any = { status: newStatus }
    if (newStatus === 'closed') updates.closed_at = new Date().toISOString()
    await supabase.from('issues').update(updates).eq('id', issue.id)
    mutate(`issues-${groupId}`)
  }

  async function handleSaveResolution() {
    await supabase.from('issues').update({ resolution_notes: resolution }).eq('id', issue.id)
    mutate(`issues-${groupId}`)
  }

  if (!issue) return null

  const statusColors: Record<string, string
handleStatusChange function · typescript · L30-L36 (7 LOC)
src/components/issue-detail-dialog.tsx
  async function handleStatusChange(newStatus: string) {
    setStatus(newStatus)
    const updates: any = { status: newStatus }
    if (newStatus === 'closed') updates.closed_at = new Date().toISOString()
    await supabase.from('issues').update(updates).eq('id', issue.id)
    mutate(`issues-${groupId}`)
  }
handleSaveResolution function · typescript · L38-L41 (4 LOC)
src/components/issue-detail-dialog.tsx
  async function handleSaveResolution() {
    await supabase.from('issues').update({ resolution_notes: resolution }).eq('id', issue.id)
    mutate(`issues-${groupId}`)
  }
MeetingAgenda function · typescript · L20-L69 (50 LOC)
src/components/meeting-agenda.tsx
export function MeetingAgenda({ activeStep, onStepChange, completedSteps = [] }: MeetingAgendaProps) {
  return (
    <nav className="space-y-0">
      {AGENDA_STEPS.map((step, index) => {
        const isCompleted = completedSteps.includes(step.id)
        const isActive = activeStep === step.id

        return (
          <div key={step.id}>
            {index > 0 && (
              <div className="flex justify-start pl-[15px]">
                <div className={cn(
                  'w-0.5 h-3',
                  completedSteps.includes(AGENDA_STEPS[index - 1].id) ? 'bg-green-500' : 'bg-border'
                )} />
              </div>
            )}
            <button
              onClick={() => onStepChange(step.id)}
              className={cn(
                'w-full text-left rounded-md px-3 py-2 text-sm transition-all duration-200',
                isActive ? 'bg-primary/10' : 'hover:bg-accent'
              )}
            >
              <div className="flex items-center gap
MilestoneList function · typescript · L16-L231 (216 LOC)
src/components/milestone-list.tsx
export function MilestoneList({ rockId, readOnly = false }: MilestoneListProps) {
  const supabase = createClient()
  const [newTitle, setNewTitle] = useState('')

  const { data: milestones, isLoading } = useSWR(`milestones-${rockId}`, async () => {
    const { data, error } = await supabase
      .from('milestones')
      .select('*, collaborators:milestone_collaborators(user_id, profiles(full_name))')
      .eq('rock_id', rockId)
      .order('sort_order', { ascending: true })
    if (error) throw error
    return data
  })

  async function addMilestone() {
    if (!newTitle.trim()) return
    const maxOrder = milestones?.reduce((max: number, m: any) => Math.max(max, m.sort_order), -1) ?? -1
    await supabase.from('milestones').insert({
      rock_id: rockId,
      title: newTitle.trim(),
      sort_order: maxOrder + 1,
    })
    setNewTitle('')
    mutate(`milestones-${rockId}`)
  }

  async function updateMilestone(id: string, field: string, value: any) {
    await supabase.fro
addMilestone function · typescript · L30-L40 (11 LOC)
src/components/milestone-list.tsx
  async function addMilestone() {
    if (!newTitle.trim()) return
    const maxOrder = milestones?.reduce((max: number, m: any) => Math.max(max, m.sort_order), -1) ?? -1
    await supabase.from('milestones').insert({
      rock_id: rockId,
      title: newTitle.trim(),
      sort_order: maxOrder + 1,
    })
    setNewTitle('')
    mutate(`milestones-${rockId}`)
  }
About: code-quality intelligence by Repobility · https://repobility.com
updateMilestone function · typescript · L42-L45 (4 LOC)
src/components/milestone-list.tsx
  async function updateMilestone(id: string, field: string, value: any) {
    await supabase.from('milestones').update({ [field]: value }).eq('id', id)
    mutate(`milestones-${rockId}`)
  }
deleteMilestone function · typescript · L47-L50 (4 LOC)
src/components/milestone-list.tsx
  async function deleteMilestone(id: string) {
    await supabase.from('milestones').delete().eq('id', id)
    mutate(`milestones-${rockId}`)
  }
moveMilestone function · typescript · L52-L72 (21 LOC)
src/components/milestone-list.tsx
  async function moveMilestone(index: number, direction: 'up' | 'down') {
    if (!milestones) return
    const newIndex = direction === 'up' ? index - 1 : index + 1
    if (newIndex < 0 || newIndex >= milestones.length) return

    const updates = milestones.map((m: any, i: number) => {
      let newOrder = m.sort_order
      if (i === index) newOrder = milestones[newIndex].sort_order
      if (i === newIndex) newOrder = milestones[index].sort_order
      return { id: m.id, sort_order: newOrder }
    })

    await Promise.all(
      updates
        .filter((u: any, i: number) => u.sort_order !== milestones[i].sort_order)
        .map((u: any) =>
          supabase.from('milestones').update({ sort_order: u.sort_order }).eq('id', u.id)
        )
    )
    mutate(`milestones-${rockId}`)
  }
CardSkeleton function · typescript · L3-L11 (9 LOC)
src/components/page-skeleton.tsx
export function CardSkeleton() {
  return (
    <div className="rounded-lg border bg-card p-4 space-y-3">
      <Skeleton className="h-4 w-1/3" />
      <Skeleton className="h-8 w-1/2" />
      <Skeleton className="h-3 w-1/4" />
    </div>
  )
}
TableSkeleton function · typescript · L13-L29 (17 LOC)
src/components/page-skeleton.tsx
export function TableSkeleton({ rows = 5 }: { rows?: number }) {
  return (
    <div className="rounded-lg border bg-card p-4 space-y-3">
      <Skeleton className="h-5 w-1/4 mb-4" />
      <div className="space-y-2">
        {Array.from({ length: rows }).map((_, i) => (
          <div key={i} className="flex gap-4">
            <Skeleton className="h-4 w-1/4" />
            <Skeleton className="h-4 w-1/6" />
            <Skeleton className="h-4 w-1/6" />
            <Skeleton className="h-4 w-1/6" />
          </div>
        ))}
      </div>
    </div>
  )
}
KpiSkeleton function · typescript · L31-L38 (8 LOC)
src/components/page-skeleton.tsx
export function KpiSkeleton() {
  return (
    <div className="rounded-lg border bg-card p-4 space-y-2 border-l-4 border-l-muted">
      <Skeleton className="h-3 w-1/2" />
      <Skeleton className="h-7 w-1/3" />
    </div>
  )
}
Providers function · typescript · L5-L11 (7 LOC)
src/components/providers.tsx
export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="light" enableSystem={false}>
      {children}
    </ThemeProvider>
  )
}
QuarterSelector function · typescript · L11-L30 (20 LOC)
src/components/quarter-selector.tsx
export function QuarterSelector({ value, onChange }: QuarterSelectorProps) {
  const { data: quarters, isLoading } = useQuarters()

  if (isLoading || !quarters) return null

  return (
    <Select value={value || undefined} onValueChange={onChange}>
      <SelectTrigger className="w-36 sm:w-48">
        <SelectValue placeholder="Select quarter" />
      </SelectTrigger>
      <SelectContent>
        {quarters.map((q: any) => (
          <SelectItem key={q.id} value={q.id}>
            {q.label} {q.is_current ? '(Current)' : ''}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  )
}
Repobility · severity-and-effort ranking · https://repobility.com
RockCard function · typescript · L16-L92 (77 LOC)
src/components/rock-card.tsx
export function RockCard({ rock, groupId, readOnly = false }: RockCardProps) {
  const supabase = createClient()

  const totalMilestones = rock.milestones?.length || 0
  const doneMilestones = rock.milestones?.filter((m: any) => m.status === 'done').length || 0

  async function toggleStatus() {
    const newStatus = rock.status === 'on_track' ? 'off_track' : 'on_track'
    await supabase
      .from('rocks')
      .update({ status: newStatus })
      .eq('id', rock.id)
    mutate(`rocks-${groupId}-${rock.quarter_id}`)
  }

  return (
    <Card className="card-hover animate-fade-in">
      <CardHeader className="pb-2">
        <div className="flex items-start justify-between">
          <Link href={`/groups/${groupId}/rocks/${rock.id}`} className="hover:underline">
            <CardTitle className="text-base">{rock.title}</CardTitle>
          </Link>
          {!readOnly && (
            <Button
              variant="ghost"
              size="sm"
              onClick={toggleStatus
toggleStatus function · typescript · L22-L29 (8 LOC)
src/components/rock-card.tsx
  async function toggleStatus() {
    const newStatus = rock.status === 'on_track' ? 'off_track' : 'on_track'
    await supabase
      .from('rocks')
      .update({ status: newStatus })
      .eq('id', rock.id)
    mutate(`rocks-${groupId}-${rock.quarter_id}`)
  }
RockCompletionDropdown function · typescript · L17-L118 (102 LOC)
src/components/rock-completion-dropdown.tsx
export function RockCompletionDropdown({ rock, groupId }: RockCompletionDropdownProps) {
  const supabase = createClient()
  const { data: quarters } = useQuarters()
  const [rollForwardOpen, setRollForwardOpen] = useState(false)
  const [targetQuarterId, setTargetQuarterId] = useState('')
  const [rollResult, setRollResult] = useState<string | null>(null)

  const futureQuarters = quarters?.filter((q: any) => q.id !== rock.quarter_id) || []

  async function handleCompletionChange(value: string) {
    if (value === 'rolled_forward') {
      setRollForwardOpen(true)
      return
    }

    await supabase.from('rocks').update({ completion: value }).eq('id', rock.id)
    mutate(`rocks-${groupId}-${rock.quarter_id}`)
    mutate(`rock-${rock.id}`)
  }

  async function handleRollForward() {
    if (!targetQuarterId) return

    const { data, error } = await supabase.rpc('roll_forward_rock', {
      p_rock_id: rock.id,
      p_new_quarter_id: targetQuarterId,
    })

    if (error) {
      
handleCompletionChange function · typescript · L26-L35 (10 LOC)
src/components/rock-completion-dropdown.tsx
  async function handleCompletionChange(value: string) {
    if (value === 'rolled_forward') {
      setRollForwardOpen(true)
      return
    }

    await supabase.from('rocks').update({ completion: value }).eq('id', rock.id)
    mutate(`rocks-${groupId}-${rock.quarter_id}`)
    mutate(`rock-${rock.id}`)
  }
handleRollForward function · typescript · L37-L54 (18 LOC)
src/components/rock-completion-dropdown.tsx
  async function handleRollForward() {
    if (!targetQuarterId) return

    const { data, error } = await supabase.rpc('roll_forward_rock', {
      p_rock_id: rock.id,
      p_new_quarter_id: targetQuarterId,
    })

    if (error) {
      alert('Error rolling forward: ' + error.message)
      return
    }

    setRollResult(data)
    mutate(`rocks-${groupId}-${rock.quarter_id}`)
    mutate(`rocks-${groupId}-${targetQuarterId}`)
    mutate(`rock-${rock.id}`)
  }
CampaignComparisonChart function · typescript · L25-L48 (24 LOC)
src/components/scorecard/campaign-comparison-chart.tsx
export function CampaignComparisonChart({ campaigns }: CampaignComparisonChartProps) {
  if (campaigns.length === 0) return null

  return (
    <div className="space-y-2">
      <p className="text-sm font-medium">Campaign Comparison</p>
      <div className="h-72">
        <ResponsiveContainer width="100%" height="100%">
          <BarChart data={campaigns} margin={{ top: 5, right: 20, left: 10, bottom: 5 }}>
            <CartesianGrid strokeDasharray="3 3" className="opacity-30" />
            <XAxis dataKey="name" tick={{ fontSize: 11 }} angle={-20} textAnchor="end" height={60} />
            <YAxis tick={{ fontSize: 12 }} />
            <Tooltip contentStyle={{ fontSize: 12 }} />
            <Legend wrapperStyle={{ fontSize: 12 }} />
            <Bar dataKey="outreach" fill={COLORS.outreach} name="Outreach" />
            <Bar dataKey="connects" fill={COLORS.connects} name="Connects" />
            <Bar dataKey="meetings" fill={COLORS.meetings} name="Meetings" />
            <Bar d
CampaignGrid function · typescript · L23-L185 (163 LOC)
src/components/scorecard/campaign-grid.tsx
export function CampaignGrid({ campaignId, groupId, weekEndings, readOnly = false }: CampaignGridProps) {
  const { user } = useUser()
  const supabase = createClient()
  const { data: weeklyData } = useCampaignData(campaignId, weekEndings)
  const { data: metrics } = useCampaignMetrics(groupId)
  const [editingCell, setEditingCell] = useState<EditingCell | null>(null)
  const [editValue, setEditValue] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    if (editingCell && inputRef.current) {
      inputRef.current.focus()
      inputRef.current.select()
    }
  }, [editingCell])

  // Build lookup: weekEnding -> JSONB data object
  const dataMap = new Map<string, { id: string; data: Record<string, any> }>()
  weeklyData?.forEach((wd: any) => {
    dataMap.set(wd.week_ending, { id: wd.id, data: wd.data || {} })
  })

  const saveCell = useCallback(async (metricKey: string, weekEnding: string, rawValue: string) => {
    if (!user) return
    const nu
CellEntryPopover function · typescript · L27-L180 (154 LOC)
src/components/scorecard/cell-entry-popover.tsx
export function CellEntryPopover({
  measureId,
  measureName,
  dataType,
  weekEnding,
  groupId,
  weekEndings,
  members,
  userEntryMap,
  aggregateValue,
  readOnly = false,
  children,
}: CellEntryPopoverProps) {
  const { user } = useUser()
  const supabase = createClient()
  const [open, setOpen] = useState(false)
  const [localValue, setLocalValue] = useState('')
  const inputRef = useRef<HTMLInputElement>(null)

  // When popover opens, set local value to current user's entry
  useEffect(() => {
    if (open && user) {
      const entry = userEntryMap.get(`${measureId}-${weekEnding}-${user.id}`)
      setLocalValue(entry?.value != null ? String(entry.value) : '')
    }
  }, [open, user, measureId, weekEnding, userEntryMap])

  // Auto-focus input when popover opens
  useEffect(() => {
    if (open && inputRef.current) {
      const t = setTimeout(() => inputRef.current?.focus(), 50)
      return () => clearTimeout(t)
    }
  }, [open])

  // Compute running total from all me
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
CreateCampaignDialog function · typescript · L23-L88 (66 LOC)
src/components/scorecard/create-campaign-dialog.tsx
export function CreateCampaignDialog({ open, onOpenChange, groupId }: CreateCampaignDialogProps) {
  const supabase = createClient()
  const [name, setName] = useState('')
  const [leadsCount, setLeadsCount] = useState('')
  const [saving, setSaving] = useState(false)

  const handleCreate = async () => {
    if (!name.trim()) return
    setSaving(true)

    const leads = leadsCount ? parseInt(leadsCount, 10) : null

    await supabase.from('campaigns').insert({
      group_id: groupId,
      name: name.trim(),
      leads_count_total: isNaN(leads as number) ? null : leads,
      status: 'active',
    })

    setSaving(false)
    setName('')
    setLeadsCount('')
    onOpenChange(false)
    mutate(`campaigns-${groupId}`)
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>New Campaign</DialogTitle>
          <DialogDescription>Add a new campaign to track outreach metrics.</DialogDescription>
        </
DetailLineItemsPanel function · typescript · L32-L228 (197 LOC)
src/components/scorecard/detail-line-items-panel.tsx
export function DetailLineItemsPanel({
  open,
  onOpenChange,
  entryId,
  measureName,
  entryValue,
  dataType,
  weekEnding,
  readOnly = false,
}: DetailLineItemsPanelProps) {
  const supabase = createClient()
  const { data: details, isLoading } = useEntryDetails(entryId)
  const [newName, setNewName] = useState('')
  const [newValue, setNewValue] = useState('')
  const [newNotes, setNewNotes] = useState('')

  // Calculate sum of line items
  const lineItemSum = details?.reduce((sum: number, d: any) => sum + (Number(d.line_value) || 0), 0) || 0
  const hasMismatch = entryValue != null && details && details.length > 0 && Math.abs(lineItemSum - entryValue) > 0.01

  const addLineItem = useCallback(async () => {
    if (!entryId || !newName.trim()) return
    const value = newValue ? parseFloat(newValue.replace(/[$,]/g, '')) : null

    await supabase.from('scorecard_entry_details').insert({
      entry_id: entryId,
      line_name: newName.trim(),
      line_value: isNaN(value as 
EntryStatusBadge function · typescript · L11-L22 (12 LOC)
src/components/scorecard/entry-status-badge.tsx
export function EntryStatusBadge({ userName, hasUpdated }: EntryStatusBadgeProps) {
  return (
    <div className="flex items-center gap-2 text-sm">
      {hasUpdated ? (
        <CheckCircle2 className="h-4 w-4 text-green-500 shrink-0" />
      ) : (
        <XCircle className="h-4 w-4 text-red-400 shrink-0" />
      )}
      <span className={cn(!hasUpdated && 'text-muted-foreground')}>{userName}</span>
    </div>
  )
}
GoalEditor function · typescript · L31-L149 (119 LOC)
src/components/scorecard/goal-editor.tsx
export function GoalEditor({
  open,
  onOpenChange,
  goalId,
  measureId,
  measureName,
  dataType,
  quarter,
  currentValue,
  groupId,
}: GoalEditorProps) {
  const { user } = useUser()
  const supabase = createClient()
  const [newValue, setNewValue] = useState('')
  const [reason, setReason] = useState('')
  const [saving, setSaving] = useState(false)

  const handleSave = useCallback(async () => {
    if (!user) return
    const parsed = parseInputValue(newValue, dataType)
    if (parsed === null) return

    setSaving(true)

    if (goalId) {
      // Update existing goal (trigger auto-logs the change)
      await supabase
        .from('scorecard_goals')
        .update({ goal_value: parsed })
        .eq('id', goalId)

      // Manually insert reason into change log if provided
      if (reason.trim()) {
        // Get the most recent log entry for this goal to add reason
        const { data: logs } = await supabase
          .from('goal_change_log')
          .select('id'
MeetingScorecardReview function · typescript · L26-L170 (145 LOC)
src/components/scorecard/meeting-scorecard-review.tsx
export function MeetingScorecardReview({ groupId, meetingDate, attendees }: MeetingScorecardReviewProps) {
  const { user } = useUser()
  const supabase = createClient()
  const quarterLabel = getCurrentQuarterLabel()

  const { data: settings } = useScorecardSettings(groupId)
  const weekEndingDay = settings?.week_ending_day || 'friday'

  // Determine the relevant week ending for this meeting
  const meetingWeekEnding = useMemo(() => {
    const d = new Date(meetingDate + 'T00:00:00')
    return formatDate(getWeekEnding(d, weekEndingDay))
  }, [meetingDate, weekEndingDay])

  const weekEndings = useMemo(() => [meetingWeekEnding], [meetingWeekEnding])

  const { data: template } = useScorecardTemplate(groupId)
  const { data: entries } = useScorecardEntries(groupId, weekEndings)
  const { data: goals } = useScorecardGoals(groupId, quarterLabel)

  // Calculate entry status per attendee
  const entryStatuses = useMemo(() => {
    if (!template || !entries) return []

    // Get all non
ProgressBar function · typescript · L13-L43 (31 LOC)
src/components/scorecard/progress-bar.tsx
export function ProgressBar({ label, actual, goal, dataType }: ProgressBarProps) {
  const pct = goal > 0 ? Math.min((actual / goal) * 100, 100) : 0
  const overGoal = goal > 0 && actual > goal

  return (
    <div className="space-y-1.5">
      <div className="flex items-center justify-between text-sm">
        <span className="font-medium truncate">{label}</span>
        <span className="text-muted-foreground shrink-0 ml-2">
          {formatValue(actual, dataType)} / {formatValue(goal, dataType)}
        </span>
      </div>
      <div className="h-3 rounded-full bg-muted overflow-hidden">
        <div
          className={cn(
            'h-full rounded-full transition-all duration-500',
            overGoal ? 'bg-green-500' :
            pct >= 70 ? 'bg-green-500' :
            pct >= 40 ? 'bg-yellow-500' :
            'bg-red-500'
          )}
          style={{ width: `${pct}%` }}
        />
      </div>
      <div className="flex justify-between text-xs text-muted-foreground">
RollupRow function · typescript · L21-L104 (84 LOC)
src/components/scorecard/rollup-row.tsx
export function RollupRow({
  label,
  level,
  weekEndings,
  weekTotals,
  goalTotal,
  dataType,
  children,
  defaultExpanded = false,
}: RollupRowProps) {
  const [expanded, setExpanded] = useState(defaultExpanded)

  let grandTotal = 0
  weekEndings.forEach((week) => {
    grandTotal += weekTotals.get(week) || 0
  })

  const pctToGoal = goalTotal ? percentToGoal(grandTotal, goalTotal) : null

  return (
    <>
      <tr
        className={cn(
          'border-t cursor-pointer transition-colors',
          level === 'company' ? 'bg-primary/10 font-semibold' : 'bg-muted/40 font-medium'
        )}
        onClick={() => setExpanded(!expanded)}
      >
        {/* Label with expand/collapse icon */}
        <td className="sticky left-0 z-10 px-3 py-2 text-left whitespace-nowrap"
          style={{ backgroundColor: 'inherit' }}
        >
          <div className="flex items-center gap-1.5">
            {expanded
              ? <ChevronDown className="h-4 w-4 shrink-0 text-muted-for
computeRollupTotals function · typescript · L107-L122 (16 LOC)
src/components/scorecard/rollup-row.tsx
export function computeRollupTotals(
  measureIds: string[],
  weekEndings: string[],
  entryMap: Map<string, any>
): Map<string, number> {
  const totals = new Map<string, number>()
  weekEndings.forEach((week) => {
    let sum = 0
    measureIds.forEach((mid) => {
      const entry = entryMap.get(`${mid}-${week}`)
      if (entry?.value != null) sum += Number(entry.value)
    })
    totals.set(week, sum)
  })
  return totals
}
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
computeGoalTotal function · typescript · L125-L134 (10 LOC)
src/components/scorecard/rollup-row.tsx
export function computeGoalTotal(
  measureIds: string[],
  goalMap: Map<string, number>
): number {
  let total = 0
  measureIds.forEach((mid) => {
    total += goalMap.get(mid) || 0
  })
  return total
}
ScorecardGrid function · typescript · L24-L183 (160 LOC)
src/components/scorecard/scorecard-grid.tsx
export function ScorecardGrid({
  template,
  entries,
  goals,
  weekEndings,
  groupId,
  quarter,
  readOnly = false,
  onCellClick,
  onCreateIssue,
  onGoalEdit,
}: ScorecardGridProps) {
  const { data: members } = useGroupMembers(groupId)

  // Build per-user entry map (for popover individual values)
  const userEntryMap = useMemo(() => {
    const map = new Map<string, any>()
    entries?.forEach((e: any) => {
      map.set(`${e.measure_id}-${e.week_ending}-${e.user_id}`, e)
    })
    return map
  }, [entries])

  // Build aggregate map (for grid cell display - sum per measure+week)
  // Also compute calculated measure values from their formulas
  const aggregateMap = useMemo(() => {
    const map = new Map<string, number>()
    entries?.forEach((e: any) => {
      const key = `${e.measure_id}-${e.week_ending}`
      map.set(key, (map.get(key) || 0) + Number(e.value || 0))
    })

    // Compute calculated measures (e.g., sum of source measures)
    template?.scorecard_sections
ScorecardSection function · typescript · L202-L338 (137 LOC)
src/components/scorecard/scorecard-grid.tsx
function ScorecardSection({
  section,
  weekEndings,
  rollupEntryMap,
  aggregateMap,
  userEntryMap,
  goalMap,
  goalIdMap,
  members,
  groupId,
  readOnly,
  getMeasureTotal,
  onDetailClick,
  onCreateIssue,
  onGoalEdit,
}: ScorecardSectionProps) {
  const measures = section.scorecard_measures || []

  // Compute team-level rollup for this section
  const sectionMeasureIds = measures.filter((m: any) => !m.is_calculated).map((m: any) => m.id)
  const sectionWeekTotals = computeRollupTotals(sectionMeasureIds, weekEndings, rollupEntryMap)
  const sectionGoalTotal = computeGoalTotal(sectionMeasureIds, goalMap)

  return (
    <>
      <RollupRow
        label={section.name}
        level="team"
        weekEndings={weekEndings}
        weekTotals={sectionWeekTotals}
        goalTotal={sectionGoalTotal}
        dataType="currency"
        defaultExpanded={true}
      >
        {measures.map((measure: any) => {
          const goal = goalMap.get(measure.id)
          const total = ge
‹ prevpage 2 / 5next ›