Merge branch 'scheduled-post-ui' into 'develop'
More scheduled post updates Closes #660 See merge request soapbox-pub/soapbox-fe!553
This commit is contained in:
commit
855c4bf6be
6 changed files with 113 additions and 40 deletions
|
@ -35,6 +35,7 @@ const messages = defineMessages({
|
|||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
|
||||
publish: { id: 'compose_form.publish', defaultMessage: 'Publish' },
|
||||
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
|
||||
schedule: { id: 'compose_form.schedule', defaultMessage: 'Schedule' },
|
||||
});
|
||||
|
||||
export default @injectIntl
|
||||
|
@ -262,6 +263,10 @@ class ComposeForm extends ImmutablePureComponent {
|
|||
publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
|
||||
}
|
||||
|
||||
if (this.props.scheduledAt) {
|
||||
publishText = intl.formatMessage(messages.schedule);
|
||||
}
|
||||
|
||||
const composeClassNames = classNames({
|
||||
'compose-form': true,
|
||||
'condensed': condensed,
|
||||
|
|
|
@ -3,25 +3,34 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import DatePicker from 'react-datepicker';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import { removeSchedule } from 'soapbox/actions/compose';
|
||||
|
||||
const messages = defineMessages({
|
||||
schedule: { id: 'schedule.post_time', defaultMessage: 'Post Date/Time' },
|
||||
remove: { id: 'schedule.remove', defaultMessage: 'Remove schedule' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
scheduledAt: state.getIn(['compose', 'schedule']),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class ScheduleForm extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
schedule: PropTypes.instanceOf(Date),
|
||||
scheduledAt: PropTypes.instanceOf(Date),
|
||||
intl: PropTypes.object.isRequired,
|
||||
onSchedule: PropTypes.func.isRequired,
|
||||
dispatch: PropTypes.func,
|
||||
active: PropTypes.bool,
|
||||
};
|
||||
|
||||
setSchedule(date) {
|
||||
this.setState({ schedule: date });
|
||||
setSchedule = date => {
|
||||
this.props.onSchedule(date);
|
||||
}
|
||||
|
||||
|
@ -33,16 +42,6 @@ class ScheduleForm extends React.Component {
|
|||
datePicker.setOpen(true);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ schedule: this.props.schedule });
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setSchedule = this.setSchedule.bind(this);
|
||||
}
|
||||
|
||||
isCurrentOrFutureDate(date) {
|
||||
return date && new Date().setHours(0, 0, 0, 0) <= new Date(date).setHours(0, 0, 0, 0);
|
||||
}
|
||||
|
@ -54,33 +53,42 @@ class ScheduleForm extends React.Component {
|
|||
return fiveMinutesFromNow.getTime() < selectedDate.getTime();
|
||||
};
|
||||
|
||||
handleRemove = e => {
|
||||
this.props.dispatch(removeSchedule());
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.active || !this.state) {
|
||||
if (!this.props.active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { schedule } = this.state;
|
||||
const { intl, scheduledAt } = this.props;
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
selected={schedule}
|
||||
showTimeSelect
|
||||
dateFormat='MMMM d, yyyy h:mm aa'
|
||||
timeIntervals={15}
|
||||
wrapperClassName='react-datepicker-wrapper'
|
||||
onChange={this.setSchedule}
|
||||
placeholderText={this.props.intl.formatMessage(messages.schedule)}
|
||||
filterDate={this.isCurrentOrFutureDate}
|
||||
filterTime={this.isFiveMinutesFromNow}
|
||||
ref={this.isCurrentOrFutureDate(schedule) ? null : this.openDatePicker}
|
||||
/>
|
||||
<div className='datepicker'>
|
||||
<div className='datepicker__hint'>
|
||||
<FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' />
|
||||
</div>
|
||||
<div className='datepicker__input'>
|
||||
<DatePicker
|
||||
selected={scheduledAt}
|
||||
showTimeSelect
|
||||
dateFormat='MMMM d, yyyy h:mm aa'
|
||||
timeIntervals={15}
|
||||
wrapperClassName='react-datepicker-wrapper'
|
||||
onChange={this.setSchedule}
|
||||
placeholderText={this.props.intl.formatMessage(messages.schedule)}
|
||||
filterDate={this.isCurrentOrFutureDate}
|
||||
filterTime={this.isFiveMinutesFromNow}
|
||||
ref={this.isCurrentOrFutureDate(scheduledAt) ? null : this.openDatePicker}
|
||||
/>
|
||||
<div className='datepicker__cancel'>
|
||||
<IconButton size={20} title={intl.formatMessage(messages.remove)} icon='times' onClick={this.handleRemove} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
schedule: state.getIn(['compose', 'schedule']),
|
||||
});
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(ScheduleForm));
|
||||
|
|
|
@ -26,7 +26,7 @@ const mapStateToProps = state => ({
|
|||
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
isModalOpen: state.get('modal').modalType === 'COMPOSE',
|
||||
maxTootChars: state.getIn(['instance', 'max_toot_chars']),
|
||||
schedule: state.getIn(['instance', 'schedule']),
|
||||
scheduledAt: state.getIn(['compose', 'schedule']),
|
||||
scheduledStatusCount: state.get('scheduled_statuses').size,
|
||||
});
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ const mapStateToProps = state => ({
|
|||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onClick() {
|
||||
dispatch((_, getState) => {
|
||||
dispatch((dispatch, getState) => {
|
||||
if (getState().getIn(['compose', 'schedule'])) {
|
||||
dispatch(removeSchedule());
|
||||
} else {
|
||||
|
|
|
@ -51,7 +51,7 @@ class ScheduledStatuses extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.scheduled_statuses' defaultMessage="You don't have any scheduled statuses yet. When you add one, it will show up here." />;
|
||||
|
||||
return (
|
||||
<Column icon='edit' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
||||
<Column icon='calendar' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
||||
<ScrollableList
|
||||
scrollKey='scheduled_statuses'
|
||||
emptyMessage={emptyMessage}
|
||||
|
|
|
@ -1,4 +1,28 @@
|
|||
.ui .react-datepicker {
|
||||
.datepicker {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 10px 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid var(--foreground-color);
|
||||
|
||||
&__hint {
|
||||
font-style: italic;
|
||||
color: var(--primary-text-color--faint);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__cancel {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker .react-datepicker {
|
||||
box-shadow: 0 0 6px 0 rgb(0 0 0 / 30%);
|
||||
font-size: 12px;
|
||||
border: 0;
|
||||
|
@ -7,9 +31,45 @@
|
|||
color: var(--primary-text-color);
|
||||
|
||||
&-wrapper {
|
||||
margin-left: 10px;
|
||||
background: var(--foreground-color);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__input-container {
|
||||
border: 2px solid var(--brand-color);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
background: var(--background-color);
|
||||
color: var(--primary-text-color);
|
||||
padding: 10px;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
resize: vertical;
|
||||
outline: 0;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '\f073';
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 ForkAwesome;
|
||||
font-size: 14px;
|
||||
color: var(--primary-text-color--faint);
|
||||
}
|
||||
}
|
||||
|
||||
&__current-month,
|
||||
|
|
Loading…
Reference in a new issue