/** * WordPress dependencies */ import { useSelect } from '@wordpress/data'; import { store as coreStore, type GlobalStylesRevision, } from '@wordpress/core-data'; import { useContext, useMemo } from '@wordpress/element'; /** * Internal dependencies */ import { GlobalStylesContext } from '../context'; import type { Revision, User } from './types'; interface RawRevision extends Omit< Revision, 'author' > { author?: number; } interface Query { per_page?: number; page?: number; } interface UseGlobalStylesRevisionsParams { query?: Query; } interface UseGlobalStylesRevisionsReturn { revisions: Revision[]; hasUnsavedChanges: boolean; isLoading: boolean; revisionsCount: number; } const SITE_EDITOR_AUTHORS_QUERY = { per_page: -1, _fields: 'id,name,avatar_urls', context: 'view', capabilities: [ 'edit_theme_options' ], }; const DEFAULT_QUERY = { per_page: 100, page: 1 }; const EMPTY_ARRAY: [] = []; export default function useGlobalStylesRevisions( { query, }: UseGlobalStylesRevisionsParams = {} ): UseGlobalStylesRevisionsReturn { const { user: userConfig } = useContext( GlobalStylesContext ); const _query: Query = useMemo( () => ( { ...DEFAULT_QUERY, ...query } ), [ query ] ); const { authors, currentUser, isDirty, revisions, isLoadingGlobalStylesRevisions, revisionsCount, } = useSelect( ( select ) => { const { __experimentalGetDirtyEntityRecords, getCurrentUser, getUsers, getRevisions, __experimentalGetCurrentGlobalStylesId, getEntityRecord, isResolving, } = select( coreStore ); const dirtyEntityRecords = __experimentalGetDirtyEntityRecords() || []; const _currentUser = getCurrentUser(); const _isDirty = dirtyEntityRecords.length > 0; const globalStylesId = __experimentalGetCurrentGlobalStylesId(); const globalStyles = globalStylesId ? getEntityRecord< GlobalStylesRevision >( 'root', 'globalStyles', globalStylesId ) : undefined; const _revisionsCount: number = // @ts-expect-error - _links is not typed in GlobalStylesRevision globalStyles?._links?.[ 'version-history' ]?.[ 0 ]?.count ?? 0; // @ts-expect-error - getRevisions is not fully typed const globalStylesRevisions: RawRevision[] = globalStylesId ? getRevisions( 'root', 'globalStyles', globalStylesId, _query ) || EMPTY_ARRAY : EMPTY_ARRAY; // @ts-expect-error - getUsers is not fully typed const _authors: User[] = getUsers( SITE_EDITOR_AUTHORS_QUERY ) || EMPTY_ARRAY; const _isResolving = globalStylesId ? isResolving( 'getRevisions', [ 'root', 'globalStyles', globalStylesId, _query, ] ) : false; return { authors: _authors, currentUser: _currentUser, isDirty: _isDirty, revisions: globalStylesRevisions, isLoadingGlobalStylesRevisions: _isResolving, revisionsCount: _revisionsCount, }; }, [ _query ] ); return useMemo( (): UseGlobalStylesRevisionsReturn => { if ( ! authors.length || isLoadingGlobalStylesRevisions ) { return { revisions: EMPTY_ARRAY as Revision[], hasUnsavedChanges: isDirty, isLoading: true, revisionsCount, }; } // Adds author details to each revision. const _modifiedRevisions: Revision[] = revisions.map( ( revision ) => { return { ...revision, author: authors.find( ( author ) => author.id === revision.author ), }; } ); const fetchedRevisionsCount = revisions.length; if ( fetchedRevisionsCount ) { // Flags the most current saved revision. if ( _modifiedRevisions[ 0 ].id !== 'unsaved' && _query.page === 1 ) { _modifiedRevisions[ 0 ].isLatest = true; } // Adds an item for unsaved changes. if ( isDirty && userConfig && Object.keys( userConfig ).length > 0 && currentUser && _query.page === 1 ) { const unsavedRevision: Revision = { id: 'unsaved', styles: userConfig?.styles, settings: userConfig?.settings, _links: userConfig?._links, author: { name: currentUser?.name || '', // @ts-expect-error - avatar_urls is not typed in User avatar_urls: currentUser?.avatar_urls || {}, }, modified: new Date(), }; _modifiedRevisions.unshift( unsavedRevision ); } if ( _query.per_page && _query.page === Math.ceil( revisionsCount / _query.per_page ) ) { // Adds an item for the default theme styles. _modifiedRevisions.push( { id: 'parent', styles: {}, settings: {}, } ); } } return { revisions: _modifiedRevisions, hasUnsavedChanges: isDirty, isLoading: false, revisionsCount, }; }, [ isDirty, revisions, currentUser, authors, userConfig, isLoadingGlobalStylesRevisions, revisionsCount, _query.page, _query.per_page, ] ); }