This commit is contained in:
Cassio Santos
2020-05-23 17:19:42 -03:00
commit 47f152a145
48 changed files with 19316 additions and 0 deletions

11
frontend/src/App.css Normal file
View File

@@ -0,0 +1,11 @@
button:active {
opacity: 0.5;
}
button:focus {
outline: 0;
}
img:active {
opacity: 0.5;
}

60
frontend/src/App.js Normal file
View File

@@ -0,0 +1,60 @@
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { toast, ToastContainer } from "react-toastify";
import Home from "./pages/Home/Home";
import Chat from "./pages/Chat/Chat";
import Profile from "./pages/Profile/Profile";
import Signup from "./pages/Signup/Signup";
import Login from "./pages/Login/Login";
import "./App.css";
const App = () => {
const showToast = (type, message) => {
switch (type) {
case 0:
toast.warning(message);
break;
case 1:
toast.success(message);
break;
default:
break;
}
};
return (
<BrowserRouter>
<ToastContainer
autoClose={2000}
hideProgressBar={true}
position={toast.POSITION.TOP_CENTER}
/>
<Switch>
<Route exact path="/" render={props => <Home />} />
<Route
exact
path="/login"
render={props => <Login showToast={showToast} />}
/>
<Route
exact
path="/profile"
render={props => <Profile showToast={showToast} />}
/>
<Route
exact
path="/signup"
render={props => <Signup showToast={showToast} />}
/>
<Route
exact
path="/chat"
render={props => <Chat showToast={showToast} />}
/>
</Switch>
</BrowserRouter>
);
};
export default App;

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

View File

@@ -0,0 +1,37 @@
import React from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
const LogedinNavbar = () => {
return (
<div>
<Navbar variant="dark" bg="dark" expand="lg">
<Container>
<LinkContainer to="/" style={{ color: "#519032" }}>
<Navbar.Brand>EconoWhatsBot</Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<LinkContainer to="/">
<Nav.Link href="#home">Home</Nav.Link>
</LinkContainer>
<LinkContainer to="/chat">
<Nav.Link href="#link">Chat</Nav.Link>
</LinkContainer>
</Nav>
<LinkContainer to="/login">
<Nav.Link href="#login">Login</Nav.Link>
</LinkContainer>
<LinkContainer to="/signup">
<Nav.Link href="#signup">Signup</Nav.Link>
</LinkContainer>
</Navbar.Collapse>
</Container>
</Navbar>
</div>
);
};
export default LogedinNavbar;

View File

@@ -0,0 +1,48 @@
import React from "react";
import { useHistory } from "react-router-dom";
import { Navbar, Nav, Container } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
const DefaultNavbar = () => {
const username = localStorage.getItem("username");
const history = useHistory();
const handleLogout = e => {
e.preventDefault();
localStorage.removeItem("token");
localStorage.removeItem("userName");
localStorage.removeItem("userId");
history.push("/");
};
return (
<div>
<Navbar variant="dark" bg="dark" expand="lg">
<Container>
<LinkContainer to="/" style={{ color: "#519032" }}>
<Navbar.Brand>EconoWhatsBot</Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<LinkContainer to="/">
<Nav.Link href="#home">Home</Nav.Link>
</LinkContainer>
<LinkContainer to="/chat">
<Nav.Link href="#link">Chat</Nav.Link>
</LinkContainer>
</Nav>
<Navbar.Text>
Logado como: <a href="#login">{username}</a>
</Navbar.Text>
<Nav.Link href="#logout" onClick={handleLogout}>
Logout
</Nav.Link>
</Navbar.Collapse>
</Container>
</Navbar>
</div>
);
};
export default DefaultNavbar;

View File

11
frontend/src/index.js Normal file
View File

@@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "bootstrap/dist/css/bootstrap.min.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

View File

@@ -0,0 +1,213 @@
.root {
text-align: center;
flex-direction: column;
display: flex;
}
.body {
display: flex;
flex-direction: row;
}
.ProfilePicture {
width: 45px;
height: 45px;
left: 10px;
position: absolute;
cursor: pointer;
border-radius: 50px;
}
.ProfileHeaderText {
font-weight: bold;
color: #203152;
font-size: 20px;
/* padding: 60px; */
text-align: center;
align-items: center;
position: absolute;
margin-top: 5px;
margin-left: -10px;
}
/* .notificationpragraph {
right: 0;
bottom: 0;
} */
.newmessages {
border-radius: 20%;
width: 30px;
height: 30px;
padding: 8px;
background: green;
color: white;
text-align: center;
font: 14px Arial, sans-serif;
}
/* List user */
.viewListUser {
overflow-y: scroll;
max-height: 90vh;
min-height: 90vh;
height: auto;
width: 50vh;
/* padding-top: 10px; */
/* padding-bottom: 10px; */
}
.viewListUser::-webkit-scrollbar-track {
padding: 2px 0;
background-color: #ffffff;
}
.viewListUser::-webkit-scrollbar {
width: 6px;
}
.viewListUser::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #9999;
}
.viewWrapItem {
border: none;
display: flex;
flex-direction: row;
background-color: #fff;
max-width: 100%;
min-width: 100%;
padding: 10px;
align-items: center;
justify-content: center;
/* border-left: 15px solid #1ebea5; */
/* margin-bottom: 3px; */
border-bottom: 1px solid rgb(220, 220, 220);
}
.selectedviewWrapItem {
border: none;
display: flex;
flex-direction: row;
background-color: #e2e2e2;
max-width: 100%;
min-width: 100%;
padding: 10px;
align-items: center;
justify-content: center;
/* border-left: 15px solid #1ebea5; */
/* margin-bottom: 3px; */
border-bottom: 1px solid rgb(220, 220, 220);
}
.viewWrapItemNotification {
border: none;
display: flex;
flex-direction: row;
background-color: #1de9b6;
max-width: 44vh;
min-width: 44vh;
padding: 10px;
align-items: center;
justify-content: center;
/* border-left: 15px solid #1ebea5; */
/* margin-bottom: 3px; */
border-bottom: 1px solid rgb(220, 220, 220);
}
.viewAvatarItem {
width: 50px;
height: 50px;
border-radius: 25px;
object-fit: cover;
}
.viewWrapContentItem {
flex-direction: column;
display: flex;
flex: 1;
margin-left: 15px;
color: #203152;
word-wrap: break-word;
}
.textItem {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 240px;
text-align: left;
font-size: 14px;
}
.viewBoard {
display: flex;
flex: 1;
max-height: 90vh;
}
/* --------------------------------SEARCH BUTTON DESIGN-------------------------------- */
.rootsearchbar {
padding: 10px;
width: 100%;
margin-bottom: 10px;
background-color: #f7f7f7;
}
.input-icons i {
position: absolute;
}
.input-icons {
width: 100%;
}
.profileviewleftside {
padding: 10px;
width: 100%;
background-color: #ededed;
height: 64px;
position: relative;
margin-top: 0;
}
.input-container {
/* IE10 */
display: flex;
width: 100%;
margin-bottom: 15px;
}
.icon {
padding: 10px;
background: rgb(148, 167, 185);
color: white;
min-width: 50px;
text-align: center;
border-radius: 10px;
opacity: 0.5;
}
.input-field {
width: 100%;
border-radius: 10px;
/* margin-right: 85%; */
border: none !important;
box-shadow: none !important;
outline: none !important;
width: 100%;
padding: 10px;
text-align: center;
}
.input-field:focus {
border: 2px solid dodgerblue;
}

View File

@@ -0,0 +1,141 @@
import React, { useState, useEffect } from "react";
import "./Chat.css";
import api from "../../util/api";
import profilePic from "../../Images/canove.png";
import profileDefaultPic from "../../Images/profile_default.png";
import openSocket from "socket.io-client";
import { FiSearch } from "react-icons/fi";
import LogedinNavbar from "../../components/Navbar/LogedinNavbar";
import DefaultNavbar from "../../components/Navbar/DefaultNavbar";
import ChatBox from "../ChatBox/ChatBox";
const Chat = ({ showToast }) => {
const token = localStorage.getItem("token");
const username = localStorage.getItem("username");
const [currentPeerContact, setCurrentPeerContact] = useState(null);
const [contacts, setContacts] = useState([]);
const [displayedContacts, setDisplayedContacts] = useState([]);
useEffect(() => {
const fetchContacts = async () => {
const res = await api.get("/contacts", {
headers: { Authorization: "Bearer " + token },
});
setContacts(res.data);
setDisplayedContacts(res.data);
};
fetchContacts();
const socket = openSocket("http://localhost:8080");
socket.on("contact", data => {
console.log(data);
if (data.action === "create") {
addContact(data.contact);
}
});
return () => {
socket.disconnect();
};
}, [currentPeerContact, token]);
const addContact = contact => {
setContacts(prevState => [...prevState, contact]);
console.log("adicionando contato", contact);
setDisplayedContacts(prevState => [...prevState, contact]);
};
const handleSearchContact = e => {
let searchTerm = e.target.value.toLowerCase();
setDisplayedContacts(
contacts.filter(contact =>
contact.name.toLowerCase().includes(searchTerm)
)
);
};
const handleSelectContact = (e, contact) => {
setCurrentPeerContact(contact);
};
return (
<div>
{!localStorage.getItem("token") ? (
<div>
<DefaultNavbar />
<h1> Você não está logado </h1>
</div>
) : (
<div>
<LogedinNavbar />
<div className="root">
<div className="body">
<div className="viewListUser">
<div className="profileviewleftside">
<img className="ProfilePicture" alt="" src={profilePic} />
<span className="ProfileHeaderText">{username}</span>
</div>
<div className="rootsearchbar">
<div className="input-container">
<i className="fa fa-search icon">
<FiSearch size="20px" />
</i>
<input
className="input-field"
type="text"
placeholder="Buscar Contato"
onChange={handleSearchContact}
/>
</div>
</div>
{displayedContacts &&
displayedContacts.length > 0 &&
displayedContacts.map((contact, index) => (
<button
className={
currentPeerContact &&
currentPeerContact.id === contact.id
? "selectedviewWrapItem"
: "viewWrapItem"
}
id={contact.id}
key={contact.id}
onClick={e => handleSelectContact(e, contact)}
>
<img
className="viewAvatarItem"
alt=""
src={profileDefaultPic}
/>
<div className="viewWrapContentItem">
<span className="textItem">{contact.name}</span>
</div>
{contact.messages && contact.messages.length > 0 && (
<div className="notificationpragraph">
<p className="newmessages">
{contact.messages.length}
</p>
</div>
)}
</button>
))}
</div>
<div className="viewBoard">
{currentPeerContact ? (
<ChatBox currentPeerContact={currentPeerContact} />
) : null}
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default Chat;

View File

@@ -0,0 +1,368 @@
/* Chat board */
.viewChatBoard {
display: flex;
flex: 1;
flex-direction: column;
width: 100%;
position: relative;
background-image: url("../../Images/wa-background.png");
backface-visibility: hidden;
border-left: 1px solid #ededed;
/* border-right: 5px solid #DFA375; */
max-height: 104%;
min-height: 104%;
/* margin-right: 20px; */
border-radius: 10px;
/* box-shadow: 0 5px 5px #808888; */
}
.viewAvatarItem {
margin-left: 20px;
/* background-image: url('../../images/nopic.jpg'); */
}
.headerChatBoard {
border-bottom: 1px solid #e8e8e8;
padding: 5px;
display: flex;
background-color: #ededed;
}
.aboutme {
padding-top: 20px;
margin-left: 80px;
align-items: center;
display: flex;
position: absolute;
}
.textHeaderChatBoard {
font-weight: bold;
color: #203152;
margin-left: 10px;
}
.viewListContentChat {
display: flex;
flex: 1;
flex-direction: column;
overflow-y: scroll;
padding-top: 10px;
padding-bottom: 20px;
}
.viewListContentChat::-webkit-scrollbar-track {
padding: 2px 0;
}
.viewListContentChat::-webkit-scrollbar {
width: 15px;
}
.viewListContentChat::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #e8e8e8;
}
.teste {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #e8e8e8;
}
.viewBottom {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
height: 100px;
background-color: #f0f0f0;
}
.icOpenGallery {
width: 30px;
height: 30px;
margin-left: 10px;
}
.viewInputGallery {
opacity: 0;
position: absolute;
z-index: -1;
left: 10px;
width: 30px;
}
.icOpenSticker {
width: 30px;
height: 30px;
margin-left: 5px;
margin-right: 5px;
}
.icSend {
width: 30px;
height: 30px;
margin-left: 5px;
margin-right: 30px;
}
.viewInput {
flex: 1;
border-radius: 30px;
padding-left: 10px;
padding-right: 10px;
border: 0px;
height: 50px;
margin-right: 10px;
}
.viewInput:focus {
outline: 0;
}
input::placeholder {
color: rgb(199, 199, 199);
}
/* View item message */
.viewItemRight {
width: 300px;
height: auto;
background-color: #dcf8c6;
align-self: flex-end;
margin-right: 20px;
margin-top: 10px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 0px;
color: #203152;
text-align: left;
padding-left: 20px;
padding-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
box-shadow: 0 5px 5px #808888;
}
.viewItemRight2 {
width: 300px;
height: auto;
background-color: #e1f3fb;
align-self: flex-end;
margin-right: 20px;
margin-top: 10px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 0px;
color: #203152;
text-align: left;
box-shadow: 0 5px 5px #808888;
}
.viewItemRight3 {
width: 300px;
height: auto;
align-self: flex-end;
margin-right: 20px;
margin-top: 10px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 0px;
text-align: left;
}
.viewWrapItemLeft {
width: 300px;
text-align: left;
align-self: flex-start;
margin-left: 20px;
margin-top: 10px;
margin-bottom: -15px;
}
.viewWrapItemLeft2 {
width: 300px;
align-self: flex-start;
text-align: left;
margin-left: 20px;
margin-top: 10px;
margin-bottom: -15px;
}
.viewWrapItemLeft3 {
flex-direction: row;
display: flex;
width: 340px;
margin-bottom: -15px;
}
.viewItemLeft {
width: 300px;
height: auto;
margin-top: 10px;
background-color: #ffffff;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 8px;
padding-left: 20px;
padding-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
color: #303030;
box-shadow: 0 5px 5px #808888;
}
.viewItemLeft2 {
width: 300px;
height: auto;
background-color: #203152;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 8px;
color: white;
box-shadow: 0 5px 5px #808888;
}
.viewItemLeft3 {
width: 300px;
height: auto;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 8px;
color: white;
}
.time {
display: flex;
align-items: center;
text-align: center;
margin-left: 400px;
font: italic small-caps bold 15px/30px Georgia, serif;
width: 110px;
background-color: #e1f3fb;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 5px;
padding-right: 5px;
border-radius: 10px;
}
.timesetup {
align-items: center;
}
.peerAvatarLeft {
width: 30px;
height: 30px;
border-radius: 15px;
margin-right: 10px;
margin-bottom: 10px;
object-fit: cover;
align-self: flex-end;
}
.viewPaddingLeft {
width: 40px;
}
/* Item text */
.textContentItem {
font-size: 16px;
word-break: break-all;
}
.viewListContentChat div:last-child {
margin-bottom: 10px;
}
/* Item image */
.imgItemRight {
object-fit: cover;
width: 300px;
height: 300px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 0px;
}
.imgItemLeft {
object-fit: cover;
width: 300px;
height: 300px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 8px;
}
.textTimeLeft {
color: #808888;
font-size: 12px;
font-style: italic;
margin-left: 50px;
}
/* Stickers */
.viewStickers {
display: block;
border-top: 1px solid #e8e8e8;
height: 100px;
align-items: center;
justify-content: space-around;
overflow-x: scroll;
}
.viewStickers::-webkit-scrollbar-track {
padding: 2px 0;
}
.viewStickers::-webkit-scrollbar {
width: 15px;
}
.viewStickers::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #e8e8e8;
}
.imgSticker {
width: 80px;
height: 80px;
object-fit: contain;
}
/* Say hi */
.viewWrapSayHi {
margin-top: 20px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.textSayHi {
color: #808888;
font-size: 14px;
}
.imgWaveHand {
width: 40px;
height: 40px;
margin-left: 10px;
}

View File

@@ -0,0 +1,139 @@
import React, { useState, useEffect } from "react";
import { Card } from "react-bootstrap";
import profileDefaultPic from "../../Images/profile_default.png";
import uploadPic from "../../Images/upload.png";
import sendPic from "../../Images/send.png";
import api from "../../util/api";
import openSocket from "socket.io-client";
import ScrollToBottom from "react-scroll-to-bottom";
import "react-toastify/dist/ReactToastify.css";
import "./ChatBox.css";
const ChatBox = ({ currentPeerContact }) => {
const contactId = currentPeerContact.id;
const unreadMessages = currentPeerContact.messages;
const userId = localStorage.getItem("userId");
const username = localStorage.getItem("username");
const token = localStorage.getItem("token");
const [listMessages, setListMessages] = useState([]);
const [inputMessage, setInputMessage] = useState("");
useEffect(() => {
const fetchMessages = async () => {
try {
const res = await api.get("/messages/" + contactId, {
headers: { Authorization: "Bearer " + token },
});
setListMessages(res.data);
} catch (err) {
alert(err);
}
};
const readMesages = async () => {
try {
await api.post(
"/messages/setread",
{ messagesToSetRead: unreadMessages },
{ headers: { Authorization: "Bearer " + token } }
);
} catch (err) {
alert(err);
}
};
const socket = openSocket("http://localhost:8080");
socket.on("appMessage", data => {
if (data.action === "create") {
if (contactId === data.message.contactId) {
addMessage(data.message);
}
}
});
fetchMessages();
readMesages();
return () => {
socket.disconnect();
};
}, [contactId, unreadMessages, token]);
const handleChangeInput = e => {
setInputMessage(e.target.value);
};
const handleSendMessage = async () => {
if (inputMessage.trim() === "") return;
const message = {
read: 1,
userId: userId,
messageBody: `${username}: ${inputMessage.trim()}`,
};
try {
await api.post(`/messages/${contactId}`, message, {
headers: { Authorization: "Bearer " + token },
});
} catch (err) {
alert(err);
}
setInputMessage("");
};
const addMessage = message => {
setListMessages(prevState => [...prevState, message]);
};
return (
<Card className="viewChatBoard">
<div className="headerChatBoard">
<img className="viewAvatarItem" src={profileDefaultPic} alt="" />
<span className="textHeaderChatBoard">
<p style={{ fontSize: "20px" }}>{currentPeerContact.name}</p>
</span>
</div>
<ScrollToBottom className="viewListContentChat">
<div className="viewListContentChat">
{listMessages.map((message, index) =>
message.userId === 0 ? (
<div className="viewItemLeft" key={message.id}>
<span className="textContentItem">{message.messageBody}</span>
</div>
) : (
<div className="viewItemRight" key={message.id}>
<span className="textContentItem">{message.messageBody}</span>
</div>
)
)}
</div>
</ScrollToBottom>
<div className="viewBottom">
<img className="icOpenGallery" src={uploadPic} alt="" />
<input
// ref={input => input && input.focus()}
name="inputMessage"
className="viewInput"
placeholder="mensagem"
value={inputMessage}
onChange={handleChangeInput}
onKeyPress={e => {
if (e.key === "Enter") {
handleSendMessage();
}
}}
></input>
<img
className="icSend"
src={sendPic}
alt=""
onClick={handleSendMessage}
/>
</div>
</Card>
);
};
export default ChatBox;

View File

View File

@@ -0,0 +1,20 @@
import React from "react";
import LogedinNavbar from "../../components/Navbar/LogedinNavbar";
import DefaultNavbar from "../../components/Navbar/DefaultNavbar";
import { Container } from "react-bootstrap";
import "./Home.css";
const Home = () => {
return (
<div>
{localStorage.getItem("token") ? <LogedinNavbar /> : <DefaultNavbar />}
<Container>
<h1>Home</h1>
</Container>
</div>
);
};
export default Home;

View File

View File

@@ -0,0 +1,80 @@
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import api from "../../util/api";
import LogedinNavbar from "../../components/Navbar/LogedinNavbar";
import DefaultNavbar from "../../components/Navbar/DefaultNavbar";
import { Container, Form, Button } from "react-bootstrap";
const Login = ({ showToast }) => {
const [user, setUser] = useState({ email: "", password: "" });
const history = useHistory();
// const [token, setToken] = useState(null);
// const [userId, setUserId] = useState(null);
const handleLogin = async e => {
e.preventDefault();
try {
const res = await api.post("/auth/login", user);
// setToken(res.data.token);
// setUserId(res.data.userId);
localStorage.setItem("token", res.data.token);
localStorage.setItem("username", res.data.username);
localStorage.setItem("userId", res.data.userId);
const remainingMilliseconds = 60 * 60 * 1000;
const expiryDate = new Date(new Date().getTime() + remainingMilliseconds);
localStorage.setItem("expiryDate", expiryDate.toISOString());
showToast(1, "Login efetuado com sucesso");
history.push("/chat");
} catch (err) {
alert(err.response.data.message);
}
};
const handleChangeInput = e => {
setUser({ ...user, [e.target.name]: e.target.value });
};
return (
<div>
{localStorage.getItem("token") ? <LogedinNavbar /> : <DefaultNavbar />}
<div>
<br></br>
<Container>
<Form onSubmit={e => handleLogin(e, user)}>
<Form.Group>
{/* <Form.Label>Email address</Form.Label> */}
<Form.Control
name="email"
type="email"
placeholder="Email"
value={user.email}
onChange={handleChangeInput}
/>
</Form.Group>
<Form.Group>
{/* <Form.Label>Password</Form.Label> */}
<Form.Control
name="password"
type="password"
placeholder="Senha"
value={user.password}
onChange={handleChangeInput}
/>
</Form.Group>
<Button variant="primary" type="submit">
Entrar
</Button>
</Form>
</Container>
</div>
</div>
);
};
export default Login;

View File

View File

View File

View File

@@ -0,0 +1,88 @@
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import api from "../../util/api";
import LogedinNavbar from "../../components/Navbar/LogedinNavbar";
import DefaultNavbar from "../../components/Navbar/DefaultNavbar";
import { Container, Form, Button } from "react-bootstrap";
const Signup = () => {
const history = useHistory();
const initialState = { name: "", email: "", password: "" };
const [user, setUser] = useState(initialState);
const handleChangeInput = e => {
setUser({ ...user, [e.target.name]: e.target.value });
};
const handleSignUp = async e => {
e.preventDefault();
try {
await api.put("/auth/signup", user);
} catch (err) {
alert(err);
}
history.push("/login");
};
return (
<div>
{localStorage.getItem("token") ? (
<div>
<LogedinNavbar />
<h1> Você está logado </h1>
</div>
) : (
<div>
<DefaultNavbar />
<br></br>
<Container>
<Form onSubmit={handleSignUp}>
<Form.Group>
{/* <Form.Label>Nome</Form.Label> */}
<Form.Control
name="name"
type="text"
placeholder="Nome"
value={user.name}
onChange={handleChangeInput}
/>
</Form.Group>
<Form.Group>
{/* <Form.Label>Email address</Form.Label> */}
<Form.Control
name="email"
type="email"
placeholder="Email"
value={user.email}
onChange={handleChangeInput}
/>
</Form.Group>
<Form.Group>
{/* <Form.Label>Password</Form.Label> */}
<Form.Control
name="password"
type="password"
placeholder="Senha"
value={user.password}
onChange={handleChangeInput}
/>
<Form.Text className="text-muted">
Mínimo de 5 caracteres.
</Form.Text>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Container>
</div>
)}
<br></br>
</div>
);
};
export default Signup;

7
frontend/src/util/api.js Normal file
View File

@@ -0,0 +1,7 @@
import axios from "axios";
const api = axios.create({
baseURL: "http://localhost:8080",
});
export default api;