mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-21 22:27:11 +00:00
Post scheduling (#2693)
* Post scheduling Adds simple input for scheduling a post x minutes in the future. Do you want to pull in a date picker library for this? See https://github.com/LemmyNet/lemmy/pull/5025 * lint * add date picker * Adding i18n, and fixing some fields (#2694) * fix edits * cleanup --------- Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
parent
6b5da8cfb1
commit
8b7a4e72af
|
@ -48,6 +48,11 @@ import { isBrowser } from "@utils/browser";
|
||||||
import isMagnetLink, {
|
import isMagnetLink, {
|
||||||
extractMagnetLinkDownloadName,
|
extractMagnetLinkDownloadName,
|
||||||
} from "@utils/media/is-magnet-link";
|
} from "@utils/media/is-magnet-link";
|
||||||
|
import {
|
||||||
|
getUnixTimeLemmy,
|
||||||
|
getUnixTime,
|
||||||
|
unixTimeToLocalDateStr,
|
||||||
|
} from "@utils/helpers/get-unix-time";
|
||||||
|
|
||||||
const MAX_POST_TITLE_LENGTH = 200;
|
const MAX_POST_TITLE_LENGTH = 200;
|
||||||
|
|
||||||
|
@ -88,6 +93,8 @@ interface PostFormState {
|
||||||
honeypot?: string;
|
honeypot?: string;
|
||||||
custom_thumbnail?: string;
|
custom_thumbnail?: string;
|
||||||
alt_text?: string;
|
alt_text?: string;
|
||||||
|
// Javascript treats this field as a string, that can't have timezone info.
|
||||||
|
scheduled_publish_time?: string;
|
||||||
};
|
};
|
||||||
suggestedPostsRes: RequestState<SearchResponse>;
|
suggestedPostsRes: RequestState<SearchResponse>;
|
||||||
metadataRes: RequestState<GetSiteMetadataResponse>;
|
metadataRes: RequestState<GetSiteMetadataResponse>;
|
||||||
|
@ -112,6 +119,7 @@ function handlePostSubmit(i: PostForm, event: any) {
|
||||||
|
|
||||||
const pForm = i.state.form;
|
const pForm = i.state.form;
|
||||||
const pv = i.props.post_view;
|
const pv = i.props.post_view;
|
||||||
|
const scheduled_publish_time = getUnixTimeLemmy(pForm.scheduled_publish_time);
|
||||||
|
|
||||||
if (pv) {
|
if (pv) {
|
||||||
i.props.onEdit?.(
|
i.props.onEdit?.(
|
||||||
|
@ -124,6 +132,7 @@ function handlePostSubmit(i: PostForm, event: any) {
|
||||||
language_id: pForm.language_id,
|
language_id: pForm.language_id,
|
||||||
custom_thumbnail: pForm.custom_thumbnail,
|
custom_thumbnail: pForm.custom_thumbnail,
|
||||||
alt_text: pForm.alt_text,
|
alt_text: pForm.alt_text,
|
||||||
|
scheduled_publish_time,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
i.setState({ bypassNavWarning: true });
|
i.setState({ bypassNavWarning: true });
|
||||||
|
@ -141,6 +150,7 @@ function handlePostSubmit(i: PostForm, event: any) {
|
||||||
honeypot: pForm.honeypot,
|
honeypot: pForm.honeypot,
|
||||||
custom_thumbnail: pForm.custom_thumbnail,
|
custom_thumbnail: pForm.custom_thumbnail,
|
||||||
alt_text: pForm.alt_text,
|
alt_text: pForm.alt_text,
|
||||||
|
scheduled_publish_time,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
i.setState({ bypassNavWarning: true });
|
i.setState({ bypassNavWarning: true });
|
||||||
|
@ -202,6 +212,18 @@ function handlePostNsfwChange(i: PostForm, event: any) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handlePostScheduleChange(i: PostForm, event: any) {
|
||||||
|
const scheduled_publish_time = event.target.value;
|
||||||
|
|
||||||
|
i.setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
form: {
|
||||||
|
...prev.form,
|
||||||
|
scheduled_publish_time,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function handleHoneyPotChange(i: PostForm, event: any) {
|
function handleHoneyPotChange(i: PostForm, event: any) {
|
||||||
i.setState(s => ((s.form.honeypot = event.target.value), s));
|
i.setState(s => ((s.form.honeypot = event.target.value), s));
|
||||||
}
|
}
|
||||||
|
@ -317,9 +339,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
this.updateUrl = this.updateUrl.bind(this);
|
this.updateUrl = this.updateUrl.bind(this);
|
||||||
|
|
||||||
const { post_view, selectedCommunityChoice, params } = this.props;
|
const { post_view, selectedCommunityChoice, params } = this.props;
|
||||||
|
|
||||||
// Means its an edit
|
// Means its an edit
|
||||||
if (post_view) {
|
if (post_view) {
|
||||||
|
const unix = getUnixTime(post_view.post.scheduled_publish_time);
|
||||||
|
var scheduled_publish_time = unixTimeToLocalDateStr(unix);
|
||||||
this.state = {
|
this.state = {
|
||||||
...this.state,
|
...this.state,
|
||||||
form: {
|
form: {
|
||||||
|
@ -331,6 +354,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
language_id: post_view.post.language_id,
|
language_id: post_view.post.language_id,
|
||||||
custom_thumbnail: post_view.post.thumbnail_url,
|
custom_thumbnail: post_view.post.thumbnail_url,
|
||||||
alt_text: post_view.post.alt_text,
|
alt_text: post_view.post.alt_text,
|
||||||
|
scheduled_publish_time,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else if (selectedCommunityChoice) {
|
} else if (selectedCommunityChoice) {
|
||||||
|
@ -684,6 +708,23 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className="mb-3 row">
|
||||||
|
<label className="col-sm-2 col-form-label" htmlFor="post-schedule">
|
||||||
|
{I18NextService.i18n.t("scheduled_publish_time")}
|
||||||
|
</label>
|
||||||
|
<div className="col-sm-10">
|
||||||
|
<input
|
||||||
|
type="datetime-local"
|
||||||
|
value={this.state.form.scheduled_publish_time}
|
||||||
|
min={unixTimeToLocalDateStr(Date.now())}
|
||||||
|
id="post-schedule"
|
||||||
|
className="form-control mb-3"
|
||||||
|
onInput={linkEvent(this, handlePostScheduleChange)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
autoComplete="false"
|
autoComplete="false"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { myAuth, setIsoData } from "@utils/app";
|
import { myAuth, setIsoData } from "@utils/app";
|
||||||
import { canShare, share } from "@utils/browser";
|
import { canShare, share } from "@utils/browser";
|
||||||
import { getExternalHost, getHttpBase } from "@utils/env";
|
import { getExternalHost, getHttpBase } from "@utils/env";
|
||||||
import { futureDaysToUnixTime, hostname } from "@utils/helpers";
|
import { formatPastDate, futureDaysToUnixTime, hostname } from "@utils/helpers";
|
||||||
import { isImage, isVideo } from "@utils/media";
|
import { isImage, isVideo } from "@utils/media";
|
||||||
import { canAdmin, canMod } from "@utils/roles";
|
import { canAdmin, canMod } from "@utils/roles";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -433,7 +433,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
createdLine() {
|
createdLine() {
|
||||||
const pv = this.postView;
|
const pv = this.postView;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="small mb-1 mb-md-0">
|
<div className="small mb-1 mb-md-0">
|
||||||
<PersonListing person={pv.creator} />
|
<PersonListing person={pv.creator} />
|
||||||
|
@ -459,6 +458,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
)}{" "}
|
)}{" "}
|
||||||
|
{pv.post.scheduled_publish_time && (
|
||||||
|
<span className="mx-1 badge text-bg-light">
|
||||||
|
{I18NextService.i18n.t("publish_in_time", {
|
||||||
|
time: formatPastDate(pv.post.scheduled_publish_time),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)}{" "}
|
||||||
· <MomentTime published={pv.post.published} updated={pv.post.updated} />
|
· <MomentTime published={pv.post.published} updated={pv.post.updated} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,27 @@
|
||||||
export default function getUnixTime(text?: string): number | undefined {
|
/**
|
||||||
|
* Converts timestamp string to unix timestamp in seconds, as used by Lemmy API
|
||||||
|
*/
|
||||||
|
export function getUnixTimeLemmy(text?: string): number | undefined {
|
||||||
return text ? new Date(text).getTime() / 1000 : undefined;
|
return text ? new Date(text).getTime() / 1000 : undefined;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Converts timestamp string to unix timestamp in millis, as used by Javascript
|
||||||
|
*/
|
||||||
|
export function getUnixTime(text?: string): number | undefined {
|
||||||
|
return text ? new Date(text).getTime() : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This converts a unix time to a local date string,
|
||||||
|
* popping to tho nearest minute, and removing the Z for
|
||||||
|
* javascript fields.
|
||||||
|
*/
|
||||||
|
export function unixTimeToLocalDateStr(unixTime?: number): string | undefined {
|
||||||
|
return unixTime
|
||||||
|
? convertUTCDateToLocalDate(new Date(unixTime)).toISOString().slice(0, -8)
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertUTCDateToLocalDate(date: Date): Date {
|
||||||
|
return new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import getQueryParams from "./get-query-params";
|
||||||
import getQueryString from "./get-query-string";
|
import getQueryString from "./get-query-string";
|
||||||
import getRandomCharFromAlphabet from "./get-random-char-from-alphabet";
|
import getRandomCharFromAlphabet from "./get-random-char-from-alphabet";
|
||||||
import getRandomFromList from "./get-random-from-list";
|
import getRandomFromList from "./get-random-from-list";
|
||||||
import getUnixTime from "./get-unix-time";
|
|
||||||
import { groupBy } from "./group-by";
|
import { groupBy } from "./group-by";
|
||||||
import hostname from "./hostname";
|
import hostname from "./hostname";
|
||||||
import hsl from "./hsl";
|
import hsl from "./hsl";
|
||||||
|
@ -43,7 +42,6 @@ export {
|
||||||
getQueryString,
|
getQueryString,
|
||||||
getRandomCharFromAlphabet,
|
getRandomCharFromAlphabet,
|
||||||
getRandomFromList,
|
getRandomFromList,
|
||||||
getUnixTime,
|
|
||||||
groupBy,
|
groupBy,
|
||||||
hostname,
|
hostname,
|
||||||
hsl,
|
hsl,
|
||||||
|
|
Loading…
Reference in a new issue