Fakultas Ilmu Komputer UI

Commit 0677eced authored by Muhammad Rafif Elfazri's avatar Muhammad Rafif Elfazri
Browse files

Merge branch 'master' of...

Merge branch 'master' of https://gitlab.cs.ui.ac.id/functional-programming/diskuy-frontend into deploy
parents e7821a52 98c67a46
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"bracketSpacing": true
}
\ No newline at end of file
......@@ -9,6 +9,7 @@
"axios": "^0.21.1",
"http-proxy-middleware": "^1.0.6",
"nodemon": "^2.0.7",
"prettier": "^2.2.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-google-login": "^5.2.2",
......@@ -47,6 +48,5 @@
"description": "This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).",
"main": "index.js",
"author": "",
"license": "ISC",
"proxy": "https://diskuyapi-google.herokuapp.com/api"
"license": "ISC"
}
const path = require('path')
const express = require('express')
const { createProxyMiddleware } = require('http-proxy-middleware')
const path = require('path');
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const port = process.env.PORT || 3000
const app = express()
const publicPath = path.join(__dirname, '..', 'build')
const port = process.env.PORT || 3000;
const app = express();
const publicPath = path.join(__dirname, '..', 'build');
app.use(express.static(publicPath))
app.use(express.static(publicPath));
app.use('/api', createProxyMiddleware({target: 'https://diskuyapi-google.herokuapp.com', changeOrigin: true,}))
app.use(
'/api',
createProxyMiddleware({
target: 'https://diskuyapi-google.herokuapp.com',
changeOrigin: true,
})
);
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'))
})
res.sendFile(path.join(publicPath, 'index.html'));
});
app.listen(port, () => {
console.log(`Server is up on port ${port}`)
})
console.log(`Server is up on port ${port}`);
});
import React from 'react';
import '../styles/LoginForm.css';
import { GoogleLogin } from 'react-google-login';
import { API_URL, CLIENT_ID } from '../config/keys'
import { API_URL, CLIENT_ID } from '../config/keys';
import axios from 'axios';
import authHeader from '../helpers/services/authHeader.service';
export default function LoginForm(props) {
const handleGoogleLogin = (response) => {
localStorage.setItem('user', JSON.stringify(response));
props.history.push('/page/1');
callback();
};
const handleGoogleLogin = (response) => {
localStorage.setItem('user', JSON.stringify(response));
props.history.push('/page/1');
callback();
};
async function callback() {
var response = await axios.get(`${API_URL}/auth/google/callback`, {
headers: authHeader()
});
localStorage.setItem('user', JSON.stringify(response));
window.location.reload();
}
async function callback() {
var response = await axios.get(`${API_URL}/auth/google/callback`, {
headers: authHeader(),
});
localStorage.setItem('user', JSON.stringify(response));
window.location.reload();
}
const handleGoogleLoginFailed = () => {};
const handleGoogleLoginFailed = () => {};
return (
<div className="formContainer">
<div className="App">
<GoogleLogin
clientId={CLIENT_ID}
onSuccess={handleGoogleLogin}
onFailure={handleGoogleLoginFailed}
/>
</div>
</div>
);
return (
<div className="loginFormContainer">
<h1><b>Login to discuss anything on Diskuy</b></h1>
<div className="App">
<GoogleLogin
clientId={CLIENT_ID}
onSuccess={handleGoogleLogin}
onFailure={handleGoogleLoginFailed}
/>
</div>
</div>
);
}
......@@ -4,42 +4,50 @@ import axios from 'axios';
import ThreadList from './thread/ThreadList';
import { API_URL } from '../config/keys';
import Pagination from './thread/Pagination';
import "../styles/Search.css"
export default function Search(props) {
const [ threads, setThreads ] = useState([]);
const searchParam = props.match.params.input;
const [ currentPage, setCurrentPage ] = useState(props.match.params.pageNumber);
const [ totalItems, setTotalItems ] = useState(0);
const { params } = props.match;
const searchParam = params.input;
const currentPage = params.pageNumber;
if (currentPage != props.match.params.pageNumber) {
window.location.reload();
}
const [threads, setThreads] = useState([]);
const [totalItems, setTotalItems] = useState(0);
useEffect(
() => {
const fetch = async () => {
const responseThreads = await axios.get(
`${API_URL}/threads/pages/search/${searchParam}/?page=${currentPage}`
);
console.log(responseThreads.data.data);
setThreads(responseThreads.data.data);
setTotalItems(responseThreads.data.metadata.total_data);
};
fetch();
},
[ searchParam, currentPage ]
);
if (currentPage != params.pageNumber) {
window.location.reload();
}
function swithPage(pageNumber) {
props.history.push(`/search/${searchParam}/${pageNumber}`);
window.location.reload();
}
useEffect(() => {
const fetch = async () => {
const responseThreads = await axios.get(
`${API_URL}/threads/pages/search/${searchParam}/?page=${currentPage}`
);
const { data } = responseThreads;
setThreads(data?.data);
setTotalItems(data?.metadata?.total_data);
};
fetch();
}, [searchParam, currentPage]);
return (
<div>
<h1>Search results for '{searchParam}'</h1>
<ThreadList thread={threads} />
{totalItems != 0 && <Pagination activePage={currentPage} totalItems={totalItems} switchPage={swithPage} />}
</div>
);
function switchPage(pageNumber) {
props.history.push(`/search/${searchParam}/page/${pageNumber}`);
window.location.reload();
}
return (
<div className="searchresultContainer">
<h1><b>Search Results for "{searchParam}"</b></h1>
<ThreadList thread={threads} />
{totalItems != 0 && (
<div className="paginationContainer">
<Pagination
activePage={currentPage}
totalItems={totalItems}
switchPage={switchPage}
/>
</div>
)}
</div>
);
}
......@@ -8,75 +8,98 @@ import AuthService from '../../helpers/services/auth.service';
import { API_URL } from '../../config/keys';
import Pagination from '../thread/Pagination';
function Profile(props) {
const username = AuthService.getCurrentUsername();
const profileUsername = props.match.params.user;
const [ user, setUser ] = useState({
id: '',
name: '',
username: ''
});
const [ usersThreads, setUsersThreads ] = useState([]);
const [ currentPage, setCurrentPage ] = useState(props.match.params.pageNumber);
const [ totalItems, setTotalItems ] = useState(0);
export default function Profile(props) {
const { params } = props.match;
const profileUsername = params.user;
const currentPage = params.pageNumber;
useEffect(
() => {
async function fetch(profileUsername) {
const getUser = await axios.get(`${API_URL}/users/name/${profileUsername}`);
const currentUser = getUser.data.data;
setUser(currentUser);
const username = AuthService.getCurrentUsername();
const responseThreads = await axios.get(
`${API_URL}/threads/pages/user/${profileUsername}/?page=${currentPage}`
);
setUsersThreads(responseThreads.data.data);
setTotalItems(responseThreads.data.metadata.total_data);
}
fetch(profileUsername);
},
[ currentPage, profileUsername ]
);
const [user, setUser] = useState({
id: '',
name: '',
username: '',
});
const [usersThreads, setUsersThreads] = useState([]);
const [totalItems, setTotalItems] = useState(0);
function swithPage(pageNumber) {
props.history.push(`/profile/${profileUsername}/${pageNumber}`);
window.location.reload();
}
useEffect(() => {
async function fetch(profileUsername) {
// Fetch current user
const getUser = await axios.get(
`${API_URL}/users/name/${profileUsername}`
);
setUser(getUser?.data?.data);
return (
<div>
<div className="header">
<h1>
<b>Profile</b>
</h1>
</div>
<div className="profile_section">
<div className="userIcon">
{user.picture == 'None' && <i class="far fa-user-circle" />}
{user.picture != 'None' && <img alt="profile pic" src={user.picture} />}
</div>
<h2>
<b>{user.username}</b>
</h2>
{username == profileUsername && <Button text="Edit Profile" color="orange" url="profile/update" />}
</div>
<div className="my_threads_section">
<div className="sub_header_my_threads">
<h3>
<b>Threads Created by {user.username}</b>
</h3>
const responseThreads = await axios.get(
`${API_URL}/threads/pages/user/${profileUsername}/?page=${currentPage}`
);
const { data } = responseThreads;
setUsersThreads(data?.data);
setTotalItems(data?.metadata?.total_data);
}
fetch(profileUsername);
}, [currentPage, profileUsername]);
{username == profileUsername && <Button text="Create Thread" color="orange" url="create/thread" />}
</div>
{totalItems == 0 && <p>You don't have any thread. Why don't you make one?</p>}
function switchPage(pageNumber) {
props.history.push(`/profile/${profileUsername}/page/${pageNumber}`);
window.location.reload();
}
{totalItems != 0 && <ThreadList thread={usersThreads} />}
{totalItems != 0 && (
<Pagination activePage={currentPage} totalItems={totalItems} switchPage={swithPage} />
)}
</div>
</div>
);
}
return (
<div className="profileContainer">
<div className="header">
<h1>
<b>Profile</b>
</h1>
</div>
<div className="profile_section">
<div className="userIcon">
{user.picture == 'None' && <i className="far fa-user-circle" />}
{user.picture != 'None' && (
<img alt="profile pic" src={user.picture} />
)}
</div>
<h2>
<b>{user.username}</b>
</h2>
{username == profileUsername && (
<Button text="Edit Profile" color="orange" url="profile/update" />
)}
</div>
<div className="my_threads_section">
<div className="sub_header_my_threads">
<h3>
{username == profileUsername && (
<b>Your threads</b>
)}
{username != profileUsername && (
<b>{user.username}s threads</b>
)}
</h3>
{username == profileUsername && (
<Button text="Create Thread" color="orange" url="create/thread" />
)}
</div>
{totalItems == 0 && username == profileUsername && (
<p>You don't have any thread. Why don't you make one?</p>
)}
{totalItems == 0 && username != profileUsername && (
<p>{user.username} doesn't have any threads.</p>
)}
export default Profile;
{totalItems != 0 && <ThreadList thread={usersThreads} />}
{totalItems != 0 && (
<div className="paginationContainer">
<Pagination
activePage={currentPage}
totalItems={totalItems}
switchPage={switchPage}
/>
</div>
)}
</div>
</div>
);
}
......@@ -3,61 +3,84 @@ import React, { useState } from 'react';
import { useInput } from '../../helpers/hooks/input-hook';
import '../../styles/profile/UpdateProfileForm.css';
import authHeader from '../../helpers/services/authHeader.service';
import { API_URL } from '../../config/keys';
export default function FormCreateThread(props) {
const { value: username, bind: bindUsername, reset: resetUsername } = useInput('');
const [ message, setMessage ] = useState('');
const {
value: username,
bind: bindUsername,
reset: resetUsername,
} = useInput('');
const [message, setMessage] = useState('');
const handleSubmit = async (event) => {
event.preventDefault();
try {
await axios.put(
`https://diskuyapi-google.herokuapp.com/api/users/update`,
{
user: {
username: username
}
},
{
headers: authHeader()
}
);
const currentUser = JSON.parse(localStorage.getItem('user'));
currentUser.data.username = username;
console.log(currentUser);
const back = () => {
props.history.goBack();
};
localStorage.setItem('user', JSON.stringify(currentUser));
const handleSubmit = async (event) => {
event.preventDefault();
try {
await axios.put(
`${API_URL}/users/update`,
{
user: {
username: username,
},
},
{
headers: authHeader(),
}
);
const currentUser = JSON.parse(localStorage.getItem('user'));
currentUser.data.username = username;
props.history.push(`/profile/${username}/1`);
} catch (error) {
setMessage('Username is already used by another User!');
}
resetUsername();
};
localStorage.setItem('user', JSON.stringify(currentUser));
return (
<div>
{message && (
<div>
<div className="alert alert-danger" role="alert">
{message}
</div>
</div>
)}
<form onSubmit={handleSubmit}>
<div className="form_container">
<label for="title">Change Username</label>
<input
type="text"
className="username"
name="username"
placeholder="Your new Username"
required="false"
{...bindUsername}
/>
<input type="submit" className="buttonSubmit" value="Update Profile" />
</div>
</form>
</div>
);
props.history.push(`/profile/${username}/1`);
} catch (error) {
setMessage('Username is already used by another User!');
}
resetUsername();
};
return (
<div className="updateProfileFormContainer">
<div className="back" onClick={back}>
<i class="fas fa-angle-left"></i>
<h5>Back</h5>
</div>
<div className="header">
<h1>
<b>Edit Profile</b>
</h1>
</div>
{message && (
<div>
<div className="alert alert-danger" role="alert">
{message}
</div>
</div>
)}
<form onSubmit={handleSubmit}>
<div className="form_container">
<label htmlFor="title">Username</label>
<input
type="text"
className="username"
name="username"
placeholder="Your new Username"
required="false"
{...bindUsername}
/>
<div className="buttonContainer">
<input
type="submit"
className="buttonSubmit"
value="Update Profile"
/>
</div>
</div>
</form>
</div>
);
}
import Post from './Post';
export default function CommentList(props) {
return (
<div>
{props.comment.map((value) => (
<div id="threadComment">
<Post type="comment" content={value} />
</div>
))}
</div>
);
return (
<div>
{props.comment.map((value) => (
<div id="threadComment">
<Post type="comment" content={value} />
</div>
))}
</div>
);
}
import React from 'react';
import axios from 'axios';
import React, { useState, useEffect } from 'react';
import { useInput } from '../../helpers/hooks/input-hook';
import authHeader from '../../helpers/services/authHeader.service';
import { API_URL } from '../../config/keys';
import '../../styles/thread/CreateThread.css';
import FormCreateThread from './form/FormCreateThread';
function ListThreads(props) {
const back = () => {
props.history.goBack();
};
const redirect = (path) => {
props.history.push(path);
};
return (
<div>
<div className="back" onClick={back}>
<h5>Back</h5>
</div>
<div className="header">
<h1>
<b>Create a Thread</b>
</h1>
</div>
<div className="form_section">
<FormCreateThread redirect={redirect} />
</div>
</div>
);
}
export default ListThreads;
export default function ListThreads(props) {
const { history } = props;
const back = () => {
history.goBack();
};
const redirect = (path) => {
history.push(path);
};
const { value: title, bind: bindTitle, reset: resetTitle } = useInput('');
const { value: body, bind: bindBody, reset: resetBody } = useInput('');
const { value: topicId, bind: bindTopicId, reset: resetTopicId } = useInput(
0
);
const [listTopic, setlistTopic] = useState([]);
const [message, setMessage] = useState('');