summaryrefslogtreecommitdiff
path: root/trongleposting-client/src/App.js
blob: 4ffaacb40884ea1a6eab8e7964990bff2609e090 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { useRef, useState, useEffect } from "react";
import { generateGruvboxFromString } from "./utils/generate_gruvbox";
import "./App.css";

function App() {
  const [socket, setSocket] = useState(null);
  const [posts, setPosts] = useState([]);
  const postsRef = useRef([]);
  const [content, setContent] = useState("");
  const [username, setUsername] = useState("");
  const [error, setError] = useState("");
  const [color, setColor] = useState("");

  const scrollToBottomOfChat = () => {
    const objDiv = document.getElementById("chat");
    objDiv.scrollTop = objDiv.scrollHeight;
  };

  useEffect(() => {
    const protocol = document.location.protocol === "https:" ? "wss:" : "ws:";
    let socket;

    fetch("/posts")
      .then((r) => r.json())
      .then((msgs) => {
        postsRef.current = msgs;
        setPosts(postsRef.current);
        scrollToBottomOfChat();
      })
      .then(() => {
        socket = new WebSocket(`${protocol}//${document.location.host}/`);
        socket.addEventListener("open", () => {
          socket.send("ping");
        });
        socket.addEventListener("message", (msg) => {
          const { data } = msg;
          if (data === "pong") return;

          const chat = JSON.parse(msg.data);
          if (chat.author) {
            postsRef.current = [...postsRef.current, chat];
            setPosts(postsRef.current);
            scrollToBottomOfChat();
          }
        });

        setSocket(socket);
      });

    return () => {
      socket.close();
    };
  }, []);

  useEffect(() => {
    setColor(generateGruvboxFromString(username));
  }, [username]);

  const addPost = () => {
    setError("");
    if (socket) {
      fetch("/posts", {
        method: "POST",
        headers: { Content: "application/json" },
        body: JSON.stringify({ author: username, message: content }),
      }).then(() => setContent(""));
    }
  };

  return (
    <div className="container" style={{ border: `1px solid ${color}` }}>
      <div style={{ textAlign: "center" }}>
        <h2>TrongELISPosting</h2>
      </div>
      <div id="chat" className="chat">
        <p>Welcome!</p>
        {posts.map((post) => (
          <div
            key={post.id}
            style={{
              lineBreak: "normal",
              display: "flex",
              alignItems: "center",
              justifyContent: "space-between",
            }}
          >
            <div>
              <span style={{ color: generateGruvboxFromString(post.author) }}>
                {post.author}:{" "}
              </span>
              <span>{post.message}</span>
            </div>
            <div style={{ fontSize: "x-small" }}>
              [{new Date(post.date).toLocaleString()}]
            </div>
          </div>
        ))}
      </div>
      <div>
        <input
          placeholder={"Username"}
          className="input"
          style={{ color }}
          onChange={(e) => {
            setUsername(e.target.value);
          }}
          value={username}
        ></input>
        <textarea
          placeholder={"Message"}
          className="input"
          onChange={(e) => setContent(e.target.value)}
          value={content}
          rows={1}
          cols={40}
        ></textarea>
        <div className="button" onClick={addPost}>
          Post
        </div>
        {error ? <p style={{ color: "red" }}>{error}</p> : null}
      </div>
    </div>
  );
}

export default App;