seanoh

Finish README

......@@ -3,7 +3,6 @@ tunnel_BE/server/node_modules
# dependencies
/.pnp
.pnp.js
>>>>>>> board
### VisualStudioCode ###
.vscode/*
......
......@@ -16,6 +16,7 @@ ENGINE = InnoDB;
CREATE TABLE tunnel.posts(
id INT NOT NULL AUTO_INCREMENT,
userid VARCHAR(30) NOT NULL,
title TEXT NOT NULL,
post TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT now(),
status TINYINT NOT NULL,
......
......@@ -3,6 +3,10 @@ const Sequelize = require('sequelize');
module.exports = class Comment extends Sequelize.Model {
static init(sequelize) {
return super.init({
postid:{
type: Sequelize.INTEGER,
allowNull: false,
},
userid:{
type: Sequelize.STRING(30),
allowNull: false,
......@@ -31,6 +35,6 @@ module.exports = class Comment extends Sequelize.Model {
static associate(db) {
db.Comment.belongsTo(db.Post,{foreignKey: 'postid', targetKey:'id' });
//db.Comment.belongsTo(db.Post,{foreignKey: 'postid', targetKey:'id' });
}
};
\ No newline at end of file
......
const express = require("express");
const bodyParser = require("body-parser");
const router = express.Router();
const auth = require("../obj/authorize");
const {User}=require('../models'); //유저정보 db연결
const {Post}=require('../models'); //게시물정보 db연결
const {Comment}=require('../models');
//현재 로그인된 사용자의 게시물 배열 응답
router.post('/reply',auth,(req,res)=>{
Comment.findAll({
where:{postid: req.body.id},
order: [['created_at', 'ASC']],
})
.then((result)=>{
//console.log(result);
res.send(result);
//게시물이 0개인 경우
// if(result === null || result === undefined){
// console.log("해당유저의 게시물이 없습니다.")
// res.status(401).send("null");
// }
// else{
// console.log(result.length);
// res.sendStatus(200);
// }
})
});
//게시물 작성
router.post('/write',auth,(req,res)=>{
console.log(req.params.id);
try{
Comment.create({
userid : req.session.name,
postid : req.body.postid,
comment : req.body.comment,
})
console.log("게시");
res.sendStatus(200);
} catch(err){
console.log("실패");
res.send(err);
}
/*
User.create({
name: req.body.Id,
pw:req.body.Password,
personality:req.body.Personality,
status:false
*/
});
module.exports = router;
\ No newline at end of file
......@@ -8,9 +8,9 @@ const {Post}=require('../models'); //게시물정보 db연결
//현재 로그인된 사용자의 게시물 배열 응답
router.get('/',auth,(req,res)=>{
Post.findAll({
//where:{userid: req.session.name}
// where:{userid: req.session.name},
order: [['created_at', 'DESC']],
})
.then((result)=>{
//console.log(result);
......
......@@ -18,6 +18,7 @@ const logoutRouter = require('./routes/logout.js');
const authRouter = require('./routes/auth.js');
const userRouter = require('./routes/user.js');
const postRouter = require('./routes/post.js');
const commentRouter = require('./routes/comment.js');
const app = express();
app.set('port', process.env.PORT || 3001);
......@@ -57,6 +58,7 @@ app.use('/api/auth',authRouter);//가입여부 확인
app.use('/api/logout',logoutRouter);//로그아웃
app.use('/api/user',userRouter);//유저정보 응답
app.use('/api/post',postRouter);//유저정보 응답
app.use('/api/comment',commentRouter);//유저정보 응답
//에러처리 미들웨어
......
import Axios from 'axios';
import React, { useState, useEffect} from 'react';
import '../style/Board.scss'
import ReactHtmlParser from 'react-html-parser';
import BoardModal from "../Modal/BoardModal";
import ContentModal from '../Modal/ContentModal';
function Board() {
const [viewContent,setViewContent] = useState([]);
......@@ -15,16 +14,12 @@ function Board() {
},[viewContent])
return (
<div className="Board">
<div className="write-button">
<BoardModal/>
</div>
<div className="contents">
{viewContent&&viewContent.map(element =>{
return <div className="ui segment">
<h2>{element.title}</h2>
<div>
{ReactHtmlParser(element.post)}
</div>
<h4>{element.created_at.slice(0,10)+" " +element.created_at.slice(11,16)}</h4>
<ContentModal element={element}/>
</div>}
)}
</div>
......
......@@ -4,6 +4,7 @@ import "../style/MainPage.scss";
import { useNavigate } from "react-router-dom";
import Board from "../Board/Board"
import React from "react";
import BoardModal from "../Modal/BoardModal";
function MainPage(props) {
const navigate = useNavigate();
......@@ -19,44 +20,22 @@ function MainPage(props) {
return (
<div id="Main">
<div className="Main-header">
<div className="title">
<h1>"말하기 어려운 고민 여기에 털어놓으세요 :)"</h1>
<div className="wrapper">
<div className="title">
<h1 style={{color: 'white'}}>"말하기 어려운 고민 여기에 털어놓으세요 :)"</h1>
</div>
<div className="None-title">
<Button className="ui right floated button" onClick={()=>onLogout()}>
Logout
</Button>
</div>
</div>
<div className="None-title">
<Button className="ui right floated button" onClick={()=>onLogout()}>
Logout
</Button>
<div className="write-btn">
<BoardModal/>
</div>
</div>
<div className="Main-body">
<Board/>
{/* <div className="user-container">
<div className="userInfo">
<h1>User ID</h1>
</div>
<div className="checkIssue-button">
<Button className="ui animated button"
tabIndex="0">
<div className="visible content">도착한 글</div>
<div className="hidden content">
<i className="paper plane icon"></i>
</div>
</Button>
</div>
<div className="user">
<div className="Answer">
<div className="ui segment">
<p>a</p>
</div>
<div className="ui segment">
<p>a</p>
</div>
<div className="ui segment">
<p>a</p>
</div>
</div>
</div>
</div> */}
</div>
</div>
);
......
......@@ -4,6 +4,7 @@ import { Button, Modal } from 'semantic-ui-react'
import {CKEditor} from "@ckeditor/ckeditor5-react";
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
function BoardModal() {
const handleClose = (event) => {
event.preventDefault();
......@@ -50,12 +51,9 @@ function BoardModal() {
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
trigger={<Button className="ui animated button" tabIndex="0">
<div className="visible content">게시글 작성하기</div>
<div className="hidden content">
<i className="pencil alternate icon"></i>
</div>
</Button>}
trigger={<Button className="ui right floated button" tabIndex="0" >
게시글 작성하기
</Button>}
>
<Modal.Header>고민이 있나요?</Modal.Header>
<Modal.Content >
......
import React, {useState, useEffect} from 'react'
import Axios from 'axios'
import ReactHtmlParser from 'react-html-parser';
import { Button, Modal, Comment, Form } from 'semantic-ui-react'
import '../style/ContentModal.scss'
function ContentModal({element}) {
const [viewComment,setviewComment] = useState([]);
useEffect(()=>{
Axios.post('/api/comment/reply',{id : element.id}).then((response)=>{
setviewComment(response.data);
})
},[viewComment])
const handleClose = (event) => {
event.preventDefault();
setOpen(false);
}
const [open, setOpen] = useState(false)
const [BoardComment, setBoardComment] = useState('')
const onCommentHandler = (event) => {
setBoardComment(event.currentTarget.value)
console.log(BoardComment)
}
const onSubmitHandler = () => {
Axios.post('/api/comment/write',{
postid: element.id,
comment: BoardComment
})
.then((res)=>{
if(res.status === 200){
alert("댓글 작성을 완료하였습니다.")
setOpen(false);
}
}).catch((error) => {
console.log(error.response)
alert("댓글 작성을 실패하였습니다.")
})
}
return (
<Modal
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
trigger={<Button basic color='purple' className="ui floated button" tabIndex="0">
보기
</Button>}
>
<Modal.Header><h2>{element.title}</h2></Modal.Header>
<Modal.Content>
<Modal.Description>
<div className="problems">
{ReactHtmlParser(element.post)}
</div>
</Modal.Description>
</Modal.Content>
<Modal.Content>
{viewComment&&viewComment.map(elem =>{
return <div className="ui segment">
<h4>{elem.userid}</h4>
<h4>{elem.comment}</h4>
</div>}
)}
</Modal.Content>
<Modal.Actions>
<Comment>
<Form reply>
<Form.TextArea value={BoardComment} onChange={onCommentHandler}/>
<Button content='댓글 남기기' onClick={onSubmitHandler} labelPosition='left' icon='edit' primary />
<Button onClick={handleClose} color='black'>닫기</Button>
</Form>
</Comment>
</Modal.Actions>
</Modal>
)
}
export default ContentModal
\ No newline at end of file
import React, {useState, useCallback} from "react";
import { useNavigate } from "react-router-dom";
import "../style/RegisterPage.scss";
import { Button, Icon, Input } from "semantic-ui-react";
import { Button, Dropdown, Icon, Input} from "semantic-ui-react";
import Axios from 'axios'
function RegisterPage(props) {
const navigate = useNavigate();
......@@ -16,7 +16,7 @@ function RegisterPage(props) {
setPassword(event.currentTarget.value);
};
const onPersonalityHandler = (event) => {
setPersonality(event.currentTarget.value);
setPersonality(event.currentTarget.value.toUpperCase());
};
const onPasswordChkHandler = (event) => {
//비밀번호를 입력할때마다 password 를 검증하는 함수
......@@ -30,6 +30,11 @@ function RegisterPage(props) {
if (Password !== PasswordCheck) {
return alert('비밀번호가 일치하지 않습니다.')
}
else if((Personality[0] !== 'I' && Personality[0] !== 'E') || (Personality[1] !== 'S' && Personality[1] !== 'N')
|| (Personality[2] !== 'F' && Personality[2] !== 'T') || (Personality[3] !== 'J' && Personality[3] !== 'P'))
{
return alert('올바르지 않은 MBTI입니다.')
}
else{
Axios.post('/api/register',{
Id,
......@@ -67,6 +72,7 @@ function RegisterPage(props) {
icon={<Icon name='heart'/>}
iconPosition='left'
placeholder="Your MBTI"
maxlength='4'
type="text"
value={Personality}
autoComplete="off"
......
......@@ -11,16 +11,22 @@
margin: 10px;
}
.write-button{
margin-bottom: 30px;
height: 70px;
display: flex;
justify-content: center;
align-items: center;
}
.contents{
background-color: rgb(36, 83, 121);
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 30px;
border: 2px solid #333;
.ui.segment{
padding: 20px;
width: 67%;
text-align: center;
}
}
\ No newline at end of file
......
.title-input{
width: 500px;
height: 40px;
margin: 10px;
}
.write-button{
height: 70px;
display: flex;
justify-content: center;
align-items: center;
}
\ No newline at end of file
.header{
text-align: center;
display: flex;
}
.content{
height: fit-content;
text-align: left;
}
\ No newline at end of file
#Main{
background-color: beige;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.Main-header{
background-color: rgb(77, 62, 161);
position: fixed;
top: 0;
left: 0;
z-index: 10;
text-align: center;
display: flex;
flex-direction: row;
height: 70px;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 120px;
.wrapper{
display: flex;
flex-direction: row;
margin-bottom: 20px;
width:100%;
}
.title{
display: flex;
justify-content: center;
align-items: center;
width: 90%;
width: 100%;
.h1{
font-family:Arial, Helvetica, sans-serif;
font-size: 60px;
......@@ -19,44 +34,25 @@
}
.None-title{
display: flex;
justify-content: center;
justify-content:right;
align-items: center;
width: 10%;
.ui button{
height: 40px;
}
}
}
.Main-body{
padding-top: 120px;
display: flex;
flex-direction: row;
height: 100vh;
border: 3px solid black;
justify-content: center;
align-items: center;
width: 100%;
.Board{
text-align: center;
display: flex;
justify-content: flex-start;
flex-direction: column;
width: 100%;
height: 100%;
}
.user-container{
display: flex;
flex-direction: column;
width: 25%;
border: 2px solid black;
padding: 10px 0 30px 0;
.userInfo{
display: flex;
justify-content: center;
align-items: center;
}
.checkIssue-button{
height: 70px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
}
......