Skip to content

Instantly share code, notes, and snippets.

@ylastapis
Created November 18, 2019 15:30
Show Gist options
  • Save ylastapis/789d693960a8260af791746a8b7143a6 to your computer and use it in GitHub Desktop.
Save ylastapis/789d693960a8260af791746a8b7143a6 to your computer and use it in GitHub Desktop.
Add a Dialog confirmation to any action in any component in React, using Hooks & Context
import React from 'react';
import { Button } from '../../../components/UI/new/Button';
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import { ButtonsContainer } from '../../../components/UI/new/ButtonsContainer';
import { FormattedMessage } from 'react-intl';
export interface ConfirmationOptions {
title: string | React.ReactNode;
confirmLabel: string | React.ReactNode;
description: string | React.ReactNode;
}
interface ConfirmationDialogProps extends ConfirmationOptions {
open: boolean;
onSubmit: () => void;
onClose: () => void;
}
export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
open,
onSubmit,
onClose,
title,
confirmLabel,
description,
}) => {
return (
<Modal isOpen={open} toggle={onClose}>
<ModalHeader toggle={onClose}>{title}</ModalHeader>
<ModalBody className="description">
{description}
</ModalBody>
<ModalFooter>
<ButtonsContainer>
<Button
onClick={onClose}
color="secondary"
light={true}
autoFocus
>
<FormattedMessage id="global.cancel" />
</Button>
<Button
color="primary"
onClick={onSubmit}
>
{confirmLabel}
</Button>
</ButtonsContainer>
</ModalFooter>
</Modal>
);
};
import React from 'react';
import { ConfirmationDialog, ConfirmationOptions } from './ConfirmationDialog';
const ConfirmationServiceContext = React.createContext<{
openConfirmation: (options: ConfirmationOptions) => Promise<void>
}>({
openConfirmation: Promise.reject,
});
export const useConfirmation = () => React.useContext(ConfirmationServiceContext);
export const ConfirmationServiceProvider: React.FC = ({
children,
}) => {
const [confirmationState, setConfirmationState] = React.useState<ConfirmationOptions | null>(null);
const awaitingPromiseRef = React.useRef<{
resolve: () => void;
reject: () => void;
}>();
const openConfirmation = (options: ConfirmationOptions) => {
setConfirmationState(options);
return new Promise<void>((resolve, reject) => {
awaitingPromiseRef.current = { resolve, reject };
});
};
const handleClose = () => {
setConfirmationState(null);
};
const handleSubmit = () => {
if (awaitingPromiseRef.current) {
awaitingPromiseRef.current.resolve();
}
setConfirmationState(null);
};
return (
<>
<ConfirmationServiceContext.Provider
value={{ openConfirmation }}
children={children}
/>
<ConfirmationDialog
open={Boolean(confirmationState)}
onSubmit={handleSubmit}
onClose={handleClose}
{...confirmationState!}
/>
</>
);
};
import { ConfirmationServiceProvider, useConfirmation } from '../Dialog/ConfirmationService';
export const someFC = () => (
<>
<ConfirmationServiceProvider>
<ComponentRequiringConfimationPopin />
</ConfirmationServiceProvider>
</>
);
export const ComponentRequiringConfimationPopin = () => {
const { openConfirmation } = useConfirmation();
const doYourStuffOnConfirm = useCallback(() => {
console.log('confirmed');
}, [])
const confirmRefuseSomething = useCallback(() => {
openConfirmation({
confirmLabel: "Confirm",
title: "Sure bro ?",
description: "You really know wwhat youa re doing ?",
})
.then(doYourStuffOnConfirm);
}, [openConfirmation, doRequest]);
return (
<Button
onClick={confirmRefuseSomething}
>
Refusable click
</Button>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment