Merge branch 'filterbutton' into 'master'
SortBY feature See merge request lukas/openmediacenter!49
This commit is contained in:
		@@ -31,23 +31,46 @@ func getVideoHandlers() {
 | 
			
		||||
	 */
 | 
			
		||||
	AddHandler("getMovies", VideoNode, func(info *HandlerInfo) []byte {
 | 
			
		||||
		var args struct {
 | 
			
		||||
			Tag int
 | 
			
		||||
			Tag  uint32
 | 
			
		||||
			Sort uint8
 | 
			
		||||
		}
 | 
			
		||||
		if err := FillStruct(&args, info.Data); err != nil {
 | 
			
		||||
			fmt.Println(err.Error())
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const (
 | 
			
		||||
			date   = iota
 | 
			
		||||
			likes  = iota
 | 
			
		||||
			random = iota
 | 
			
		||||
			names  = iota
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		var SortClause string
 | 
			
		||||
		switch args.Sort {
 | 
			
		||||
		case date:
 | 
			
		||||
			SortClause = "ORDER BY create_date DESC, movie_name"
 | 
			
		||||
			break
 | 
			
		||||
		case likes:
 | 
			
		||||
			SortClause = "ORDER BY likes DESC"
 | 
			
		||||
			break
 | 
			
		||||
		case random:
 | 
			
		||||
			SortClause = "ORDER BY RAND()"
 | 
			
		||||
			break
 | 
			
		||||
		case names:
 | 
			
		||||
			SortClause = "ORDER BY movie_name"
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var query string
 | 
			
		||||
		// 1 is the id of the ALL tag
 | 
			
		||||
		if args.Tag != 1 {
 | 
			
		||||
			query = fmt.Sprintf(`SELECT movie_id,movie_name,t.tag_name FROM videos
 | 
			
		||||
					INNER JOIN video_tags vt on videos.movie_id = vt.video_id
 | 
			
		||||
					INNER JOIN tags t on vt.tag_id = t.tag_id
 | 
			
		||||
					WHERE t.tag_id = %d
 | 
			
		||||
					ORDER BY likes DESC, create_date, movie_name`, args.Tag)
 | 
			
		||||
					WHERE t.tag_id = %d %s`, args.Tag, SortClause)
 | 
			
		||||
		} else {
 | 
			
		||||
			query = "SELECT movie_id,movie_name, (SELECT 'All' as tag_name) FROM videos ORDER BY create_date DESC, movie_name"
 | 
			
		||||
			query = fmt.Sprintf("SELECT movie_id,movie_name, (SELECT 'All' as tag_name) FROM videos %s", SortClause)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var result struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -41,18 +41,24 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate(prevProps: Props<T>): void {
 | 
			
		||||
        // when source props change force update!
 | 
			
		||||
        if (prevProps.data.length !== this.props.data.length) {
 | 
			
		||||
            this.clean();
 | 
			
		||||
        if (
 | 
			
		||||
            // diff the two arrays
 | 
			
		||||
            this.props.data
 | 
			
		||||
                .filter((x) => !prevProps.data.includes(x))
 | 
			
		||||
                .concat(prevProps.data.filter((x) => !this.props.data.includes(x))).length !== 0
 | 
			
		||||
        ) {
 | 
			
		||||
            this.clean((): void => {
 | 
			
		||||
                this.loadPreviewBlock(this.InitialLoadNR);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * clear all elements rendered...
 | 
			
		||||
     */
 | 
			
		||||
    clean(): void {
 | 
			
		||||
    clean(callback: () => void): void {
 | 
			
		||||
        this.loadindex = 0;
 | 
			
		||||
        this.setState({loadeditems: []});
 | 
			
		||||
        this.setState({loadeditems: []}, callback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): JSX.Element {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,3 +7,61 @@
 | 
			
		||||
    float: right;
 | 
			
		||||
    margin-top: 25px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sortbyLabel {
 | 
			
		||||
    color: grey;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
    margin-left: 25px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Style The Dropdown Button */
 | 
			
		||||
.dropbtn {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    color: white;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The container <div> - needed to position the dropdown content */
 | 
			
		||||
.dropdown {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dropdown Content (Hidden by Default) */
 | 
			
		||||
.dropdownContent {
 | 
			
		||||
    display: none;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    background-color: #f9f9f9;
 | 
			
		||||
    min-width: 160px;
 | 
			
		||||
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Links inside the dropdown */
 | 
			
		||||
.dropdownContent span {
 | 
			
		||||
    color: black;
 | 
			
		||||
    padding: 12px 16px;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    display: block;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Change color of dropdown links on hover */
 | 
			
		||||
.dropdownContent span:hover {
 | 
			
		||||
    background-color: #f1f1f1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Show the dropdown menu on hover */
 | 
			
		||||
.dropdown:hover .dropdownContent {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Change the background color of the dropdown button when the dropdown content is shown */
 | 
			
		||||
.dropdown:hover .dropbtn {
 | 
			
		||||
    background-color: #3574fe;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import {shallow} from 'enzyme';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import {HomePage} from './HomePage';
 | 
			
		||||
import {HomePage, SortBy} from './HomePage';
 | 
			
		||||
import VideoContainer from '../../elements/VideoContainer/VideoContainer';
 | 
			
		||||
import {SearchHandling} from './SearchHandling';
 | 
			
		||||
import exp from "constants";
 | 
			
		||||
import {DefaultTags} from "../../types/GeneralTypes";
 | 
			
		||||
 | 
			
		||||
describe('<HomePage/>', function () {
 | 
			
		||||
    it('renders without crashing ', function () {
 | 
			
		||||
@@ -83,6 +85,20 @@ describe('<HomePage/>', function () {
 | 
			
		||||
 | 
			
		||||
        testBtn(tags.first());
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('test sortby type change', function () {
 | 
			
		||||
        const wrapper = shallow(<HomePage/>);
 | 
			
		||||
 | 
			
		||||
        // expect those default values
 | 
			
		||||
        expect(wrapper.state().sortby).toBe('Date Added');
 | 
			
		||||
        expect(wrapper.instance().sortState).toBe(SortBy.date);
 | 
			
		||||
        expect(wrapper.instance().tagState).toBe(DefaultTags.all);
 | 
			
		||||
 | 
			
		||||
        wrapper.instance().onDropDownItemClick(SortBy.name, 'namesort');
 | 
			
		||||
 | 
			
		||||
        expect(wrapper.state().sortby).toBe('namesort');
 | 
			
		||||
        expect(wrapper.instance().sortState).toBe(SortBy.name);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('<SearchHandling/>', () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,16 @@ import {RouteComponentProps} from 'react-router';
 | 
			
		||||
import SearchHandling from './SearchHandling';
 | 
			
		||||
import {VideoTypes} from '../../types/ApiTypes';
 | 
			
		||||
import {DefaultTags} from '../../types/GeneralTypes';
 | 
			
		||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
 | 
			
		||||
import {faSortDown} from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line no-shadow
 | 
			
		||||
export enum SortBy {
 | 
			
		||||
    date,
 | 
			
		||||
    likes,
 | 
			
		||||
    random,
 | 
			
		||||
    name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Props extends RouteComponentProps {}
 | 
			
		||||
 | 
			
		||||
@@ -19,6 +29,7 @@ interface state {
 | 
			
		||||
    subtitle: string;
 | 
			
		||||
    data: VideoTypes.VideoUnloadedType[];
 | 
			
		||||
    selectionnr: number;
 | 
			
		||||
    sortby: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -42,13 +53,17 @@ export class HomePage extends React.Component<Props, state> {
 | 
			
		||||
            },
 | 
			
		||||
            subtitle: 'All Videos',
 | 
			
		||||
            data: [],
 | 
			
		||||
            selectionnr: 0
 | 
			
		||||
            selectionnr: 0,
 | 
			
		||||
            sortby: 'Date Added'
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sortState = SortBy.date;
 | 
			
		||||
    tagState = DefaultTags.all;
 | 
			
		||||
 | 
			
		||||
    componentDidMount(): void {
 | 
			
		||||
        // initial get of all videos
 | 
			
		||||
        this.fetchVideoData(DefaultTags.all.TagId);
 | 
			
		||||
        this.fetchVideoData();
 | 
			
		||||
        this.fetchStartData();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -58,14 +73,11 @@ export class HomePage extends React.Component<Props, state> {
 | 
			
		||||
     *
 | 
			
		||||
     * @param tag tag to fetch videos
 | 
			
		||||
     */
 | 
			
		||||
    fetchVideoData(tag: number): void {
 | 
			
		||||
    fetchVideoData(): void {
 | 
			
		||||
        callAPI(
 | 
			
		||||
            APINode.Video,
 | 
			
		||||
            {action: 'getMovies', Tag: tag},
 | 
			
		||||
            {action: 'getMovies', Tag: this.tagState.TagId, Sort: this.sortState},
 | 
			
		||||
            (result: {Videos: VideoTypes.VideoUnloadedType[]; TagName: string}) => {
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    data: []
 | 
			
		||||
                });
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    data: result.Videos,
 | 
			
		||||
                    selectionnr: result.Videos.length
 | 
			
		||||
@@ -135,32 +147,52 @@ export class HomePage extends React.Component<Props, state> {
 | 
			
		||||
                            <Tag
 | 
			
		||||
                                tagInfo={{TagName: 'All', TagId: DefaultTags.all.TagId}}
 | 
			
		||||
                                onclick={(): void => {
 | 
			
		||||
                                    this.fetchVideoData(DefaultTags.all.TagId);
 | 
			
		||||
                                    this.tagState = DefaultTags.all;
 | 
			
		||||
                                    this.fetchVideoData();
 | 
			
		||||
                                    this.setState({subtitle: 'All Videos'});
 | 
			
		||||
                                }}
 | 
			
		||||
                            />
 | 
			
		||||
                            <Tag
 | 
			
		||||
                                tagInfo={{TagName: 'Full Hd', TagId: DefaultTags.fullhd.TagId}}
 | 
			
		||||
                                onclick={(): void => {
 | 
			
		||||
                                    this.fetchVideoData(DefaultTags.fullhd.TagId);
 | 
			
		||||
                                    this.tagState = DefaultTags.fullhd;
 | 
			
		||||
                                    this.fetchVideoData();
 | 
			
		||||
                                    this.setState({subtitle: 'Full Hd Videos'});
 | 
			
		||||
                                }}
 | 
			
		||||
                            />
 | 
			
		||||
                            <Tag
 | 
			
		||||
                                tagInfo={{TagName: 'Low Quality', TagId: DefaultTags.lowq.TagId}}
 | 
			
		||||
                                onclick={(): void => {
 | 
			
		||||
                                    this.fetchVideoData(DefaultTags.lowq.TagId);
 | 
			
		||||
                                    this.tagState = DefaultTags.lowq;
 | 
			
		||||
                                    this.fetchVideoData();
 | 
			
		||||
                                    this.setState({subtitle: 'Low Quality Videos'});
 | 
			
		||||
                                }}
 | 
			
		||||
                            />
 | 
			
		||||
                            <Tag
 | 
			
		||||
                                tagInfo={{TagName: 'HD', TagId: DefaultTags.hd.TagId}}
 | 
			
		||||
                                onclick={(): void => {
 | 
			
		||||
                                    this.fetchVideoData(DefaultTags.hd.TagId);
 | 
			
		||||
                                    this.tagState = DefaultTags.hd;
 | 
			
		||||
                                    this.fetchVideoData();
 | 
			
		||||
                                    this.setState({subtitle: 'HD Videos'});
 | 
			
		||||
                                }}
 | 
			
		||||
                            />
 | 
			
		||||
                        </SideBar>
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <span className={style.sortbyLabel}>Sort By: </span>
 | 
			
		||||
                            <div className={style.dropdown}>
 | 
			
		||||
                                <span className={style.dropbtn}>
 | 
			
		||||
                                    <span>{this.state.sortby}</span>
 | 
			
		||||
                                    <FontAwesomeIcon style={{marginLeft: 3, paddingBottom: 3}} icon={faSortDown} size='1x' />
 | 
			
		||||
                                </span>
 | 
			
		||||
                                <div className={style.dropdownContent}>
 | 
			
		||||
                                    <span onClick={(): void => this.onDropDownItemClick(SortBy.date, 'Date Added')}>Date Added</span>
 | 
			
		||||
                                    <span onClick={(): void => this.onDropDownItemClick(SortBy.likes, 'Most likes')}>Most likes</span>
 | 
			
		||||
                                    <span onClick={(): void => this.onDropDownItemClick(SortBy.random, 'Random')}>Random</span>
 | 
			
		||||
                                    <span onClick={(): void => this.onDropDownItemClick(SortBy.name, 'Name')}>Name</span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <VideoContainer data={this.state.data} />
 | 
			
		||||
                        <div className={style.rightinfo} />
 | 
			
		||||
                    </Route>
 | 
			
		||||
@@ -168,6 +200,17 @@ export class HomePage extends React.Component<Props, state> {
 | 
			
		||||
            </>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * click handler for sortby dropdown item click
 | 
			
		||||
     * @param type type of sort action
 | 
			
		||||
     * @param name new header title
 | 
			
		||||
     */
 | 
			
		||||
    onDropDownItemClick(type: SortBy, name: string): void {
 | 
			
		||||
        this.sortState = type;
 | 
			
		||||
        this.setState({sortby: name});
 | 
			
		||||
        this.fetchVideoData();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default withRouter(HomePage);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user