Просмотр исходного кода

Merge pull request #1453 from weseek/feat/add-check-box-for-search-option

Feat/add check box for search option
itizawa 6 лет назад
Родитель
Сommit
2eb84f81c1

+ 5 - 0
resource/locales/en-US/translation.json

@@ -680,6 +680,11 @@
     "remove_external_user_success": "Succeeded to remove {{accountId}} "
   },
   "user_group_management": {
+    "search_option": "Search Option",
+    "enable_option": "Enable {{option}}",
+    "forward_match": "forword match",
+    "partial_match": "partial match",
+    "backward_match": "backward match",
     "group_list": "Group List",
     "back_to_list": "Go Back to Group List",
     "basic_info": "Basic Info",

+ 5 - 0
resource/locales/ja/translation.json

@@ -664,6 +664,11 @@
     "remove_external_user_success": "{{accountId}}を削除しました "
   },
   "user_group_management": {
+    "search_option": "検索オプション",
+    "enable_option": "{{option}}を有効にする",
+    "forward_match": "前方一致",
+    "partial_match": "部分一致",
+    "backward_match": "後方一致",
     "group_list": "グループ一覧",
     "back_to_list": "グループ一覧に戻る",
     "basic_info": "基本情報",

+ 37 - 0
src/client/js/components/Admin/UserGroupDetail/CheckBoxForSerchUserOption.jsx

@@ -0,0 +1,37 @@
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+class CheckBoxForSerchUserOption extends React.Component {
+
+  render() {
+    const { t, option } = this.props;
+    return (
+      <div className="checkbox checkbox-info" key={`isAlso${option}Searched`}>
+        <input
+          type="checkbox"
+          id={`isAlso${option}Searched`}
+          className="form-check-input"
+          checked={this.props.checked}
+          onChange={this.props.onChange}
+        />
+        <label className="text-capitalize form-check-label ml-3" htmlFor={`isAlso${option}Searched`}>
+          {t('user_group_management.enable_option', { option })}
+        </label>
+      </div>
+    );
+  }
+
+}
+
+
+CheckBoxForSerchUserOption.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  option: PropTypes.string.isRequired,
+  checked: PropTypes.bool.isRequired,
+  onChange: PropTypes.bool.isRequired,
+};
+
+export default withTranslation()(CheckBoxForSerchUserOption);

+ 37 - 0
src/client/js/components/Admin/UserGroupDetail/RadioButtonForSerchUserOption.jsx

@@ -0,0 +1,37 @@
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+class RadioButtonForSerchUserOption extends React.Component {
+
+  render() {
+    const { t, searchType } = this.props;
+    return (
+      <div className="radio" key={`${searchType}Match`}>
+        <input
+          type="radio"
+          id={`${searchType}Match`}
+          className="form-check-radio"
+          checked={this.props.checked}
+          onChange={this.props.onChange}
+        />
+        <label className="text-capitalize form-check-label ml-3" htmlFor={`${searchType}Match`}>
+          {t(`user_group_management.${searchType}_match`)}
+        </label>
+      </div>
+    );
+  }
+
+}
+
+
+RadioButtonForSerchUserOption.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  searchType: PropTypes.string.isRequired,
+  checked: PropTypes.bool.isRequired,
+  onChange: PropTypes.bool.isRequired,
+};
+
+export default withTranslation()(RadioButtonForSerchUserOption);

+ 16 - 20
src/client/js/components/Admin/UserGroupDetail/UserGroupUserFormByInput.jsx

@@ -29,7 +29,6 @@ class UserGroupUserFormByInput extends React.Component {
     this.handleChange = this.handleChange.bind(this);
     this.handleSearch = this.handleSearch.bind(this);
     this.onKeyDown = this.onKeyDown.bind(this);
-    this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this);
 
     this.searhApplicableUsersDebounce = debounce(1000, this.searhApplicableUsers);
   }
@@ -46,9 +45,7 @@ class UserGroupUserFormByInput extends React.Component {
   }
 
 
-  async addUserBySubmit(e) {
-    e.preventDefault();
-    const { input } = this.state;
+  async addUserBySubmit(input) {
 
     try {
       await this.props.userGroupDetailContainer.addUserByUsername(input);
@@ -93,9 +90,10 @@ class UserGroupUserFormByInput extends React.Component {
   }
 
   onKeyDown(event) {
+    const input = event.target.defaultValue;
     // 13 is Enter key
     if (event.keyCode === 13) {
-      this.addUserBySubmit();
+      this.addUserBySubmit(input);
     }
   }
 
@@ -103,23 +101,14 @@ class UserGroupUserFormByInput extends React.Component {
     return (this.state.searchError !== null) && 'Error on searching.';
   }
 
-  renderMenuItemChildren(option, props, index) {
-    const user = option;
-    return (
-      <span>
-        {user}
-      </span>
-    );
-  }
-
   render() {
     const { t } = this.props;
 
     const inputProps = { autoComplete: 'off' };
 
     return (
-      <form className="form-inline" onSubmit={this.addUserBySubmit}>
-        <div className="form-group">
+      <div className="row">
+        <div className="col-xs-8 pr-0">
           <AsyncTypeahead
             {...this.props}
             id="name-typeahead-asynctypeahead"
@@ -129,19 +118,26 @@ class UserGroupUserFormByInput extends React.Component {
             labelKey="name"
             minLength={0}
             options={this.state.applicableUsers} // Search result
-            emptyLabel={this.getEmptyLabel()}
             searchText={(this.state.isLoading ? 'Searching...' : this.getEmptyLabel())}
             align="left"
             onChange={this.handleChange}
             onSearch={this.handleSearch}
             onInputChange={this.onInputChange}
             onKeyDown={this.onKeyDown}
-            renderMenuItemChildren={this.renderMenuItemChildren}
             caseSensitive={false}
           />
         </div>
-        <button type="submit" className="btn btn-sm btn-success" disabled={!this.validateForm()}>{t('add')}</button>
-      </form>
+        <div className="col-xs-2 pl-0">
+          <button
+            type="button"
+            className="btn btn-sm btn-success"
+            disabled={!this.validateForm()}
+            onClick={event => this.addUserBySubmit(event.target.value)}
+          >
+            {t('add')}
+          </button>
+        </div>
+      </div>
     );
   }
 

+ 48 - 2
src/client/js/components/Admin/UserGroupDetail/UserGroupUserModal.jsx

@@ -7,6 +7,8 @@ import UserGroupUserFormByInput from './UserGroupUserFormByInput';
 import { createSubscribedElement } from '../../UnstatedUtils';
 import AppContainer from '../../../services/AppContainer';
 import UserGroupDetailContainer from '../../../services/UserGroupDetailContainer';
+import RadioButtonForSerchUserOption from './RadioButtonForSerchUserOption';
+import CheckBoxForSerchUserOption from './CheckBoxForSerchUserOption';
 
 class UserGroupUserModal extends React.Component {
 
@@ -16,10 +18,54 @@ class UserGroupUserModal extends React.Component {
     return (
       <Modal show={userGroupDetailContainer.state.isUserGroupUserModalOpen} onHide={userGroupDetailContainer.closeUserGroupUserModal}>
         <Modal.Header closeButton>
-          <Modal.Title>{ t('user_group_management.add_user') }</Modal.Title>
+          <Modal.Title>{t('user_group_management.add_user')}</Modal.Title>
         </Modal.Header>
         <Modal.Body>
-          <UserGroupUserFormByInput />
+          <div className="p-3">
+            <UserGroupUserFormByInput />
+          </div>
+          <h2 className="border-bottom">{t('user_group_management.search_option')}</h2>
+          <div className="row mt-4">
+            <div className="col-xs-6">
+              <div className="mb-5">
+                <CheckBoxForSerchUserOption
+                  option="Mail"
+                  checked={userGroupDetailContainer.state.isAlsoMailSearched}
+                  onChange={userGroupDetailContainer.switchIsAlsoMailSearched}
+                />
+              </div>
+              <div className="mb-5">
+                <CheckBoxForSerchUserOption
+                  option="Name"
+                  checked={userGroupDetailContainer.state.isAlsoNameSearched}
+                  onChange={userGroupDetailContainer.switchIsAlsoNameSearched}
+                />
+              </div>
+            </div>
+            <div className="col-xs-6">
+              <div className="mb-5">
+                <RadioButtonForSerchUserOption
+                  searchType="forward"
+                  checked={userGroupDetailContainer.state.searchType === 'forward'}
+                  onChange={() => { userGroupDetailContainer.switchSearchType('forward') }}
+                />
+              </div>
+              <div className="mb-5">
+                <RadioButtonForSerchUserOption
+                  searchType="partial"
+                  checked={userGroupDetailContainer.state.searchType === 'partial'}
+                  onChange={() => { userGroupDetailContainer.switchSearchType('partial') }}
+                />
+              </div>
+              <div className="mb-5">
+                <RadioButtonForSerchUserOption
+                  searchType="backward"
+                  checked={userGroupDetailContainer.state.searchType === 'backword'}
+                  onChange={() => { userGroupDetailContainer.switchSearchType('backword') }}
+                />
+              </div>
+            </div>
+          </div>
         </Modal.Body>
       </Modal>
     );

+ 29 - 4
src/client/js/services/UserGroupDetailContainer.js

@@ -24,10 +24,15 @@ export default class UserGroupDetailContainer extends Container {
       userGroupRelations: [],
       relatedPages: [],
       isUserGroupUserModalOpen: false,
+      searchType: 'partial',
+      isAlsoMailSearched: false,
+      isAlsoNameSearched: false,
     };
 
     this.init();
 
+    this.switchIsAlsoMailSearched = this.switchIsAlsoMailSearched.bind(this);
+    this.switchIsAlsoNameSearched = this.switchIsAlsoNameSearched.bind(this);
     this.openUserGroupUserModal = this.openUserGroupUserModal.bind(this);
     this.closeUserGroupUserModal = this.closeUserGroupUserModal.bind(this);
     this.addUserByUsername = this.addUserByUsername.bind(this);
@@ -65,6 +70,27 @@ export default class UserGroupDetailContainer extends Container {
     }
   }
 
+  /**
+   * switch isAlsoMailSearched
+   */
+  switchIsAlsoMailSearched() {
+    this.setState({ isAlsoMailSearched: !this.state.isAlsoMailSearched });
+  }
+
+  /**
+   * switch isAlsoNameSearched
+   */
+  switchIsAlsoNameSearched() {
+    this.setState({ isAlsoNameSearched: !this.state.isAlsoNameSearched });
+  }
+
+  /**
+   * switch searchType
+   */
+  switchSearchType(searchType) {
+    this.setState({ searchType });
+  }
+
   /**
    * update user group
    *
@@ -106,10 +132,9 @@ export default class UserGroupDetailContainer extends Container {
   async fetchApplicableUsers(searchWord) {
     const res = await this.appContainer.apiv3.get(`/user-groups/${this.state.userGroup._id}/unrelated-users`, {
       searchWord,
-      // TODO GW-716 switch value
-      isForwardMatch: false,
-      isAlsoNameSearched: false,
-      isAlsoMailSearched: false,
+      isForwardMatch: this.state.searchType,
+      isAlsoMailSearched: this.state.isAlsoMailSearched,
+      isAlsoNameSearched: this.state.isAlsoNameSearched,
     });
 
     const { users } = res.data;