diff --git a/.mcp/memory.db-wal b/.mcp/memory.db-wal index ee8181bb9..3901427b4 100644 Binary files a/.mcp/memory.db-wal and b/.mcp/memory.db-wal differ diff --git a/eslint.config.js b/eslint.config.js index cbd0fffee..38629c55e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -258,6 +258,21 @@ export default [ 'no-restricted-imports': 'off', }, }, + { + // Web UI components can import from @ark-ui/solid directly (shadcn-style primitives) + files: ['packages/web/src/components/ui/**/*.{js,jsx,ts,tsx}'], + rules: { + 'no-restricted-imports': 'off', + 'corates/corates-ui-imports': 'off', + }, + }, + { + // Web lib/ui can import from @ark-ui/solid directly + files: ['packages/web/src/lib/ui/**/*.{js,jsx,ts,tsx}'], + rules: { + 'no-restricted-imports': 'off', + }, + }, { // Test file configuration files: [ diff --git a/package.json b/package.json index a4d4a5174..a3ca3482d 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,10 @@ "eslint-plugin-solid": "^0.14.5", "eslint-plugin-sonarjs": "^3.0.5", "eslint-plugin-unicorn": "^62.0.0", - "prettier": "^3.7.4", + "prettier": "^3.8.0", "prettier-plugin-tailwindcss": "^0.7.2", - "turbo": "^2.7.4", - "wrangler": "^4.59.1" + "turbo": "^2.7.5", + "wrangler": "^4.59.2" }, "engines": { "node": ">=24.0.0", diff --git a/packages/docs/plans/project-creation-wizard.md b/packages/docs/plans/project-creation-wizard.md new file mode 100644 index 000000000..2d6fe9aad --- /dev/null +++ b/packages/docs/plans/project-creation-wizard.md @@ -0,0 +1,487 @@ +# Plan: Project Creation Wizard + +**Status:** Draft +**Created:** 2026-01-18 +**Last Updated:** 2026-01-18 + +--- + +## Overview + +Project creation uses a progressive setup flow where the project is created immediately (Step 1), then the user is guided through optional configuration steps (Team, Studies, Assignment). Each step uses the same component that appears in project management, ensuring consistent UX and no duplicated code. + +Users can exit the wizard at any point - the project exists and can be configured later through the standard project UI. + +## Architecture Principle + +**One component, two contexts.** Each configuration panel (Team, Studies, Assignment) is a standalone component that: + +- Renders identically in the wizard flow and in project settings +- Operates on a real project (not wizard state) +- Saves changes immediately (no "submit all at once") + +The wizard is simply a guided wrapper that presents these components in sequence with a stepper UI. + +## Prerequisites + +- Existing team/organization membership system +- Study import infrastructure (PDF upload, reference parsing) +- Google Drive integration for PDF import +- DOI/PMID metadata lookup service + +## Goals + +1. Guide new users through complete project setup with a stepper UI +2. Allow experienced users to skip wizard and configure manually +3. Reuse components between wizard and project management (no duplication) +4. Enable flexible, incremental project configuration +5. Reduce time-to-first-review while remaining non-prescriptive + +## Non-Goals + +- Forcing users through the wizard (it's optional guidance) +- Atomic/transactional project creation (project exists after step 1) +- Draft projects (project is real immediately) +- Bulk project creation or templates (future enhancement) + +--- + +## User Flows + +### Flow A: Guided Wizard (New Users) + +``` +Create Project → [Project Created] → Team Panel → Studies Panel → Assignment Panel → Done + ↓ ↓ ↓ + (can exit) (can exit) (can exit) +``` + +### Flow B: Manual Setup (Experienced Users) + +``` +Create Project → [Project Created] → Exit to Project View → Configure via Settings/Tabs +``` + +### Flow C: Hybrid + +``` +Create Project → Team Panel → Exit → (later) → Studies Tab → Add Studies +``` + +All flows result in the same project state - the wizard is just one path to get there. + +--- + +## Component Architecture + +### Shared Panels + +These components are used in both the wizard and project management: + +| Component | Wizard Context | Management Context | +| -------------------- | ---------------- | -------------------------------- | +| `TeamPanel` | Step 2 of wizard | Project Settings > Team | +| `StudiesImportPanel` | Step 3 of wizard | Studies Tab > Add Studies button | +| `AssignmentPanel` | Step 4 of wizard | Studies Tab > Manage Assignments | + +Each panel: + +- Receives `projectId` as prop +- Fetches/mutates project data directly +- Has no wizard-specific logic +- Can be used standalone or within wizard wrapper + +### Wizard Wrapper + +```tsx + + + {/* Only used here, creates project */} + + + + + + + + + + + +``` + +The wrapper provides: + +- Stepper UI showing progress +- Next/Back/Skip navigation +- "Exit to Project" option on every step +- Completion celebration on final step + +--- + +## Step Specifications + +### Step 1: Create Project + +**Purpose:** Create the project shell. This is the only wizard-specific step. + +**Fields:** + +| Field | Type | Required | Notes | +| --------------- | ------------ | -------- | ------------------------------------ | +| Project Name | text | Yes | 3-100 characters | +| Description | textarea | No | Optional, supports markdown | +| Checklist Types | multi-select | Yes | One or more: AMSTAR2, ROBINS-I, etc. | +| Registration ID | text | No | PROSPERO or other registry ID | + +**Behavior:** + +- On submit, project is created via API +- User becomes Owner automatically +- Wizard advances to Step 2 with real `projectId` + +**Validation:** + +- Name must be unique within the organization +- At least one checklist type must be selected + +**UI Notes:** + +- Clean, focused form +- Checklist type selector shows brief description of each option +- No "skip" option - project must be created to proceed + +--- + +### Step 2: Team Panel + +**Purpose:** Add team members and assign roles. + +**This is the same `TeamPanel` component used in Project Settings > Team.** + +**Roles:** + +| Role | Permissions | +| ------ | ------------------------------------------------------------------ | +| Owner | Full access: manage team, reconcile, edit settings, delete project | +| Member | Can review assigned studies, view all project data | + +**Features:** + +1. **Add Members** + - Email input with role selector (Owner/Member) + - Autocomplete for organization members + - Batch add support (comma-separated) + - Invites sent immediately when added + +2. **Member List** + - Shows all members with role badges + - Pending invite indicator for non-org members + - Role change dropdown + - Remove button + +3. **Wizard-Specific UI** + - "Skip for now" button (can add members later) + - Helper text: "You can always add more team members later" + +**Validation:** + +- Warning if fewer than 2 members for dual-review workflow +- Warning is non-blocking (user can proceed) + +--- + +### Step 3: Studies Import Panel + +**Purpose:** Import studies from various sources. + +**This is the same `StudiesImportPanel` component used in Studies Tab > Add Studies.** + +#### Import Sources (Tabs) + +**Tab: PDF Upload** + +- Drag-and-drop zone for PDF files +- Multi-file upload support +- Extracts metadata from PDF (title, authors, DOI if available) +- Progress indicator for uploads +- Studies created immediately as uploads complete + +**Tab: DOI/PMID Lookup** + +- Text input for DOI or PMID (one per line or comma-separated) +- "Lookup" button fetches metadata from CrossRef/PubMed +- Results shown with confirm/add action +- Option to attach PDF after lookup + +**Tab: Reference File** + +- Upload RIS, BibTeX, EndNote XML, or CSV +- Parser extracts all references +- Preview table before import +- Field mapping UI for CSV +- Bulk add to project + +**Tab: Google Drive** + +- "Connect Google Drive" button (OAuth if not connected) +- Folder browser for selecting PDFs +- Multi-select with "Import Selected" button +- PDFs downloaded to CoRATES storage on import + +#### Deduplication + +- Automatic detection on import (exact DOI, fuzzy title match) +- Warning shown before adding duplicate +- User chooses: "Add anyway" or "Skip" + +#### PDF Matching + +- For references without PDFs, suggest matches from uploaded PDFs +- Auto-match by DOI or title similarity +- Manual drag-drop matching + +#### Primary vs Secondary PDFs + +- Per-study PDF list with drag to reorder +- First position = primary (shown in viewer) +- Secondary PDFs available as attachments + +**Wizard-Specific UI:** + +- "Skip for now" button +- Counter showing studies added this session +- Helper text: "You can import more studies anytime from the Studies tab" + +--- + +### Step 4: Assignment Panel + +**Purpose:** Configure and run reviewer assignment. + +**This is the same `AssignmentPanel` component used in Studies Tab > Manage Assignments.** + +#### Assignment Strategy + +| Strategy | Description | +| ----------- | ---------------------------------------------- | +| Random | Randomly assign members, balanced distribution | +| Round-Robin | Cycle through members in order | +| Manual | Assign individually per study | + +#### Configuration Options + +| Option | Type | Default | Notes | +| ------------------- | -------- | ------- | ----------------------------------------- | +| Reviewers per Study | number | 2 | Standard dual-review; 1 for single-review | +| Include Owners | checkbox | true | Whether owners are in assignment pool | +| Balanced Load | checkbox | true | Ensure equal distribution | + +#### Assignment Preview + +Before applying, show: + +**Summary Table:** + +``` +Member | Assigned | Percentage +--------------------|----------|------------ +sarah@example.com | 12 | 50% +michael@example.com | 12 | 50% +``` + +**Per-Study View:** + +- Table showing each study and assigned members +- Click to manually adjust +- "Regenerate" button to re-randomize + +**Actions:** + +- "Apply Assignments" - saves to project +- "Clear All" - removes all assignments + +**Wizard-Specific UI:** + +- "Skip for now" button +- Disabled state if no studies or fewer than 2 members +- Helper text explaining why assignment is disabled (if applicable) + +--- + +### Wizard Completion + +After Step 4 (or when user clicks "Finish" on any step): + +- Show completion message with summary +- "Go to Project" button +- Optional: brief tour of project view highlighting where to find each panel + +--- + +## Technical Details + +### No Wizard State + +Since each step operates on the real project, there's no wizard-specific state to manage. The only "state" is: + +- Current step number (URL param or local state) +- Project ID (from step 1 creation) + +```typescript +// Wizard just tracks position, not data +interface WizardNavState { + projectId: string; + currentStep: 1 | 2 | 3 | 4; +} +``` + +### Panel Props Interface + +Each shared panel follows this pattern: + +```typescript +interface PanelProps { + projectId: string; + // Optional wizard context + wizardMode?: boolean; // Enables "Skip" button, helper text + onComplete?: () => void; // Called when user clicks "Continue" in wizard +} +``` + +### API Endpoints + +Panels use existing project APIs where possible: + +| Panel | Endpoints Used | +| ------------------ | ---------------------------------------------------------------------------------- | +| TeamPanel | `POST /projects/:id/members`, `DELETE /projects/:id/members/:memberId` | +| StudiesImportPanel | `POST /projects/:id/studies`, `POST /api/lookup-doi`, `POST /api/parse-references` | +| AssignmentPanel | `POST /projects/:id/assignments`, `GET /projects/:id/assignment-preview` | + +**New endpoints needed:** + +| Method | Path | Purpose | +| ------ | ---------------------------------- | ------------------------------------------ | +| POST | `/api/lookup-doi` | Fetch metadata for DOI/PMID batch | +| POST | `/api/parse-references` | Parse uploaded reference file | +| POST | `/api/extract-pdf-metadata` | Extract metadata from PDF | +| POST | `/projects/:id/assignment-preview` | Generate assignment preview without saving | + +### PDF Handling + +PDFs are uploaded directly to permanent storage: + +1. User uploads PDF +2. PDF stored in R2: `projects/{projectId}/studies/{studyId}/{filename}` +3. Metadata extracted and study created +4. No temp storage needed (project exists) + +For Google Drive: + +1. User selects files +2. Backend downloads from Drive to R2 +3. Study created with PDF reference + +--- + +## UI/UX Considerations + +### Wizard Stepper + +Horizontal stepper at top: + +``` +[1. Create] ---- [2. Team] ---- [3. Studies] ---- [4. Assignment] + done current o o +``` + +- Completed steps show checkmark +- Current step highlighted +- Future steps shown but not clickable +- "Exit to Project" link always visible + +### Navigation + +Each step has: + +- "Back" button (except step 1) +- "Continue" / "Skip" buttons +- "Exit to Project" link + +Browser back button navigates wizard steps (not browser history). + +### Empty States + +Each panel handles empty state gracefully: + +- Team: "No members yet. Add team members to enable dual-review." +- Studies: "No studies yet. Import studies to get started." +- Assignment: "Add studies and team members before assigning reviewers." + +### Responsive Design + +- Desktop: Full panel width, side help text +- Tablet: Stacked layout +- Mobile: Full-screen panels, simplified import (PDF upload + DOI primarily) + +--- + +## Component Reuse Matrix + +| Component | Wizard Step 2 | Wizard Step 3 | Wizard Step 4 | Project Settings | Studies Tab | +| ------------------ | ------------- | ------------- | ------------- | ---------------- | ----------- | +| TeamPanel | X | | | X | | +| StudiesImportPanel | | X | | | X | +| AssignmentPanel | | | X | | X | + +--- + +## Success Criteria + +Before considering this plan complete: + +- [ ] Project creation (Step 1) functional +- [ ] TeamPanel works in both wizard and settings context +- [ ] StudiesImportPanel works in both wizard and studies tab context +- [ ] AssignmentPanel works in both wizard and studies tab context +- [ ] All import methods functional (PDF, DOI, reference file, Google Drive) +- [ ] Deduplication detection working +- [ ] PDF matching (auto and manual) implemented +- [ ] Assignment strategies implemented with preview +- [ ] Wizard navigation (next/back/skip/exit) working +- [ ] Responsive design for all panels +- [ ] Tests for shared panel components +- [ ] Tests for assignment algorithm + +--- + +## Resolved Questions + +1. **Draft Projects:** No. Project is created immediately in Step 1. + +2. **Study Limit:** No limits for initial implementation. + +3. **Checklist Selection:** Multiple checklist types allowed per project. + +4. **Roles:** Two roles - "Owner" and "Member". + +5. **Post-Creation Editing:** All wizard steps map to management UI. Same components, same capabilities. + +6. **Google Drive:** One-time import. PDFs downloaded to CoRATES storage. + +7. **Reference Manager Integration:** File import only (RIS, BibTeX, EndNote). No direct API integration. + +8. **Invite Timing:** Invites sent immediately when members are added (project exists). + +9. **Wizard Flexibility:** Users can skip steps, exit early, or bypass wizard entirely. Wizard is guidance, not enforcement. + +--- + +## Related Documents + +- [State Management Guide](../guides/state-management.md) - For panel state patterns +- [PDF Handling](../../.cursor/rules/pdf-handling.mdc) - PDF upload and storage patterns +- [Authentication Guide](../guides/authentication.md) - For Google OAuth (Drive integration) +- [API Development Guide](../guides/api-development.md) - For endpoint patterns +- [Add Studies Mocks](../../web/src/components/mocks/) - Existing UI explorations diff --git a/packages/mcp-memory/package.json b/packages/mcp-memory/package.json index 329c88266..4c22cc52e 100644 --- a/packages/mcp-memory/package.json +++ b/packages/mcp-memory/package.json @@ -21,12 +21,12 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.25.2", "@xenova/transformers": "^2.17.2", - "better-sqlite3": "^11.8.1", + "better-sqlite3": "^11.10.0", "zod": "^4.3.5" }, "devDependencies": { - "@types/better-sqlite3": "^7.6.12", - "@types/node": "^25.0.8", + "@types/better-sqlite3": "^7.6.13", + "@types/node": "^25.0.9", "tsx": "^4.21.0", "typescript": "^5.9.3", "vitest": "^4.0.17" diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 8c8f30d34..0a710b018 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -24,7 +24,7 @@ "zod": "^4.3.5" }, "devDependencies": { - "@types/node": "^25.0.8", + "@types/node": "^25.0.9", "tsx": "^4.21.0", "typescript": "^5.9.3", "vitest": "^4.0.17" diff --git a/packages/ui/README.md b/packages/ui/README.md deleted file mode 100644 index aaaa600ed..000000000 --- a/packages/ui/README.md +++ /dev/null @@ -1,440 +0,0 @@ -# @corates/ui - -**Shared UI component library for CoRATES** - SolidJS components built with Ark UI, providing accessible, headless components with Tailwind CSS styling. - -## Purpose - -This package provides reusable UI components for the CoRATES frontend: - -- **40+ accessible components** built on Ark UI primitives -- **Headless component architecture** with full styling control -- **SolidJS-native** with reactive state management -- **Tailwind CSS** styling with `cn()` utility for class merging -- **TypeScript** type definitions for all components - -## Tech Stack - -- **Framework:** SolidJS 1.9+ (peer dependency) -- **Primitives:** Ark UI 5.30+ (accessible headless components) -- **Legacy:** Zag.js 1.32+ (Tour component only) -- **Styling:** Tailwind CSS + clsx + tailwind-merge -- **Icons:** solid-icons 1.1+ (peer dependency) -- **Testing:** Vitest 4.0+ with SolidJS Testing Library - -## Installation - -This package is designed for use within the CoRATES monorepo: - -```bash -# Add to another workspace package -pnpm add @corates/ui --workspace -``` - -## Usage - -### Importing Components - -```jsx -import { Dialog, Select, Tabs, Toast, toaster, Tooltip } from '@corates/ui'; - -// Import primitives for custom components -import { DialogPrimitive } from '@corates/ui'; - -// Import utilities -import { cn, Z_INDEX } from '@corates/ui'; -``` - -### Basic Example - -```jsx -import { Dialog, toaster } from '@corates/ui'; - -function MyComponent() { - const [open, setOpen] = createSignal(false); - - return ( - <> - - - setOpen(open)} - title='Confirm Action' - description='Are you sure you want to proceed?' - > - - - - ); -} -``` - -## Component Categories - -### Layout & Structure - -| Component | Description | -| --------------- | ---------------------------------------------------------------- | -| **Accordion** | Expandable/collapsible content sections with keyboard navigation | -| **Collapsible** | Single collapsible content section | -| **Splitter** | Resizable split panels for layouts | -| **Tabs** | Tabbed content panels with routed or local state | - -### Forms & Input - -| Component | Description | -| ----------------- | ------------------------------------------------- | -| **Checkbox** | Checkbox input with indeterminate state support | -| **Combobox** | Searchable select with autocomplete and filtering | -| **Editable** | Inline editable text with submit/cancel | -| **FileUpload** | File upload with drag-and-drop and previews | -| **NumberInput** | Numeric input with increment/decrement buttons | -| **PasswordInput** | Password input with visibility toggle | -| **PinInput** | OTP/PIN code input with auto-focus | -| **RadioGroup** | Radio button group with keyboard navigation | -| **Select** | Dropdown select with search and multi-select | -| **Switch** | Toggle switch (on/off) | -| **TagsInput** | Tag/chip input with add/remove | - -### Overlays & Dialogs - -| Component | Description | -| ----------------- | --------------------------------------------------- | -| **Dialog** | Modal dialog with backdrop and focus trap | -| **ConfirmDialog** | Pre-built confirmation dialog with promise API | -| **Drawer** | Slide-in panel from any edge | -| **FloatingPanel** | Draggable/resizable floating panel | -| **Menu** | Dropdown menu with submenus and keyboard navigation | -| **Popover** | Floating content panel with positioning | -| **Tooltip** | Hover tooltips with delay and positioning | - -### Feedback & Status - -| Component | Description | -| ----------------- | ---------------------------------------------------- | -| **Avatar** | User avatar with fallback initials | -| **Progress** | Progress bar with percentage display | -| **Spinner** | Loading spinner with variants (button, page, inline) | -| **Toast/Toaster** | Toast notifications (success, error, info, loading) | - -### Utilities - -| Component | Description | -| --------------- | ------------------------------------------------ | -| **Clipboard** | Copy to clipboard button with feedback | -| **QRCode** | QR code generator | -| **ToggleGroup** | Group of toggle buttons (single or multi-select) | -| **Tour** | Guided tour/onboarding with steps | - -## Key Exports - -### Components - -All components export two versions: - -1. **High-level component** (e.g., `Dialog`) - Pre-styled, opinionated implementation -2. **Primitive** (e.g., `DialogPrimitive`) - Headless Ark UI primitive for custom styling - -```jsx -// Use high-level component for standard UI -import { Dialog } from '@corates/ui'; - -// Use primitive for custom implementations -import { DialogPrimitive } from '@corates/ui'; -``` - -### Hooks - -Some components also export hooks: - -```jsx -import { - useCheckbox, - useCombobox, - useConfirmDialog, - usePopover, - useSelect, - useSwitch, - useTour, - useTooltip, - useWindowDrag, -} from '@corates/ui'; -``` - -### Utilities - -```jsx -import { cn } from '@corates/ui'; // Class name utility (clsx + tailwind-merge) -import { Z_INDEX } from '@corates/ui'; // z-index constants for layering -``` - -### Toast API - -```jsx -import { toaster, showToast } from '@corates/ui'; - -// Promise-based API -toaster.promise(fetchData(), { - loading: 'Loading...', - success: 'Data loaded!', - error: 'Failed to load data', -}); - -// Direct API -toaster.success('Success message'); -toaster.error('Error message'); -toaster.info('Info message'); -toaster.loading('Loading...'); - -// Custom toast with duration -showToast({ - title: 'Custom Toast', - description: 'With custom options', - type: 'success', - duration: 5000, -}); -``` - -## Styling - -### Tailwind CSS - -Components use Tailwind CSS classes. Ensure your Tailwind config includes the UI package: - -```js -// tailwind.config.js (Tailwind v4) -@source "../../packages/ui/src/**/*.{ts,tsx}"; -``` - -### Class Name Merging - -Use the `cn()` utility to merge Tailwind classes with proper precedence: - -```jsx -import { cn } from '@corates/ui'; - -
; -``` - -### Z-Index System - -Use centralized z-index constants for consistent layering: - -```jsx -import { Z_INDEX } from '@corates/ui'; - -// Z_INDEX.MODAL, Z_INDEX.TOOLTIP, Z_INDEX.POPOVER, etc. -
; -``` - -## Development - -```bash -# Install dependencies -pnpm install - -# Type check -pnpm typecheck - -# Run tests -pnpm test - -# Run tests in watch mode -pnpm test:watch - -# Run tests with coverage -pnpm test:coverage -``` - -## Testing - -All components have comprehensive unit tests using Vitest and SolidJS Testing Library: - -```bash -# Run all tests -pnpm test - -# Run specific test -pnpm test Dialog - -# Watch mode -pnpm test:watch -``` - -Test files are located in `src/components/__tests__/`. - -### Testing Example - -```tsx -import { render, screen } from '@solidjs/testing-library'; -import { Dialog } from './Dialog'; - -test('Dialog renders with title and description', () => { - render(() => ); - - expect(screen.getByText('Test Title')).toBeInTheDocument(); - expect(screen.getByText('Test Description')).toBeInTheDocument(); -}); -``` - -## Architecture - -### Component Structure - -Each component follows this pattern: - -```tsx -// High-level styled component -export function Dialog(props) { - return {/* Pre-styled implementation */}; -} - -// Re-export primitive for custom use -export { Dialog as DialogPrimitive } from '@ark-ui/solid'; -``` - -### Headless Primitives - -Most components are built on [Ark UI](https://ark-ui.com/) primitives: - -- **Accessibility**: ARIA attributes, keyboard navigation, focus management -- **State management**: Handle open/close, selection, focus, etc. -- **No styling**: Bring your own styles with Tailwind - -### Legacy Components - -The **Tour** component still uses Zag.js (not migrated to Ark UI). This is the only remaining Zag.js dependency and may be migrated in the future. - -## Common Patterns - -### Dialog with Confirmation - -```jsx -import { ConfirmDialog, useConfirmDialog } from '@corates/ui'; - -const confirmDialog = useConfirmDialog(); - -// Show confirmation dialog -const confirmed = await confirmDialog.confirm({ - title: 'Delete Project', - description: 'Are you sure? This cannot be undone.', - confirmText: 'Delete', - cancelText: 'Cancel', -}); - -if (confirmed) { - // Proceed with deletion -} -``` - -### Select with Search - -```jsx -import { Select } from '@corates/ui'; - - props.onTypeChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - > - - - -
-
- - props.onStartsAtChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - props.onExpiresAtChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - -
-
+ props.onOpenChange?.(details.open)}> + + + + + Create Grant + + + + + +
+
+ + +
+
+ + props.onStartsAtChange?.(e.target.value)} + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + props.onExpiresAtChange?.(e.target.value)} + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + Cancel + + +
+
+
+
+
); } diff --git a/packages/web/src/components/admin/ImpersonationBanner.jsx b/packages/web/src/components/admin/ImpersonationBanner.jsx index 095d565f5..96ab1e102 100644 --- a/packages/web/src/components/admin/ImpersonationBanner.jsx +++ b/packages/web/src/components/admin/ImpersonationBanner.jsx @@ -9,7 +9,7 @@ import { stopImpersonation, checkImpersonationStatus, } from '@/stores/adminStore.js'; -import { Z_INDEX } from '@corates/ui'; +import { Z_INDEX } from '@/components/ui/z-index'; /** * Impersonation Banner component diff --git a/packages/web/src/components/admin/OrgDetail.jsx b/packages/web/src/components/admin/OrgDetail.jsx index ffa8d5472..065fb0238 100644 --- a/packages/web/src/components/admin/OrgDetail.jsx +++ b/packages/web/src/components/admin/OrgDetail.jsx @@ -6,7 +6,7 @@ import { createSignal, Show } from 'solid-js'; import { useParams, A } from '@solidjs/router'; -import { FiArrowLeft, FiHome, FiUsers, FiFolder, FiShield, FiLoader } from 'solid-icons/fi'; +import { FiArrowLeft, FiHome, FiUsers, FiFolder, FiShield, FiLoader, FiX } from 'solid-icons/fi'; import { useAdminOrgDetails, useAdminOrgBilling } from '@primitives/useAdminQueries.js'; import { createOrgSubscription, @@ -19,7 +19,17 @@ import { isAdminChecked, isAdmin, } from '@/stores/adminStore.js'; -import { Dialog, showToast } from '@corates/ui'; +import { showToast } from '@/components/ui/toast'; +import { + Dialog, + DialogBackdrop, + DialogPositioner, + DialogContent, + DialogHeader, + DialogTitle, + DialogBody, + DialogCloseTrigger, +} from '@/components/ui/dialog'; import { handleError } from '@/lib/error-utils.js'; import { AdminBox } from './ui/index.js'; import OrgBillingSummary from './OrgBillingSummary.jsx'; @@ -447,43 +457,53 @@ export default function OrgDetail() { /> {/* Confirm Dialog */} - !open && setConfirmDialog(null)} - title={ - confirmDialog()?.type === 'cancel-subscription' ? 'Cancel Subscription' : 'Revoke Grant' - } - role='alertdialog' - > -
-

- {confirmDialog()?.type === 'cancel-subscription' ? - 'Are you sure you want to cancel this subscription?' - : 'Are you sure you want to revoke this grant?'} -

-
- - -
-
+ !open && setConfirmDialog(null)}> + + + + + + {confirmDialog()?.type === 'cancel-subscription' ? + 'Cancel Subscription' + : 'Revoke Grant'} + + + + + + +
+

+ {confirmDialog()?.type === 'cancel-subscription' ? + 'Are you sure you want to cancel this subscription?' + : 'Are you sure you want to revoke this grant?'} +

+
+ + +
+
+
+
+
diff --git a/packages/web/src/components/admin/ProjectDetail.jsx b/packages/web/src/components/admin/ProjectDetail.jsx index 9030a263f..4ccd576a2 100644 --- a/packages/web/src/components/admin/ProjectDetail.jsx +++ b/packages/web/src/components/admin/ProjectDetail.jsx @@ -20,6 +20,7 @@ import { FiCopy, FiHardDrive, FiUserMinus, + FiX, } from 'solid-icons/fi'; import { useAdminProjectDetails } from '@primitives/useAdminQueries.js'; import { @@ -28,7 +29,18 @@ import { isAdminChecked, isAdmin, } from '@/stores/adminStore.js'; -import { Dialog, Avatar, showToast } from '@corates/ui'; +import { showToast } from '@/components/ui/toast'; +import { UserAvatar } from '@/components/ui/avatar'; +import { + Dialog, + DialogBackdrop, + DialogPositioner, + DialogContent, + DialogHeader, + DialogTitle, + DialogBody, + DialogCloseTrigger, +} from '@/components/ui/dialog'; import { handleError } from '@/lib/error-utils.js'; import { AdminBox } from './ui/index.js'; import { table } from './styles/admin-tokens.js'; @@ -319,7 +331,7 @@ export default function ProjectDetail() {
- {/* Confirm Dialog */} - !open && setConfirmDialog(null)} - title={ - confirmDialog()?.type === 'delete-project' ? 'Delete Project' - : confirmDialog()?.type === 'remove-member' ? - 'Remove Member' - : 'Confirm' - } - role='alertdialog' - > -
- -

- This will permanently delete the project and all associated data including files, - members, and invitations. This action cannot be undone. -

-
- -

- Are you sure you want to remove{' '} - - {confirmDialog()?.member?.userDisplayName || - confirmDialog()?.member?.userName || - confirmDialog()?.member?.userEmail} - {' '} - from this project? -

-
-
- - -
-
+ !open && setConfirmDialog(null)}> + + + + + + {confirmDialog()?.type === 'delete-project' ? + 'Delete Project' + : confirmDialog()?.type === 'remove-member' ? + 'Remove Member' + : 'Confirm'} + + + + + + +
+ +

+ This will permanently delete the project and all associated data including + files, members, and invitations. This action cannot be undone. +

+
+ +

+ Are you sure you want to remove{' '} + + {confirmDialog()?.member?.userDisplayName || + confirmDialog()?.member?.userName || + confirmDialog()?.member?.userEmail} + {' '} + from this project? +

+
+
+ + +
+
+
+
+
diff --git a/packages/web/src/components/admin/ProjectList.jsx b/packages/web/src/components/admin/ProjectList.jsx index 410a97c9c..7d20dfd7e 100644 --- a/packages/web/src/components/admin/ProjectList.jsx +++ b/packages/web/src/components/admin/ProjectList.jsx @@ -19,7 +19,7 @@ import { } from 'solid-icons/fi'; import { useAdminProjects, useAdminOrgs } from '@primitives/useAdminQueries.js'; import { isAdminChecked, isAdmin } from '@/stores/adminStore.js'; -import { Select } from '@corates/ui'; +import { SimpleSelect } from '@/components/ui/select'; import { DashboardHeader, AdminSection, AdminDataTable } from './ui/index.js'; import { input } from './styles/admin-tokens.js'; @@ -213,9 +213,9 @@ export default function ProjectList() { {/* Org Filter */}
- props.onPlanChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - > - - - - -
-
- - -
-
- - props.onPeriodStartChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - props.onPeriodEndChange?.(e.target.value)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- props.onCancelAtPeriodEndChange?.(e.target.checked)} - class='h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-2 focus:ring-blue-500' - /> - -
-
- - - props.onCanceledAtChange?.(e.target.value ? new Date(e.target.value) : null) - } - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - props.onEndedAtChange?.(e.target.value ? new Date(e.target.value) : null)} - class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - props.onStripeCustomerIdChange?.(e.target.value)} - placeholder='cus_...' - class='w-full rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - props.onStripeSubscriptionIdChange?.(e.target.value)} - placeholder='sub_...' - class='w-full rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' - /> -
-
- - -
-
+ + + + + + {isEdit() ? 'Edit Subscription' : 'Create Subscription'} + + + + + +
+
+ + +
+
+ + +
+
+ + props.onPeriodStartChange?.(e.target.value)} + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + props.onPeriodEndChange?.(e.target.value)} + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ props.onCancelAtPeriodEndChange?.(e.target.checked)} + class='h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-2 focus:ring-blue-500' + /> + +
+
+ + + props.onCanceledAtChange?.(e.target.value ? new Date(e.target.value) : null) + } + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + + props.onEndedAtChange?.(e.target.value ? new Date(e.target.value) : null) + } + class='w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + props.onStripeCustomerIdChange?.(e.target.value)} + placeholder='cus_...' + class='w-full rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + props.onStripeSubscriptionIdChange?.(e.target.value)} + placeholder='sub_...' + class='w-full rounded-lg border border-gray-300 px-3 py-2 font-mono text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none' + /> +
+
+ + +
+
+
+
+
); } diff --git a/packages/web/src/components/admin/SubscriptionList.jsx b/packages/web/src/components/admin/SubscriptionList.jsx index 1ca0da154..d82483602 100644 --- a/packages/web/src/components/admin/SubscriptionList.jsx +++ b/packages/web/src/components/admin/SubscriptionList.jsx @@ -6,7 +6,7 @@ import { Show, For } from 'solid-js'; import { FiLoader, FiTrash2, FiEdit, FiCopy, FiCheck } from 'solid-icons/fi'; import { createSignal } from 'solid-js'; -import { showToast } from '@corates/ui'; +import { showToast } from '@/components/ui/toast'; /** * Subscription List component for admin dashboard diff --git a/packages/web/src/components/admin/UserDetail.jsx b/packages/web/src/components/admin/UserDetail.jsx index beaf3d7ed..0d4f67940 100644 --- a/packages/web/src/components/admin/UserDetail.jsx +++ b/packages/web/src/components/admin/UserDetail.jsx @@ -24,6 +24,7 @@ import { FiCheckCircle, FiCopy, FiExternalLink, + FiX, } from 'solid-icons/fi'; import { useAdminUserDetails } from '@primitives/useAdminQueries.js'; import { @@ -36,7 +37,18 @@ import { isAdminChecked, isAdmin, } from '@/stores/adminStore.js'; -import { Dialog, Avatar, showToast } from '@corates/ui'; +import { showToast } from '@/components/ui/toast'; +import { UserAvatar } from '@/components/ui/avatar'; +import { + Dialog, + DialogBackdrop, + DialogPositioner, + DialogContent, + DialogHeader, + DialogTitle, + DialogBody, + DialogCloseTrigger, +} from '@/components/ui/dialog'; import { handleError } from '@/lib/error-utils.js'; import { AdminBox } from './ui/index.js'; import { table } from './styles/admin-tokens.js'; @@ -255,10 +267,10 @@ export default function UserDetail() { {/* Header */}
-

@@ -631,77 +643,101 @@ export default function UserDetail() { {/* Ban Dialog */} - -
-

- This will ban the user and revoke all their sessions. -

-
- -