1 import { enableDownvotes, enableNsfw, myAuth, setIsoData } from "@utils/app";
2 import { isBrowser } from "@utils/browser";
3 import { getIdFromString, getQueryParams } from "@utils/helpers";
4 import type { QueryParams } from "@utils/types";
5 import { Choice, RouteDataResponse } from "@utils/types";
6 import { Component } from "inferno";
7 import { RouteComponentProps } from "inferno-router/dist/Route";
9 CreatePost as CreatePostI,
13 ListCommunitiesResponse,
14 } from "lemmy-js-client";
15 import { InitialFetchRequest, PostFormParams } from "../../interfaces";
16 import { FirstLoadService, I18NextService } from "../../services";
21 } from "../../services/HttpService";
22 import { HtmlTags } from "../common/html-tags";
23 import { Spinner } from "../common/icon";
24 import { PostForm } from "./post-form";
26 export interface CreatePostProps {
30 type CreatePostData = RouteDataResponse<{
31 communityResponse: GetCommunityResponse;
32 initialCommunitiesRes: ListCommunitiesResponse;
35 function getCreatePostQueryParams() {
36 return getQueryParams<CreatePostProps>({
37 communityId: getIdFromString,
41 function fetchCommunitiesForOptions(client: WrappedLemmyHttp) {
42 return client.listCommunities({ limit: 30, sort: "TopMonth", type_: "All" });
45 interface CreatePostState {
46 siteRes: GetSiteResponse;
48 selectedCommunityChoice?: Choice;
49 initialCommunitiesRes: RequestState<ListCommunitiesResponse>;
50 isIsomorphic: boolean;
53 export class CreatePost extends Component<
54 RouteComponentProps<Record<string, never>>,
57 private isoData = setIsoData<CreatePostData>(this.context);
58 state: CreatePostState = {
59 siteRes: this.isoData.site_res,
61 initialCommunitiesRes: { state: "empty" },
65 constructor(props: RouteComponentProps<Record<string, never>>, context: any) {
66 super(props, context);
68 this.handlePostCreate = this.handlePostCreate.bind(this);
69 this.handleSelectedCommunityChange =
70 this.handleSelectedCommunityChange.bind(this);
72 // Only fetch the data if coming from another route
73 if (!isBrowser() || FirstLoadService.isFirstLoad) {
74 const { communityResponse: communityRes, initialCommunitiesRes } =
75 this.isoData.routeData;
80 initialCommunitiesRes,
84 if (communityRes?.state === "success") {
85 const communityChoice: Choice = {
86 label: communityRes.data.community_view.community.title,
87 value: communityRes.data.community_view.community.id.toString(),
92 selectedCommunityChoice: communityChoice,
98 async fetchCommunity() {
99 const { communityId } = getCreatePostQueryParams();
100 const auth = myAuth();
103 const res = await HttpService.client.getCommunity({
107 if (res.state === "success") {
109 selectedCommunityChoice: {
110 label: res.data.community_view.community.title,
111 value: res.data.community_view.community.id.toString(),
119 async componentDidMount() {
121 if (!this.state.isIsomorphic) {
122 const { communityId } = getCreatePostQueryParams();
124 const initialCommunitiesRes = await fetchCommunitiesForOptions(
129 initialCommunitiesRes,
133 communityId?.toString() !== this.state.selectedCommunityChoice?.value
135 await this.fetchCommunity();
136 } else if (!communityId) {
138 selectedCommunityChoice: undefined,
145 get documentTitle(): string {
146 return `${I18NextService.i18n.t("create_post")} - ${
147 this.state.siteRes.site_view.site.name
152 const { selectedCommunityChoice } = this.state;
154 const locationState = this.props.history.location.state as
159 <div className="create-post container-lg">
161 title={this.documentTitle}
162 path={this.context.router.route.match.url}
164 {this.state.loading ? (
169 <div className="row">
172 className="col-12 col-lg-6 offset-lg-3 mb-4"
174 <h1 className="h4">{I18NextService.i18n.t("create_post")}</h1>
176 onCreate={this.handlePostCreate}
177 params={locationState}
178 enableDownvotes={enableDownvotes(this.state.siteRes)}
179 enableNsfw={enableNsfw(this.state.siteRes)}
180 allLanguages={this.state.siteRes.all_languages}
181 siteLanguages={this.state.siteRes.discussion_languages}
182 selectedCommunityChoice={selectedCommunityChoice}
183 onSelectCommunity={this.handleSelectedCommunityChange}
185 this.state.initialCommunitiesRes.state === "success"
186 ? this.state.initialCommunitiesRes.data.communities
197 async updateUrl({ communityId }: Partial<CreatePostProps>) {
198 const { communityId: urlCommunityId } = getCreatePostQueryParams();
200 const locationState = this.props.history.location.state as
204 const url = new URL(location.href);
206 const newId = (communityId ?? urlCommunityId)?.toString();
208 if (newId !== undefined) {
209 url.searchParams.set("communityId", newId);
211 url.searchParams.delete("communityId");
214 history.replaceState(locationState, "", url);
216 await this.fetchCommunity();
219 handleSelectedCommunityChange(choice: Choice) {
221 communityId: getIdFromString(choice?.value),
225 async handlePostCreate(form: CreatePostI) {
226 const res = await HttpService.client.createPost(form);
228 if (res.state === "success") {
229 const postId = res.data.post_view.post.id;
230 this.props.history.replace(`/post/${postId}`);
238 static async fetchInitialData({
240 query: { communityId },
242 }: InitialFetchRequest<
243 QueryParams<CreatePostProps>
244 >): Promise<CreatePostData> {
245 const data: CreatePostData = {
246 initialCommunitiesRes: await fetchCommunitiesForOptions(client),
247 communityResponse: { state: "empty" },
251 const form: GetCommunity = {
253 id: getIdFromString(communityId),
256 data.communityResponse = await client.getCommunity(form);