Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions apps/web/components/dashboard-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
import { normalizePluginClientId } from "@/lib/plugin-catalog"
import { detectPluginSpace } from "@/lib/plugin-space"
import { useDigests } from "@/hooks/use-digests"
import { ReviewMemoriesCard } from "@/components/review-memories-card"

type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
Expand Down Expand Up @@ -1180,6 +1181,7 @@ export function DashboardView({
}) {
const { user, org } = useAuth()
const { effectiveContainerTags } = useProject()
const primaryContainerTag = effectiveContainerTags?.[0]
const _router = useRouter()
const { data: recentsData, isPending: isRecentsLoading } = useQuery({
queryKey: ["dashboard-recents", effectiveContainerTags],
Expand Down Expand Up @@ -1598,7 +1600,8 @@ export function DashboardView({
)}
</div>

<div className="flex-[2] min-w-0 hidden sm:block">
<div className="flex-[2] min-w-0 hidden sm:block space-y-2">
<ReviewMemoriesCard containerTag={primaryContainerTag} />
<RecommendedPluginsCard
profession={profession}
setProfession={setProfession}
Expand All @@ -1615,7 +1618,8 @@ export function DashboardView({
<p className="text-[10px] font-medium uppercase tracking-[0.12em] text-fg-faint">
Suggested for you
</p>
<div className="max-w-sm">
<div className="max-w-sm space-y-2">
<ReviewMemoriesCard containerTag={primaryContainerTag} />
<RecommendedPluginsCard
profession={profession}
setProfession={setProfession}
Expand Down
79 changes: 79 additions & 0 deletions apps/web/components/review-memories-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"use client"

import { ReviewMemoriesModal } from "@/components/review-memories-modal"
import { useInferredMemories } from "@/hooks/use-inferred-memories"
import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
import { ArrowRight } from "lucide-react"
import { useEffect, useState } from "react"

// "Suggested for you" entry point — opens the swipe-review modal. The trigger
// hides when there's nothing to review, but the modal stays mounted while open
// (even after the last card) so it can show its "all caught up" summary.
// Styled to match the Weekly digest box above it.
export function ReviewMemoriesCard({
containerTag,
className,
}: {
containerTag: string | undefined
className?: string
}) {
const [open, setOpen] = useState(false)
const { data: memories = [] } = useInferredMemories(containerTag)
const liveCount = memories.length

// While the modal is open, freeze the count shown on the trigger so the
// background button stays put (doesn't tick down or vanish) until it closes.
const [frozenCount, setFrozenCount] = useState(0)
const count = open ? frozenCount : liveCount

const handleOpenChange = (next: boolean) => {
if (next) setFrozenCount(liveCount)
setOpen(next)
}

// Switching spaces shouldn't carry an open modal over to the new space.
// biome-ignore lint/correctness/useExhaustiveDependencies: reset on space switch
useEffect(() => {
setOpen(false)
}, [containerTag])

return (
<>
{count > 0 && (
<button
type="button"
onClick={() => handleOpenChange(true)}
className={cn(
"group flex w-full items-center justify-between gap-3 rounded-xl bg-[#0c1a30]/80 px-3.5 py-3 text-left shadow-[0_12px_40px_rgba(0,0,0,0.22)] ring-1 ring-[#4BA0FA]/20 backdrop-blur-md transition-colors hover:bg-[#0e2038]/90 hover:ring-[#4BA0FA]/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#4BA0FA]/45",
dmSansClassName(),
className,
)}
>
<div className="min-w-0">
<p className="text-[13px] font-semibold leading-tight text-fg-primary">
Review suggestions
</p>
<p className="mt-1 truncate text-[11px] leading-tight text-fg-faint">
{count} {count === 1 ? "memory" : "memories"} we inferred for you
</p>
</div>
<span className="flex shrink-0 items-center gap-2 text-fg-faint transition-colors group-hover:text-fg-muted">
<span className="flex h-5 min-w-5 items-center justify-center rounded-full bg-brand-accent px-1.5 text-[10px] font-bold text-[#00111f]">
{count}
</span>
<ArrowRight className="size-3.5 transition-transform group-hover:translate-x-0.5" />
</span>
</button>
)}

{(open || liveCount > 0) && (
<ReviewMemoriesModal
open={open}
onOpenChange={handleOpenChange}
containerTag={containerTag}
/>
)}
</>
)
}
Loading
Loading