import classnames from 'classnames' ; import { isUndefined } from 'lodash' ; import { MouseEvent as ReactMouseEvent , useContext , useRef , useState } from 'react' ; import { BsThreeDotsVertical } from 'react-icons/bs' ; import { FaPencilAlt , FaTrashAlt } from 'react-icons/fa' ; import { IoMdCloseCircle } from 'react-icons/io' ; import { TiWarningOutline } from 'react-icons/ti' ; import API from '../../../../api' ; import { AppCtx } from '../../../../context/AppCtx' ; import useOutsideClick from '../../../../hooks/useOutsideClick' ; import { ErrorKind , Webhook } from '../../../../types' ; import alertDispatcher from '../../../../utils/alertDispatcher' ; import ElementWithTooltip from '../../../common/ElementWithTooltip' ; import Modal from '../../../common/Modal' ; import styles from './Card.module.css' ; import LastNotificationsModal from './LastNotificationsModal' ; interface Props { webhook : Webhook ; onEdition : ( ) => void ; onDeletion : ( ) => void ; onAuthError : ( ) => void ; } const WebhookCard = ( props ) => { const { ctx } = useContext ( AppCtx ) ; const [ isDeleting , setIsDeleting ] = useState < boolean > ( false ) ; const [ dropdownMenuStatus , setDropdownMenuStatus ] = useState < boolean > ( false ) ; const dropdownMenu = useRef ( null ) ; const [ deletionModalStatus , setDeletionModalStatus ] = useState < boolean > ( false ) ; const closeDropdown = ( ) => { setDropdownMenuStatus ( false ) ; } ; useOutsideClick ( [ dropdownMenu ] , dropdownMenuStatus , closeDropdown ) ; async function deleteWebhook ( ) { try { setIsDeleting ( true ) ; await API . deleteWebhook ( props . webhook . webhookId ! , ctx . prefs . controlPanel . selectedOrg ) ; setIsDeleting ( false ) ; props . onDeletion ( ) ; } catch ( err ) { setIsDeleting ( false ) ; if ( err . kind === ErrorKind . Unauthorized ) { props . onAuthError ( ) ; } else { alertDispatcher . postAlert ( { type : 'danger' , message : 'An error occurred deleting the webhook, please try again later.' , } ) ; } } } return ( < div className = "col-12 col-xxl-6 py-sm-3 py-2 px-0 px-xxl-3" role = "listitem" > < div className = { `card cardWithHover w-100 h-100 mw-100 bg-white ${ styles . card }` } > < div className = "card-body position-relative" > < div className = "d-flex flex-row" > < div className = "h5 card-title mb-3 me-3 lh-1 text-break" > < div className = "d-flex flex-row align-items-start" > < div > { props . webhook . name } < /div> { props . webhook . active ? ( < span className = { `ms-3 mt-1 fw-bold badge rounded-pill border border-success text-success text-uppercase ${ styles . badge }` } > Active < /span>) : (<span className={`ms-3 mt-1 fw-bold badge rounded-pill border border-dark text-dark text-uppercase ${styles.badge} ${styles.inactiveBadge}`}> Inactive < /span>)} < /div> < /div> { deletionModalStatus && ( < Modal className = { `d-inline-block ${ styles . modal }` } closeButton = { < > < button className = "btn btn-sm btn-outline-secondary text-uppercase" onClick = { ( ) => setDeletionModalStatus ( false ) } aria - label = "Close deletion modal" > < div className = "d-flex flex-row align-items-center" > < IoMdCloseCircle className = "me-2" / > < span > Cancel < /span> < /div> < /button> < button className = "btn btn-sm btn-danger ms-3" onClick = { ( e ) => { e . preventDefault ( ) ; deleteWebhook ( ) ; } } disabled = { isDeleting } aria - label = "Delete webhook" > < div className = "d-flex flex-row align-items-center text-uppercase" > { isDeleting ? ( < > < span className = "spinner-grow spinner-grow-sm" role = "status" aria - hidden = "true" / > < span className = "ms-2" > Deleting ... < /span> < />) : (<> < FaTrashAlt className = { `me-2 ${ styles . btnDeleteIcon }` } /> < span > Delete < /span> < />)} < /div> < /button> < />} header={<div className={`h3 m-2 flex-grow-1 ${styles.title}`}>Delete webhook</div > } onClose = { ( ) => setDeletionModalStatus ( false ) } open > < div className = "mt-3 mw-100 text-center" > < p > Are you sure you want to delete this webhook ? < /p> < /div> < /Modal>)} < div className = "ms-auto" > < div ref = { dropdownMenu } className = { classnames ( 'dropdown-menu dropdown-menu-end p-0' , styles . dropdownMenu , { show : dropdownMenuStatus , } ) } > < div className = { `dropdown-arrow ${ styles . arrow }` } /> < button className = "dropdown-item btn btn-sm rounded-0 text-dark" onClick = { ( e ) => { e . preventDefault ( ) ; closeDropdown ( ) ; props . onEdition ( ) ; } } aria - label = "Edit webhook" > < div className = "d-flex flex-row align-items-center" > < FaPencilAlt className = { `me-2 ${ styles . btnIcon }` } /> < span > Edit < /span> < /div> < /button> < button className = "dropdown-item btn btn-sm rounded-0 text-dark" onClick = { ( e ) => { e . preventDefault ( ) ; closeDropdown ( ) ; setDeletionModalStatus ( true ) ; } } aria - label = "Open deletion webhook modal" > < div className = "d-flex flex-row align-items-center" > < FaTrashAlt className = { `me-2 ${ styles . btnIcon }` } /> < span > Delete < /span> < /div> < /button> < /div> < button className = { `btn btn-outline-secondary rounded-circle p-0 text-center  ${ styles . btnDropdown }` } onClick = { ( ) => setDropdownMenuStatus ( true ) } aria - label = "Open menu" aria - expanded = { dropdownMenuStatus } > < BsThreeDotsVertical /> < /button> < /div> < /div> < div className = "d-flex flex-column" > < div className = "card-subtitle d-flex flex-column mw-100 mt-1" > < p className = "card-text" > { props . webhook . description } < /p> < /div> < div className = "text-truncate" > < small className = "text-muted text-uppercase me-2" > Url : < /small> < small > { props . webhook . url } < /small> < /div> < div className = "d-flex flex-row justify-content-between align-items-baseline" > { props . webhook . lastNotifications && ( < div className = "d-none d-md-inline mt-2" > < LastNotificationsModal notifications = { props . webhook . lastNotifications } /> < /div>)} { ( isUndefined ( props . webhook . packages ) || props . webhook . packages . length === 0 ) && ( < div className = "ms-auto mt-2" > < ElementWithTooltip element = { < span className = { `d-flex flex-row align-items-center badge bg-warning rounded-pill ${ styles . badgeNoPackages }` } > < TiWarningOutline /> < span className = "ms-1" > No packages < /span> < /span>} tooltipMessage="This webhook is not associated to any packages." active visibleTooltip/ > < /div>)} < /div> < /div> < /div> < /div> < /div>); } ; export default WebhookCard ;