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:
140
src/components/features/draft/DraftViewSheet.tsx
Normal file
140
src/components/features/draft/DraftViewSheet.tsx
Normal 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)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user