aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/pages/summary.js
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/pages/summary.js')
-rw-r--r--frontend/src/components/pages/summary.js650
1 files changed, 0 insertions, 650 deletions
diff --git a/frontend/src/components/pages/summary.js b/frontend/src/components/pages/summary.js
deleted file mode 100644
index d276408..0000000
--- a/frontend/src/components/pages/summary.js
+++ /dev/null
@@ -1,650 +0,0 @@
1import React, { useEffect } from 'react';
2import { useLocation, Link } from "react-router-dom";
3import ReactMarkdown from 'react-markdown'
4
5import "./summary.css";
6
7import img4 from "../../imgs/4.png"
8import img5 from "../../imgs/5.png"
9import img6 from "../../imgs/6.png"
10import img12 from "../../imgs/12.png"
11import img13 from "../../imgs/13.png"
12import Modview from "./summary_modview.js"
13
14export default function Summary(prop) {
15const {token,mod} = prop
16const fakedata={} //for debug
17
18 const location = useLocation()
19
20 //fetching data
21 const [data, setData] = React.useState(null);
22 React.useEffect(() => {
23 setData(null)
24 setDiscussionThread(null)
25 setCreatePostState(0)
26 setSelectedRun(0)
27 setCatState(1)
28 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/summary`)
29 .then(r => r.json())
30 .then(d => {
31 if(Object.keys(fakedata).length!==0){setData(fakedata)}
32 else{setData(d.data)}
33 if(d.data.summary.routes.length===0){d.data.summary.routes[0]={"category": "","history": {"score_count": 0,},"rating": 0,"description": "","showcase": ""}}
34 })
35 // eslint-disable-next-line
36 }, [location.pathname]);
37
38 const [pageNumber, setPageNumber] = React.useState(1);
39 const [lbData, setLbData] = React.useState(null);
40 React.useEffect(() => {
41 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/leaderboards?page=${pageNumber}`)
42 .then(r => r.json())
43 .then(d => setLbData(d))
44 // eslint-disable-next-line
45 }, [pageNumber,location.pathname]);
46
47 const [discussions,setDiscussions] = React.useState(null)
48 function fetchDiscussions() {
49 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/discussions`)
50 .then(r=>r.json())
51 .then(d=>setDiscussions(d.data.discussions))
52 }
53
54 React.useEffect(()=>{
55 fetchDiscussions()
56 },[location.pathname])
57
58
59
60const [discussionThread,setDiscussionThread] = React.useState(null)
61function openDiscussion(x){
62 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/discussions/${x}`)
63 .then(r=>r.json())
64 .then(d=>setDiscussionThread(d.data.discussion))
65}
66const [discussionSearch, setDiscussionSearch] = React.useState("")
67
68
69
70
71const [navState, setNavState] = React.useState(0); // eslint-disable-next-line
72React.useEffect(() => {NavClick();}, [[],navState]);
73
74function NavClick() {
75 if(data!==null){
76 const btn = document.querySelectorAll("#section2 button.nav-button");
77 btn.forEach((e) => {e.style.backgroundColor = "#2b2e46"});
78 btn[navState].style.backgroundColor = "#202232";
79
80 document.querySelectorAll("section").forEach((e,i)=>i>=2?e.style.display="none":"")
81 if(navState === 0){document.querySelectorAll(".summary1").forEach((e) => {e.style.display = "grid"});}
82 if(navState === 1){document.querySelectorAll(".summary2").forEach((e) => {e.style.display = "block"});}
83 if(navState === 2){document.querySelectorAll(".summary3").forEach((e) => {e.style.display = "block"});}
84}}
85
86
87const [catState, setCatState] = React.useState(1); // eslint-disable-next-line
88React.useEffect(() => {CatClick();}, [[],catState]);
89
90function CatClick() {
91 if(data!==null){
92 const btn = document.querySelectorAll("#section3 #category span button");
93 btn.forEach((e) => {e.style.backgroundColor = "#2b2e46"});
94 btn[catState-1].style.backgroundColor = "#202232";
95}}
96React.useEffect(()=>{
97 if(data!==null && data.summary.routes.filter(e=>e.category.id===catState).length!==0){
98 selectRun(0,catState)} // eslint-disable-next-line
99},[catState,data])
100
101
102const [hisState, setHisState] = React.useState(0); // eslint-disable-next-line
103React.useEffect(() => {HisClick();}, [[],hisState]);
104
105function HisClick() {
106 if(data!==null){
107 const btn = document.querySelectorAll("#section3 #history span button");
108 btn.forEach((e) => {e.style.backgroundColor = "#2b2e46"});
109 btn[hisState].style.backgroundColor = "#202232";
110
111}}
112
113const [selectedRun,setSelectedRun] = React.useState(0)
114
115function selectRun(x,y){
116 let r = document.querySelectorAll("button.record")
117 r.forEach(e=>e.style.backgroundColor="#2b2e46")
118 r[x].style.backgroundColor="#161723"
119
120
121 if(data!==null && data.summary.routes.length!==0 && data.summary.routes.length!==0){
122 if(y===2){x+=data.summary.routes.filter(e=>e.category.id<2).length}
123 if(y===3){x+=data.summary.routes.filter(e=>e.category.id<3).length}
124 if(y===4){x+=data.summary.routes.filter(e=>e.category.id<4).length}
125 setSelectedRun(x)
126 }
127}
128
129function graph(state) {
130 // this is such a mess
131 let graph = data.summary.routes.filter(e=>e.category.id===catState)
132 let graph_score = []
133 data.summary.routes.filter(e=>e.category.id===catState).forEach(e=>graph_score.push(e.history.score_count))
134 let graph_dates = []
135 data.summary.routes.filter(e=>e.category.id===catState).forEach(e=>graph_dates.push(e.history.date.split("T")[0]))
136 let graph_max = graph[graph.length-1].history.score_count
137 let graph_numbers = []
138 for (let i=graph_max;i>=0;i--){
139 graph_numbers[i]=i
140 }
141
142 switch (state) {
143 case 1: //numbers
144 return graph_numbers
145 .reverse().map(e=>(
146 graph_score.includes(e) || e===0 ?
147 <span>{e}<br/></span>
148 :
149 <span><br/></span>
150 ))
151 case 2: // graph
152 let g = 0
153 let h = 0
154 return graph_numbers.map((e,j)=>(
155 <tr id={'graph_row-'+(graph_max-j)}
156 data-graph={ graph_score.includes(graph_max-j) ? g++ : 0}
157 data-graph2={h=0}
158
159 >
160 {
161 graph_score.map((e,i)=>(
162 <>
163 <td className='graph_ver'
164 data-graph={ h++ }
165 style={{outline:
166 g===h-1 ?
167 "1px solid #2b2e46" : g>=h ? "1px dashed white" : "0" }}
168 ></td>
169
170 {g===h && graph_score.includes(graph_max-j) ?
171 <button className='graph-button'
172 onClick={()=>{
173 selectRun(graph_dates.length-(i-1),catState);
174 }}
175 style={{left: `calc(100% / ${graph_dates.length} * ${h-1})`}}
176 ></button>
177 : ""}
178
179 <td className='graph_hor' id={'graph_table-'+i++}
180 style={{
181 outline:
182 graph_score.includes(graph_max-j) ?
183 g>=h ?
184 g-1>=h ? "1px dashed #2b2e46" : "1px solid white" : "0"
185 : "0"}}
186 ></td>
187
188
189
190 <td className='graph_hor' id={'graph_table-'+i++}
191 style={{outline:
192 graph_score.includes(graph_max-j) ?
193 g>=h ?
194 g-1>=h ? "1px dashed #2b2e46" : "1px solid white" : "0"
195 : "0"}}
196 ></td>
197
198 </>
199 ))
200
201 }
202
203 </tr>
204 ))
205
206 case 3: // dates
207 return graph_dates
208 .reverse().map(e=>(
209 <span>{e}</span>
210 ))
211 default:
212 break;
213
214 }
215
216}
217
218const [vid,setVid] = React.useState("")
219React.useEffect(()=>{
220 if(data!==null){
221 let showcase = data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].showcase
222 showcase.length>6 ? setVid("https://www.youtube.com/embed/"+YouTubeGetID(showcase))
223 : setVid("")
224 } // eslint-disable-next-line
225},[[],selectedRun])
226
227function YouTubeGetID(url){
228 url = url.split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
229 return (url[2] !== undefined) ? url[2].split(/[^0-9a-z_]/i)[0] : url[0];
230 }
231
232function TimeAgo(date) {
233 // const seconds = Math.floor((new Date() - date) / 1000);
234
235 const seconds = Math.floor(((new Date(new Date() - (date.getTimezoneOffset()*-60000))) - date) / 1000);
236
237 let interval = Math.floor(seconds / 31536000);
238 if (interval === 1) {return interval + ' year ago';}
239 if (interval > 1) {return interval + ' years ago';}
240
241 interval = Math.floor(seconds / 2592000);
242 if (interval === 1) {return interval + ' month ago';}
243 if (interval > 1) {return interval + ' months ago';}
244
245 interval = Math.floor(seconds / 86400);
246 if (interval === 1) {return interval + ' day ago';}
247 if (interval > 1) {return interval + ' days ago';}
248
249 interval = Math.floor(seconds / 3600);
250 if (interval === 1) {return interval + ' hour ago';}
251 if (interval > 1) {return interval + ' hours ago';}
252
253 interval = Math.floor(seconds / 60);
254 if (interval === 1) {return interval + ' minute ago';}
255 if (interval > 1) {return interval + ' minutes ago';}
256
257 if(seconds < 10) return 'just now';
258
259 return Math.floor(seconds) + ' seconds ago';
260 };
261
262function TicksToTime(ticks) {
263
264 let seconds = Math.floor(ticks/60)
265 let minutes = Math.floor(seconds/60)
266 let hours = Math.floor(minutes/60)
267
268 let milliseconds = Math.floor((ticks%60)*1000/60)
269 seconds = seconds % 60;
270 minutes = minutes % 60;
271
272 return `${hours===0?"":hours+":"}${minutes===0?"":hours>0?minutes.toString().padStart(2, '0')+":":(minutes+":")}${minutes>0?seconds.toString().padStart(2, '0'):seconds}.${milliseconds.toString().padStart(3, '0')} (${ticks})`;
273}
274
275function PostComment() {
276
277 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/discussions/${discussionThread.id}`,{
278 method:"POST",
279 headers:{authorization:token},
280 body:JSON.stringify({"comment":document.querySelector("#discussion-send>input").value})
281})
282.then(r=>r.json())
283.then(d=>{
284 document.querySelector("#discussion-send>input").value=""
285 openDiscussion(discussionThread.id)
286})
287}
288
289
290const [createPostState,setCreatePostState] = React.useState(0)
291function CreatePost() {
292
293 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/discussions`,{
294 method:"POST",
295 headers:{authorization:token},
296 body:JSON.stringify({"title":document.querySelector("#discussion-create-title").value,"content":document.querySelector("#discussion-create-content").value})
297 })
298 .then(r=>r.json())
299 .then(d=>{
300 setCreatePostState(0)
301 fetchDiscussions()
302 })
303}
304
305function DeletePost(post) {
306if(window.confirm(`Are you sure you want to remove post: ${post.title}?`)){
307 console.log("deleted",post.id)
308 fetch(`https://lp.ardapektezol.com/api/v1/maps/${location.pathname.split('/')[2]}/discussions/${post.id}`,{
309 method:"DELETE",
310 headers:{authorization:token},
311 })
312 .then(r=>r.json())
313 .then(d=>{
314 fetchDiscussions()
315 })
316}
317}
318
319
320if(data!==null){
321 console.log(data)
322
323let current_chapter = data.map.chapter_name
324let isCoop = false;
325if (data.map.game_name == "Portal 2 - Cooperative") {
326 isCoop = true
327}
328
329current_chapter = data.map.chapter_name.split(" ")
330// current_chapter = current_chapter.split("-")
331current_chapter = current_chapter[1]
332
333return (
334 <>
335 {token!==null?mod===true?<Modview selectedRun={selectedRun} data={data} token={token}/>:"":""}
336
337 <div id='background-image'>
338 <img src={data.map.image} alt="" />
339 </div>
340 <main>
341 <section id='section1' className='summary1'>
342 <div>
343 <Link to="/games"><button className='nav-button' style={{borderRadius: "20px 0px 0px 20px"}}><i className='triangle'></i><span>Games list</span></button></Link>
344 <Link to={`/games/${!data.map.is_coop ? "1" : "2"}?chapter=${current_chapter}`}><button className='nav-button' style={{borderRadius: "0px 20px 20px 0px", marginLeft: "2px"}}><i className='triangle'></i><span>{data.map.chapter_name}</span></button></Link>
345 <br/><span><b>{data.map.map_name}</b></span>
346 </div>
347
348
349 </section>
350
351 <section id='section2' className='summary1'>
352 <button className='nav-button' onClick={()=>setNavState(0)}><img src={img4} alt="" /><span>Summary</span></button>
353 <button className='nav-button' onClick={()=>setNavState(1)}><img src={img5} alt="" /><span>Leaderboards</span></button>
354 <button className='nav-button' onClick={()=>setNavState(2)}><img src={img6} alt="" /><span>Discussions</span></button>
355 </section>
356 <section id='section3' className='summary1'>
357 <div id='category'
358 style={data.map.image===""?{backgroundColor:"#202232"}:{}}>
359 <img src={data.map.image} alt="" id='category-image'></img>
360 <p><span className='portal-count'>{data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].history.score_count}</span>
361 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].history.score_count === 1 ? ` portal` : ` portals` }</p>
362 <span>
363 <button onClick={()=>setCatState(1)}>CM</button>
364 <button onClick={()=>setCatState(2)}>NoSLA</button>
365 {data.map.is_coop?<button onClick={()=>setCatState(3)}>SLA</button>
366 :<button onClick={()=>setCatState(3)}>Inbounds SLA</button>}
367 <button onClick={()=>setCatState(4)}>Any%</button>
368 </span>
369
370 </div>
371
372 <div id='history'>
373
374 <div style={{display: hisState ? "none" : "block"}}>
375 {data.summary.routes.filter(e=>e.category.id===catState).length===0 ? <h5>There are no records for this map.</h5> :
376 <>
377 <div className='record-top'>
378 <span>Date</span>
379 <span>Record</span>
380 <span>First completion</span>
381 </div>
382 <hr/>
383 <div id='records'>
384
385 {data.summary.routes
386 .sort((a, b) => a.history.score_count - b.history.score_count)
387 .filter(e=>e.category.id===catState)
388 .map((r, index) => (
389 <button className='record' key={index} onClick={()=>{
390 selectRun(index,r.category.id);
391 }}>
392 <span>{ new Date(r.history.date).toLocaleDateString(
393 "en-US", { month: 'long', day: 'numeric', year: 'numeric' }
394 )}</span>
395 <span>{r.history.score_count}</span>
396 <span>{r.history.runner_name}</span>
397 </button>
398 ))}
399 </div>
400 </>
401 }
402 </div>
403
404 <div style={{display: hisState ? "block" : "none"}}>
405 {data.summary.routes.filter(e=>e.category.id===catState).length===0 ? <h5>There are no records for this map.</h5> :
406 <div id='graph'>
407 <div>{graph(1)}</div>
408 <div>{graph(2)}</div>
409 <div>{graph(3)}</div>
410 </div>
411 }
412 </div>
413 <span>
414 <button onClick={()=>setHisState(0)}>List</button>
415 <button onClick={()=>setHisState(1)}>Graph</button>
416 </span>
417 </div>
418
419
420 </section>
421 <section id='section4' className='summary1'>
422 <div id='difficulty'>
423 <span>Difficulty</span>
424 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 0 ? (<span>N/A</span>):null}
425 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 1 ? (<span style={{color:"lime"}}>Very easy</span>):null}
426 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 2 ? (<span style={{color:"green"}}>Easy</span>):null}
427 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 3 ? (<span style={{color:"yellow"}}>Medium</span>):null}
428 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 4 ? (<span style={{color:"orange"}}>Hard</span>):null}
429 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 5 ? (<span style={{color:"red"}}>Very hard</span>):null}
430 <div>
431 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 1 ? (<div className='difficulty-rating' style={{backgroundColor:"lime"}}></div>) : (<div className='difficulty-rating'></div>)}
432 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 2 ? (<div className='difficulty-rating' style={{backgroundColor:"green"}}></div>) : (<div className='difficulty-rating'></div>)}
433 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 3 ? (<div className='difficulty-rating' style={{backgroundColor:"yellow"}}></div>) : (<div className='difficulty-rating'></div>)}
434 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 4 ? (<div className='difficulty-rating' style={{backgroundColor:"orange"}}></div>) : (<div className='difficulty-rating'></div>)}
435 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].rating === 5 ? (<div className='difficulty-rating' style={{backgroundColor:"red"}}></div>) : (<div className='difficulty-rating'></div>)}
436 </div>
437 </div>
438 <div id='count'>
439 <span>Completion count</span>
440 <div>{catState===1?data.summary.routes[selectedRun].completion_count:"N/A"}</div>
441 </div>
442 </section>
443
444 <section id='section5' className='summary1'>
445 <div id='description'>
446 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].showcase!=="" ?
447 <iframe title='Showcase video' src={vid}> </iframe>
448 : ""}
449 <h3>Route description</h3>
450 <span id='description-text'>
451 <ReactMarkdown>
452 {data.summary.routes.sort((a,b)=>a.category.id - b.category.id)[selectedRun].description}
453 </ReactMarkdown>
454 </span>
455 </div>
456 </section>
457
458 {/* Leaderboards */}
459
460 {lbData===null?"":lbData.success===false?(
461 <section id='section6' className='summary2'>
462 <h1 style={{textAlign:"center"}}>Map is not available for competitive boards.</h1>
463 </section>
464 ):lbData.data.records.length===0?(
465 <section id='section6' className='summary2'>
466 <h1 style={{textAlign:"center"}}>No records found.</h1>
467 </section>
468 ):(
469 <section id='section6' className='summary2'>
470
471 <div id='leaderboard-top'
472 style={lbData.data.map.is_coop?{gridTemplateColumns:"7.5% 40% 7.5% 15% 15% 15%"}:{gridTemplateColumns:"7.5% 30% 10% 20% 17.5% 15%"}}
473 >
474 <span>Place</span>
475
476 {lbData.data.map.is_coop?(
477 <div id='runner'>
478 <span>Host</span>
479 <span>Partner</span>
480 </div>
481 ):(
482 <span>Runner</span>
483 )}
484
485 <span>Portals</span>
486 <span>Time</span>
487 <span>Date</span>
488 <div id='page-number'>
489 <div>
490
491 <button onClick={() => pageNumber === 1 ? null : setPageNumber(prevPageNumber => prevPageNumber - 1)}
492 ><i className='triangle' style={{position:'relative',left:'-5px',}}></i> </button>
493 <span>{lbData.data.pagination.current_page}/{lbData.data.pagination.total_pages}</span>
494 <button onClick={() => pageNumber === lbData.data.pagination.total_pages ? null : setPageNumber(prevPageNumber => prevPageNumber + 1)}
495 ><i className='triangle' style={{position:'relative',left:'5px',transform:'rotate(180deg)'}}></i> </button>
496 </div>
497 </div>
498 </div>
499 <hr/>
500 <div id='leaderboard-records'>
501 {lbData.data.records.map((r, index) => (
502 <span className='leaderboard-record' key={index}
503 style={lbData.data.map.is_coop?{gridTemplateColumns:"3% 4.5% 40% 4% 3.5% 15% 15% 14.5%"}:{gridTemplateColumns:"3% 4.5% 30% 4% 6% 20% 17% 15%"}}
504 >
505 <span>{r.placement}</span>
506 <span> </span>
507 {lbData.data.map.is_coop?(
508 <div>
509 <span><img src={r.host.avatar_link} alt='' /> &nbsp; {r.host.user_name}</span>
510 <span><img src={r.partner.avatar_link} alt='' /> &nbsp; {r.partner.user_name}</span>
511 </div>
512 ):(
513 <div><span><img src={r.user.avatar_link} alt='' /> &nbsp; {r.user.user_name}</span></div>
514 )}
515
516 <span>{r.score_count}</span>
517 <span> </span>
518 <span>{TicksToTime(r.score_time)}</span>
519 <span className='hover-popup' popup-text={r.record_date.replace("T",' ').split(".")[0]}>{ TimeAgo(new Date(r.record_date.replace("T"," ").replace("Z",""))) }</span>
520
521 {lbData.data.map.is_coop?(
522 <span>
523 <button onClick={()=>{window.alert(`Host demo ID: ${r.host_demo_id} \nParnter demo ID: ${r.partner_demo_id}`)}}><img src={img13} alt="demo_id" /></button>
524 <button onClick={()=>window.location.href=`https://lp.ardapektezol.com/api/v1/demos?uuid=${r.partner_demo_id}`}><img src={img12} alt="download" style={{filter:"hue-rotate(160deg) contrast(60%) saturate(1000%)"}}/></button>
525 <button onClick={()=>window.location.href=`https://lp.ardapektezol.com/api/v1/demos?uuid=${r.host_demo_id}`}><img src={img12} alt="download" style={{filter:"hue-rotate(300deg) contrast(60%) saturate(1000%)"}}/></button>
526 </span>
527 ):(
528
529 <span>
530 <button onClick={()=>{window.alert(`Demo ID: ${r.demo_id}`)}}><img src={img13} alt="demo_id" /></button>
531 <button onClick={()=>window.location.href=`https://lp.ardapektezol.com/api/v1/demos?uuid=${r.demo_id}`}><img src={img12} alt="download" /></button>
532 </span>
533 )}
534 </span>
535 ))}
536 </div>
537 </section>
538 )}
539
540
541 {/* Discussions */}
542 <section id='section7' className='summary3'>
543
544 {discussionThread === null ? (
545 createPostState === 0 ? (
546 discussions !== null ? (
547 // Main screen
548 <>
549 <div id='discussion-search'>
550 <input type="text" value={discussionSearch} placeholder={"Search for posts..."} onChange={()=>setDiscussionSearch(document.querySelector("#discussion-search>input").value)} />
551 <div><button onClick={()=>setCreatePostState(1)}>New Post</button></div>
552 </div>
553 {discussions.filter(f=>f.title.includes(discussionSearch)).sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at))
554 .map((e, i) => (
555 <div id='discussion-post'>
556
557 <button key={e.id} onClick={() => openDiscussion(e.id)}>
558 <span>{e.title}</span>
559
560 {token!==null?e.creator.steam_id===JSON.parse(atob(token.split(".")[1])).sub?
561 <button onClick={()=>DeletePost(e)}>Delete Post</button>
562 :<span></span>:<span></span>}
563 <span><b>{e.creator.user_name}:</b> {e.content}</span>
564 <span>last updated: {TimeAgo(new Date(e.updated_at.replace("T"," ").replace("Z","")))}</span>
565 </button>
566 </div>
567 ))}
568 </>
569 ):(
570
571 // Main screen (no posts)
572 <>
573 <div id='discussion-search'>
574 <input type="text" value={discussionSearch} placeholder={"Search for posts..."} onChange={()=>setDiscussionSearch(document.querySelector("#discussion-search>input").value)} />
575 <div><button onClick={()=>setCreatePostState(1)}>New Post</button></div>
576 </div>
577 <span style={{textAlign:"center",display:"block"}}>no discussions</span>
578</>
579 )
580 ):(
581 // Creating post
582 <div id='discussion-create'>
583 <span>Create post</span>
584 <button onClick={()=>setCreatePostState(0)}>X</button>
585 <div style={{gridColumn:"1 / span 2"}}>
586 <input id='discussion-create-title' placeholder='Title...'></input>
587 <input id='discussion-create-content' placeholder='Enter the comment...' ></input>
588 </div>
589 <div style={{placeItems:"end",gridColumn:"1 / span 2"}}>
590 <button id='discussion-create-button' onClick={()=>CreatePost()}>Post</button>
591 </div>
592
593 </div>
594
595 )):(
596 // Post screen
597 <div id='discussion-thread'>
598 <div>
599 <span>{discussionThread.title}</span>
600 <button onClick={()=>setDiscussionThread(null)}>X</button>
601 </div>
602
603 <div>
604 <img src={discussionThread.creator.avatar_link} alt="" />
605 <div>
606 <span>{discussionThread.creator.user_name}</span>
607 <span>{TimeAgo(new Date(discussionThread.created_at.replace("T"," ").replace("Z","")))}</span>
608 <span>{discussionThread.content}</span>
609 </div>
610 {discussionThread.comments!==null?
611 discussionThread.comments.sort((a, b) => new Date(a.date) - new Date(b.date))
612 .map(e=>(
613 <>
614 <img src={e.user.avatar_link} alt="" />
615 <div>
616 <span>{e.user.user_name}</span>
617 <span>{TimeAgo(new Date(e.date.replace("T"," ").replace("Z","")))}</span>
618 <span>{e.comment}</span>
619 </div>
620 </>
621
622 )):""}
623
624
625 </div>
626 <div id='discussion-send'>
627 <input type="text" placeholder={"Message"} onKeyDown={(e)=>e.key==="Enter"?PostComment():""}/>
628 <div><button onClick={()=>PostComment()}>Send</button></div>
629 </div>
630
631 </div>
632
633
634 )}
635
636 </section>
637
638 </main>
639 </>
640 )
641}else{
642 return (
643 <main></main>
644 )
645}
646
647
648}
649
650