import React, { useRef, useState, useEffect } from 'react'; import { CSSTransition } from 'react-transition-group'; import cn from 'classnames'; import { createPortal } from 'react-dom'; import { useWindowScroll } from 'react-use'; import { ViewTypes } from '@veeqo/ui/dist/components/View/types'; import useDropdown from 'hooks/useDropdown'; import Confirmation from './Confirmation'; import InfoPill from './Pills/Info'; import DarkPill from './Pills/Success/Dark'; import UnsavedChangesPill from './Pills/UnsavedChanges'; import EditDropdown from './EditDropdown'; import OptionsDropdown from './OptionsDropdown'; import { Container, View } from './styled'; import { Shared, ViewType, ViewClassNames, ViewHandlers, CommonViewPropTypes, } from '../types'; import { DEFAULT_CONTENT_WIDTH as DEFAULT_EDIT_DROPDOWN_CONTENT_WIDTH } from './EditDropdown/styled'; import { getOptionsDropdownWidth } from './OptionsDropdown/styled'; const DEFAULT_DROPDOWN_OFFSET = 24; const getDropdownStyle = ( referenceElementRect: DOMRect, dropdownWidth: number, scrollY: number, ): React.CSSProperties => { const isOutsideTheScreenOnRight = referenceElementRect.right > window.innerWidth; const isOutsideTheScreenOnLeft = referenceElementRect.left < 0; let { left } = referenceElementRect; if (isOutsideTheScreenOnRight) left = window.innerWidth - referenceElementRect.width - 40; // 72 is dropdown width if (isOutsideTheScreenOnLeft) left = 40 + 72; const isFitOnRight = ( window.innerWidth - (left + DEFAULT_DROPDOWN_OFFSET) > dropdownWidth ); return { position: 'absolute', top: referenceElementRect.bottom - 12 + scrollY, left: isFitOnRight ? left + DEFAULT_DROPDOWN_OFFSET : ( left - dropdownWidth + referenceElementRect.width - DEFAULT_DROPDOWN_OFFSET ), }; }; export type ViewElementPropsType = CommonViewPropTypes & ViewHandlers & { className?: string; e2eClassName?: string; view: ViewType; updateChunks: () => void; }; const generateClassNames = (prefix?: string): ViewClassNames => ({ view: prefix ? `${prefix}-view` : undefined, optionsDropdown: prefix ? `${prefix}-view-options-dropdown` : undefined, savedViewEditDropdown: prefix ? `${prefix}-saved-view-edit-dropdown` : undefined, draftViewEditDropdown: prefix ? `${prefix}-draft-view-edit-dropdown` : undefined, deleteConfirmation: prefix ? `${prefix}-delete-view-confirmation` : undefined, draftViewInfoPill: prefix ? `${prefix}-draft-view-info-pill` : undefined, successNotification: prefix ? `${prefix}-view-success-notification` : undefined, unsavedChangesPill: prefix ? `${prefix}-view-unsaved-changes-pill` : undefined, }); const ViewElement = ({ className, e2eClassName, view, activeViewKey, includedFilters, hasUnsavedChanges, pageName, onSave, onDelete, updateChunks, handleDuplicateView, handleChangeActiveView, handleDiscardUnsavedChanges, handleSaveToCurrentView, handleCreateCustomViewWithCurrentFilters, handleSetDefault, }: ViewElementPropsType) => { const classNames = generateClassNames(className); const e2eClassNames = generateClassNames(e2eClassName); const { shouldShowDropdown, toggleShouldShowDropdown, setShouldShowDropdown } = useDropdown(); const [shouldShowDeleteConfirmation, setShouldShowDeleteConfirmation] = useState(false); const [shouldShowEditDropdown, setShouldShowEditDropdown] = useState(false); const [shouldShowCreateDropdown, setShouldShowCreateDropdown] = useState(false); const [successNotificationMessage, setSuccessNotificationMessage] = useState( null, ); const referenceElement = useRef(null); const referenceElementRect = referenceElement.current?.getBoundingClientRect(); const { y: scrollY } = useWindowScroll(); const [viewName, setViewName] = useState(view.label || ''); const [isShared, setIsShared] = useState(view.shared ? 'true' : 'false'); const [isDefault, setIsViewDefault] = useState(view.default); const isDraft = view.type === ViewTypes.draft; const isSaved = view.type === ViewTypes.saved; const isActive = view.key === activeViewKey; const handleCreate = (editable: boolean) => { updateChunks(); handleSetDefault(view.key, isDefault); onSave(view.key, viewName, editable, isShared === 'true'); setShouldShowCreateDropdown(false); setSuccessNotificationMessage(`'${viewName}' view created`); setTimeout(() => { setSuccessNotificationMessage(null); }, 5000); }; const handleSave = (editable: boolean) => { updateChunks(); handleSetDefault(view.key, isDefault); onSave(view.key, viewName, editable, isShared === 'true'); setShouldShowEditDropdown(false); setSuccessNotificationMessage(`'${viewName}' view updated`); setTimeout(() => { setSuccessNotificationMessage(null); }, 5000); }; const handleMakeDefaultView = () => { setIsViewDefault(true); handleSetDefault(view.key, true); setShouldShowDropdown(false); setSuccessNotificationMessage(`'${viewName}' is now your default view`); setTimeout(() => { setSuccessNotificationMessage(null); }, 5000); }; const handleDelete = () => { onDelete(view.key); if (shouldShowEditDropdown) setShouldShowEditDropdown(shouldShowEditDropdown); if (shouldShowDeleteConfirmation) setShouldShowDeleteConfirmation(false); }; useEffect(() => { setIsViewDefault(view.default); }, [view.default]); return ( <> (viewKey !== activeViewKey ? handleChangeActiveView(viewKey) : {})} onDelete={handleDelete} onEdit={toggleShouldShowDropdown} onOptions={toggleShouldShowDropdown} /> setShouldShowDeleteConfirmation(false)} onDelete={() => handleDelete()} /> setShouldShowCreateDropdown(true)} /> setSuccessNotificationMessage(null)} /> handleSaveToCurrentView(view.key, view.editable || true)} handleCreateCustomViewWithCurrentFilters={handleCreateCustomViewWithCurrentFilters} /> {shouldShowDropdown && createPortal(
setShouldShowDeleteConfirmation(true)} onDuplicate={() => handleDuplicateView(view.key)} onEdit={() => { setShouldShowDropdown(false); setShouldShowEditDropdown(true); }} handleCloseDropdown={() => ( shouldShowDeleteConfirmation ? {} : setShouldShowDropdown(false) )} />
, document.body, )} {shouldShowEditDropdown && createPortal(
setViewName(value)} onCloseDropdown={() => { setShouldShowEditDropdown(false); setViewName(view.label); setIsViewDefault(view.default); setIsShared(view.shared ? 'true' : 'false'); }} onSave={(editable) => handleSave(editable)} onDelete={() => setShouldShowDeleteConfirmation(true)} onSharingOptionChange={setIsShared} handleChangeIsDefault={setIsViewDefault} />
, document.body, )} {shouldShowCreateDropdown && createPortal(
{/* Reusing same dropdown for drafts as it looks the same with few minor tweaks in behavior */} setViewName(value)} onCloseDropdown={() => setShouldShowCreateDropdown(false)} onSave={(editable) => handleCreate(editable)} onDelete={() => setShouldShowDeleteConfirmation(true)} onSharingOptionChange={setIsShared} handleChangeIsDefault={setIsViewDefault} />
, document.body, )} ); }; export default ViewElement;