From 489462ffe55360925fe2441c27a1556a800d89f5 Mon Sep 17 00:00:00 2001 From: Jacob Maynard Date: Thu, 18 Dec 2025 10:46:58 -0600 Subject: [PATCH 1/4] cleaned up some inconsistencies, added multiple pdf support to the todo tab --- .clauderc | 2 + .cursorrules | 2 + docs/plans/dashboard-ux-improvements.plan.md | 334 ++++++++++++++++++ packages/ui/src/index.d.ts | 2 +- .../components/project-ui/ProjectHeader.jsx | 3 +- .../src/components/project-ui/ProjectView.jsx | 14 +- .../project-ui/ReviewerAssignment.jsx | 47 ++- .../src/components/project-ui/StudyCard.jsx | 66 +++- .../AllStudiesTab.jsx | 0 .../AssignReviewersModal.jsx | 0 .../EditPdfMetadataModal.jsx | 0 .../{all-studies => all-studies-tab}/index.js | 0 .../study-card/StudyCard.jsx | 0 .../study-card/StudyCardHeader.jsx | 2 +- .../study-card/StudyPdfSection.jsx | 0 .../study-card/index.js | 0 .../CompletedChecklistRow.jsx | 0 .../CompletedStudyCard.jsx | 0 .../CompletedTab.jsx | 0 .../completed => completed-tab}/index.js | 2 +- .../{tabs => overview-tab}/OverviewTab.jsx | 0 .../project-ui/overview-tab/index.js | 2 + .../ReconcileTab.jsx} | 4 +- .../project-ui/reconcile-tab/index.js | 2 + .../project-ui/{tabs => todo-tab}/ToDoTab.jsx | 60 ++-- .../project-ui/todo-tab/TodoStudyRow.jsx | 202 +++++++++++ .../components/project-ui/todo-tab/index.js | 3 + 27 files changed, 661 insertions(+), 86 deletions(-) create mode 100644 docs/plans/dashboard-ux-improvements.plan.md rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/AllStudiesTab.jsx (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/AssignReviewersModal.jsx (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/EditPdfMetadataModal.jsx (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/index.js (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/study-card/StudyCard.jsx (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/study-card/StudyCardHeader.jsx (99%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/study-card/StudyPdfSection.jsx (100%) rename packages/web/src/components/project-ui/{all-studies => all-studies-tab}/study-card/index.js (100%) rename packages/web/src/components/project-ui/{tabs/completed => completed-tab}/CompletedChecklistRow.jsx (100%) rename packages/web/src/components/project-ui/{tabs/completed => completed-tab}/CompletedStudyCard.jsx (100%) rename packages/web/src/components/project-ui/{tabs/completed => completed-tab}/CompletedTab.jsx (100%) rename packages/web/src/components/project-ui/{tabs/completed => completed-tab}/index.js (71%) rename packages/web/src/components/project-ui/{tabs => overview-tab}/OverviewTab.jsx (100%) create mode 100644 packages/web/src/components/project-ui/overview-tab/index.js rename packages/web/src/components/project-ui/{tabs/ReadyToReconcileTab.jsx => reconcile-tab/ReconcileTab.jsx} (95%) create mode 100644 packages/web/src/components/project-ui/reconcile-tab/index.js rename packages/web/src/components/project-ui/{tabs => todo-tab}/ToDoTab.jsx (60%) create mode 100644 packages/web/src/components/project-ui/todo-tab/TodoStudyRow.jsx create mode 100644 packages/web/src/components/project-ui/todo-tab/index.js diff --git a/.clauderc b/.clauderc index 2b3ba671f..947a592fe 100644 --- a/.clauderc +++ b/.clauderc @@ -8,6 +8,8 @@ the /landing package contains the marketing and landing site. The web package is copied into the landing package during the build process for deployment and all deployed as a single site on a single worker. +Do not worry about migrations either client side or backend unless specifically instructed to do so in the prompt. This project is not in production and has no users. + ## Coding Standards - Do not use emojis in code, comments, documentation, or commit messages. diff --git a/.cursorrules b/.cursorrules index 2b3ba671f..947a592fe 100644 --- a/.cursorrules +++ b/.cursorrules @@ -8,6 +8,8 @@ the /landing package contains the marketing and landing site. The web package is copied into the landing package during the build process for deployment and all deployed as a single site on a single worker. +Do not worry about migrations either client side or backend unless specifically instructed to do so in the prompt. This project is not in production and has no users. + ## Coding Standards - Do not use emojis in code, comments, documentation, or commit messages. diff --git a/docs/plans/dashboard-ux-improvements.plan.md b/docs/plans/dashboard-ux-improvements.plan.md new file mode 100644 index 000000000..768cef874 --- /dev/null +++ b/docs/plans/dashboard-ux-improvements.plan.md @@ -0,0 +1,334 @@ +# Dashboard UX Improvements Plan + +## Current State Analysis + +The dashboard consists of two main sections: + +1. **ProjectDashboard** - Cloud projects for logged-in users +2. **ChecklistsDashboard** - Local appraisals stored in browser + +### Current Structure + +``` +Dashboard.jsx +├── ProjectDashboard.jsx (logged in only) +│ ├── Header with "New Project" button +│ ├── Error display +│ ├── CreateProjectForm.jsx (expandable) +│ └── Projects grid (ProjectCard.jsx) +└── ChecklistsDashboard.jsx + ├── Header with "New Appraisal" button + ├── Sign-in prompt (logged out only) + └── Appraisals grid (inline cards) +``` + +### Pain Points Identified + +1. **Visual Hierarchy Issues** + - Two separate sections feel disconnected + - No clear overview or "welcome" state + - Empty states are inconsistent between sections + +2. **Cognitive Load** + - Users must understand the difference between cloud projects vs local appraisals + - No guidance for new users on what to do first + - CreateProjectForm expands inline, pushing content down + +3. **Discoverability** + - Recent/activity items not surfaced + - No quick stats or progress indicators + - No search or filtering for projects + +4. **Mobile Experience** + - Grid layouts may feel cramped on mobile + - No compact list view option + +5. **Empty States** + - Generic "No projects yet" text + - No illustration or engaging visuals + - No explanation of value proposition + +--- + +## Proposed Improvements + +### Option A: Incremental Improvements (Low Effort) + +Small changes to polish the existing layout without major restructuring. + +#### A1. Unified Header with Tabs + +Replace two separate sections with tabbed navigation: + +``` +[My Projects] [My Appraisals] +``` + +- Cleaner visual hierarchy +- Reduces vertical scrolling +- Better matches ProjectView's tab pattern + +#### A2. Enhanced Empty States + +- Add illustrations/icons to empty states +- Include clear value propositions +- Add quick-start CTAs with descriptions + +#### A3. Improved Card Design + +- Add progress indicators (e.g., "3/5 studies completed") +- Show collaborator avatars on project cards +- Add "last activity" instead of just creation date + +#### A4. Quick Actions + +- Add "Create" dropdown with options (Project/Appraisal) +- Add search/filter bar above grid +- Add sort options (Recent, Name, Progress) + +--- + +### Option B: Dashboard Redesign (Medium Effort) + +A more comprehensive redesign with better information architecture. + +#### B1. Overview Section + +Add a summary section at the top: + +``` +┌─────────────────────────────────────────────┐ +│ Welcome back, [Name]! │ +│ ────────────────────────────────────────── │ +│ [3 Projects] [5 Appraisals] [2 Pending] │ +│ │ +│ Quick Actions: [+ New Project] [+ New App] │ +└─────────────────────────────────────────────┘ +``` + +#### B2. Activity Feed + +Show recent activity across all items: + +- "You completed checklist X in Study Y" +- "Team member joined Project Z" +- "Study awaiting reconciliation" + +#### B3. "Continue Where You Left Off" + +Smart section showing: + +- Most recently edited items (1-3) +- Items needing attention (pending reconciliation) + +#### B4. Unified Items View + +Single grid showing both projects and appraisals with: + +- Type badge (Cloud Project / Local) +- Consistent card design +- Filter chips: [All] [Projects] [Appraisals] + +--- + +### Option C: Complete Overhaul (High Effort) + +Full redesign with new UX patterns. + +#### C1. Kanban-style Board View + +Organize by status: + +``` +[In Progress] → [Ready to Review] → [Completed] +``` + +- Drag-and-drop reordering +- Visual workflow progress +- Great for tracking multiple concurrent projects + +#### C2. Table View Option + +For users with many projects: + +- Sortable columns (Name, Updated, Progress, Role) +- Bulk actions +- Pagination/infinite scroll + +#### C3. Dashboard Widgets + +Customizable dashboard with draggable widgets: + +- Quick stats widget +- Recent activity widget +- Deadlines/reminders widget +- Team activity widget + +--- + +## Recommended Approach + +### Phase 1: Quick Wins (Immediate) + +1. **Improve Empty States** + - Add icons/illustrations + - Better copy explaining value + - Estimated: 1-2 hours + +2. **Add Progress to Cards** + - Show study count/completion on ProjectCard + - Estimated: 2-3 hours + +3. **Unified Create Button** + - Single "Create" button with dropdown menu + - Options: "New Project" and "New Appraisal" + - Estimated: 1-2 hours + +### Phase 2: Structure Improvements (Short-term) + +1. **Tabbed Interface** + - Use existing Tabs component from @corates/ui + - [Projects] [Appraisals] tabs + - Persist tab selection in URL params + - Estimated: 3-4 hours + +2. **Search and Sort** + - Add search input above grid + - Sort dropdown (Recent, Alphabetical) + - Estimated: 4-5 hours + +3. **Modal for Create Forms** + - Move CreateProjectForm to a Dialog modal + - Better UX than inline expansion + - Estimated: 2-3 hours + +### Phase 3: Enhanced Features (Medium-term) + +1. **Recent Activity Section** + - Show last 3-5 items worked on + - "Continue where you left off" section + - Requires: API changes for activity tracking + - Estimated: 1-2 days + +2. **Quick Stats Overview** + - Project/appraisal counts + - Pending items count + - Completion stats + - Estimated: 4-6 hours + +3. **List View Toggle** + - Grid vs List view toggle + - Compact list for many items + - Estimated: 4-6 hours + +--- + +## UI Mockups (ASCII) + +### Current Layout + +``` +┌─────────────────────────────────────────────┐ +│ My Projects [+ New Proj] │ +│ Manage your research projects │ +├─────────────────────────────────────────────┤ +│ [Card][Card][Card][Card] │ +│ │ +├─────────────────────────────────────────────┤ +│ My Appraisals [+ New App] │ +│ Create and manage appraisals locally... │ +├─────────────────────────────────────────────┤ +│ [Sign in prompt banner] │ +│ [Card][Card][Card] │ +└─────────────────────────────────────────────┘ +``` + +### Proposed Layout (Phase 2) + +``` +┌─────────────────────────────────────────────┐ +│ Dashboard [+ Create ▾]│ +│ │ +│ [🔍 Search...] [Sort: Recent ▾]│ +├─────────────────────────────────────────────┤ +│ [Projects (3)] [Appraisals (5)] │ +├─────────────────────────────────────────────┤ +│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ +│ │Card │ │Card │ │Card │ │Card │ │ +│ │ │ │ │ │ │ │ │ │ +│ │ 2/5 │ │ 4/4 │ │ 0/3 │ │ │ │ +│ └─────┘ └─────┘ └─────┘ └─────┘ │ +│ │ +│ [Empty state or more cards] │ +└─────────────────────────────────────────────┘ +``` + +### Enhanced ProjectCard + +``` +┌─────────────────────────────────────────────┐ +│ Sleep Study Meta-Analysis [Owner ▪] │ +│ Analyzing sleep patterns in... │ +├─────────────────────────────────────────────┤ +│ ●●●○○ 3/5 studies Updated 2h ago │ +│ 👤👤 2 members │ +├─────────────────────────────────────────────┤ +│ [Open Project] [🗑] │ +└─────────────────────────────────────────────┘ +``` + +--- + +## Technical Considerations + +### Existing Components to Leverage + +- `Tabs` from @corates/ui +- `Dialog` for modals +- `Menu` for dropdown create button +- `Tooltip` for info hints + +### Store Changes Needed + +- Add `recentActivity` to projectStore (Phase 3) +- Add sorting/filtering state + +### API Changes (Phase 3) + +- New endpoint for activity feed +- Aggregate stats endpoint + +--- + +## Implementation Priority + +| Item | Effort | Impact | Priority | +| ------------------- | ------ | ------ | -------- | +| Better empty states | Low | Medium | P1 | +| Progress on cards | Low | Medium | P1 | +| Create dropdown | Low | Low | P2 | +| Tabbed interface | Medium | High | P1 | +| Search/sort | Medium | High | P2 | +| Modal create form | Low | Medium | P2 | +| Recent activity | High | Medium | P3 | +| Quick stats | Medium | Medium | P3 | +| List view toggle | Medium | Low | P3 | + +--- + +## Questions for Stakeholder + +1. Is the distinction between Cloud Projects and Local Appraisals important to emphasize, or should we blur that line? +2. How many projects/appraisals do power users typically have? +3. Is mobile usage a priority? +4. Should we track "recent activity" server-side? +5. Are there plans for teams/organizations that would affect dashboard structure? + +--- + +## Next Steps + +1. Review this plan and select preferred option/phase +2. Create detailed tasks for selected improvements +3. Implement Phase 1 quick wins +4. Test with users and iterate diff --git a/packages/ui/src/index.d.ts b/packages/ui/src/index.d.ts index 5be052dbb..e38f1d311 100644 --- a/packages/ui/src/index.d.ts +++ b/packages/ui/src/index.d.ts @@ -5,7 +5,7 @@ export interface EditableProps { value?: string; onSubmit?: (_value: string) => void; activationMode?: 'focus' | 'dblclick' | 'click' | 'none'; - variant?: 'default' | 'heading'; + variant?: 'default' | 'heading' | 'inline' | 'field'; showEditIcon?: boolean; readOnly?: boolean; class?: string; diff --git a/packages/web/src/components/project-ui/ProjectHeader.jsx b/packages/web/src/components/project-ui/ProjectHeader.jsx index 706d94af8..9e3f59ae1 100644 --- a/packages/web/src/components/project-ui/ProjectHeader.jsx +++ b/packages/web/src/components/project-ui/ProjectHeader.jsx @@ -83,12 +83,11 @@ export default function ProjectHeader(props) {
diff --git a/packages/web/src/components/project-ui/ProjectView.jsx b/packages/web/src/components/project-ui/ProjectView.jsx index 7a9776289..ded202eda 100644 --- a/packages/web/src/components/project-ui/ProjectView.jsx +++ b/packages/web/src/components/project-ui/ProjectView.jsx @@ -27,11 +27,11 @@ import useProjectMemberHandlers from '@primitives/useProjectMemberHandlers.js'; import { ProjectProvider } from './ProjectContext.jsx'; import AddMemberModal from './AddMemberModal.jsx'; import ProjectHeader from './ProjectHeader.jsx'; -import OverviewTab from './tabs/OverviewTab.jsx'; -import IncludedStudiesTab from './all-studies/AllStudiesTab.jsx'; -import ToDoTab from './tabs/ToDoTab.jsx'; -import ReadyToReconcileTab from './tabs/ReadyToReconcileTab.jsx'; -import CompletedTab from './tabs/completed'; +import { OverviewTab } from './overview-tab'; +import { AllStudiesTab } from './all-studies-tab'; +import { ToDoTab } from './todo-tab'; +import { ReconcileTab } from './reconcile-tab'; +import { CompletedTab } from './completed-tab'; export default function ProjectView() { const params = useParams(); @@ -257,7 +257,7 @@ export default function ProjectView() { - + @@ -265,7 +265,7 @@ export default function ProjectView() { - + diff --git a/packages/web/src/components/project-ui/ReviewerAssignment.jsx b/packages/web/src/components/project-ui/ReviewerAssignment.jsx index d642c57ae..5985c7d0e 100644 --- a/packages/web/src/components/project-ui/ReviewerAssignment.jsx +++ b/packages/web/src/components/project-ui/ReviewerAssignment.jsx @@ -5,14 +5,8 @@ import { createSignal, createMemo, For, Show } from 'solid-js'; import { createStore, produce } from 'solid-js/store'; -import { showToast } from '@corates/ui'; -import { - BiRegularShuffle, - BiRegularCheck, - BiRegularX, - BiRegularChevronDown, - BiRegularChevronUp, -} from 'solid-icons/bi'; +import { showToast, Collapsible } from '@corates/ui'; +import { BiRegularShuffle, BiRegularCheck, BiRegularX, BiRegularChevronRight } from 'solid-icons/bi'; import { FiUsers } from 'solid-icons/fi'; /** @@ -427,22 +421,27 @@ export default function ReviewerAssignment(props) { return (
- {/* Trigger Button */} - - - {/* Expandable Content */} -
= 2} @@ -585,7 +584,7 @@ export default function ReviewerAssignment(props) {
-
+
); } diff --git a/packages/web/src/components/project-ui/StudyCard.jsx b/packages/web/src/components/project-ui/StudyCard.jsx index 883e7d04e..acdbd0a1c 100644 --- a/packages/web/src/components/project-ui/StudyCard.jsx +++ b/packages/web/src/components/project-ui/StudyCard.jsx @@ -17,6 +17,7 @@ * @param {boolean} [props.creatingChecklist] - Loading state for checklist creation * @param {function(type: string, assigneeId: string|number)} props.onAddChecklist - Creates a new checklist for a study * @param {function(Object): void} [props.onViewPdf] - Called to open/view a PDF (passed a PDF object from study.pdfs) + * @param {function(Object): void} [props.onDownloadPdf] - Called to download a PDF (passed a PDF object from study.pdfs) * @param {function(): void} [props.onToggleChecklistForm] - Toggles visibility for the checklist creation form * @param {function(checklistId: string|number): void} [props.onOpenChecklist] - Open a specific checklist for editing/review * @param {function(checklistId: string|number, updates: Object): void} [props.onUpdateChecklist] - Update checklist metadata @@ -25,24 +26,40 @@ * * Behavior * - Renders a card header with the study title and optional citation line - * - Shows a View / Add / Change PDF button depending on whether PDFs exist + * - Shows a collapsible PDF section with all PDFs (read-only, view/download only) * - Allows creating new checklists via an `Add Checklist` button and `ChecklistForm` * - Renders existing checklists using `ChecklistRow` and forwards checklist actions */ -import { For, Show } from 'solid-js'; -import { CgFileDocument } from 'solid-icons/cg'; +import { For, Show, createSignal, createMemo } from 'solid-js'; +import { BiRegularChevronRight } from 'solid-icons/bi'; +import { Collapsible } from '@corates/ui'; import ChecklistForm from './ChecklistForm.jsx'; import ChecklistRow from './ChecklistRow.jsx'; +import PdfListItem from '@/components/checklist-ui/pdf/PdfListItem.jsx'; export default function StudyCard(props) { + const [pdfSectionOpen, setPdfSectionOpen] = createSignal(false); + const handleCreateChecklist = (type, assigneeId) => { props.onAddChecklist(type, assigneeId); }; // Check if study has PDFs const hasPdfs = () => props.study.pdfs && props.study.pdfs.length > 0; - const firstPdf = () => (hasPdfs() ? props.study.pdfs[0] : null); + const pdfCount = () => props.study.pdfs?.length || 0; + + // Sort PDFs: primary first, then protocol, then secondary by uploadedAt desc + const sortedPdfs = createMemo(() => { + if (!hasPdfs()) return []; + return [...props.study.pdfs].sort((a, b) => { + const tagOrder = { primary: 0, protocol: 1, secondary: 2 }; + const tagA = tagOrder[a.tag] ?? 2; + const tagB = tagOrder[b.tag] ?? 2; + if (tagA !== tagB) return tagA - tagB; + return (b.uploadedAt || 0) - (a.uploadedAt || 0); + }); + }); return (
@@ -66,16 +83,6 @@ export default function StudyCard(props) {
- - -
+ {/* Collapsible PDF Section */} + +
+ ( +
+ + PDFs ({pdfCount()}) +
+ )} + > +
+ + {pdf => ( + props.onViewPdf?.(pdf)} + onDownload={() => props.onDownloadPdf?.(pdf)} + readOnly={true} + /> + )} + +
+
+
+
+ {/* Add Checklist Form */}

diff --git a/packages/web/src/components/project-ui/all-studies/study-card/StudyPdfSection.jsx b/packages/web/src/components/project-ui/all-studies-tab/study-card/StudyPdfSection.jsx similarity index 100% rename from packages/web/src/components/project-ui/all-studies/study-card/StudyPdfSection.jsx rename to packages/web/src/components/project-ui/all-studies-tab/study-card/StudyPdfSection.jsx diff --git a/packages/web/src/components/project-ui/all-studies/study-card/index.js b/packages/web/src/components/project-ui/all-studies-tab/study-card/index.js similarity index 100% rename from packages/web/src/components/project-ui/all-studies/study-card/index.js rename to packages/web/src/components/project-ui/all-studies-tab/study-card/index.js diff --git a/packages/web/src/components/project-ui/tabs/completed/CompletedChecklistRow.jsx b/packages/web/src/components/project-ui/completed-tab/CompletedChecklistRow.jsx similarity index 100% rename from packages/web/src/components/project-ui/tabs/completed/CompletedChecklistRow.jsx rename to packages/web/src/components/project-ui/completed-tab/CompletedChecklistRow.jsx diff --git a/packages/web/src/components/project-ui/tabs/completed/CompletedStudyCard.jsx b/packages/web/src/components/project-ui/completed-tab/CompletedStudyCard.jsx similarity index 100% rename from packages/web/src/components/project-ui/tabs/completed/CompletedStudyCard.jsx rename to packages/web/src/components/project-ui/completed-tab/CompletedStudyCard.jsx diff --git a/packages/web/src/components/project-ui/tabs/completed/CompletedTab.jsx b/packages/web/src/components/project-ui/completed-tab/CompletedTab.jsx similarity index 100% rename from packages/web/src/components/project-ui/tabs/completed/CompletedTab.jsx rename to packages/web/src/components/project-ui/completed-tab/CompletedTab.jsx diff --git a/packages/web/src/components/project-ui/tabs/completed/index.js b/packages/web/src/components/project-ui/completed-tab/index.js similarity index 71% rename from packages/web/src/components/project-ui/tabs/completed/index.js rename to packages/web/src/components/project-ui/completed-tab/index.js index 1008267e5..5cec5dd70 100644 --- a/packages/web/src/components/project-ui/tabs/completed/index.js +++ b/packages/web/src/components/project-ui/completed-tab/index.js @@ -1,3 +1,3 @@ export { default as CompletedStudyCard } from './CompletedStudyCard.jsx'; export { default as CompletedChecklistRow } from './CompletedChecklistRow.jsx'; -export { default } from './CompletedTab.jsx'; +export { default as CompletedTab } from './CompletedTab.jsx'; diff --git a/packages/web/src/components/project-ui/tabs/OverviewTab.jsx b/packages/web/src/components/project-ui/overview-tab/OverviewTab.jsx similarity index 100% rename from packages/web/src/components/project-ui/tabs/OverviewTab.jsx rename to packages/web/src/components/project-ui/overview-tab/OverviewTab.jsx diff --git a/packages/web/src/components/project-ui/overview-tab/index.js b/packages/web/src/components/project-ui/overview-tab/index.js new file mode 100644 index 000000000..0ba58d9a1 --- /dev/null +++ b/packages/web/src/components/project-ui/overview-tab/index.js @@ -0,0 +1,2 @@ +// overview barrel export +export { default as OverviewTab } from './OverviewTab.jsx'; diff --git a/packages/web/src/components/project-ui/tabs/ReadyToReconcileTab.jsx b/packages/web/src/components/project-ui/reconcile-tab/ReconcileTab.jsx similarity index 95% rename from packages/web/src/components/project-ui/tabs/ReadyToReconcileTab.jsx rename to packages/web/src/components/project-ui/reconcile-tab/ReconcileTab.jsx index 15c4e9014..ded88d122 100644 --- a/packages/web/src/components/project-ui/tabs/ReadyToReconcileTab.jsx +++ b/packages/web/src/components/project-ui/reconcile-tab/ReconcileTab.jsx @@ -5,10 +5,10 @@ import projectStore from '@/stores/projectStore.js'; import { useProjectContext } from '../ProjectContext.jsx'; /** - * ReadyToReconcileTab - Shows studies ready for reconciliation + * ReconcileTab - Shows studies ready for reconciliation * Uses ProjectContext for projectId, handlers, and helpers */ -export default function ReadyToReconcileTab() { +export default function ReconcileTab() { const { projectId, handlers, getAssigneeName } = useProjectContext(); const { checklistHandlers, pdfHandlers } = handlers; diff --git a/packages/web/src/components/project-ui/reconcile-tab/index.js b/packages/web/src/components/project-ui/reconcile-tab/index.js new file mode 100644 index 000000000..75c2df54a --- /dev/null +++ b/packages/web/src/components/project-ui/reconcile-tab/index.js @@ -0,0 +1,2 @@ +// reconcile barrel export +export { default as ReconcileTab } from './ReconcileTab.jsx'; \ No newline at end of file diff --git a/packages/web/src/components/project-ui/tabs/ToDoTab.jsx b/packages/web/src/components/project-ui/todo-tab/ToDoTab.jsx similarity index 60% rename from packages/web/src/components/project-ui/tabs/ToDoTab.jsx rename to packages/web/src/components/project-ui/todo-tab/ToDoTab.jsx index fead3058e..f3490b44b 100644 --- a/packages/web/src/components/project-ui/tabs/ToDoTab.jsx +++ b/packages/web/src/components/project-ui/todo-tab/ToDoTab.jsx @@ -1,15 +1,15 @@ import { For, Show, createMemo, createSignal } from 'solid-js'; -import StudyCard from '../StudyCard.jsx'; +import TodoStudyRow from './TodoStudyRow.jsx'; import projectStore from '@/stores/projectStore.js'; import { useBetterAuth } from '@api/better-auth-store.js'; import { useProjectContext } from '../ProjectContext.jsx'; /** - * ToDoTab - Shows studies assigned to the current user + * ToDoTab - Shows studies assigned to the current user in compact rows * Uses ProjectContext for projectId, handlers, and helpers */ export default function ToDoTab() { - const { projectId, handlers, getAssigneeName } = useProjectContext(); + const { projectId, handlers } = useProjectContext(); const { checklistHandlers, pdfHandlers } = handlers; const { user } = useBetterAuth(); @@ -50,7 +50,7 @@ export default function ToDoTab() { }; return ( -

+
{/* Studies List */} 0} @@ -62,36 +62,28 @@ export default function ToDoTab() { } > -
- - {study => ( - - setShowChecklistForm(prev => (prev === study.id ? null : study.id)) - } - onAddChecklist={(type, assigneeId) => - handleCreateChecklist(study.id, type, assigneeId) - } - onOpenChecklist={checklistId => - checklistHandlers.openChecklist(study.id, checklistId) - } - onViewPdf={pdf => pdfHandlers.handleViewPdf(study.id, pdf)} - onUpdateChecklist={(checklistId, updates) => - checklistHandlers.handleUpdateChecklist(study.id, checklistId, updates) - } - onDeleteChecklist={checklistId => - checklistHandlers.handleDeleteChecklist(study.id, checklistId) - } - getAssigneeName={getAssigneeName} - creatingChecklist={creatingChecklist()} - /> - )} - -
+ + {study => ( + + setShowChecklistForm(prev => (prev === study.id ? null : study.id)) + } + onAddChecklist={(type, assigneeId) => + handleCreateChecklist(study.id, type, assigneeId) + } + onOpenChecklist={checklistId => + checklistHandlers.openChecklist(study.id, checklistId) + } + onViewPdf={pdf => pdfHandlers.handleViewPdf(study.id, pdf)} + onDownloadPdf={pdf => pdfHandlers.handleDownloadPdf(study.id, pdf)} + creatingChecklist={creatingChecklist()} + /> + )} +
); diff --git a/packages/web/src/components/project-ui/todo-tab/TodoStudyRow.jsx b/packages/web/src/components/project-ui/todo-tab/TodoStudyRow.jsx new file mode 100644 index 000000000..9039a2d87 --- /dev/null +++ b/packages/web/src/components/project-ui/todo-tab/TodoStudyRow.jsx @@ -0,0 +1,202 @@ +/** + * TodoStudyRow - Compact study card for the todo tab + * + * Displays study info, checklist status, and collapsible PDF section. + * Clicking whitespace on the header row toggles the PDF section. + */ + +import { For, Show, createMemo, createSignal } from 'solid-js'; +import { BiRegularChevronRight } from 'solid-icons/bi'; +import { Collapsible } from '@corates/ui'; +import { getChecklistMetadata } from '@/checklist-registry'; +import PdfListItem from '@/components/checklist-ui/pdf/PdfListItem.jsx'; +import ChecklistForm from '../ChecklistForm.jsx'; + +export default function TodoStudyRow(props) { + // props.study: Study object with pdfs and checklists arrays + // props.members: Array of project members + // props.currentUserId: Current user's ID + // props.onOpenChecklist: (checklistId) => void + // props.onAddChecklist: (type, assigneeId) => void + // props.onViewPdf: (pdf) => void + // props.onDownloadPdf: (pdf) => void + // props.showChecklistForm: boolean + // props.onToggleChecklistForm: () => void + // props.creatingChecklist: boolean + + const [expanded, setExpanded] = createSignal(false); + + const study = () => props.study; + const checklist = () => study().checklists?.[0]; // In todo tab, user sees only their checklist + + // Get PDFs sorted: primary first, then protocol, then secondary + const sortedPdfs = createMemo(() => { + const pdfs = study().pdfs || []; + return [...pdfs].sort((a, b) => { + const tagOrder = { primary: 0, protocol: 1, secondary: 2 }; + const tagA = tagOrder[a.tag] ?? 2; + const tagB = tagOrder[b.tag] ?? 2; + if (tagA !== tagB) return tagA - tagB; + return (b.uploadedAt || 0) - (a.uploadedAt || 0); + }); + }); + + const hasPdfs = () => sortedPdfs().length > 0; + const pdfCount = () => sortedPdfs().length; + + // Citation line from study or primary PDF + const citationLine = () => { + const primaryPdf = sortedPdfs().find(p => p.tag === 'primary') || sortedPdfs()[0]; + const author = primaryPdf?.firstAuthor || study().firstAuthor; + const year = primaryPdf?.publicationYear || study().publicationYear; + if (!author && !year) return null; + return `${author || 'Unknown'}${year ? ` (${year})` : ''}`; + }; + + // Status badge styling + const getStatusStyle = status => { + switch (status) { + case 'completed': + return 'bg-green-100 text-green-700'; + case 'in-progress': + return 'bg-yellow-100 text-yellow-700'; + default: + return 'bg-gray-100 text-gray-600'; + } + }; + + // Handle header click - toggle unless clicking on interactive elements or selectable text + const handleHeaderClick = e => { + // Don't toggle if clicking on interactive elements or selectable text areas + const target = e.target; + const interactive = target.closest( + 'button, [role="button"], [role="menuitem"], input, textarea, [data-selectable]', + ); + if (interactive) return; + + // Only toggle if there are PDFs to show + if (hasPdfs()) { + setExpanded(prev => !prev); + } + }; + + return ( +
+ ( +
+ {/* Chevron indicator (only if has PDFs) */} + +
+ +
+
+ + {/* Study info */} +
+
+ {study().name} +
+ {/* Citation line - selectable */} + +

+ {citationLine()} + + · {pdfCount()} PDFs + +

+
+ +

{pdfCount()} PDFs

+
+
+ + {/* Checklist type badge - selectable */} + + + {getChecklistMetadata(checklist().type)?.name || 'Checklist'} + + + + {/* Checklist status badge */} + + + {checklist().status === 'in-progress' ? + 'In Progress' + : checklist().status === 'completed' ? + 'Completed' + : 'Pending'} + + + + {/* Open checklist button (when checklist exists) */} + + + + + {/* Select Checklist button (when no checklist) */} + + + +
+ )} + > + {/* Expanded PDF Section */} + +
+ + {pdf => ( + props.onViewPdf?.(pdf)} + onDownload={() => props.onDownloadPdf?.(pdf)} + readOnly={true} + /> + )} + +
+
+
+ + {/* Checklist Form (when adding a new checklist) - outside collapsible */} + +
+ props.onAddChecklist?.(type, assigneeId)} + onCancel={() => props.onToggleChecklistForm?.()} + loading={props.creatingChecklist} + /> +
+
+
+ ); +} diff --git a/packages/web/src/components/project-ui/todo-tab/index.js b/packages/web/src/components/project-ui/todo-tab/index.js new file mode 100644 index 000000000..6a65c07c0 --- /dev/null +++ b/packages/web/src/components/project-ui/todo-tab/index.js @@ -0,0 +1,3 @@ +// todo barrel export +export { default as TodoStudyRow } from './TodoStudyRow.jsx'; +export { default as ToDoTab } from './ToDoTab.jsx'; From 7e9a423f29f17bbbec9a6fee5c632d0653704745 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 18 Dec 2025 16:47:30 +0000 Subject: [PATCH 2/4] Apply Prettier formatting --- .../web/src/components/project-ui/ReviewerAssignment.jsx | 7 ++++++- .../web/src/components/project-ui/reconcile-tab/index.js | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/web/src/components/project-ui/ReviewerAssignment.jsx b/packages/web/src/components/project-ui/ReviewerAssignment.jsx index 5985c7d0e..c7d87c853 100644 --- a/packages/web/src/components/project-ui/ReviewerAssignment.jsx +++ b/packages/web/src/components/project-ui/ReviewerAssignment.jsx @@ -6,7 +6,12 @@ import { createSignal, createMemo, For, Show } from 'solid-js'; import { createStore, produce } from 'solid-js/store'; import { showToast, Collapsible } from '@corates/ui'; -import { BiRegularShuffle, BiRegularCheck, BiRegularX, BiRegularChevronRight } from 'solid-icons/bi'; +import { + BiRegularShuffle, + BiRegularCheck, + BiRegularX, + BiRegularChevronRight, +} from 'solid-icons/bi'; import { FiUsers } from 'solid-icons/fi'; /** diff --git a/packages/web/src/components/project-ui/reconcile-tab/index.js b/packages/web/src/components/project-ui/reconcile-tab/index.js index 75c2df54a..4adf0c239 100644 --- a/packages/web/src/components/project-ui/reconcile-tab/index.js +++ b/packages/web/src/components/project-ui/reconcile-tab/index.js @@ -1,2 +1,2 @@ // reconcile barrel export -export { default as ReconcileTab } from './ReconcileTab.jsx'; \ No newline at end of file +export { default as ReconcileTab } from './ReconcileTab.jsx'; From 664e8704506bb40209cbe238ef3ba63de0ede0cb Mon Sep 17 00:00:00 2001 From: Jacob Maynard Date: Thu, 18 Dec 2025 10:51:11 -0600 Subject: [PATCH 3/4] style and bug fix with checklist progress state indicator --- .../components/project-ui/all-studies-tab/AllStudiesTab.jsx | 4 ++-- packages/web/src/primitives/useProject/checklists.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/web/src/components/project-ui/all-studies-tab/AllStudiesTab.jsx b/packages/web/src/components/project-ui/all-studies-tab/AllStudiesTab.jsx index 8e5e0b338..2cc46b666 100644 --- a/packages/web/src/components/project-ui/all-studies-tab/AllStudiesTab.jsx +++ b/packages/web/src/components/project-ui/all-studies-tab/AllStudiesTab.jsx @@ -149,7 +149,7 @@ export default function AllStudiesTab() { }; return ( -
+
{/* Add Studies Section */} {/* Study count */} -
+

{studies().length} {studies().length === 1 ? 'study' : 'studies'} in this project

diff --git a/packages/web/src/primitives/useProject/checklists.js b/packages/web/src/primitives/useProject/checklists.js index 7df09d4cc..8b825b8b6 100644 --- a/packages/web/src/primitives/useProject/checklists.js +++ b/packages/web/src/primitives/useProject/checklists.js @@ -444,6 +444,12 @@ export function createChecklistOperations(projectId, getYDoc, isSynced) { answersMap.set(key, data); } + // Auto-transition status from 'pending' to 'in-progress' on first edit + const currentStatus = checklistYMap.get('status'); + if (currentStatus === 'pending') { + checklistYMap.set('status', 'in-progress'); + } + checklistYMap.set('updatedAt', Date.now()); } From 86869a6ef2d5b6abd3095d05840eb0589c055caa Mon Sep 17 00:00:00 2001 From: Jacob Maynard Date: Thu, 18 Dec 2025 11:04:57 -0600 Subject: [PATCH 4/4] add temp plans to gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 93774806e..2fa51d0e4 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,7 @@ config/secrets.json secrets.txt # Generated files -openapi.json \ No newline at end of file +openapi.json + +# Temp files +/docs/plans/* \ No newline at end of file