import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { orgApi } from './org' // Branding changes rarely and is read by the shell on every screen, so it is cached for the session. export function useOrgBranding() { return useQuery({ queryKey: ['org', 'branding'], queryFn: orgApi.branding, staleTime: 5 * 60_000 }) } export function useSetDisplayName() { const qc = useQueryClient() return useMutation({ mutationFn: (name: string) => orgApi.setDisplayName(name), onSuccess: () => void qc.invalidateQueries({ queryKey: ['org', 'branding'] }), }) } export function useUploadLogo() { const qc = useQueryClient() return useMutation({ mutationFn: async (file: File) => { // Sent as a raw body, not multipart. The server ignores the declared type entirely and derives the // format by decoding the bytes, so there is nothing to gain from a form envelope. const csrf = await fetch('/api/auth/csrf', { credentials: 'include' }) .then((r) => r.json()) .then((j: { csrf_token: string }) => j.csrf_token) const res = await fetch('/api/org/logo', { method: 'PUT', credentials: 'include', headers: { 'X-CSRF-Token': csrf, 'Content-Type': 'application/octet-stream' }, body: file, }) if (!res.ok) { const body = (await res.json().catch(() => ({}))) as { error?: string } throw new Error(body.error ?? `upload failed with ${res.status}`) } return res.json() }, onSuccess: () => void qc.invalidateQueries({ queryKey: ['org', 'branding'] }), }) } export function useClearLogo() { const qc = useQueryClient() return useMutation({ mutationFn: () => orgApi.clearLogo(), onSuccess: () => void qc.invalidateQueries({ queryKey: ['org', 'branding'] }), }) }