Type mutation inputs with shared Zod schemas instead of Record<string, unknown>

Replaced loose Record<string, unknown> types on useCreateTicket,
useUpdateTicket, useCreateUser, useUpdateUser, useUpdateWebhook,
and useCreateSavedView with their corresponding shared schema types.
Fixed three type errors this surfaced at call sites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 20:37:23 -04:00
parent 86399c4ed0
commit c0ff063023
4 changed files with 20 additions and 15 deletions
+10 -6
View File
@@ -7,6 +7,10 @@ import type {
Webhook, Webhook,
PaginatedResponse, PaginatedResponse,
} from '../../../shared/types'; } from '../../../shared/types';
import type { CreateTicketInput, UpdateTicketInput } from '../../../shared/schemas/ticket';
import type { CreateUserInput, UpdateUserInput } from '../../../shared/schemas/user';
import type { UpdateWebhookInput } from '../../../shared/schemas/notification';
import type { CreateSavedViewInput } from '../../../shared/schemas/savedView';
// ── Keys ───────────────────────────────────────────────────────────────────── // ── Keys ─────────────────────────────────────────────────────────────────────
@@ -96,7 +100,7 @@ export function useTicketAudit(id: string | undefined, enabled = true) {
export function useCreateTicket() { export function useCreateTicket() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (data: Record<string, unknown>) => mutationFn: async (data: CreateTicketInput) =>
(await api.post<Ticket>('/tickets', data)).data, (await api.post<Ticket>('/tickets', data)).data,
onSuccess: () => { onSuccess: () => {
qc.invalidateQueries({ queryKey: ['tickets'] }); qc.invalidateQueries({ queryKey: ['tickets'] });
@@ -107,7 +111,7 @@ export function useCreateTicket() {
export function useUpdateTicket() { export function useUpdateTicket() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async ({ id, data }: { id: string; data: Record<string, unknown> }) => mutationFn: async ({ id, data }: { id: string; data: UpdateTicketInput }) =>
(await api.patch<Ticket>(`/tickets/${id}`, data)).data, (await api.patch<Ticket>(`/tickets/${id}`, data)).data,
onSuccess: (ticket) => { onSuccess: (ticket) => {
qc.setQueryData(qk.ticket(ticket.displayId), ticket); qc.setQueryData(qk.ticket(ticket.displayId), ticket);
@@ -265,7 +269,7 @@ export function useUsers() {
export function useCreateUser() { export function useCreateUser() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (data: Record<string, unknown>) => mutationFn: async (data: CreateUserInput) =>
(await api.post<User>('/users', data)).data, (await api.post<User>('/users', data)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: qk.users() }), onSuccess: () => qc.invalidateQueries({ queryKey: qk.users() }),
}); });
@@ -274,7 +278,7 @@ export function useCreateUser() {
export function useUpdateUser() { export function useUpdateUser() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async ({ id, data }: { id: string; data: Record<string, unknown> }) => mutationFn: async ({ id, data }: { id: string; data: UpdateUserInput }) =>
(await api.patch<User>(`/users/${id}`, data)).data, (await api.patch<User>(`/users/${id}`, data)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: qk.users() }), onSuccess: () => qc.invalidateQueries({ queryKey: qk.users() }),
}); });
@@ -344,7 +348,7 @@ export function useCreateWebhook() {
export function useUpdateWebhook() { export function useUpdateWebhook() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async ({ id, data }: { id: string; data: Record<string, unknown> }) => mutationFn: async ({ id, data }: { id: string; data: UpdateWebhookInput }) =>
(await api.patch<Webhook>(`/webhooks/${id}`, data)).data, (await api.patch<Webhook>(`/webhooks/${id}`, data)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: qk.webhooks() }), onSuccess: () => qc.invalidateQueries({ queryKey: qk.webhooks() }),
}); });
@@ -382,7 +386,7 @@ export function useSavedViews() {
export function useCreateSavedView() { export function useCreateSavedView() {
const qc = useQueryClient(); const qc = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (data: { name: string; filters: Record<string, unknown> }) => mutationFn: async (data: CreateSavedViewInput) =>
(await api.post<SavedView>('/saved-views', data)).data, (await api.post<SavedView>('/saved-views', data)).data,
onSuccess: () => qc.invalidateQueries({ queryKey: qk.savedViews() }), onSuccess: () => qc.invalidateQueries({ queryKey: qk.savedViews() }),
}); });
+4 -3
View File
@@ -38,9 +38,10 @@ export default function NewTicketModal({ onClose }: NewTicketModalProps) {
const onSubmit = async (data: CreateTicketInput) => { const onSubmit = async (data: CreateTicketInput) => {
setError(''); setError('');
try { try {
const payload: Record<string, unknown> = { ...data }; const { assigneeId, ...rest } = data;
if (!data.assigneeId) delete payload.assigneeId; const created = await createTicket.mutateAsync(
const created = await createTicket.mutateAsync(payload); assigneeId ? { ...rest, assigneeId } : rest,
);
onClose(); onClose();
navigate(`/${created.displayId}`); navigate(`/${created.displayId}`);
} catch { } catch {
+1 -1
View File
@@ -154,7 +154,7 @@ export default function Tickets() {
const currentFilters = useMemo( const currentFilters = useMemo(
() => ({ () => ({
status: status || undefined, status: status || undefined,
severity: severity || undefined, severity: severity ? Number(severity) : undefined,
assigneeId: assigneeId || undefined, assigneeId: assigneeId || undefined,
categoryId: categoryId || undefined, categoryId: categoryId || undefined,
typeId: typeId || undefined, typeId: typeId || undefined,
+5 -5
View File
@@ -4,6 +4,7 @@ import { toast } from 'sonner';
import Layout from '../../components/Layout'; import Layout from '../../components/Layout';
import Modal from '../../components/Modal'; import Modal from '../../components/Modal';
import { User, Role } from '../../types'; import { User, Role } from '../../types';
import type { CreateUserInput } from '../../../../shared/schemas/user';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
import { import {
useUsers, useUsers,
@@ -105,14 +106,13 @@ export default function AdminUsers() {
e.preventDefault(); e.preventDefault();
setError(''); setError('');
try { try {
const payload: Record<string, string> = { const created = await createUser.mutateAsync({
username: form.username, username: form.username,
email: form.email, email: form.email,
displayName: form.displayName, displayName: form.displayName,
role: form.role, role: form.role as CreateUserInput['role'],
}; password: form.password,
if (form.password) payload.password = form.password; });
const created = await createUser.mutateAsync(payload);
if (created.apiKey) setNewApiKey(created.apiKey); if (created.apiKey) setNewApiKey(created.apiKey);
else closeModal(); else closeModal();
} catch (err: unknown) { } catch (err: unknown) {