diff --git a/client/app/components/admin/Sidebar.jsx b/client/app/components/admin/Sidebar.jsx index 5d001b0..7d48397 100644 --- a/client/app/components/admin/Sidebar.jsx +++ b/client/app/components/admin/Sidebar.jsx @@ -1,57 +1,213 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; +import Interactive from 'react-interactive'; + +import sidebarCSS from '../styles/adminSidebar.jsx' + class SidebarComponent extends Component { - generateListElements(index, item) { - if (index == this.props.listItemSelected) - return ( - {item.name} - ) - else - return ( - {item.name} - ) - } - - displayRequestedElementsInfo() { - if (this.props.requested_objects) { - let requestedElement = this.props.requested_objects.map((item, index) => { - return ( - - { this.generateListElements(index, item) } - {item.status} - {item.requested_date} - - ) - }) - - return ( - - - - - - - - - - {requestedElement} - -
NameStatusDate
- ) + constructor(props){ + super(props) + // Constructor with states holding the search query and the element of reponse. + this.state = { + filterValue: '', + filterQuery: '', + requestItemsToBeDisplayed: [], + listItemSelected: '', } } - render() { - console.log('sidebar: ', this.props.requested_objects) - return ( -
-

Hello from the sidebar:

- { this.displayRequestedElementsInfo() } -
- ); - } + // Where we wait for api response to be delivered from parent through props + componentWillReceiveProps(props) { + this.state.listItemSelected = props.listItemSelected; + this.displayRequestedElementsInfo(props.requested_objects); + } + + // Inputs a date and returns a text string that matches how long it was since + convertDateToDaysSince(date) { + var oneDay = 24*60*60*1000; + var firstDate = new Date(date); + var secondDate = new Date(); + + var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime()) / oneDay)); + + switch (diffDays) { + case 0: + return 'Today'; + case 1: + return '1 day ago' + default: + return diffDays + ' days ago' + } + } + + // Called from our dropdown, receives a filter string and checks it with status field + // of our request objects. + filterItems(filterValue) { + let filteredRequestElements = this.props.requested_objects.map((item, index) => { + if (item.status === filterValue || filterValue === 'all') + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: filteredRequestElements, + filterValue: filterValue, + }) + } + + + // Updates the internal state of the query filter and updates the list to only + // display names matching the query. This is real-time filtering. + updateFilterQuery(event) { + const query = event.target.value; + + let filteredByQuery = this.props.requested_objects.map((item, index) => { + if (item.name.toLowerCase().indexOf(query.toLowerCase()) != -1) + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: filteredByQuery, + filterQuery: query, + }); + } + + + generateFilterDropdown() { + return ( + + ) + } + + generateFilterSearchbar() { + return ( + this.updateFilterQuery(event)} + value={this.state.filterQuery}/> + ) + } + + // A colored bar indicating the status of a item by color. + generateRequestIndicator(status) { + let statusColor; + + switch (status) { + case 'requested': + // Yellow + statusColor = '#ffe14d'; + break; + case 'downloading': + // Blue + statusColor = '#3fc3f3'; + break; + case 'downloaded': + // Green + statusColor = '#6be682'; + break; + default: + statusColor = 'grey'; + } + + const indicatorCSS = { + width: '100%', + height: '4px', + marginTop: '3px', + backgroundColor: statusColor, + } + + return ( +
+ ) + } + + + generateListElements(index, item) { + if (index == this.state.listItemSelected) { + return ( +
+
+ {item.name } +
+ { this.convertDateToDaysSince(item.requested_date) } +
+
+ Status: { item.status } +
+ Matches found: 0 + { this.generateRequestIndicator(item.status) } +
+ ) + } + else + return ( + + + + {item.name } +
+ { this.convertDateToDaysSince(item.requested_date) } +
+
+ { this.generateRequestIndicator(item.status) } +
+ + ) + } + + // This is our main loader that gets called when we receive api response through props from parent + displayRequestedElementsInfo(requested_objects) { + let requestedElement = requested_objects.map((item, index) => { + if (['requested', 'downloading', 'downloaded'].indexOf(this.state.filterValue) != -1) { + if (item.status === this.state.filterValue){ + return this.generateListElements(index, item); + } + } + + else if (this.state.filterQuery !== '') { + if (item.name.toLowerCase().indexOf(this.state.filterQuery.toLowerCase()) != -1) + return this.generateListElements(index, item); + } + + else + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: requestedElement, + }) + } + + render() { + let bodyCSS = sidebarCSS.body; + if (typeof InstallTrigger !== 'undefined') + bodyCSS.width = '-moz-min-content'; + + return ( +
+

Hello from the sidebar:

+ { this.generateFilterDropdown() } + { this.generateFilterSearchbar() } +
+ { this.state.requestItemsToBeDisplayed } +
+
+ ); + } } export default SidebarComponent; \ No newline at end of file diff --git a/client/app/components/styles/adminSidebar.jsx b/client/app/components/styles/adminSidebar.jsx new file mode 100644 index 0000000..c10fe49 --- /dev/null +++ b/client/app/components/styles/adminSidebar.jsx @@ -0,0 +1,50 @@ +export default { + body: { + backgroundColor: 'white', + width: 'min-content', + }, + + parentElement: { + display: 'inline-block', + width: '300px', + border: '1px solid black', + borderRadius: '2px', + padding: '4px', + margin: '4px', + marginLeft: '4px', + backgroundColor: 'white', + }, + + parentElement_hover: { + marginLeft: '10px', + }, + + parentElement_active: { + textDecoration: 'none', + }, + + parentElement_selected: { + display: 'inline-block', + width: '300px', + border: '1px solid black', + borderRadius: '2px', + padding: '4px', + margin: '4px 0px 4px 4px', + marginLeft: '10px', + backgroundColor: 'white', + }, + + title: { + maxWidth: '70%', + display: 'inline-flex', + }, + + link: { + color: 'black', + textDecoration: 'none', + }, + + rightContainer: { + float: 'right', + }, +} \ No newline at end of file