Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export default function CompletedOutcomeRow(props) {
</span>
</Show>

{/* Checklist type */}
<span class='text-foreground text-sm font-medium'>
{/* Checklist type badge */}
<span class='bg-secondary text-secondary-foreground rounded-full px-2 py-0.5 text-xs font-medium'>
{getChecklistMetadata(outcomeGroup().type)?.name || outcomeGroup().type}
</span>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* CompletedStudyRow - Compact study row for the completed tab
* CompletedStudyRow - Study row for the completed tab
*
* Displays study info, completed checklist(s), collapsible PDF section, and
* button to view previous reviewer checklists (for dual-reviewer studies).
* Supports multiple outcomes - shows expandable sections when multiple outcomes exist.
* Single-outcome studies show inline badges + buttons in the header.
* Multi-outcome studies show stacked sub-rows (always visible).
* PDFs are expandable via chevron.
*/

import { For, Show, createMemo, createSignal } from 'solid-js';
Expand All @@ -17,13 +17,8 @@ import PreviousReviewersView from './PreviousReviewersView.jsx';
import CompletedOutcomeRow from './CompletedOutcomeRow.jsx';

export default function CompletedStudyRow(props) {
// props.study: Study object with pdfs and checklists arrays
// props.onOpenChecklist: (checklistId) => void
// props.onViewPdf: (pdf) => void
// props.onDownloadPdf: (pdf) => void
// props.getReconciliationProgress: (outcomeId, type) => Object | null
// props.getAssigneeName: (userId) => string
// props.getOutcomeName: (outcomeId) => string | null
// props.study, props.onOpenChecklist, props.onViewPdf, props.onDownloadPdf,
// props.getReconciliationProgress, props.getAssigneeName, props.getOutcomeName

const [expanded, setExpanded] = createSignal(false);
const [showPreviousReviewers, setShowPreviousReviewers] = createSignal(false);
Expand Down Expand Up @@ -59,10 +54,7 @@ export default function CompletedStudyRow(props) {
return getCompletedChecklistsByOutcome(study());
});

// Check if there are multiple outcomes
const hasMultipleOutcomes = () => completedOutcomeGroups().length > 1;

// Get the first group for compact display
const firstGroup = () => completedOutcomeGroups()[0];

// Check if we have previous reviewers to show (for first group in single-outcome mode)
Expand All @@ -73,12 +65,9 @@ export default function CompletedStudyRow(props) {
return !!(progress?.checklist1Id && progress?.checklist2Id);
};

// Determine if row should be expandable (has PDFs or multiple outcomes)
const isExpandable = () => hasPdfs() || hasMultipleOutcomes();

// Handle row click - toggle unless clicking on interactive elements or selectable text
// Handle row click - only for PDF expansion
const handleRowClick = e => {
if (!isExpandable()) return;
if (!hasPdfs()) return;
const target = e.target;
const interactive = target.closest('button, [role="button"], [data-selectable]');
if (interactive) return;
Expand All @@ -89,12 +78,13 @@ export default function CompletedStudyRow(props) {
<>
<div class='border-border bg-card hover:border-border-strong overflow-hidden rounded-lg border transition-colors'>
<Collapsible open={expanded()}>
{/* Study header */}
<div
class={`flex items-center gap-3 px-4 py-3 select-none ${isExpandable() ? 'cursor-pointer' : ''}`}
class={`flex flex-wrap items-center gap-3 px-4 py-3 select-none ${hasPdfs() ? 'cursor-pointer' : ''}`}
onClick={handleRowClick}
>
{/* Chevron indicator (only if expandable) */}
<Show when={isExpandable()}>
{/* Chevron for PDFs */}
<Show when={hasPdfs()}>
<div class='-ml-1 shrink-0 p-1'>
<BiRegularChevronRight
class={`text-muted-foreground/70 h-5 w-5 transition-transform duration-200 ${expanded() ? 'rotate-90' : ''}`}
Expand All @@ -107,7 +97,6 @@ export default function CompletedStudyRow(props) {
<div class='flex items-center gap-2'>
<span class='text-foreground truncate font-medium'>{study().name}</span>
</div>
{/* Citation line - selectable */}
<Show when={citationLine()}>
<p
class='text-muted-foreground w-fit cursor-text truncate text-xs select-text'
Expand All @@ -117,77 +106,50 @@ export default function CompletedStudyRow(props) {
<Show when={hasPdfs()}>
<span class='text-muted-foreground/70'> · {pdfCount()} PDFs</span>
</Show>
<Show when={hasMultipleOutcomes()}>
<span class='text-muted-foreground/70'>
{' '}
· {completedOutcomeGroups().length} outcomes
</span>
</Show>
</p>
</Show>
<Show when={!citationLine() && (hasPdfs() || hasMultipleOutcomes())}>
<p class='text-muted-foreground/70 text-xs'>
<Show when={hasPdfs()}>{pdfCount()} PDFs</Show>
<Show when={hasPdfs() && hasMultipleOutcomes()}> · </Show>
<Show when={hasMultipleOutcomes()}>
{completedOutcomeGroups().length} outcomes
</Show>
</p>
<Show when={!citationLine() && hasPdfs()}>
<p class='text-muted-foreground/70 text-xs'>{pdfCount()} PDFs</p>
</Show>
</div>

{/* First outcome badge (if has outcomeId) */}
<Show when={firstGroup()?.outcomeId}>
<span
class='bg-secondary text-secondary-foreground inline-flex shrink-0 cursor-text items-center rounded-full px-2 py-1 text-xs font-medium select-text'
data-selectable
>
{props.getOutcomeName?.(firstGroup().outcomeId) || 'Unknown Outcome'}
</span>
</Show>

{/* Multiple outcomes indicator */}
<Show when={hasMultipleOutcomes()}>
<span class='text-muted-foreground text-xs'>
+{completedOutcomeGroups().length - 1} more
</span>
</Show>
{/* Single outcome: inline badges + buttons */}
<Show when={!hasMultipleOutcomes() && firstGroup()}>
<Show when={firstGroup()?.outcomeId}>
<span
class='bg-secondary text-secondary-foreground inline-flex shrink-0 cursor-text items-center rounded-full px-2 py-0.5 text-xs font-medium select-text'
data-selectable
>
{props.getOutcomeName?.(firstGroup().outcomeId) || 'Unknown Outcome'}
</span>
</Show>

{/* Checklist type badge - selectable */}
<Show when={firstGroup()}>
<span
class='bg-secondary text-secondary-foreground inline-flex shrink-0 cursor-text items-center rounded-full px-2 py-1 text-xs font-medium select-text'
class='bg-secondary text-secondary-foreground inline-flex shrink-0 cursor-text items-center rounded-full px-2 py-0.5 text-xs font-medium select-text'
data-selectable
>
{getChecklistMetadata(firstGroup()?.type)?.name || 'Checklist'}
</span>
</Show>

{/* Checklist status badge (single outcome mode) */}
<Show when={!hasMultipleOutcomes() && firstGroup()}>
<span
class={`inline-flex shrink-0 cursor-text items-center rounded-full px-2.5 py-1 text-xs font-medium select-text ${getStatusStyle(firstGroup()?.checklists[0]?.status)}`}
data-selectable
>
{getStatusLabel(firstGroup()?.checklists[0]?.status)}
</span>
</Show>

{/* View Previous Reviewers button (single outcome mode, for dual-reviewer studies) */}
<Show when={!hasMultipleOutcomes() && hasPreviousReviewers()}>
<button
onClick={e => {
e.stopPropagation();
setShowPreviousReviewers(true);
}}
class='bg-secondary text-secondary-foreground hover:bg-secondary/80 shrink-0 rounded-lg px-4 py-1.5 text-sm font-medium transition-colors'
>
View Previous
</button>
</Show>
<Show when={hasPreviousReviewers()}>
<button
onClick={e => {
e.stopPropagation();
setShowPreviousReviewers(true);
}}
class='bg-secondary text-secondary-foreground hover:bg-secondary/80 shrink-0 rounded-lg px-4 py-1.5 text-sm font-medium transition-colors'
>
View Previous
</button>
</Show>

{/* Open checklist button (single outcome mode) */}
<Show when={!hasMultipleOutcomes() && firstGroup()}>
<button
onClick={e => {
e.stopPropagation();
Expand All @@ -200,26 +162,26 @@ export default function CompletedStudyRow(props) {
</Show>
</div>

<CollapsibleContent>
{/* Multiple outcomes section */}
<Show when={hasMultipleOutcomes()}>
<div class='border-border-subtle space-y-2 border-t px-4 py-3'>
<For each={completedOutcomeGroups()}>
{outcomeGroup => (
<CompletedOutcomeRow
study={study()}
outcomeGroup={outcomeGroup}
onOpenChecklist={props.onOpenChecklist}
getAssigneeName={props.getAssigneeName}
getOutcomeName={props.getOutcomeName}
getReconciliationProgress={props.getReconciliationProgress}
/>
)}
</For>
</div>
</Show>
{/* Multi-outcome: stacked sub-rows (always visible) */}
<Show when={hasMultipleOutcomes()}>
<div class='divide-border-subtle divide-y'>
<For each={completedOutcomeGroups()}>
{outcomeGroup => (
<CompletedOutcomeRow
study={study()}
outcomeGroup={outcomeGroup}
onOpenChecklist={props.onOpenChecklist}
getAssigneeName={props.getAssigneeName}
getOutcomeName={props.getOutcomeName}
getReconciliationProgress={props.getReconciliationProgress}
/>
)}
</For>
</div>
</Show>

{/* Expanded PDF Section */}
{/* Expandable PDF Section */}
<CollapsibleContent>
<Show when={hasPdfs()}>
<div class='border-border-subtle space-y-2 border-t px-4 py-3'>
<For each={sortedPdfs()}>
Expand Down
Loading