2019-04-03 20:59:37 +00:00
import { Component , linkEvent } from 'inferno' ;
2019-07-29 01:57:09 +00:00
import { PostListings } from './post-listings' ;
2019-04-03 20:59:37 +00:00
import { Subscription } from "rxjs" ;
import { retryWhen , delay , take } from 'rxjs/operators' ;
2019-07-29 01:57:09 +00:00
import { PostForm as PostFormI , Post , PostResponse , UserOperation , Community , ListCommunitiesResponse , ListCommunitiesForm , SortType , SearchForm , SearchType , SearchResponse } from '../interfaces' ;
2019-04-15 23:12:06 +00:00
import { WebSocketService , UserService } from '../services' ;
2019-08-03 20:26:20 +00:00
import { msgOp , getPageTitle , debounce } from '../utils' ;
2019-04-08 21:46:09 +00:00
import * as autosize from 'autosize' ;
2019-04-03 20:59:37 +00:00
interface PostFormProps {
post? : Post ; // If a post is given, that means this is an edit
2019-04-29 16:07:41 +00:00
prevCommunityName? : string ;
2019-04-08 05:19:02 +00:00
onCancel ? ( ) : any ;
onCreate ? ( id : number ) : any ;
onEdit ? ( post : Post ) : any ;
2019-04-03 20:59:37 +00:00
}
interface PostFormState {
postForm : PostFormI ;
communities : Array < Community > ;
2019-04-08 21:46:09 +00:00
loading : boolean ;
2019-04-30 14:45:50 +00:00
suggestedTitle : string ;
2019-07-29 01:57:09 +00:00
suggestedPosts : Array < Post > ;
2019-04-03 20:59:37 +00:00
}
export class PostForm extends Component < PostFormProps , PostFormState > {
private subscription : Subscription ;
private emptyState : PostFormState = {
postForm : {
name : null ,
auth : null ,
2019-04-15 23:12:06 +00:00
community_id : null ,
2019-04-16 23:04:23 +00:00
creator_id : ( UserService . Instance . user ) ? UserService.Instance.user.id : null ,
2019-04-03 20:59:37 +00:00
} ,
2019-04-08 21:46:09 +00:00
communities : [ ] ,
2019-04-30 14:45:50 +00:00
loading : false ,
suggestedTitle : undefined ,
2019-07-29 01:57:09 +00:00
suggestedPosts : [ ] ,
2019-04-03 20:59:37 +00:00
}
2019-04-08 05:19:02 +00:00
constructor ( props : any , context : any ) {
2019-04-03 20:59:37 +00:00
super ( props , context ) ;
this . state = this . emptyState ;
if ( this . props . post ) {
this . state . postForm = {
body : this.props.post.body ,
name : this.props.post.name ,
community_id : this.props.post.community_id ,
edit_id : this.props.post.id ,
2019-04-15 23:12:06 +00:00
creator_id : this.props.post.creator_id ,
2019-04-03 20:59:37 +00:00
url : this.props.post.url ,
auth : null
}
}
this . subscription = WebSocketService . Instance . subject
. pipe ( retryWhen ( errors = > errors . pipe ( delay ( 3000 ) , take ( 10 ) ) ) )
. subscribe (
( msg ) = > this . parseMessage ( msg ) ,
( err ) = > console . error ( err ) ,
( ) = > console . log ( 'complete' )
) ;
2019-04-10 06:19:12 +00:00
let listCommunitiesForm : ListCommunitiesForm = {
2019-04-18 15:28:24 +00:00
sort : SortType [ SortType . TopAll ] ,
limit : 9999 ,
2019-04-10 06:19:12 +00:00
}
WebSocketService . Instance . listCommunities ( listCommunitiesForm ) ;
2019-04-03 20:59:37 +00:00
}
2019-04-08 21:46:09 +00:00
componentDidMount() {
autosize ( document . querySelectorAll ( 'textarea' ) ) ;
}
2019-04-03 20:59:37 +00:00
componentWillUnmount() {
this . subscription . unsubscribe ( ) ;
}
render() {
return (
< div >
< form onSubmit = { linkEvent ( this , this . handlePostSubmit ) } >
< div class = "form-group row" >
< label class = "col-sm-2 col-form-label" > URL < / label >
< div class = "col-sm-10" >
2019-08-03 20:26:20 +00:00
< input type = "url" class = "form-control" value = { this . state . postForm . url } onInput = { linkEvent ( this , debounce ( this . handlePostUrlChange ) ) } / >
2019-04-30 14:45:50 +00:00
{ this . state . suggestedTitle &&
2019-07-29 01:57:09 +00:00
< div class = "mt-1 text-muted small font-weight-bold pointer" onClick = { linkEvent ( this , this . copySuggestedTitle ) } > copy suggested title : { this . state . suggestedTitle } < / div >
2019-04-30 14:45:50 +00:00
}
2019-04-03 20:59:37 +00:00
< / div >
< / div >
< div class = "form-group row" >
< label class = "col-sm-2 col-form-label" > Title < / label >
< div class = "col-sm-10" >
2019-08-03 20:26:20 +00:00
< textarea value = { this . state . postForm . name } onInput = { linkEvent ( this , debounce ( this . handlePostNameChange ) ) } class = "form-control" required rows = { 2 } minLength = { 3 } maxLength = { 100 } / >
2019-07-29 01:57:09 +00:00
{ this . state . suggestedPosts . length > 0 &&
< >
< div class = "my-1 text-muted small font-weight-bold" > These posts might be related < / div >
< PostListings posts = { this . state . suggestedPosts } / >
< / >
}
2019-04-03 20:59:37 +00:00
< / div >
< / div >
< div class = "form-group row" >
< label class = "col-sm-2 col-form-label" > Body < / label >
< div class = "col-sm-10" >
2019-04-29 19:42:22 +00:00
< textarea value = { this . state . postForm . body } onInput = { linkEvent ( this , this . handlePostBodyChange ) } class = "form-control" rows = { 4 } maxLength = { 10000 } / >
2019-04-03 20:59:37 +00:00
< / div >
< / div >
2019-04-16 23:04:23 +00:00
{ /* Cant change a community from an edit */ }
{ ! this . props . post &&
< div class = "form-group row" >
2019-04-29 02:05:11 +00:00
< label class = "col-sm-2 col-form-label" > Community < / label >
2019-04-03 20:59:37 +00:00
< div class = "col-sm-10" >
< select class = "form-control" value = { this . state . postForm . community_id } onInput = { linkEvent ( this , this . handlePostCommunityChange ) } >
{ this . state . communities . map ( community = >
< option value = { community . id } > { community . name } < / option >
) }
< / select >
< / div >
2019-04-16 23:04:23 +00:00
< / div >
}
2019-04-03 20:59:37 +00:00
< div class = "form-group row" >
< div class = "col-sm-10" >
2019-04-08 21:46:09 +00:00
< button type = "submit" class = "btn btn-secondary mr-2" >
{ this . state . loading ?
< svg class = "icon icon-spinner spin" > < use xlinkHref = "#icon-spinner" > < / use > < / svg > :
this . props . post ? 'Save' : 'Create' } < / button >
2019-04-05 02:08:21 +00:00
{ this . props . post && < button type = "button" class = "btn btn-secondary" onClick = { linkEvent ( this , this . handleCancel ) } > Cancel < / button > }
2019-04-03 20:59:37 +00:00
< / div >
< / div >
< / form >
< / div >
) ;
}
2019-04-08 05:19:02 +00:00
handlePostSubmit ( i : PostForm , event : any ) {
2019-04-03 20:59:37 +00:00
event . preventDefault ( ) ;
if ( i . props . post ) {
WebSocketService . Instance . editPost ( i . state . postForm ) ;
} else {
WebSocketService . Instance . createPost ( i . state . postForm ) ;
}
2019-04-08 21:46:09 +00:00
i . state . loading = true ;
i . setState ( i . state ) ;
2019-04-03 20:59:37 +00:00
}
2019-04-30 14:45:50 +00:00
copySuggestedTitle ( i : PostForm ) {
i . state . postForm . name = i . state . suggestedTitle ;
i . state . suggestedTitle = undefined ;
i . setState ( i . state ) ;
}
2019-04-08 05:19:02 +00:00
handlePostUrlChange ( i : PostForm , event : any ) {
2019-04-03 20:59:37 +00:00
i . state . postForm . url = event . target . value ;
2019-04-30 14:45:50 +00:00
getPageTitle ( i . state . postForm . url ) . then ( d = > {
i . state . suggestedTitle = d ;
i . setState ( i . state ) ;
} ) ;
2019-04-03 20:59:37 +00:00
i . setState ( i . state ) ;
}
2019-04-08 05:19:02 +00:00
handlePostNameChange ( i : PostForm , event : any ) {
2019-04-03 20:59:37 +00:00
i . state . postForm . name = event . target . value ;
2019-07-29 01:57:09 +00:00
let form : SearchForm = {
q : i.state.postForm.name ,
type_ : SearchType [ SearchType . Posts ] ,
sort : SortType [ SortType . TopAll ] ,
community_id : i.state.postForm.community_id ,
page : 1 ,
limit : 6 ,
} ;
if ( i . state . postForm . name !== '' ) {
WebSocketService . Instance . search ( form ) ;
} else {
i . state . suggestedPosts = [ ] ;
}
2019-04-03 20:59:37 +00:00
i . setState ( i . state ) ;
}
2019-04-08 05:19:02 +00:00
handlePostBodyChange ( i : PostForm , event : any ) {
2019-04-03 20:59:37 +00:00
i . state . postForm . body = event . target . value ;
i . setState ( i . state ) ;
}
2019-04-08 05:19:02 +00:00
handlePostCommunityChange ( i : PostForm , event : any ) {
2019-04-03 20:59:37 +00:00
i . state . postForm . community_id = Number ( event . target . value ) ;
i . setState ( i . state ) ;
}
2019-04-08 05:19:02 +00:00
handleCancel ( i : PostForm ) {
2019-04-05 02:08:21 +00:00
i . props . onCancel ( ) ;
}
2019-04-03 20:59:37 +00:00
parseMessage ( msg : any ) {
let op : UserOperation = msgOp ( msg ) ;
if ( msg . error ) {
2019-04-09 18:35:16 +00:00
alert ( msg . error ) ;
2019-04-08 21:46:09 +00:00
this . state . loading = false ;
2019-04-09 18:35:16 +00:00
this . setState ( this . state ) ;
2019-04-03 20:59:37 +00:00
return ;
} else if ( op == UserOperation . ListCommunities ) {
let res : ListCommunitiesResponse = msg ;
this . state . communities = res . communities ;
if ( this . props . post ) {
this . state . postForm . community_id = this . props . post . community_id ;
2019-04-29 16:07:41 +00:00
} else if ( this . props . prevCommunityName ) {
let foundCommunityId = res . communities . find ( r = > r . name == this . props . prevCommunityName ) . id ;
this . state . postForm . community_id = foundCommunityId ;
2019-04-03 20:59:37 +00:00
} else {
this . state . postForm . community_id = res . communities [ 0 ] . id ;
}
this . setState ( this . state ) ;
} else if ( op == UserOperation . CreatePost ) {
2019-04-08 21:46:09 +00:00
this . state . loading = false ;
2019-04-03 20:59:37 +00:00
let res : PostResponse = msg ;
this . props . onCreate ( res . post . id ) ;
} else if ( op == UserOperation . EditPost ) {
2019-04-08 21:46:09 +00:00
this . state . loading = false ;
2019-04-03 20:59:37 +00:00
let res : PostResponse = msg ;
this . props . onEdit ( res . post ) ;
2019-07-29 01:57:09 +00:00
} else if ( op == UserOperation . Search ) {
let res : SearchResponse = msg ;
this . state . suggestedPosts = res . posts ;
this . setState ( this . state ) ;
2019-04-03 20:59:37 +00:00
}
}
}