Răsfoiți Sursa

Merge pull request #4684 from weseek/feat/77525-80785-implement-select-all-checkbox

Feat/77525 80785 implement select all checkbox
Yuki Takei 4 ani în urmă
părinte
comite
3da77c581f

+ 25 - 0
packages/app/src/components/SearchPage.jsx

@@ -13,6 +13,8 @@ import SearchResultContent from './SearchPage/SearchResultContent';
 import SearchResultList from './SearchPage/SearchResultList';
 import SearchControl from './SearchPage/SearchControl';
 
+import { CheckboxType } from '../interfaces/search';
+
 export const specificPathNames = {
   user: '/user',
   trash: '/trash',
@@ -37,6 +39,7 @@ class SearchPage extends React.Component {
       pagingLimit: 10, // change to an appropriate limit number
       excludeUsersHome: true,
       excludeTrash: true,
+      selectAllCheckboxType: CheckboxType.NONE_CHECKED,
     };
 
     this.changeURL = this.changeURL.bind(this);
@@ -189,8 +192,28 @@ class SearchPage extends React.Component {
     else {
       this.state.selectedPages.add(page);
     }
+    switch (this.state.selectedPages.size) {
+      case 0:
+        return this.setState({ selectAllCheckboxType: CheckboxType.NONE_CHECKED });
+      case this.state.searchedPages.length:
+        return this.setState({ selectAllCheckboxType: CheckboxType.ALL_CHECKED });
+      default:
+        return this.setState({ selectAllCheckboxType: CheckboxType.INDETERMINATE });
+    }
   }
 
+  toggleAllCheckBox = (nextSelectAllCheckboxType) => {
+    if (nextSelectAllCheckboxType === CheckboxType.NONE_CHECKED) {
+      this.state.selectedPages.clear();
+    }
+    else {
+      this.state.searchedPages.forEach((page) => {
+        this.state.selectedPages.add(page);
+      });
+    }
+    this.setState({ selectAllCheckboxType: nextSelectAllCheckboxType });
+  };
+
   renderSearchResultContent = () => {
     return (
       <SearchResultContent
@@ -226,6 +249,8 @@ class SearchPage extends React.Component {
         onSearchInvoked={this.searchHandler}
         onExcludeUsersHome={this.onExcludeUsersHome}
         onExcludeTrash={this.onExcludeTrash}
+        onClickSelectAllCheckbox={this.toggleAllCheckBox}
+        selectAllCheckboxType={this.state.selectAllCheckboxType}
       >
       </SearchControl>
     );

+ 16 - 23
packages/app/src/components/SearchPage/DeleteSelectedPageGroup.tsx

@@ -1,52 +1,45 @@
 import React, { FC } from 'react';
 import { useTranslation } from 'react-i18next';
-import loggerFactory from '~/utils/logger';
 import { CheckboxType } from '../../interfaces/search';
 
-const logger = loggerFactory('growi:searchResultList');
-
 type Props = {
-  checkboxState: CheckboxType,
-  onClickInvoked?: () => void,
-  onCheckInvoked?: (string:CheckboxType) => void,
+  selectAllCheckboxType: CheckboxType,
+  onClickDeleteButton?: () => void,
+  onClickSelectAllCheckbox?: (nextSelectAllCheckboxType: CheckboxType) => void,
 }
 
 const DeleteSelectedPageGroup:FC<Props> = (props:Props) => {
   const { t } = useTranslation();
   const {
-    checkboxState, onClickInvoked, onCheckInvoked,
+    onClickDeleteButton, onClickSelectAllCheckbox, selectAllCheckboxType,
   } = props;
 
-  const changeCheckboxStateHandler = () => {
-    console.log(`changeCheckboxStateHandler is called. current changebox state is ${checkboxState}`);
-    // Todo: determine next checkboxState from one of the following and tell the parent component
-    // to change the checkboxState by passing onCheckInvoked function the next checkboxState
-    // - NONE_CHECKED
-    // - INDETERMINATE
-    // - ALL_CHECKED
-    // https://estoc.weseek.co.jp/redmine/issues/77525
-    // use CheckboxType by importing from packages/app/src/interfaces/
-    if (onCheckInvoked == null) { logger.error('onCheckInvoked is null') }
-    else { onCheckInvoked(CheckboxType.ALL_CHECKED) } // change this to an appropriate value
-  };
+  const onClickCheckbox = () => {
+    if (onClickSelectAllCheckbox != null) {
+      const next = selectAllCheckboxType === CheckboxType.ALL_CHECKED ? CheckboxType.NONE_CHECKED : CheckboxType.ALL_CHECKED;
+      onClickSelectAllCheckbox(next);
+    }
 
+  };
 
   return (
     <>
+      {/** todo: implement the design for CheckboxType = INDETERMINATE */}
       <input
         id="check-all-pages"
         type="checkbox"
         name="check-all-pages"
         className="custom-control custom-checkbox ml-1 align-self-center"
-        onChange={changeCheckboxStateHandler}
-        checked={checkboxState === CheckboxType.INDETERMINATE || checkboxState === CheckboxType.ALL_CHECKED}
+        onClick={onClickCheckbox}
+        checked={selectAllCheckboxType !== CheckboxType.NONE_CHECKED}
       />
       <button
         type="button"
         className="btn text-danger font-weight-light p-0 ml-3"
         onClick={() => {
-          if (onClickInvoked == null) { logger.error('onClickInvoked is null') }
-          else { onClickInvoked() }
+          if (onClickDeleteButton != null) {
+            onClickDeleteButton();
+          }
         }}
       >
         <i className="icon-trash"></i>

+ 5 - 12
packages/app/src/components/SearchPage/SearchControl.tsx

@@ -8,9 +8,11 @@ import { CheckboxType } from '../../interfaces/search';
 type Props = {
   searchingKeyword: string,
   appContainer: AppContainer,
+  selectAllCheckboxType: CheckboxType,
   onSearchInvoked: (data : any[]) => boolean,
   onExcludeUsersHome?: () => void,
   onExcludeTrash?: () => void,
+  onClickSelectAllCheckbox?: (nextSelectAllCheckboxType: CheckboxType) => void,
 }
 
 const SearchControl: FC <Props> = (props: Props) => {
@@ -37,15 +39,6 @@ const SearchControl: FC <Props> = (props: Props) => {
     // https://estoc.weseek.co.jp/redmine/issues/77525
   };
 
-  const onCheckAllPagesInvoked = (nextCheckboxState:CheckboxType) => {
-    console.log(`onCheckAllPagesInvoked is called with arg ${nextCheckboxState}`);
-    // Todo: set the checkboxState, isChecked, and indeterminate value of checkbox element according to the passed argument
-    // https://estoc.weseek.co.jp/redmine/issues/77525
-
-    // setting checkbox to indeterminate is required to use of useRef to access checkbox element.
-    // ref: https://getbootstrap.com/docs/4.5/components/forms/#checkboxes
-  };
-
   return (
     <div className="">
       <div className="search-page-input sps sps--abv">
@@ -59,9 +52,9 @@ const SearchControl: FC <Props> = (props: Props) => {
       <div className="d-flex my-4">
         {/* Todo: design will be fixed in #80324. Function will be implemented in #77525 */}
         <DeleteSelectedPageGroup
-          checkboxState={'' || CheckboxType.NONE_CHECKED} // Todo: change the left value to appropriate value
-          onClickInvoked={onDeleteSelectedPageHandler}
-          onCheckInvoked={onCheckAllPagesInvoked}
+          selectAllCheckboxType={props.selectAllCheckboxType}
+          onClickDeleteButton={onDeleteSelectedPageHandler}
+          onClickSelectAllCheckbox={props.onClickSelectAllCheckbox}
         />
         <div className="d-flex align-items-center border rounded border-gray px-2 py-1 mr-2 ml-auto">
           <label className="my-0 mr-2" htmlFor="flexCheckDefault">

+ 1 - 1
packages/app/src/components/SearchPage/SearchResultList.tsx

@@ -35,7 +35,7 @@ const SearchResultList: FC<Props> = (props:Props) => {
             key={page._id}
             page={page}
             onClickInvoked={props.onClickInvoked}
-            onChangedInvoked={props.onChangedInvoked}
+            onClickCheckboxInvoked={props.onChangedInvoked}
             isSelected={page._id === focusedPageId || false}
           />
         );

+ 16 - 4
packages/app/src/components/SearchPage/SearchResultListItem.tsx

@@ -69,12 +69,16 @@ const PageItemControl: FC<PageItemControlProps> = (props: {page: ISearchedPage})
 type Props = {
   page: ISearchedPage,
   isSelected: boolean,
-  onChangedInvoked?: (page: ISearchedPage) => void,
+  onClickCheckboxInvoked?: (page: ISearchedPage) => void,
+  // todo: fix name
+  // refs: https://redmine.weseek.co.jp/issues/81100
   onClickInvoked?: (pageId: string) => void,
 }
 
 const SearchResultListItem: FC<Props> = (props:Props) => {
-  const { page, isSelected } = props;
+  const {
+    page, isSelected, onClickInvoked, onClickCheckboxInvoked,
+  } = props;
 
   // Add prefix 'id_' in pageId, because scrollspy of bootstrap doesn't work when the first letter of id attr of target component is numeral.
   const pageId = `#${page._id}`;
@@ -87,7 +91,11 @@ const SearchResultListItem: FC<Props> = (props:Props) => {
       <a
         className="d-block pt-3"
         href={pageId}
-        onClick={() => { if (props.onClickInvoked != null) { props.onClickInvoked(page._id) } }}
+        onClick={() => {
+          if (onClickInvoked != null) {
+            onClickInvoked(page._id);
+          }
+        }}
       >
         <div className="d-flex">
           {/* checkbox */}
@@ -96,7 +104,11 @@ const SearchResultListItem: FC<Props> = (props:Props) => {
               className="form-check-input my-auto"
               type="checkbox"
               id="flexCheckDefault"
-              onClick={() => { if (props.onChangedInvoked != null) { props.onChangedInvoked(page) } }}
+              onClick={() => {
+                if (onClickCheckboxInvoked != null) {
+                  onClickCheckboxInvoked(page);
+                }
+              }}
             />
           </div>
           <div className="w-100">