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 {
 | 
						AddHandler("getMovies", VideoNode, func(info *HandlerInfo) []byte {
 | 
				
			||||||
		var args struct {
 | 
							var args struct {
 | 
				
			||||||
			Tag int
 | 
								Tag  uint32
 | 
				
			||||||
 | 
								Sort uint8
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := FillStruct(&args, info.Data); err != nil {
 | 
							if err := FillStruct(&args, info.Data); err != nil {
 | 
				
			||||||
			fmt.Println(err.Error())
 | 
								fmt.Println(err.Error())
 | 
				
			||||||
			return nil
 | 
								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
 | 
							var query string
 | 
				
			||||||
		// 1 is the id of the ALL tag
 | 
							// 1 is the id of the ALL tag
 | 
				
			||||||
		if args.Tag != 1 {
 | 
							if args.Tag != 1 {
 | 
				
			||||||
			query = fmt.Sprintf(`SELECT movie_id,movie_name,t.tag_name FROM videos
 | 
								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 video_tags vt on videos.movie_id = vt.video_id
 | 
				
			||||||
					INNER JOIN tags t on vt.tag_id = t.tag_id
 | 
										INNER JOIN tags t on vt.tag_id = t.tag_id
 | 
				
			||||||
					WHERE t.tag_id = %d
 | 
										WHERE t.tag_id = %d %s`, args.Tag, SortClause)
 | 
				
			||||||
					ORDER BY likes DESC, create_date, movie_name`, args.Tag)
 | 
					 | 
				
			||||||
		} else {
 | 
							} 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 {
 | 
							var result struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,18 +41,24 @@ class DynamicContentContainer<T> extends React.Component<Props<T>, state<T>> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    componentDidUpdate(prevProps: Props<T>): void {
 | 
					    componentDidUpdate(prevProps: Props<T>): void {
 | 
				
			||||||
        // when source props change force update!
 | 
					        // when source props change force update!
 | 
				
			||||||
        if (prevProps.data.length !== this.props.data.length) {
 | 
					        if (
 | 
				
			||||||
            this.clean();
 | 
					            // 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);
 | 
					                this.loadPreviewBlock(this.InitialLoadNR);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * clear all elements rendered...
 | 
					     * clear all elements rendered...
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    clean(): void {
 | 
					    clean(callback: () => void): void {
 | 
				
			||||||
        this.loadindex = 0;
 | 
					        this.loadindex = 0;
 | 
				
			||||||
        this.setState({loadeditems: []});
 | 
					        this.setState({loadeditems: []}, callback);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render(): JSX.Element {
 | 
					    render(): JSX.Element {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,3 +7,61 @@
 | 
				
			|||||||
    float: right;
 | 
					    float: right;
 | 
				
			||||||
    margin-top: 25px;
 | 
					    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 {shallow} from 'enzyme';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import {HomePage} from './HomePage';
 | 
					import {HomePage, SortBy} from './HomePage';
 | 
				
			||||||
import VideoContainer from '../../elements/VideoContainer/VideoContainer';
 | 
					import VideoContainer from '../../elements/VideoContainer/VideoContainer';
 | 
				
			||||||
import {SearchHandling} from './SearchHandling';
 | 
					import {SearchHandling} from './SearchHandling';
 | 
				
			||||||
 | 
					import exp from "constants";
 | 
				
			||||||
 | 
					import {DefaultTags} from "../../types/GeneralTypes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('<HomePage/>', function () {
 | 
					describe('<HomePage/>', function () {
 | 
				
			||||||
    it('renders without crashing ', function () {
 | 
					    it('renders without crashing ', function () {
 | 
				
			||||||
@@ -83,6 +85,20 @@ describe('<HomePage/>', function () {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        testBtn(tags.first());
 | 
					        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/>', () => {
 | 
					describe('<SearchHandling/>', () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,16 @@ import {RouteComponentProps} from 'react-router';
 | 
				
			|||||||
import SearchHandling from './SearchHandling';
 | 
					import SearchHandling from './SearchHandling';
 | 
				
			||||||
import {VideoTypes} from '../../types/ApiTypes';
 | 
					import {VideoTypes} from '../../types/ApiTypes';
 | 
				
			||||||
import {DefaultTags} from '../../types/GeneralTypes';
 | 
					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 {}
 | 
					interface Props extends RouteComponentProps {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,6 +29,7 @@ interface state {
 | 
				
			|||||||
    subtitle: string;
 | 
					    subtitle: string;
 | 
				
			||||||
    data: VideoTypes.VideoUnloadedType[];
 | 
					    data: VideoTypes.VideoUnloadedType[];
 | 
				
			||||||
    selectionnr: number;
 | 
					    selectionnr: number;
 | 
				
			||||||
 | 
					    sortby: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -42,13 +53,17 @@ export class HomePage extends React.Component<Props, state> {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            subtitle: 'All Videos',
 | 
					            subtitle: 'All Videos',
 | 
				
			||||||
            data: [],
 | 
					            data: [],
 | 
				
			||||||
            selectionnr: 0
 | 
					            selectionnr: 0,
 | 
				
			||||||
 | 
					            sortby: 'Date Added'
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sortState = SortBy.date;
 | 
				
			||||||
 | 
					    tagState = DefaultTags.all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount(): void {
 | 
					    componentDidMount(): void {
 | 
				
			||||||
        // initial get of all videos
 | 
					        // initial get of all videos
 | 
				
			||||||
        this.fetchVideoData(DefaultTags.all.TagId);
 | 
					        this.fetchVideoData();
 | 
				
			||||||
        this.fetchStartData();
 | 
					        this.fetchStartData();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,14 +73,11 @@ export class HomePage extends React.Component<Props, state> {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param tag tag to fetch videos
 | 
					     * @param tag tag to fetch videos
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fetchVideoData(tag: number): void {
 | 
					    fetchVideoData(): void {
 | 
				
			||||||
        callAPI(
 | 
					        callAPI(
 | 
				
			||||||
            APINode.Video,
 | 
					            APINode.Video,
 | 
				
			||||||
            {action: 'getMovies', Tag: tag},
 | 
					            {action: 'getMovies', Tag: this.tagState.TagId, Sort: this.sortState},
 | 
				
			||||||
            (result: {Videos: VideoTypes.VideoUnloadedType[]; TagName: string}) => {
 | 
					            (result: {Videos: VideoTypes.VideoUnloadedType[]; TagName: string}) => {
 | 
				
			||||||
                this.setState({
 | 
					 | 
				
			||||||
                    data: []
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                this.setState({
 | 
					                this.setState({
 | 
				
			||||||
                    data: result.Videos,
 | 
					                    data: result.Videos,
 | 
				
			||||||
                    selectionnr: result.Videos.length
 | 
					                    selectionnr: result.Videos.length
 | 
				
			||||||
@@ -135,32 +147,52 @@ export class HomePage extends React.Component<Props, state> {
 | 
				
			|||||||
                            <Tag
 | 
					                            <Tag
 | 
				
			||||||
                                tagInfo={{TagName: 'All', TagId: DefaultTags.all.TagId}}
 | 
					                                tagInfo={{TagName: 'All', TagId: DefaultTags.all.TagId}}
 | 
				
			||||||
                                onclick={(): void => {
 | 
					                                onclick={(): void => {
 | 
				
			||||||
                                    this.fetchVideoData(DefaultTags.all.TagId);
 | 
					                                    this.tagState = DefaultTags.all;
 | 
				
			||||||
 | 
					                                    this.fetchVideoData();
 | 
				
			||||||
                                    this.setState({subtitle: 'All Videos'});
 | 
					                                    this.setState({subtitle: 'All Videos'});
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Tag
 | 
					                            <Tag
 | 
				
			||||||
                                tagInfo={{TagName: 'Full Hd', TagId: DefaultTags.fullhd.TagId}}
 | 
					                                tagInfo={{TagName: 'Full Hd', TagId: DefaultTags.fullhd.TagId}}
 | 
				
			||||||
                                onclick={(): void => {
 | 
					                                onclick={(): void => {
 | 
				
			||||||
                                    this.fetchVideoData(DefaultTags.fullhd.TagId);
 | 
					                                    this.tagState = DefaultTags.fullhd;
 | 
				
			||||||
 | 
					                                    this.fetchVideoData();
 | 
				
			||||||
                                    this.setState({subtitle: 'Full Hd Videos'});
 | 
					                                    this.setState({subtitle: 'Full Hd Videos'});
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Tag
 | 
					                            <Tag
 | 
				
			||||||
                                tagInfo={{TagName: 'Low Quality', TagId: DefaultTags.lowq.TagId}}
 | 
					                                tagInfo={{TagName: 'Low Quality', TagId: DefaultTags.lowq.TagId}}
 | 
				
			||||||
                                onclick={(): void => {
 | 
					                                onclick={(): void => {
 | 
				
			||||||
                                    this.fetchVideoData(DefaultTags.lowq.TagId);
 | 
					                                    this.tagState = DefaultTags.lowq;
 | 
				
			||||||
 | 
					                                    this.fetchVideoData();
 | 
				
			||||||
                                    this.setState({subtitle: 'Low Quality Videos'});
 | 
					                                    this.setState({subtitle: 'Low Quality Videos'});
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Tag
 | 
					                            <Tag
 | 
				
			||||||
                                tagInfo={{TagName: 'HD', TagId: DefaultTags.hd.TagId}}
 | 
					                                tagInfo={{TagName: 'HD', TagId: DefaultTags.hd.TagId}}
 | 
				
			||||||
                                onclick={(): void => {
 | 
					                                onclick={(): void => {
 | 
				
			||||||
                                    this.fetchVideoData(DefaultTags.hd.TagId);
 | 
					                                    this.tagState = DefaultTags.hd;
 | 
				
			||||||
 | 
					                                    this.fetchVideoData();
 | 
				
			||||||
                                    this.setState({subtitle: 'HD Videos'});
 | 
					                                    this.setState({subtitle: 'HD Videos'});
 | 
				
			||||||
                                }}
 | 
					                                }}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        </SideBar>
 | 
					                        </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} />
 | 
					                        <VideoContainer data={this.state.data} />
 | 
				
			||||||
                        <div className={style.rightinfo} />
 | 
					                        <div className={style.rightinfo} />
 | 
				
			||||||
                    </Route>
 | 
					                    </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);
 | 
					export default withRouter(HomePage);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user