diff --git a/front/src/components/MessageComponent.tsx b/front/src/components/MessageComponent.tsx index 18e5999..68528a0 100644 --- a/front/src/components/MessageComponent.tsx +++ b/front/src/components/MessageComponent.tsx @@ -1,6 +1,8 @@ import { Link } from "react-router-dom"; import { Message, User, Channel } from "../types"; +import "../styles/MessageComponent.css"; + export default function MessageComponent({ message, user, channel, deleteMessage }: { message: Message; user: User | undefined; @@ -9,7 +11,7 @@ export default function MessageComponent({ message, user, channel, deleteMessage }) { return ( -
  • +
    {message.username}:{" "} {message.content.split(" ").map((word, index) => { if (word.startsWith("@")) { @@ -28,6 +30,6 @@ export default function MessageComponent({ message, user, channel, deleteMessage

    In {message.channel_name}

    ) } -
  • + ); } \ No newline at end of file diff --git a/front/src/components/TopBar.tsx b/front/src/components/TopBar.tsx new file mode 100644 index 0000000..35f1c72 --- /dev/null +++ b/front/src/components/TopBar.tsx @@ -0,0 +1,32 @@ +import { Link } from "react-router-dom" +import { User } from "../types" + +import "../styles/TopBar.css" + +export default function TopBar({ user }: { user: User | undefined }) { + return ( +
    +
    +

    Tanuki's Forum

    + Home + Channels +
    + {user ? ( +
    + {user.username} + +
    + ) : ( +
    + Login + Register +
    + )} +
    + ) +} \ No newline at end of file diff --git a/front/src/index.css b/front/src/index.css index 75e6ee3..1809dd7 100644 --- a/front/src/index.css +++ b/front/src/index.css @@ -1,3 +1,7 @@ +html { + background-color: #FFE0E3; +} + .cat { width: 100px; } diff --git a/front/src/pages/ChannelPage.tsx b/front/src/pages/ChannelPage.tsx index c9658b3..e8f8656 100644 --- a/front/src/pages/ChannelPage.tsx +++ b/front/src/pages/ChannelPage.tsx @@ -1,9 +1,12 @@ import { useParams, Link } from "react-router-dom"; import React, { useEffect, useState } from "react"; import { Channel, Messages, User } from "../types"; +import TopBar from "../components/TopBar"; import MessageComponent from "../components/MessageComponent"; import axios from "axios"; +import "../styles/ChannelPage.css"; + export default function ChannelPage() { const { name } = useParams(); const [channel, setChannel] = useState(); @@ -102,17 +105,24 @@ export default function ChannelPage() { } return ( -
    - Home -

    Channel {channel.name}

    -

    {channel.description}

    -

    Owner: {channel.owner_username}

    - {channel.name.toLowerCase().includes("cat") && ( - cat - )} - { - token ? ( -
    +
    + +
    +

    Channel {channel.name}

    +

    {channel.description}

    +

    Owner: {channel.owner_username}

    + {channel.name.toLowerCase().includes("cat") && ( + cat + )} + {token ? ( + + setMessage(e.target.value)} + /> + {searchedUsers.length > 0 && (

    Mentions:

    @@ -134,37 +144,28 @@ export default function ChannelPage() { ))}
    )} - setMessage(e.target.value)} - /> - ) : ( -
    +
    Login Register
    - ) - } -
      - {messages.slice(0, maxMessageToShown).map((message) => ( - - ))} -
    - { - messages.length > maxMessageToShown && ( - - ) - } + )} +
    + {messages.slice(0, maxMessageToShown).map((message) => ( + + ))} + {messages.length > maxMessageToShown && ( + + )} +
    +
    ); } \ No newline at end of file diff --git a/front/src/pages/ChannelsPage.tsx b/front/src/pages/ChannelsPage.tsx index 222a88a..2e6e11e 100644 --- a/front/src/pages/ChannelsPage.tsx +++ b/front/src/pages/ChannelsPage.tsx @@ -1,13 +1,28 @@ import { useState, useEffect } from "react" import { Link } from "react-router-dom" -import { Channels } from "../types" +import { Channels, User } from "../types" import axios from "axios" +import TopBar from "../components/TopBar" + +import "../styles/ChannelsPage.css" export default function ChannelsPage() { const [channels, setChannels] = useState(); const [search, setSearch] = useState(""); + const [user, setUser] = useState(); useEffect(() => { + const token = localStorage.getItem("token") + + if (token) { + axios + .post("/api/auth/me", { + token: token + }) + .then((res) => { + setUser(res.data) + }) + } axios .get("/api/channels") .then((res) => { @@ -31,22 +46,24 @@ export default function ChannelsPage() { }, []) return ( -
    - Home -

    Channels

    - setSearch(e.target.value)} - /> -
      - {channels?.filter((channel) => channel.name.toLowerCase().includes(search.toLowerCase())).map((channel) => ( -
    • - {channel.name} -
    • - ))} -
    +
    + +
    +

    Channels

    + setSearch(e.target.value)} + /> +
      + {channels?.filter((channel) => channel.name.toLowerCase().includes(search.toLowerCase())).map((channel) => ( +
    • + {channel.name} +
    • + ))} +
    +
    ) } \ No newline at end of file diff --git a/front/src/pages/CreateChannel.tsx b/front/src/pages/CreateChannel.tsx index a75aea3..d19a906 100644 --- a/front/src/pages/CreateChannel.tsx +++ b/front/src/pages/CreateChannel.tsx @@ -1,17 +1,29 @@ import { useState, useEffect } from "react"; import { Link, useNavigate } from "react-router-dom"; +import { User } from "../types"; import axios from "axios"; +import TopBar from "../components/TopBar"; +import "../styles/CreateChannel.css"; export default function CreateChannel() { const navigate = useNavigate(); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [token, setToken] = useState(""); + const [user , setUser] = useState(); useEffect(() => { const localToken = localStorage.getItem("token"); - if (localToken) setToken(localToken); + if (localToken) { + setToken(localToken) + + axios + .post("/api/auth/me", { token: localToken }) + .then((res) => { + setUser(res.data); + }); + } }, []); function handleSubmit(e: React.FormEvent) { @@ -27,31 +39,33 @@ export default function CreateChannel() { } return ( -
    - Home -

    Create Channel

    -
    -

    - {!/^[a-zA-Z0-9-_]+$/.test(name) && name.length != 0 && ( - Channel name can only contain letters, numbers, - and _ - )} -

    - setName(e.target.value)} - /> - setDescription(e.target.value)} - /> - -
    +
    + +
    +

    Create Channel

    +
    +

    + {!/^[a-zA-Z0-9-_]+$/.test(name) && name.length != 0 && ( + Channel name can only contain letters, numbers, - and _ + )} +

    + setName(e.target.value)} + /> + setDescription(e.target.value)} + /> + +
    +
    ); } \ No newline at end of file diff --git a/front/src/pages/Home.tsx b/front/src/pages/Home.tsx index 13aa52f..15209c9 100644 --- a/front/src/pages/Home.tsx +++ b/front/src/pages/Home.tsx @@ -1,9 +1,12 @@ import { useState, useEffect } from "react" import { Link } from "react-router-dom" import { Channels, RecentChannels, User, Messages } from "../types" +import TopBar from "../components/TopBar" import MessageComponent from "../components/MessageComponent" import axios from "axios" +import "../styles/Home.css" + export default function Home() { const [user, setUser] = useState(); const [channels, setChannels] = useState(); @@ -80,59 +83,66 @@ export default function Home() { }, [search]) return ( -
    -

    Home

    - {user ? ( -
    -

    Welcome {user.username}

    - - Create Channel +
    + +
    +
    +

    Welcome to Tanuki's forum !

    +

    + I don't know what to say, but I hope you will enjoy your stay here. +

    - ) : ( -
    - Login - Register + osaka +
    +
    +
    +

    Last messages

    +
    + {messages?.map((message) => ( + + ))} +
    - )} -

    Recent active channels

    -
      - {channels?.map((channel) => ( -
    • - {channel.name} -
    • - ))} -
    -

    Search channels

    - setSearch(e.target.value)} - /> -
      - {searchedChannels?.map((channel) => ( -
    • - {channel.name} -
    • - ))} -
    - All channels -

    Last messages

    -
      - {messages?.map((message) => ( - - ))} -
    - osaka +
    +

    Channels

    + All channels + {user && ( + Create channel + )} +
    +

    Recent active channels

    +
      + {channels?.map((channel) => ( +
    • + {channel.name} +
    • + ))} +
    +
    +
    +

    Search channels

    + setSearch(e.target.value)} + /> +
      + {searchedChannels?.map((channel) => ( +
    • + {channel.name} +
    • + ))} +
    +
    +
    +
    ) } \ No newline at end of file diff --git a/front/src/pages/Login.tsx b/front/src/pages/Login.tsx index 9c747f8..9d72af9 100644 --- a/front/src/pages/Login.tsx +++ b/front/src/pages/Login.tsx @@ -1,6 +1,9 @@ import axios from "axios"; import { useState } from "react"; import { useNavigate, Link } from "react-router-dom"; +import TopBar from "../components/TopBar"; + +import "../styles/Login.css"; export default function Login() { const [username, setUsername] = useState(""); @@ -21,25 +24,27 @@ export default function Login() { } return ( -
    - Home -

    Login

    -
    - setUsername(e.target.value)} - /> - setPassword(e.target.value)} - /> - -
    - Register +
    + +
    +

    Login

    +
    + setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
    + Register +
    ); } \ No newline at end of file diff --git a/front/src/pages/Register.tsx b/front/src/pages/Register.tsx index abfa299..bed1947 100644 --- a/front/src/pages/Register.tsx +++ b/front/src/pages/Register.tsx @@ -1,6 +1,9 @@ import axios from "axios"; import { useState } from "react"; import { useNavigate, Link } from "react-router-dom"; +import TopBar from "../components/TopBar"; + +import "../styles/Register.css"; export default function Register () { const [username, setUsername] = useState(""); @@ -28,32 +31,34 @@ export default function Register () { } return ( -
    - Home -

    Register

    -
    -

    - {!/^[a-zA-Z0-9-_]+$/.test(username) && username.length != 0 && ( - Username can only contain letters, numbers, - and _ - )} -

    - setUsername(e.target.value)} - /> - setPassword(e.target.value)} - /> - -
    - Login +
    + +
    +

    Register

    +
    +

    + {!/^[a-zA-Z0-9-_]+$/.test(username) && username.length != 0 && ( + Username can only contain letters, numbers, - and _ + )} +

    + setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
    + Login +
    ); } \ No newline at end of file diff --git a/front/src/pages/UserPage.tsx b/front/src/pages/UserPage.tsx index c03a79e..69fa15f 100644 --- a/front/src/pages/UserPage.tsx +++ b/front/src/pages/UserPage.tsx @@ -1,17 +1,32 @@ import { useParams, Link } from "react-router-dom"; import { useEffect, useState } from "react"; import { User, Messages } from "../types"; +import TopBar from "../components/TopBar"; import MessageComponent from "../components/MessageComponent"; import axios from "axios"; +import "../styles/UserPage.css"; + export default function UserPage() { const { username } = useParams(); - const [user, setUser] = useState(); + const [pageUser, setPageUser] = useState(); const [messages, setMessages] = useState(); + const [user, setUser] = useState(); + + useEffect(() => { + const localToken = localStorage.getItem("token"); + + if (localToken) { + axios + .post("/api/auth/me", { token: localToken }).then((res) => { + setUser(res.data); + }); + } + }, []); useEffect(() => { axios.get(`/api/users/${username}`).then((res) => { - setUser(res.data); + setPageUser(res.data); }); axios.get(`/api/users/${username}/lastmessages`).then((res) => { @@ -30,27 +45,31 @@ export default function UserPage() { return () => { clearInterval(id) } }, [username]) - if (!user) { + if (!pageUser) { return
    Loading...
    ; } return ( -
    - Home -

    {user.username}

    - {user.admin ?

    Admin

    :

    User

    } -

    Last messages

    -
      - {messages?.map((message) => ( - - ))} -
    +
    + +
    +

    {pageUser.username}

    + {pageUser.admin ?

    Admin

    :

    User

    } +
    +

    Last messages

    +
    + {messages?.map((message) => ( + + ))} +
    +
    +
    ); } \ No newline at end of file diff --git a/front/src/styles/ChannelPage.css b/front/src/styles/ChannelPage.css new file mode 100644 index 0000000..36b734c --- /dev/null +++ b/front/src/styles/ChannelPage.css @@ -0,0 +1,35 @@ +.channel-page { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + min-height: 100vh; + gap: 20px; +} + +.channel { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} + +.message-form { + margin: 16px 0; +} + +.login-prompt { + margin: 16px 0; + display: flex; + flex-direction: row; + gap: 10px; +} + +.messages-list { + width: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + gap: 10px; +} diff --git a/front/src/styles/ChannelsPage.css b/front/src/styles/ChannelsPage.css new file mode 100644 index 0000000..a320492 --- /dev/null +++ b/front/src/styles/ChannelsPage.css @@ -0,0 +1,15 @@ +.channels-page { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + min-height: 100vh; + gap: 20px; +} + +.channels-page-channels { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} \ No newline at end of file diff --git a/front/src/styles/CreateChannel.css b/front/src/styles/CreateChannel.css new file mode 100644 index 0000000..7ea8f08 --- /dev/null +++ b/front/src/styles/CreateChannel.css @@ -0,0 +1,14 @@ +.create-channel-page { + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; + width: 100%; + gap: 20px; +} + +.create-channel { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} \ No newline at end of file diff --git a/front/src/styles/Home.css b/front/src/styles/Home.css new file mode 100644 index 0000000..ab17a93 --- /dev/null +++ b/front/src/styles/Home.css @@ -0,0 +1,71 @@ +.home { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + min-height: 100vh; + gap: 20px; +} + +.main-content { + display: flex; + justify-content: space-around; + align-items: top; + width: 100%; + min-height: 100%; +} + +.home-header { + width: 97%; + border: 1px solid #270722; + display: flex; + justify-content: space-between; + align-items: top; + padding: 10px; +} + +.home-messages { + width: 60%; + border: 1px solid #270722; + padding: 10px; +} + +.messages-list { + width: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + gap: 10px; +} + +.channels { + width: 34%; + border: 1px solid #270722; + min-height: 100%; + padding: 10px; + display: flex; + flex-direction: column; +} + +@media (max-width: 800px) { + .home-header { + flex-direction: column; + align-items: center; + } + + .main-content { + flex-direction: column; + align-items: center; + gap: 20px; + } + + .home-messages { + width: 97%; + } + + .channels { + width: 97%; + } +} diff --git a/front/src/styles/Login.css b/front/src/styles/Login.css new file mode 100644 index 0000000..d24f2e9 --- /dev/null +++ b/front/src/styles/Login.css @@ -0,0 +1,14 @@ +.login-page { + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; + width: 100%; + gap: 20px; +} + +.login { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} \ No newline at end of file diff --git a/front/src/styles/MessageComponent.css b/front/src/styles/MessageComponent.css new file mode 100644 index 0000000..6bd7d62 --- /dev/null +++ b/front/src/styles/MessageComponent.css @@ -0,0 +1,5 @@ +.message { + width: 95%; + border: 1px solid #270722; + padding: 10px; +} \ No newline at end of file diff --git a/front/src/styles/Register.css b/front/src/styles/Register.css new file mode 100644 index 0000000..d17a074 --- /dev/null +++ b/front/src/styles/Register.css @@ -0,0 +1,14 @@ +.register-page { + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; + width: 100%; + gap: 20px; +} + +.register { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} \ No newline at end of file diff --git a/front/src/styles/TopBar.css b/front/src/styles/TopBar.css new file mode 100644 index 0000000..7eef8af --- /dev/null +++ b/front/src/styles/TopBar.css @@ -0,0 +1,39 @@ +.topbar { + width: 97%; + display: flex; + justify-content: space-between; + align-items: center; + border: 1px solid #270722; + padding: 10px; +} + +.topbar-left { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; +} + +.topbar-right { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; +} + +@media (max-width: 560px) { + .topbar { + flex-direction: column; + align-items: center; + } + + .topbar-left { + flex-direction: column; + align-items: center; + } + + .topbar-right { + flex-direction: column; + align-items: center; + } +} diff --git a/front/src/styles/UserPage.css b/front/src/styles/UserPage.css new file mode 100644 index 0000000..a44aa87 --- /dev/null +++ b/front/src/styles/UserPage.css @@ -0,0 +1,30 @@ +.user-page { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + min-height: 100vh; + gap: 20px; +} + +.user { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} + +.user-messages { + width: 97%; + border: 1px solid #270722; + padding: 10px; +} + +.messages-list { + width: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + gap: 10px; +}