Initial commit: Brachnha Insight project setup

- Next.js 14+ with App Router and TypeScript
- Tailwind CSS and ShadCN UI styling
- Zustand state management
- Dexie.js for IndexedDB (local-first data)
- Auth.js v5 for authentication
- BMAD framework integration

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Max
2026-01-26 12:28:43 +07:00
commit 3fbbb1a93b
812 changed files with 150531 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
'use client';
import { useState } from 'react';
import { Trash2 } from 'lucide-react';
import { useChatStore } from '@/lib/store/chat-store';
import { Sheet } from './Sheet';
import { DraftContent } from './DraftContent';
import { DraftActions } from './DraftActions';
import { CopySuccessToast } from '@/components/features/feedback/CopySuccessToast';
import { DeleteConfirmDialog } from '../journal/DeleteConfirmDialog';
/**
* DraftViewSheet - Main draft view component
*
* Story 2.4: Updated to use completeDraft action with toast feedback.
* Story 3.2: Added delete functionality with confirmation dialog.
*
* Combines Sheet, DraftContent, and DraftActions to display
* the Ghostwriter's draft in a polished, reading-focused interface.
*
* Auto-opens when currentDraft transitions from null to populated.
* Integrates with ChatStore for approval/rejection actions.
*/
export function DraftViewSheet() {
const currentDraft = useChatStore((s) => s.currentDraft);
const showDraftView = useChatStore((s) => s.showDraftView);
const closeDraftView = useChatStore((s) => s.closeDraftView);
const completeDraft = useChatStore((s) => s.completeDraft);
const copyDraftToClipboard = useChatStore((s) => s.copyDraftToClipboard);
const rejectDraft = useChatStore((s) => s.rejectDraft);
// Story 3.2: Use store action for architecture compliance
const deleteDraft = useChatStore((s) => s.deleteDraft);
// Story 3.2: Delete dialog state
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
// Toast state for copy feedback
const [toastShow, setToastShow] = useState(false);
const [toastMessage, setToastMessage] = useState('');
const showCopyToast = (message: string = 'Copied to clipboard!') => {
setToastMessage(message);
setToastShow(true);
};
const handleClose = () => {
closeDraftView();
};
const handleApprove = async () => {
if (currentDraft) {
// Story 2.4: Use completeDraft which copies + marks completed
await completeDraft(currentDraft.id);
showCopyToast('Copied and saved to history!');
}
};
const handleCopyOnly = async () => {
if (currentDraft) {
// Story 2.4: Copy without closing sheet or marking as completed
await copyDraftToClipboard(currentDraft.id);
showCopyToast('Copied to clipboard!');
}
};
const handleReject = () => {
if (currentDraft) {
rejectDraft(currentDraft.id);
// Add system message to chat: "What should we change?"
// This will be handled by the ChatService in story 2.3
}
};
// Story 3.2: Delete handler
const handleDelete = async () => {
if (currentDraft) {
// Use store action
const success = await deleteDraft(currentDraft.id);
if (success) {
// Close the dialog (Sheet closed by store action if current draft verified)
setShowDeleteDialog(false);
showCopyToast('Post deleted successfully!');
} else {
// Handle error - close dialog but keep sheet open
setShowDeleteDialog(false);
showCopyToast('Failed to delete post');
}
}
};
if (!currentDraft) {
return null;
}
return (
<>
<Sheet open={showDraftView} onClose={handleClose}>
<DraftContent draft={currentDraft} />
{/* Story 3.2: Extended footer with delete button */}
<nav className="sticky bottom-0 flex gap-3 p-4 bg-white border-t border-slate-200">
{/* Delete button (Story 3.2) */}
<button
onClick={() => setShowDeleteDialog(true)}
type="button"
className="min-h-[44px] px-4 py-3 border border-destructive text-destructive rounded-md hover:bg-destructive/10 transition-colors flex items-center justify-center gap-2"
aria-label="Delete this draft"
>
<Trash2 className="w-5 h-5" aria-hidden="true" />
<span>Delete</span>
</button>
{/* Draft actions from original component */}
<DraftActions
onApprove={handleApprove}
onReject={handleReject}
onCopyOnly={handleCopyOnly}
/>
</nav>
</Sheet>
{/* Story 3.2: Delete confirmation dialog */}
<DeleteConfirmDialog
open={showDeleteDialog}
onOpenChange={setShowDeleteDialog}
onConfirm={handleDelete}
draftTitle={currentDraft.title}
/>
{/* Toast for copy feedback (Story 2.4) */}
<CopySuccessToast
show={toastShow}
message={toastMessage}
onClose={() => setToastShow(false)}
/>
</>
);
}