diff --git a/client/modules/IDE/actions/collections.js b/client/modules/IDE/actions/collections.js index 5a9218520b..35d9ff2dc9 100644 --- a/client/modules/IDE/actions/collections.js +++ b/client/modules/IDE/actions/collections.js @@ -6,7 +6,6 @@ import { setToastText, showToast } from './toast'; const TOAST_DISPLAY_TIME_MS = 1500; -// eslint-disable-next-line export function getCollections(username) { return (dispatch) => { dispatch(startLoader()); @@ -16,8 +15,7 @@ export function getCollections(username) { } else { url = '/collections'; } - console.log(url); - apiClient + return apiClient .get(url) .then((response) => { dispatch({ @@ -27,10 +25,9 @@ export function getCollections(username) { dispatch(stopLoader()); }) .catch((error) => { - const { response } = error; dispatch({ type: ActionTypes.ERROR, - error: response.data + error: error?.response?.data }); dispatch(stopLoader()); }); @@ -183,4 +180,4 @@ export function deleteCollection(collectionId) { return response.data; }); }; -} +} \ No newline at end of file diff --git a/client/modules/IDE/components/AddToCollectionList.jsx b/client/modules/IDE/components/AddToCollectionList.jsx index fc5c161fdc..7e8b2bbdf3 100644 --- a/client/modules/IDE/components/AddToCollectionList.jsx +++ b/client/modules/IDE/components/AddToCollectionList.jsx @@ -1,23 +1,38 @@ + + +Settings + +Hi! Here some our recommendations to get the best out of BLACKBOX: + +Be as clear as possible + +End the question in what language you want the answer to be, e.g: ‘connect to mongodb in python +or you can just +Go to Blackbox +Here are some suggestion (choose one): +Write a function that reads data from a json file +How to delete docs from mongodb in phyton +Connect to mongodb in nodejs +Ask any coding question +send +refresh +Blackbox AI Chat is in beta and Blackbox is not liable for the content generated. By using Blackbox, you acknowledge that you agree to agree to Blackbox's Terms and Privacy Policy import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import * as ProjectActions from '../actions/project'; -import * as ProjectsActions from '../actions/projects'; -import * as CollectionsActions from '../actions/collections'; -import * as ToastActions from '../actions/toast'; -import * as SortingActions from '../actions/sorting'; -import getSortedCollections from '../selectors/collections'; import Loader from '../../App/components/loader'; +import { + addToCollection, + getCollections, + removeFromCollection +} from '../actions/collections'; +import getSortedCollections from '../selectors/collections'; import QuickAddList from './QuickAddList'; import { remSize } from '../../../theme'; -const projectInCollection = (project, collection) => - collection.items.find((item) => item.projectId === project.id) != null; - export const CollectionAddSketchWrapper = styled.div` width: ${remSize(600)}; max-width: 100%; @@ -31,166 +46,67 @@ export const QuickAddWrapper = styled.div` height: 100%; `; -class CollectionList extends React.Component { - constructor(props) { - super(props); +const AddToCollectionList = ({ projectId }) => { + const { t } = useTranslation(); - if (props.projectId) { - props.getProject(props.projectId); - } + const dispatch = useDispatch(); - this.props.getCollections(this.props.username); + const username = useSelector((state) => state.user.username); - this.state = { - hasLoadedData: false - }; - } + const collections = useSelector(getSortedCollections); - componentDidUpdate(prevProps) { - if (prevProps.loading === true && this.props.loading === false) { - // eslint-disable-next-line react/no-did-update-set-state - this.setState({ - hasLoadedData: true - }); - } - } + // TODO: improve loading state + const loading = useSelector((state) => state.loading); + const [hasLoadedData, setHasLoadedData] = useState(false); + const showLoader = loading && !hasLoadedData; - getTitle() { - if (this.props.username === this.props.user.username) { - return this.props.t('AddToCollectionList.Title'); - } - return this.props.t('AddToCollectionList.AnothersTitle', { - anotheruser: this.props.username - }); - } + useEffect(() => { + dispatch(getCollections(username)).then(() => setHasLoadedData(true)); + }, [dispatch, username]); - handleCollectionAdd = (collection) => { - this.props.addToCollection(collection.id, this.props.project.id); + const handleCollectionAdd = (collection) => { + dispatch(addToCollection(collection.id, projectId)); }; - handleCollectionRemove = (collection) => { - this.props.removeFromCollection(collection.id, this.props.project.id); + const handleCollectionRemove = (collection) => { + dispatch(removeFromCollection(collection.id, projectId)); }; - render() { - const { collections, project } = this.props; - const hasCollections = collections.length > 0; - const collectionWithSketchStatus = collections.map((collection) => ({ - ...collection, - url: `/${collection.owner.username}/collections/${collection.id}`, - isAdded: projectInCollection(project, collection) - })); - - let content = null; - - if (this.props.loading && !this.state.hasLoadedData) { - content = ; - } else if (hasCollections) { - content = ( - - ); - } else { - content = this.props.t('AddToCollectionList.Empty'); + const collectionWithSketchStatus = collections.map((collection) => ({ + ...collection, + url: `/${collection.owner.username}/collections/${collection.id}`, + isAdded: collection.items.some((item) => item.projectId === projectId) + })); + + const getContent = () => { + if (showLoader) { + return ; + } else if (collections.length === 0) { + return t('AddToCollectionList.Empty'); } - return ( - - - - {this.getTitle()} - - {content} - - + ); - } -} - -const ProjectShape = PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - createdAt: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - user: PropTypes.shape({ - username: PropTypes.string.isRequired - }).isRequired -}); - -const ItemsShape = PropTypes.shape({ - createdAt: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - project: ProjectShape -}); - -CollectionList.propTypes = { - user: PropTypes.shape({ - username: PropTypes.string, - authenticated: PropTypes.bool.isRequired - }).isRequired, - projectId: PropTypes.string.isRequired, - getCollections: PropTypes.func.isRequired, - getProject: PropTypes.func.isRequired, - addToCollection: PropTypes.func.isRequired, - removeFromCollection: PropTypes.func.isRequired, - collections: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - description: PropTypes.string, - createdAt: PropTypes.string.isRequired, - updatedAt: PropTypes.string.isRequired, - items: PropTypes.arrayOf(ItemsShape) - }) - ).isRequired, - username: PropTypes.string, - loading: PropTypes.bool.isRequired, - project: PropTypes.shape({ - id: PropTypes.string, - owner: PropTypes.shape({ - id: PropTypes.string - }) - }), - t: PropTypes.func.isRequired -}; + }; -CollectionList.defaultProps = { - project: { - id: undefined, - owner: undefined - }, - username: undefined + return ( + + + + {t('AddToCollectionList.Title')} + + {getContent()} + + + ); }; -function mapStateToProps(state, ownProps) { - return { - user: state.user, - collections: getSortedCollections(state), - sorting: state.sorting, - loading: state.loading, - project: ownProps.project || state.project, - projectId: ownProps && ownProps.params ? ownProps.prams.project_id : null - }; -} - -function mapDispatchToProps(dispatch) { - return bindActionCreators( - Object.assign( - {}, - CollectionsActions, - ProjectsActions, - ProjectActions, - ToastActions, - SortingActions - ), - dispatch - ); -} +AddToCollectionList.propTypes = { + projectId: PropTypes.string.isRequired +}; -export default withTranslation()( - connect(mapStateToProps, mapDispatchToProps)(CollectionList) -); +export default AddToCollectionList; \ No newline at end of file diff --git a/client/modules/IDE/components/Searchbar/Searchbar.jsx b/client/modules/IDE/components/Searchbar/Searchbar.jsx index a7c79d1f46..1c2217fd7a 100644 --- a/client/modules/IDE/components/Searchbar/Searchbar.jsx +++ b/client/modules/IDE/components/Searchbar/Searchbar.jsx @@ -1,71 +1,65 @@ +import React, { useState, useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; -import React from 'react'; import { throttle } from 'lodash'; import { withTranslation } from 'react-i18next'; import i18next from 'i18next'; import SearchIcon from '../../../../images/magnifyingglass.svg'; -class Searchbar extends React.Component { - constructor(props) { - super(props); - this.state = { - searchValue: this.props.searchTerm - }; - this.throttledSearchChange = throttle(this.searchChange, 500); - } +const Searchbar = ({ + searchTerm, + setSearchTerm, + resetSearchTerm, + searchLabel, + t +}) => { + const [searchValue, setSearchValue] = useState(searchTerm); - componentWillUnmount() { - this.props.resetSearchTerm(); - } + const throttledSearchChange = useCallback( + throttle((value) => { + setSearchTerm(value.trim()); + }, 500), + [] + ); - handleResetSearch = () => { - this.setState({ searchValue: '' }, () => { - this.props.resetSearchTerm(); - }); + const handleResetSearch = () => { + setSearchValue(''); + resetSearchTerm(); }; - searchChange = () => { - this.props.setSearchTerm(this.state.searchValue.trim()); + const handleSearchChange = (e) => { + const { value } = e.target; + setSearchValue(value); + throttledSearchChange(value.trim()); }; - handleSearchChange = (e) => { - this.setState({ searchValue: e.target.value }, () => { - this.throttledSearchChange(this.state.searchValue.trim()); - }); - }; + useEffect(() => { + setSearchValue(searchTerm); + }, [searchTerm]); - render() { - const { searchValue } = this.state; - return ( -
-
-
- +
+
- ); - } -} + + +
+ ); +}; Searchbar.propTypes = { searchTerm: PropTypes.string.isRequired, diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx index bce30da1dc..7b37c04bf2 100644 --- a/client/modules/IDE/components/SketchList.jsx +++ b/client/modules/IDE/components/SketchList.jsx @@ -1,3 +1,22 @@ + + +Settings + +Hi! Here some our recommendations to get the best out of BLACKBOX: + +Be as clear as possible + +End the question in what language you want the answer to be, e.g: ‘connect to mongodb in python +or you can just +Go to Blackbox +Here are some suggestion (choose one): +Write a function that reads data from a json file +How to delete docs from mongodb in phyton +Connect to mongodb in nodejs +Ask any coding question +send +refresh +Blackbox AI Chat is in beta and Blackbox is not liable for the content generated. By using Blackbox, you acknowledge that you agree to agree to Blackbox's Terms and Privacy Policy import PropTypes from 'prop-types'; import React from 'react'; import { Helmet } from 'react-helmet'; @@ -23,7 +42,6 @@ import getConfig from '../../../utils/getConfig'; import ArrowUpIcon from '../../../images/sort-arrow-up.svg'; import ArrowDownIcon from '../../../images/sort-arrow-down.svg'; import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg'; -import MoreIconSvg from '../../../images/more.svg'; const ROOT_URL = getConfig('API_URL'); @@ -199,11 +217,7 @@ class SketchListRowBase extends React.Component { onFocus={this.onFocusComponent} aria-label={this.props.t('SketchList.ToggleLabelARIA')} > - {this.props.mobile ? ( -