UNPKG

sanity-plugin-media

Version:

This version of `sanity-plugin-media` is for Sanity Studio V3.

127 lines (108 loc) 4.17 kB
import type {MutationEvent, SanityClient} from '@sanity/client' import groq from 'groq' import {useEffect} from 'react' import {useDispatch, useSelector} from 'react-redux' import type {AssetSourceComponentProps} from 'sanity' import type {Dispatch} from 'redux' import {inputs} from '../../config/searchFacets' import {TAG_DOCUMENT_NAME} from '../../constants' import {searchActions} from '../../modules/search' import {tagsActions} from '../../modules/tags' import type {RootReducerState} from '../../modules/types' import type {Asset, Tag} from '../../types' import {assetsActions} from '../../modules/assets' function getMediaTagNames(schemaType?: AssetSourceComponentProps['schemaType']): string[] { const mediaTags = (schemaType?.options as {mediaTags?: string[]} | undefined)?.mediaTags if (!mediaTags?.length) return [] const unique = new Set( mediaTags.map(t => t?.trim()).filter((t): t is string => Boolean(t?.length)) ) return Array.from(unique) } function createAssetHandler(dispatch: Dispatch) { return (update: MutationEvent) => { const {documentId, result, transition} = update switch (transition) { case 'appear': dispatch(assetsActions.listenerCreateQueue({asset: result as Asset})) break case 'disappear': dispatch(assetsActions.listenerDeleteQueue({assetId: documentId})) break case 'update': dispatch(assetsActions.listenerUpdateQueue({asset: result as Asset})) break default: break } } } function createTagHandler(dispatch: Dispatch) { return (update: MutationEvent) => { const {documentId, result, transition} = update switch (transition) { case 'appear': dispatch(tagsActions.listenerCreateQueue({tag: result as Tag})) break case 'disappear': dispatch(tagsActions.listenerDeleteQueue({tagId: documentId})) break case 'update': dispatch(tagsActions.listenerUpdateQueue({tag: result as Tag})) break default: break } } } export function useBrowserInit( client: SanityClient, schemaType?: AssetSourceComponentProps['schemaType'] ): void { const dispatch = useDispatch() const tagsByIds = useSelector((state: RootReducerState) => state.tags.byIds) const tagsFetchCount = useSelector((state: RootReducerState) => state.tags.fetchCount) const tagNames = getMediaTagNames(schemaType) const hasMediaTags = tagNames.length > 0 useEffect(() => { if (!hasMediaTags) { dispatch(searchActions.facetsClear()) } dispatch(tagsActions.fetchRequest()) const assetSubscription = client .listen( groq`*[_type in ["sanity.fileAsset", "sanity.imageAsset"] && !(_id in path("drafts.**"))]` ) .subscribe(createAssetHandler(dispatch)) const tagSubscription = client .listen(groq`*[_type == "${TAG_DOCUMENT_NAME}" && !(_id in path("drafts.**"))]`) .subscribe(createTagHandler(dispatch)) return () => { assetSubscription.unsubscribe() tagSubscription.unsubscribe() } }, [client, dispatch, hasMediaTags]) // When mediaTags are configured, wait for the tag fetch to complete then apply facets. // Dispatching clear + add synchronously keeps all actions within assetsSearchEpic's // 400ms debounce window, so the browser performs exactly one asset fetch on open. useEffect(() => { if (!hasMediaTags || tagsFetchCount < 0) return const tagFacetInput = inputs.tag if (tagFacetInput.type !== 'searchable') return const resolvedTags = tagNames .map(name => Object.values(tagsByIds).find(item => item.tag.name.current === name)) .filter((item): item is NonNullable<typeof item> => Boolean(item)) dispatch(searchActions.facetsClear()) for (const tagItem of resolvedTags) { dispatch( searchActions.facetsAdd({ facet: { ...tagFacetInput, operatorType: 'references', value: {label: tagItem.tag.name.current, value: tagItem.tag._id} } }) ) } }, [tagsFetchCount, hasMediaTags]) // eslint-disable-line react-hooks/exhaustive-deps }