Commit 660e363c authored by Kim, Subin's avatar Kim, Subin
Browse files

Merge branch 'kimpen'

parents 52f6e103 b7b819be
...@@ -6,6 +6,11 @@ const getTodo = async (userId, date = "", todoId = "") => { ...@@ -6,6 +6,11 @@ const getTodo = async (userId, date = "", todoId = "") => {
return data return data
} }
const getTodopercent = async (userId, start, end = "") => {
const { data } = await axios.get(`${baseUrl}/api/todo/percent/${userId}?start=${start}&end=${end}`)
return data
}
const submit = async (todo, userId) => { const submit = async (todo, userId) => {
const { data } = await axios.post(`${baseUrl}/api/todo/${userId}`, todo) const { data } = await axios.post(`${baseUrl}/api/todo/${userId}`, todo)
return data return data
...@@ -23,6 +28,7 @@ const remove = async (todoId, userId) => { ...@@ -23,6 +28,7 @@ const remove = async (todoId, userId) => {
const todoApi = { const todoApi = {
getTodo, getTodo,
getTodopercent,
submit, submit,
edit, edit,
remove remove
......
...@@ -97,7 +97,7 @@ const ScheduleForm = () => { ...@@ -97,7 +97,7 @@ const ScheduleForm = () => {
return ( return (
<form className="pt-5"> <form className="pt-5">
<div> <div>
<input className={`form-control form-control-lg shadow-none rounded-0 px-1 mb-5 ${styles.textInput}`} type="text" name="title" value={schedule.title} placeholder="제목" aria-label="title" onChange={handleChange} autoFocus /> <input className={`form-control form-control-lg shadow-none rounded-0 px-1 mb-5 ${styles.textInput}`} type="text" name="title" value={schedule.title} placeholder="제목" aria-label="title" onChange={handleChange} autoFocus autoComplete="off" />
</div> </div>
<div className="d-flex mb-4"> <div className="d-flex mb-4">
<label className="col col-form-label align-self-center py-0">시작</label> <label className="col col-form-label align-self-center py-0">시작</label>
......
...@@ -119,7 +119,7 @@ const StudyPlanEditForm = () => { ...@@ -119,7 +119,7 @@ const StudyPlanEditForm = () => {
</select> </select>
<input type="text" name="studyplanTitle" <input type="text" name="studyplanTitle"
className={`form-control shadow-none rounded-0 mb-5 ${styles.textInput}`} className={`form-control shadow-none rounded-0 mb-5 ${styles.textInput}`}
placeholder="제목" value={studyplan.studyplanTitle} onChange={handleChange} /> placeholder="제목" value={studyplan.studyplanTitle} onChange={handleChange} autoComplete="off" />
<div className="d-flex mb-3"> <div className="d-flex mb-3">
<label className="col col-form-label align-self-center py-0">마감일</label> <label className="col col-form-label align-self-center py-0">마감일</label>
<div className={studyplan.deadline === "on" ? "col-5" : "col-7"}> <div className={studyplan.deadline === "on" ? "col-5" : "col-7"}>
......
...@@ -83,15 +83,15 @@ const SubjectForm = () => { ...@@ -83,15 +83,15 @@ const SubjectForm = () => {
<div> <div>
<div className="mb-5 d-flex flex-row"> <div className="mb-5 d-flex flex-row">
<label className="form-label fs-4" style={{ width: "100px" }}>강의명</label> <label className="form-label fs-4" style={{ width: "100px" }}>강의명</label>
<input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.lectureName} name="lectureName" onChange={handleChange} /> <input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.lectureName} name="lectureName" onChange={handleChange} autoComplete="off" />
</div> </div>
<div className="mb-5 pt-2 d-flex flex-row"> <div className="mb-5 pt-2 d-flex flex-row">
<label className="form-label fs-4" style={{ width: "100px" }}>교수명</label> <label className="form-label fs-4" style={{ width: "100px" }}>교수명</label>
<input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.prof} name="prof" onChange={handleChange} /> <input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.prof} name="prof" onChange={handleChange} autoComplete="off" />
</div> </div>
<div className="mb-5 pt-2 d-flex flex-row"> <div className="mb-5 pt-2 d-flex flex-row">
<label className="form-label fs-4 " style={{ width: "100px", letterSpacing: "15px" }}>장소</label> <label className="form-label fs-4 " style={{ width: "100px", letterSpacing: "15px" }}>장소</label>
<input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.classRoom} name="classRoom" onChange={handleChange} /> <input className={`form-control shadow-none rounded-0 ${styles.textInput}`} value={subject.classRoom} name="classRoom" onChange={handleChange} autoComplete="off" />
</div> </div>
</div> </div>
<div className="pt-2"> <div className="pt-2">
......
...@@ -8,7 +8,7 @@ import styles from "./menu.module.scss"; ...@@ -8,7 +8,7 @@ import styles from "./menu.module.scss";
const Menu = () => { const Menu = () => {
const { user, logout } = useAuth(); const { user, logout } = useAuth();
const [todoList, setTodoList] = useState([]) const [todoList, setTodoList] = useState({ percent: 0, list: [] })
const [error, setError] = useState(""); const [error, setError] = useState("");
useEffect(() => { useEffect(() => {
...@@ -18,9 +18,9 @@ const Menu = () => { ...@@ -18,9 +18,9 @@ const Menu = () => {
async function todayTodo() { async function todayTodo() {
try { try {
setError("") setError("")
const result = await todoApi.getTodo(user.id, moment().format("YYYY-MM-DD")) const result = await todoApi.getTodopercent(user.id, moment().format("YYYY-MM-DD"))
console.log("client resList",result) console.log("client resList",result)
setTodoList(result) setTodoList({...todoList, ...result})
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
} }
...@@ -36,23 +36,17 @@ const Menu = () => { ...@@ -36,23 +36,17 @@ const Menu = () => {
<button type="button" className={`btn-close btn-close-white btn-lg position-absolute ${styles.close}`} data-bs-toggle="collapse" data-bs-target="#menuContent" aria-controls="menuContent" aria-expanded="true" aria-label="menu"></button> <button type="button" className={`btn-close btn-close-white btn-lg position-absolute ${styles.close}`} data-bs-toggle="collapse" data-bs-target="#menuContent" aria-controls="menuContent" aria-expanded="true" aria-label="menu"></button>
<div className="d-flex flex-column align-items-center text-white py-5" style={{ backgroundColor: "crimson" }}> <div className="d-flex flex-column align-items-center text-white py-5" style={{ backgroundColor: "crimson" }}>
<h1 className="my-3">{user.name} </h1> <h1 className="my-3">{user.name} </h1>
<h2 className="my-2">오늘의 목표 95% 달성!</h2> <h2 className="my-2">오늘의 목표 {todoList.percent}% 달성!</h2>
</div> </div>
<div className="d-flex flex-column justify-content-between flex-grow-1 py-4 ps-3 text-dark" > <div className="d-flex flex-column justify-content-between flex-grow-1 py-4 ps-3 text-dark" >
<div className="user-select-none w-75 ps-3"> <div className="user-select-none w-75 ps-3">
<h2 className="mb-5">To-do</h2> <h2 className="mb-4">To-do</h2>
<div className="d-flex mt-2"> {todoList.list.length!==0 ? todoList.list.map((todo, idx) => {
<p className={`form-check-label border-bottom border-2 fs-5 pb-1 me-3 ${styles.title}`}>sdasdsasdasdsadsadsadsadsadsadsadaddad</p> if (idx <= 2) return <div className="d-flex">
<input className={`form-check-input rounded-0 border-dark shadow-none mt-1 ${styles.checkBox}`} type="checkbox" id="inlineCheckbox1" value="" aria-label="checkbox" /> <p className={`form-check-label border-bottom border-2 fs-5 pb-1 me-3 ${styles.title}`}>{todo.title}</p>
</div> <input className={`form-check-input rounded-0 border-dark shadow-none mt-1 ${styles.checkBox}`} type="checkbox" id="inlineCheckbox1" aria-label="checkbox" checked={todo.done} />
<div className="d-flex">
<p className={`form-check-label border-bottom border-2 fs-5 pb-1 me-3 ${styles.title}`}>sdasdsadad</p>
<input className={`form-check-input rounded-0 border-dark shadow-none mt-1 ${styles.checkBox}`} type="checkbox" id="inlineCheckbox1" value="" aria-label="checkbox" />
</div>
<div className="d-flex">
<p className={`form-check-label border-bottom border-2 fs-5 pb-1 me-3 ${styles.title}`}>sdasdsadad</p>
<input className={`form-check-input rounded-0 border-dark shadow-none mt-1 ${styles.checkBox}`} type="checkbox" id="inlineCheckbox1" value="" aria-label="checkbox" />
</div> </div>
}) : null}
<Link className="d-flex justify-content-center text-dark text-decoration-none" to={`/todo/${moment().format("YYYY-MM-DD")}`}> <Link className="d-flex justify-content-center text-dark text-decoration-none" to={`/todo/${moment().format("YYYY-MM-DD")}`}>
<i className="bi bi-plus-lg me-2"></i> <i className="bi bi-plus-lg me-2"></i>
<p className="mb-0">더보기</p> <p className="mb-0">더보기</p>
......
const PlanAlertModal = ({ planId, handleClick }) => {
return (
<div className="modal fade" id="planmodal" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby="planLabel" aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
관련 학업계획까지 삭제됩니다.
정말 삭제하시겠습니까?
</div>
<div className="modal-footer p-1">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">취소</button>
<button type="button" className="btn btn-crimson btn-sm" onClick={() => handleClick(planId)}>삭제</button>
</div>
</div>
</div>
</div>
)
}
export default PlanAlertModal
\ No newline at end of file
import { useState, useEffect, useRef } from "react"; import { useState, useEffect } from "react";
import todoApi from "../../apis/todo.api"; import todoApi from "../../apis/todo.api";
import { useAuth } from "../../utils/context"; import { useAuth } from "../../utils/context";
import catchErrors from "../../utils/catchErrors"; import catchErrors from "../../utils/catchErrors";
...@@ -47,7 +47,6 @@ const TodoModal = ({ curDate, selectTodo = "" }) => { ...@@ -47,7 +47,6 @@ const TodoModal = ({ curDate, selectTodo = "" }) => {
return ( return (
<div className="modal fade" id="todomodal" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby="todoLabel" aria-hidden="true"> <div className="modal fade" id="todomodal" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex="-1" aria-labelledby="todoLabel" aria-hidden="true">
{console.log("Modal date==", curDate, selectTodo)}
<div className="modal-dialog modal-dialog-centered"> <div className="modal-dialog modal-dialog-centered">
<div className="modal-content" style={{ backgroundColor: "crimson" }}> <div className="modal-content" style={{ backgroundColor: "crimson" }}>
<div className="modal-header px-2 py-1" > <div className="modal-header px-2 py-1" >
......
...@@ -2,7 +2,7 @@ import PlanItem from "./PlanItem"; ...@@ -2,7 +2,7 @@ import PlanItem from "./PlanItem";
import styles from "./studyplan.module.scss"; import styles from "./studyplan.module.scss";
const AddplanList = ({ planList }) => { const AddplanList = ({ planList }) => {
console.log("planList ",planList)
return ( return (
<div className={`mt-5 ${styles.list}`}> <div className={`mt-5 ${styles.list}`}>
<div className={`accordion accordion-flush`} id="addplanlist"> <div className={`accordion accordion-flush`} id="addplanlist">
......
import { useState } from "react"; import { useState } from "react";
import { Link, useHistory } from "react-router-dom"; import { Link, useHistory } from "react-router-dom";
import AlertModal from "../Modal/PlanAlertModal";
import planApi from "../../apis/plan.api"; import planApi from "../../apis/plan.api";
import { useAuth } from "../../utils/context"; import { useAuth } from "../../utils/context";
import catchErrors from "../../utils/catchErrors"; import catchErrors from "../../utils/catchErrors";
...@@ -46,8 +45,7 @@ const PlanItem = ({ planList = [], subjectId }) => { ...@@ -46,8 +45,7 @@ const PlanItem = ({ planList = [], subjectId }) => {
{plan.memo} {plan.memo}
<div className="d-flex justify-content-end mt-3"> <div className="d-flex justify-content-end mt-3">
<Link className="btn btn-light btn-sm border-dark" to={`/studyplan/edit/${plan.id}`}>수정</Link> <Link className="btn btn-light btn-sm border-dark" to={`/studyplan/edit/${plan.id}`}>수정</Link>
<button type="button" className="btn btn-crimson btn-sm ms-2" data-bs-toggle="modal" data-bs-target="#planmodal">삭제</button> <button type="button" className="btn btn-crimson btn-sm ms-2" onClick={() => delPlan(plan.id)}>삭제</button>
<AlertModal planId={plan.id} handleClick={delPlan} />
</div> </div>
</div> </div>
</div> </div>
......
...@@ -3,7 +3,7 @@ import styles from "./studyplan.module.scss"; ...@@ -3,7 +3,7 @@ import styles from "./studyplan.module.scss";
const PlanLineList = ({ subjectId, planList = [] }) => { const PlanLineList = ({ subjectId, planList = [] }) => {
return ( return (
<> <Link to={`/studyplan/${subjectId}`}>
{planList.length !== 0 ? planList.map(plan => <div className="d-flex justify-content-between"> {planList.length !== 0 ? planList.map(plan => <div className="d-flex justify-content-between">
<p className={`card-text mb-1 ${styles.text}`}>- {plan.title}</p> <p className={`card-text mb-1 ${styles.text}`}>- {plan.title}</p>
<input className={`form-check-input shadow-none ${styles.checkBox}`} type="checkbox" /> <input className={`form-check-input shadow-none ${styles.checkBox}`} type="checkbox" />
...@@ -13,7 +13,7 @@ const PlanLineList = ({ subjectId, planList = [] }) => { ...@@ -13,7 +13,7 @@ const PlanLineList = ({ subjectId, planList = [] }) => {
<p className="card-text mb-1">새로운 계획 추가하기</p> <p className="card-text mb-1">새로운 계획 추가하기</p>
</div> </div>
</Link>} </Link>}
</> </Link>
) )
} }
......
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import PlanLineList from "./PlanLineList"; import PlanLineList from "./PlanLineList";
const StudyPlanCard = ({ renList }) => { const StudyPlanCard = ({ renList, handleClick }) => {
return ( return (
<Link className="card text-decoration-none link-dark mb-3" style={{ width: "20rem" }} to={`/studyplan/${renList.id}`}> <div className="card text-decoration-none link-dark mb-3" style={{ width: "20rem" }} >
<div className="card-body"> <div className="card-body">
<div className="d-flex"> <div className="d-flex">
<h5 className="card-title col-10 text-nowrap" style={{ overflow: "hidden", textOverflow: "ellipsis" }}>{renList.name}</h5> <h5 className="card-title col-10 text-nowrap" style={{ overflow: "hidden", textOverflow: "ellipsis" }}>{renList.name}</h5>
<div className="col-2 d-flex justify-content-end"> <div className="col-2 d-flex justify-content-end">
<Link className="text-decoration-none link-dark" to={`/subject/edit/${renList.id}`}><i className="bi bi-pencil-square pe-2"></i></Link> <Link className="text-decoration-none link-dark" to={`/subject/edit/${renList.id}`}><i className="bi bi-pencil-square pe-2"></i></Link>
<i className="bi bi-trash"></i> <i className="bi bi-trash" onClick={() => handleClick(renList.id)}>
</i>
</div> </div>
</div> </div>
<p className="card-subtitle ms-1 mb-2 text-muted">{renList.prof && renList.room ? renList.prof + ' - ' + renList.room : (renList.prof || renList.room)}</p> <p className="card-subtitle ms-1 mb-2 text-muted">{renList.prof && renList.room ? renList.prof + ' - ' + renList.room : (renList.prof || renList.room)}</p>
<PlanLineList subjectId={renList.id} planList={renList.planList} /> <PlanLineList subjectId={renList.id} planList={renList.planList} />
</div> </div>
</Link> </div>
) )
} }
......
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Link } from "react-router-dom"; import { Link, useHistory } from "react-router-dom";
import StudyPlanCard from "./StudyPlanCard"; import StudyPlanCard from "./StudyPlanCard";
import subjectApi from '../../apis/subject.api'; import subjectApi from '../../apis/subject.api';
import catchErrors from "../../utils/catchErrors"; import catchErrors from "../../utils/catchErrors";
...@@ -9,7 +9,9 @@ import styles from "./studyplan.module.scss"; ...@@ -9,7 +9,9 @@ import styles from "./studyplan.module.scss";
const StudyPlanList = () => { const StudyPlanList = () => {
const { user } = useAuth(); const { user } = useAuth();
const [renList, setRenList] = useState([]) const [renList, setRenList] = useState([])
const [success, setSuccess] = useState(false)
const [error, setError] = useState("") const [error, setError] = useState("")
const history = useHistory()
useEffect(() => { useEffect(() => {
getList(user.id); getList(user.id);
...@@ -25,10 +27,23 @@ const StudyPlanList = () => { ...@@ -25,10 +27,23 @@ const StudyPlanList = () => {
} }
} }
async function delSubject(subjectId) {
try {
setError("")
await subjectApi.removeSubject(subjectId, user.id)
alert("해당 과목 정보가 성공적으로 삭제되었습니다.")
setSuccess(true)
} catch (error) {
catchErrors(error, setError)
}
}
if (success) history.push("/home")
return ( return (
<div className={`mt-4 ${styles.list}`}> <div className={`mt-4 ${styles.list}`}>
<div className="d-flex flex-column align-items-center"> <div className="d-flex flex-column align-items-center">
{renList.length !== 0 ? renList.map((info, idx) => <StudyPlanCard key={idx} renList={info} />) : null} {renList.length !== 0 ? renList.map((info, idx) => <StudyPlanCard key={idx} renList={info} handleClick={delSubject} />) : null}
<Link className="card text-decoration-none link-dark" to="/subject/edit" style={{ width: "20rem" }}> <Link className="card text-decoration-none link-dark" to="/subject/edit" style={{ width: "20rem" }}>
<div className="card-body d-flex flex-column bg-secondary bg-opacity-25"> <div className="card-body d-flex flex-column bg-secondary bg-opacity-25">
<i className="bi bi-plus-lg d-flex justify-content-center fs-3"></i> <i className="bi bi-plus-lg d-flex justify-content-center fs-3"></i>
......
...@@ -35,6 +35,30 @@ const findbyDate = async (req, res, next) => { ...@@ -35,6 +35,30 @@ const findbyDate = async (req, res, next) => {
} }
} }
const findforPercent = async (req, res) => {
try {
let doneTodo = null
const userId = req.userId
const { start, end } = req.query
if (end) {
const { count, rows } = await Todo.findAndCountAll({ where: { [Op.and]: [{ date: { [Op.eq]: start } }, { userId: userId }] } })
} else {
let percent = 0
console.log("findforPercent end 없음")
const nonCheck = await Todo.findAndCountAll({ where: { [Op.and]: [{ date: { [Op.eq]: start } }, { userId: userId }, { done: false }] } })
const check = await Todo.findAndCountAll({ where: { [Op.and]: [{ date: { [Op.eq]: start } }, { userId: userId }, { done: true }] } })
let total = nonCheck.count + check.count
check.rows.forEach(el => nonCheck.rows.push(el.dataValues))
console.log("non",nonCheck)
if (total === 0) percent = 0
else percent = Math.round((check.count / total)*100)
return res.json({ percent: percent, list: nonCheck.rows })
}
} catch (error) {
return res.status(500).send(error.message || "todo 가져오는 중 에러 발생")
}
}
const create = async (req, res) => { const create = async (req, res) => {
try { try {
const userId = req.userId const userId = req.userId
...@@ -95,6 +119,7 @@ const send = async (req, res) => { ...@@ -95,6 +119,7 @@ const send = async (req, res) => {
export default { export default {
findbyId, findbyId,
findbyDate, findbyDate,
findforPercent,
create, create,
edit, edit,
remove, remove,
......
...@@ -34,6 +34,11 @@ const Plan = PlanModel(sequelize) ...@@ -34,6 +34,11 @@ const Plan = PlanModel(sequelize)
Schedule.belongsTo(User) Schedule.belongsTo(User)
Subject.belongsTo(User) Subject.belongsTo(User)
Todo.belongsTo(User) Todo.belongsTo(User)
Subject.hasOne(Plan, {
onDelete: "CASCADE"
})
Plan.belongsTo(Subject) Plan.belongsTo(Subject)
export { export {
......
...@@ -3,6 +3,10 @@ import todoCtrl from "../controllers/todo.controller.js"; ...@@ -3,6 +3,10 @@ import todoCtrl from "../controllers/todo.controller.js";
const router = express.Router(); const router = express.Router();
router
.route("/percent/:userId")
.get(todoCtrl.findforPercent)
router router
.route("/:userId") .route("/:userId")
.get(todoCtrl.findbyId, todoCtrl.findbyDate, todoCtrl.send) .get(todoCtrl.findbyId, todoCtrl.findbyDate, todoCtrl.send)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment