diff options
author | Dessalines <tyhou13@gmx.com> | 2020-03-06 14:57:52 -0500 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-03-06 14:57:52 -0500 |
commit | a67a69f95e268a679a6c42722240628019355790 (patch) | |
tree | 5e7334cb89e4e69d547e90ccba7864bd0f62fc19 /ui/src/components | |
parent | 0708a6d665ef81700ac61c32f1c3710db9493108 (diff) |
Ask for confirmation on leaving pages with incomplete forms. Fixes #529
Diffstat (limited to 'ui/src/components')
-rw-r--r-- | ui/src/components/comment-form.tsx | 5 | ||||
-rw-r--r-- | ui/src/components/community-form.tsx | 220 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 10 | ||||
-rw-r--r-- | ui/src/components/private-message-form.tsx | 5 | ||||
-rw-r--r-- | ui/src/components/site-form.tsx | 228 |
5 files changed, 258 insertions, 210 deletions
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index aa8e651d..f3009d34 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Prompt } from 'inferno-router'; import { CommentNode as CommentNodeI, CommentForm as CommentFormI, @@ -87,6 +88,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> { render() { return ( <div class="mb-3"> + <Prompt + when={this.state.commentForm.content} + message={i18n.t('block_leaving')} + /> <form onSubmit={linkEvent(this, this.handleCommentSubmit)}> <div class="form-group row"> <div className={`col-sm-12`}> diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index aaa3e6c4..eedc2003 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Prompt } from 'inferno-router'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; import { @@ -105,120 +106,131 @@ export class CommunityForm extends Component< render() { return ( - <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor="community-name"> - {i18n.t('name')} - </label> - <div class="col-12"> - <input - type="text" - id="community-name" - class="form-control" - value={this.state.communityForm.name} - onInput={linkEvent(this, this.handleCommunityNameChange)} - required - minLength={3} - maxLength={20} - pattern="[a-z0-9_]+" - title={i18n.t('community_reqs')} - /> + <> + <Prompt + when={ + !this.state.loading && + (this.state.communityForm.name || + this.state.communityForm.title || + this.state.communityForm.description) + } + message={i18n.t('block_leaving')} + /> + <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}> + <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor="community-name"> + {i18n.t('name')} + </label> + <div class="col-12"> + <input + type="text" + id="community-name" + class="form-control" + value={this.state.communityForm.name} + onInput={linkEvent(this, this.handleCommunityNameChange)} + required + minLength={3} + maxLength={20} + pattern="[a-z0-9_]+" + title={i18n.t('community_reqs')} + /> + </div> </div> - </div> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor="community-title"> - {i18n.t('title')} - </label> - <div class="col-12"> - <input - type="text" - id="community-title" - value={this.state.communityForm.title} - onInput={linkEvent(this, this.handleCommunityTitleChange)} - class="form-control" - required - minLength={3} - maxLength={100} - /> - </div> - </div> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor={this.id}> - {i18n.t('sidebar')} - </label> - <div class="col-12"> - <textarea - id={this.id} - value={this.state.communityForm.description} - onInput={linkEvent(this, this.handleCommunityDescriptionChange)} - class="form-control" - rows={3} - maxLength={10000} - /> - </div> - </div> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor="community-category"> - {i18n.t('category')} - </label> - <div class="col-12"> - <select - class="form-control" - id="community-category" - value={this.state.communityForm.category_id} - onInput={linkEvent(this, this.handleCommunityCategoryChange)} - > - {this.state.categories.map(category => ( - <option value={category.id}>{category.name}</option> - ))} - </select> + <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor="community-title"> + {i18n.t('title')} + </label> + <div class="col-12"> + <input + type="text" + id="community-title" + value={this.state.communityForm.title} + onInput={linkEvent(this, this.handleCommunityTitleChange)} + class="form-control" + required + minLength={3} + maxLength={100} + /> + </div> </div> - </div> - - {this.state.enable_nsfw && ( <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor={this.id}> + {i18n.t('sidebar')} + </label> <div class="col-12"> - <div class="form-check"> - <input - class="form-check-input" - id="community-nsfw" - type="checkbox" - checked={this.state.communityForm.nsfw} - onChange={linkEvent(this, this.handleCommunityNsfwChange)} - /> - <label class="form-check-label" htmlFor="community-nsfw"> - {i18n.t('nsfw')} - </label> - </div> + <textarea + id={this.id} + value={this.state.communityForm.description} + onInput={linkEvent(this, this.handleCommunityDescriptionChange)} + class="form-control" + rows={3} + maxLength={10000} + /> </div> </div> - )} - <div class="form-group row"> - <div class="col-12"> - <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.community ? ( - capitalizeFirstLetter(i18n.t('save')) - ) : ( - capitalizeFirstLetter(i18n.t('create')) - )} - </button> - {this.props.community && ( - <button - type="button" - class="btn btn-secondary" - onClick={linkEvent(this, this.handleCancel)} + <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor="community-category"> + {i18n.t('category')} + </label> + <div class="col-12"> + <select + class="form-control" + id="community-category" + value={this.state.communityForm.category_id} + onInput={linkEvent(this, this.handleCommunityCategoryChange)} > - {i18n.t('cancel')} + {this.state.categories.map(category => ( + <option value={category.id}>{category.name}</option> + ))} + </select> + </div> + </div> + + {this.state.enable_nsfw && ( + <div class="form-group row"> + <div class="col-12"> + <div class="form-check"> + <input + class="form-check-input" + id="community-nsfw" + type="checkbox" + checked={this.state.communityForm.nsfw} + onChange={linkEvent(this, this.handleCommunityNsfwChange)} + /> + <label class="form-check-label" htmlFor="community-nsfw"> + {i18n.t('nsfw')} + </label> + </div> + </div> + </div> + )} + <div class="form-group row"> + <div class="col-12"> + <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.community ? ( + capitalizeFirstLetter(i18n.t('save')) + ) : ( + capitalizeFirstLetter(i18n.t('create')) + )} </button> - )} + {this.props.community && ( + <button + type="button" + class="btn btn-secondary" + onClick={linkEvent(this, this.handleCancel)} + > + {i18n.t('cancel')} + </button> + )} + </div> </div> - </div> - </form> + </form> + </> ); } diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index ef25a546..5f05bd58 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Prompt } from 'inferno-router'; import { PostListings } from './post-listings'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -153,6 +154,15 @@ export class PostForm extends Component<PostFormProps, PostFormState> { render() { return ( <div> + <Prompt + when={ + !this.state.loading && + (this.state.postForm.name || + this.state.postForm.url || + this.state.postForm.body) + } + message={i18n.t('block_leaving')} + /> <form onSubmit={linkEvent(this, this.handlePostSubmit)}> <div class="form-group row"> <label class="col-sm-2 col-form-label" htmlFor="post-url"> diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index 90b3b6e1..f5f0cc75 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Prompt } from 'inferno-router'; import { Link } from 'inferno-router'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -116,6 +117,10 @@ export class PrivateMessageForm extends Component< render() { return ( <div> + <Prompt + when={!this.state.loading && this.state.privateMessageForm.content} + message={i18n.t('block_leaving')} + /> <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}> {!this.props.privateMessage && ( <div class="form-group row"> diff --git a/ui/src/components/site-form.tsx b/ui/src/components/site-form.tsx index 113e9c66..df913043 100644 --- a/ui/src/components/site-form.tsx +++ b/ui/src/components/site-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Prompt } from 'inferno-router'; import { Site, SiteForm as SiteFormI } from '../interfaces'; import { WebSocketService } from '../services'; import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils'; @@ -59,123 +60,138 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> { render() { return ( - <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}> - <h5>{`${ - this.props.site - ? capitalizeFirstLetter(i18n.t('edit')) - : capitalizeFirstLetter(i18n.t('name')) - } ${i18n.t('your_site')}`}</h5> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor="create-site-name"> - {i18n.t('name')} - </label> - <div class="col-12"> - <input - type="text" - id="create-site-name" - class="form-control" - value={this.state.siteForm.name} - onInput={linkEvent(this, this.handleSiteNameChange)} - required - minLength={3} - maxLength={20} - /> - </div> - </div> - <div class="form-group row"> - <label class="col-12 col-form-label" htmlFor={this.id}> - {i18n.t('sidebar')} - </label> - <div class="col-12"> - <textarea - id={this.id} - value={this.state.siteForm.description} - onInput={linkEvent(this, this.handleSiteDescriptionChange)} - class="form-control" - rows={3} - maxLength={10000} - /> - </div> - </div> - <div class="form-group row"> - <div class="col-12"> - <div class="form-check"> + <> + <Prompt + when={ + !this.state.loading && + (this.state.siteForm.name || this.state.siteForm.description) + } + message={i18n.t('block_leaving')} + /> + <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}> + <h5>{`${ + this.props.site + ? capitalizeFirstLetter(i18n.t('edit')) + : capitalizeFirstLetter(i18n.t('name')) + } ${i18n.t('your_site')}`}</h5> + <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor="create-site-name"> + {i18n.t('name')} + </label> + <div class="col-12"> <input - class="form-check-input" - id="create-site-downvotes" - type="checkbox" - checked={this.state.siteForm.enable_downvotes} - onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)} + type="text" + id="create-site-name" + class="form-control" + value={this.state.siteForm.name} + onInput={linkEvent(this, this.handleSiteNameChange)} + required + minLength={3} + maxLength={20} /> - <label class="form-check-label" htmlFor="create-site-downvotes"> - {i18n.t('enable_downvotes')} - </label> </div> </div> - </div> - <div class="form-group row"> - <div class="col-12"> - <div class="form-check"> - <input - class="form-check-input" - id="create-site-enable-nsfw" - type="checkbox" - checked={this.state.siteForm.enable_nsfw} - onChange={linkEvent(this, this.handleSiteEnableNsfwChange)} + <div class="form-group row"> + <label class="col-12 col-form-label" htmlFor={this.id}> + {i18n.t('sidebar')} + </label> + <div class="col-12"> + <textarea + id={this.id} + value={this.state.siteForm.description} + onInput={linkEvent(this, this.handleSiteDescriptionChange)} + class="form-control" + rows={3} + maxLength={10000} /> - <label class="form-check-label" htmlFor="create-site-enable-nsfw"> - {i18n.t('enable_nsfw')} - </label> </div> </div> - </div> - <div class="form-group row"> - <div class="col-12"> - <div class="form-check"> - <input - class="form-check-input" - id="create-site-open-registration" - type="checkbox" - checked={this.state.siteForm.open_registration} - onChange={linkEvent( - this, - this.handleSiteOpenRegistrationChange - )} - /> - <label - class="form-check-label" - htmlFor="create-site-open-registration" - > - {i18n.t('open_registration')} - </label> + <div class="form-group row"> + <div class="col-12"> + <div class="form-check"> + <input + class="form-check-input" + id="create-site-downvotes" + type="checkbox" + checked={this.state.siteForm.enable_downvotes} + onChange={linkEvent( + this, + this.handleSiteEnableDownvotesChange + )} + /> + <label class="form-check-label" htmlFor="create-site-downvotes"> + {i18n.t('enable_downvotes')} + </label> + </div> </div> </div> - </div> - <div class="form-group row"> - <div class="col-12"> - <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.site ? ( - capitalizeFirstLetter(i18n.t('save')) - ) : ( - capitalizeFirstLetter(i18n.t('create')) - )} - </button> - {this.props.site && ( - <button - type="button" - class="btn btn-secondary" - onClick={linkEvent(this, this.handleCancel)} - > - {i18n.t('cancel')} + <div class="form-group row"> + <div class="col-12"> + <div class="form-check"> + <input + class="form-check-input" + id="create-site-enable-nsfw" + type="checkbox" + checked={this.state.siteForm.enable_nsfw} + onChange={linkEvent(this, this.handleSiteEnableNsfwChange)} + /> + <label + class="form-check-label" + htmlFor="create-site-enable-nsfw" + > + {i18n.t('enable_nsfw')} + </label> + </div> + </div> + </div> + <div class="form-group row"> + <div class="col-12"> + <div class="form-check"> + <input + class="form-check-input" + id="create-site-open-registration" + type="checkbox" + checked={this.state.siteForm.open_registration} + onChange={linkEvent( + this, + this.handleSiteOpenRegistrationChange + )} + /> + <label + class="form-check-label" + htmlFor="create-site-open-registration" + > + {i18n.t('open_registration')} + </label> + </div> + </div> + </div> + <div class="form-group row"> + <div class="col-12"> + <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.site ? ( + capitalizeFirstLetter(i18n.t('save')) + ) : ( + capitalizeFirstLetter(i18n.t('create')) + )} </button> - )} + {this.props.site && ( + <button + type="button" + class="btn btn-secondary" + onClick={linkEvent(this, this.handleCancel)} + > + {i18n.t('cancel')} + </button> + )} + </div> </div> - </div> - </form> + </form> + </> ); } |