송용우

Update Challenge Layout

......@@ -1982,9 +1982,9 @@
}
},
"@material-ui/core": {
"version": "4.10.2",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.10.2.tgz",
"integrity": "sha512-Uf4iDLi9sW6HKbVQDyDZDr1nMR4RUAE7w/RIIJZGNVZResC0xwmpLRZMtaUdSO43N0R0yJehfxTi4Z461Cd49A==",
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz",
"integrity": "sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==",
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.10.0",
......@@ -2000,6 +2000,18 @@
"react-transition-group": "^4.4.0"
}
},
"@material-ui/lab": {
"version": "4.0.0-alpha.56",
"resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz",
"integrity": "sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==",
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.10.2",
"clsx": "^1.0.4",
"prop-types": "^15.7.2",
"react-is": "^16.8.0"
}
},
"@material-ui/styles": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz",
......@@ -5322,12 +5334,19 @@
}
},
"dom-helpers": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz",
"integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz",
"integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==",
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^2.6.7"
"csstype": "^3.0.2"
},
"dependencies": {
"csstype": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag=="
}
}
},
"dom-serializer": {
......@@ -7343,9 +7362,9 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
},
"hyphenate-style-name": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz",
"integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ=="
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
},
"iconv-lite": {
"version": "0.4.24",
......@@ -8537,81 +8556,88 @@
}
},
"jss": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss/-/jss-10.3.0.tgz",
"integrity": "sha512-B5sTRW9B6uHaUVzSo9YiMEOEp3UX8lWevU0Fsv+xtRnsShmgCfIYX44bTH8bPJe6LQKqEXku3ulKuHLbxBS97Q==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss/-/jss-10.4.0.tgz",
"integrity": "sha512-l7EwdwhsDishXzqTc3lbsbyZ83tlUl5L/Hb16pHCvZliA9lRDdNBZmHzeJHP0sxqD0t1mrMmMR8XroR12JBYzw==",
"requires": {
"@babel/runtime": "^7.3.1",
"csstype": "^2.6.5",
"csstype": "^3.0.2",
"is-in-browser": "^1.1.3",
"tiny-warning": "^1.0.2"
},
"dependencies": {
"csstype": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag=="
}
}
},
"jss-plugin-camel-case": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.3.0.tgz",
"integrity": "sha512-tadWRi/SLWqLK3EUZEdDNJL71F3ST93Zrl9JYMjV0QDqKPAl0Liue81q7m/nFUpnSTXczbKDy4wq8rI8o7WFqA==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.4.0.tgz",
"integrity": "sha512-9oDjsQ/AgdBbMyRjc06Kl3P8lDCSEts2vYZiPZfGAxbGCegqE4RnMob3mDaBby5H9vL9gWmyyImhLRWqIkRUCw==",
"requires": {
"@babel/runtime": "^7.3.1",
"hyphenate-style-name": "^1.0.3",
"jss": "^10.3.0"
"jss": "10.4.0"
}
},
"jss-plugin-default-unit": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.3.0.tgz",
"integrity": "sha512-tT5KkIXAsZOSS9WDSe8m8lEHIjoEOj4Pr0WrG0WZZsMXZ1mVLFCSsD2jdWarQWDaRNyMj/I4d7czRRObhOxSuw==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.4.0.tgz",
"integrity": "sha512-BYJ+Y3RUYiMEgmlcYMLqwbA49DcSWsGgHpVmEEllTC8MK5iJ7++pT9TnKkKBnNZZxTV75ycyFCR5xeLSOzVm4A==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "^10.3.0"
"jss": "10.4.0"
}
},
"jss-plugin-global": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.3.0.tgz",
"integrity": "sha512-etYTG/y3qIR/vxZnKY+J3wXwObyBDNhBiB3l/EW9/pE3WHE//BZdK8LFvQcrCO48sZW1Z6paHo6klxUPP7WbzA==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.4.0.tgz",
"integrity": "sha512-b8IHMJUmv29cidt3nI4bUI1+Mo5RZE37kqthaFpmxf5K7r2aAegGliAw4hXvA70ca6ckAoXMUl4SN/zxiRcRag==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "^10.3.0"
"jss": "10.4.0"
}
},
"jss-plugin-nested": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.3.0.tgz",
"integrity": "sha512-qWiEkoXNEkkZ+FZrWmUGpf+zBsnEOmKXhkjNX85/ZfWhH9dfGxUCKuJFuOWFM+rjQfxV4csfesq4hY0jk8Qt0w==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.4.0.tgz",
"integrity": "sha512-cKgpeHIxAP0ygeWh+drpLbrxFiak6zzJ2toVRi/NmHbpkNaLjTLgePmOz5+67ln3qzJiPdXXJB1tbOyYKAP4Pw==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "^10.3.0",
"jss": "10.4.0",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-props-sort": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.3.0.tgz",
"integrity": "sha512-boetORqL/lfd7BWeFD3K+IyPqyIC+l3CRrdZr+NPq7Noqp+xyg/0MR7QisgzpxCEulk+j2CRcEUoZsvgPC4nTg==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.4.0.tgz",
"integrity": "sha512-j/t0R40/2fp+Nzt6GgHeUFnHVY2kPGF5drUVlgkcwYoHCgtBDOhTTsOfdaQFW6sHWfoQYgnGV4CXdjlPiRrzwA==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "^10.3.0"
"jss": "10.4.0"
}
},
"jss-plugin-rule-value-function": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.3.0.tgz",
"integrity": "sha512-7WiMrKIHH3rwxTuJki9+7nY11r1UXqaUZRhHvqTD4/ZE+SVhvtD5Tx21ivNxotwUSleucA/8boX+NF21oXzr5Q==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.4.0.tgz",
"integrity": "sha512-w8504Cdfu66+0SJoLkr6GUQlEb8keHg8ymtJXdVHWh0YvFxDG2l/nS93SI5Gfx0fV29dO6yUugXnKzDFJxrdFQ==",
"requires": {
"@babel/runtime": "^7.3.1",
"jss": "^10.3.0",
"jss": "10.4.0",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-vendor-prefixer": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.3.0.tgz",
"integrity": "sha512-sZQbrcZyP5V0ADjCLwUA1spVWoaZvM7XZ+2fSeieZFBj31cRsnV7X70FFDerMHeiHAXKWzYek+67nMDjhrZAVQ==",
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.4.0.tgz",
"integrity": "sha512-DpF+/a+GU8hMh/948sBGnKSNfKkoHg2p9aRFUmyoyxgKjOeH9n74Ht3Yt8lOgdZsuWNJbPrvaa3U4PXKwxVpTQ==",
"requires": {
"@babel/runtime": "^7.3.1",
"css-vendor": "^2.0.8",
"jss": "^10.3.0"
"jss": "10.4.0"
}
},
"jsx-ast-utils": {
......@@ -8928,6 +8954,11 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"memoize-one": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
"integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
......@@ -14326,6 +14357,15 @@
"whatwg-fetch": "^3.0.0"
}
},
"react-calendar-heatmap": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/react-calendar-heatmap/-/react-calendar-heatmap-1.8.1.tgz",
"integrity": "sha512-4Hbq/pDMJoCPzZnyIWFfHgokLlLXzKyGsDcMgNhYpi7zcKHcvsK9soLEPvhW2dBBqgDrQOSp/uG4wtifaDg4eQ==",
"requires": {
"memoize-one": "^5.0.0",
"prop-types": "^15.6.2"
}
},
"react-dev-utils": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
......
......@@ -3,7 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.10.2",
"@material-ui/core": "^4.11.0",
"@material-ui/lab": "^4.0.0-alpha.56",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
......
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Accordion from '@material-ui/core/Accordion';
import AccordionSummary from '@material-ui/core/AccordionSummary';
import AccordionDetails from '@material-ui/core/AccordionDetails';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete';
import palette from '../../lib/styles/palette';
import Typography from '@material-ui/core/Typography';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
background: palette.gray[2],
padding: theme.spacing(8),
},
paper: {
padding: theme.spacing(8),
margin: 'auto',
textAlign: 'center',
color: theme.palette.text.secondary,
},
}));
const ChallengeForm = () => {
return <div></div>;
const classes = useStyles();
return (
<div className={classes.root}>
<Grid container spacing={5}>
<Grid item xs={12}>
<Accordion>
<AccordionSummary>
<Typography>챌린지 참여하기</Typography>
</AccordionSummary>
<AccordionDetails>
<Paper className={classes.paper}>
챌린지 참여하기
<Autocomplete
style={{ width: 300 }}
options={['전체', '준비', '진행 중', '마감']}
renderInput={(params) => (
<TextField
{...params}
label="검색 기준"
variant="outlined"
inputProps={{
...params.inputProps,
Autocomplete: 'new-password',
}}
/>
)}
/>
</Paper>
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
참여중인 챌린지
<Autocomplete
style={{ width: 300 }}
options={['전체', '준비', '진행 중', '마감']}
renderInput={(params) => (
<TextField
{...params}
label="검색 기준"
variant="outlined"
inputProps={{
...params.inputProps,
Autocomplete: 'new-password',
}}
/>
)}
/>
<Grid container spacing={5}>
<Grid item xs={4}>
<Paper className={classes.paper}>
챌린지 이름, 기간, 참여 인원수
</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}> 배경 변경 필요</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}>test3</Paper>
</Grid>
<Grid item xs={4}>
<Paper className={classes.paper}>test4</Paper>
</Grid>
</Grid>
</Paper>
</Grid>
</Grid>
</div>
);
};
/*
Todo
TODO:
챌린지 목록
챌린지 이름
챌린지 기간 (Start - End)
챌린지 세션 정보 (일 간격과 목표 문제)
......
......@@ -50,6 +50,7 @@ const HomeForm = ({ PSdata, HMArr, goalNum }) => {
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
<h1>알고리즘 기록</h1>
<HeatMap HMArr={HMArr} />
</Paper>
</Grid>
......
......@@ -4,7 +4,7 @@ import { withRouter } from 'react-router-dom';
import ChallengeForm from '../../components/challenge/ChallengeForm';
const ChallengeContainer = () => {
return <div></div>;
return <ChallengeForm />;
};
export default ChallengeContainer;
......
......@@ -2,7 +2,7 @@ const Challenge = require("../../models/challenge");
const Session = require("../../models/session");
const Participation = require("../../models/participation");
const Group = require("../../models/group");
const User = require('../../models/user');
const User = require("../../models/user");
const Joi = require("joi");
/*POST /api/challenge/getChallenge
......@@ -13,7 +13,9 @@ const Joi = require("joi");
exports.getChallenge = async (ctx) => {
try {
const { challengeName } = ctx.request.body;
const challenge = await Challenge.findByChallengeName(challengeName).select('-_id');
const challenge = await Challenge.findByChallengeName(challengeName).select(
"-_id"
);
if (!challenge) {
ctx.status = 401;
return;
......@@ -39,7 +41,7 @@ exports.addChallenge = async (ctx) => {
startDate: Joi.date(),
endDate: Joi.date(),
durationPerSession: Joi.string(),
goalPerSession: Joi.number()
goalPerSession: Joi.number(),
})
.unknown();
const result = Joi.validate(ctx.request.body, schema);
......@@ -58,7 +60,9 @@ exports.addChallenge = async (ctx) => {
} = ctx.request.body;
try {
const isChallengeExist = await Challenge.findByChallengeName(challengeName).select('-_id');
const isChallengeExist = await Challenge.findByChallengeName(
challengeName
).select("-_id");
if (isChallengeExist) {
ctx.status = 409;
......@@ -73,54 +77,50 @@ exports.addChallenge = async (ctx) => {
});
await challenge.save();
const newChallenge=await Challenge.findByChallengeName(challengeName);
const newChallenge_id=newChallenge._id;
const timeStep=Number(durationPerSession.slice(0,-1))
if(typeof(startDate)=='string'){
startDate=new Date(startDate);
const newChallenge = await Challenge.findByChallengeName(challengeName);
const newChallenge_id = newChallenge._id;
const timeStep = Number(durationPerSession.slice(0, -1));
if (typeof startDate == "string") {
startDate = new Date(startDate);
}
if(typeof(endDate)=='string'){
endDate=new Date(endDate);
if (typeof endDate == "string") {
endDate = new Date(endDate);
}
for(let s_date=new Date(startDate);s_date<endDate;){
let e_date=new Date(s_date);
if(durationPerSession[durationPerSession.length-1]==='d'){
console.log('day');
e_date.setDate(s_date.getDate()+timeStep);
}
else if(durationPerSession[durationPerSession.length-1]==='w'){
console.log('week');
e_date.setDate(s_date.getDate()+timeStep*7);
for (let s_date = new Date(startDate); s_date < endDate; ) {
let e_date = new Date(s_date);
if (durationPerSession[durationPerSession.length - 1] === "d") {
console.log("day");
e_date.setDate(s_date.getDate() + timeStep);
} else if (durationPerSession[durationPerSession.length - 1] === "w") {
console.log("week");
e_date.setDate(s_date.getDate() + timeStep * 7);
} else if (durationPerSession[durationPerSession.length - 1] === "m") {
console.log("month");
e_date.setMonth(s_date.getMonth() + timeStep);
}
else if(durationPerSession[durationPerSession.length-1]==='m'){
console.log('month');
e_date.setMonth(s_date.getMonth()+timeStep);
}
e_date.setMinutes(e_date.getMinutes()-1);
if(e_date>endDate){
e_date.setMinutes(e_date.getMinutes() - 1);
if (e_date > endDate) {
break;
}
let status="";
if (s_date>new Date()){
status="enrolled";
}
else if (s_date<=new Date() && new Date() <= e_date){
status="progress";
}
else{
status="end";
let status = "";
if (s_date > new Date()) {
status = "enrolled";
} else if (s_date <= new Date() && new Date() <= e_date) {
status = "progress";
} else {
status = "end";
}
console.log(`start:${s_date}\nend:${e_date}`);
const session=new Session({
challengeId:newChallenge_id,
sessionStartDate:s_date,
sessionEndDate:e_date,
status:status,
const session = new Session({
challengeId: newChallenge_id,
sessionStartDate: s_date,
sessionEndDate: e_date,
status: status,
});
await session.save();
s_date=new Date(e_date);
s_date.setMinutes(s_date.getMinutes()+1);
s_date = new Date(e_date);
s_date.setMinutes(s_date.getMinutes() + 1);
}
ctx.body = challenge;
} catch (e) {
......@@ -128,24 +128,23 @@ exports.addChallenge = async (ctx) => {
}
};
/* GET /api/challenge/list?status
query string status can be in ['all','enrolled','progress','end']
*/
exports.list = async (ctx) => {
try{
try {
const status = ctx.query.status;
if (status!=='all'){
const challenges = await Challenge.find({status:status}).select('-_id');
if (status !== "all") {
const challenges = await Challenge.find({ status: status }).select(
"-_id"
);
ctx.body = challenges;
}
else {
const challenges = await Challenge.find({}).select('-_id');
} else {
const challenges = await Challenge.find({}).select("-_id");
ctx.body = challenges;
}
}
catch(e){
ctx.throw(500,e);
} catch (e) {
ctx.throw(500, e);
}
};
......@@ -156,40 +155,39 @@ exports.list = async (ctx) => {
}
*/
exports.participate=async (ctx)=>{
try{
/*
exports.participate = async (ctx) => {
try {
/*
TODO: access token validation,
recommend:get username from access_token
*/
console.log(ctx.request.body);
const {username,challengeName}=ctx.request.body;
const challenge=await Challenge.findByChallengeName(challengeName);
const challenge_id=challenge._id;
const user=await User.findByUsername(username);
const user_id=user._id;
const newGroup=new Group({
members:[user_id],
const { username, challengeName } = ctx.request.body;
const challenge = await Challenge.findByChallengeName(challengeName);
const challenge_id = challenge._id;
const user = await User.findByUsername(username);
const user_id = user._id;
const newGroup = new Group({
members: [user_id],
});
let newGroup_id=""
await newGroup.save(async (err,product)=>{
if(err){
let newGroup_id = "";
await newGroup.save(async (err, product) => {
if (err) {
throw err;
}
newGroup_id=product._id;
const sessions=await Session.findByChallengeId(challenge_id);
newGroup_id = product._id;
const sessions = await Session.findByChallengeId(challenge_id);
sessions.forEach(async (elem) => {
const newParticipation=new Participation({
sessionId:elem._id,
groupId:newGroup_id,
problems:[],
const newParticipation = new Participation({
sessionId: elem._id,
groupId: newGroup_id,
problems: [],
});
await newParticipation.save();
});
});
}
catch(e){
} catch (e) {
console.error(e);
ctx.throw(500,e);
ctx.throw(500, e);
}
};
\ No newline at end of file
};
......