UNPKG

@orfeas126/box-ui-elements

Version:
399 lines (396 loc) 15.8 kB
const _excluded = ["collaborationRestrictionWarning", "intl", "inviteButtonProps", "isEligibleForReferAFriendProgram", "itemName", "itemType", "submissionError", "submitting"]; function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import PropTypes from 'prop-types'; import React, { Component } from 'react'; import omit from 'lodash/omit'; import throttle from 'lodash/throttle'; import { FormattedMessage, injectIntl } from 'react-intl'; import { UpgradeBadge } from '../../components/badge'; import Button from '../../components/button'; import InlineNotice from '../../components/inline-notice'; import PrimaryButton from '../../components/primary-button'; import Select from '../../components/select'; import TextArea from '../../components/text-area'; import { Link } from '../../components/link'; import { Modal, ModalActions } from '../../components/modal'; import ContactDatalistItem from '../../components/contact-datalist-item'; import PillSelectorDropdown from '../../components/pill-selector-dropdown'; import parseEmails from '../../utils/parseEmails'; import { RESIN_TAG_TARGET } from '../../common/variables'; import PermissionFlyout from './PermissionFlyout'; import ReferAFriendAd from './ReferAFriendAd'; import messages from './messages'; import commonMessages from '../../common/messages'; import './InviteCollaboratorsModal.scss'; const COLLAB_ROLE_FOR_FILE = 'Editor'; const INPUT_DELAY = 250; /** * Returns true if the given value is a substring of the searchString * @param {String} value * @param {String} searchString * @return {boolean} */ const isSubstring = (value, searchString) => value && value.toLowerCase().indexOf(searchString.toLowerCase()) !== -1; class InviteCollaboratorsModal extends Component { constructor(props) { super(props); _defineProperty(this, "getSelectorOptions", () => { const { contacts } = this.props; const { pillSelectorInputValue, selectedOptions } = this.state; if (pillSelectorInputValue !== '') { return contacts.filter( // filter contacts whose name or email don't match input value ({ name, email }) => isSubstring(name, pillSelectorInputValue) || isSubstring(email, pillSelectorInputValue)).filter( // filter contacts who have already been selected ({ email, id }) => !selectedOptions.find(({ value }) => value === email || value === id)).map(({ email, id, name, type }) => ({ // map to standardized DatalistItem format // TODO: refactor this so inline conversions aren't required at every usage email, id, text: name, type, value: email || id // if email doesn't exist, contact is a group, use id })); } // return empty selector options if input value is empty return []; }); _defineProperty(this, "closeModal", () => { this.setState({ pillSelectorError: '', pillSelectorInputValue: '', selectedOptions: [] }); this.props.onRequestClose(); }); _defineProperty(this, "sendInvites", () => { const { intl, sendInvites } = this.props; const { message, permission, pillSelectorError, selectedOptions } = this.state; if (pillSelectorError) { // Block submission if there's a validation error return; } if (selectedOptions.length === 0) { // Block submission if no pills are selected this.setState({ pillSelectorError: intl.formatMessage(commonMessages.requiredFieldError) }); return; } const emails = []; const groupIDs = []; selectedOptions.forEach(({ type, value }) => { if (type === 'group') { groupIDs.push(value); } else { emails.push(value); } }); const params = { emails: emails.join(','), groupIDs: groupIDs.join(','), emailMessage: message, permission: permission || COLLAB_ROLE_FOR_FILE, numsOfInvitees: emails.length, numOfInviteeGroups: groupIDs.length }; sendInvites(params).catch(error => { // Remove invited emails from selected pills const invitedEmails = error.invitedEmails || []; this.filterInvitedEmails(invitedEmails); }); }); _defineProperty(this, "filterInvitedEmails", invitedEmails => { this.setState({ selectedOptions: this.state.selectedOptions.filter(({ value }) => !invitedEmails.includes(value)) }); }); _defineProperty(this, "handlePillSelectorInput", throttle(value => { const { onUserInput } = this.props; if (onUserInput) { onUserInput(value); } // As user is typing, reset error this.setState({ pillSelectorError: '', pillSelectorInputValue: value }); }, INPUT_DELAY)); _defineProperty(this, "handlePillSelect", pills => { this.setState({ selectedOptions: [...this.state.selectedOptions, ...pills] }); }); _defineProperty(this, "handlePillRemove", (option, index) => { const selectedOptions = this.state.selectedOptions.slice(); selectedOptions.splice(index, 1); this.setState({ selectedOptions }); }); _defineProperty(this, "validateForError", text => { const { intl } = this.props; let pillSelectorError = ''; if (text && !this.validator(text)) { pillSelectorError = intl.formatMessage(commonMessages.invalidEmailError); } this.setState({ pillSelectorError }); }); _defineProperty(this, "validator", text => { // email input validation const pattern = /^[^\s<>@,]+@[^\s<>@,/\\]+\.[^\s<>@,]+$/i; return pattern.test(text); }); _defineProperty(this, "handlePermissionChange", ({ target }) => { const { value } = target; this.setState({ permission: value }); }); _defineProperty(this, "handleMessageChange", ({ target }) => { const { value } = target; this.setState({ message: value }); }); const { defaultPersonalMessage, inviteePermissions } = props; this.state = { message: defaultPersonalMessage || '', permission: inviteePermissions ? inviteePermissions[0].value : COLLAB_ROLE_FOR_FILE, pillSelectorError: '', pillSelectorInputValue: '', selectedOptions: [] }; } renderFileCollabComponents() { return /*#__PURE__*/React.createElement("div", { className: "invite-file-editors" }, /*#__PURE__*/React.createElement(FormattedMessage, messages.inviteFileEditorsLabel)); } renderPermissionsSection() { const { inviteePermissions } = this.props; return /*#__PURE__*/React.createElement("div", { className: "invite-permissions-container" }, /*#__PURE__*/React.createElement(Select, { className: "select-container-medium", "data-resin-target": "selectpermission", label: /*#__PURE__*/React.createElement(FormattedMessage, messages.inviteePermissionsFieldLabel), name: "invite-permission", onChange: this.handlePermissionChange }, inviteePermissions.map(({ value, disabled = false, text }) => /*#__PURE__*/React.createElement("option", { key: value, "data-resin-option": value, disabled: disabled, value: value }, text))), /*#__PURE__*/React.createElement(PermissionFlyout, null)); } renderFolderCollabComponents() { const { defaultPersonalMessage, inviteePermissions, showUpgradeOptions } = this.props; return /*#__PURE__*/React.createElement("div", null, inviteePermissions && this.renderPermissionsSection(), showUpgradeOptions && /*#__PURE__*/React.createElement(Link, { className: "upgrade-link", href: "/upgrade" }, /*#__PURE__*/React.createElement(UpgradeBadge, null), /*#__PURE__*/React.createElement(FormattedMessage, messages.upgradeGetMoreAccessControls)), defaultPersonalMessage && /*#__PURE__*/React.createElement(TextArea, { cols: "30", "data-resin-feature": "personalmessage", "data-resin-target": "message", defaultValue: defaultPersonalMessage, label: /*#__PURE__*/React.createElement(FormattedMessage, messages.personalMessageLabel), name: "collab-message", onChange: this.handleMessageChange, rows: "4" })); } render() { const _this$props = this.props, { collaborationRestrictionWarning, intl, inviteButtonProps, isEligibleForReferAFriendProgram, itemName, itemType, submissionError, submitting } = _this$props, rest = _objectWithoutProperties(_this$props, _excluded); const { pillSelectorError, selectedOptions } = this.state; const modalProps = omit(rest, ['contacts', 'defaultPersonalMessage', 'inviteePermissions', 'itemTypedID', 'onRequestClose', 'onUserInput', 'sendInvites', 'showUpgradeOptions']); const selectorOptions = this.getSelectorOptions(); const title = /*#__PURE__*/React.createElement(FormattedMessage, _extends({}, messages.inviteCollaboratorsModalTitle, { values: { itemName } })); const groupLabel = /*#__PURE__*/React.createElement(FormattedMessage, messages.groupLabel); return /*#__PURE__*/React.createElement(Modal, _extends({ className: "invite-collaborators-modal", closeButtonProps: { [RESIN_TAG_TARGET]: 'close' }, "data-resin-component": "modal", "data-resin-feature": "invitecollaborators", onRequestClose: this.closeModal, title: title }, modalProps), submissionError && /*#__PURE__*/React.createElement(InlineNotice, { type: "error" }, submissionError), collaborationRestrictionWarning && /*#__PURE__*/React.createElement(InlineNotice, { type: "warning" }, collaborationRestrictionWarning), /*#__PURE__*/React.createElement(PillSelectorDropdown, { allowCustomPills: true, error: pillSelectorError, label: /*#__PURE__*/React.createElement(FormattedMessage, messages.inviteFieldLabel), onInput: this.handlePillSelectorInput, onRemove: this.handlePillRemove, onSelect: this.handlePillSelect, parseItems: parseEmails, placeholder: intl.formatMessage(commonMessages.pillSelectorPlaceholder), selectedOptions: selectedOptions, selectorOptions: selectorOptions, validateForError: this.validateForError, validator: this.validator }, selectorOptions.map(({ email, text, value }) => /*#__PURE__*/React.createElement(ContactDatalistItem, { key: value, name: text, subtitle: email || groupLabel }))), itemType === 'file' ? this.renderFileCollabComponents() : this.renderFolderCollabComponents(), isEligibleForReferAFriendProgram && /*#__PURE__*/React.createElement(ReferAFriendAd, null), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(Button, { "data-resin-target": "cancel", isDisabled: submitting, onClick: this.closeModal, type: "button" }, /*#__PURE__*/React.createElement(FormattedMessage, messages.inviteCollaboratorsModalCancelButton)), /*#__PURE__*/React.createElement(PrimaryButton, _extends({}, inviteButtonProps, { isDisabled: submitting, isLoading: submitting, onClick: this.sendInvites }), /*#__PURE__*/React.createElement(FormattedMessage, messages.inviteCollaboratorsModalSendInvitesButton)))); } } _defineProperty(InviteCollaboratorsModal, "propTypes", { /** Message warning about restrictions regarding inviting collaborators to the item */ collaborationRestrictionWarning: PropTypes.node, /** An array of contacts for the pill selector dropdown */ contacts: PropTypes.arrayOf(PropTypes.shape({ email: PropTypes.string, id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isrequired, name: PropTypes.string.isRequired, type: PropTypes.string.isRequired })).isRequired, /** * Default personal message for inviting collaborators to the item. * Do not include if no personal message textarea should show up. * Only applicable to non-file item types. * */ defaultPersonalMessage: PropTypes.node, intl: PropTypes.any, /** Props for the invite button */ inviteButtonProps: PropTypes.object, /** An array of invitee permissions */ inviteePermissions: PropTypes.arrayOf(PropTypes.shape({ disabled: PropTypes.bool, text: PropTypes.string.isRequired, value: PropTypes.string.isRequired })), /** If true, will render a link to the refer-a-friend reward center */ isEligibleForReferAFriendProgram: PropTypes.bool, /** The name of the item to invite collaborators for */ itemName: PropTypes.string.isRequired, /** The type of the item to invite collaborators for (e.g. "file", "folder") */ itemType: PropTypes.string.isRequired, /** The typed id of the item to invite collaborators for */ itemTypedID: PropTypes.string.isRequired, /** Handler function for closing the modal */ onRequestClose: PropTypes.func.isRequired, /** Handler function whenever the user types, e.g. to fetch contacts. */ onUserInput: PropTypes.func, /** * Function to send collab invitations based on the given parameters object. * This function should return a Promise. */ sendInvites: PropTypes.func.isRequired, /** * Flag to show link to upgrade and get more access controls. * Only applicable to non-file item types. */ showUpgradeOptions: PropTypes.bool, /** Message indicating an error occurred while sending the invites. */ submissionError: PropTypes.node, /** * Flag indicating whether the send invites request is submitting. */ submitting: PropTypes.bool }); _defineProperty(InviteCollaboratorsModal, "defaultProps", { inviteButtonProps: {} }); export { InviteCollaboratorsModal as InviteCollaboratorsModalBase }; export default injectIntl(InviteCollaboratorsModal); //# sourceMappingURL=InviteCollaboratorsModal.js.map