Skip to content

Commit

Permalink
Merge pull request bruin-tennis-consulting#64 from awest25/activeFilters
Browse files Browse the repository at this point in the history
Moved "Active Filters" above points and filters columns.
  • Loading branch information
awest25 authored Feb 7, 2024
2 parents 6929b4d + 5e6bd4d commit 56820b6
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 61 deletions.
84 changes: 43 additions & 41 deletions components/FilterList.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import styles from '../styles/FilterList.module.css';
// This file renammes columns to more human-readable names
import nameMap from '../services/nameMap.js';

const FilterList = ({ pointsData, filterList, setFilterList }) => {
const FilterList = ({ pointsData, filterList, setFilterList, showPercent, showCount }) => {
const keys = Object.keys(nameMap); // Sort the keys array
const uniqueValues = {};

Expand Down Expand Up @@ -40,9 +40,9 @@ const FilterList = ({ pointsData, filterList, setFilterList }) => {
}
}

const removeFilter = (key, value) => {
const updatedFilterList = filterList.filter(([filterKey, filterValue]) => !(filterKey === key && filterValue === value));
setFilterList(updatedFilterList);
//Counts points for each filter
const countFilteredPointsForValue = (key, value) => {
return pointsData.filter(point => point[key] === value).length;
};

// Function to determine if the value is an active filter
Expand All @@ -54,31 +54,22 @@ const FilterList = ({ pointsData, filterList, setFilterList }) => {
const sortedFilterList = filterList.sort((a, b) => a[0].localeCompare(b[0]));

return (
<div>
<div className={styles.activeFilterListContainer}>
Active Filters:
<ul className={styles.activeFilterList}>
{sortedFilterList.map(([key, value]) => (
<li className={styles.activeFilterItem} key={`${key}-${value}`} style={{ cursor: 'pointer' }} onClick={() => removeFilter(key, value)}>
{nameMap[key]}: {value}
</li>
))}
</ul>
</div>
<ul className={styles.availableFilterList}>
{keys.map((key) => {
// Check if key is in the nameMap
if (nameMap.hasOwnProperty(key)) {
return (
<div className={styles.availableFilterItem} key={key} onClick={() => toggleOpen(key)}>
<li>
<strong>
{nameMap[key]}
</strong>
<ul className={styles.filterValuesList} style={{ display: openKey === key ? 'block' : 'none' }}>
{uniqueValues[key].map((value) => (
value !== '' && (
<li className={styles.filterValueItem} key={value} style={{
<>
<div>
<ul className={styles.availableFilterList}>
{keys.map((key) => {
// Check if key is in the nameMap
if (nameMap.hasOwnProperty(key)) {
return (
<div className={styles.availableFilterItem} key={key} onClick={() => toggleOpen(key)}>
<li>
<strong>
{nameMap[key]}
</strong>
<ul className={styles.filterValuesList} style={{ display: openKey === key ? 'block' : 'none' }}>
{uniqueValues[key].map((value) => (
value !== '' && (
<div className={styles.filterValueItem} key={value} style={{
cursor: 'pointer',
backgroundColor: isActiveFilter(key, value) ? '#8BB8E8' : ''
}}
Expand All @@ -89,18 +80,29 @@ const FilterList = ({ pointsData, filterList, setFilterList }) => {
} else {
addFilter(key, value);
}
}}>{value}</li>
)))}
</ul>
</li>
</div>
);
} else {
return null; // Skip rendering if key is not in the map
}
})}
</ul>
</div>
}}>
<li >{value}</li>
{/* Point Percentage */}
{!showCount && showPercent && value && (
<li>{Math.round((countFilteredPointsForValue(key, value) / pointsData.length) * 100)}%</li>
)}
{/* Point Count */}
{showCount && showPercent && value && (
<li>{countFilteredPointsForValue(key, value)} / {pointsData.length}</li>
)}
</div>
)))}
</ul>
</li>
</div>
);
} else {
return null; // Skip rendering if key is not in the map
}
})}
</ul>
</div>
</>
);
}

Expand Down
1 change: 1 addition & 0 deletions components/PointsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const PointsList = ({ pointsData, onPointSelect }) => {
<li className={styles.pointsListItem} key={index} onClick={() => onPointSelect(point.Position)}>
{point.Name}
</li>

))}
</ul>
);
Expand Down
122 changes: 102 additions & 20 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import filterStyles from '../styles/FilterList.module.css';
import Link from 'next/link';
import React, { useState, useEffect } from 'react';
import nameMap from '../services/nameMap.js';
import '../services/initializeFirebase.js'; // Initialize Firebase on the client side

import SearchDropdown from '../components/SearchDropdown';
import VideoPlayer from '../components/VideoPlayer';
import FilterList from '../components/FilterList';
import PointsList from '../components/PointsList';
import Toolbar from '../components/Toolbar.js';
import Select from 'react-select';

export default function Home() {

const [matchData, setMatchData] = useState();
const [filterList, setFilterList] = useState([]);
const [videoObject, setVideoObject] = useState(null);
const [showOptions, setShowOptions] = useState(false);
const [showPercent, setShowPercent] = useState(false);
const [showCount, setShowCount] = useState(false);

// Function to jump to a specific time in the video, given in milliseconds, via the YouTube Player API
const handleJumpToTime = (time) => {
Expand All @@ -26,7 +31,7 @@ export default function Home() {
const returnFilteredPoints = () => {
let filteredPoints = matchData.points;
const filterMap = new Map();

// Group filters by key
filterList.forEach(filter => {
const [key, value] = filter;
Expand All @@ -36,7 +41,7 @@ export default function Home() {
filterMap.set(key, [value]);
}
});

// Apply filters
filterMap.forEach((values, key) => {
if (values.length > 1) {
Expand All @@ -47,10 +52,17 @@ export default function Home() {
filteredPoints = filteredPoints.filter(point => point[key] === values[0]);
}
});

return filteredPoints;
}

//Active Filter
const removeFilter = (key, value) => {
const updatedFilterList = filterList.filter(([filterKey, filterValue]) => !(filterKey === key && filterValue === value));
setFilterList(updatedFilterList);
};

const sortedFilterList = filterList.sort((a, b) => a[0].localeCompare(b[0]));

return (
<div className={styles.container}>
<Head>
Expand All @@ -75,7 +87,7 @@ export default function Home() {
<p>Or get started by:</p>
<ul>
<li>
<Link href="/upload-video">Uploading a video</Link>
<Link href="/upload-video">Uploading a video</Link>
</li>
<li>
<Link href="/tag-match">Tagging a match</Link>
Expand All @@ -90,22 +102,88 @@ export default function Home() {
{matchData && (
<>
{/* Toolbar */}
<Toolbar setMatchData={setMatchData}/>
<h2>{matchData.name}</h2>
<Toolbar setMatchData={setMatchData} />
<div className={styles.headerRow}>
<div className={styles.titleContainer}>
<h2>{matchData.name}</h2>
</div>
{/* Options Container */}
<div className={filterStyles.optionsContainer}>
<svg
className={filterStyles.optionsToggle}
onClick={() => setShowOptions(!showOptions)}
viewBox="0 0 24 24"
fill="black"
xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0">
</g>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round">
</g>
<g id="SVGRepo_iconCarrier">
<path d="M4 18L20 18" stroke="#000000" stroke-width="2" stroke-linecap="round">
</path>
<path d="M4 12L20 12" stroke="#000000" stroke-width="2" stroke-linecap="round">
</path>
<path d="M4 6L20 6" stroke="#000000" stroke-width="2" stroke-linecap="round">
</path>
</g>
</svg>
<div className={filterStyles.optionsList}>
{showOptions && (
<>
<div>
<input
type="checkbox"
id="showOptionsCheckbox"
checked={showPercent}
onChange={() => setShowPercent(!showPercent)}
/>
<label htmlFor="showOptionsCheckbox">Show Percentage</label>
</div>
{showPercent && (
<Select
onChange={(selectedOption) => setShowCount(selectedOption.value === "option2")}
options={[
{ value: "option1", label: "Percent" },
{ value: "option2", label: "Count" }
]}
isSearchable={false}
/>
)}
</>
)}
</div>
</div>
</div>
<div className={styles.mainContent}>
{/* Video Player */}
<div className="videoPlayer">
<VideoPlayer videoId={matchData.videoId} setVideoObject={setVideoObject} />
</div>
<div>
{/* Filter List */}
<div className={filterStyles.activeFilterListContainer}>
Active Filters:
<ul className={filterStyles.activeFilterList}>
{sortedFilterList.map(([key, value]) => (
<li className={filterStyles.activeFilterItem} key={`${key}-${value}`} style={{ cursor: 'pointer' }} onClick={() => removeFilter(key, value)}>
{nameMap[key]}: {value}
</li>
))}
</ul>
</div>
{/* List Holders */}
<div className='listHolder'>
{/* Filter List */}
<div className="filterList">
<FilterList pointsData={matchData.points} filterList={filterList} setFilterList={setFilterList} showPercent={showPercent} showCount={showCount} />
</div>

{/* Filter List */}
<div className="filterList">
<FilterList pointsData={matchData.points} filterList={filterList} setFilterList={setFilterList} />
</div>

{/* Points List */}
<div className="pointsList">
<PointsList pointsData={returnFilteredPoints()} onPointSelect={handleJumpToTime}/>
{/* Points List */}
<div className="pointsList">
<PointsList pointsData={returnFilteredPoints()} onPointSelect={handleJumpToTime} />
</div>
</div>
</div>
</div>
{matchData.pdfUrl && <iframe className={styles.pdfView} src={matchData.pdfUrl} width="90%" height="1550" />}
Expand All @@ -115,7 +193,7 @@ export default function Home() {
</main>

<footer>
Developed by Bruin Sports Analytics for use by UCLA Tennis
Developed by Bruin Sports Analytics for use by UCLA Tennis
</footer>


Expand Down Expand Up @@ -148,22 +226,26 @@ export default function Home() {
.pointsList {
flex: 1; // Takes up 1/3 of the space
margin-top: 1rem;
margin-top: 0rem;
padding: 1rem;
border: 1px solid #ddd;
border-radius: 5px;
overflow-y: auto;
height: 400px;
height: 350px;
}
.filterList {
flex: 1; // Takes up 1/3 of the space
margin-top: 1rem;
margin-top: 0rem;
padding: 1rem;
border: 1px solid #ddd;
border-radius: 5px;
overflow-y: auto;
height: 400px;
height: 350px;
}
.listHolder {
display: flex;
}
footer {
Expand Down
35 changes: 35 additions & 0 deletions styles/FilterList.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
padding: 0;
list-style-type: none;
margin: 0;
overflow-y: scroll;
max-height: 65px;
display: flex;
flex-wrap: wrap;
}

.activeFilterItem {
Expand Down Expand Up @@ -86,6 +90,8 @@
border-radius: 4px; /* Rounded corners for the items */
cursor: pointer; /* Cursor changes to pointer to indicate clickability */
transition: background-color 0.2s ease-in-out; /* Smooth transition for hover effect */
display: flex;
justify-content: space-between;
}

.filterValueItem:hover {
Expand All @@ -104,3 +110,32 @@
border-left: 4px solid #007bff; /* Blue border for active item */
padding-left: 8px; /* Adjust padding to accommodate the border */
}

/* Styles for options menu */
.optionsContainer{
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
max-width: 100%;
box-sizing: border-box;
padding: 2px;
margin: 5px 0;
background-color: #ffffff;
}

.optionsList {
padding: 0;
list-style-type: none;
margin: 0;
display: flex;
flex-direction: column;
}

.optionsToggle{
color: #333;
cursor: pointer;
transition: all 0.2s ease-in-out;
height: 30px;
width: 30px;
}
Loading

0 comments on commit 56820b6

Please sign in to comment.