Files
simstudioai--sim/apps/sim/hooks/queries/inbox.ts
T
wehub-resource-sync d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

230 lines
6.9 KiB
TypeScript

import { generateId } from '@sim/utils/id'
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { requestJson } from '@/lib/api/client/request'
import {
addInboxSenderContract,
getInboxConfigContract,
type InboxConfig,
type InboxSendersResponseBody,
type InboxTask,
type InboxTaskStatus,
type InboxTasksResponseBody,
listInboxSendersContract,
listInboxTasksContract,
removeInboxSenderContract,
updateInboxConfigContract,
} from '@/lib/api/contracts'
export type { InboxConfig, InboxSendersResponseBody }
export type InboxTaskItem = InboxTask
export type InboxTasksResponse = InboxTasksResponseBody
export const INBOX_CONFIG_STALE_TIME = 30 * 1000
export const INBOX_SENDER_LIST_STALE_TIME = 60 * 1000
export const INBOX_TASK_LIST_STALE_TIME = 15 * 1000
export const inboxKeys = {
all: ['inbox'] as const,
configs: () => [...inboxKeys.all, 'config'] as const,
config: (workspaceId: string) => [...inboxKeys.configs(), workspaceId] as const,
senders: () => [...inboxKeys.all, 'sender'] as const,
senderList: (workspaceId: string) => [...inboxKeys.senders(), workspaceId] as const,
tasks: () => [...inboxKeys.all, 'task'] as const,
taskList: (workspaceId: string, status?: string, cursor?: string, limit?: number) =>
[...inboxKeys.tasks(), workspaceId, status ?? 'all', cursor ?? '', limit ?? ''] as const,
}
type InboxTaskStatusFilter = InboxTaskStatus
async function fetchInboxConfig(workspaceId: string, signal?: AbortSignal): Promise<InboxConfig> {
return requestJson(getInboxConfigContract, {
params: { id: workspaceId },
signal,
})
}
async function fetchInboxSenders(
workspaceId: string,
signal?: AbortSignal
): Promise<InboxSendersResponseBody> {
return requestJson(listInboxSendersContract, {
params: { id: workspaceId },
signal,
})
}
async function fetchInboxTasks(
workspaceId: string,
opts: { status?: InboxTaskStatusFilter; cursor?: string; limit?: number },
signal?: AbortSignal
): Promise<InboxTasksResponseBody> {
return requestJson(listInboxTasksContract, {
params: { id: workspaceId },
query: {
status: opts.status && opts.status !== 'all' ? opts.status : undefined,
cursor: opts.cursor,
limit: opts.limit,
},
signal,
})
}
export function useInboxConfig(workspaceId: string) {
return useQuery({
queryKey: inboxKeys.config(workspaceId),
queryFn: ({ signal }) => fetchInboxConfig(workspaceId, signal),
enabled: Boolean(workspaceId),
staleTime: INBOX_CONFIG_STALE_TIME,
})
}
export function useInboxSenders(workspaceId: string) {
return useQuery({
queryKey: inboxKeys.senderList(workspaceId),
queryFn: ({ signal }) => fetchInboxSenders(workspaceId, signal),
enabled: Boolean(workspaceId),
staleTime: INBOX_SENDER_LIST_STALE_TIME,
})
}
export function useInboxTasks(
workspaceId: string,
opts: { status?: InboxTaskStatusFilter; cursor?: string; limit?: number } = {}
) {
return useQuery({
queryKey: inboxKeys.taskList(workspaceId, opts.status, opts.cursor, opts.limit),
queryFn: ({ signal }) => fetchInboxTasks(workspaceId, opts, signal),
enabled: Boolean(workspaceId),
staleTime: INBOX_TASK_LIST_STALE_TIME,
placeholderData: keepPreviousData,
})
}
export function useToggleInbox() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async ({
workspaceId,
enabled,
username,
}: {
workspaceId: string
enabled: boolean
username?: string
}) => {
return requestJson(updateInboxConfigContract, {
params: { id: workspaceId },
body: { enabled, username },
})
},
onSettled: (_data, _error, variables) => {
return queryClient.invalidateQueries({ queryKey: inboxKeys.config(variables.workspaceId) })
},
})
}
export function useUpdateInboxAddress() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async ({ workspaceId, username }: { workspaceId: string; username: string }) => {
return requestJson(updateInboxConfigContract, {
params: { id: workspaceId },
body: { username },
})
},
onSettled: (_data, _error, variables) => {
return queryClient.invalidateQueries({ queryKey: inboxKeys.config(variables.workspaceId) })
},
})
}
export function useAddInboxSender() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async ({
workspaceId,
email,
label,
}: {
workspaceId: string
email: string
label?: string
}) => {
return requestJson(addInboxSenderContract, {
params: { id: workspaceId },
body: { email, label },
})
},
onMutate: async ({ workspaceId, email, label }) => {
await queryClient.cancelQueries({ queryKey: inboxKeys.senderList(workspaceId) })
const previous = queryClient.getQueryData<InboxSendersResponseBody>(
inboxKeys.senderList(workspaceId)
)
if (previous) {
queryClient.setQueryData<InboxSendersResponseBody>(inboxKeys.senderList(workspaceId), {
...previous,
senders: [
...previous.senders,
{
id: `optimistic-${generateId()}`,
email,
label: label || null,
createdAt: new Date().toISOString(),
},
],
})
}
return { previous }
},
onError: (_err, variables, context) => {
if (context?.previous) {
queryClient.setQueryData(inboxKeys.senderList(variables.workspaceId), context.previous)
}
},
onSettled: (_data, _error, variables) => {
return queryClient.invalidateQueries({
queryKey: inboxKeys.senderList(variables.workspaceId),
})
},
})
}
export function useRemoveInboxSender() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async ({ workspaceId, senderId }: { workspaceId: string; senderId: string }) => {
return requestJson(removeInboxSenderContract, {
params: { id: workspaceId },
body: { senderId },
})
},
onMutate: async ({ workspaceId, senderId }) => {
await queryClient.cancelQueries({ queryKey: inboxKeys.senderList(workspaceId) })
const previous = queryClient.getQueryData<InboxSendersResponseBody>(
inboxKeys.senderList(workspaceId)
)
if (previous) {
queryClient.setQueryData<InboxSendersResponseBody>(inboxKeys.senderList(workspaceId), {
...previous,
senders: previous.senders.filter((s) => s.id !== senderId),
})
}
return { previous }
},
onError: (_err, variables, context) => {
if (context?.previous) {
queryClient.setQueryData(inboxKeys.senderList(variables.workspaceId), context.previous)
}
},
onSettled: (_data, _error, variables) => {
return queryClient.invalidateQueries({
queryKey: inboxKeys.senderList(variables.workspaceId),
})
},
})
}