Skip to content

Commit

Permalink
Merge branch 'main' into viewport_fix_pointlists
Browse files Browse the repository at this point in the history
  • Loading branch information
awest25 authored May 13, 2024
2 parents 054e746 + 9e97e51 commit 2b35f1c
Show file tree
Hide file tree
Showing 17 changed files with 3,031 additions and 2,057 deletions.
55 changes: 42 additions & 13 deletions app/(interactive)/matches/[slug]/page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { usePathname } from 'next/navigation'

import filterStyles from '../../../styles/FilterList.module.css'
Expand All @@ -11,6 +11,7 @@ import PointsList from '../../../components/PointsList';
import ScoreBoard from '../../../components/ScoreBoard';
import MatchTiles from '@/app/components/MatchTiles';
import extractSetScores from '@/app/services/extractSetScores';
import ExtendedList from '../../../components/ExtendedList';

import { doc, getDoc } from 'firebase/firestore';
import { db } from '../../../services/initializeFirebase';
Expand All @@ -34,10 +35,14 @@ const MatchPage = () => {
const [showPercent, setShowPercent] = useState(false);
const [showCount, setShowCount] = useState(false);
const [playingPoint, setPlayingPoint] = useState(null);
const [showPDF, setShowPDF] = useState(false);
const tableRef = useRef(null);
const iframeRef = useRef(null);

const matchSetScores = matchData ? extractSetScores(matchData.points) : {};

// const router = useRouter();
console.log(matchData)
const pathname = usePathname()
const docId = pathname.substring(pathname.lastIndexOf('/') + 1);

Expand Down Expand Up @@ -114,6 +119,20 @@ const MatchPage = () => {
setFilterList(updatedFilterList);
};

const scrollToDetailedList=()=>{
if (tableRef.current) {
tableRef.current.scrollIntoView({ behavior: "smooth" });
}
};

const togglePDF = () => {
setShowPDF(false);
};

const togglePoints = () => {
setShowPDF(true);
};

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

return (
Expand All @@ -130,7 +149,7 @@ const MatchPage = () => {
<div className={styles.mainContent}>
{/* Video Player */}
<div className="videoPlayer">
<div>
<div ref={iframeRef}>
<VideoPlayer videoId={matchData.videoId} setVideoObject={setVideoObject} />
</div>
</div>
Expand Down Expand Up @@ -196,20 +215,28 @@ const MatchPage = () => {
<div className="pointsList">
<PointsList pointsData={returnFilteredPoints()} onPointSelect={handleJumpToTime} clientTeam={matchData.clientTeam} opponentTeam={matchData.opponentTeam}/>
</div>
<div style={{ padding: '0.5vw', paddingLeft: '5vw' }}>
<button className={styles.viewDetailedListButton} onClick={() => scrollToDetailedList()}>View Detailed List</button>
</div>
{/* Score display */}
<div className="scoreboard">
<ScoreBoard names={matchData.name} playData={playingPoint} {...matchSetScores}/>
</div>
</div>



</div>
</div>
</div>
<br></br>
{matchData.pdfUrl && <iframe className={styles.pdfView} src={matchData.pdfUrl} width="90%" height="1550" />}
<br></br>
<div className={styles.toggle}>
<button onClick={() => togglePDF()} className={showPDF ? styles.toggle_buttona_inactive : styles.toggle_buttona_active}>Points</button>
<button onClick={() => togglePoints()} className={showPDF ? styles.toggle_buttonb_active : styles.toggle_buttonb_inactive}>Key Stats & Visuals</button>
{showPDF ? (
<iframe className={styles.pdfView} src={matchData.pdfUrl} width="90%" height="1550" />
) : (
<div ref={tableRef} className={styles.ExtendedList}>
<ExtendedList pointsData={returnFilteredPoints()} clientTeam={matchData.clientTeam} opponentTeam={matchData.opponentTeam} onPointSelect={handleJumpToTime} iframe = {iframeRef}/>
</div>
)}
</div>
</>
)}

Expand Down Expand Up @@ -246,7 +273,7 @@ const MatchPage = () => {
margin-top: 0;
padding: 1vw;
margin-left: 1vw;
border: 0.1vw solid #ddd;
border: 1px solid #ddd;
border-radius: 1.5vw;
overflow-y: auto;
height: 30vw;
Expand All @@ -255,12 +282,14 @@ const MatchPage = () => {
.filterList {
flex: 2; // Takes up 1/3 of the space
margin-top: 0rem;
padding: 1rem;
margin-top: 0;
padding: 1vw;
margin-left: 1vw;
border: 1px solid #ddd;
border-radius: 15px;
border-radius: 1.5vw;
overflow-y: auto;
height: 350px;
height: 30vw;
background: linear-gradient(to bottom, #ffffff, #fafafa);
}
.jumpList {
width: 25vw;
Expand Down
111 changes: 67 additions & 44 deletions app/(interactive)/tag-match/[slug]/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import styles from '../../../styles/TagMatch.module.css';
import { usePathname } from 'next/navigation'
import getMatchInfo from '../../../services/getMatchInfo.js';
import updateMatchDocument from '../../../services/updateMatchDocument.js';
import TennisCourtSVG from '@/app/components/TennisCourtSVG';

export default function TagMatch() {
// const router = useRouter();
Expand All @@ -20,6 +21,8 @@ export default function TagMatch() {
const [currentPage, setCurrentPage] = useState('ServerName'); // TODO: the default should continue from what was filled in last
const [taggerHistory, setTaggerHistory] = useState([]); // Array to hold the history of states
const [isPublished, setIsPublished] = useState(false); // TODO: impliment this functionality (only show published matches)
const [matchMetadata, setMatchMetadata] = useState({});

const [popUp, setPopUp] = useState([]);
const [isVisible, setIsVisible] = useState(false);
const [displayPopUp, setDisplayPopUp] = useState(false);
Expand Down Expand Up @@ -48,6 +51,10 @@ export default function TagMatch() {
return { ...oldTableState, rows: [] };
});
}

// Set the metadata to matchDocument but without the 'points'
const { points, ...metadata } = matchDocument;
setMatchMetadata(metadata);
});
}, [matchId]);

Expand Down Expand Up @@ -147,27 +154,27 @@ export default function TagMatch() {
}

const addNewRowAndSync = () => {
pullAndPushRows();
setTableState(oldTableState => {
pullAndPushRows(oldTableState.rows, null);

let newTimestamp = getVideoTimestamp();
let newTimestamp = getVideoTimestamp();

// Create a new row object with the required structure
const newRow = columnNames.reduce((acc, columnName) => {
// Check if a row already exists with the new timestamp
let existingRow = tableState.rows.find(row => row.pointStartTime === newTimestamp);
// Create a new row object with the required structure
const newRow = columnNames.reduce((acc, columnName) => {
// Check if a row already exists with the new timestamp
let existingRow = tableState.rows.find(row => row.pointStartTime === newTimestamp);

while (existingRow !== undefined) {
// If a row already exists, increment the timestamp by 1
newTimestamp += 1;
existingRow = tableState.rows.find(row => row.pointStartTime === newTimestamp);
}
while (existingRow !== undefined) {
// If a row already exists, increment the timestamp by 1
newTimestamp += 1;
existingRow = tableState.rows.find(row => row.pointStartTime === newTimestamp);
}

acc[columnName] = columnName === 'pointStartTime' ? newTimestamp : '';
return acc;
}, {});
acc[columnName] = columnName === 'pointStartTime' ? newTimestamp : '';
return acc;
}, {});

// Add new row and sort
setTableState(oldTableState => {
// Add new row and sort
const updatedTable = [...oldTableState.rows, newRow];
// Sort the table by 'pointStartTime'
updatedTable.sort((a, b) => a.pointStartTime - b.pointStartTime);
Expand All @@ -188,7 +195,7 @@ export default function TagMatch() {
const newActiveRowIndex = rowIndex === oldTableState.activeRowIndex ? oldTableState.activeRowIndex - 1 : oldTableState.activeRowIndex;
return { rows: updatedTable, activeRowIndex: newActiveRowIndex };
});
pullAndPushRows(rowToDeleteTimestamp);
pullAndPushRows(tableState.rows, rowToDeleteTimestamp);
}


Expand Down Expand Up @@ -249,9 +256,9 @@ export default function TagMatch() {
}, [displayPopUp]);


const pullAndPushRows = async (rowToDeleteTimestamp = null) => {
const pullAndPushRows = async (rowState, rowToDeleteTimestamp = null) => {
try {
const tableSnapshot = [...tableState.rows]; // Snapshot of the table before fetching updates
const tableSnapshot = [...rowState]; // Snapshot of the table before fetching updates
// Fetch the current document state from the database
const matchDocument = await getMatchInfo(matchId);
const incomingRows = matchDocument.points ?? [];
Expand Down Expand Up @@ -308,7 +315,7 @@ export default function TagMatch() {

// Toggle the publushed state of the match
const togglePublish = async () => {
pullAndPushRows();
pullAndPushRows(tableState.rows, null);
try {
await updateMatchDocument(matchId, {
published: !isPublished
Expand Down Expand Up @@ -352,26 +359,43 @@ export default function TagMatch() {
const buttonData = getTaggerButtonData(updateActiveRow, addNewRowAndSync, setCurrentPage);

const handleImageClick = (event) => {
console.log("event: ", event);
const courtWidthInInches = 432; // The court is 36 feet wide, or 432 inches
const courtHeightInInches = 936; // The court is 78 feet long, or 936 inches
// const courtHeightInInches = 936; // The court is 78 feet long, or 936 inches

// The current SVG has the actual in width of the court as 360 out of 600 total
// The height is 780 out of 1080 total
// This makes the ratio 0.6 for width and 0.7222 for height
const xRatio = 0.6;
// const yRatio = 0.7222;

// Get the bounding rectangle of the SVG container
const rect = event.currentTarget.getBoundingClientRect();

// Get the bounding rectangle of the target (image)
const rect = event.target.getBoundingClientRect();
const widthOfCourt = rect.width; // Using rect.width is more reliable
const heightOfCourt = rect.height;

const widthOfCourt = rect.right - rect.left;
const heightOfCourt = rect.bottom - rect.top;
const inchesPerPixel = courtWidthInInches / (widthOfCourt * xRatio); // This is slightly wrong bc it rounds at some point?

// Calculate the click position relative to the image
// Calculate the click position relative to the SVG container
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;

// Calculate the click position relative to the court
const xInches = Math.round((x / widthOfCourt) * courtWidthInInches);
const yInches = Math.round((y / heightOfCourt) * courtHeightInInches);
// Find how far from the center the click was
const xFromCenter = x - widthOfCourt / 2;
const yFromCenter = y - heightOfCourt / 2;

// Calculate the click position in inches
let xInches = Math.round(xFromCenter * inchesPerPixel);
let yInches = Math.round(yFromCenter * inchesPerPixel) * -1;

// Convert -0 to 0
xInches = Object.is(xInches, -0) ? 0 : xInches;
yInches = Object.is(yInches, -0) ? 0 : yInches;

console.log("xInches: " + xInches + " yInches: " + yInches);
return { 'x': xInches, 'y': yInches };
}
return { x: xInches, y: yInches };
};


return (
Expand All @@ -391,35 +415,34 @@ export default function TagMatch() {
<div>
<p>{currentPage}</p>
{buttonData[currentPage].map((button, index) => {
return button.courtImage === true ? (
return button.courtImage ? (
<div>
<p>{button.label}</p>
<img
src="/images/Tennis_Court_Full.png"
alt="tennis court"
onClick={(event) => {
<TennisCourtSVG className={styles.courtImage} courtType={button.courtImage} handleImageClick={(event) => {
setPopUp([])
saveToHistory();
let data = handleImageClick(event); // returns data.x and data.y coordinates
let data = matchMetadata;
// add data.x and data.y to the data object
const { x, y } = handleImageClick(event);
data.x = x;
data.y = y;
data.table = tableState.rows;
data.activeRowIndex = tableState.activeRowIndex;
data.videoTimestamp = getVideoTimestamp();
button.action(data);
showPopUp()
}}
style={{ width: "10%" }}
/>
showPopUp();
}} />
</div>
) : (
<button className={styles.customButton} key={index} onClick={() => {
setPopUp([])
saveToHistory();
let data = {};
let data = matchMetadata;
data.table = tableState.rows;
data.activeRowIndex = tableState.activeRowIndex;
data.videoTimestamp = getVideoTimestamp();
button.action(data);
showPopUp()
showPopUp();
}}>
{button.label}
</button>
Expand Down Expand Up @@ -465,7 +488,7 @@ export default function TagMatch() {
<td key={colIndex}>
<input
type="text"
value={row[columnName] || ''}
value={row[columnName] === undefined || row[columnName] === null ? '' : row[columnName]}
onChange={(event) => {
saveToHistory(); // Save the current state to history first
changeRowValue(rowIndex, columnName, event.target.value); // Then handle the change
Expand Down
Loading

0 comments on commit 2b35f1c

Please sign in to comment.