vitess.io/vitess@v0.16.2/web/vtadmin/src/components/routes/tablets/InfoDialog.tsx (about)

     1  import React, { useEffect, useState } from 'react';
     2  import { Transition } from '@headlessui/react';
     3  import Dialog from '../../dialog/Dialog';
     4  import { Icon, Icons } from '../../Icon';
     5  import { UseQueryResult } from 'react-query';
     6  
     7  export interface BaseInfoDialogProps {
     8      loadingTitle?: string;
     9      loadingDescription: string;
    10      successTitle?: string;
    11      successDescription: string;
    12      errorTitle?: string;
    13      errorDescription: string;
    14      useHook: () => UseQueryResult<any, Error>;
    15  }
    16  
    17  interface InfoDialogProps extends BaseInfoDialogProps {
    18      isOpen: boolean;
    19      onClose: () => void;
    20  }
    21  
    22  const InfoDialog: React.FC<InfoDialogProps> = ({
    23      loadingTitle,
    24      loadingDescription,
    25      successTitle,
    26      successDescription,
    27      errorTitle,
    28      errorDescription,
    29      useHook,
    30      isOpen,
    31      onClose,
    32  }) => {
    33      const { data, error, isLoading, refetch } = useHook();
    34  
    35      // Animate loading briefly in case useHook is very fast
    36      // to give UX sense of work being done
    37      const [animationDone, setAnimationDone] = useState(false);
    38      useEffect(() => {
    39          let timeout: NodeJS.Timeout;
    40          if (isOpen) {
    41              timeout = setTimeout(() => {
    42                  refetch();
    43                  setAnimationDone(true);
    44              }, 300);
    45          }
    46          return () => timeout && clearTimeout(timeout);
    47          // eslint-disable-next-line react-hooks/exhaustive-deps
    48      }, [isOpen]);
    49  
    50      const loading = !animationDone || isLoading;
    51  
    52      const SuccessState: React.FC = () => (
    53          <div className="w-full flex flex-col justify-center items-center">
    54              <span className="flex h-12 w-12 relative items-center justify-center">
    55                  <Icon className="fill-current text-green-500" icon={Icons.checkSuccess} />
    56              </span>
    57              <div className="text-lg mt-3 font-bold">{successTitle || 'Success!'}</div>
    58              <div className="text-sm">{successDescription}</div>
    59          </div>
    60      );
    61  
    62      const FailState: React.FC = () => (
    63          <div className="w-full flex flex-col justify-center items-center">
    64              <span className="flex h-12 w-12 relative items-center justify-center">
    65                  <Icon className="fill-current text-red-500" icon={Icons.alertFail} />
    66              </span>
    67              <div className="text-lg mt-3 font-bold">{errorTitle || 'Error'}</div>
    68              <div className="text-sm">
    69                  {errorDescription}: {error?.message}
    70              </div>
    71          </div>
    72      );
    73  
    74      return (
    75          <Dialog
    76              isOpen={isOpen}
    77              onClose={() => {
    78                  setAnimationDone(false);
    79                  onClose();
    80              }}
    81              hideCancel={true}
    82              confirmText="Done"
    83          >
    84              <div>
    85                  <div className="flex justify-center items-center w-full h-40">
    86                      {loading && (
    87                          <Transition
    88                              className="absolute"
    89                              show={loading && isOpen}
    90                              leave="transition-opacity duration-100"
    91                              enter="transition-opacity duration-75"
    92                              enterFrom="opacity-0"
    93                              enterTo="opacity-100"
    94                              leaveFrom="opacity-100"
    95                              leaveTo="opacity-0"
    96                          >
    97                              <div className="w-full flex flex-col justify-center items-center">
    98                                  <span className="flex h-6 w-6 relative items-center justify-center">
    99                                      <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-yellow-400 opacity-75"></span>
   100                                      <span className="relative inline-flex rounded-full h-6 w-6 bg-yellow-500"></span>
   101                                  </span>
   102                                  <div className="text-lg mt-6 font-bold">{loadingTitle || 'Loading...'}</div>
   103                                  <div className="text-sm">{loadingDescription}</div>
   104                              </div>
   105                          </Transition>
   106                      )}
   107                      {!loading && (
   108                          <Transition
   109                              className="absolute"
   110                              show={!loading && isOpen}
   111                              enter="delay-100 transition-opacity duration-75"
   112                              enterFrom="opacity-0"
   113                              enterTo="opacity-100"
   114                          >
   115                              {data && <SuccessState />}
   116                              {error && <FailState />}
   117                          </Transition>
   118                      )}
   119                  </div>
   120              </div>
   121          </Dialog>
   122      );
   123  };
   124  
   125  export default InfoDialog;