lots of changes

This commit is contained in:
2026-02-04 11:18:33 +00:00
parent d02d95e680
commit 4fdbfb0fb3
30 changed files with 1796 additions and 822 deletions

View File

@@ -98,8 +98,8 @@ export function SectionEditor({
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-3">
<CardTitle className="text-base">{title}</CardTitle>
<CardHeader className="flex flex-row items-center justify-between gap-2 px-4 py-3">
<CardTitle className="text-sm">{title}</CardTitle>
<div className="flex flex-wrap items-center gap-2">
<Button variant="outline" size="sm" onClick={() => setIsAddOpen(true)}>
Add
@@ -109,17 +109,17 @@ export function SectionEditor({
</Button>
</div>
</CardHeader>
<CardContent className="space-y-2 text-sm">
<CardContent className="max-h-[260px] space-y-2 overflow-auto px-4 pb-4 text-xs">
{items.length === 0 ? (
<div className="text-muted-foreground">No items yet.</div>
) : (
items.map((item, index) => (
<div
key={`${sectionKey}-${index}`}
className="flex flex-wrap items-start justify-between gap-2 rounded-md border border-border/60 p-3"
className="flex flex-wrap items-start justify-between gap-2 rounded-md border border-border/60 p-2"
>
<div className="space-y-2">
<div className="font-medium">{summarizeItem(item)}</div>
<div className="space-y-1">
<div className="font-medium text-sm">{summarizeItem(item)}</div>
<Badge variant="outline">#{index + 1}</Badge>
</div>
<Button
@@ -246,8 +246,8 @@ export function ProfileSectionEditor({
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-3">
<CardTitle className="text-base">Product Profile</CardTitle>
<CardHeader className="flex flex-row items-center justify-between gap-2 px-4 py-3">
<CardTitle className="text-sm">Product Profile</CardTitle>
<div className="flex flex-wrap items-center gap-2">
<Button variant="outline" size="sm" onClick={() => setIsEditOpen(true)}>
Edit
@@ -257,7 +257,7 @@ export function ProfileSectionEditor({
</Button>
</div>
</CardHeader>
<CardContent className="space-y-2 text-sm text-muted-foreground">
<CardContent className="max-h-[260px] space-y-2 overflow-auto px-4 pb-4 text-xs text-muted-foreground">
<div>
<span className="font-medium text-foreground">Product:</span>{" "}
{items.productName || "Not set"}

View File

@@ -9,6 +9,7 @@ import {
Settings,
Terminal,
Target,
Inbox,
Plus,
ArrowUpRight,
ChevronsUpDown
@@ -87,6 +88,10 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const [pendingSourceId, setPendingSourceId] = React.useState<string | null>(null);
const [pendingProjectId, setPendingProjectId] = React.useState<string | null>(null);
const [pendingJobId, setPendingJobId] = React.useState<string | null>(null);
const sourceUrlRef = React.useRef<HTMLInputElement | null>(null);
const sourceNameRef = React.useRef<HTMLInputElement | null>(null);
const manualProductNameRef = React.useRef<HTMLInputElement | null>(null);
const manualDescriptionRef = React.useRef<HTMLTextAreaElement | null>(null);
const analysisJob = useQuery(
api.analysisJobs.getById,
pendingJobId ? { jobId: pendingJobId as any } : "skip"
@@ -189,18 +194,20 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
throw new Error(data.error || "Analysis failed");
}
await createAnalysis({
projectId: result.projectId,
dataSourceId: result.sourceId,
analysis: data.data,
});
if (!data.persisted) {
await createAnalysis({
projectId: result.projectId,
dataSourceId: result.sourceId,
analysis: data.data,
});
await updateDataSourceStatus({
dataSourceId: result.sourceId,
analysisStatus: "completed",
lastError: undefined,
lastAnalyzedAt: Date.now(),
});
await updateDataSourceStatus({
dataSourceId: result.sourceId,
analysisStatus: "completed",
lastError: undefined,
lastAnalyzedAt: Date.now(),
});
}
setSourceUrl("");
setSourceName("");
@@ -258,18 +265,20 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
throw new Error(data.error || "Manual analysis failed");
}
await createAnalysis({
projectId: pendingProjectId as any,
dataSourceId: pendingSourceId as any,
analysis: data.data,
});
if (!data.persisted) {
await createAnalysis({
projectId: pendingProjectId as any,
dataSourceId: pendingSourceId as any,
analysis: data.data,
});
await updateDataSourceStatus({
dataSourceId: pendingSourceId as any,
analysisStatus: "completed",
lastError: undefined,
lastAnalyzedAt: Date.now(),
});
await updateDataSourceStatus({
dataSourceId: pendingSourceId as any,
analysisStatus: "completed",
lastError: undefined,
lastAnalyzedAt: Date.now(),
});
}
setSourceUrl("");
setSourceName("");
@@ -288,6 +297,20 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
}
};
const handleInputEnter = (
event: React.KeyboardEvent<HTMLInputElement>,
next?: React.RefObject<HTMLElement>,
onSubmit?: () => void
) => {
if (event.key !== "Enter" || isSubmittingSource) return;
event.preventDefault();
if (next?.current) {
next.current.focus();
return;
}
onSubmit?.();
};
return (
<Sidebar variant="inset" {...props}>
<SidebarHeader>
@@ -365,9 +388,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarMenuButton
asChild
tooltip="Overview"
isActive={pathname === "/dashboard"}
isActive={pathname === "/app/dashboard"}
>
<Link href="/dashboard">
<Link href="/app/dashboard">
<Terminal />
<span>Overview</span>
</Link>
@@ -377,9 +400,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarMenuButton
asChild
tooltip="Search"
isActive={pathname === "/opportunities"}
isActive={pathname === "/app/search"}
>
<Link href="/opportunities">
<Link href="/app/search">
<Target />
<span>Search</span>
</Link>
@@ -389,9 +412,10 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarMenuButton
asChild
tooltip="Inbox"
isActive={pathname === "/leads"}
isActive={pathname === "/app/inbox"}
>
<Link href="/leads" className="pl-8 text-sm text-muted-foreground hover:text-foreground">
<Link href="/app/inbox">
<Inbox />
<span>Inbox</span>
</Link>
</SidebarMenuButton>
@@ -431,7 +455,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
</Label>
</div>
<Link
href={`/data-sources/${source._id}`}
href={`/app/data-sources/${source._id}`}
className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
>
Details
@@ -508,7 +532,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
placeholder="https://example.com"
value={sourceUrl}
onChange={(event) => setSourceUrl(event.target.value)}
onKeyDown={(event) => handleInputEnter(event, sourceNameRef)}
disabled={isSubmittingSource}
ref={sourceUrlRef}
/>
</div>
<div className="space-y-2">
@@ -518,7 +544,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
placeholder="Product name"
value={sourceName}
onChange={(event) => setSourceName(event.target.value)}
onKeyDown={(event) => handleInputEnter(event, undefined, handleAddSource)}
disabled={isSubmittingSource}
ref={sourceNameRef}
/>
</div>
</>
@@ -531,7 +559,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
id="manualProductName"
value={manualProductName}
onChange={(event) => setManualProductName(event.target.value)}
onKeyDown={(event) => handleInputEnter(event, manualDescriptionRef)}
disabled={isSubmittingSource}
ref={manualProductNameRef}
/>
</div>
<div className="space-y-2">
@@ -542,6 +572,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
onChange={(event) => setManualDescription(event.target.value)}
disabled={isSubmittingSource}
rows={3}
ref={manualDescriptionRef}
/>
</div>
<div className="space-y-2">

View File

@@ -23,7 +23,7 @@ export function SignIn() {
try {
const flow = step === "signIn" ? "signIn" : "signUp";
await signIn("password", { email, password, flow });
const next = nextPath || (flow === "signIn" ? "/dashboard" : "/onboarding");
const next = nextPath || (flow === "signIn" ? "/app/dashboard" : "/onboarding");
if (flow === "signIn") {
router.push(next);
} else {
@@ -41,7 +41,7 @@ export function SignIn() {
};
const handleGoogleSignIn = () => {
const next = nextPath || "/dashboard";
const next = nextPath || "/app/dashboard";
void signIn("google", { redirectTo: next });
};

View File

@@ -100,24 +100,24 @@ export function NavUser({
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => router.push("/settings?tab=upgrade")}>
<DropdownMenuItem onSelect={() => router.push("/app/settings?tab=upgrade")}>
<Sparkles />
Upgrade to Pro
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => router.push("/settings?tab=account")}>
<DropdownMenuItem onSelect={() => router.push("/app/settings?tab=account")}>
<BadgeCheck />
Account
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => router.push("/settings?tab=billing")}>
<DropdownMenuItem onSelect={() => router.push("/app/settings?tab=billing")}>
<CreditCard />
Billing
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem onSelect={() => router.push("/help")}>
<DropdownMenuItem onSelect={() => router.push("/app/help")}>
<HelpCircle />
Support
</DropdownMenuItem>

View File

@@ -24,8 +24,8 @@ export function Sidebar({ productName }: SidebarProps) {
{
label: 'Overview',
icon: LayoutDashboard,
href: '/dashboard',
active: pathname === '/dashboard',
href: '/app/dashboard',
active: pathname === '/app/dashboard',
},
]
@@ -68,10 +68,10 @@ export function Sidebar({ productName }: SidebarProps) {
</Link>
))}
<Link
href="/opportunities"
href="/app/search"
className={cn(
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
pathname === '/opportunities'
pathname === '/app/search'
? 'bg-primary text-primary-foreground'
: 'text-muted-foreground hover:bg-muted hover:text-foreground'
)}
@@ -80,10 +80,10 @@ export function Sidebar({ productName }: SidebarProps) {
Search
</Link>
<Link
href="/leads"
href="/app/inbox"
className={cn(
'flex items-center rounded-md px-3 py-2 pl-9 text-sm font-medium transition-colors',
pathname === '/leads'
pathname === '/app/inbox'
? 'bg-primary text-primary-foreground'
: 'text-muted-foreground hover:bg-muted hover:text-foreground'
)}