PnP React Controls Part 6 – Animated Dialog

Introduction

Hi friends, this is part 6 where I will explain the usage of the PnP Animated Dialog control. We will see how we can leverage this control on our SPFx projects and make use of the feature provided by this control. Thanks to the community.

About the control

Most of us knows Dialog control helps us to display the contents that need confirmation or show information without have to redirect to a new page. Animated Dialog control is nothing but the same dialog control inherited from the default based dialog but we can add animation on top of the base dialog.

Focus on the Code

You can refer Part 1 post on the creation of the SPFx project and installing all the dependencies. In addition to the dependencies mentioned in that post you have to install @pnp/sp – v3.5.1. You should also do some changes to the project files to make the pnpjs version 3 to work on SPFx 1.14.0. Please follow this link to do the changes.

Created a web part named dialogsDemo. Below is the DialogsDemo.tsx file.

import * as React from 'react';
import styles from './DialogsDemo.module.scss';
import { IDialogsDemoProps } from './IDialogsDemoProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { PrimaryButton, Stack } from 'office-ui-fabric-react';
import AnimDialog from '../../../common/AnimDialog';
import { useState } from 'react';


const DialogsDemo: React.FC<IDialogsDemoProps> = (props) => {
    const {
        description,
        isDarkTheme,
        environmentMessage,
        hasTeamsContext,
        userDisplayName
    } = props;
    const [showAnimDialog, setShowAnimDialog] = useState<boolean>(false);
    const [animDialogScope, setAnimDialogScope] = useState<number>(0);
    const [disableButtons, setDisableButtons] = useState<boolean>(false);

    const _setDialogStatus = () => {
        setShowAnimDialog(!showAnimDialog);
        setDisableButtons(false);
    };

    const _showNormalAnimatedDialog = () => {
        setShowAnimDialog(true);
        setAnimDialogScope(0);
        setDisableButtons(true);
    };

    const _showCustomAnimatedDialog = () => {
        setShowAnimDialog(true);
        setAnimDialogScope(1);
        setDisableButtons(true);
    };

    const _showCustomAnimatedDialogWithIcon = () => {
        setShowAnimDialog(true);
        setAnimDialogScope(2);
        setDisableButtons(true);
    };

    return (
        <section className={`${styles.dialogsDemo} ${hasTeamsContext ? styles.teams : ''}`}>
            <AnimDialog showDialog={showAnimDialog} setDialogStatus={_setDialogStatus} scope={animDialogScope} />
            <Stack tokens={{ childrenGap: 10 }} horizontal>
                <Stack.Item>
                    <PrimaryButton text="Show Animated Dialog" onClick={_showNormalAnimatedDialog}></PrimaryButton>
                </Stack.Item>
                <Stack.Item>
                    <PrimaryButton text="Show Custom Animated Dialog" onClick={_showCustomAnimatedDialog}></PrimaryButton>
                </Stack.Item>
                <Stack.Item>
                    <PrimaryButton text="Show Animated Dialog with Icon" onClick={_showCustomAnimatedDialogWithIcon}></PrimaryButton>
                </Stack.Item>
            </Stack>
        </section>
    );
};

export default DialogsDemo;

Below are the updates done to the file.

  • Changed the class component to the react functional component
  • Created some state variables to store the show or hide dialog values.
  • Created 3 different methods to show some different dialogs
  • Created 3 different methods to the show the dialogs
    • Show Animated Dialog
    • Show Custom Animated Dialog
    • Show Animated Dialog with Icon
  • Created a common component named AnimDialog and below are the properties that are passed to the common component
    • showDialog – To show the dialog or not
    • setDialogStatus – To set the state of the dialog to the normal state when clicking the close button or cancelling the dialog.
    • scope – Numeric values to show different dialogs based on the button click.

Below is the code for the common component named AnimDialog.tsx

import * as React from 'react';
import styles from './AnimDialog.module.scss';
import { AnimatedDialog } from "@pnp/spfx-controls-react/lib/AnimatedDialog";
import { useState } from 'react';
import { DialogFooter, DialogType, IDialogContentProps } from 'office-ui-fabric-react/lib/Dialog';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { IModalProps } from 'office-ui-fabric-react/lib/Modal';


export interface IAnimDialogProps {
    showDialog: boolean;
    setDialogStatus: () => void;
    scope: number;
}

const AnimDialog: React.FC<IAnimDialogProps> = (props) => {
    const [showDialog, setShowDialog] = useState<boolean>(false);
    const [showSuccessDialog, setShowSuccessDialog] = useState<boolean>(false);
    const [showErrorDialog, setShowErrorDialog] = useState<boolean>(false);

    const animatedDialogContentProps: IDialogContentProps = {
        type: DialogType.normal,
        title: 'Animated Dialog',
        subText: 'Do you like the animated dialog?',
    };

    const successDialogContentProps: IDialogContentProps = {
        type: DialogType.normal,
        title: 'Good answer!'
    };

    const errorDialogContentProps: IDialogContentProps = {
        type: DialogType.normal,
        title: 'Wrong answer!'
    };

    const animatedModalProps: IModalProps = {
        isDarkOverlay: true,
        isBlocking: true
    };

    const _hideDialog = () => {
        setShowDialog(false);
        props.setDialogStatus();
    };

    // The operation that does something - e.g. update data
    const timeout = (ms: number): Promise<void> => {
        return new Promise((resolve, reject) => setTimeout(resolve, ms));
    };

    const _onYesButtonClick = () => {
        _hideDialog();
        setShowSuccessDialog(true);
    };

    const _onNoButtonClick = () => {
        _hideDialog();
        setShowErrorDialog(true);
    };

    React.useEffect(() => {
        setShowDialog(props.showDialog);
    }, [props.showDialog]);

    return (
        <div className={styles.dialogContainer}>
            {props.scope == 0 &&
                <AnimatedDialog
                    hidden={!showDialog}
                    onDismiss={() => { _hideDialog(); }}
                    dialogContentProps={animatedDialogContentProps}
                    modalProps={animatedModalProps}
                >
                    <DialogFooter>
                        <PrimaryButton onClick={() => { _hideDialog(); }} text="Yes" />
                        <DefaultButton onClick={() => { _hideDialog(); }} text="No" />
                    </DialogFooter>
                </AnimatedDialog>
            }
            {props.scope == 1 &&
                <AnimatedDialog
                    hidden={!showDialog}
                    onDismiss={() => { _hideDialog(); }}
                    dialogContentProps={animatedDialogContentProps}
                    modalProps={animatedModalProps}
                    dialogAnimationInType='fadeInDown'
                    dialogAnimationOutType='fadeOutDown'
                >
                    <DialogFooter>
                        <PrimaryButton onClick={() => { _hideDialog(); }} text="Yes" />
                        <DefaultButton onClick={() => { _hideDialog(); }} text="No" />
                    </DialogFooter>
                </AnimatedDialog>
            }
            {props.scope == 2 &&
                <>
                    <AnimatedDialog
                        hidden={!showDialog}
                        onDismiss={() => { _hideDialog(); }}
                        dialogContentProps={animatedDialogContentProps}
                        modalProps={animatedModalProps}
                        iconName='UnknownSolid'
                        showAnimatedDialogFooter={true}
                        okButtonText="Yes"
                        cancelButtonText="No"
                        onOkClick={() => timeout(1500)}
                        onSuccess={() => _onYesButtonClick()}
                        onError={() => _onNoButtonClick()}
                    >
                    </AnimatedDialog>
                    <AnimatedDialog
                        hidden={!showSuccessDialog}
                        onDismiss={() => { setShowSuccessDialog(false); }}
                        dialogContentProps={successDialogContentProps}
                        modalProps={animatedModalProps}
                        iconName='CompletedSolid'
                        className={styles.dialogContainer}
                    >
                        <div className={styles.dialogContent}><span>Thank you.</span></div>
                        <div className={styles.resultDialogFooter}>
                            <PrimaryButton onClick={() => { setShowSuccessDialog(false); }} text="OK" >
                            </PrimaryButton>
                        </div>
                    </AnimatedDialog>
                    <AnimatedDialog
                        hidden={!showErrorDialog}
                        onDismiss={() => { setShowErrorDialog(false); }}
                        dialogContentProps={errorDialogContentProps}
                        modalProps={animatedModalProps}
                        iconName='StatusErrorFull'
                        className={styles.dialogContainer}
                    >
                        <div className={styles.dialogContent}><span>Try again!</span></div>
                        <div className={styles.resultDialogFooter}>
                            <PrimaryButton onClick={() => { setShowErrorDialog(false); }} text="OK" >
                            </PrimaryButton>
                        </div>
                    </AnimatedDialog>
                </>
            }
        </div>
    );
};

export default AnimDialog
  • Import the AnimatedDialog component from the pnp controls
  • Created some state variables and couple of DialogContentProps for different dialogs.
  • Based on the scope, created different dialog control with different set of properties.

Reference URL

Animated Dialog – @pnp/spfx-controls-react

Sample Implementation

Conclussion

I hope you had learned something about one of the pnp control. There are lot to come in future.

Please free to post your comments and let me know if you want me to post article on any particular feature or plugins that relates to SharePoint. Thanks for your support.

sudharsank/pnpcontrols-demo: Demo project on different PnP React Controls. (github.com)

Happy Coding…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s