diff options
Diffstat (limited to 'frontend/src/components/Summary.tsx')
| -rw-r--r-- | frontend/src/components/Summary.tsx | 300 |
1 files changed, 187 insertions, 113 deletions
diff --git a/frontend/src/components/Summary.tsx b/frontend/src/components/Summary.tsx index 7da2f1e..ba91f57 100644 --- a/frontend/src/components/Summary.tsx +++ b/frontend/src/components/Summary.tsx | |||
| @@ -1,193 +1,267 @@ | |||
| 1 | import React from 'react'; | 1 | import React from "react"; |
| 2 | import ReactMarkdown from 'react-markdown'; | 2 | import ReactMarkdown from "react-markdown"; |
| 3 | 3 | ||
| 4 | import { MapSummary } from '@customTypes/Map'; | 4 | import { MapSummary } from "@customTypes/Map"; |
| 5 | import "@css/Maps.css" | ||
| 6 | 5 | ||
| 7 | interface SummaryProps { | 6 | interface SummaryProps { |
| 8 | selectedRun: number | 7 | selectedRun: number; |
| 9 | setSelectedRun: (x: number) => void; | 8 | setSelectedRun: (x: number) => void; |
| 10 | data: MapSummary; | 9 | data: MapSummary; |
| 11 | } | 10 | } |
| 12 | 11 | ||
| 13 | const Summary: React.FC<SummaryProps> = ({ selectedRun, setSelectedRun, data }) => { | 12 | const Summary: React.FC<SummaryProps> = ({ |
| 14 | 13 | selectedRun, | |
| 14 | setSelectedRun, | ||
| 15 | data, | ||
| 16 | }) => { | ||
| 15 | const [selectedCategory, setSelectedCategory] = React.useState<number>(1); | 17 | const [selectedCategory, setSelectedCategory] = React.useState<number>(1); |
| 16 | const [historySelected, setHistorySelected] = React.useState<boolean>(false); | 18 | const [historySelected, setHistorySelected] = React.useState<boolean>(false); |
| 17 | 19 | ||
| 18 | function _select_run(idx: number, category_id: number) { | 20 | const _select_run = React.useCallback( |
| 19 | let r = document.querySelectorAll("button.record"); | 21 | (idx: number, category_id: number) => { |
| 20 | r.forEach(e => (e as HTMLElement).style.backgroundColor = "#2b2e46"); | 22 | let r = document.querySelectorAll("button.record"); |
| 21 | (r[idx] as HTMLElement).style.backgroundColor = "#161723" | 23 | r.forEach(e => ((e as HTMLElement).style.backgroundColor = "#2b2e46")); |
| 22 | 24 | (r[idx] as HTMLElement).style.backgroundColor = "#161723"; | |
| 23 | 25 | ||
| 24 | if (data && data.summary.routes.length !== 0) { | 26 | if (data && data.summary.routes.length !== 0) { |
| 25 | idx += data.summary.routes.filter(e => e.category.id < category_id).length // lethimcook | 27 | idx += data.summary.routes.filter( |
| 26 | setSelectedRun(idx); | 28 | e => e.category.id < category_id |
| 27 | } | 29 | ).length; // lethimcook |
| 28 | }; | 30 | setSelectedRun(idx); |
| 31 | } | ||
| 32 | }, | ||
| 33 | [data, setSelectedRun] | ||
| 34 | ); | ||
| 29 | 35 | ||
| 30 | function _get_youtube_id(url: string): string { | 36 | function _get_youtube_id(url: string): string { |
| 31 | const urlArray = url.split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/); | 37 | const urlArray = url.split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/); |
| 32 | return (urlArray[2] !== undefined) ? urlArray[2].split(/[^0-9a-z_-]/i)[0] : urlArray[0]; | 38 | return urlArray[2] !== undefined |
| 33 | }; | 39 | ? urlArray[2].split(/[^0-9a-z_-]/i)[0] |
| 40 | : urlArray[0]; | ||
| 41 | } | ||
| 34 | 42 | ||
| 35 | function _category_change() { | 43 | const _category_change = React.useCallback(() => { |
| 36 | const btn = document.querySelectorAll("#section3 #category span button"); | 44 | const btn = document.querySelectorAll("#section3 #category span button"); |
| 37 | btn.forEach((e) => { (e as HTMLElement).style.backgroundColor = "#2b2e46" }); | 45 | btn.forEach(e => { |
| 46 | (e as HTMLElement).style.backgroundColor = "#2b2e46"; | ||
| 47 | }); | ||
| 38 | // heavenly father forgive me for i have sinned. TODO: fix this bullshit with dynamic categories | 48 | // heavenly father forgive me for i have sinned. TODO: fix this bullshit with dynamic categories |
| 39 | const idx = selectedCategory === 1 ? 0 : data.map.is_coop ? selectedCategory - 3 : selectedCategory - 1; | 49 | const idx = |
| 50 | selectedCategory === 1 | ||
| 51 | ? 0 | ||
| 52 | : data.map.is_coop | ||
| 53 | ? selectedCategory - 3 | ||
| 54 | : selectedCategory - 1; | ||
| 40 | (btn[idx] as HTMLElement).style.backgroundColor = "#202232"; | 55 | (btn[idx] as HTMLElement).style.backgroundColor = "#202232"; |
| 41 | }; | 56 | }, [selectedCategory, data.map.is_coop]); |
| 42 | 57 | ||
| 43 | function _history_change() { | 58 | const _history_change = React.useCallback(() => { |
| 44 | const btn = document.querySelectorAll("#section3 #history span button"); | 59 | const btn = document.querySelectorAll("#section3 #history span button"); |
| 45 | btn.forEach((e) => { (e as HTMLElement).style.backgroundColor = "#2b2e46" }); | 60 | btn.forEach(e => { |
| 46 | (historySelected ? btn[1] as HTMLElement : btn[0] as HTMLElement).style.backgroundColor = "#202232"; | 61 | (e as HTMLElement).style.backgroundColor = "#2b2e46"; |
| 47 | }; | 62 | }); |
| 63 | (historySelected | ||
| 64 | ? (btn[1] as HTMLElement) | ||
| 65 | : (btn[0] as HTMLElement) | ||
| 66 | ).style.backgroundColor = "#202232"; | ||
| 67 | }, [historySelected]); | ||
| 48 | 68 | ||
| 49 | React.useEffect(() => { | 69 | React.useEffect(() => { |
| 50 | _history_change(); | 70 | _history_change(); |
| 51 | }, [historySelected]); | 71 | }, [historySelected, _history_change]); |
| 52 | 72 | ||
| 53 | React.useEffect(() => { | 73 | React.useEffect(() => { |
| 54 | _category_change(); | 74 | _category_change(); |
| 55 | _select_run(0, selectedCategory); | 75 | _select_run(0, selectedCategory); |
| 56 | }, [selectedCategory]); | 76 | }, [selectedCategory, _category_change, _select_run]); |
| 57 | 77 | ||
| 58 | React.useEffect(() => { | 78 | React.useEffect(() => { |
| 59 | _select_run(0, selectedCategory); | 79 | _select_run(0, selectedCategory); |
| 60 | }, []); | 80 | }, [_select_run, selectedCategory]); |
| 61 | 81 | ||
| 62 | return ( | 82 | return ( |
| 63 | <> | 83 | <> |
| 64 | <section id='section3' className='summary1'> | 84 | <section id="section3" className="summary1 text-foreground"> |
| 65 | <div id='category' | 85 | <div |
| 66 | style={data.map.image === "" ? { backgroundColor: "#202232" } : {}}> | 86 | id="category" |
| 67 | <img src={data.map.image} alt="" id='category-image'></img> | 87 | style={data.map.image === "" ? { backgroundColor: "#202232" } : {}} |
| 68 | <p><span className='portal-count'>{data.summary.routes[selectedRun].history.score_count}</span> | 88 | > |
| 69 | {data.summary.routes[selectedRun].history.score_count === 1 ? ` portal` : ` portals`}</p> | 89 | <img src={data.map.image} alt="" id="category-image"></img> |
| 70 | {data.map.is_coop ? // TODO: make this part dynamic | 90 | <p> |
| 71 | ( | 91 | <span className="portal-count"> |
| 72 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr" }}> | 92 | {data.summary.routes[selectedRun].history.score_count} |
| 73 | <button onClick={() => setSelectedCategory(1)}>CM</button> | 93 | </span> |
| 74 | <button onClick={() => setSelectedCategory(4)}>Any%</button> | 94 | {data.summary.routes[selectedRun].history.score_count === 1 |
| 75 | <button onClick={() => setSelectedCategory(5)}>All Courses</button> | 95 | ? ` portal` |
| 76 | </span> | 96 | : ` portals`} |
| 77 | ) | 97 | </p> |
| 78 | : | 98 | {data.map.is_coop ? ( // TODO: make this part dynamic |
| 79 | ( | 99 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr" }}> |
| 80 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}> | 100 | <button onClick={() => setSelectedCategory(1)}>CM</button> |
| 81 | 101 | <button onClick={() => setSelectedCategory(4)}>Any%</button> | |
| 82 | <button onClick={() => setSelectedCategory(1)}>CM</button> | 102 | <button onClick={() => setSelectedCategory(5)}> |
| 83 | <button onClick={() => setSelectedCategory(2)}>NoSLA</button> | 103 | All Courses |
| 84 | <button onClick={() => setSelectedCategory(3)}>Inbounds SLA</button> | 104 | </button> |
| 85 | <button onClick={() => setSelectedCategory(4)}>Any%</button> | 105 | </span> |
| 86 | </span> | 106 | ) : ( |
| 87 | ) | 107 | <span style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}> |
| 88 | } | 108 | <button onClick={() => setSelectedCategory(1)}>CM</button> |
| 89 | 109 | <button onClick={() => setSelectedCategory(2)}>NoSLA</button> | |
| 110 | <button onClick={() => setSelectedCategory(3)}> | ||
| 111 | Inbounds SLA | ||
| 112 | </button> | ||
| 113 | <button onClick={() => setSelectedCategory(4)}>Any%</button> | ||
| 114 | </span> | ||
| 115 | )} | ||
| 90 | </div> | 116 | </div> |
| 91 | 117 | ||
| 92 | <div id='history'> | 118 | <div id="history"> |
| 93 | |||
| 94 | <div style={{ display: historySelected ? "none" : "block" }}> | 119 | <div style={{ display: historySelected ? "none" : "block" }}> |
| 95 | {data.summary.routes.filter(e => e.category.id === selectedCategory).length === 0 ? <h5>There are no records for this map.</h5> : | 120 | {data.summary.routes.filter(e => e.category.id === selectedCategory) |
| 121 | .length === 0 ? ( | ||
| 122 | <h5>There are no records for this map.</h5> | ||
| 123 | ) : ( | ||
| 96 | <> | 124 | <> |
| 97 | <div className='record-top'> | 125 | <div className="record-top"> |
| 98 | <span>Date</span> | 126 | <span>Date</span> |
| 99 | <span>Record</span> | 127 | <span>Record</span> |
| 100 | <span>First Completion</span> | 128 | <span>First Completion</span> |
| 101 | </div> | 129 | </div> |
| 102 | <hr /> | 130 | <hr /> |
| 103 | <div id='records'> | 131 | <div id="records"> |
| 104 | |||
| 105 | {data.summary.routes | 132 | {data.summary.routes |
| 106 | .filter(e => e.category.id === selectedCategory) | 133 | .filter(e => e.category.id === selectedCategory) |
| 107 | .map((r, index) => ( | 134 | .map((r, index) => ( |
| 108 | <button className='record' key={index} onClick={() => { | 135 | <button |
| 109 | _select_run(index, r.category.id); | 136 | className="record" |
| 110 | }}> | 137 | key={index} |
| 111 | <span>{new Date(r.history.date).toLocaleDateString( | 138 | onClick={() => { |
| 112 | "en-US", { month: 'long', day: 'numeric', year: 'numeric' } | 139 | _select_run(index, r.category.id); |
| 113 | )}</span> | 140 | }} |
| 141 | > | ||
| 142 | <span> | ||
| 143 | {new Date(r.history.date).toLocaleDateString( | ||
| 144 | "en-US", | ||
| 145 | { month: "long", day: "numeric", year: "numeric" } | ||
| 146 | )} | ||
| 147 | </span> | ||
| 114 | <span>{r.history.score_count}</span> | 148 | <span>{r.history.score_count}</span> |
| 115 | <span>{r.history.runner_name}</span> | 149 | <span>{r.history.runner_name}</span> |
| 116 | </button> | 150 | </button> |
| 117 | ))} | 151 | ))} |
| 118 | </div> | 152 | </div> |
| 119 | </> | 153 | </> |
| 120 | } | 154 | )} |
| 121 | </div> | 155 | </div> |
| 122 | 156 | ||
| 123 | <div style={{ display: historySelected ? "block" : "none" }}> | 157 | <div style={{ display: historySelected ? "block" : "none" }}> |
| 124 | {data.summary.routes.filter(e => e.category.id === selectedCategory).length === 0 ? <h5>There are no records for this map.</h5> : | 158 | {data.summary.routes.filter(e => e.category.id === selectedCategory) |
| 125 | <div id='graph'> | 159 | .length === 0 ? ( |
| 160 | <h5>There are no records for this map.</h5> | ||
| 161 | ) : ( | ||
| 162 | <div id="graph"> | ||
| 126 | {/* <div>{graph(1)}</div> | 163 | {/* <div>{graph(1)}</div> |
| 127 | <div>{graph(2)}</div> | 164 | <div>{graph(2)}</div> |
| 128 | <div>{graph(3)}</div> */} | 165 | <div>{graph(3)}</div> */} |
| 129 | </div> | 166 | </div> |
| 130 | } | 167 | )} |
| 131 | </div> | 168 | </div> |
| 132 | <span> | 169 | <span> |
| 133 | <button onClick={() => setHistorySelected(false)}>List</button> | 170 | <button onClick={() => setHistorySelected(false)}>List</button> |
| 134 | <button onClick={() => setHistorySelected(true)}>Graph</button> | 171 | <button onClick={() => setHistorySelected(true)}>Graph</button> |
| 135 | </span> | 172 | </span> |
| 136 | </div> | 173 | </div> |
| 137 | 174 | </section> | |
| 138 | 175 | <section id="section4" className="summary1"> | |
| 139 | </section > | 176 | <div id="difficulty"> |
| 140 | <section id='section4' className='summary1'> | 177 | <span className="">Difficulty</span> |
| 141 | <div id='difficulty'> | 178 | {data.map.difficulty <= 2 && ( |
| 142 | <span>Difficulty</span> | 179 | <span style={{ color: "lime" }}>Very Easy</span> |
| 143 | {data.map.difficulty <= 2 && (<span style={{ color: "lime" }}>Very easy</span>)} | 180 | )} |
| 144 | {data.map.difficulty > 2 && data.map.difficulty <= 4 && (<span style={{ color: "green" }}>Easy</span>)} | 181 | {data.map.difficulty > 2 && data.map.difficulty <= 4 && ( |
| 145 | {data.map.difficulty > 4 && data.map.difficulty <= 6 && (<span style={{ color: "yellow" }}>Medium</span>)} | 182 | <span style={{ color: "green" }}>Easy</span> |
| 146 | {data.map.difficulty > 6 && data.map.difficulty <= 8 && (<span style={{ color: "orange" }}>Hard</span>)} | 183 | )} |
| 147 | {data.map.difficulty > 8 && data.map.difficulty <= 10 && (<span style={{ color: "red" }}>Very hard</span>)} | 184 | {data.map.difficulty > 4 && data.map.difficulty <= 6 && ( |
| 185 | <span style={{ color: "yellow" }}>Medium</span> | ||
| 186 | )} | ||
| 187 | {data.map.difficulty > 6 && data.map.difficulty <= 8 && ( | ||
| 188 | <span style={{ color: "orange" }}>Hard</span> | ||
| 189 | )} | ||
| 190 | {data.map.difficulty > 8 && data.map.difficulty <= 10 && ( | ||
| 191 | <span style={{ color: "red" }}>Very Hard</span> | ||
| 192 | )} | ||
| 148 | <div> | 193 | <div> |
| 149 | {data.map.difficulty <= 2 ? (<div className='difficulty-rating' style={{ backgroundColor: "lime" }}></div>) : (<div className='difficulty-rating'></div>)} | 194 | {data.map.difficulty <= 2 && ? ( |
| 150 | {data.map.difficulty > 2 && data.map.difficulty <= 4 ? (<div className='difficulty-rating' style={{ backgroundColor: "green" }}></div>) : (<div className='difficulty-rating'></div>)} | 195 | <div |
| 151 | {data.map.difficulty > 4 && data.map.difficulty <= 6 ? (<div className='difficulty-rating' style={{ backgroundColor: "yellow" }}></div>) : (<div className='difficulty-rating'></div>)} | 196 | className="difficulty-rating" |
| 152 | {data.map.difficulty > 6 && data.map.difficulty <= 8 ? (<div className='difficulty-rating' style={{ backgroundColor: "orange" }}></div>) : (<div className='difficulty-rating'></div>)} | 197 | style={{ backgroundColor: "lime" }} |
| 153 | {data.map.difficulty > 8 && data.map.difficulty <= 10 ? (<div className='difficulty-rating' style={{ backgroundColor: "red" }}></div>) : (<div className='difficulty-rating'></div>)} | 198 | ></div> |
| 199 | ) : ( | ||
| 200 | <div className="difficulty-rating"></div> | ||
| 201 | )} | ||
| 202 | {data.map.difficulty > 2 && data.map.difficulty <= 4 && ? ( | ||
| 203 | <div | ||
| 204 | className="difficulty-rating" | ||
| 205 | style={{ backgroundColor: "green" }} | ||
| 206 | ></div> | ||
| 207 | ) : ( | ||
| 208 | <div className="difficulty-rating"></div> | ||
| 209 | )} | ||
| 210 | {data.map.difficulty > 4 && data.map.difficulty <= 6 && ? ( | ||
| 211 | <div | ||
| 212 | className="difficulty-rating" | ||
| 213 | style={{ backgroundColor: "yellow" }} | ||
| 214 | ></div> | ||
| 215 | ) : ( | ||
| 216 | <div className="difficulty-rating"></div> | ||
| 217 | )} | ||
| 218 | {data.map.difficulty > 6 && data.map.difficulty <= 8 && ? ( | ||
| 219 | <div | ||
| 220 | className="difficulty-rating" | ||
| 221 | style={{ backgroundColor: "orange" }} | ||
| 222 | ></div> | ||
| 223 | ) : ( | ||
| 224 | <div className="difficulty-rating"></div> | ||
| 225 | )} | ||
| 226 | {data.map.difficulty > 8 && data.map.difficulty <= 10 && ? ( | ||
| 227 | <div | ||
| 228 | className="difficulty-rating" | ||
| 229 | style={{ backgroundColor: "red" }} | ||
| 230 | ></div> | ||
| 231 | ) : ( | ||
| 232 | <div className="difficulty-rating"></div> | ||
| 233 | )} | ||
| 154 | </div> | 234 | </div> |
| 155 | </div> | 235 | </div> |
| 156 | {/* <div id='difficulty'> | 236 | <div id="count"> |
| 157 | <span>Difficulty</span> | ||
| 158 | {data.summary.routes[selectedRun].rating <= 2 && (<span style={{ color: "lime" }}>Very easy</span>)} | ||
| 159 | {data.summary.routes[selectedRun].rating > 2 && data.summary.routes[selectedRun].rating <= 4 && (<span style={{ color: "green" }}>Easy</span>)} | ||
| 160 | {data.summary.routes[selectedRun].rating > 4 && data.summary.routes[selectedRun].rating <= 6 && (<span style={{ color: "yellow" }}>Medium</span>)} | ||
| 161 | {data.summary.routes[selectedRun].rating > 6 && data.summary.routes[selectedRun].rating <= 8 && (<span style={{ color: "orange" }}>Hard</span>)} | ||
| 162 | {data.summary.routes[selectedRun].rating > 8 && data.summary.routes[selectedRun].rating <= 10 && (<span style={{ color: "red" }}>Very hard</span>)} | ||
| 163 | <div> | ||
| 164 | {data.summary.routes[selectedRun].rating <= 2 ? (<div className='difficulty-rating' style={{ backgroundColor: "lime" }}></div>) : (<div className='difficulty-rating'></div>)} | ||
| 165 | {data.summary.routes[selectedRun].rating > 2 && data.summary.routes[selectedRun].rating <= 4 ? (<div className='difficulty-rating' style={{ backgroundColor: "green" }}></div>) : (<div className='difficulty-rating'></div>)} | ||
| 166 | {data.summary.routes[selectedRun].rating > 4 && data.summary.routes[selectedRun].rating <= 6 ? (<div className='difficulty-rating' style={{ backgroundColor: "yellow" }}></div>) : (<div className='difficulty-rating'></div>)} | ||
| 167 | {data.summary.routes[selectedRun].rating > 6 && data.summary.routes[selectedRun].rating <= 8 ? (<div className='difficulty-rating' style={{ backgroundColor: "orange" }}></div>) : (<div className='difficulty-rating'></div>)} | ||
| 168 | {data.summary.routes[selectedRun].rating > 8 && data.summary.routes[selectedRun].rating <= 10 ? (<div className='difficulty-rating' style={{ backgroundColor: "red" }}></div>) : (<div className='difficulty-rating'></div>)} | ||
| 169 | </div> | ||
| 170 | </div> */} | ||
| 171 | <div id='count'> | ||
| 172 | <span>Completion Count</span> | 237 | <span>Completion Count</span> |
| 173 | <div>{data.summary.routes[selectedRun].completion_count}</div> | 238 | <div>{data.summary.routes[selectedRun].completion_count}</div> |
| 174 | </div> | 239 | </div> |
| 175 | </section> | 240 | </section> |
| 176 | 241 | ||
| 177 | <section id='section5' className='summary1'> | 242 | <section id="section5" className="summary1"> |
| 178 | <div id='description'> | 243 | <div id="description"> |
| 179 | {data.summary.routes[selectedRun].showcase !== "" ? | 244 | {data.summary.routes[selectedRun].showcase !== "" ? ( |
| 180 | <iframe title='Showcase video' src={"https://www.youtube.com/embed/" + _get_youtube_id(data.summary.routes[selectedRun].showcase)}> </iframe> | 245 | <iframe |
| 181 | : ""} | 246 | title="Showcase video" |
| 182 | <h3>Route Description</h3> | 247 | src={ |
| 183 | <span id='description-text'> | 248 | "https://www.youtube.com/embed/" + |
| 184 | <ReactMarkdown> | 249 | _get_youtube_id(data.summary.routes[selectedRun].showcase) |
| 250 | } | ||
| 251 | > | ||
| 252 | {" "} | ||
| 253 | </iframe> | ||
| 254 | ) : ( | ||
| 255 | "" | ||
| 256 | )} | ||
| 257 | <h3 className="font-semibold">Route Description</h3> | ||
| 258 | <span id="description-text"> | ||
| 259 | <ReactMarkdown className="text-foreground"> | ||
| 185 | {data.summary.routes[selectedRun].description} | 260 | {data.summary.routes[selectedRun].description} |
| 186 | </ReactMarkdown> | 261 | </ReactMarkdown> |
| 187 | </span> | 262 | </span> |
| 188 | </div> | 263 | </div> |
| 189 | </section> | 264 | </section> |
| 190 | |||
| 191 | </> | 265 | </> |
| 192 | ); | 266 | ); |
| 193 | }; | 267 | }; |