ghostwriter panel
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
CalendarClock,
|
CalendarClock,
|
||||||
ClipboardList,
|
ClipboardList,
|
||||||
DollarSign,
|
DollarSign,
|
||||||
|
PanelRightOpen,
|
||||||
PlusCircle,
|
PlusCircle,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
@@ -20,6 +21,14 @@ import { toast } from "sonner";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetDescription,
|
||||||
|
SheetHeader,
|
||||||
|
SheetTitle,
|
||||||
|
SheetTrigger,
|
||||||
|
} from "@/components/ui/sheet";
|
||||||
import { formatTimestamp } from "@/lib/utils";
|
import { formatTimestamp } from "@/lib/utils";
|
||||||
import * as api from "../api";
|
import * as api from "../api";
|
||||||
import { ConfirmDelete } from "../components/ConfirmDelete";
|
import { ConfirmDelete } from "../components/ConfirmDelete";
|
||||||
@@ -40,6 +49,7 @@ export const JobPage: React.FC = () => {
|
|||||||
const [isLoading, setIsLoading] = React.useState(true);
|
const [isLoading, setIsLoading] = React.useState(true);
|
||||||
const [isLogModalOpen, setIsLogModalOpen] = React.useState(false);
|
const [isLogModalOpen, setIsLogModalOpen] = React.useState(false);
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = React.useState(false);
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = React.useState(false);
|
||||||
|
const [isGhostwriterOpen, setIsGhostwriterOpen] = React.useState(false);
|
||||||
const [eventToDelete, setEventToDelete] = React.useState<string | null>(null);
|
const [eventToDelete, setEventToDelete] = React.useState<string | null>(null);
|
||||||
const [editingEvent, setEditingEvent] = React.useState<StageEvent | null>(
|
const [editingEvent, setEditingEvent] = React.useState<StageEvent | null>(
|
||||||
null,
|
null,
|
||||||
@@ -271,6 +281,7 @@ export const JobPage: React.FC = () => {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Sheet open={isGhostwriterOpen} onOpenChange={setIsGhostwriterOpen}>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Card className="border-border/50">
|
<Card className="border-border/50">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -279,7 +290,17 @@ export const JobPage: React.FC = () => {
|
|||||||
<CalendarClock className="h-4 w-4" />
|
<CalendarClock className="h-4 w-4" />
|
||||||
Application details
|
Application details
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<GhostwriterDrawer job={job} />
|
<SheetTrigger asChild>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 gap-1.5 text-xs"
|
||||||
|
disabled={!job}
|
||||||
|
>
|
||||||
|
<PanelRightOpen className="h-3.5 w-3.5" />
|
||||||
|
Ghostwriter
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
@@ -353,8 +374,26 @@ export const JobPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{job && <GhostwriterPanel job={job} />}
|
<SheetContent
|
||||||
|
side="right"
|
||||||
|
className="w-full p-0 sm:max-w-none lg:w-[40vw]"
|
||||||
|
>
|
||||||
|
<div className="h-full overflow-y-auto p-4">
|
||||||
|
<SheetHeader>
|
||||||
|
<SheetTitle>Ghostwriter</SheetTitle>
|
||||||
|
<SheetDescription>
|
||||||
|
Chat with context from this job and your writing style.
|
||||||
|
</SheetDescription>
|
||||||
|
</SheetHeader>
|
||||||
|
{job && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<GhostwriterPanel job={job} />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</div>
|
||||||
|
</Sheet>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LogEventModal
|
<LogEventModal
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
FileText,
|
FileText,
|
||||||
Loader2,
|
Loader2,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
|
PanelRightOpen,
|
||||||
RefreshCcw,
|
RefreshCcw,
|
||||||
Save,
|
Save,
|
||||||
XCircle,
|
XCircle,
|
||||||
@@ -24,6 +25,14 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import {
|
||||||
|
Sheet,
|
||||||
|
SheetContent,
|
||||||
|
SheetDescription,
|
||||||
|
SheetHeader,
|
||||||
|
SheetTitle,
|
||||||
|
SheetTrigger,
|
||||||
|
} from "@/components/ui/sheet";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
@@ -39,6 +48,7 @@ import {
|
|||||||
JobHeader,
|
JobHeader,
|
||||||
TailoredSummary,
|
TailoredSummary,
|
||||||
} from "../../components";
|
} from "../../components";
|
||||||
|
import { GhostwriterPanel } from "../../components/ghostwriter/GhostwriterPanel";
|
||||||
import { JobDetailsEditDrawer } from "../../components/JobDetailsEditDrawer";
|
import { JobDetailsEditDrawer } from "../../components/JobDetailsEditDrawer";
|
||||||
import { ReadyPanel } from "../../components/ReadyPanel";
|
import { ReadyPanel } from "../../components/ReadyPanel";
|
||||||
import { TailoringEditor } from "../../components/TailoringEditor";
|
import { TailoringEditor } from "../../components/TailoringEditor";
|
||||||
@@ -71,6 +81,7 @@ export const JobDetailPanel: React.FC<JobDetailPanelProps> = ({
|
|||||||
const [hasUnsavedTailoring, setHasUnsavedTailoring] = useState(false);
|
const [hasUnsavedTailoring, setHasUnsavedTailoring] = useState(false);
|
||||||
const [processingJobId, setProcessingJobId] = useState<string | null>(null);
|
const [processingJobId, setProcessingJobId] = useState<string | null>(null);
|
||||||
const [isEditDetailsOpen, setIsEditDetailsOpen] = useState(false);
|
const [isEditDetailsOpen, setIsEditDetailsOpen] = useState(false);
|
||||||
|
const [isGhostwriterOpen, setIsGhostwriterOpen] = useState(false);
|
||||||
const saveTailoringRef = useRef<null | (() => Promise<void>)>(null);
|
const saveTailoringRef = useRef<null | (() => Promise<void>)>(null);
|
||||||
const previousSelectedJobIdRef = useRef<string | null>(null);
|
const previousSelectedJobIdRef = useRef<string | null>(null);
|
||||||
|
|
||||||
@@ -310,23 +321,93 @@ export const JobDetailPanel: React.FC<JobDetailPanelProps> = ({
|
|||||||
|
|
||||||
if (activeTab === "discovered") {
|
if (activeTab === "discovered") {
|
||||||
return (
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Sheet open={isGhostwriterOpen} onOpenChange={setIsGhostwriterOpen}>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 gap-1.5 text-xs"
|
||||||
|
disabled={!selectedJob}
|
||||||
|
>
|
||||||
|
<PanelRightOpen className="h-3.5 w-3.5" />
|
||||||
|
Ghostwriter
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent
|
||||||
|
side="right"
|
||||||
|
className="w-full p-0 sm:max-w-none lg:w-[40vw]"
|
||||||
|
>
|
||||||
|
<div className="h-full overflow-y-auto p-4">
|
||||||
|
<SheetHeader>
|
||||||
|
<SheetTitle>Ghostwriter</SheetTitle>
|
||||||
|
<SheetDescription>
|
||||||
|
Chat with context from this job and your writing style.
|
||||||
|
</SheetDescription>
|
||||||
|
</SheetHeader>
|
||||||
|
{selectedJob && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<GhostwriterPanel job={selectedJob} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
</div>
|
||||||
<DiscoveredPanel
|
<DiscoveredPanel
|
||||||
job={selectedJob}
|
job={selectedJob}
|
||||||
onJobUpdated={onJobUpdated}
|
onJobUpdated={onJobUpdated}
|
||||||
onJobMoved={handleJobMoved}
|
onJobMoved={handleJobMoved}
|
||||||
onTailoringDirtyChange={handleTailoringDirtyChange}
|
onTailoringDirtyChange={handleTailoringDirtyChange}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeTab === "ready") {
|
if (activeTab === "ready") {
|
||||||
return (
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Sheet open={isGhostwriterOpen} onOpenChange={setIsGhostwriterOpen}>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 gap-1.5 text-xs"
|
||||||
|
disabled={!selectedJob}
|
||||||
|
>
|
||||||
|
<PanelRightOpen className="h-3.5 w-3.5" />
|
||||||
|
Ghostwriter
|
||||||
|
</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent
|
||||||
|
side="right"
|
||||||
|
className="w-full p-0 sm:max-w-none lg:w-[40vw]"
|
||||||
|
>
|
||||||
|
<div className="h-full overflow-y-auto p-4">
|
||||||
|
<SheetHeader>
|
||||||
|
<SheetTitle>Ghostwriter</SheetTitle>
|
||||||
|
<SheetDescription>
|
||||||
|
Chat with context from this job and your writing style.
|
||||||
|
</SheetDescription>
|
||||||
|
</SheetHeader>
|
||||||
|
{selectedJob && (
|
||||||
|
<div className="mt-4">
|
||||||
|
<GhostwriterPanel job={selectedJob} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
</div>
|
||||||
<ReadyPanel
|
<ReadyPanel
|
||||||
job={selectedJob}
|
job={selectedJob}
|
||||||
onJobUpdated={onJobUpdated}
|
onJobUpdated={onJobUpdated}
|
||||||
onJobMoved={handleJobMoved}
|
onJobMoved={handleJobMoved}
|
||||||
onTailoringDirtyChange={handleTailoringDirtyChange}
|
onTailoringDirtyChange={handleTailoringDirtyChange}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user