From 49fe4e2ccacb5bb68e44c1d230d4b279ef04ec09 Mon Sep 17 00:00:00 2001 From: gabriellsh <40830821+gabriellsh@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:30:38 -0300 Subject: [PATCH] [FIX] Modal keeps state if reset too fast. (#23791) * Remove subscription, queue updates * use key instead of queue * Fix types * little adjustments --- client/lib/imperativeModal.ts | 81 ++++-------------------- client/views/hooks/useImperativeModal.ts | 34 +++++----- 2 files changed, 29 insertions(+), 86 deletions(-) diff --git a/client/lib/imperativeModal.ts b/client/lib/imperativeModal.ts index 51a69aeab63..917049a942e 100644 --- a/client/lib/imperativeModal.ts +++ b/client/lib/imperativeModal.ts @@ -1,81 +1,28 @@ import { Emitter } from '@rocket.chat/emitter'; import { ComponentType } from 'react'; -import { Subscription, Unsubscribe } from 'use-subscription'; -type BlazeModalOptions = { - confirmButtonText?: string; - cancelButtonText?: string; - showCancelButton?: boolean; - confirmButtonColor?: string; - cancelButtonColor?: string; - - allowOutsideClick?: boolean; - confirmOnEnter?: boolean; - - closeOnConfirm?: boolean; - closeOnEscape?: boolean; - - type?: 'input'; - inputType?: 'text' | 'password'; - inputActionText?: string; - inputAction?: () => any; - inputPlaceholder?: string; - - modalIcon?: string; - - timer?: number; - dontAskAgain?: { - action: string; - label: string; - }; - - data?: Record; - content?: string; - template?: string; - - title?: string; - text?: string; - html?: boolean; +type ReactModalDescriptor = { + component: ComponentType; + props?: TProps; }; -type BlazeModalDescriptor = { - options: BlazeModalOptions; - confirmFn?: () => any; - cancelFn?: () => any; -}; - -type ReactModalDescriptor = { - component: ComponentType; - props?: Props; -}; - -type ModalDescriptor = BlazeModalDescriptor | ReactModalDescriptor | null; - -class ImperativeModalSubscription - extends Emitter<{ update: void }> - implements Subscription -{ - private descriptor: ModalDescriptor = null; - - getCurrentValue = (): ModalDescriptor => this.descriptor; - - subscribe = (callback: () => void): Unsubscribe => this.on('update', callback); +type ModalDescriptor = ReactModalDescriptor<{}> | null; - setCurrentValue(descriptor: ModalDescriptor): void { - this.descriptor = descriptor; - this.emit('update'); +class ImperativeModalEmmiter extends Emitter<{ update: ModalDescriptor }> { + update(descriptor: ModalDescriptor): void { + this.emit('update', descriptor); } - open: { - (descriptor: BlazeModalDescriptor): void; - (descriptor: ReactModalDescriptor): void; - } = (templateOrDescriptor: ModalDescriptor): void => { - this.setCurrentValue(templateOrDescriptor); + open = (descriptor: ReactModalDescriptor | null): void => { + // There are some TS shenanigans causing errors if this is not asserted + // Since this method is for internal use only, it's ok to use this here + // This will not affect prop types inference when using the method. + this.update(descriptor as ModalDescriptor); }; close = (): void => { - this.setCurrentValue(null); + this.update(null); }; } -export const imperativeModal = new ImperativeModalSubscription(); +export const imperativeModal = new ImperativeModalEmmiter(); diff --git a/client/views/hooks/useImperativeModal.ts b/client/views/hooks/useImperativeModal.ts index 9766ba0ce78..54dcbbe2fcd 100644 --- a/client/views/hooks/useImperativeModal.ts +++ b/client/views/hooks/useImperativeModal.ts @@ -1,26 +1,22 @@ import { createElement, useEffect, Dispatch, SetStateAction, ReactNode } from 'react'; -import { useSubscription } from 'use-subscription'; import { imperativeModal } from '../../lib/imperativeModal'; export const useImperativeModal = (setModal: Dispatch>): void => { - const descriptor = useSubscription(imperativeModal); - useEffect(() => { - if (descriptor === null) { - return setModal(null); - } - - // todo API to accept old modal props - // and return equivalent React modal - if ('options' in descriptor) { - return; // handleBlazeModal - } - - if ('component' in descriptor) { - return setModal(createElement(descriptor.component, descriptor.props)); - } - - throw new Error('invalid modal descriptor'); - }, [descriptor, setModal]); + const unsub = imperativeModal.on('update', (descriptor) => { + if (descriptor === null) { + return setModal(null); + } + if ('component' in descriptor) { + setModal( + createElement(descriptor.component, { + key: Math.random(), + ...descriptor.props, + }), + ); + } + }); + return unsub; + }, [setModal]); };