supermemory/apps/web/hooks/use-org-settings.ts
vorflux 8071a7b085 Add Nova workspace prompt settings (#1323)
Adds a dedicated Workspace Prompt editor for Company Brain organizations while preserving the existing Organization Context ingestion-filter controls for every organization manager.

## Changes

- Keeps Organization Context byte-for-byte unchanged and available independently to all organization managers.
- Adds Workspace Prompt as a separate Company-Brain-only section below it, using the established settings styling and contextual divider.
- Describes Workspace Prompt as persistent guidance that can shape operating preferences, priorities, source/tool choices, workflows, terminology, formatting, and communication style.
- Adds nullable, 1,500-character `workspacePrompt` support to shared request, GET response, and PATCH response contracts.
- Aligns PATCH validation with the real `{ orgId, orgSlug, updated }` API response.
- Merges canonical `updated` settings into the submitting organization’s cache, then exactly refetches that organization.
- Preserves drafts during background refetches, isolates organization switches, retains actionable errors, accessibility, empty `filterPrompt` compatibility, and `X-App-Source: nova`.

## Testing

- Passed focused Biome checks on all changed files.
- Passed `packages/lib` and `packages/validation` TypeScript checks.
- Verified GET/PATCH settings response contracts, partial/null/limit validation, canonical cache merge, and exact organization-bound invalidation.
- Verified Organization Context remains unchanged and Workspace Prompt is separately Company-Brain/manager-gated.
- Confirmed no remaining Workspace Persona identifiers.
- Public preview returns HTTP 200; authenticated settings interactions remain unavailable without a saved OAuth session.
- Full web type-check remains blocked by unrelated baseline diagnostics; none reference changed files.
- No dedicated tests were added, per requester instruction.

---
**Session Details**
- Session: [View Session](https://supermemory.us1.vorflux.com/agent-sessions/7544b72b-aeca-48e2-81c3-514df21cd081)
- Requested by: Soham Daga (soham@supermemory.com)
- Address comments on this PR. Add `(aside)` to your comment to have me ignore it.
2026-07-29 21:13:59 +00:00

74 lines
2.1 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { toast } from "sonner"
import { $fetch } from "@lib/api"
import { useAuth } from "@lib/auth-context"
export type OrgSettings = {
shouldLLMFilter: boolean
filterPrompt: string | null
workspacePrompt: string | null
includeItems?: string[] | null
excludeItems?: string[] | null
}
export function useOrgSettings() {
const { org } = useAuth()
const orgId = org?.id ?? ""
return useQuery({
queryKey: ["settings", "org", orgId],
queryFn: async (): Promise<OrgSettings> => {
const response = await $fetch("@get/settings")
if (response.error) {
throw new Error(response.error.message || "Failed to load settings")
}
const settings = response.data ?? {}
return {
shouldLLMFilter: settings.shouldLLMFilter ?? false,
filterPrompt: settings.filterPrompt ?? null,
workspacePrompt: settings.workspacePrompt ?? null,
includeItems: settings.includeItems ?? null,
excludeItems: settings.excludeItems ?? null,
}
},
enabled: !!orgId,
staleTime: 60 * 1000,
})
}
export function useUpdateOrgSettings() {
const { org } = useAuth()
const queryClient = useQueryClient()
const orgId = org?.id ?? ""
return useMutation({
mutationFn: async (settings: Partial<OrgSettings>) => {
const response = await $fetch("@patch/settings", {
body: settings,
})
if (response.error) {
throw new Error(response.error.message || "Failed to save settings", {
cause: response.error,
})
}
return response.data
},
onMutate: () => ({ orgId }),
onSuccess: async (data, _settings, mutationContext) => {
const queryKey = ["settings", "org", mutationContext.orgId] as const
const canonicalSettings = data?.updated
if (canonicalSettings) {
queryClient.setQueryData<OrgSettings>(queryKey, (current) =>
current ? { ...current, ...canonicalSettings } : current,
)
}
await queryClient.invalidateQueries({ queryKey, exact: true })
toast.success("Settings saved")
},
onError: (error) => {
toast.error(
error instanceof Error ? error.message : "Failed to save settings",
)
},
})
}