import { useMutation, useQueryClient } from "@tanstack/react-query"; import { createParticle, createStreamParticle } from "@/lib/firestore-particles"; import { CONTAINER_TYPES, type NetworkUsage, type ParticleType, type ParticlePropertiesMap } from "@/api/types"; import { parseParticlePath, particlePath, ParticlePath, toFirestoreChildrenPath } from "@/lib/particle-path"; import { QuotaExceededError } from "@/lib/errors"; import { isUsageExhausted, networkUsageQueryKey, useBumpNetworkUsage, useInvalidateNetworkUsage, } from "./use-network-usage"; interface CreateParticleParams { // Path to which the new particle will be added as a child path: ParticlePath; type: T; properties: ParticlePropertiesMap[T]; createdByHumanId: string; } export function useCreateParticle() { const qc = useQueryClient(); const bumpUsage = useBumpNetworkUsage(); const invalidateUsage = useInvalidateNetworkUsage(); return useMutation({ // Compose UI renders a custom quota-exceeded toast + cancels the overlay. // Opt out of the global mutation error toast to avoid a double-toast. meta: { suppressToast: true }, mutationFn: async (params: CreateParticleParams) => { const { networkId } = parseParticlePath(params.path); // Containers aren't counted server-side, so we block them here if (!CONTAINER_TYPES.has(params.type)) { const cached = qc.getQueryData(networkUsageQueryKey(networkId)); if (isUsageExhausted(cached)) { throw new QuotaExceededError(networkId); } } const collectionPath = toFirestoreChildrenPath(params.path); const result = await createParticle( collectionPath, params.type, params.properties, params.createdByHumanId, ); if (!CONTAINER_TYPES.has(params.type)) { bumpUsage(networkId); void invalidateUsage(networkId); } return result; }, }); } type CreateStreamParticleParams = { networkId: string; properties: ParticlePropertiesMap["stream"]; createdByHumanId: string; visibleTo?: string[]; }; export function useCreateStreamParticle() { return useMutation({ mutationFn: async (params: CreateStreamParticleParams) => { const path = particlePath(params.networkId, []); const networkCollectionPath = toFirestoreChildrenPath(path); return await createStreamParticle( networkCollectionPath, params.properties, params.createdByHumanId, params.visibleTo, ); } }); }