From 4c3728a20fcf2b51d4d3d19a370ebc90cd6eaf13 Mon Sep 17 00:00:00 2001 From: infiinte-persistence Date: Fri, 14 Aug 2020 03:06:43 +0800 Subject: [PATCH] Add "Publish Preview" modal --- ui/constants/modal_types.js | 1 + ui/modal/modalPublishPreview/index.js | 19 ++++ ui/modal/modalPublishPreview/view.jsx | 157 ++++++++++++++++++++++++++ ui/modal/modalRouter/view.jsx | 3 + ui/scss/component/_media.scss | 8 ++ ui/scss/component/_table.scss | 26 +++++ 6 files changed, 214 insertions(+) create mode 100644 ui/modal/modalPublishPreview/index.js create mode 100644 ui/modal/modalPublishPreview/view.jsx diff --git a/ui/constants/modal_types.js b/ui/constants/modal_types.js index 517580aa3..709f17b21 100644 --- a/ui/constants/modal_types.js +++ b/ui/constants/modal_types.js @@ -22,6 +22,7 @@ export const SEND_TIP = 'send_tip'; export const CONFIRM_SEND_TIP = 'confirm_send_tip'; export const SOCIAL_SHARE = 'social_share'; export const PUBLISH = 'publish'; +export const PUBLISH_PREVIEW = 'publish_preview'; export const SEARCH = 'search'; export const CONFIRM_TRANSACTION = 'confirm_transaction'; export const CONFIRM_THUMBNAIL_UPLOAD = 'confirm_thumbnail_upload'; diff --git a/ui/modal/modalPublishPreview/index.js b/ui/modal/modalPublishPreview/index.js new file mode 100644 index 000000000..68cd22599 --- /dev/null +++ b/ui/modal/modalPublishPreview/index.js @@ -0,0 +1,19 @@ +import { connect } from 'react-redux'; +import { doHideModal } from 'redux/actions/app'; +import ModalPublishPreview from './view'; +import { makeSelectPublishFormValue, selectPublishFormValues } from 'lbry-redux'; +import { selectFfmpegStatus } from 'redux/selectors/settings'; +import { doPublishDesktop } from 'redux/actions/publish'; + +const select = state => ({ + ...selectPublishFormValues(state), + isVid: makeSelectPublishFormValue('fileVid')(state), + ffmpegStatus: selectFfmpegStatus(state), +}); + +const perform = dispatch => ({ + publish: (filePath, preview) => dispatch(doPublishDesktop(filePath, preview)), + closeModal: () => dispatch(doHideModal()), +}); + +export default connect(select, perform)(ModalPublishPreview); diff --git a/ui/modal/modalPublishPreview/view.jsx b/ui/modal/modalPublishPreview/view.jsx new file mode 100644 index 000000000..f90f0b901 --- /dev/null +++ b/ui/modal/modalPublishPreview/view.jsx @@ -0,0 +1,157 @@ +// @flow +import React from 'react'; +import Button from 'component/button'; +import { Form } from 'component/common/form'; +import { Modal } from 'modal/modal'; +import Card from 'component/common/card'; +import Tag from 'component/tag'; +import MarkdownPreview from 'component/common/markdown-preview'; +import { COPYRIGHT, OTHER } from 'constants/licenses'; + +type Props = { + filePath: string | WebFile, + optimize: boolean, + title: ?string, + description: ?string, + channel: ?string, + bid: ?number, + uri: ?string, + contentIsFree: boolean, + fee: { + amount: string, + currency: string, + }, + language: string, + licenseType: string, + otherLicenseDescription: ?string, + licenseUrl: ?string, + tags: Array, + isVid: boolean, + ffmpegStatus: any, + previewResponse: PublishResponse, + publish: (?string, ?boolean) => void, + closeModal: () => void, +}; + +class ModalPublishPreview extends React.PureComponent { + onConfirmed() { + const { filePath, publish, closeModal } = this.props; + // Publish for real: + publish(this.resolveFilePathName(filePath), false); + closeModal(); + } + + resolveFilePathName(filePath: string | WebFile) { + if (typeof filePath === 'string') { + return filePath; + } else { + return filePath.name; + } + } + + createRow(label: string, value: any) { + return ( + + {label} + {value} + + ); + } + + render() { + const { + filePath, + optimize, + title, + description, + channel, + bid, + uri, + contentIsFree, + fee, + language, + licenseType, + otherLicenseDescription, + licenseUrl, + tags, + isVid, + ffmpegStatus = {}, + previewResponse, + closeModal, + } = this.props; + + const modalTitle = __('Confirm Publish'); + const txFee = previewResponse ? previewResponse['total_fee'] : null; + const isOptimizeAvail = filePath && filePath !== '' && isVid && ffmpegStatus.available; + + const descriptionValue = description ? ( +
+ +
+ ) : null; + + const licenseValue = + licenseType === COPYRIGHT ? ( +

© {otherLicenseDescription}

+ ) : licenseType === OTHER ? ( +

+ {otherLicenseDescription} +
+ {licenseUrl} +

+ ) : ( +

{licenseType}

+ ); + + const tagsValue = + // Do nothing for onClick(). Setting to 'null' results in "View Tag" action -- we don't want to leave the modal. + tags.map(tag => {}} />); + + return ( + +
this.onConfirmed()}> + +
+ + + {this.createRow(__('File'), this.resolveFilePathName(filePath))} + {isOptimizeAvail && this.createRow(__('Transcode'), optimize ? __('Yes') : __('No'))} + {this.createRow(__('Title'), title)} + {this.createRow(__('Description'), descriptionValue)} + {this.createRow(__('Channel'), channel)} + {this.createRow(__('URL'), uri)} + {this.createRow(__('Deposit'), bid ? `${bid} LBC` : '---')} + {this.createRow(__('Price'), contentIsFree ? __('Free') : `${fee.amount} ${fee.currency}`)} + {this.createRow(__('Language'), language)} + {this.createRow(__('License'), licenseValue)} + {this.createRow(__('Tags'), tagsValue)} + +
+
+ {txFee && ( +
+ {__('Est. transaction fee:')}  {txFee} LBC +
+ )} + + } + actions={ + <> +
+
+

{__('Once the transaction is sent, it cannot be reversed.')}

+ + } + /> + +
+ ); + } +} + +export default ModalPublishPreview; diff --git a/ui/modal/modalRouter/view.jsx b/ui/modal/modalRouter/view.jsx index 727f648eb..1bcf7c05d 100644 --- a/ui/modal/modalRouter/view.jsx +++ b/ui/modal/modalRouter/view.jsx @@ -20,6 +20,7 @@ import ModalRemoveBlocked from 'modal/modalRemoveBlocked'; import ModalSocialShare from 'modal/modalSocialShare'; import ModalSendTip from 'modal/modalSendTip'; import ModalPublish from 'modal/modalPublish'; +import ModalPublishPreview from 'modal/modalPublishPreview'; import ModalOpenExternalResource from 'modal/modalOpenExternalResource'; import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload'; import ModalWalletEncrypt from 'modal/modalWalletEncrypt'; @@ -99,6 +100,8 @@ function ModalRouter(props: Props) { return ; case MODALS.PUBLISH: return ; + case MODALS.PUBLISH_PREVIEW: + return ; case MODALS.CONFIRM_EXTERNAL_RESOURCE: return ; case MODALS.CONFIRM_TRANSACTION: diff --git a/ui/scss/component/_media.scss b/ui/scss/component/_media.scss index cba4721bd..f2e3cc076 100644 --- a/ui/scss/component/_media.scss +++ b/ui/scss/component/_media.scss @@ -119,6 +119,14 @@ margin-top: var(--spacing-s); } +.media__info-text-preview { + @extend .media__info-text; + + max-height: 5rem; + overflow: auto; + padding: var(--spacing-xxs) 0; // for scrollbar to auto-hide +} + .media__actions { display: flex; flex-wrap: wrap; diff --git a/ui/scss/component/_table.scss b/ui/scss/component/_table.scss index 30e8e5475..c1def458b 100644 --- a/ui/scss/component/_table.scss +++ b/ui/scss/component/_table.scss @@ -209,3 +209,29 @@ th { margin-left: var(--spacing-m); } } + +.table--publish-preview { + line-height: 1.1; + table-layout: fixed; + + th, + td { + padding: 0.4rem 1rem; + } + + // Column-1: "Label" + td:nth-of-type(1) { + font-weight: bold; + // The "value" is more important on smaller screens, so we truncate the "label". + width: 30%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + // Column-2: "Value" + td:nth-of-type(2) { + white-space: normal; + max-width: 70%; + } +}