diff --git a/packages/components/List/index.js b/packages/components/List/index.js new file mode 100644 index 0000000..f1c9083 --- /dev/null +++ b/packages/components/List/index.js @@ -0,0 +1,105 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import SimpleCard from '../SimpleCard'; +import SearchBar from '../SearchBar'; + +const List = ({ projectItems, handleEdit, handleDelete }) => { + + const [ items, setItems ] = useState(projectItems); + + const includesText = (text, subsetText) => { + return text.toLowerCase().includes(subsetText.toLowerCase().trim()); + }; + + const handleDeleteItem = async (itemId) => { + const updatedList = items.filter((item) => { + return item.id !== itemId; + }); + handleDelete(itemId); + setItems(updatedList); + }; + + // This is the original handleDelete, which took place at the page level: + // https://github.com/bbc/digital-paper-edit-client/blob/ba1924e89592fc8cd75fcb1e450ea15bc2599d95/src/Components/Projects/index.js + // + // const result = await ApiWrapper.deleteProject(itemId); + // if (result.ok) { + // const newItemsList = this.state.items.filter((p) => { + // return p.id !== itemId; + // }); + // this.setState({ items: newItemsList }); + // } else { + // // TODO: some error handling, error message saying something went wrong + // } + + const handleDisplay = (item, searchText) => { + if ( + includesText(item.title, searchText) || + includesText(item.description, searchText) + ) { + item.display = true; + } else { + item.display = false; + } + + return item; + }; + + const handleSearchItem = searchText => { + const results = items.filter(item => handleDisplay(item, searchText)); + setItems(results); + }; + + const listItems = items.map((item) => { + if (item.display) { + return ( + + );} + + return null; + }).filter(item => { + return item !== null; + }); + + return ( +
+ {items !== null && items.length !== 0 ? : null} + {listItems} +
+ ); +}; + +List.propTypes = { + projectItems: PropTypes.array.isRequired, + handleEdit: PropTypes.func.isRequired, + handleDelete: PropTypes.func.isRequired, +}; + +List.defaultProps = { + projectItems: { + itemOne: { + id: '1234', + key: 'abc123', + title: 'Sample Simple Card Title One', + description: 'This is a sample card description. This is fun!', + display: true, + url: '/projects/1/transcripts/5678' + } + }, + handleEdit: () => { + console.log('Edit button clicked'); + }, + handleDelete: () => { + console.log('Delete button clicked'); + }, +}; + +export default List; \ No newline at end of file diff --git a/packages/components/List/stories/index.stories.js b/packages/components/List/stories/index.stories.js new file mode 100644 index 0000000..28c2670 --- /dev/null +++ b/packages/components/List/stories/index.stories.js @@ -0,0 +1,49 @@ +import React from 'react'; + +import { storiesOf } from '@storybook/react'; +import { actions } from '@storybook/addon-actions'; +import StoryRouter from 'storybook-react-router'; +import List from '../index.js'; +import SearchBar from '../../SearchBar'; + +import { item, cardActions } from '../../SimpleCard/stories/index.stories.js'; + +export const searchActions = actions({ handleSearch: 'Handle search' }); + +export const items = [ { + ...item, + id: '1234', + key: 'abc123', + title: 'Sample Simple Card Title One', + description: 'This is a sample card description. This is fun!', + display: true, +}, { ...item, + id: '5678', + key: 'def456', + title: 'Sample Simple Card Title Two', + description: 'This is a sample card description. This is fun!', + display: true, + url: '/projects/1/transcripts/5678' +} ]; + +storiesOf('List', module) + .addDecorator(StoryRouter()) + .add('With Simple Cards', () => + + ); + +storiesOf('List/Search Bar', module) + .addDecorator(StoryRouter()) + .add('Default', () => { + return ( +
+ +
+ ); + }); \ No newline at end of file diff --git a/packages/components/SearchBar/index.js b/packages/components/SearchBar/index.js new file mode 100644 index 0000000..858694a --- /dev/null +++ b/packages/components/SearchBar/index.js @@ -0,0 +1,52 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import InputGroup from 'react-bootstrap/InputGroup'; +import FormControl from 'react-bootstrap/FormControl'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faSearch, +} from '@fortawesome/free-solid-svg-icons'; + +const SearchBar = ({ handleSearch }) => { + + const [ toggleSearchInput, setToggleShowInput ] = useState(false); + + const [ searchValue, setSearchValue ] = useState(''); + + const handleSearchInputChanges = (e) => { + handleSearch(e.target.value); + setSearchValue(e.target.value); + }; + + return ( + + setToggleShowInput(!toggleSearchInput) } + > + + + + + + + ); +}; + +SearchBar.propTypes = { + handleSearch: PropTypes.func.isRequired, +}; + +SearchBar.defaultProps = { + handleSearch: () => { + console.log('Searching...'); + }, +}; + +export default SearchBar; \ No newline at end of file diff --git a/packages/components/SimpleCard/index.js b/packages/components/SimpleCard/index.js index 23b3366..0607e07 100644 --- a/packages/components/SimpleCard/index.js +++ b/packages/components/SimpleCard/index.js @@ -14,30 +14,26 @@ import 'bootstrap-css-only/css/bootstrap.css'; class SimpleCard extends Component { handleDelete = () => { - const confirmDeleteText = "Click OK if you wish to delete or cancel if you don't"; - const cancelDeleteText = "All is good, it was not deleted"; - const confirmationPrompt = confirm(confirmDeleteText); - - if (confirmationPrompt) { - this.props.handleDelete ? this.props.handleDelete(this.props.id) : alert(cancelDeleteText); - } + const confirmDeleteText = "Click OK if you wish to delete or cancel if you don't"; + const cancelDeleteText = 'All is good, it was not deleted'; + const confirmationPrompt = confirm(confirmDeleteText); + + if (confirmationPrompt) { + this.props.handleDelete ? this.props.handleDelete(this.props.id) : alert(cancelDeleteText); + } }; handleEdit = () => { this.props.handleEdit(this.props.id); } - showLinkPath = () => { - return this.props.showLinkPath(this.props.id) || ''; - } - render() { return ( - + {this.props.title} @@ -86,6 +82,7 @@ SimpleCard.propTypes = { key: PropTypes.string.isRequired, id: PropTypes.string.isRequired, title: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, description: PropTypes.string, handleEdit: PropTypes.func, handleDelete: PropTypes.func, @@ -103,9 +100,6 @@ SimpleCard.defaultProps = { handleDelete: () => { console.log('Delete button clicked'); }, - showLinkPath: () => { - console.log('Card clicked'); - } }; export default SimpleCard; diff --git a/packages/components/SimpleCard/stories/index.stories.js b/packages/components/SimpleCard/stories/index.stories.js index 0d821ee..3e11c03 100644 --- a/packages/components/SimpleCard/stories/index.stories.js +++ b/packages/components/SimpleCard/stories/index.stories.js @@ -10,9 +10,10 @@ export const item = { key: 'abc123', title: 'Sample Simple Card Title', description: 'This is a sample card description. This is fun!', + url: '/projects/1/transcripts/1234' }; -const cardActions = actions({ handleEdit: 'Edit button clicked', handleDelete: 'Delete button clicked', showLinkPath: 'Card clicked' }); +export const cardActions = actions({ handleEdit: 'Edit button clicked', handleDelete: 'Delete button clicked' }); storiesOf('Simple Card', module) .addDecorator(StoryRouter()) @@ -24,8 +25,9 @@ storiesOf('Simple Card', module) id={ item.id } title={ item.title } description={ item.description } + url={ item.url } { ...cardActions } /> ); - }); \ No newline at end of file + });