Skip to content

Instantly share code, notes, and snippets.

@itwasmattgregg
Created March 24, 2020 18:26
Show Gist options
  • Save itwasmattgregg/766e00949baefed4873f4b9a62549704 to your computer and use it in GitHub Desktop.
Save itwasmattgregg/766e00949baefed4873f4b9a62549704 to your computer and use it in GitHub Desktop.
import { PostPartialUpdateRequest, PostUpdateRequest, ExternalLink, Post } from "../gen/api";
import { Component } from "react";
import { apiCall, postApi, externalLinkApi } from "../Api";
export type PostCreateUpdateRequest = Post;
function isPostUpdateRequest(request: PostCreateUpdateRequest): request is PostPartialUpdateRequest | PostUpdateRequest {
return (request as PostPartialUpdateRequest).id !== undefined;
}
export interface PostDraft {
post: PostCreateUpdateRequest;
content?: PostContent;
news?: ExternalLink;
}
export interface PostContent {
media?: File;
}
export interface PostCreatorState {
postDraft: PostDraft;
submittingNews?: Promise<void>;
}
export const PostCreatorState_INITIAL: PostCreatorState = {
postDraft: {
post: {
description: "",
challengeLink: ""
}
}
};
type PostCreatorComponent = Component<any, PostCreatorState>;
export default class PostCreator {
constructor(readonly component: { setState: PostCreatorComponent["setState"] }) {
}
post: PostCreateUpdateRequest = PostCreatorState_INITIAL.postDraft.post;
content?: PostContent;
news?: ExternalLink;
submittingNews?: Promise<void>;
serialize() {
return JSON.stringify(this.post);
}
deserialize(value: string) {
this.updatePost(JSON.parse(value));
}
readonly savePost = async () => {
const post = this.post;
const postId = post.id;
if (postId !== undefined) {
return await apiCall(() => postApi.postPartialUpdate({
id: postId,
data: post
}));
} else {
const savedPost = await apiCall(() => postApi.postCreate({ data: post }));
this.updatePost({
...post,
id: savedPost.id,
});
return savedPost;
}
}
readonly submitNews = async () => {
const news = this.news;
if (this.submittingNews) { await this.submittingNews; }
if (!news || !news.sourceUrl || this.post.externalLink !== undefined) {
// either have no news to submit or news is already submitted
return;
}
try {
this.submittingNews = (async () => {
const link = await apiCall(() => externalLinkApi.externalLinkCreate({ data: news }));
if (link.id) {
this.setPostProperty("externalLinkId", link.id);
this.news = link;
this.updatePostDraft();
}
})();
this.component.setState({ submittingNews: this.submittingNews });
await this.submittingNews;
} finally {
this.submittingNews = undefined;
this.component.setState({ submittingNews: undefined });
}
}
updatePostDraft() {
this.component.setState({
postDraft: {
post: this.post,
content: this.content,
news: this.news,
},
});
}
readonly setContent = (content: PostContent) => {
this.content = content;
this.updatePostDraft();
}
readonly updatePost = (post: PostCreateUpdateRequest) => {
this.post = post;
this.updatePostDraft();
}
readonly setPostProperty = <T extends keyof PostCreateUpdateRequest>(property: T, value: PostCreateUpdateRequest[T]) => {
const post = {
...this.post,
[property]: value,
}
this.updatePost(post);
}
readonly setNewsSourceUrl = (sourceUrl: string) => {
const currentSourceUrl = this.news && this.news.sourceUrl;
if (sourceUrl !== currentSourceUrl && this.post.externalLink) {
this.setPostProperty("externalLink", undefined);
}
this.news = {
sourceUrl: sourceUrl,
};
this.updatePostDraft();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment