import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { DialogBox } from '../dialogbox' import { Button } from '../inputs/button' import _ from 'lodash' import { StyledDialogBox } from './confirm-modal.styles' type TAnswer = { text: string; value: T } type TContext = { [key: string]: string | number } type TUseConfirmation = [(context?: TContext) => Promise, JSX.Element] interface IConfirmModalProps { message: string onResult: (value: TValue) => void buttons: TAnswer[] show: boolean } const ConfirmModal = >(props: IConfirmModalProps): JSX.Element => { function onClick(answer: TAnswer) { props.onResult.bind(null, answer.value) return undefined } return ( {props.message} {props.buttons.map((answer, index) => ( ))} ) } /** * useConfirmation can be used to show a confirmation dialog box * @param info - Info text to show * @param buttons - buttons, array: [{text: string, value: TValue}, ...] * @param resultCallback - Callback to be called on result * * @returns an array with [showFn: () => Promise, component], * where showFn is a function to be called to show the dialog box. It returns a * promise that resolves to the result value. * component is a component that must be rendered somewhere */ export const useConfirmation = >( info: string, buttons: TAnswer[], resultCallback?: (value: T) => void, ): TUseConfirmation => { const [template, setTemplate] = useState(info) const [context, setContext] = useState() const [showDialog, setShowDialog] = useState(false) const resolverRef = useRef<((value: T) => void) | null>(null) const callbackRef = useRef<((value: T) => void) | null>(null) const message = useMemo(() => { const compiled = _.template(template) try { return compiled(context) } catch { return 'invalid-template' } }, [template, context]) // Update message if modified useEffect(() => { setTemplate(info) }, [info]) // Update callback if modified useEffect(() => { callbackRef.current = resultCallback || null }, [resultCallback]) const handleResult = useCallback((result: T) => { setShowDialog(false) if (callbackRef.current) callbackRef.current(result) if (resolverRef.current) resolverRef.current(result) }, []) const showConfirmation = (context?: TContext): Promise => { const promise = new Promise(resolve => { resolverRef.current = resolve setContext(context) setShowDialog(true) }) return promise } const component = return [showConfirmation, component] }