aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/components/Discussions.tsx
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2024-09-03 00:08:53 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2024-09-03 00:08:53 +0300
commita65d6d9127c3fa7f6a8ecaec5d1ffd1f47c2bc98 (patch)
treeedf8630e9d6426124dd49854af0cb703ebc5b710 /frontend/src/components/Discussions.tsx
parentfix: revert to static homepage (#195) (diff)
downloadlphub-a65d6d9127c3fa7f6a8ecaec5d1ffd1f47c2bc98.tar.gz
lphub-a65d6d9127c3fa7f6a8ecaec5d1ffd1f47c2bc98.tar.bz2
lphub-a65d6d9127c3fa7f6a8ecaec5d1ffd1f47c2bc98.zip
refactor: port to typescript
Diffstat (limited to 'frontend/src/components/Discussions.tsx')
-rw-r--r--frontend/src/components/Discussions.tsx151
1 files changed, 151 insertions, 0 deletions
diff --git a/frontend/src/components/Discussions.tsx b/frontend/src/components/Discussions.tsx
new file mode 100644
index 0000000..1cd3523
--- /dev/null
+++ b/frontend/src/components/Discussions.tsx
@@ -0,0 +1,151 @@
1import React from 'react';
2
3import { MapDiscussion, MapDiscussions, MapDiscussionsDetail } from '../types/Map';
4import { MapDiscussionCommentContent, MapDiscussionContent } from '../types/Content';
5import { time_ago } from '../utils/Time';
6import { API } from '../api/Api';
7import "../css/Maps.css"
8
9interface DiscussionsProps {
10 data?: MapDiscussions;
11 isModerator: boolean;
12 mapID: string;
13 onRefresh: () => void;
14}
15
16const Discussions: React.FC<DiscussionsProps> = ({ data, isModerator, mapID, onRefresh }) => {
17
18 const [discussionThread, setDiscussionThread] = React.useState<MapDiscussion | undefined>(undefined);
19 const [discussionSearch, setDiscussionSearch] = React.useState<string>("");
20
21 const [createDiscussion, setCreateDiscussion] = React.useState<boolean>(false);
22 const [createDiscussionContent, setCreateDiscussionContent] = React.useState<MapDiscussionContent>({
23 title: "",
24 content: "",
25 });
26 const [createDiscussionCommentContent, setCreateDiscussionCommentContent] = React.useState<MapDiscussionCommentContent>({
27 comment: "",
28 });
29
30 const _open_map_discussion = async (discussion_id: number) => {
31 const mapDiscussion = await API.get_map_discussion(mapID, discussion_id);
32 setDiscussionThread(mapDiscussion);
33 };
34
35 const _create_map_discussion = async () => {
36 await API.post_map_discussion(mapID, createDiscussionContent);
37 setCreateDiscussion(false);
38 onRefresh();
39 };
40
41 const _create_map_discussion_comment = async (discussion_id: number) => {
42 await API.post_map_discussion_comment(mapID, discussion_id, createDiscussionCommentContent);
43 await _open_map_discussion(discussion_id);
44 };
45
46 const _delete_map_discussion = async (discussion: MapDiscussionsDetail) => {
47 if (window.confirm(`Are you sure you want to remove post: ${discussion.title}?`)) {
48 await API.delete_map_discussion(mapID, discussion.id);
49 onRefresh();
50 }
51 };
52
53 return (
54 <section id='section7' className='summary3'>
55 <div id='discussion-search'>
56 <input type="text" value={discussionSearch} placeholder={"Search for posts..."} onChange={(e) => setDiscussionSearch(e.target.value)} />
57 <div><button onClick={() => setCreateDiscussion(true)}>New Post</button></div>
58 </div>
59
60 { // janky ternary operators here, could divide them to more components?
61 createDiscussion ?
62 (
63 <div id='discussion-create'>
64 <span>Create Post</span>
65 <button onClick={() => setCreateDiscussion(false)}>X</button>
66 <div style={{ gridColumn: "1 / span 2" }}>
67 <input id='discussion-create-title' placeholder='Title...' onChange={(e) => setCreateDiscussionContent({
68 ...createDiscussionContent,
69 title: e.target.value,
70 })} />
71 <input id='discussion-create-content' placeholder='Enter the comment...' onChange={(e) => setCreateDiscussionContent({
72 ...createDiscussionContent,
73 title: e.target.value,
74 })} />
75 </div>
76 <div style={{ placeItems: "end", gridColumn: "1 / span 2" }}>
77 <button id='discussion-create-button' onClick={() => _create_map_discussion()}>Post</button>
78 </div>
79 </div>
80 )
81 :
82 discussionThread ?
83 (
84 <div id='discussion-thread'>
85 <div>
86 <span>{discussionThread.discussion.title}</span>
87 <button onClick={() => setDiscussionThread(undefined)}>X</button>
88 </div>
89
90 <div>
91 <img src={discussionThread.discussion.creator.avatar_link} alt="" />
92 <div>
93 <span>{discussionThread.discussion.creator.user_name}</span>
94 <span>{time_ago(new Date(discussionThread.discussion.created_at.replace("T", " ").replace("Z", "")))}</span>
95 <span>{discussionThread.discussion.content}</span>
96 </div>
97 {discussionThread.discussion.comments ?
98 discussionThread.discussion.comments.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
99 .map(e => (
100 <>
101 <img src={e.user.avatar_link} alt="" />
102 <div>
103 <span>{e.user.user_name}</span>
104 <span>{time_ago(new Date(e.date.replace("T", " ").replace("Z", "")))}</span>
105 <span>{e.comment}</span>
106 </div>
107 </>
108 )) : ""
109 }
110 </div>
111 <div id='discussion-send'>
112 <input type="text" placeholder={"Message"} onKeyDown={(e) => e.key === "Enter" && _create_map_discussion_comment(discussionThread.discussion.id)} onChange={(e) => setCreateDiscussionCommentContent({
113 ...createDiscussionContent,
114 comment: e.target.value,
115 })} />
116 <div><button onClick={() => _create_map_discussion_comment(discussionThread.discussion.id)}>Send</button></div>
117 </div>
118
119 </div>
120 )
121 :
122 (
123 data ?
124 (<>
125 {data.discussions.filter(f => f.title.includes(discussionSearch)).sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())
126 .map((e, i) => (
127 <div id='discussion-post'>
128 <button key={e.id} onClick={() => _open_map_discussion(e.id)}>
129 <span>{e.title}</span>
130 {isModerator ?
131 <button onClick={(m) => {
132 m.stopPropagation();
133 _delete_map_discussion(e);
134 }}>Delete Post</button>
135 : <span></span>
136 }
137 <span><b>{e.creator.user_name}:</b> {e.content}</span>
138 <span>Last Updated: {time_ago(new Date(e.updated_at.replace("T", " ").replace("Z", "")))}</span>
139 </button>
140 </div>
141 ))}
142 </>)
143 :
144 (<span style={{ textAlign: "center", display: "block" }}>No Discussions...</span>)
145 )
146 }
147 </section>
148 );
149};
150
151export default Discussions;