diff --git a/backend/.env.example b/backend/.env.example
index 2d2f04eb..f8021068 100644
--- a/backend/.env.example
+++ b/backend/.env.example
@@ -122,10 +122,14 @@ AUTH_PROD_TOKEN_AUDIENCE=
#######################################################################################################################
# redis
REDIS_DEV_CONTAINER_NAME=redis_dev
-REDIS_DEV_PORT=6379
+REDIS_DEV_PORT=6380
REDIS_DEV_HOST=127.0.0.1
-REDIS_PROD_CONTAINER_NAME=redis_dev
+REDIS_TEST_CONTAINER_NAME=redis_test
+REDIS_TEST_PORT=6381
+REDIS_TEST_HOST=127.0.0.1
+
+REDIS_PROD_CONTAINER_NAME=redis
REDIS_PROD_PORT=6379
-REDIS_PROD_HOST=127.0.0.1
+REDIS_PROD_HOST=redis
#######################################################################################################################
\ No newline at end of file
diff --git a/backend/DB/dummy/RandomGuestName/Adjective.js b/backend/DB/dummy/RandomGuestName/Adjective.js
new file mode 100644
index 00000000..209a57ae
--- /dev/null
+++ b/backend/DB/dummy/RandomGuestName/Adjective.js
@@ -0,0 +1,66 @@
+const Adjectives = [
+ "춤추는",
+ "멋있는",
+ "차가운",
+ "뜨거운",
+ "호기심이 많은",
+ "귀여운",
+ "울부짖는",
+ "궁금한게 많은",
+ "노래하는",
+ "랩하는",
+ "화사한",
+ "맵시있는",
+ "요리하는",
+ "재미있는",
+ "큰 눈의",
+ "착한",
+ "정직한",
+ "조용한",
+ "즐거운",
+ "졸고있는",
+ "기쁜",
+ "벅찬",
+ "포근한",
+ "흐뭇한",
+ "상쾌한",
+ "시원한",
+ "반가운",
+ "후련한",
+ "살맛 나는",
+ "신바람 나는",
+ "아늑한",
+ "흥분되는",
+ "온화한",
+ "느긋한",
+ "끝내주는",
+ "괜찮은",
+ "쌈박한",
+ "정다운",
+ "그리운",
+ "자유로운",
+ "따사로운",
+ "감미로운",
+ "황홀한",
+ "상큼한",
+ "개념있는",
+ "지성적인",
+ "자상한",
+ "아리따운",
+ "여유있는",
+ "감정이 풍부한",
+ "활기찬",
+ "힘찬",
+ "생생한",
+ "의기 양양한",
+ "든든한",
+ "격렬한",
+ "당당한",
+ "팔팔한",
+ "엄청난",
+ "자신만만한",
+ "패기만만한",
+ "충만한",
+];
+
+export default Adjectives;
diff --git a/backend/DB/dummy/RandomGuestName/Animals.js b/backend/DB/dummy/RandomGuestName/Animals.js
new file mode 100644
index 00000000..5067fea8
--- /dev/null
+++ b/backend/DB/dummy/RandomGuestName/Animals.js
@@ -0,0 +1,3 @@
+const Animals = ["크롱", "호눅스", "부캠퍼", "타노스", "배트맨", "아이언맨", "헐크", "토르", "갈까마귀", "돌고래", "해오라기", "갈매기", "갈색여우원숭이", "개구리", "개미핥기", "개코원숭이", "거북", "거위", "고래", "고래상어", "고릴라", "고슴도치", "고양이", "곰", "공룡", "공작", "괭이갈매기", "구관조", "금붕어", "기러기", "기린", "까마귀", "까치", "꿩", "나무늘보", "나비", "낙타", "너구리", "노란눈썹펭귄", "늑대", "다람쥐", "달마시안", "달팽이", "담비", "딱다구리", "맘모스", "무당개구리", "무당벌레", "무스", "물개", "물총새", "바다코끼리", "바다표범", "방울뱀", "방울새", "백로", "북극여우", "비단뱀", "비둘기", "비버", "뻐꾸기", "사막여우", "사슴", "사자", "상어", "소", "소쩍새", "송골매", "수리부엉이", "시조새", "악어", "앵무새", "오리", "올빼미", "원숭이", "장수하늘소", "제비", "족제비", "진돗개", "참새", "청개구리", "초록비단뱀", "치타", "캥거루", "코끼리", "코뿔소", "코알라", "타조", "토끼", "파랑새", "펭귄", "표범", "퓨마", "하마", "흑표범"];
+
+export default Animals;
diff --git a/backend/DB/dummy/RandomGuestName/index.js b/backend/DB/dummy/RandomGuestName/index.js
new file mode 100644
index 00000000..43fcfe5c
--- /dev/null
+++ b/backend/DB/dummy/RandomGuestName/index.js
@@ -0,0 +1,12 @@
+import faker from "faker";
+import Adjectives from "./Adjective.js";
+import Animals from "./Animals.js";
+
+function getRandomGuestName() {
+ const adjective = faker.random.arrayElement(Adjectives);
+ const animal = faker.random.arrayElement(Animals);
+
+ return `${adjective} ${animal}`;
+}
+
+export default getRandomGuestName;
diff --git a/backend/DB/logger.js b/backend/DB/logger.js
new file mode 100644
index 00000000..5a058011
--- /dev/null
+++ b/backend/DB/logger.js
@@ -0,0 +1,5 @@
+import getLogger from "../libs/logger.js";
+
+const logger = getLogger("mySQL_Query");
+
+export default logger;
diff --git a/backend/DB/queries/candidate.js b/backend/DB/queries/candidate.js
index dbec87f5..b278906c 100644
--- a/backend/DB/queries/candidate.js
+++ b/backend/DB/queries/candidate.js
@@ -1,17 +1,14 @@
+import Sequelize from "sequelize";
import models from "../models";
-const Sequelize = require("sequelize");
-
const Op = Sequelize.Op;
export async function getCandidatesByPollId(pollIdList) {
- const result = await models.Candidate.findAll({
+ return models.Candidate.findAll({
where: {
PollId: {
[Op.or]: pollIdList,
},
},
});
-
- return result;
}
diff --git a/backend/DB/queries/event.js b/backend/DB/queries/event.js
index cba8bda9..f71f29c4 100644
--- a/backend/DB/queries/event.js
+++ b/backend/DB/queries/event.js
@@ -16,141 +16,57 @@ export async function createEvent({
return models.Event.findOrCreate({
where: {eventCode},
defaults: {
+ eventName,
+ HostId,
moderationOption,
replyOption,
startAt,
endAt,
- HostId,
- eventName,
},
});
}
-export async function updateEventById(
+export async function updateEventById({
id,
- {eventName, moderationOption, replyOption, startAt, endAt}
-) {
+ eventName,
+ moderationOption,
+ replyOption,
+ startAt,
+ endAt,
+}) {
return models.Event.update(
{eventName, moderationOption, replyOption, startAt, endAt},
- {where: {id}}
+ {where: {id}},
);
}
export async function getEventsByHostId(hostId) {
- const events = await models.Event.findAll({
+ return models.Event.findAll({
where: {HostId: hostId},
});
-
- return events;
}
-export async function getEventIdByEventCode(eventCode) {
- const event = await models.Event.findOne({
+export async function getEventByEventCode(eventCode) {
+ return models.Event.findOne({
where: {
eventCode,
},
- attributes: ["id"],
});
-
- return event;
}
export async function getEventById(EventId) {
- const event = await models.Event.findOne({
+ return models.Event.findOne({
where: {
id: EventId,
},
});
-
- return event;
}
export async function getEventOptionByEventId(id) {
- const event = await models.Event.findOne({
+ return models.Event.findOne({
where: {
id,
},
attributes: ["moderationOption", "replyOption"],
});
-
- return event;
-}
-
-export async function getQuestionLikeCount(EventId = 2, limit, offset) {
- return models.Question.findAll({
- attributes: ["id", [models.sequelize.fn("count", "*"), "likeCount"]],
- where: {EventId, QuestionId: null},
- include: [
- {
- model: models.Like,
- attributes: [],
- },
- ],
- group: "id",
- offset,
- limit,
- });
-}
-
-export async function getQuestionsByEventCodeAndGuestId(
- eventCode,
- guestId,
- limit = 70,
- offset
-) {
- // const event = await models.Event.findOne({where: {eventCode}});
- // const EventId = event.dataValues.id
- const EventId = 2;
-
- return models.Question.findAll({
- where: {EventId, QuestionId: null},
- include: [
- {
- model: models.Like,
- },
- {
- model: models.Emoji,
- },
- {
- model: models.Guest,
- },
- ],
- offset,
- limit,
- });
-}
-
-export async function raw_getQuestionsByEventCodeAndGuestId(
- eventCode,
- guestId,
- limit = 100,
- offset = 0
-) {
- // const event = await models.Event.findOne({where: {eventCode}});
- // const EventId = event.dataValues.id
- const EventId = 2;
-
- const query = `
- select *, Emojis.name, Emojis.GuestId
- from Questions
- inner join Emojis on Questions.id = Emojis.QuestionId
- where EventId = :EventId and Questions.QuestionId is null
--- order by Emojis.QuestionId DESC
-
--- limit :limit offset :offset
-
--- group by Emojis.QuestionId
-`;
- // console.log(event.dataValues.id)
- const [questions] = await models.sequelize.query(query, {
- replacements: {
- EventId,
- limit,
- offset,
- type: Sequelize.QueryTypes.SELECT,
- raw: true,
- },
- });
-
- return questions;
}
diff --git a/backend/DB/queries/guest.js b/backend/DB/queries/guest.js
index b66d5964..2034253e 100644
--- a/backend/DB/queries/guest.js
+++ b/backend/DB/queries/guest.js
@@ -1,26 +1,26 @@
import uuidv1 from "uuid/v1";
import models from "../models";
+import getRandomGuestName from "../dummy/RandomGuestName";
const Guest = models.Guest;
-async function findGuestBySid(guestSid) {
- const guest = await Guest.findOne({where: {guestSid}});
- const result = guest ? guest.dataValues : false;
+async function getGuestByGuestSid(guestSid) {
+ return Guest.findOne({where: {guestSid}});
+}
- return result;
+async function isExistGuest(guestSid) {
+ return !!(await getGuestByGuestSid(guestSid));
}
-async function createGuest(name, eventId) {
+async function createGuest(eventId) {
const guest = await Guest.create({
- name,
+ name: getRandomGuestName(),
EventId: eventId,
guestSid: uuidv1(),
isAnonymous: 1,
});
- const result = guest ? guest.dataValues : false;
-
- return result;
+ return guest.get({plain: true});
}
async function getGuestById(id) {
@@ -30,10 +30,7 @@ async function getGuestById(id) {
}
async function updateGuestById({id, name, isAnonymous, company, email}) {
- return Guest.update(
- {name, company, isAnonymous, email},
- {where: {id}},
- );
+ return Guest.update({name, company, isAnonymous, email}, {where: {id}});
}
async function getGuestByEventId(EventId) {
@@ -45,5 +42,6 @@ export {
getGuestById,
updateGuestById,
getGuestByEventId,
- findGuestBySid,
+ isExistGuest,
+ getGuestByGuestSid
};
diff --git a/backend/DB/queries/hashtag.js b/backend/DB/queries/hashtag.js
index f53a44f6..44e3dd35 100644
--- a/backend/DB/queries/hashtag.js
+++ b/backend/DB/queries/hashtag.js
@@ -5,7 +5,7 @@ const Hashtag = models.Hashtag;
export async function createHashtag({name, EventId}) {
return Hashtag.create(
{name, EventId},
- {default: {updateAt: new Date(), createAt: new Date()}}
+ {default: {updateAt: new Date(), createAt: new Date()}},
);
}
diff --git a/backend/DB/queries/host.js b/backend/DB/queries/host.js
index f304ddb3..b82c8cb4 100644
--- a/backend/DB/queries/host.js
+++ b/backend/DB/queries/host.js
@@ -1,23 +1,20 @@
import models from "../models";
-async function findHostByAuthId(oAuthid) {
- const host = await models.Host.findOne({where: {oauthId: oAuthid}});
- const result = host ? host.dataValues : false;
+// todo: 더 좋은 이름
+export async function findHostByAuthId(oauthId) {
+ const host = await models.Host.findOne({where: {oauthId}});
- return result;
+ return host ? host.dataValues : false;
}
-async function createHost(oAuthid, name, image, email) {
+export async function createHost(oauthId, name, image, email) {
const host = await models.Host.create({
- oauthId: oAuthid,
+ oauthId,
name,
email,
image,
- emailFeedBack: 0,
+ emailFeedBack: false,
});
- const result = host ? host.dataValues : false;
- return result;
+ return host ? host.dataValues : false;
}
-
-export {createHost, findHostByAuthId};
diff --git a/backend/DB/queries/poll.js b/backend/DB/queries/poll.js
index 69333965..2badd882 100644
--- a/backend/DB/queries/poll.js
+++ b/backend/DB/queries/poll.js
@@ -1,46 +1,40 @@
import models from "../models";
+import logger from "../logger.js";
const sequelize = models.sequelize;
const Poll = models.Poll;
const Candidate = models.Candidate;
-export async function openPoll(pollId) {
- const now = new Date();
- const result = await models.Poll.update(
+export async function openPoll(id) {
+ // result should be == [1], 1개의 row가 성공했다는 의미
+ return Poll.update(
{
state: "running",
- pollDate: now,
+ pollDate: new Date(),
},
{
- where: {id: pollId},
- }
+ where: {id},
+ },
);
-
- // result should be == [1], 1개의 row가 성공했다는 의미
- return result;
}
-export async function closePoll(pollId) {
- const result = await models.Poll.update(
+export async function closePoll(id) {
+ // result should be == [1], 1개의 row가 성공했다는 의미
+ return Poll.update(
{
state: "closed",
},
{
- where: {id: pollId},
- }
+ where: {id},
+ },
);
-
- // result should be == [1], 1개의 row가 성공했다는 의미
- return result;
}
-export async function getPollsByEventId(eventId) {
- const result = await models.Poll.findAll({
- where: {EventId: eventId},
+export async function getPollsByEventId(EventId) {
+ return Poll.findAll({
+ where: {EventId},
order: [["id", "DESC"]],
});
-
- return result;
}
const makeCandidateRows = (id, pollType, candidates) => {
@@ -55,6 +49,7 @@ const makeCandidateRows = (id, pollType, candidates) => {
});
i++;
}
+
return nItems;
};
@@ -64,13 +59,15 @@ export async function createPoll(
pollType,
selectionType,
allowDuplication,
- state,
- candidates
+ candidates,
) {
let transaction;
let poll;
let nItems;
+ const state = "standby";
+ const pollDate = new Date();
+
try {
// get transaction
transaction = await sequelize.transaction();
@@ -84,8 +81,9 @@ export async function createPoll(
selectionType,
allowDuplication,
state,
+ pollDate,
},
- {transaction}
+ {transaction},
);
// step 2
@@ -98,7 +96,7 @@ export async function createPoll(
} catch (err) {
// Rollback transaction only if the transaction object is defined
if (transaction) await transaction.rollback();
- console.log("Transaction rollback", err);
+ logger.error("Transaction rollback", err);
}
if (poll && nItems) {
diff --git a/backend/DB/queries/question.js b/backend/DB/queries/question.js
index 0cce9953..cf0e1685 100644
--- a/backend/DB/queries/question.js
+++ b/backend/DB/queries/question.js
@@ -1,5 +1,6 @@
import Sequelize from "sequelize";
import models from "../models";
+import logger from "../logger.js";
const sequelize = models.sequelize;
const Op = Sequelize.Op;
@@ -22,7 +23,7 @@ export async function createQuestion(
}
export async function getQuestionsByEventId(EventId) {
- return models.Question.findAll({
+ return Question.findAll({
where: {EventId},
});
}
@@ -59,19 +60,26 @@ export async function updateIsStared(from, to) {
try {
if (from) {
- await Question.update({isStared: from.isStared},
+ await Question.update(
+ {isStared: from.isStared},
{where: {id: from.id}},
{transaction},
);
}
- await Question.update({isStared: to.isStared},
+
+ await Question.update(
+ {isStared: to.isStared},
{where: {id: to.id}},
{transaction},
);
+
await transaction.commit();
} catch (err) {
- if (transaction) await transaction.rollback();
- console.log("Transaction rollback", err);
+ if (transaction) {
+ await transaction.rollback();
+ }
+
+ logger.error("Transaction rollback", err);
}
}
diff --git a/backend/DB/queries/vote.js b/backend/DB/queries/vote.js
index ebdff291..d7417aec 100644
--- a/backend/DB/queries/vote.js
+++ b/backend/DB/queries/vote.js
@@ -1,22 +1,21 @@
-import models from "../models";
import Sequelize from "sequelize";
+import models from "../models";
+import logger from "../logger.js";
+const sequelize = models.sequelize;
+const Vote = models.Vote;
const Op = Sequelize.Op;
export async function addVote({GuestId, CandidateId}) {
- const vote = models.Vote.create({GuestId, CandidateId});
-
- return vote;
+ return Vote.create({GuestId, CandidateId});
}
export async function deleteVoteBy({GuestId, CandidateId}) {
- return models.Vote.destroy({where: {GuestId, CandidateId}});
+ return Vote.destroy({where: {GuestId, CandidateId}});
}
-export async function addAndDelete(gId, candidateToAdd, candidateToDelete) {
- const sequelize = models.sequelize;
- const Vote = models.Vote;
- const GuestId = gId;
+export async function addAndDelete(guestId, candidateToAdd, candidateToDelete) {
+ const GuestId = guestId;
let CandidateId = candidateToAdd;
let transaction;
let rows;
@@ -24,13 +23,14 @@ export async function addAndDelete(gId, candidateToAdd, candidateToDelete) {
try {
// get transaction
transaction = await sequelize.transaction();
+
// step 1
await Vote.create(
{
GuestId,
CandidateId,
},
- {transaction}
+ {transaction},
);
// step 2
@@ -40,33 +40,28 @@ export async function addAndDelete(gId, candidateToAdd, candidateToDelete) {
GuestId,
CandidateId,
},
+ transaction,
});
// commit
await transaction.commit();
} catch (err) {
// Rollback transaction only if the transaction object is defined
- if (transaction) await transaction.rollback();
- console.log("Transaction rollback", err);
+ if (transaction) {
+ await transaction.rollback();
+ }
+
+ logger.error("Transaction rollback", err);
}
return rows;
}
-export async function deleteVoteById({}) {}
-
-export async function getVotesByCandidate() {}
-
-export async function getVotesByGuestId() {}
-
-export async function getFromGuest() {}
-
export async function getCandidatesByGuestId(candidateList, guestId) {
- const result = await models.Vote.findAll({
+ return Vote.findAll({
where: {
[Op.and]: [
- {GuestId: guestId},
- {
+ {GuestId: guestId}, {
CandidateId: {
[Op.or]: candidateList,
},
@@ -75,12 +70,10 @@ export async function getCandidatesByGuestId(candidateList, guestId) {
},
attributes: ["CandidateId"],
});
-
- return result;
}
export async function getVotersByCandidateList(candidateList) {
- const count = await models.Vote.count({
+ return Vote.count({
where: {
CandidateId: {
[Op.or]: candidateList,
@@ -89,6 +82,4 @@ export async function getVotersByCandidateList(candidateList) {
distinct: true,
col: "GuestId",
});
-
- return count;
}
diff --git a/backend/docker/docker-development.yml b/backend/docker/docker-development.yml
index 1b5369b5..42939da0 100644
--- a/backend/docker/docker-development.yml
+++ b/backend/docker/docker-development.yml
@@ -1,31 +1,31 @@
version: "2.0"
services:
- mysql:
- container_name: ${MYSQL_DEV_CONTAINER_NAME}
- image: mysql
- ports:
- - ${MYSQL_DEV_PORT}:3306
- volumes:
- - ${DOCKER_VOLUMNS_PATH}/${MYSQL_DEV_CONTAINER_NAME}:/var/lib/mysql
- command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci --log-bin-trust-function-creators=1
- environment:
- - MYSQL_ROOT_PASSWORD=${MYSQL_DEV_ROOT_PASSWORD}
- - MYSQL_DATABASE=${MYSQL_DEV_SCHEME}
- - MYSQL_USER=${MYSQL_DEV_USER}
- - MYSQL_PASSWORD=${MYSQL_DEV_PASSWORD}
- networks:
- - backend
- redis:
- container_name: ${REDIS_DEV_CONTAINER_NAME}
- image: redis
- ports:
- - ${REDIS_DEV_PORT}:6379
- volumes:
- - ${DOCKER_VOLUMNS_PATH}/${REDIS_DEV_CONTAINER_NAME}:/data
- networks:
- - backend
+ mysql:
+ container_name: ${MYSQL_DEV_CONTAINER_NAME}
+ image: mysql
+ ports:
+ - ${MYSQL_DEV_PORT}:3306
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${MYSQL_DEV_CONTAINER_NAME}:/var/lib/mysql
+ command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci --log-bin-trust-function-creators=1
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MYSQL_DEV_ROOT_PASSWORD}
+ - MYSQL_DATABASE=${MYSQL_DEV_SCHEME}
+ - MYSQL_USER=${MYSQL_DEV_USER}
+ - MYSQL_PASSWORD=${MYSQL_DEV_PASSWORD}
+ networks:
+ - backend
+ redis:
+ container_name: ${REDIS_DEV_CONTAINER_NAME}
+ image: redis
+ ports:
+ - ${REDIS_DEV_PORT}:6379
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${REDIS_DEV_CONTAINER_NAME}:/data
+ networks:
+ - backend
networks:
- backend:
- driver: "bridge"
+ backend:
+ driver: "bridge"
diff --git a/backend/docker/docker-product.yml b/backend/docker/docker-product.yml
index 73d7eb69..2fe43f96 100644
--- a/backend/docker/docker-product.yml
+++ b/backend/docker/docker-product.yml
@@ -1,89 +1,89 @@
version: "2.0"
services:
- express:
- container_name: ${EXPRESS_PROD_CONTAINER_NAME}
- image: ${NODE_IMAGE_NAME}
- command: yarn pm2-runtime start ./build/express/app.js --watch
- environment:
- - NODE_ENV=production
- # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
- - IS_DOCKER_CONTAINER=true
- volumes:
- - ../build:/usr/src/app/build
- tty: true
- ports:
- - 80:${EXPRESS_PROD_PORT}
- networks:
- - backend
- links:
- - mysql
- - redis
+ express:
+ container_name: ${EXPRESS_PROD_CONTAINER_NAME}
+ image: ${NODE_IMAGE_NAME}
+ command: yarn pm2-runtime start ./build/express/app.js --watch
+ environment:
+ - NODE_ENV=production
+ # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
+ - IS_DOCKER_CONTAINER=true
+ volumes:
+ - ../build:/usr/src/app/build
+ tty: true
+ ports:
+ - 80:${EXPRESS_PROD_PORT}
+ networks:
+ - backend
+ links:
+ - mysql
+ - redis
- socket_io:
- container_name: ${SOCKET_IO_SERVER_PROD_CONTAINER_NAME}
- image: ${NODE_IMAGE_NAME}
- command: yarn pm2-runtime start ./build/socket_io_server/app.js --watch
- environment:
- - NODE_ENV=production
- # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
- - IS_DOCKER_CONTAINER=true
- volumes:
- - ../build:/usr/src/app/build
- tty: true
- ports:
- - ${SOCKET_IO_SERVER_PROD_PORT}:${SOCKET_IO_SERVER_PROD_PORT}
- networks:
- - backend
- links:
- - mysql
- - redis
+ socket_io:
+ container_name: ${SOCKET_IO_SERVER_PROD_CONTAINER_NAME}
+ image: ${NODE_IMAGE_NAME}
+ command: yarn pm2-runtime start ./build/socket_io_server/app.js --watch
+ environment:
+ - NODE_ENV=production
+ # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
+ - IS_DOCKER_CONTAINER=true
+ volumes:
+ - ../build:/usr/src/app/build
+ tty: true
+ ports:
+ - ${SOCKET_IO_SERVER_PROD_PORT}:${SOCKET_IO_SERVER_PROD_PORT}
+ networks:
+ - backend
+ links:
+ - mysql
+ - redis
- graphQL_yoga:
- container_name: ${GRAPHQL_YOGA_SERVER_PROD_CONTAINER_NAME}
- image: ${NODE_IMAGE_NAME}
- command: yarn pm2-runtime start ./build/graphQL/app.js --watch
- environment:
- - NODE_ENV=production
- # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
- - IS_DOCKER_CONTAINER=true
- volumes:
- - ../build:/usr/src/app/build
- tty: true
- ports:
- - ${GRAPHQL_YOGA_SERVER_PROD_PORT}:${GRAPHQL_YOGA_SERVER_PROD_PORT}
- networks:
- - backend
- links:
- - mysql
- - redis
+ graphQL_yoga:
+ container_name: ${GRAPHQL_YOGA_SERVER_PROD_CONTAINER_NAME}
+ image: ${NODE_IMAGE_NAME}
+ command: yarn pm2-runtime start ./build/graphQL/app.js --watch
+ environment:
+ - NODE_ENV=production
+ # container 내부에서 DB container 를 접근하기위해 필요한 환경변수
+ - IS_DOCKER_CONTAINER=true
+ volumes:
+ - ../build:/usr/src/app/build
+ tty: true
+ ports:
+ - ${GRAPHQL_YOGA_SERVER_PROD_PORT}:${GRAPHQL_YOGA_SERVER_PROD_PORT}
+ networks:
+ - backend
+ links:
+ - mysql
+ - redis
- mysql:
- container_name: ${MYSQL_PROD_CONTAINER_NAME}
- image: mysql
- ports:
- - ${MYSQL_PROD_PORT}:3306
- volumes:
- - ${DOCKER_VOLUMNS_PATH}/${MYSQL_PROD_CONTAINER_NAME}:/var/lib/mysql
- command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci --log-bin-trust-function-creators=1
- environment:
- - MYSQL_ROOT_PASSWORD=${MYSQL_PROD_ROOT_PASSWORD}
- - MYSQL_DATABASE=${MYSQL_PROD_SCHEME}
- - MYSQL_USER=${MYSQL_PROD_USER}
- - MYSQL_PASSWORD=${MYSQL_PROD_PASSWORD}
- networks:
- - backend
+ mysql:
+ container_name: ${MYSQL_PROD_CONTAINER_NAME}
+ image: mysql
+ ports:
+ - ${MYSQL_PROD_PORT}:3306
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${MYSQL_PROD_CONTAINER_NAME}:/var/lib/mysql
+ command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci --log-bin-trust-function-creators=1
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MYSQL_PROD_ROOT_PASSWORD}
+ - MYSQL_DATABASE=${MYSQL_PROD_SCHEME}
+ - MYSQL_USER=${MYSQL_PROD_USER}
+ - MYSQL_PASSWORD=${MYSQL_PROD_PASSWORD}
+ networks:
+ - backend
- redis:
- container_name: ${REDIS_PROD_CONTAINER_NAME}
- image: redis
- ports:
- - ${REDIS_PROD_PORT}:6379
- volumes:
- - ${DOCKER_VOLUMNS_PATH}/${REDIS_PROD_CONTAINER_NAME}:/data
- networks:
- - backend
+ redis:
+ container_name: ${REDIS_PROD_CONTAINER_NAME}
+ image: redis
+ ports:
+ - ${REDIS_PROD_PORT}:6379
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${REDIS_PROD_CONTAINER_NAME}:/data
+ networks:
+ - backend
networks:
- backend:
- driver: "bridge"
+ backend:
+ driver: "bridge"
diff --git a/backend/docker/docker-test.yml b/backend/docker/docker-test.yml
new file mode 100644
index 00000000..6ae7af62
--- /dev/null
+++ b/backend/docker/docker-test.yml
@@ -0,0 +1,32 @@
+version: "2.0"
+
+services:
+ mysql_test:
+ container_name: ${MYSQL_TEST_CONTAINER_NAME}
+ image: mysql
+ ports:
+ - ${MYSQL_TEST_PORT}:3306
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${MYSQL_TEST_CONTAINER_NAME}:/var/lib/mysql
+ command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8 --collation-server=utf8_general_ci --log-bin-trust-function-creators=1
+ environment:
+ - MYSQL_ROOT_PASSWORD=${MYSQL_TEST_ROOT_PASSWORD}
+ - MYSQL_DATABASE=${MYSQL_TEST_SCHEME}
+ - MYSQL_USER=${MYSQL_TEST_USER}
+ - MYSQL_PASSWORD=${MYSQL_TEST_PASSWORD}
+ networks:
+ - backend
+
+ redis_test:
+ container_name: ${REDIS_TEST_CONTAINER_NAME}
+ image: redis
+ ports:
+ - ${REDIS_TEST_PORT}:6379
+ volumes:
+ - ${DOCKER_VOLUMNS_PATH}/${REDIS_TEST_CONTAINER_NAME}:/data
+ networks:
+ - backend
+
+networks:
+ backend:
+ driver: "bridge"
diff --git a/backend/express/CookieKeys.js b/backend/express/CookieKeys.js
new file mode 100644
index 00000000..1cfc8e0a
--- /dev/null
+++ b/backend/express/CookieKeys.js
@@ -0,0 +1,6 @@
+const GUEST_APP = "vaagle-guest";
+const HOST_APP = "vaagle-host";
+
+export default {
+ GUEST_APP, HOST_APP,
+};
diff --git a/backend/express/app.js b/backend/express/app.js
index 02b5743f..47dd7d9a 100644
--- a/backend/express/app.js
+++ b/backend/express/app.js
@@ -1,19 +1,20 @@
-import {config} from "dotenv";
+import dotenv from "dotenv";
import express from "express";
import passport from "passport";
import cors from "cors";
import cookieParser from "cookie-parser";
import morgan from "morgan";
-import loadConfig from "./config/configLoader.js";
+import config from "./config";
import applyStaticAppServing from "./middleware/applyStaticAppServing.js";
import "./authentication/google.js";
import authRouter from "./routes/auth";
import guestRouter from "./routes/guest";
import hostRouter from "./routes/host";
+import logger from "./logger.js";
-config();
+dotenv.config()
-const {port, publicPath, routePage} = loadConfig();
+const {port, publicPath, routePage} = config;
const app = express();
applyStaticAppServing(app, publicPath);
@@ -32,10 +33,9 @@ app.get("/", (req, res, next) => {
});
app.listen(port, () => {
- console.log(
- `start express server at ${port} with ${process.env.NODE_ENV} mode`,
+ logger.info(
+ `start express server at ${port} with ${process.env.NODE_ENV} mode at public path = ${publicPath}`,
);
- console.log(`public path = ${publicPath}`);
});
export default app;
diff --git a/backend/express/authentication/google.js b/backend/express/authentication/google.js
index c882fe17..51ba1b9d 100644
--- a/backend/express/authentication/google.js
+++ b/backend/express/authentication/google.js
@@ -1,7 +1,8 @@
import passport from "passport";
import {Strategy} from "passport-google-oauth20";
-import loadConfig from "../config/configLoader";
+import config from "../config";
import {createHost, findHostByAuthId} from "../../DB/queries/host";
+import logger from "../logger.js";
const GoogleStrategy = Strategy;
@@ -11,6 +12,7 @@ function extractProfile(profile) {
if (profile.photos && profile.photos.length) {
imageUrl = profile.photos[0].value;
}
+
return {
id: profile.id,
displayName: profile.displayName,
@@ -19,9 +21,9 @@ function extractProfile(profile) {
};
}
-export default (function() {
- const {oAuthArgs} = loadConfig();
+const {oAuthArgs} = config;
+export default (function() {
const verify = async (accessToken, refreshToken, profile, cb) => {
try {
const {id, displayName, image, email} = extractProfile(profile);
@@ -30,9 +32,11 @@ export default (function() {
if (!host) {
host = await createHost(id, displayName, image, email);
}
+
return cb(null, host);
} catch (error) {
- console.error(error);
+ logger.error(error);
+
return null;
}
};
diff --git a/backend/express/authentication/token.js b/backend/express/authentication/token.js
index 5b45358f..1c6fcda6 100644
--- a/backend/express/authentication/token.js
+++ b/backend/express/authentication/token.js
@@ -1,15 +1,14 @@
import jwt from "jsonwebtoken";
-import loadConfig from "../config/configLoader";
+import config from "../config";
+
+const {tokenArgs} = config;
+const expiresIn = "24 hour";
export default function generateAccessToken(sub, aud) {
- const {tokenArgs} = loadConfig();
- const expiresIn = "24 hour";
- const token = jwt.sign({}, tokenArgs.secret, {
+ return jwt.sign({}, tokenArgs.secret, {
expiresIn,
issuer: tokenArgs.issuer,
audience: aud,
subject: sub,
});
-
- return token;
}
diff --git a/backend/express/config/configLoader.js b/backend/express/config/index.js
similarity index 79%
rename from backend/express/config/configLoader.js
rename to backend/express/config/index.js
index 1701a295..f3acf69b 100644
--- a/backend/express/config/configLoader.js
+++ b/backend/express/config/index.js
@@ -1,9 +1,9 @@
-import {config} from "dotenv";
+import dotenv from "dotenv";
import devConfig from "./express.dev.config.js";
import prodConfig from "./express.prod.config.js";
import testConfig from "./express.test.config.js";
-config();
+dotenv.config();
function loadConfig() {
let configs = {};
@@ -19,4 +19,6 @@ function loadConfig() {
return configs;
}
-export default loadConfig;
+const config = loadConfig();
+
+export default config;
diff --git a/backend/express/logger.js b/backend/express/logger.js
new file mode 100644
index 00000000..e43dab6e
--- /dev/null
+++ b/backend/express/logger.js
@@ -0,0 +1,5 @@
+import getLogger from "../libs/logger.js";
+
+const logger = getLogger("express");
+
+export default logger;
diff --git a/backend/express/middleware/authenticate.js b/backend/express/middleware/authenticate.js
index 82aa7e27..ae987d10 100644
--- a/backend/express/middleware/authenticate.js
+++ b/backend/express/middleware/authenticate.js
@@ -1,62 +1,55 @@
import jwt from "jsonwebtoken";
-import loadConfig from "../config/configLoader.js";
+import config from "../config";
import {findHostByAuthId} from "../../DB/queries/host";
-import {findGuestBySid} from "../../DB/queries/guest";
-import {getEventIdByEventCode} from "../../DB/queries/event";
-
-const {tokenArgs, routePage} = loadConfig();
-
-async function comparePathToCookie(path, guest) {
- const eventCode = Buffer.from(path, "base64").toString();
- const EventId = await getEventIdByEventCode(eventCode);
- if (guest.EventId !== EventId.dataValues.id) {
- return true;
- }
- return false;
-}
+import {isExistGuest} from "../../DB/queries/guest";
+import {convertPathToEventId} from "../utils";
+import logger from "../logger.js";
+import CookieKeys from "../CookieKeys.js";
-export function guestAuthenticate() {
- const cookieName = "vaagle-guest";
+const {tokenArgs, routePage} = config;
+export function guestAuthenticate() {
return async function(req, res, next) {
const path = req.params.path;
+
try {
const payload = jwt.verify(
- req.cookies[cookieName],
+ req.cookies[CookieKeys.GUEST_APP],
tokenArgs.secret
);
- const guest = await findGuestBySid(payload.sub);
- const isAnotherPath = await comparePathToCookie(path, guest);
- if (isAnotherPath) {
- return next();
- }
- if (!guest) {
- throw Error("token is invalid");
+
+ const guest = await isExistGuest(payload.sub);
+ const eventId = await convertPathToEventId(path);
+ const isGuestBelongToEvent = guest.EventId === eventId;
+
+ if (isGuestBelongToEvent) {
+ return res.redirect(routePage.guest);
}
- res.redirect(routePage.guest);
+
+ return next();
} catch (e) {
+ logger.error(e);
return next();
}
};
}
export function hostAuthenticate() {
- const cookieName = "vaagle-host";
-
return async function(req, res, next) {
try {
const payload = jwt.verify(
- req.cookies[cookieName],
+ req.cookies[CookieKeys.HOST_APP],
tokenArgs.secret
);
const host = await findHostByAuthId(payload.sub);
- if (!host) {
- throw Error("token is invalid");
+ if (host) {
+ res.redirect(routePage.host);
}
- res.redirect(routePage.host);
+
+ return next();
} catch (e) {
- console.log(e);
+ logger.error(e);
return next();
}
};
diff --git a/backend/express/routes/auth.js b/backend/express/routes/auth.js
index 99ab7cab..d9360de1 100644
--- a/backend/express/routes/auth.js
+++ b/backend/express/routes/auth.js
@@ -1,10 +1,12 @@
import express from "express";
import passport from "passport";
-import {getTokenExpired} from "../utils";
+import {getTokenExpired} from "../../libs/utils";
import generateAccessToken from "../authentication/token";
-import loadConfig from "../config/configLoader";
+import config from "../config";
+import CookieKeys from "../CookieKeys.js";
-const {routePage} = loadConfig();
+const EXPIRE_TIME = 2;
+const {routePage} = config;
const router = express.Router();
router.get(
@@ -13,7 +15,7 @@ router.get(
session: false,
scope: ["email", "profile"],
prompt: "select_account",
- }),
+ })
);
router.get(
@@ -24,8 +26,11 @@ router.get(
(req, res) => {
const accessToken = generateAccessToken(req.user.oauthId, "host");
- res.cookie("vaagle-host", accessToken, {expires: getTokenExpired(24)});
+ res.cookie(CookieKeys.HOST_APP, accessToken, {
+ expires: getTokenExpired(EXPIRE_TIME),
+ });
res.redirect(routePage.host);
- },
+ }
);
-module.exports = router;
+
+export default router;
diff --git a/backend/express/routes/guest.js b/backend/express/routes/guest.js
index 108940c9..08a0aebe 100644
--- a/backend/express/routes/guest.js
+++ b/backend/express/routes/guest.js
@@ -1,42 +1,55 @@
import express from "express";
-import {getTokenExpired} from "../utils";
+import jwt from "jsonwebtoken";
+import {getTokenExpired} from "../../libs/utils";
import generateAccessToken from "../authentication/token";
-import loadConfig from "../config/configLoader";
+import config from "../config";
import {guestAuthenticate} from "../middleware/authenticate";
import {createGuest} from "../../DB/queries/guest";
-import {getEventIdByEventCode} from "../../DB/queries/event";
+import {convertPathToEventId} from "../utils";
+import CookieKeys from "../CookieKeys.js";
+import logger from "../logger.js";
+import {isExistGuest} from "../../DB/queries/guest";
-const {routePage} = loadConfig();
+const {routePage, tokenArgs} = config;
const router = express.Router();
-const cookieName = "vaagle-guest";
+const cookieExpireTime = 2;
-async function pathToCode(path) {
- const eventCode = Buffer.from(path, "base64").toString();
- const eventId = await getEventIdByEventCode(eventCode);
+router.get("/", async (req, res, next) => {
+ try {
+ const payload = jwt.verify(
+ req.cookies[CookieKeys.GUEST_APP],
+ tokenArgs.secret
+ );
- return eventId.dataValues.id;
-}
+ const guest = await isExistGuest(payload.sub);
+ if (!guest) {
+ throw Error("Guest is not found");
+ }
-router.get("/", guestAuthenticate(), (req, res, next) => {
- res.redirect(routePage.main);
+ res.redirect(routePage.guest);
+ } catch (e) {
+ logger.error([e, e.stack]);
+ res.redirect(routePage.main);
+ }
});
router.get("/logout", (req, res, next) => {
- res.clearCookie(cookieName).redirect(routePage.main);
+ res.clearCookie(CookieKeys.GUEST_APP).redirect(routePage.main);
});
router.get("/:path", guestAuthenticate(), async (req, res, next) => {
try {
const path = req.params.path;
- const eventId = await pathToCode(path);
- const guest = await createGuest("Anonymous", eventId);
+ const eventId = await convertPathToEventId(path);
+ const guest = await createGuest(eventId);
const accessToken = generateAccessToken(guest.guestSid, "guest");
- res.cookie(cookieName, accessToken, {
- expires: getTokenExpired(24),
+
+ res.cookie(CookieKeys.GUEST_APP, accessToken, {
+ expires: getTokenExpired(cookieExpireTime),
});
res.redirect(routePage.guest);
} catch (e) {
- console.log(e);
+ logger.error([e, e.stack]);
res.redirect(routePage.main);
}
});
diff --git a/backend/express/routes/host.js b/backend/express/routes/host.js
index 988897cb..5b8cc851 100644
--- a/backend/express/routes/host.js
+++ b/backend/express/routes/host.js
@@ -1,13 +1,13 @@
import express from "express";
-import loadConfig from "../config/configLoader";
+import config from "../config";
import {hostAuthenticate} from "../middleware/authenticate";
+import CookieKeys from "../CookieKeys.js";
-const {routePage} = loadConfig();
+const {routePage} = config;
const router = express.Router();
-const cookieName = "vaagle-host";
router.get("/logout", (req, res, next) => {
- res.clearCookie(cookieName).redirect(routePage.main);
+ res.clearCookie(CookieKeys.HOST_APP).redirect(routePage.main);
});
router.get("/", hostAuthenticate(), (req, res, next) => {
diff --git a/backend/express/utils.js b/backend/express/utils.js
index 9e1735e9..d8efa91b 100644
--- a/backend/express/utils.js
+++ b/backend/express/utils.js
@@ -1,7 +1,15 @@
-const getSequelizeData = function(data) {
- return JSON.parse(JSON.stringify(data));
-};
+import {getEventByEventCode} from "../DB/queries/event";
+import {compareCurrentDateToTarget} from "../libs/utils";
-const getTokenExpired = hour => new Date(new Date().getTime() + 1000 * 60 * 60 * Number(hour));
+async function convertPathToEventId(path, guest) {
+ const eventCode = Buffer.from(path, "base64").toString();
+ let event = await getEventByEventCode(eventCode);
+ event = event.get({plain: true});
+ const diff = compareCurrentDateToTarget(event.endAt);
+ if (diff <= 0) {
+ throw new Error("이벤트 만료기간이 지났습니다.");
+ }
+ return event.id;
+}
-export {getSequelizeData, getTokenExpired};
+export {convertPathToEventId};
diff --git a/backend/graphQL/app.js b/backend/graphQL/app.js
index f0cab76c..50743ae5 100644
--- a/backend/graphQL/app.js
+++ b/backend/graphQL/app.js
@@ -6,55 +6,40 @@ import cookieParser from "cookie-parser";
import resolvers from "./resolvers.js";
import typeDefs from "./typeDefs.js";
import config from "./config.js";
-import {findHostByAuthId} from "../DB/queries/host";
import logger from "./logger.js";
+import authenticate from "./middlewares/authenticate.js";
-const authenticate = async (resolve, root, args, context, info) => {
- let audience = "anonymous";
+function parserJWT(data) {
+ return data.split(" ")[1];
+}
- audience = context.payload && context.payload.aud;
- let authority = {sub: null, info: null};
+const context = ({request}) => {
+ const authorization = request.headers.authorization;
- switch (audience) {
- case "host":
- {
- const hostInfo = await findHostByAuthId(context.payload.sub);
+ if (!authorization) {
+ return {payload: undefined};
+ }
- authority = {sub: "host", info: hostInfo};
- break;
- }
- case "guest":
- {
- const guestInfo = context.payload.sub;
+ let payload;
- authority = {sub: "guest", info: guestInfo};
- break;
- }
- default : {
- // console.log(`unexpected type of audience ${audience}`)
- }
+ try {
+ payload = jwt.verify(
+ parserJWT(authorization),
+ process.env.AUTH_TOKEN_SECRET,
+ );
+ } catch (e) {
+ logger.error(e);
+ payload = undefined;
}
- const result = await resolve(root, args, authority, info);
- return result;
+ return {payload};
};
const server = new GraphQLServer({
typeDefs,
resolvers,
middlewares: [authenticate],
- context: ({request}) => {
- let payload;
- const token = request.headers.authorization || "";
-
- try {
- payload = token === "" ? undefined : jwt.verify(token.split(" ")[1], process.env.AUTH_TOKEN_SECRET);
- } catch (e) {
- payload = undefined;
- } finally {
- return {payload};
- }
- },
+ context,
});
server.express.use(cors());
diff --git a/backend/graphQL/authentication/jwt.js b/backend/graphQL/authentication/jwt.js
deleted file mode 100644
index 1c3e695d..00000000
--- a/backend/graphQL/authentication/jwt.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import passport from "passport";
-import passportJwt from "passport-jwt";
-import {findHostById} from "../../DB/queries/host";
-
-export default (function() {
- const tokenArgs = {
- secret: process.env.AUTH_TOKEN_SECRET,
- issuer: process.env.AUTH_TOKEN_ISSUER,
- audience: process.env.AUTH_TOKEN_AUDIENCE,
- };
- const jwtOptions = {
- jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeaderAsBearerToken(),
- secretOrKey: tokenArgs.secret,
- issuer: tokenArgs.issuer,
- audience: tokenArgs.audience,
- };
-
- passport.use(
- new passportJwt.Strategy(jwtOptions, async (payload, cb) => {
- try {
- const host = await findHostById(payload.sub);
-
- if (host) {
- return cb(null, host, payload);
- }
- return cb();
- } catch (error) {}
- }),
- );
-})();
diff --git a/backend/graphQL/authentication/token.js b/backend/graphQL/authentication/token.js
index 20477415..56f5aa45 100644
--- a/backend/graphQL/authentication/token.js
+++ b/backend/graphQL/authentication/token.js
@@ -1,18 +1,17 @@
import jwt from "jsonwebtoken";
+const expiresIn = "1 hour";
+const tokenArgs = {
+ secret: process.env.AUTH_TOKEN_SECRET,
+ issuer: process.env.AUTH_TOKEN_ISSUER,
+ audience: process.env.AUTH_TOKEN_AUDIENCE,
+};
+
export default function generateAccessToken(hostOauthId) {
- const tokenArgs = {
- secret: process.env.AUTH_TOKEN_SECRET,
- issuer: process.env.AUTH_TOKEN_ISSUER,
- audience: process.env.AUTH_TOKEN_AUDIENCE,
- };
- const expiresIn = "1 hour";
- const token = jwt.sign({}, tokenArgs.secret, {
+ return jwt.sign({}, tokenArgs.secret, {
expiresIn,
issuer: tokenArgs.issuer,
audience: tokenArgs.audience,
subject: hostOauthId,
});
-
- return token;
}
diff --git a/backend/graphQL/middlewares/authenticate.js b/backend/graphQL/middlewares/authenticate.js
new file mode 100644
index 00000000..6058a824
--- /dev/null
+++ b/backend/graphQL/middlewares/authenticate.js
@@ -0,0 +1,29 @@
+import {findHostByAuthId} from "../../DB/queries/host.js";
+import logger from "../logger.js";
+
+const authenticate = async (resolve, root, args, context, info) => {
+ const audience = context.payload && context.payload.aud;
+ let authority = {sub: null, info: null};
+
+ switch (audience) {
+ case "host": {
+ const hostInfo = await findHostByAuthId(context.payload.sub);
+
+ authority = {sub: "host", info: hostInfo};
+ break;
+ }
+ case "guest": {
+ const guestInfo = context.payload.sub;
+
+ authority = {sub: "guest", info: guestInfo};
+ break;
+ }
+ default: {
+ logger.error(`unexpected type of audience ${audience}`);
+ }
+ }
+
+ return resolve(root, args, authority, info);
+};
+
+export default authenticate;
diff --git a/backend/graphQL/model/guest/guest.resolver.js b/backend/graphQL/model/guest/guest.resolver.js
index 948d2366..e92246ff 100644
--- a/backend/graphQL/model/guest/guest.resolver.js
+++ b/backend/graphQL/model/guest/guest.resolver.js
@@ -1,4 +1,7 @@
-import {getGuestByEventId, findGuestBySid} from "../../../DB/queries/guest.js";
+import {
+ getGuestByEventId,
+ getGuestByGuestSid,
+} from "../../../DB/queries/guest.js";
import {getEventById} from "../../../DB/queries/event.js";
const guestResolver = async EventId => getGuestByEventId(EventId);
@@ -8,10 +11,10 @@ const guestInEventResolver = async authority => {
throw Error("AuthenticationError in guestInEventResolver");
}
- const guest = await findGuestBySid(authority.info);
- const event = await getEventById(guest.EventId);
+ const guest = (await getGuestByGuestSid(authority.info)).get({plain: true});
+ const event = (await getEventById(guest.EventId)).get({plain: true});
- return {event: event.dataValues, guest};
+ return {event, guest};
};
// noinspection JSUnusedGlobalSymbols
diff --git a/backend/graphQL/model/hostpage/hostpage.resolver.js b/backend/graphQL/model/hostpage/hostpage.resolver.js
index 0c1adb51..f0d77ee0 100644
--- a/backend/graphQL/model/hostpage/hostpage.resolver.js
+++ b/backend/graphQL/model/hostpage/hostpage.resolver.js
@@ -11,12 +11,44 @@ import {
createHashtag,
getHashtagByEventIds,
} from "../../../DB/queries/hashtag.js";
+import {compareCurrentDateToTarget} from "../../../libs/utils";
-const moderationResolver = async (eventId, moderationOption) => {
- const updatedEvent = await updateEventById(eventId, {moderationOption});
+function verifySubjectHostJwt(jwtSub) {
+ if (jwtSub !== "host") {
+ throw new Error("AuthenticationError");
+ }
+}
- return updatedEvent[0];
-};
+function mappingHashTagsToEvents(hashTags, events, eventMap) {
+ hashTags.forEach(hashTag => {
+ const hashTagObject = hashTag.get({plain: true});
+
+ eventMap.get(hashTagObject.EventId).push(hashTagObject);
+ });
+ events.forEach(event => {
+ Object.assign(event, {HashTags: eventMap.get(event.id)});
+ });
+
+ return events;
+}
+
+async function generateEventCode() {
+ let generatedEventCode = faker.random.alphaNumeric(4);
+ const events = await getAllEvents();
+ const allreadyExistEventCode = events.map(event => event.eventCode);
+
+ while (1) {
+ const isExist = allreadyExistEventCode.some(
+ someCode => generateEventCode === someCode
+ );
+
+ if (!isExist) {
+ break;
+ }
+ generatedEventCode = faker.random.alphaNumeric(4);
+ }
+ return generatedEventCode;
+}
const getEventOptionResolver = async eventId => {
const evnetOption = await getEventOptionByEventId(eventId);
@@ -27,80 +59,69 @@ const getEventOptionResolver = async eventId => {
export default {
Query: {
init: async (_, {param}, authority) => {
- if (authority.sub === "host") {
- const host = authority.info;
- let events = await getEventsByHostId(host.id);
- events = events.map(event => event.get({plain: true}));
-
- const eventMap = new Map();
- const eventIdList = events.map(event => {
- eventMap.set(event.id, []);
- return event.id;
- });
+ verifySubjectHostJwt(authority.sub);
+ const host = authority.info;
+ let events = await getEventsByHostId(host.id);
- let hashTags = await getHashtagByEventIds(eventIdList);
- hashTags.forEach(hashTag => {
- const hashTagObject = hashTag.get({plain: true});
- eventMap.get(hashTagObject.EventId).push(hashTagObject);
- });
- events.forEach(event => {
- Object.assign(event, {HashTags: eventMap.get(event.id)});
- });
+ events = events.filter(event => {
+ const eventPlainObject = event.get({plain: true});
+ return eventPlainObject;
+ });
- return {events, host};
- }
+ const eventMap = new Map();
+ const eventIdList = events.map(event => {
+ eventMap.set(event.id, []);
+ return event.id;
+ });
+
+ const hashTags = await getHashtagByEventIds(eventIdList);
+ events = mappingHashTagsToEvents(hashTags, events, eventMap);
- throw new Error("AuthenticationError");
+ return {events, host};
},
+
getEventOption: async (_, {EventId}) => getEventOptionResolver(EventId),
},
+
Mutation: {
createHashTags: async (_, {hashTags}, authority) => {
- for (let hashTag of hashTags) {
+ verifySubjectHostJwt(authority.sub);
+ for (const hashTag of hashTags) {
await createHashtag({
name: hashTag.name,
EventId: hashTag.EventId,
});
}
},
+
createEvent: async (_, {info}, authority) => {
- if (authority.sub === "host") {
- let eventCode = faker.random.alphaNumeric(4);
- const events = await getAllEvents();
- const existCode = events.map(event => event.eventCode);
-
- while (true) {
- const exist = existCode.some(
- someCode => eventCode === someCode
- );
-
- if (!exist) break;
- eventCode = faker.random.alphaNumeric(4);
- }
- let event = await createEvent({
- eventName: info.eventName,
- eventCode,
- HostId: authority.info.id,
- startAt: info.startAt,
- endAt: info.endAt,
- });
+ verifySubjectHostJwt(authority.sub);
+ const eventCode = await generateEventCode();
- event = event[0].dataValues;
- return {...event};
- }
- throw new Error("AuthenticationError");
+ let event = await createEvent({
+ eventName: info.eventName,
+ eventCode: eventCode,
+ HostId: authority.info.id,
+ startAt: info.startAt,
+ endAt: info.endAt,
+ });
+
+ event = event[0].get({plain: true});
+ return {...event};
},
+
updateEvent: async (_, {event}, authority) => {
- let updatedEvent = await updateEventById(event.EventId, {
+ verifySubjectHostJwt(authority.sub);
+ await updateEventById({
+ id: event.EventId,
eventName: event.eventName,
startAt: event.startAt,
endAt: event.endAt,
});
- updatedEvent = await getEventById(event.EventId);
+
+ const updatedEvent = await getEventById(event.EventId);
return updatedEvent.get({plain: true});
},
- moderation: (_, {eventId, moderationOption}) =>
- moderationResolver(eventId, moderationOption),
},
};
diff --git a/backend/graphQL/model/poll/pollGuest.resolver.js b/backend/graphQL/model/poll/pollGuest.resolver.js
index b60ba219..032d83f7 100644
--- a/backend/graphQL/model/poll/pollGuest.resolver.js
+++ b/backend/graphQL/model/poll/pollGuest.resolver.js
@@ -1,100 +1,11 @@
-import {getPollsByEventId} from "../../../DB/queries/poll.js";
-import {getCandidatesByPollId} from "../../../DB/queries/candidate.js";
+import {getCandidatesByGuestId} from "../../../DB/queries/vote.js";
import {
- getVotersByCandidateList,
- getCandidatesByGuestId,
-} from "../../../DB/queries/vote.js";
-
-const simplifyList = list => list.map(n => n.get({plain: true}));
-
-/**
- *
- * @param {int} pollId
- * @param {array of int} candidates
- *
- * 하나의 poll 은 여러개의 candidates (예. 기호1번, 기호2번 등)을 가지고 있음
- * 각 candidate 별 득표수를 계산하고,
- * 가장 많은 득표수를 받은 candidate의 firstPlace 값을 true로 설정하고,
- * candidates들을 묶어서 nItems 라는 하나의 array에 넣어서 poll 객체에 넣어주는 함수
- */
-async function getItems(pollId, candidates) {
- const nItems = [];
- let firstPlaceIndex = [];
- let index = 0;
- let firstPlaceValue = 0;
-
- for (const n of candidates) {
- if (n.PollId === pollId) {
- const voters = await getVotersByCandidateList([n.id]);
-
- nItems.push({
- ...n,
- voters,
- voted: false,
- firstPlace: false,
- });
- // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 찾아내는 부분
- if (voters == firstPlaceValue) {
- firstPlaceIndex.push(index);
- } else if (voters > firstPlaceValue) {
- firstPlaceIndex = [];
- firstPlaceIndex.push(index);
- firstPlaceValue = voters;
- }
- index++;
- }
- }
- // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 지정하는 부분
- firstPlaceIndex.forEach(i => {
- nItems[i].firstPlace = true;
- });
-
- return nItems;
-}
-
-/**
- *
- * @param {array of object} polls
- *
- * 하나의 poll에 속한 candidates들을 DB에서 읽어오는 함수
- */
-async function getCandidatesByPolls(polls) {
- const pollIdList = polls.map(poll => poll.id);
- let candidates = await getCandidatesByPollId(pollIdList);
-
- candidates = simplifyList(candidates);
-
- return candidates;
-}
-
-/**
- *
- * @param {array of object} items
- *
- * CandidateId (int) 만 읽어서 array로 반환해주는 함수
- */
-const getCandidateList = items => items.map(n => n.id);
-
-/**
- *
- * @param {array of object} polls
- * @param {array of object} candidates
- *
- * 여러개의 poll들과 그 poll들에 속하는 모든 candidates를 가져와서
- * 각 poll에 속한 candidates 들만 nItems 객체로 만들어서 저장함
- *
- * 그리고 해당 poll에 속한 모든 candidates들에 투표한 투표자수를 unique하게 더한 총투표수를 구함
- */
-async function setPollItems(polls, candidates) {
- for (const poll of polls) {
- poll.nItems = await getItems(poll.id, candidates);
- const candidateList = getCandidateList(poll.nItems);
-
- poll.totalVoters = await getVotersByCandidateList(candidateList);
- }
-
- return polls;
-}
+ getCandidateList,
+ getCandidatesByPolls,
+ setPollItems,
+ simplifyList,
+} from "./resolveHelper.js";
+import {getPollsByEventId} from "../../../DB/queries/poll.js";
/**
*
diff --git a/backend/graphQL/model/poll/pollHost.resolver.js b/backend/graphQL/model/poll/pollHost.resolver.js
index fbd2cead..28e28a0c 100644
--- a/backend/graphQL/model/poll/pollHost.resolver.js
+++ b/backend/graphQL/model/poll/pollHost.resolver.js
@@ -1,98 +1,5 @@
import {getPollsByEventId} from "../../../DB/queries/poll.js";
-import {getCandidatesByPollId} from "../../../DB/queries/candidate.js";
-import {getVotersByCandidateList} from "../../../DB/queries/vote.js";
-// import { getCandidatesByGuestId } from "../../../DB/queries/vote.js";
-
-const simplifyList = list => list.map(n => n.get({plain: true}));
-
-/**
- *
- * @param {int} pollId
- * @param {array of int} candidates
- *
- * 하나의 poll 은 여러개의 candidates (예. 기호1번, 기호2번 등)을 가지고 있음
- * 각 candidate 별 득표수를 계산하고,
- * 가장 많은 득표수를 받은 candidate의 firstPlace 값을 true로 설정하고,
- * candidates들을 묶어서 nItems 라는 하나의 array에 넣어서 poll 객체에 넣어주는 함수
- */
-async function getItems(pollId, candidates) {
- const nItems = [];
- let firstPlaceIndex = [];
- let index = 0;
- let firstPlaceValue = 0;
-
- for (const n of candidates) {
- if (n.PollId === pollId) {
- const voters = await getVotersByCandidateList([n.id]);
-
- nItems.push({
- ...n,
- voters,
- voted: false,
- firstPlace: false,
- });
- // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 찾아내는 부분
- if (voters == firstPlaceValue) {
- firstPlaceIndex.push(index);
- } else if (voters > firstPlaceValue) {
- firstPlaceIndex = [];
- firstPlaceIndex.push(index);
- firstPlaceValue = voters;
- }
- index++;
- }
- }
- // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 지정하는 부분
- firstPlaceIndex.forEach(i => {
- nItems[i].firstPlace = true;
- });
-
- return nItems;
-}
-
-/**
- *
- * @param {array of object} polls
- *
- * 하나의 poll에 속한 candidates들을 DB에서 읽어오는 함수
- */
-async function getCandidatesByPolls(polls) {
- const pollIdList = polls.map(poll => poll.id);
- let candidates = await getCandidatesByPollId(pollIdList);
-
- candidates = simplifyList(candidates);
-
- return candidates;
-}
-
-/**
- *
- * @param {array of object} items
- *
- * CandidateId (int) 만 읽어서 array로 반환해주는 함수
- */
-const getCandidateList = items => items.map(n => n.id);
-
-/**
- *
- * @param {array of object} polls
- * @param {array of object} candidates
- *
- * 여러개의 poll들과 그 poll들에 속하는 모든 candidates를 가져와서
- * 각 poll에 속한 candidates 들만 nItems 객체로 만들어서 저장함
- *
- * 그리고 해당 poll에 속한 모든 candidates들에 투표한 투표자수를 unique하게 더한 총투표수를 구함
- */
-async function setPollItems(polls, candidates) {
- for (const poll of polls) {
- poll.nItems = await getItems(poll.id, candidates);
- const candidateList = getCandidateList(poll.nItems);
-
- poll.totalVoters = await getVotersByCandidateList(candidateList);
- }
-
- return polls;
-}
+import {getCandidatesByPolls, setPollItems, simplifyList} from "./resolveHelper.js";
/**
*
@@ -116,7 +23,6 @@ async function pollHostResolver(EventId) {
const candidates = await getCandidatesByPolls(polls);
polls = await setPollItems(polls, candidates);
-
return polls;
}
diff --git a/backend/graphQL/model/poll/resolveHelper.js b/backend/graphQL/model/poll/resolveHelper.js
new file mode 100644
index 00000000..6d1811da
--- /dev/null
+++ b/backend/graphQL/model/poll/resolveHelper.js
@@ -0,0 +1,90 @@
+import {getVotersByCandidateList} from "../../../DB/queries/vote.js";
+import {getCandidatesByPollId} from "../../../DB/queries/candidate.js";
+
+export const simplifyList = list => list.map(n => n.get({plain: true}));
+
+/**
+ *
+ * @param {array of object} items
+ *
+ * CandidateId (int) 만 읽어서 array로 반환해주는 함수
+ */
+export const getCandidateList = items => items.map(n => n.id);
+/**
+ *
+ * @param {int} pollId
+ * @param {array of int} candidates
+ *
+ * 하나의 poll 은 여러개의 candidates (예. 기호1번, 기호2번 등)을 가지고 있음
+ * 각 candidate 별 득표수를 계산하고,
+ * 가장 많은 득표수를 받은 candidate의 firstPlace 값을 true로 설정하고,
+ * candidates들을 묶어서 nItems 라는 하나의 array에 넣어서 poll 객체에 넣어주는 함수
+ */
+export async function getItems(pollId, candidates) {
+ const nItems = [];
+ let firstPlaceIndex = [];
+ let index = 0;
+ let firstPlaceValue = 0;
+
+ for (const n of candidates) {
+ if (n.PollId === pollId) {
+ const voters = await getVotersByCandidateList([n.id]);
+
+ nItems.push({
+ ...n,
+ voters,
+ voted: false,
+ firstPlace: false,
+ });
+ // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 찾아내는 부분
+ if (voters === firstPlaceValue) {
+ firstPlaceIndex.push(index);
+ } else if (voters > firstPlaceValue) {
+ firstPlaceIndex = [];
+ firstPlaceIndex.push(index);
+ firstPlaceValue = voters;
+ }
+ index++;
+ }
+ }
+ // Poll에 속한 candidates들 중에 가장 많은 득표수를 받은 candidate을 지정하는 부분
+ firstPlaceIndex.forEach(i => {
+ nItems[i].firstPlace = true;
+ });
+
+ return nItems;
+}
+
+/**
+ *
+ * @param {array of object} polls
+ *
+ * 하나의 poll에 속한 candidates들을 DB에서 읽어오는 함수
+ */
+export async function getCandidatesByPolls(polls) {
+ const pollIdList = polls.map(poll => poll.id);
+ const candidates = await getCandidatesByPollId(pollIdList);
+
+ return simplifyList(candidates);
+}
+
+/**
+ *
+ * @param {array of object} polls
+ * @param {array of object} candidates
+ *
+ * 여러개의 poll들과 그 poll들에 속하는 모든 candidates를 가져와서
+ * 각 poll에 속한 candidates 들만 nItems 객체로 만들어서 저장함
+ *
+ * 그리고 해당 poll에 속한 모든 candidates들에 투표한 투표자수를 unique하게 더한 총투표수를 구함
+ */
+export async function setPollItems(polls, candidates) {
+ for (const poll of polls) {
+ poll.nItems = await getItems(poll.id, candidates);
+ const candidateList = getCandidateList(poll.nItems);
+
+ poll.totalVoters = await getVotersByCandidateList(candidateList);
+ }
+
+ return polls;
+}
diff --git a/backend/libs/utils.js b/backend/libs/utils.js
new file mode 100644
index 00000000..b0f615dc
--- /dev/null
+++ b/backend/libs/utils.js
@@ -0,0 +1,17 @@
+import moment from "moment";
+
+const compareCurrentDateToTarget = baseDate => {
+ const endAt = moment(baseDate);
+ const current = moment();
+
+ return endAt.diff(current, "minute");
+};
+
+const getSequelizeData = function(data) {
+ return JSON.parse(JSON.stringify(data));
+};
+
+const getTokenExpired = hour =>
+ new Date(new Date().getTime() + 1000 * 60 * 60 * Number(hour));
+
+export {getSequelizeData, getTokenExpired, compareCurrentDateToTarget};
diff --git a/backend/package.json b/backend/package.json
index 8b172589..d723043c 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -8,10 +8,10 @@
"scripts": {
"node:babel": "node -r @babel/register",
"reinstall": "rm -rf ../node_modules && yarn install",
- "test": "./node_modules/.bin/mocha ./spec --recursive",
- "test:DB": "./node_modules/.bin/mocha ./spec -name '*.db.spec.js' --recursive --watch",
- "test:watch": "./node_modules/.bin/mocha ./spec --recursive --watch",
- "test:only": "./node_modules/.bin/mocha --watch",
+ "test": "cross-env NODE_ENV=test ./node_modules/.bin/mocha ./spec --recursive",
+ "test:DB": "cross-env NODE_ENV=test ./node_modules/.bin/mocha ./spec -name '*.db.spec.js' --recursive --watch",
+ "test:watch": "cross-env NODE_ENV=test ./node_modules/.bin/mocha ./spec --recursive --watch",
+ "test:only": "cross-env NODE_ENV=test ./node_modules/.bin/mocha --watch",
"build": "sh script/build.sh",
"build:clean": "rm -rf ./build",
"start": "concurrently \"yarn start:socket\" \"yarn start:express\" \"yarn start:yoga\" \"yarn start:DB\" ",
@@ -19,8 +19,10 @@
"start:socket": "cross-env NODE_ENV=development ./node_modules/.bin/nodemon --config ./nodemon.json --exec babel-watch ./socket_io_server/app.js",
"start:yoga": "cross-env NODE_ENV=development ./node_modules/.bin/nodemon --config ./nodemon.json --exec babel-watch ./graphQL/app.js",
"start:DB": "docker-compose -f docker/docker-development.yml up -d",
- "stop": "yarn stop:DB",
+ "start:DB:test": "docker-compose -f docker/docker-test.yml up -d",
"stop:DB": "docker-compose -f docker/docker-development.yml down --remove-orphans",
+ "stop:DB:test": "docker-compose -f docker/docker-test.yml down --remove-orphans",
+ "stop": "yarn stop:DB",
"migration:development": "cross-env NODE_ENV=development sh ./script/sequelize.sh",
"migration:test": "cross-env NODE_ENV=test sh ./script/sequelize.sh",
"migration:production": "cross-env NODE_ENV=production sh ./script/sequelize.sh",
diff --git a/backend/redis/config/dev.config.js b/backend/redis/config/dev.config.js
index 25b91377..a0692eed 100644
--- a/backend/redis/config/dev.config.js
+++ b/backend/redis/config/dev.config.js
@@ -3,7 +3,7 @@ import dotenv from "dotenv";
dotenv.config();
const config = {
- port: process.env.REDIS_DEV_PORT,
+ port: parseInt(process.env.REDIS_DEV_PORT, 10),
host: process.env.REDIS_DEV_HOST,
};
diff --git a/backend/redis/config/configLoader.js b/backend/redis/config/index.js
similarity index 87%
rename from backend/redis/config/configLoader.js
rename to backend/redis/config/index.js
index 76b974ef..52eae70c 100644
--- a/backend/redis/config/configLoader.js
+++ b/backend/redis/config/index.js
@@ -17,4 +17,6 @@ function loadConfig() {
return config;
}
-export default loadConfig;
+const config = loadConfig();
+
+export default config;
diff --git a/backend/redis/config/prod.config.js b/backend/redis/config/prod.config.js
index 25b91377..1f1fc5eb 100644
--- a/backend/redis/config/prod.config.js
+++ b/backend/redis/config/prod.config.js
@@ -3,8 +3,8 @@ import dotenv from "dotenv";
dotenv.config();
const config = {
- port: process.env.REDIS_DEV_PORT,
- host: process.env.REDIS_DEV_HOST,
+ port: parseInt(process.env.REDIS_PROD_PORT, 10),
+ host: process.env.REDIS_PROD_HOST,
};
export default config;
diff --git a/backend/redis/config/test.config.js b/backend/redis/config/test.config.js
index 25b91377..91d8d18c 100644
--- a/backend/redis/config/test.config.js
+++ b/backend/redis/config/test.config.js
@@ -3,8 +3,8 @@ import dotenv from "dotenv";
dotenv.config();
const config = {
- port: process.env.REDIS_DEV_PORT,
- host: process.env.REDIS_DEV_HOST,
+ port: parseInt(process.env.REDIS_TEST_PORT, 10),
+ host: process.env.REDIS_TEST_HOST,
};
export default config;
diff --git a/backend/redis/redisClient.js b/backend/redis/redisClient.js
index acedd402..e72339e6 100644
--- a/backend/redis/redisClient.js
+++ b/backend/redis/redisClient.js
@@ -1,9 +1,8 @@
import redis from "redis";
import asyncRedis from "async-redis";
import getLogger from "../libs/logger.js";
-import loadConfig from "./config/configLoader.js";
+import config from "./config";
-const config = loadConfig();
const client = redis.createClient(config.port, config.host);
const asyncRedisClient = asyncRedis.decorate(client);
diff --git a/backend/socket_io_server/IORoomManager.js b/backend/socket_io_server/IORoomManager.js
deleted file mode 100644
index 468164e0..00000000
--- a/backend/socket_io_server/IORoomManager.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import logger from "./logger.js";
-
-const IORoomManager = ({socket, afterJoinRoom, afterLeaveRoom, room}) => {
- const id = socket.id;
- let currentRoom = room;
-
- const joinRoom = async room => {
- try {
- await socket.join(room);
- currentRoom = room;
- } catch (e) {
- logger.error(`error raised while join room ${e}`);
- }
- };
-
- const leaveRoom = async () => {
- try {
- socket.leave(currentRoom);
- currentRoom = null;
- } catch (e) {
- logger.error(`error raised while leave room ${e}`);
- }
- };
-
- const onJoinRoom = async req => {
- if (currentRoom) {
- logger.error(`id: ${id} already join in room`);
- return;
- }
-
- await joinRoom(req.room);
- socket.emit("joinRoom");
- afterJoinRoom(req.room, socket);
- };
-
- const onLeaveRoom = async req => {
- if (currentRoom === null) {
- logger.error(`id: ${id} is not in room`);
- return;
- }
-
- const lastRoom = currentRoom;
-
- await leaveRoom();
- socket.emit("leaveRoom");
- afterLeaveRoom(lastRoom, socket);
- };
-
- const onChangeRoom = async req => {
- await onLeaveRoom(req);
- await onJoinRoom(req);
- };
-
- socket.on("joinRoom", onJoinRoom);
- socket.on("leaveRoom", onLeaveRoom);
- socket.on("changeRoom", onChangeRoom);
-};
-
-export default IORoomManager;
diff --git a/backend/socket_io_server/RoomSocket.js b/backend/socket_io_server/RoomSocket.js
new file mode 100644
index 00000000..a64f8fb1
--- /dev/null
+++ b/backend/socket_io_server/RoomSocket.js
@@ -0,0 +1,52 @@
+class RoomSocket {
+ constructor({socket, server, handlerEventPair}) {
+ this.socket = socket;
+ this.server = server;
+ this.handlerPair = handlerEventPair;
+ this.registeredHandler = [];
+ }
+
+ joinRoom(room) {
+ this.room = room;
+
+ this.socket.join(this.room);
+
+ this.registeredHandler = this.handlerPair.map(({eventName, handler}) =>
+ this.addListener(eventName, handler)
+ );
+
+ this.socket.emit("joinRoom");
+ }
+
+ leaveRoom() {
+ this.socket.leave(this.room);
+
+ this.registeredHandler.map(({eventName, handler}) =>
+ this.socket.removeListener(eventName, handler)
+ );
+
+ this.socket.emit("leaveRoom");
+
+ this.room = null;
+ this.registeredHandler = [];
+ }
+
+ addListener(event, handler) {
+ const roomEmit = res => {
+ this.server.to(this.room).emit(event, res);
+ };
+
+ const wrappedSocketHandler = data => {
+ handler(data, roomEmit, {socket: this.socket, server: this.server});
+ };
+
+ this.socket.on(event, wrappedSocketHandler);
+
+ return {
+ eventName: event,
+ handler: wrappedSocketHandler,
+ };
+ }
+}
+
+export default RoomSocket;
diff --git a/backend/socket_io_server/RoomSocketHelper.js b/backend/socket_io_server/RoomSocketHelper.js
new file mode 100644
index 00000000..d98d20cb
--- /dev/null
+++ b/backend/socket_io_server/RoomSocketHelper.js
@@ -0,0 +1,45 @@
+import logger from "./logger.js";
+import RoomSocket from "./RoomSocket.js";
+
+const RoomSocketHelper = ({server, socket, handlerEventPair}) => {
+ const id = socket.id;
+ const currentRoom = null;
+ const roomSocket = new RoomSocket({
+ socket,
+ server,
+ handlerEventPair,
+ });
+
+ const onJoinRoom = async req => {
+ const {room} = req;
+
+ if (currentRoom) {
+ logger.error(`id: ${id} already join in room`);
+ return;
+ }
+
+ try {
+ roomSocket.joinRoom(room);
+ } catch (e) {
+ logger.error(`error raised while join room ${e}`);
+ }
+ };
+
+ const onLeaveRoom = async () => {
+ // if (currentRoom === null) {
+ // logger.error(`id: ${id} is not in room`);
+ // return;
+ // }
+
+ try {
+ roomSocket.leaveRoom();
+ } catch (e) {
+ logger.error(`error raised while leave room ${e}`);
+ }
+ };
+
+ socket.on("joinRoom", onJoinRoom);
+ socket.on("leaveRoom", onLeaveRoom);
+};
+
+export default RoomSocketHelper;
diff --git a/backend/socket_io_server/SocketIOBulkHandlerManager.js b/backend/socket_io_server/SocketIOBulkHandlerManager.js
deleted file mode 100644
index 6f55bf9f..00000000
--- a/backend/socket_io_server/SocketIOBulkHandlerManager.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import logger from "./logger.js";
-
-const bindAddSocketListener = (socket, server, room) => (
- eventName,
- handler,
-) => {
- const wrappedHandler = data => {
- const emit = res => {
- server.to(room).emit(eventName, res);
- };
-
- try {
- handler(data, emit, {socket, server});
- } catch (e) {
- logger.error(
- `while handing ${eventName} error raise,\n ${e.toString()}\n${
- e.stack
- }`,
- );
- socket.send({status: "error", error: e});
- }
- };
-
- socket.on(eventName, wrappedHandler);
-
- return () => {
- socket.off(eventName, wrappedHandler);
- };
-};
-
-export const addBulkSocketIOHandlers = ({handlers, socket, server, room}) => {
- const addSocketListener = bindAddSocketListener(socket, server, room);
-
- const AttachedHandlers = handlers.map(({eventName, handler}) => {
- addSocketListener(eventName, handler);
- });
-
- return () => AttachedHandlers.map(removeHandler => removeHandler());
-};
-
-export const removeBulkSocketIOHandlers = handlers => handlers();
diff --git a/backend/socket_io_server/app.js b/backend/socket_io_server/app.js
index 1556161b..6e2f0f3b 100644
--- a/backend/socket_io_server/app.js
+++ b/backend/socket_io_server/app.js
@@ -5,8 +5,7 @@ import io from "socket.io";
import configLoader from "./config/configLoader.js";
import logger from "./logger.js";
import authenticate from "./middleware/authenticate";
-import IORoomManager from "./IORoomManager.js";
-import {addBulkSocketIOHandlers, removeBulkSocketIOHandlers} from "./SocketIOBulkHandlerManager.js";
+import RoomSocketHelper from "./RoomSocketHelper.js";
import socketHandlers from "./socketHandler";
dotenv.config();
@@ -25,25 +24,13 @@ const namedServer = socketServer.of(NAME_SPACE);
socketServer.use(authenticate());
namedServer.on("connection", async socket => {
const id = socket.id;
- let bulkHandlers = null;
logger.info(`id ${id} connected at /${NAME_SPACE}`);
- IORoomManager({
- bulkHandlers,
+ RoomSocketHelper({
socket,
- afterJoinRoom: (room, socket) => {
- bulkHandlers = addBulkSocketIOHandlers({
- handlers: socketHandlers,
- socket,
- server: namedServer,
- room,
- });
- },
- afterLeaveRoom: (room, socket) => {
- removeBulkSocketIOHandlers(bulkHandlers);
- bulkHandlers = null;
- },
+ server: namedServer,
+ handlerEventPair: socketHandlers,
});
socket.on("error", error =>
diff --git a/backend/socket_io_server/middleware/authenticate.js b/backend/socket_io_server/middleware/authenticate.js
index c711b9b6..5ca5f03e 100644
--- a/backend/socket_io_server/middleware/authenticate.js
+++ b/backend/socket_io_server/middleware/authenticate.js
@@ -2,25 +2,34 @@ import jwt from "jsonwebtoken";
import loadConfig from "../config/configLoader";
import logger from "../logger";
import {findHostByAuthId} from "../../DB/queries/host";
-import {findGuestBySid} from "../../DB/queries/guest";
+import {isExistGuest} from "../../DB/queries/guest";
const {tokenArgs} = loadConfig();
+const audienceVerify = {guest: isExistGuest, host: findHostByAuthId};
+
+const isValidAud = aud => aud !== "guest" && aud !== "host";
+
+const isValidIss = iss => iss !== tokenArgs.issuer;
+
async function payloadVerify(payload) {
const {aud, iss, sub} = payload;
- const audienceVerify = {guest: findGuestBySid, host: findHostByAuthId};
- if (iss !== tokenArgs.issuer) {
- return new Error("Authentication Error");
+
+ if (isValidIss(iss)) {
+ throw new Error("Authentication Error: invalid iss");
}
- if (aud !== "guest" && aud !== "host") {
- return new Error("Authentication Error");
+
+ if (isValidAud(aud)) {
+ throw new Error("Authentication Error: invalid aud");
}
- const audience = aud === "guest" ? "guest" : "host";
- const userInfo = await audienceVerify[audience](sub);
+
+ const userInfo = await audienceVerify[aud](sub);
+
if (!userInfo) {
- return new Error("Authentication Error");
+ throw new Error("Authentication Error: invalid userInfo");
}
- return userInfo;
+
+ return null;
}
function authenticate() {
@@ -28,10 +37,9 @@ function authenticate() {
try {
const token = socket.handshake.query.token;
const payload = jwt.verify(token, tokenArgs.secret);
- const userInfo = await payloadVerify(payload);
- if (!userInfo) {
- throw Error("Authentication Error");
- }
+
+ await payloadVerify(payload);
+
return next();
} catch (e) {
logger.debug(e);
diff --git a/backend/socket_io_server/socketHandler/Poll/closePoll.socketHandler.js b/backend/socket_io_server/socketHandler/Poll/closePoll.socketHandler.js
index 98ddb169..7b2112b1 100644
--- a/backend/socket_io_server/socketHandler/Poll/closePoll.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Poll/closePoll.socketHandler.js
@@ -1,20 +1,22 @@
import {closePoll} from "../../../DB/queries/poll";
+import logger from "../../logger.js";
const closePollSocketHandler = async (data, emit) => {
try {
+ let status = "ok";
const {pollId} = data;
const result = await closePoll(pollId);
if (result[0] != 1) {
- console.log(
+ logger.error(
`Something wrong with poll/close: affected number of rows = ${result[0]}`
);
- return;
+ status = "error";
}
- emit(pollId);
+ emit({status, pollId});
} catch (e) {
- console.error(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Poll/createPoll.socketHandler.js b/backend/socket_io_server/socketHandler/Poll/createPoll.socketHandler.js
index 08d41cd7..665b18ba 100644
--- a/backend/socket_io_server/socketHandler/Poll/createPoll.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Poll/createPoll.socketHandler.js
@@ -1,4 +1,5 @@
import {createPoll} from "../../../DB/queries/poll";
+import logger from "../../logger.js";
const createPollSocketHandler = async (data, emit) => {
try {
@@ -11,21 +12,18 @@ const createPollSocketHandler = async (data, emit) => {
candidates,
} = data;
- const state = "standby";
-
- const result = await createPoll(
+ const poll = await createPoll(
EventId,
pollName,
pollType,
selectionType,
allowDuplication,
- state,
- candidates,
+ candidates
);
- emit(result);
+ emit({status: "ok", poll});
} catch (e) {
- console.error(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Poll/nofityPollClose.socketHandler.js b/backend/socket_io_server/socketHandler/Poll/nofityPollClose.socketHandler.js
index c32f0330..d2c60c5f 100644
--- a/backend/socket_io_server/socketHandler/Poll/nofityPollClose.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Poll/nofityPollClose.socketHandler.js
@@ -1,10 +1,12 @@
+import logger from "../../logger.js";
+
const notifyPollCloseSocketHandler = async (data, emit) => {
try {
- const {id} = data;
+ const {pollId} = data;
- emit(id);
+ emit({status: "ok", pollId});
} catch (e) {
- console.error(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Poll/notifyPollOpen.socketHandler.js b/backend/socket_io_server/socketHandler/Poll/notifyPollOpen.socketHandler.js
index 3af38287..bf5f1c38 100644
--- a/backend/socket_io_server/socketHandler/Poll/notifyPollOpen.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Poll/notifyPollOpen.socketHandler.js
@@ -1,10 +1,12 @@
+import logger from "../../logger.js";
+
const notifyPollOpenSocketHandler = async (data, emit) => {
try {
const {poll} = data;
- emit(poll);
+ emit({status: "ok", poll});
} catch (e) {
- console.error(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Poll/openPoll.socketHandler.js b/backend/socket_io_server/socketHandler/Poll/openPoll.socketHandler.js
index f8a273e2..387616c1 100644
--- a/backend/socket_io_server/socketHandler/Poll/openPoll.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Poll/openPoll.socketHandler.js
@@ -1,20 +1,22 @@
import {openPoll} from "../../../DB/queries/poll";
+import logger from "../../logger.js";
const openPollSocketHandler = async (data, emit) => {
try {
+ let status = "ok";
const {pollId} = data;
const result = await openPoll(pollId);
if (result[0] != 1) {
- console.log(
- `Something wrong with poll/open: affected number of rows = ${result[0]}`,
+ logger.error(
+ `Something wrong with poll/open: affected number of rows = ${result[0]}`
);
- return;
+ status = "error";
}
- emit(pollId);
+ emit({status, pollId});
} catch (e) {
- console.error(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Question/toggleModeration.socketHandler.js b/backend/socket_io_server/socketHandler/Question/toggleModeration.socketHandler.js
index 8681f602..89033457 100644
--- a/backend/socket_io_server/socketHandler/Question/toggleModeration.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Question/toggleModeration.socketHandler.js
@@ -1,17 +1,21 @@
import {updateEventById} from "../../../DB/queries/event";
import eventCache from "../../EventCache";
+import logger from "../../logger.js";
const toggleModerationSocketHandler = async (data, emit) => {
try {
const currentState = data.state;
const currentOption = await eventCache.get(data.eventId);
- await updateEventById(data.eventId, {moderationOption: currentState});
+ await updateEventById({
+ id: data.eventId,
+ moderationOption: currentState,
+ });
currentOption.moderationOption = currentState;
await eventCache.set(data.eventId, currentOption);
emit({eventId: data.eventId, state: currentState});
} catch (e) {
- console.log(e);
+ logger.error(e);
emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Vote/rateOff.socketHandler.js b/backend/socket_io_server/socketHandler/Vote/rateOff.socketHandler.js
index b67eddf4..b1ab0b2e 100644
--- a/backend/socket_io_server/socketHandler/Vote/rateOff.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Vote/rateOff.socketHandler.js
@@ -1,20 +1,24 @@
import {deleteVoteBy} from "../../../DB/queries/vote";
+import updateVoters from "./updateVoters";
+import logger from "../../logger.js";
const rateOffSocketHandler = async (data, emit) => {
try {
const {GuestId, CandidateId, poll, index} = data;
- console.log("vote/off handler", data);
await deleteVoteBy({GuestId, CandidateId});
+ await updateVoters(poll);
+
emit({
+ status: "ok",
GuestId,
poll,
index,
});
} catch (e) {
- console.error(e);
- emit({status: "error(rate/off)", e});
+ logger.error(e);
+ emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Vote/rateOn.socketHandler.js b/backend/socket_io_server/socketHandler/Vote/rateOn.socketHandler.js
index 4daaa9f7..f4b0fa61 100644
--- a/backend/socket_io_server/socketHandler/Vote/rateOn.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Vote/rateOn.socketHandler.js
@@ -1,4 +1,6 @@
-import {addVote, deleteVoteBy} from "../../../DB/queries/vote";
+import {addVote} from "../../../DB/queries/vote";
+import updateVoters from "./updateVoters";
+import logger from "../../logger.js";
// const data = {
// GuestId: guest.id,
@@ -12,14 +14,17 @@ const rateOnSocketHandler = async (data, emit) => {
await addVote({GuestId, CandidateId});
+ await updateVoters(poll);
+
emit({
+ status: "ok",
GuestId,
poll,
index,
});
} catch (e) {
- console.error(e);
- emit({status: "error(rate/on)", e});
+ logger.error(e);
+ emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Vote/updateVoters.js b/backend/socket_io_server/socketHandler/Vote/updateVoters.js
new file mode 100644
index 00000000..5fcbc0dc
--- /dev/null
+++ b/backend/socket_io_server/socketHandler/Vote/updateVoters.js
@@ -0,0 +1,14 @@
+import {getVotersByCandidateList} from "../../../DB/queries/vote.js";
+
+const getCandidateList = items => items.map(n => n.id);
+
+const updateVoters = async poll => {
+ // DB에서 갱신된 투표인수를 읽어옴
+ for (let candidate of poll.nItems) {
+ candidate.voters = await getVotersByCandidateList([candidate.id]);
+ }
+ const candidateList = getCandidateList(poll.nItems);
+ poll.totalVoters = await getVotersByCandidateList(candidateList);
+};
+
+export default updateVoters;
diff --git a/backend/socket_io_server/socketHandler/Vote/voteOff.socketHandler.js b/backend/socket_io_server/socketHandler/Vote/voteOff.socketHandler.js
index 9277ac5d..aa1160aa 100644
--- a/backend/socket_io_server/socketHandler/Vote/voteOff.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Vote/voteOff.socketHandler.js
@@ -1,18 +1,23 @@
import {deleteVoteBy} from "../../../DB/queries/vote";
+import updateVoters from "./updateVoters";
+import logger from "../../logger.js";
const voteOffSocketHandler = async (data, emit) => {
try {
- const {GuestId, CandidateId, allowDuplication, poll} = data;
+ const {GuestId, CandidateId, poll} = data;
await deleteVoteBy({GuestId, CandidateId});
+ await updateVoters(poll);
+
emit({
+ status: "ok",
GuestId,
poll,
});
} catch (e) {
- console.error(e);
- emit({status: "error(vote/off)", e});
+ logger.error(e);
+ emit({status: "error", e});
}
};
diff --git a/backend/socket_io_server/socketHandler/Vote/voteOn.socketHandler.js b/backend/socket_io_server/socketHandler/Vote/voteOn.socketHandler.js
index 4b123b8c..2f5158e3 100644
--- a/backend/socket_io_server/socketHandler/Vote/voteOn.socketHandler.js
+++ b/backend/socket_io_server/socketHandler/Vote/voteOn.socketHandler.js
@@ -1,11 +1,6 @@
-import {addVote, deleteVoteBy, addAndDelete} from "../../../DB/queries/vote";
-
-// const data = {
-// GuestId: guest.id,
-// CandidateId: vote.candidateId,
-// allowDuplication: poll.allowDuplication,
-// poll: poll,
-// };
+import {addVote, addAndDelete} from "../../../DB/queries/vote";
+import updateVoters from "./updateVoters";
+import logger from "../../logger.js";
const voteOnSocketHandler = async (data, emit) => {
try {
@@ -17,27 +12,22 @@ const voteOnSocketHandler = async (data, emit) => {
candidateToDelete,
} = data;
- // if (!allowDuplication && candidateToDelete) {
- // await addAndDelete(GuestId, CandidateId, candidateToDelete);
- // } else {
- // await addVote({GuestId, CandidateId});
- // }
-
- await addVote({GuestId, CandidateId});
if (!allowDuplication && candidateToDelete) {
- await deleteVoteBy({
- GuestId,
- CandidateId: candidateToDelete,
- });
+ await addAndDelete(GuestId, CandidateId, candidateToDelete);
+ } else {
+ await addVote({GuestId, CandidateId});
}
+ await updateVoters(poll);
+
emit({
+ status: "ok",
GuestId,
poll,
});
} catch (e) {
- console.error(e);
- emit({status: "error(vote/on)", e});
+ logger.error(e);
+ emit({status: "error", e});
}
};
diff --git a/backend/spec/DB/QuestionQuery.test.js b/backend/spec/DB/QuestionQuery.test.js
index 75158f08..37d192cc 100644
--- a/backend/spec/DB/QuestionQuery.test.js
+++ b/backend/spec/DB/QuestionQuery.test.js
@@ -1,4 +1,3 @@
-import {getQuestionLikeCount} from "../../DB/queries/event.js";
import {
createQuestion,
deleteQuestionById,
@@ -45,15 +44,6 @@ describe("questions query api", () => {
// console.log(res.length);
});
- it("should able to get question likeCount", async () => {
- const eventId = 2;
- const res = await getQuestionLikeCount(eventId);
-
- QueryExpectMoreThanOne(res);
- // res = res.map(x => x.get({ plain: true }));
- // console.log(res.slice(0, 2));
- // console.log(res.length);
- });
it("should able to get by event id", async () => {
const eventId = 2;
diff --git a/frontend/guest-app/package.json b/frontend/guest-app/package.json
index 18591eca..9e16093d 100644
--- a/frontend/guest-app/package.json
+++ b/frontend/guest-app/package.json
@@ -53,6 +53,7 @@
"js-cookie": "^2.2.1",
"lodash": "^4.17.15",
"mini-css-extract-plugin": "0.8.0",
+ "moment": "^2.24.0",
"optimize-css-assets-webpack-plugin": "5.0.3",
"pnp-webpack-plugin": "1.5.0",
"postcss-flexbugs-fixes": "4.1.0",
diff --git a/frontend/guest-app/public/android-icon-144x144.png b/frontend/guest-app/public/android-icon-144x144.png
deleted file mode 100644
index b65cbf87..00000000
Binary files a/frontend/guest-app/public/android-icon-144x144.png and /dev/null differ
diff --git a/frontend/guest-app/public/android-icon-192x192.png b/frontend/guest-app/public/android-icon-192x192.png
deleted file mode 100644
index 6f1148bd..00000000
Binary files a/frontend/guest-app/public/android-icon-192x192.png and /dev/null differ
diff --git a/frontend/guest-app/public/android-icon-36x36.png b/frontend/guest-app/public/android-icon-36x36.png
deleted file mode 100644
index fc96f1dd..00000000
Binary files a/frontend/guest-app/public/android-icon-36x36.png and /dev/null differ
diff --git a/frontend/guest-app/public/android-icon-48x48.png b/frontend/guest-app/public/android-icon-48x48.png
deleted file mode 100644
index 5cdde9da..00000000
Binary files a/frontend/guest-app/public/android-icon-48x48.png and /dev/null differ
diff --git a/frontend/guest-app/public/android-icon-72x72.png b/frontend/guest-app/public/android-icon-72x72.png
deleted file mode 100644
index 6c2dcd4a..00000000
Binary files a/frontend/guest-app/public/android-icon-72x72.png and /dev/null differ
diff --git a/frontend/guest-app/public/android-icon-96x96.png b/frontend/guest-app/public/android-icon-96x96.png
deleted file mode 100644
index 0ac97f36..00000000
Binary files a/frontend/guest-app/public/android-icon-96x96.png and /dev/null differ
diff --git a/frontend/guest-app/public/apple-icon.png b/frontend/guest-app/public/apple-icon.png
deleted file mode 100644
index 9d0064a4..00000000
Binary files a/frontend/guest-app/public/apple-icon.png and /dev/null differ
diff --git a/frontend/guest-app/public/favicon-16x16.png b/frontend/guest-app/public/favicon-16x16.png
deleted file mode 100644
index c0db580c..00000000
Binary files a/frontend/guest-app/public/favicon-16x16.png and /dev/null differ
diff --git a/frontend/guest-app/public/favicon-32x32.png b/frontend/guest-app/public/favicon-32x32.png
deleted file mode 100644
index 8b271bda..00000000
Binary files a/frontend/guest-app/public/favicon-32x32.png and /dev/null differ
diff --git a/frontend/guest-app/public/favicon-96x96.png b/frontend/guest-app/public/favicon-96x96.png
deleted file mode 100644
index 0ac97f36..00000000
Binary files a/frontend/guest-app/public/favicon-96x96.png and /dev/null differ
diff --git a/frontend/guest-app/public/logo_vaagle(transparent).png b/frontend/guest-app/public/logo_vaagle(transparent).png
deleted file mode 100644
index 45ec93dc..00000000
Binary files a/frontend/guest-app/public/logo_vaagle(transparent).png and /dev/null differ
diff --git a/frontend/guest-app/public/manifest.json b/frontend/guest-app/public/manifest.json
index b8ac14a7..144fa033 100644
--- a/frontend/guest-app/public/manifest.json
+++ b/frontend/guest-app/public/manifest.json
@@ -6,48 +6,6 @@
"src": "favicon.ico",
"sizes": "96x96 32x32 16x16",
"type": "image/x-icon"
- },
- {
- "src": "\/android-icon-36x36.png",
- "sizes": "36x36",
- "type": "image\/png",
- "density": "0.75"
- },
- {
- "src": "\/android-icon-48x48.png",
- "sizes": "48x48",
- "type": "image\/png",
- "density": "1.0"
- },
- {
- "src": "\/android-icon-72x72.png",
- "sizes": "72x72",
- "type": "image\/png",
- "density": "1.5"
- },
- {
- "src": "\/android-icon-96x96.png",
- "sizes": "96x96",
- "type": "image\/png",
- "density": "2.0"
- },
- {
- "src": "\/android-icon-144x144.png",
- "sizes": "144x144",
- "type": "image\/png",
- "density": "3.0"
- },
- {
- "src": "\/android-icon-192x192.png",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
- },
- {
- "src": "\/android-icon-192x192.png",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
}
],
"start_url": ".",
diff --git a/frontend/guest-app/src/App/App.css b/frontend/guest-app/src/App/App.css
index 57ea2d58..fe065cc8 100644
--- a/frontend/guest-app/src/App/App.css
+++ b/frontend/guest-app/src/App/App.css
@@ -1,3 +1,8 @@
+/*아이폰*/
+*, *::before, *::after{
+ overflow: hidden;
+}
+
.App {
text-align: center;
}
diff --git a/frontend/guest-app/src/App/App.js b/frontend/guest-app/src/App/App.js
index 7e21ec5d..5d03f278 100644
--- a/frontend/guest-app/src/App/App.js
+++ b/frontend/guest-app/src/App/App.js
@@ -1,60 +1,37 @@
import React from "react";
import styled from "styled-components";
-import {useQuery} from "@apollo/react-hooks";
import "./App.css";
-import {GET_GUEST_APP_GLOBAL_DATA} from "../apollo/gqlSchemes.js";
-import TopProgressBar from "../components/TopProcessBar.js";
-import config from "../config";
-import {UIController} from "../components/UIController/UIController.js";
-import {GuestGlobalProvider} from "../libs/guestGlobalContext.js";
import NavBar from "../components/NavBar/NavBar.js";
import TabGroup from "../components/TabGroup/TabGroup.js";
-import {
- createSocketIOClient,
- SocketIoClientProvider,
-} from "../libs/socketIoClientProvider.js";
+import UIControllerProvider from "../contexts/UIController/UIControllerProvider.js";
+import ApolloClientProvider from "../apollo/ApolloClientProvider.js";
+import useGlobalData from "../contexts/GlobalData/useGlobalData.js";
+import GlobalDataProvider from "../contexts/GlobalData/GlobalDataProvider.js";
const AppStyle = styled.div`
height: 100vh;
width: 100vw;
`;
-export default function App() {
- const {data, loading, error} = useQuery(GET_GUEST_APP_GLOBAL_DATA);
-
- if (loading) {
- return ;
- }
-
- if (error) {
- window.location.href = config.inValidGuestRedirectURL;
- return
;
- }
-
- const {event, guest} = data.guestInEvent;
- const client = createSocketIOClient({
- host: config.socketIOHost,
- port: config.socketIOPort,
- namespace: "event",
- room: event.id,
- });
-
- client.on("connect", () => {
- client.emit("joinRoom", {room: event.id});
- });
-
- const globalData = {event, guest};
+const App = () => {
+ const {event} = useGlobalData();
return (
-
-
-
-
-
-
-
-
+
+
+
+
);
-}
+};
+
+const WrappedApp = () => (
+
+
+
+
+
+);
+
+export default WrappedApp;
diff --git a/frontend/guest-app/src/apollo/ApolloClientProvider.js b/frontend/guest-app/src/apollo/ApolloClientProvider.js
new file mode 100644
index 00000000..ce68c1ad
--- /dev/null
+++ b/frontend/guest-app/src/apollo/ApolloClientProvider.js
@@ -0,0 +1,19 @@
+import React from "react";
+import Cookies from "js-cookie";
+import {ApolloProvider} from "@apollo/react-hooks";
+import createApolloClient from "./createApolloClient.js";
+import config from "../config";
+
+const cookieName = "vaagle-guest";
+const token = Cookies.get(cookieName);
+const client = createApolloClient(config.apolloURI, token);
+
+function ApolloClientProvider(props) {
+ return (
+
+ {props.children}
+
+ );
+}
+
+export default ApolloClientProvider;
diff --git a/frontend/guest-app/src/apollo/asembleGetQuestionQuerys.js b/frontend/guest-app/src/apollo/asembleGetQuestionQuerys.js
new file mode 100644
index 00000000..ae0c6c90
--- /dev/null
+++ b/frontend/guest-app/src/apollo/asembleGetQuestionQuerys.js
@@ -0,0 +1,104 @@
+import _ from "lodash";
+
+function mappingByKey(object, key) {
+ const mapped = {};
+
+ object.forEach(x => {
+ mapped[x[key]] = x;
+ });
+
+ return mapped;
+}
+
+function unMappingByKey(object) {
+ return Object.values(object);
+}
+
+function JSONNestJoin(parents, children, parentKey, childKey, func) {
+ const mapped = mappingByKey(parents, parentKey);
+
+ children.forEach(child => {
+ const joinValue = child[childKey];
+
+ if (mapped[joinValue]) {
+ const parentElement = mapped[joinValue];
+
+ mapped[joinValue] = func(parentElement, child);
+ }
+ });
+
+ return unMappingByKey(mapped);
+}
+
+function JSONNestJoin2(parents, children, parentKey, childKey, func) {
+ const mapped = mappingByKey(children, childKey);
+
+ parents.forEach(parent => {
+ const joinValue = parent[parentKey];
+
+ if (mapped[joinValue]) {
+ const childElement = mapped[joinValue];
+
+ // eslint-disable-next-line no-param-reassign
+ parent = func(parent, childElement);
+ }
+ });
+
+ return parents;
+}
+
+function buildQuestions(object) {
+ const copyData = _.cloneDeep(object);
+ const {guests, didILikes} = copyData;
+ let {questions, emojis, emojiPicks} = copyData;
+
+ questions = JSONNestJoin2(questions, guests, "GuestId", "id", (a, b) => {
+ a.guestName = b.name;
+ a.isAnonymous = b.isAnonymous;
+
+ return a;
+ });
+
+ questions = questions.map(x => {
+ x.didILike = false;
+ return x;
+ });
+
+ questions = JSONNestJoin(
+ questions,
+ didILikes,
+ "id",
+ "QuestionId",
+ (x, y) => {
+ x.didILike = true;
+ return x;
+ },
+ );
+
+ emojis = emojis.map(x => {
+ x.key = `${x.QuestionId}_${x.name}`;
+ x.didIPick = false;
+ return x;
+ });
+ emojiPicks = emojiPicks.map(x => {
+ x.key = `${x.QuestionId}_${x.name}`;
+ return x;
+ });
+ emojis = JSONNestJoin(emojis, emojiPicks, "key", "key", (a, b) => {
+ a.didIPick = true;
+ return a;
+ });
+
+ questions.map(x => {
+ x.emojis = [];
+ return x;
+ });
+ questions = JSONNestJoin(questions, emojis, "id", "QuestionId", (a, b) => {
+ a.emojis.push(b);
+ return a;
+ });
+
+ return questions;
+}
+
+export default buildQuestions;
diff --git a/frontend/guest-app/src/libs/createApolloClient.js b/frontend/guest-app/src/apollo/createApolloClient.js
similarity index 68%
rename from frontend/guest-app/src/libs/createApolloClient.js
rename to frontend/guest-app/src/apollo/createApolloClient.js
index 92ec4d3a..21e23446 100644
--- a/frontend/guest-app/src/libs/createApolloClient.js
+++ b/frontend/guest-app/src/apollo/createApolloClient.js
@@ -3,17 +3,16 @@ import {createHttpLink} from "apollo-link-http";
import {InMemoryCache} from "apollo-cache-inmemory";
import {setContext} from "apollo-link-context";
-export default function creaetApolloClient(uri, token) {
+export default function createApolloClient(uri, token) {
const httpLink = createHttpLink({uri});
+
if (token) {
- const authLink = setContext((_, {headers}) => {
- return {
- headers: {
- ...headers,
- authorization: `Bearer ${token}`,
- },
- };
- });
+ const authLink = setContext((_, {headers}) => ({
+ headers: {
+ ...headers,
+ authorization: `Bearer ${token}`,
+ },
+ }));
return new ApolloClient({
link: authLink.concat(httpLink),
diff --git a/frontend/guest-app/src/apollo/gqlSchemes.js b/frontend/guest-app/src/apollo/gqlSchemes.js
index d56296b9..6837f00a 100644
--- a/frontend/guest-app/src/apollo/gqlSchemes.js
+++ b/frontend/guest-app/src/apollo/gqlSchemes.js
@@ -1,22 +1,81 @@
import {gql} from "apollo-boost";
export const GET_GUEST_APP_GLOBAL_DATA = gql`
- query {
- guestInEvent {
- event {
- id
- eventCode
- startAt
- endAt
- eventName
- HostId
- }
- guest {
- id
- name
- email
- company
- }
- }
- }
+ query {
+ guestInEvent {
+ event {
+ id
+ eventCode
+ startAt
+ endAt
+ eventName
+ HostId
+ }
+ guest {
+ id
+ name
+ email
+ company
+ }
+ }
+ }
+`;
+
+export const QUERY_INIT_QUESTIONS = gql`
+ query getQuestions($EventId: ID!, $GuestId: ID!) {
+ questions(EventId: $EventId) {
+ id
+ EventId
+ GuestId
+ createdAt
+ content
+ state
+ isStared
+ likeCount
+ QuestionId
+ }
+ emojis(EventId: $EventId) {
+ name
+ count
+ QuestionId
+ createdAt
+ }
+ emojiPicks(EventId: $EventId, GuestId: $GuestId) {
+ name
+ QuestionId
+ }
+ guests(EventId: $EventId) {
+ id
+ name
+ isAnonymous
+ }
+ didILikes(GuestId: $GuestId) {
+ QuestionId
+ }
+ }
+`;
+
+export const POLL_QUERY = gql`
+ query PollGuest($EventId: ID!, $guestId: ID!) {
+ pollGuest(EventId: $EventId, guestId: $guestId) {
+ id
+ pollName
+ pollType
+ selectionType
+ allowDuplication
+ state
+ totalVoters
+ pollDate
+ rated
+ ratingValue
+ nItems {
+ id
+ number
+ content
+ voters
+ voted
+ firstPlace
+ }
+ }
+ }
`;
diff --git a/frontend/guest-app/src/components/Emoji/EmojiPickerModal.js b/frontend/guest-app/src/components/Emoji/EmojiPickerModal.js
deleted file mode 100644
index 85b7045f..00000000
--- a/frontend/guest-app/src/components/Emoji/EmojiPickerModal.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from "react";
-import {Modal} from "@material-ui/core";
-import "emoji-mart/css/emoji-mart.css";
-import {Picker} from "emoji-mart";
-import customEmojis from "./CustomEmojis";
-
-function EmojiPickerModal({onClose, onSelect}) {
- return (
-
-
-
- );
-}
-
-export default EmojiPickerModal;
diff --git a/frontend/guest-app/src/components/Emoji/CustomEmojis.js b/frontend/guest-app/src/components/EmojiArea/CustomEmojis.js
similarity index 100%
rename from frontend/guest-app/src/components/Emoji/CustomEmojis.js
rename to frontend/guest-app/src/components/EmojiArea/CustomEmojis.js
diff --git a/frontend/guest-app/src/components/Emoji/EmojiArea.js b/frontend/guest-app/src/components/EmojiArea/EmojiArea.js
similarity index 64%
rename from frontend/guest-app/src/components/Emoji/EmojiArea.js
rename to frontend/guest-app/src/components/EmojiArea/EmojiArea.js
index 67208d11..c7a1d77d 100644
--- a/frontend/guest-app/src/components/Emoji/EmojiArea.js
+++ b/frontend/guest-app/src/components/EmojiArea/EmojiArea.js
@@ -1,12 +1,11 @@
-import React, {useContext} from "react";
+import React from "react";
import styled from "styled-components";
-import IconButton from "@material-ui/core/IconButton";
-import InsertEmoticonOutlinedIcon from "@material-ui/icons/InsertEmoticonOutlined";
-import EmojiInstance from "./EmojiInstance";
+import EmojiBadge from "./EmojiBadge.js";
import EmojiPickerModal from "./EmojiPickerModal";
import useCommonModal from "../CommonComponent/CommonModal/useCommonModal";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
+import {socketClient} from "../../socket.io";
+import EmojiInsertButton from "./EmojiInsertButton.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
const RowWrapper = styled.div`
display: flex;
@@ -22,16 +21,6 @@ const RowWrapper = styled.div`
}
`;
-function EmojiInsertButton(props) {
- const {onClick} = props;
-
- return (
-
-
-
- );
-}
-
const unPickEmoji = (emojis, name, guestGlobal, QuestionId) => {
const {event, guest} = guestGlobal;
@@ -70,15 +59,19 @@ const pickEmoji = (emojis, name, guestGlobal, QuestionId) => {
});
};
+function isIncludeSameEmoji(emojis, name) {
+ return emojis.filter(x => x.name === name).length > 0;
+}
+
function EmojiArea(props) {
const {emojis, id: QuestionId} = props;
- const guestGlobal = useContext(GuestGlobalContext);
+ const guestGlobal = useGlobalData();
const emojiPickerModal = useCommonModal();
const onEmojiInstanceClick = (name, didIPick) => {
- didIPick ?
- unPickEmoji(emojis, name, guestGlobal, QuestionId) :
- pickEmoji(emojis, name, guestGlobal, QuestionId);
+ didIPick
+ ? unPickEmoji(emojis, name, guestGlobal, QuestionId)
+ : pickEmoji(emojis, name, guestGlobal, QuestionId);
};
const onSelectOfEmojiPicker = value => {
@@ -91,7 +84,7 @@ function EmojiArea(props) {
EventId: event.id,
};
- if (emojis.filter(x => x.name === name).length) {
+ if (isIncludeSameEmoji(emojis, name)) {
return;
}
@@ -102,15 +95,18 @@ function EmojiArea(props) {
return (
{emojis.map((emj, index) => (
-
+
))}
- {emojiPickerModal.isOpened && (
-
- )}
+
);
}
diff --git a/frontend/guest-app/src/components/Emoji/EmojiInstance.js b/frontend/guest-app/src/components/EmojiArea/EmojiBadge.js
similarity index 92%
rename from frontend/guest-app/src/components/Emoji/EmojiInstance.js
rename to frontend/guest-app/src/components/EmojiArea/EmojiBadge.js
index e9fb023c..da16f378 100644
--- a/frontend/guest-app/src/components/Emoji/EmojiInstance.js
+++ b/frontend/guest-app/src/components/EmojiArea/EmojiBadge.js
@@ -24,7 +24,7 @@ const EmojiInstanceStyle = styled.div`
}
`;
-function EmojiInstance(props) {
+function EmojiBadge(props) {
const {name, count, didIPick, onClick} = props;
return (
@@ -35,4 +35,4 @@ function EmojiInstance(props) {
);
}
-export default EmojiInstance;
+export default EmojiBadge;
diff --git a/frontend/guest-app/src/components/EmojiArea/EmojiInsertButton.js b/frontend/guest-app/src/components/EmojiArea/EmojiInsertButton.js
new file mode 100644
index 00000000..e33b18a4
--- /dev/null
+++ b/frontend/guest-app/src/components/EmojiArea/EmojiInsertButton.js
@@ -0,0 +1,15 @@
+import IconButton from "@material-ui/core/IconButton";
+import InsertEmoticonOutlinedIcon from "@material-ui/icons/InsertEmoticonOutlined.js";
+import React from "react";
+
+function EmojiInsertButton(props) {
+ const {onClick} = props;
+
+ return (
+
+
+
+ );
+}
+
+export default EmojiInsertButton;
diff --git a/frontend/guest-app/src/components/EmojiArea/EmojiPickerModal.js b/frontend/guest-app/src/components/EmojiArea/EmojiPickerModal.js
new file mode 100644
index 00000000..9a78d7eb
--- /dev/null
+++ b/frontend/guest-app/src/components/EmojiArea/EmojiPickerModal.js
@@ -0,0 +1,19 @@
+import React from "react";
+import {Modal} from "@material-ui/core";
+import "emoji-mart/css/emoji-mart.css";
+import {Picker} from "emoji-mart";
+import customEmojis from "./CustomEmojis";
+
+function EmojiPickerModal({open, onClose, onSelect}) {
+ return
+
+ ;
+}
+
+
+export default EmojiPickerModal;
diff --git a/frontend/guest-app/src/components/ErrorPage/ErrorPage.js b/frontend/guest-app/src/components/ErrorPage/ErrorPage.js
deleted file mode 100644
index 057df528..00000000
--- a/frontend/guest-app/src/components/ErrorPage/ErrorPage.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from "react";
-
-export default function ErrorPage() {
- return (
-
-
-
- );
-}
diff --git a/frontend/guest-app/src/components/LikeButton/LikeButton.js b/frontend/guest-app/src/components/LikeButton/LikeButton.js
index c4b70fd1..4cef254d 100644
--- a/frontend/guest-app/src/components/LikeButton/LikeButton.js
+++ b/frontend/guest-app/src/components/LikeButton/LikeButton.js
@@ -1,10 +1,10 @@
-import React, {useContext} from "react";
+import React from "react";
import Button from "@material-ui/core/Button";
import ThumbUpIcon from "@material-ui/icons/ThumbUp";
import useCommonModal from "../CommonComponent/CommonModal/useCommonModal.js";
-import UndoLikeConfirmModal from "./UndoLikeModal.js";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
+import UndoLikeConfirmModal from "./LikeUndoModal.js";
+import {socketClient} from "../../socket.io";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
function LikeButtonAtom({isLikeClicked, onLikeButtonClicked, likeCount}) {
return (
@@ -18,7 +18,7 @@ function LikeButtonAtom({isLikeClicked, onLikeButtonClicked, likeCount}) {
justifyContent: "space-between",
}}
>
-
+
{likeCount}
);
@@ -40,7 +40,7 @@ function emitQuestionLikeRemove(GuestId, QuestionId) {
function LikeButton(props) {
const {likeCount, didILike, id} = props;
- const {guest} = useContext(GuestGlobalContext);
+ const {guest} = useGlobalData();
const modalState = useCommonModal();
const onLikeButtonClicked = () => {
if (didILike) {
diff --git a/frontend/guest-app/src/components/LikeButton/UndoLikeModal.js b/frontend/guest-app/src/components/LikeButton/LikeUndoModal.js
similarity index 73%
rename from frontend/guest-app/src/components/LikeButton/UndoLikeModal.js
rename to frontend/guest-app/src/components/LikeButton/LikeUndoModal.js
index da45d4d5..4b82e82f 100644
--- a/frontend/guest-app/src/components/LikeButton/UndoLikeModal.js
+++ b/frontend/guest-app/src/components/LikeButton/LikeUndoModal.js
@@ -3,14 +3,14 @@ import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import {Box} from "@material-ui/core";
import CommonModal from "../CommonComponent/CommonModal/CommonModal.js";
-import ConfirmButton from "../CommonComponent/CommonButtons/ConfirmButton.js";
-import CancelButton from "../CommonComponent/CommonButtons/CancelButton.js";
+import ConfirmButton from "../atoms/ConfirmButton.js";
+import CancelButton from "../atoms/CancelButton.js";
function UndoLikeConfirmModal({isOpened, onCancelClick, onConfirmClick}) {
return (
- 좋아하기를 취소하기겠습니까?
+ 좋아하기를 취소하시겠습니까?
diff --git a/frontend/guest-app/src/components/LikeButton/useLikeButton.js b/frontend/guest-app/src/components/LikeButton/useLikeButton.js
deleted file mode 100644
index 38f9486d..00000000
--- a/frontend/guest-app/src/components/LikeButton/useLikeButton.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import {useState} from "react";
-
-function useLikeButton(initialState = {isLikeClicked: false, likeCount: 0}) {
- const [likeState, setLikeState] = useState(initialState);
-
- const onLike = () =>
- setLikeState({likeCount: likeState.likeCount + 1, isLikeClicked: true});
-
- const onUndoLike = () =>
- setLikeState({
- likeCount: likeState.likeCount - 1,
- isLikeClicked: false,
- });
-
- return {...likeState, onLike, onUndoLike};
-}
-
-export default useLikeButton;
diff --git a/frontend/guest-app/src/components/Modals/EditProfileModal.js b/frontend/guest-app/src/components/Modals/EditProfileModal.js
deleted file mode 100644
index 4fadf58e..00000000
--- a/frontend/guest-app/src/components/Modals/EditProfileModal.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from "react";
-import {Grid, Typography} from "@material-ui/core";
-import Button from "@material-ui/core/Button";
-import BusinessIcon from "@material-ui/icons/Business";
-import EmailIcon from "@material-ui/icons/Email";
-import PersonIcon from "@material-ui/icons/Person";
-import UserAvatar from "../UserAvatar/UserAvatar.js";
-import CommonModal from "../CommonComponent/CommonModal/CommonModal.js";
-import CommonTextInput from "../CommonComponent/CommonTextInput/CommonTextInput.js";
-import useCommonTextInput from "../CommonComponent/CommonTextInput/useCommonTextInput.js";
-import useStringState from "../UserAvatar/useStringState.js";
-
-function UserNameInput() {
- const {state, setState} = useStringState();
-
- const onUserNameChange = e => {
- setState(e.target.value);
- };
-
- return (
-
-
-
- }
- label={"이름"}
- value={state}
- onChange={onUserNameChange}
- />
-
- );
-}
-
-function CompanyInput({company = ""}) {
- const textInputState = useCommonTextInput(company);
-
- return (
- }
- label={"회사"}
- value={textInputState.value}
- onChange={textInputState.onChange}
- />
- );
-}
-
-function EmailInput({email = ""}) {
- const textInputState = useCommonTextInput(email);
-
- return (
- }
- label={"이메일"}
- value={textInputState.value}
- onChange={textInputState.onChange}
- />
- );
-}
-
-function SaveButton({onSave}) {
- return (
-
- );
-}
-
-function EditProfileModal({isOpened = false, onCancelClick, onSave}) {
- return (
-
-
- 내 프로필 변경
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default EditProfileModal;
diff --git a/frontend/guest-app/src/components/Modals/MyQuestionModal.js b/frontend/guest-app/src/components/Modals/MyQuestionModal.js
deleted file mode 100644
index 87fc8c93..00000000
--- a/frontend/guest-app/src/components/Modals/MyQuestionModal.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React, {useState} from "react";
-import PropTypes from "prop-types";
-import {Scrollbars} from "react-custom-scrollbars";
-import {Typography} from "@material-ui/core";
-import CommonModal from "../CommonComponent/CommonModal/CommonModal.js";
-import DummyData from "../Question/QuestionDummyData.js";
-import QuestionCardList from "../Question/QuestionCard/QuestionCardList.js";
-
-function MyQuestionModal(props) {
- const {isOpened, onCancelClick} = props;
- const [datas] = useState({questions: DummyData()});
-
- return (
-
- 내 질문들
-
-
-
-
- );
-}
-
-MyQuestionModal.propTypes = {
- isOpened: PropTypes.bool,
- onCancel: PropTypes.func,
-};
-
-MyQuestionModal.defualtProps = {
- isOpened: false,
- onCancel: undefined,
-};
-
-export default MyQuestionModal;
diff --git a/frontend/guest-app/src/components/Poll/ActiveRating.js b/frontend/guest-app/src/components/Poll/ActiveRating.js
index 6deda330..143ef141 100644
--- a/frontend/guest-app/src/components/Poll/ActiveRating.js
+++ b/frontend/guest-app/src/components/Poll/ActiveRating.js
@@ -37,13 +37,14 @@ function ActiveRating({
onCancelRating,
}) {
return (
-
+
{!rated && "별 갯수로 평가해주세요"}
{rated && `투표했음: ${ratingValue}점`}
- (props.firstPlace ? "yellow" : "#868e96")}; /* Gray6 */
+ (props.firstPlace ? "yellow" : "#adb5bd")}; /* Gray5 */
height: 100%;
width: ${props => props.ratio};
box-sizing: border-box;
diff --git a/frontend/guest-app/src/components/Poll/PollApollo.js b/frontend/guest-app/src/components/Poll/PollApollo.js
deleted file mode 100644
index 7f3f4093..00000000
--- a/frontend/guest-app/src/components/Poll/PollApollo.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React, {useContext} from "react";
-import {useQuery} from "@apollo/react-hooks";
-import {gql} from "apollo-boost";
-import PollContainer from "./PollContainer";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
-
-const POLL_QUERY = gql`
- query PollGuest($EventId: ID!, $guestId: ID!) {
- pollGuest(EventId: $EventId, guestId: $guestId) {
- id
- pollName
- pollType
- selectionType
- allowDuplication
- state
- totalVoters
- pollDate
- rated
- ratingValue
- nItems {
- id
- number
- content
- voters
- voted
- firstPlace
- }
- }
- }
-`;
-
-function PollApollo() {
- const {event, guest} = useContext(GuestGlobalContext);
- const options = {
- variables: {
- EventId: event.id,
- guestId: guest.id,
- },
- };
- const {loading, error, data} = useQuery(POLL_QUERY, options);
-
- if (loading) return Loading...
;
- if (error) return Error :(
;
-
- return ;
-}
-
-export default PollApollo;
diff --git a/frontend/guest-app/src/components/Poll/PollCard.js b/frontend/guest-app/src/components/Poll/PollCard.js
index 9ada20b6..1aa1d185 100644
--- a/frontend/guest-app/src/components/Poll/PollCard.js
+++ b/frontend/guest-app/src/components/Poll/PollCard.js
@@ -10,12 +10,10 @@ const ColumnWrapper = styled.div`
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
- border: 1px solid #adb5bd; /* Gray5 */
- // box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.25);
+ border: 1px solid #dee2e6; /* Gray3 */
width: 100%;
- & + & {
- margin-top: 1rem;
- }
+ margin-top: 1rem;
+ background-color: white;
`;
const RowWrapper = styled.div`
@@ -50,13 +48,14 @@ function PollCard(props) {
} = props;
let localePollDate;
+
// socket.io, sequelize, graphQL 을 거치면서 format이 변경되어서 그때그때 처리하기 위함
if (pollDate) {
localePollDate = pollDate;
if (localePollDate.includes("-")) {
localePollDate = new Date(localePollDate);
} else {
- localePollDate = new Date(parseInt(localePollDate));
+ localePollDate = new Date(parseInt(localePollDate, 10));
}
localePollDate = `
${localePollDate.getMonth() + 1}월
@@ -89,7 +88,7 @@ function PollCard(props) {
{pollType === "rating" && }
- {`${parseInt(totalVoters).toLocaleString()} 명 참여`}
+ {`${parseInt(totalVoters, 10).toLocaleString()} 명 참여`}
);
diff --git a/frontend/guest-app/src/components/Poll/PollContainer.js b/frontend/guest-app/src/components/Poll/PollContainer.js
index 57faa5f7..2d970415 100644
--- a/frontend/guest-app/src/components/Poll/PollContainer.js
+++ b/frontend/guest-app/src/components/Poll/PollContainer.js
@@ -1,8 +1,10 @@
import React, {useReducer, useState} from "react";
import styled from "styled-components";
import PollCard from "./PollCard";
-import {useSocket} from "../../libs/socketIoClientProvider.js";
-import reducer from "./PollReducer";
+import {useSocket} from "../../socket.io";
+import reducer from "../../reducers/PollsReducer.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
+import usePolls from "../../contexts/Polls/usePolls.js";
const ColumnWrapper = styled.div`
display: flex;
@@ -15,152 +17,164 @@ const ColumnWrapper = styled.div`
width: 100%;
`;
-function PollContainer({data, GuestId}) {
- let activePollData = null;
- let clPollData = null;
+function PollContainer() {
+ const {guest} = useGlobalData();
+ const GuestId = guest.id;
+
+ const {pollGuest} = usePolls();
+ const data = pollGuest;
+
+ let rPolls = null;
+ let cPolls = null;
if (data) {
- const initialPollData = data;
+ const initialPolls = data;
- activePollData = initialPollData.filter(
- poll => poll.state === "running",
- );
- clPollData = initialPollData.filter(poll => poll.state === "closed");
+ rPolls = initialPolls.filter(poll => poll.state === "running");
+ cPolls = initialPolls.filter(poll => poll.state === "closed");
}
- const [pollData, dispatch] = useReducer(reducer, activePollData);
- const [closedPollData, setClosedPollData] = useState(clPollData);
+ const [runningPolls, dispatch] = useReducer(reducer, rPolls);
+ const [closedPolls, setClosedPolls] = useState(cPolls);
+ // guest가 N지선다형 투표를 했을때 호출되는 handler
const onVote = (id, candidateId, number, state) => {
if (state !== "running") return;
dispatch({
type: "VOTE",
- id,
+ pollId: id,
candidateId,
number,
GuestId,
});
};
+ // guest가 별점매기기 투표를 했을때 호출되는 handler
const onChange = (value, state, id) => {
if (state !== "running") return;
dispatch({
type: "RATE",
value,
- id,
+ pollId: id,
GuestId,
});
};
+ // guest가 별점매기기 투표를 취소했을때 호출되는 handler
const onCancelRating = (id, state) => {
if (state !== "running") return;
dispatch({
type: "CANCEL_RATING",
- id,
+ pollId: id,
GuestId,
});
};
- useSocket("poll/notify_open", thePoll => {
- if (thePoll.error) {
+ // host가 투표를 open했음을 guest들에게 socket.io 서버로 emit 하면
+ // guest들은 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
+ useSocket("poll/notify_open", res => {
+ if (res.status === "error") {
return;
}
- // console.log("Guest received poll/notify_open", thePoll);
+
dispatch({
type: "NOTIFY_OPEN",
- poll: thePoll,
+ poll: res.poll,
GuestId,
});
});
- useSocket("poll/notify_close", id => {
- if (id.error) {
+ // host가 투표를 close했음을 guest들에게 socket.io 서버로 emit 하면
+ // guest들은 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
+ useSocket("poll/notify_close", res => {
+ if (res.status === "error") {
return;
}
- // console.log("Guest received poll/notify_close", id);
- const thePoll = pollData.filter(poll => poll.id === id)[0];
+
+ const {pollId} = res;
+ const thePoll = {...runningPolls.find(poll => poll.id === pollId)};
thePoll.state = "closed";
- setClosedPollData([thePoll].concat(closedPollData));
+ setClosedPolls([thePoll].concat(closedPolls));
dispatch({
type: "NOTIFY_CLOSE",
- id,
+ pollId,
});
});
+ // 다른 guest들이 투표했음을 socket.io 서버로 emit 하면
+ // guest는 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
useSocket("vote/on", res => {
- if (res.error) {
+ if (res.status === "error") {
+ // eslint-disable-next-line no-console
+ console.error("vote/on ERROR");
return;
}
// 하나의 브라우저에서 여러개의 tab으로 guest들을 생성한 경우,
// 해당 guest를 제외한 나머지 guest에 상태가 적용되지 않아서 comment 처리했음
- // console.log("useSocket vote/on", res);
- // if (res.GuestId === GuestId) {
- // console.log("My vote!");
- // // return;
- // }
dispatch({
type: "SOMEONE_VOTE",
- id: res.poll.id,
+ pollId: res.poll.id,
poll: res.poll,
GuestId,
});
});
+ // 다른 guest들이 투표했음을 socket.io 서버로 emit 하면
+ // guest는 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
useSocket("vote/off", res => {
- if (res.error) {
+ if (res.status === "error") {
+ // eslint-disable-next-line no-console
+ console.error("vote/off ERROR");
return;
}
// 하나의 브라우저에서 여러개의 tab으로 guest들을 생성한 경우,
// 해당 guest를 제외한 나머지 guest에 상태가 적용되지 않아서 comment 처리했음
- // if (res.GuestId === GuestId) {
- // console.log("My vote!");
- // // return;
- // }
dispatch({
type: "SOMEONE_VOTE",
- id: res.poll.id,
+ pollId: res.poll.id,
poll: res.poll,
GuestId,
});
});
+ // 다른 guest들이 별점매기기 했음을 socket.io 서버로 emit 하면
+ // guest는 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
useSocket("rate/on", res => {
- if (res.error) {
+ if (res.status === "error") {
return;
}
// 하나의 브라우저에서 여러개의 tab으로 guest들을 생성한 경우,
// 해당 guest를 제외한 나머지 guest에 상태가 적용되지 않아서 comment 처리했음
- // console.log("useSocket vote/on", res);
- // if (res.GuestId === GuestId) {
- // console.log("My rate!");
- // // return;
- // }
dispatch({
type: "SOMEONE_RATE",
- id: res.poll.id,
+ pollId: res.poll.id,
poll: res.poll,
GuestId,
});
});
+ // 다른 guest들이 별점매기기를 취소했음을 socket.io 서버로 emit 하면
+ // guest는 아래 함수를 통해 listen하고 있다가
+ // useReduer를 호출하여 투표에 상태를 update 함
useSocket("rate/off", res => {
- if (res.error) {
+ if (res.status === "error") {
return;
}
// 하나의 브라우저에서 여러개의 tab으로 guest들을 생성한 경우,
// 해당 guest를 제외한 나머지 guest에 상태가 적용되지 않아서 comment 처리했음
- // if (res.GuestId === GuestId) {
- // console.log("My rate!");
- // // return;
- // }
dispatch({
type: "SOMEONE_RATE",
- id: res.poll.id,
+ pollId: res.poll.id,
poll: res.poll,
GuestId,
});
@@ -168,8 +182,8 @@ function PollContainer({data, GuestId}) {
return (
- {pollData &&
- pollData.map(poll => (
+ {runningPolls &&
+ runningPolls.map(poll => (
))}
- {closedPollData &&
- closedPollData.map(poll => (
+ {closedPolls &&
+ closedPolls.map(poll => (
))}
diff --git a/frontend/guest-app/src/components/Poll/PollDummyData.js b/frontend/guest-app/src/components/Poll/PollDummyData.js
deleted file mode 100644
index 2f7c59db..00000000
--- a/frontend/guest-app/src/components/Poll/PollDummyData.js
+++ /dev/null
@@ -1,85 +0,0 @@
-export default function PollDummyData() {
- return [
- {
- pollName: "2019년 송년회 일자 투표",
- pollType: "nItems",
- selectionType: "date",
- allowDuplication: true,
- nItems: [
- {
- id: 0,
- name: "12월 19일(목)",
- voters: 55,
- voted: true,
- firstPlace: false,
- }, {
- id: 1,
- name: "12월 20일(금)",
- voters: 77,
- voted: true,
- firstPlace: true,
- }, {
- id: 2,
- name: "12월 21일(토)",
- voters: 33,
- voted: false,
- firstPlace: false,
- }, {
- id: 3,
- name: "12월 22일(일)",
- voters: 22,
- voted: false,
- firstPlace: false,
- },
- ],
- pollDate: new Date(),
- active: true,
- totalVoters: 99,
- }, {
- pollName: "대한민국 수도는 어디인가요?",
- pollType: "nItems",
- selectionType: "text",
- allowDuplication: false,
- nItems: [
- {
- id: 0,
- name: "부산",
- voters: 11,
- voted: false,
- firstPlace: false,
- }, {
- id: 1,
- name: "제주",
- voters: 22,
- voted: false,
- firstPlace: false,
- }, {
- id: 2,
- name: "서울",
- voters: 999,
- voted: true,
- firstPlace: true,
- },
- ],
- pollDate: new Date(),
- active: false,
- totalVoters: 1032,
- }, {
- pollName: "마스터 강의 평가",
- pollType: "rating",
- allowDuplication: false,
- nItems: [
- {
- id: 0,
- voters: 80,
- voted: false,
- maxStars: 10,
- value: 0,
- },
- ],
- pollDate: new Date(),
- active: false,
- totalVoters: 80,
- },
- ];
-}
diff --git a/frontend/guest-app/src/components/Poll/RatingItem.js b/frontend/guest-app/src/components/Poll/RatingItem.js
index 4d741b8c..a0ea2cd2 100644
--- a/frontend/guest-app/src/components/Poll/RatingItem.js
+++ b/frontend/guest-app/src/components/Poll/RatingItem.js
@@ -31,7 +31,7 @@ function RatingItem({
id={id}
rated={rated}
ratingValue={ratingValue}
- max={parseInt(selectionType)}
+ max={parseInt(selectionType, 10)}
state={state}
onChange={onChange}
onCancelRating={onCancelRating}
@@ -44,7 +44,7 @@ function RatingItem({
>
)}
diff --git a/frontend/guest-app/src/components/Question/QuestionDummyData.js b/frontend/guest-app/src/components/Question/QuestionDummyData.js
deleted file mode 100644
index bcf4bfa8..00000000
--- a/frontend/guest-app/src/components/Question/QuestionDummyData.js
+++ /dev/null
@@ -1,96 +0,0 @@
-function DummyData() {
- return [
- {
- userName: "오랑캐1",
- date: new Date(),
- content: "content",
- isAnonymous: false,
- isShowEditButton: true,
- isLike: false,
- likeCount: 10,
- }, {
- userName: "오랑캐2",
- date: new Date(),
- content: "long content",
- isAnonymous: false,
- isShowEditButton: false,
- isLike: true,
- likeCount: 11,
- }, {
- userName: "오랑캐3",
- date: new Date(),
- content:
- "long content long content long content long content long contentlong contentlong content long contentlong content",
- isAnonymous: false,
- isShowEditButton: true,
- isLike: false,
- likeCount: 100,
- }, {
- userName: "오랑캐3",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 12,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 1,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: true,
- isLike: false,
- likeCount: 0,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 1,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 53,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 10,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 4,
- }, {
- userName: "Anonymous",
- date: new Date(),
- content: "content",
- isAnonymous: true,
- isShowEditButton: false,
- isLike: false,
- likeCount: 10,
- },
- ];
-}
-
-export default DummyData;
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/UserInfoInput.js b/frontend/guest-app/src/components/Question/QuestionInputArea/UserInfoInput.js
deleted file mode 100644
index f4760a21..00000000
--- a/frontend/guest-app/src/components/Question/QuestionInputArea/UserInfoInput.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import PropTypes from "prop-types";
-import React from "react";
-import useStringState from "../../UserAvatar/useStringState.js";
-import UserAvatar from "../../UserAvatar/UserAvatar.js";
-import QuestionUserNameInput from "./QuestionUserNameInput.js";
-
-function UserInfoInput(props) {
- const {userNameRef, initialUserName = ""} = props;
- const {state, setState} = useStringState(initialUserName);
-
- const onUserNameChange = e => {
- setState(e.target.value);
- };
-
- return (
- <>
-
-
- >
- );
-}
-
-UserInfoInput.propTypes = {
- userNameRef: PropTypes.any,
-};
-
-export default UserInfoInput;
diff --git a/frontend/guest-app/src/components/Question/ToggleReducer.js b/frontend/guest-app/src/components/Question/ToggleReducer.js
deleted file mode 100644
index 0a45541e..00000000
--- a/frontend/guest-app/src/components/Question/ToggleReducer.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import _ from "lodash";
-
-const ToggleReducer = (state, action) => {
- const {type, data} = action;
-
- const actionTable = {
- toggle: (state, data) => {
- const newState = _.cloneDeep(state);
-
- newState.data = _.cloneDeep(data);
- newState.state = !newState.state;
-
- return newState;
- },
- on: (state, data) => {
- const newState = _.cloneDeep(state);
-
- newState.data = _.cloneDeep(data);
- newState.state = true;
-
- return newState;
- },
- off: (state, data) => {
- const newState = _.cloneDeep(state);
-
- newState.data = _.cloneDeep(data);
- newState.state = false;
-
- return newState;
- },
- };
-
- if (!(type in actionTable)) {
- console.error(`unexpected action.type: ${type}`);
- return state;
- }
-
- return actionTable[type](state, data);
-};
-
-export default ToggleReducer;
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCard.js b/frontend/guest-app/src/components/QuestionCard/QuestionCard.js
similarity index 84%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCard.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCard.js
index 4b4e1c93..ba89d74c 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCard.js
+++ b/frontend/guest-app/src/components/QuestionCard/QuestionCard.js
@@ -4,8 +4,8 @@ import {CardContent} from "@material-ui/core";
import Divider from "@material-ui/core/Divider";
import QuestionHeader from "./QuestionCardHeader.js";
import QuestionBody from "./QuestionCardBody.js";
-import EmojiArea from "../../Emoji/EmojiArea.js";
-import ReplyArea from "../../Reply/ReplyArea";
+import EmojiArea from "../EmojiArea/EmojiArea.js";
+import ReplyPreviewArea from "../ReplyPreviewArea/ReplyPreviewArea.js";
const cardColor = {
focused: "rgb(242,248,255)",
@@ -24,7 +24,7 @@ const QuestionCard = React.memo(props => {
/>
-
+
);
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardBody.js b/frontend/guest-app/src/components/QuestionCard/QuestionCardBody.js
similarity index 55%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCardBody.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCardBody.js
index c52f7ba2..d829075b 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardBody.js
+++ b/frontend/guest-app/src/components/QuestionCard/QuestionCardBody.js
@@ -1,18 +1,21 @@
-import React, {useContext} from "react";
+import React from "react";
import PropTypes from "prop-types";
+import Typography from "@material-ui/core/Typography";
import QuestionEditButton from "./QuestionCardEditButton.js";
-import {GuestGlobalContext} from "../../../libs/guestGlobalContext.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
function QuestionBody(props) {
- const {guest} = useContext(GuestGlobalContext);
+ const {guest} = useGlobalData();
const {content, GuestId} = props;
const isMyQuestion = guest.id === GuestId;
return (
- {content}
- {isMyQuestion && }
+
+ {content}
+ {isMyQuestion && }
+
);
}
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardEditButton.js b/frontend/guest-app/src/components/QuestionCard/QuestionCardEditButton.js
similarity index 83%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCardEditButton.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCardEditButton.js
index 40661528..1254389f 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardEditButton.js
+++ b/frontend/guest-app/src/components/QuestionCard/QuestionCardEditButton.js
@@ -2,7 +2,7 @@ import React from "react";
import styled from "styled-components";
import {Typography} from "@material-ui/core";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz.js";
-import {useUIControllerContext} from "../../UIController/UIController.js";
+import useUIController from "../../contexts/UIController/useUIController.js";
const QuestionEditButtonStyle = styled.div`
float: right;
@@ -12,7 +12,7 @@ const QuestionEditButtonStyle = styled.div`
function QuestionEditButton(props) {
const question = props;
- const {questionEditMenuReducer} = useUIControllerContext();
+ const {questionEditMenuReducer} = useUIController();
return (
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardHeader.js b/frontend/guest-app/src/components/QuestionCard/QuestionCardHeader.js
similarity index 88%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCardHeader.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCardHeader.js
index 96a6372c..fcf35cb4 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardHeader.js
+++ b/frontend/guest-app/src/components/QuestionCard/QuestionCardHeader.js
@@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import Grid from "@material-ui/core/Grid";
-import UserAvatar from "../../UserAvatar/UserAvatar.js";
-import LikeButton from "../../LikeButton/LikeButton.js";
+import UserAvatar from "../UserAvatar/UserAvatar.js";
+import LikeButton from "../LikeButton/LikeButton.js";
import QuestionCardDate from "./QuestionsCardDate.js";
import QuestionUserName from "./QuestionCardUserName.js";
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardList.js b/frontend/guest-app/src/components/QuestionCard/QuestionCardList.js
similarity index 100%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCardList.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCardList.js
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionCardUserName.js b/frontend/guest-app/src/components/QuestionCard/QuestionCardUserName.js
similarity index 100%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionCardUserName.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionCardUserName.js
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionsCardDate.js b/frontend/guest-app/src/components/QuestionCard/QuestionsCardDate.js
similarity index 100%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionsCardDate.js
rename to frontend/guest-app/src/components/QuestionCard/QuestionsCardDate.js
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardModal.js b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardDeleteModal.js
similarity index 74%
rename from frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardModal.js
rename to frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardDeleteModal.js
index a716cdb0..009a74e0 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardModal.js
+++ b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardDeleteModal.js
@@ -2,9 +2,9 @@ import React from "react";
import PropTypes from "prop-types";
import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
-import CommonModal from "../../CommonComponent/CommonModal/CommonModal.js";
+import CommonModal from "../CommonComponent/CommonModal/CommonModal.js";
-function DeleteQuestionCardModal(props) {
+function QuestionCardDeleteModal(props) {
const {isOpened, closeModal, onCancel, onDelete} = props;
return (
@@ -20,15 +20,15 @@ function DeleteQuestionCardModal(props) {
);
}
-DeleteQuestionCardModal.propTypes = {
+QuestionCardDeleteModal.propTypes = {
isOpened: PropTypes.bool,
closeModal: PropTypes.func,
onCancel: PropTypes.func,
onDelete: PropTypes.func,
};
-DeleteQuestionCardModal.defaultProps = {
+QuestionCardDeleteModal.defaultProps = {
isOpened: PropTypes.bool,
};
-export default DeleteQuestionCardModal;
+export default QuestionCardDeleteModal;
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/QuestionEditMenuDrawer.js b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardEditMenuDrawer.js
similarity index 58%
rename from frontend/guest-app/src/components/Question/QuestionCard/QuestionEditMenuDrawer.js
rename to frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardEditMenuDrawer.js
index 1aec9771..32017380 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/QuestionEditMenuDrawer.js
+++ b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardEditMenuDrawer.js
@@ -2,25 +2,22 @@ import React from "react";
import PropTypes from "prop-types";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
-import EditIcon from "@material-ui/icons/Edit.js";
-import SideMenuItem from "../../SideMenu/SideMenuItem.js";
-import DeleteQuestionCardMenuButton from "./DeleteQuestionCardMenuButton.js";
+import QuestionCardMenuDeleteButton from "./QuestionCardMenuDeleteButton.js";
+import EditQuestionCardMenuButton from "./QuestionCardMenuEditButton.js";
-function QuestionEditMenuDrawer(props) {
+function QuestionCardEditMenuDrawer(props) {
const {isOpen, onClose, onEdit, onDelete} = props;
return (
- }
- itemText={"질문 수정"}
+ {
onEdit();
onClose();
}}
/>
-
@@ -29,18 +26,18 @@ function QuestionEditMenuDrawer(props) {
);
}
-QuestionEditMenuDrawer.propTypes = {
+QuestionCardEditMenuDrawer.propTypes = {
isOpen: PropTypes.bool,
onClose: PropTypes.func,
onEdit: PropTypes.func,
onDelete: PropTypes.func,
};
-QuestionEditMenuDrawer.defaultProps = {
+QuestionCardEditMenuDrawer.defaultProps = {
isOpen: false,
onClose: () => {},
onEdit: () => {},
onDelete: () => {},
};
-export default QuestionEditMenuDrawer;
+export default QuestionCardEditMenuDrawer;
diff --git a/frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardMenuButton.js b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardMenuDeleteButton.js
similarity index 55%
rename from frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardMenuButton.js
rename to frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardMenuDeleteButton.js
index 3f439eb9..4cdd786e 100644
--- a/frontend/guest-app/src/components/Question/QuestionCard/DeleteQuestionCardMenuButton.js
+++ b/frontend/guest-app/src/components/QuestionCardEditMenuDrawer/QuestionCardMenuDeleteButton.js
@@ -1,11 +1,11 @@
import React from "react";
import PropTypes from "prop-types";
import DeleteIcon from "@material-ui/icons/Delete.js";
-import useCommonModal from "../../CommonComponent/CommonModal/useCommonModal.js";
-import SideMenuItem from "../../SideMenu/SideMenuItem.js";
-import DeleteQuestionCardModal from "./DeleteQuestionCardModal.js";
+import useCommonModal from "../CommonComponent/CommonModal/useCommonModal.js";
+import SideMenuItem from "../SideMenu/SideMenuItem.js";
+import QuestionCardDeleteModal from "./QuestionCardDeleteModal.js";
-function DeleteQuestionCardMenuButton(props) {
+function QuestionCardMenuDeleteButton(props) {
const {onDelete} = props;
const {isOpened, openModal, closeModal} = useCommonModal();
@@ -16,7 +16,7 @@ function DeleteQuestionCardMenuButton(props) {
itemText={"질문 삭제"}
onClick={openModal}
/>
- }
+ itemText={"질문 수정"}
+ onClick={onClick}
+ />
+ );
+}
+
+export default EditQuestionCardMenuButton;
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/AddQuestionInputButton.js b/frontend/guest-app/src/components/QuestionContainer/AddQuestionInputButton.js
similarity index 97%
rename from frontend/guest-app/src/components/Question/QuestionInputArea/AddQuestionInputButton.js
rename to frontend/guest-app/src/components/QuestionContainer/AddQuestionInputButton.js
index 23b7f7c7..4ad7cb2f 100644
--- a/frontend/guest-app/src/components/Question/QuestionInputArea/AddQuestionInputButton.js
+++ b/frontend/guest-app/src/components/QuestionContainer/AddQuestionInputButton.js
@@ -11,6 +11,7 @@ const cardStyle = {
zIndex: 100,
margin: "1rem",
backgroundColor: "#3f51b5",
+ cursor: "pointer",
};
const cardContentStyle = {paddingBottom: "1rem"};
diff --git a/frontend/guest-app/src/components/Question/EditQuestionInputDrawer.js b/frontend/guest-app/src/components/QuestionContainer/EditQuestionInputDrawer.js
similarity index 72%
rename from frontend/guest-app/src/components/Question/EditQuestionInputDrawer.js
rename to frontend/guest-app/src/components/QuestionContainer/EditQuestionInputDrawer.js
index 912a09ca..631ac265 100644
--- a/frontend/guest-app/src/components/Question/EditQuestionInputDrawer.js
+++ b/frontend/guest-app/src/components/QuestionContainer/EditQuestionInputDrawer.js
@@ -1,10 +1,10 @@
-import React, {useContext} from "react";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import QuestionInputDrawer from "./QuestionInputArea/QuestionInputDrawer.js";
+import React from "react";
+import {socketClient} from "../../socket.io";
+import QuestionInputDrawer from "./QuestionInputDrawer.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
function EditQuestionInputDrawer({userNameRef, questionRef, toggleReducer}) {
- const {event, guest} = useContext(GuestGlobalContext);
+ const {event, guest} = useGlobalData();
const onConfirmEditQuestion = () => {
socketClient.emit("question/update", {
diff --git a/frontend/guest-app/src/components/Question/MyQuestionDrawer.js b/frontend/guest-app/src/components/QuestionContainer/MyQuestionDrawer.js
similarity index 71%
rename from frontend/guest-app/src/components/Question/MyQuestionDrawer.js
rename to frontend/guest-app/src/components/QuestionContainer/MyQuestionDrawer.js
index 1949b2c7..53167fde 100644
--- a/frontend/guest-app/src/components/Question/MyQuestionDrawer.js
+++ b/frontend/guest-app/src/components/QuestionContainer/MyQuestionDrawer.js
@@ -1,12 +1,12 @@
-import React, {useContext} from "react";
+import React from "react";
import PropTypes from "prop-types";
import {grey} from "@material-ui/core/colors";
import {Scrollbars} from "react-custom-scrollbars";
import AppDrawer from "../AppDrawer/AppDrawer.js";
-import {useQuestions} from "./QuestionsContext.js";
-import QuestionCardList from "./QuestionCard/QuestionCardList.js";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
-import PaddingArea from "./QuestionInputArea/PaddingArea.js";
+import QuestionCardList from "../QuestionCard/QuestionCardList.js";
+import PaddingArea from "../atoms/PaddingArea.js";
+import useQuestions from "../../contexts/Questions/useQuestions.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
const fullSizeCardStyle = {
width: "100vw",
@@ -16,7 +16,7 @@ const fullSizeCardStyle = {
function MyQuestionsDrawer(props) {
const {isOpen, onClose} = props;
- const {guest} = useContext(GuestGlobalContext);
+ const {guest} = useGlobalData();
const {questions, replies} = useQuestions();
return (
diff --git a/frontend/guest-app/src/components/Question/NewQuestionInputDrawer.js b/frontend/guest-app/src/components/QuestionContainer/NewQuestionInputDrawer.js
similarity index 72%
rename from frontend/guest-app/src/components/Question/NewQuestionInputDrawer.js
rename to frontend/guest-app/src/components/QuestionContainer/NewQuestionInputDrawer.js
index cbe37f58..3811679f 100644
--- a/frontend/guest-app/src/components/Question/NewQuestionInputDrawer.js
+++ b/frontend/guest-app/src/components/QuestionContainer/NewQuestionInputDrawer.js
@@ -1,7 +1,7 @@
-import React, {useContext} from "react";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import QuestionInputDrawer from "./QuestionInputArea/QuestionInputDrawer.js";
+import React from "react";
+import {socketClient} from "../../socket.io";
+import QuestionInputDrawer from "./QuestionInputDrawer.js";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
function getNewQuestion({EventId, GuestId, guestName, content}) {
return {
@@ -14,7 +14,7 @@ function getNewQuestion({EventId, GuestId, guestName, content}) {
}
function NewQuestionInputDrawer({userNameRef, questionRef, toggleReducer}) {
- const {event, guest} = useContext(GuestGlobalContext);
+ const {event, guest} = useGlobalData();
const onConfirmNewQuestion = () => {
socketClient.emit(
@@ -35,6 +35,7 @@ function NewQuestionInputDrawer({userNameRef, questionRef, toggleReducer}) {
onConfirm: onConfirmNewQuestion,
userNameRef,
questionRef,
+ initialUserName: guest.name,
};
return ;
diff --git a/frontend/guest-app/src/components/Question/QuestionContainer.js b/frontend/guest-app/src/components/QuestionContainer/QuestionContainer.js
similarity index 73%
rename from frontend/guest-app/src/components/Question/QuestionContainer.js
rename to frontend/guest-app/src/components/QuestionContainer/QuestionContainer.js
index 6ebc5e77..62f78f1c 100644
--- a/frontend/guest-app/src/components/Question/QuestionContainer.js
+++ b/frontend/guest-app/src/components/QuestionContainer/QuestionContainer.js
@@ -1,21 +1,26 @@
import React, {useRef} from "react";
+import styled from "styled-components";
import QuestionContainerTabBar from "./QuestionContainerTabBar.js";
-import useTabs from "../../materialUIHooks/useTabs.js";
-import AddQuestionInputButton from "./QuestionInputArea/AddQuestionInputButton.js";
-import QuestionCardList from "./QuestionCard/QuestionCardList.js";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import PaddingArea from "./QuestionInputArea/PaddingArea.js";
-import QuestionEditMenuDrawer from "./QuestionCard/QuestionEditMenuDrawer.js";
+import useTabs from "../../hooks/useTabs.js";
+import AddQuestionInputButton from "./AddQuestionInputButton.js";
+import QuestionCardList from "../QuestionCard/QuestionCardList.js";
+import {socketClient} from "../../socket.io";
+import PaddingArea from "../atoms/PaddingArea.js";
+import QuestionCardEditMenuDrawer from "../QuestionCardEditMenuDrawer/QuestionCardEditMenuDrawer.js";
import NewQuestionInputDrawer from "./NewQuestionInputDrawer.js";
import EditQuestionInputDrawer from "./EditQuestionInputDrawer.js";
-import {useUIControllerContext} from "../UIController/UIController.js";
-import {useQuestions} from "./QuestionsContext.js";
-
import MyQuestionsDrawer from "./MyQuestionDrawer.js";
+import useUIController from "../../contexts/UIController/useUIController.js";
+import useQuestions from "../../contexts/Questions/useQuestions.js";
const RECENT_TAB_IDX = 1;
const POPULAR_TAB_IDX = 2;
+const QuestionContainerStyle = styled.div`
+ overflow-y:scroll;
+ height: 100%
+`;
+
function QuestionContainer() {
const {dispatch, questions, replies} = useQuestions();
@@ -24,7 +29,7 @@ function QuestionContainer() {
editQuestionInputDrawer,
questionEditMenuReducer,
myQuestionDrawerReducer,
- } = useUIControllerContext();
+ } = useUIController();
const {tabIdx, selectTabIdx} = useTabs(RECENT_TAB_IDX);
const userNameRef = useRef(null);
const questionRef = useRef(null);
@@ -42,7 +47,7 @@ function QuestionContainer() {
};
return (
- <>
+
- questionEditMenuReducer.setOff()}
onDelete={() => {
@@ -77,14 +82,13 @@ function QuestionContainer() {
editQuestionInputDrawer.setOn(questionEditMenuReducer.data);
}}
/>
-
{
myQuestionDrawerReducer.setOff();
}}
/>
- >
+
);
}
diff --git a/frontend/guest-app/src/components/Question/QuestionContainerTabBar.js b/frontend/guest-app/src/components/QuestionContainer/QuestionContainerTabBar.js
similarity index 91%
rename from frontend/guest-app/src/components/Question/QuestionContainerTabBar.js
rename to frontend/guest-app/src/components/QuestionContainer/QuestionContainerTabBar.js
index 709d10bc..c2690ef2 100644
--- a/frontend/guest-app/src/components/Question/QuestionContainerTabBar.js
+++ b/frontend/guest-app/src/components/QuestionContainer/QuestionContainerTabBar.js
@@ -5,7 +5,7 @@ import Tab from "@material-ui/core/Tab";
import Tabs from "@material-ui/core/Tabs";
import gray from "@material-ui/core/colors/grey.js";
import PropTypes from "prop-types";
-import {useQuestions} from "./QuestionsContext.js";
+import useQuestions from "../../contexts/Questions/useQuestions.js";
const RECENT_TAB_IDX = 1;
const POPULAR_TAB_IDX = 2;
@@ -24,7 +24,7 @@ function QuestionContainerTabBar(props) {
>
최근순}
+ label={시간순}
selected={tabIdx === RECENT_TAB_IDX}
/>
{
- onConfirm && onConfirm();
- onClose();
+ if (onConfirm) {
+ if (questionRef.current.value.trim() !== "") {
+ onConfirm();
+ onClose();
+ }
+ }
}}
onCancel={onClose}
questionRef={questionRef}
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/QuestionContentInput.js b/frontend/guest-app/src/components/QuestionInput/QuestionContentInput.js
similarity index 89%
rename from frontend/guest-app/src/components/Question/QuestionInputArea/QuestionContentInput.js
rename to frontend/guest-app/src/components/QuestionInput/QuestionContentInput.js
index cd2b59c4..c5e8759f 100644
--- a/frontend/guest-app/src/components/Question/QuestionInputArea/QuestionContentInput.js
+++ b/frontend/guest-app/src/components/QuestionInput/QuestionContentInput.js
@@ -1,7 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import TextField from "@material-ui/core/TextField";
-import useCommonTextInput from "../../CommonComponent/CommonTextInput/useCommonTextInput.js";
+import useCommonTextInput from "../CommonComponent/CommonTextInput/useCommonTextInput.js";
function QuestionContentInput(props) {
const {questionRef, initValue} = props;
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/QuestionInput.js b/frontend/guest-app/src/components/QuestionInput/QuestionInput.js
similarity index 94%
rename from frontend/guest-app/src/components/Question/QuestionInputArea/QuestionInput.js
rename to frontend/guest-app/src/components/QuestionInput/QuestionInput.js
index 04360281..dfd69a36 100644
--- a/frontend/guest-app/src/components/Question/QuestionInputArea/QuestionInput.js
+++ b/frontend/guest-app/src/components/QuestionInput/QuestionInput.js
@@ -6,7 +6,7 @@ import Grid from "@material-ui/core/Grid";
import Divider from "@material-ui/core/Divider";
import QuestionContentInput from "./QuestionContentInput.js";
-import UserInfoInput from "./UserInfoInput.js";
+import QuestionUserInfoInput from "./QuestionUserInfoInput.js";
const FlexedCenterDiv = styled.div`
display: flex;
@@ -39,7 +39,7 @@ function QuestionInput(props) {
-
diff --git a/frontend/guest-app/src/components/QuestionInput/QuestionUserInfoInput.js b/frontend/guest-app/src/components/QuestionInput/QuestionUserInfoInput.js
new file mode 100644
index 00000000..2c9f083c
--- /dev/null
+++ b/frontend/guest-app/src/components/QuestionInput/QuestionUserInfoInput.js
@@ -0,0 +1,26 @@
+import PropTypes from "prop-types";
+import React from "react";
+import useStringState from "../../hooks/useStringState.js";
+import UserAvatar from "../UserAvatar/UserAvatar.js";
+import QuestionUserNameInput from "./QuestionUserNameInput.js";
+
+function QuestionUserInfoInput(props) {
+ const {userNameRef, initialUserName = ""} = props;
+ const {state} = useStringState(initialUserName);
+
+ return (
+ <>
+
+
+ >
+ );
+}
+
+QuestionUserInfoInput.propTypes = {
+ userNameRef: PropTypes.any,
+};
+
+export default QuestionUserInfoInput;
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/QuestionUserNameInput.js b/frontend/guest-app/src/components/QuestionInput/QuestionUserNameInput.js
similarity index 100%
rename from frontend/guest-app/src/components/Question/QuestionInputArea/QuestionUserNameInput.js
rename to frontend/guest-app/src/components/QuestionInput/QuestionUserNameInput.js
diff --git a/frontend/guest-app/src/components/Reply/AddReplyRow.js b/frontend/guest-app/src/components/Reply/AddReplyRow.js
deleted file mode 100644
index 31aae0a3..00000000
--- a/frontend/guest-app/src/components/Reply/AddReplyRow.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from "react";
-import Button from "@material-ui/core/Button";
-import ChatBubble from "@material-ui/icons/ChatBubble";
-import {styled} from "@material-ui/core/styles";
-
-const StyledButton = styled(Button)({
- height: "2rem",
- marginBottom: "1rem",
-});
-
-function AddReplyRow(props) {
- const {openReplies} = props;
-
- return (
-
-
- 댓글달기
-
- );
-}
-
-export default AddReplyRow;
diff --git a/frontend/guest-app/src/components/Reply/RepliesContainer.js b/frontend/guest-app/src/components/Reply/RepliesContainer.js
deleted file mode 100644
index a48164cb..00000000
--- a/frontend/guest-app/src/components/Reply/RepliesContainer.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from "react";
-import Box from "@material-ui/core/Box";
-import {styled} from "@material-ui/core/styles";
-import AppDrawNavBar from "../AppDrawer/AppDrawerNavBar";
-import PreviewQuestion from "./PreviewQuestion";
-import RepliesList from "./RepliesList";
-import ReplyQuestionDivider from "./ReplyQuestionDivider";
-import ReplyInputContainer from "./ReplyInputContainer";
-
-const Container = styled(Box)({
- display: "flex",
- flexDirection: "column",
- position: "absolute",
- top: "4rem",
- width: "99%",
-});
-
-function RepliesContainer(props) {
- const {onClose} = props;
-
- return (
-
-
-
-
-
-
-
- );
-}
-
-export default RepliesContainer;
diff --git a/frontend/guest-app/src/components/Reply/RepliesList.js b/frontend/guest-app/src/components/Reply/RepliesList.js
deleted file mode 100644
index ed8c907e..00000000
--- a/frontend/guest-app/src/components/Reply/RepliesList.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import {styled} from "@material-ui/core/styles";
-import Paper from "@material-ui/core/Paper";
-import Reply from "./Reply";
-
-const RepliesListContainer = styled(Paper)({
- width: "100%",
- backgroundColor: "#FFFFF0",
-});
-
-function RepliesList(props) {
- const {replies} = props;
-
- return (
- <>
-
- {replies.map((reply, idx) => )}
-
- >
- );
-}
-
-RepliesList.propTypes = {
- replies: PropTypes.any,
-};
-
-export default RepliesList;
diff --git a/frontend/guest-app/src/components/Reply/RepliesPaper.js b/frontend/guest-app/src/components/Reply/RepliesPaper.js
deleted file mode 100644
index 7645b426..00000000
--- a/frontend/guest-app/src/components/Reply/RepliesPaper.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from "react";
-import {styled} from "@material-ui/core/styles";
-import Paper from "@material-ui/core/Paper";
-import RepliesContainer from "./RepliesContainer";
-
-const StyledPaper = styled(Paper)({
- width: "100vw",
- height: "100vh",
- position: "relative",
-});
-
-function RepliesPaper(props) {
- return (
- <>
-
-
-
- >
- );
-}
-
-export default RepliesPaper;
diff --git a/frontend/guest-app/src/components/Reply/Reply.js b/frontend/guest-app/src/components/Reply/Reply.js
deleted file mode 100644
index ba711b50..00000000
--- a/frontend/guest-app/src/components/Reply/Reply.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from "react";
-import Card from "@material-ui/core/Card";
-import {CardContent} from "@material-ui/core";
-import Divider from "@material-ui/core/Divider";
-import QuestionHeader from "../Question/QuestionCard/QuestionCardHeader.js";
-import QuestionBody from "../Question/QuestionCard/QuestionCardBody";
-import EmojiArea from "../Emoji/EmojiArea";
-
-function Reply(props) {
- return (
- <>
-
-
-
-
-
-
-
-
- >
- );
-}
-
-export default Reply;
diff --git a/frontend/guest-app/src/components/Reply/ReplyArea.js b/frontend/guest-app/src/components/Reply/ReplyArea.js
deleted file mode 100644
index d6b3345f..00000000
--- a/frontend/guest-app/src/components/Reply/ReplyArea.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from "react";
-import PropTypes from "prop-types";
-import {styled} from "@material-ui/core/styles";
-import Paper from "@material-ui/core/Paper";
-import Drawer from "@material-ui/core/Drawer";
-import ReplyAvatar from "./ReplyAvatar";
-import RepliesPaper from "./RepliesPaper";
-import AddReplyRow from "./AddReplyRow";
-import useReplies from "./useReplies";
-
-import CurrentRepliesTextField from "./CurrentRepliesTextField";
-
-const MAX_SHOWING_AVATAR = 5;
-const PreviewReplyContainer = styled(Paper)({
- display: "flex",
- height: "3rem",
- marginBottom: 5,
- alignItems: "center",
- backgroundColor: "#FFFFF0",
-});
-
-function extractUniqueReplier(replies) {
- const uniqueGuestIdMap = new Map();
-
- replies.forEach(replie => {
- uniqueGuestIdMap.set(replie.GuestId, replie.guestName);
- });
- return [...uniqueGuestIdMap.values()];
-}
-
-export default function ReplyArea(props) {
- const {repliesIsOpened, openReplies, closeReplies} = useReplies();
- const {replies} = props;
- const repliers = extractUniqueReplier(replies);
- const repliersNum = repliers.length;
- const showingReplierList = repliers.slice(0, MAX_SHOWING_AVATAR);
-
- return (
- <>
- {replies.length !== 0 ? (
-
- {showingReplierList.map((userName, idx) => {
- if (idx === MAX_SHOWING_AVATAR - 1) {
- return (
-
- );
- }
- return (
-
- );
- })}
-
-
- {`${replies.length}개 댓글`}
-
-
- ) : (
-
- )}
-
-
-
- >
- );
-}
-
-ReplyArea.propTypes = {
- replies: PropTypes.array,
-};
diff --git a/frontend/guest-app/src/components/ReplyCard/ReplyCard.js b/frontend/guest-app/src/components/ReplyCard/ReplyCard.js
new file mode 100644
index 00000000..584b37d9
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyCard/ReplyCard.js
@@ -0,0 +1,24 @@
+import React from "react";
+import Card from "@material-ui/core/Card";
+import {CardContent} from "@material-ui/core";
+import Divider from "@material-ui/core/Divider";
+import QuestionHeader from "../QuestionCard/QuestionCardHeader.js";
+import QuestionBody from "../QuestionCard/QuestionCardBody.js";
+import EmojiArea from "../EmojiArea/EmojiArea.js";
+
+function ReplyCard(props) {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default ReplyCard;
diff --git a/frontend/guest-app/src/components/ReplyCard/ReplyCardList.js b/frontend/guest-app/src/components/ReplyCard/ReplyCardList.js
new file mode 100644
index 00000000..cad2f6e5
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyCard/ReplyCardList.js
@@ -0,0 +1,29 @@
+import React from "react";
+import PropTypes from "prop-types";
+import {styled} from "@material-ui/core/styles";
+import Paper from "@material-ui/core/Paper";
+import gray from "@material-ui/core/colors/grey.js";
+import ReplyCard from "./ReplyCard.js";
+
+const RepliesListStyle = styled(Paper)({
+ width: "100%",
+ backgroundColor: gray[300],
+});
+
+function ReplyCardList(props) {
+ const {replies} = props;
+
+ return (
+
+ {replies.map((reply, idx) => (
+
+ ))}
+
+ );
+}
+
+ReplyCardList.propTypes = {
+ replies: PropTypes.any,
+};
+
+export default ReplyCardList;
diff --git a/frontend/guest-app/src/components/Reply/PreviewQuestion.js b/frontend/guest-app/src/components/ReplyContainer/PreviewQuestion.js
similarity index 71%
rename from frontend/guest-app/src/components/Reply/PreviewQuestion.js
rename to frontend/guest-app/src/components/ReplyContainer/PreviewQuestion.js
index e3aa40d0..98a64af1 100644
--- a/frontend/guest-app/src/components/Reply/PreviewQuestion.js
+++ b/frontend/guest-app/src/components/ReplyContainer/PreviewQuestion.js
@@ -4,17 +4,17 @@ import {styled} from "@material-ui/core/styles";
import {CardContent} from "@material-ui/core";
import Divider from "@material-ui/core/Divider";
import Box from "@material-ui/core/Box";
-import QuestionHeader from "../Question/QuestionCard/QuestionCardHeader.js";
-import QuestionBody from "../Question/QuestionCard/QuestionCardBody";
-import EmojiArea from "../Emoji/EmojiArea";
+import QuestionHeader from "../QuestionCard/QuestionCardHeader.js";
+import QuestionBody from "../QuestionCard/QuestionCardBody.js";
+import EmojiArea from "../EmojiArea/EmojiArea.js";
-const Container = styled(Box)({
+const PreviewQuestionStyle = styled(Box)({
backgroundColor: "#E0E0E0",
});
function PreviewQuestion(props) {
return (
-
+
@@ -25,7 +25,7 @@ function PreviewQuestion(props) {
-
+
);
}
diff --git a/frontend/guest-app/src/components/ReplyContainer/RepliesContainer.js b/frontend/guest-app/src/components/ReplyContainer/RepliesContainer.js
new file mode 100644
index 00000000..5c5255f8
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyContainer/RepliesContainer.js
@@ -0,0 +1,41 @@
+import React from "react";
+import styled from "styled-components";
+import {Scrollbars} from "react-custom-scrollbars";
+import Box from "@material-ui/core/Box";
+import PreviewQuestion from "./PreviewQuestion.js";
+import ReplyCardList from "../ReplyCard/ReplyCardList.js";
+import ReplyQuestionDivider from "./ReplyQuestionDivider.js";
+import ReplyInputContainer from "../ReplyInput/ReplyInputContainer.js";
+import PaddingArea from "../atoms/PaddingArea.js";
+
+const RepliesContainerStyle = styled.div`
+ overflow-y: scroll;
+ ::-webkit-scrollbar {
+ display: none;
+ }
+`;
+
+const fullScreen = {
+ width: "100vw",
+ height: "100vh",
+};
+
+function RepliesContainer(props) {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default RepliesContainer;
diff --git a/frontend/guest-app/src/components/Reply/ReplyQuestionDivider.js b/frontend/guest-app/src/components/ReplyContainer/ReplyQuestionDivider.js
similarity index 78%
rename from frontend/guest-app/src/components/Reply/ReplyQuestionDivider.js
rename to frontend/guest-app/src/components/ReplyContainer/ReplyQuestionDivider.js
index 5f9eed1e..92fb89c8 100644
--- a/frontend/guest-app/src/components/Reply/ReplyQuestionDivider.js
+++ b/frontend/guest-app/src/components/ReplyContainer/ReplyQuestionDivider.js
@@ -2,6 +2,7 @@ import React from "react";
import {styled} from "@material-ui/core/styles";
import Divider from "@material-ui/core/Divider";
import Box from "@material-ui/core/Box";
+import {Typography} from "@material-ui/core";
const Container = styled(Box)({
marginTop: "1rem",
@@ -12,10 +13,6 @@ const Container = styled(Box)({
flex: 1,
});
-const ReplieNumField = styled(Box)({
- fontWeight: "bold",
-});
-
const CustomDivider = styled(Divider)({
marginLeft: "2rem",
width: "70%",
@@ -28,8 +25,8 @@ function ReplyQuestionDivider(props) {
return (
- {`${replies.length}개 댓글`}
-
+ {`댓글 ${replies.length}개`}
+
);
}
diff --git a/frontend/guest-app/src/components/Reply/ReplierInfoInput.js b/frontend/guest-app/src/components/ReplyInput/ReplierInfoInput.js
similarity index 78%
rename from frontend/guest-app/src/components/Reply/ReplierInfoInput.js
rename to frontend/guest-app/src/components/ReplyInput/ReplierInfoInput.js
index db4cfaaf..06ec7c0a 100644
--- a/frontend/guest-app/src/components/Reply/ReplierInfoInput.js
+++ b/frontend/guest-app/src/components/ReplyInput/ReplierInfoInput.js
@@ -12,11 +12,7 @@ const TextFieldStyle = styled(TextField)({
});
function UserInfoInput(props) {
- const {userNameRef, userName, setUserName} = props;
-
- const onUserNameChange = e => {
- setUserName(e.target.value);
- };
+ const {userNameRef, userName} = props;
return (
<>
@@ -24,7 +20,6 @@ function UserInfoInput(props) {
>
@@ -34,7 +29,6 @@ function UserInfoInput(props) {
UserInfoInput.propTypes = {
userNameRef: PropTypes.any,
userName: PropTypes.string,
- setUserName: PropTypes.func,
};
export default UserInfoInput;
diff --git a/frontend/guest-app/src/components/Reply/ReplyContentInput.js b/frontend/guest-app/src/components/ReplyInput/ReplyContentInput.js
similarity index 96%
rename from frontend/guest-app/src/components/Reply/ReplyContentInput.js
rename to frontend/guest-app/src/components/ReplyInput/ReplyContentInput.js
index c4f3b5b7..19d3e0eb 100644
--- a/frontend/guest-app/src/components/Reply/ReplyContentInput.js
+++ b/frontend/guest-app/src/components/ReplyInput/ReplyContentInput.js
@@ -13,7 +13,7 @@ function ReplyContentInput(props) {
@@ -37,7 +39,6 @@ function ReplyInput(props) {
@@ -45,7 +46,7 @@ function ReplyInput(props) {
variant="contained"
color={"primary"}
onClick={() => {
- onConfirm();
+ onConfirm(replyContent);
setReplyContent("");
}}
>
diff --git a/frontend/guest-app/src/components/Reply/ReplyInputContainer.js b/frontend/guest-app/src/components/ReplyInput/ReplyInputContainer.js
similarity index 67%
rename from frontend/guest-app/src/components/Reply/ReplyInputContainer.js
rename to frontend/guest-app/src/components/ReplyInput/ReplyInputContainer.js
index d858a97a..622d0eab 100644
--- a/frontend/guest-app/src/components/Reply/ReplyInputContainer.js
+++ b/frontend/guest-app/src/components/ReplyInput/ReplyInputContainer.js
@@ -1,10 +1,10 @@
-import React, {useContext, useRef} from "react";
+import React, {useRef} from "react";
import PropTypes from "prop-types";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
-import ReplyInput from "./ReplyInput";
-import {socketClient} from "../../libs/socketIoClientProvider.js";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
+import ReplyInput from "./ReplyInput.js";
+import {socketClient} from "../../socket.io";
+import useGlobalData from "../../contexts/GlobalData/useGlobalData.js";
const createNewReply = ({
EventId,
@@ -23,10 +23,14 @@ const createNewReply = ({
function ReplyInputContainer(props) {
const {id} = props;
- const {event, guest} = useContext(GuestGlobalContext);
+ const {event, guest} = useGlobalData();
const userNameRef = useRef(null);
const questionRef = useRef(null);
- const onConfirmNewReply = () => {
+ const onConfirmNewReply = reply => {
+ if (reply.trim() === "") {
+ return;
+ }
+
socketClient.emit(
"question/create",
createNewReply({
@@ -40,12 +44,10 @@ function ReplyInputContainer(props) {
};
return (
-
-
+
+
{
- onConfirmNewReply();
- }}
+ onConfirm={onConfirmNewReply}
confirmButtonText="댓글달기"
userNameRef={userNameRef}
questionRef={questionRef}
diff --git a/frontend/guest-app/src/components/ReplyPreviewArea/ReplyAddButton.js b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyAddButton.js
new file mode 100644
index 00000000..17700c82
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyAddButton.js
@@ -0,0 +1,23 @@
+import React from "react";
+import Button from "@material-ui/core/Button";
+import {ChatBubbleOutlineOutlined} from "@material-ui/icons";
+import {styled} from "@material-ui/core/styles";
+import {Typography} from "@material-ui/core";
+
+const StyledButton = styled(Button)({
+ height: "2rem",
+ marginBottom: "1rem",
+});
+
+function ReplyAddButton(props) {
+ const {onClick} = props;
+
+ return (
+
+
+ 댓글달기
+
+ );
+}
+
+export default ReplyAddButton;
diff --git a/frontend/guest-app/src/components/Reply/CurrentRepliesTextField.js b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyNumber.js
similarity index 57%
rename from frontend/guest-app/src/components/Reply/CurrentRepliesTextField.js
rename to frontend/guest-app/src/components/ReplyPreviewArea/ReplyNumber.js
index e58f1853..b54a6884 100644
--- a/frontend/guest-app/src/components/Reply/CurrentRepliesTextField.js
+++ b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyNumber.js
@@ -6,26 +6,26 @@ import {Typography} from "@material-ui/core";
const TextField = styled(Typography)({
marginLeft: 10,
textAlign: "center",
- textDecoration: "underline",
+ textDecoration: "none",
cursor: "pointer",
"&:hover": {
color: "#3f51b5",
},
});
-function CurrentRepliesTextField(props) {
- const {openReplies} = props;
+function ReplyNumber(props) {
+ const {openReplies, replyCount} = props;
return (
-
- {props.children}
+
+ {`댓글 ${replyCount}개`}
);
}
-CurrentRepliesTextField.propTypes = {
- children: PropTypes.node,
+ReplyNumber.propTypes = {
+ replyCount: PropTypes.number,
openReplies: PropTypes.func,
};
-export default CurrentRepliesTextField;
+export default ReplyNumber;
diff --git a/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreview.js b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreview.js
new file mode 100644
index 00000000..fc93760a
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreview.js
@@ -0,0 +1,53 @@
+import React from "react";
+import {styled} from "@material-ui/core/styles";
+import Paper from "@material-ui/core/Paper";
+import gray from "@material-ui/core/colors/grey.js";
+import ReplyPreviewAvatar from "./ReplyPreviewAvatar.js";
+import ReplyNumber from "./ReplyNumber.js";
+
+const MAX_SHOWING_AVATAR = 5;
+const ReplyPreviewStyle = styled(Paper)({
+ display: "flex",
+ height: "3rem",
+ marginBottom: 15,
+ alignItems: "center",
+ backgroundColor: gray[300],
+});
+
+function extractUniqueReplier(replies) {
+ const uniqueGuestIdMap = new Map();
+
+ replies.forEach(reply => {
+ uniqueGuestIdMap.set(reply.GuestId, reply.guestName);
+ });
+
+ return [...uniqueGuestIdMap.values()];
+}
+
+function ReplyPreview(props) {
+ const {replies, onClick} = props;
+ const repliers = extractUniqueReplier(replies);
+ const repliersNum = repliers.length;
+ const showingReplierList = repliers.slice(0, MAX_SHOWING_AVATAR);
+
+ return (
+
+ {showingReplierList.map((userName, idx) => {
+ if (idx === MAX_SHOWING_AVATAR - 1) {
+ return (
+
+ );
+ }
+
+ return ;
+ })}
+
+
+ );
+}
+
+export default ReplyPreview;
diff --git a/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewArea.js b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewArea.js
new file mode 100644
index 00000000..ffbe5938
--- /dev/null
+++ b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewArea.js
@@ -0,0 +1,34 @@
+import React from "react";
+import PropTypes from "prop-types";
+import AddReplyButton from "./ReplyAddButton.js";
+import useReplies from "../../hooks/useReplies.js";
+import AppDrawer from "../AppDrawer/AppDrawer.js";
+import RepliesContainer from "../ReplyContainer/RepliesContainer.js";
+import ReplyPreview from "./ReplyPreview.js";
+
+export default function ReplyPreviewArea(props) {
+ const {repliesIsOpened, openReplies, closeReplies} = useReplies();
+ const {replies} = props;
+
+ return (
+ <>
+ {replies.length !== 0 ? (
+
+ ) : (
+
+ )}
+
+
+
+ >
+ );
+}
+
+ReplyPreviewArea.propTypes = {
+ replies: PropTypes.array,
+};
diff --git a/frontend/guest-app/src/components/Reply/ReplyAvatar.js b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewAvatar.js
similarity index 92%
rename from frontend/guest-app/src/components/Reply/ReplyAvatar.js
rename to frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewAvatar.js
index 016778cc..12ede200 100644
--- a/frontend/guest-app/src/components/Reply/ReplyAvatar.js
+++ b/frontend/guest-app/src/components/ReplyPreviewArea/ReplyPreviewAvatar.js
@@ -39,7 +39,7 @@ function AnonymousAvatar() {
);
}
-function ReplyAvatar(props) {
+function ReplyPreviewAvatar(props) {
const {isAnonymous = false, userName = "Anonymous", remainder} = props;
return isAnonymous ? (
@@ -49,10 +49,10 @@ function ReplyAvatar(props) {
);
}
-ReplyAvatar.propTypes = {
+ReplyPreviewAvatar.propTypes = {
userName: PropTypes.string,
isAnonymous: PropTypes.bool,
remainder: PropTypes.any,
};
-export default ReplyAvatar;
+export default ReplyPreviewAvatar;
diff --git a/frontend/guest-app/src/components/SideMenu/EditProfileButton.js b/frontend/guest-app/src/components/SideMenu/EditProfileButton.js
deleted file mode 100644
index e5347516..00000000
--- a/frontend/guest-app/src/components/SideMenu/EditProfileButton.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from "react";
-import PersonIcon from "@material-ui/icons/Person.js";
-import useCommonModal from "../CommonComponent/CommonModal/useCommonModal.js";
-import SideMenuItem from "./SideMenuItem.js";
-import EditProfileModal from "../Modals/EditProfileModal.js";
-
-function EditProfileButton() {
- const modalState = useCommonModal();
-
- return (
-
- }
- itemText={"내 프로필 변경"}
- onClick={modalState.openModal}
- />
-
-
- );
-}
-
-export default EditProfileButton;
diff --git a/frontend/guest-app/src/components/SideMenu/LogoutButton.js b/frontend/guest-app/src/components/SideMenu/LogoutButton.js
index 7c9b6a3f..f19ff921 100644
--- a/frontend/guest-app/src/components/SideMenu/LogoutButton.js
+++ b/frontend/guest-app/src/components/SideMenu/LogoutButton.js
@@ -2,7 +2,7 @@ import React from "react";
import ExitToAppIcon from "@material-ui/icons/ExitToApp.js";
import useCommonModal from "../CommonComponent/CommonModal/useCommonModal.js";
import SideMenuItem from "./SideMenuItem.js";
-import LogOutModal from "../Modals/LogoutModal.js";
+import LogOutModal from "./LogoutModal.js";
import config from "../../config";
function LogoutButton(props) {
diff --git a/frontend/guest-app/src/components/Modals/LogoutModal.js b/frontend/guest-app/src/components/SideMenu/LogoutModal.js
similarity index 68%
rename from frontend/guest-app/src/components/Modals/LogoutModal.js
rename to frontend/guest-app/src/components/SideMenu/LogoutModal.js
index e3bed7dc..a5b4568f 100644
--- a/frontend/guest-app/src/components/Modals/LogoutModal.js
+++ b/frontend/guest-app/src/components/SideMenu/LogoutModal.js
@@ -1,9 +1,10 @@
import React from "react";
import {Grid} from "@material-ui/core";
-import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import CommonModal from "../CommonComponent/CommonModal/CommonModal.js";
+import CancelButton from "../atoms/CancelButton.js";
+import ConfirmButton from "../atoms/ConfirmButton.js";
function LogOutModal({isOpened = false, onCancelClick, onLogout}) {
return (
@@ -11,17 +12,8 @@ function LogOutModal({isOpened = false, onCancelClick, onLogout}) {
로그아웃 하시겠습니까?
-
-
-
+
+
);
diff --git a/frontend/guest-app/src/components/SideMenu/MyQuestionButton.js b/frontend/guest-app/src/components/SideMenu/MyQuestionButton.js
index 3de72aad..ba7a0df3 100644
--- a/frontend/guest-app/src/components/SideMenu/MyQuestionButton.js
+++ b/frontend/guest-app/src/components/SideMenu/MyQuestionButton.js
@@ -1,12 +1,12 @@
import React from "react";
import QuestionAnswerIcon from "@material-ui/icons/QuestionAnswer.js";
import SideMenuItem from "./SideMenuItem.js";
-import {useUIControllerContext} from "../UIController/UIController.js";
+import useUIController from "../../contexts/UIController/useUIController.js";
const MY_QUESTION_BUTTON_TEXT = "내 질문들";
function MyQuestionButton() {
- const {myQuestionDrawerReducer} = useUIControllerContext();
+ const {myQuestionDrawerReducer} = useUIController();
return (
diff --git a/frontend/guest-app/src/components/SideMenu/SideMenuBody.js b/frontend/guest-app/src/components/SideMenu/SideMenuBody.js
index 71f121c5..cc6b6bc4 100644
--- a/frontend/guest-app/src/components/SideMenu/SideMenuBody.js
+++ b/frontend/guest-app/src/components/SideMenu/SideMenuBody.js
@@ -1,10 +1,7 @@
import React from "react";
-
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
-import EditProfileModal from "../Modals/EditProfileModal.js";
import useSideMenuStyles from "./UseSideMenuStyles.js";
-import EditProfileButton from "./EditProfileButton.js";
import MyQuestionButton from "./MyQuestionButton.js";
import LogoutButton from "./LogoutButton.js";
@@ -15,13 +12,9 @@ function SideMenuBody(props) {
);
}
diff --git a/frontend/guest-app/src/components/SideMenu/SideMenuHeader.js b/frontend/guest-app/src/components/SideMenu/SideMenuHeader.js
index 907e5ee3..8cc2fccf 100644
--- a/frontend/guest-app/src/components/SideMenu/SideMenuHeader.js
+++ b/frontend/guest-app/src/components/SideMenu/SideMenuHeader.js
@@ -1,4 +1,5 @@
import React from "react";
+import moment from "moment"
import PropTypes from "prop-types";
import {Grid} from "@material-ui/core";
import {blue} from "@material-ui/core/colors";
@@ -8,12 +9,15 @@ import Typography from "@material-ui/core/Typography";
import useSideMenuStyles from "./UseSideMenuStyles.js";
const style = {background: blue[600]};
+const dateFormat="YYYY년 MM월 DD일 HH시 mm분";
function getDateRangeString(startAt, endAt) {
const start = new Date(parseInt(startAt, 10));
const end = new Date(parseInt(endAt, 10));
+ const startDate = moment(start).format(dateFormat);
+ const endDate = moment(end).format(dateFormat);
- return `${end.getFullYear()}.${start.getDay()} ~ ${end.getFullYear()}.${end.getDay()}`;
+ return `${startDate} ~ ${endDate}`;
}
function SideMenuHeader(props) {
diff --git a/frontend/guest-app/src/components/TabGroup/PollTabIcon.js b/frontend/guest-app/src/components/TabGroup/PollTabIcon.js
new file mode 100644
index 00000000..c3e50f09
--- /dev/null
+++ b/frontend/guest-app/src/components/TabGroup/PollTabIcon.js
@@ -0,0 +1,18 @@
+import React from "react";
+import Badge from "@material-ui/core/Badge/Badge.js";
+import PollIcon from "@material-ui/icons/Poll.js";
+
+const style = {marginRight: "8px"};
+
+function PollTabIcon({showBadge}) {
+ const props = showBadge ? {color: "error", variant: "dot"} : {};
+
+ return (
+
+
+ 투표
+
+ );
+}
+
+export default PollTabIcon;
diff --git a/frontend/guest-app/src/components/TabGroup/TabIcons.js b/frontend/guest-app/src/components/TabGroup/QnATabIcon.js
similarity index 54%
rename from frontend/guest-app/src/components/TabGroup/TabIcons.js
rename to frontend/guest-app/src/components/TabGroup/QnATabIcon.js
index 53e1b384..6db3d86e 100644
--- a/frontend/guest-app/src/components/TabGroup/TabIcons.js
+++ b/frontend/guest-app/src/components/TabGroup/QnATabIcon.js
@@ -1,11 +1,10 @@
import React from "react";
import Badge from "@material-ui/core/Badge/Badge.js";
-import QuestionAnswerIcon from "@material-ui/icons/QuestionAnswer";
-import PollIcon from "@material-ui/icons/Poll";
+import QuestionAnswerIcon from "@material-ui/icons/QuestionAnswer.js";
const style = {marginRight: "8px"};
-export function QnATabIcon({showBadge}) {
+function QnATabIcon({showBadge}) {
const props = showBadge ? {color: "error", variant: "dot"} : {};
return (
@@ -16,13 +15,4 @@ export function QnATabIcon({showBadge}) {
);
}
-export function PollTabIcon({showBadge}) {
- const props = showBadge ? {color: "error", variant: "dot"} : {};
-
- return (
-
-
- 투표
-
- );
-}
+export default QnATabIcon;
diff --git a/frontend/guest-app/src/components/TabGroup/TabGroup.js b/frontend/guest-app/src/components/TabGroup/TabGroup.js
index 0ad87372..905190f0 100644
--- a/frontend/guest-app/src/components/TabGroup/TabGroup.js
+++ b/frontend/guest-app/src/components/TabGroup/TabGroup.js
@@ -2,12 +2,14 @@ import React from "react";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import styled from "styled-components";
-import {PollTabIcon, QnATabIcon} from "./TabIcons.js";
-import useTabs from "../../materialUIHooks/useTabs.js";
+import useTabs from "../../hooks/useTabs.js";
import TabBody from "./TabBody.js";
-import QuestionContainer from "../Question/QuestionContainer.js";
-import PollApollo from "../Poll/PollApollo.js";
-import {QuestionsProvider} from "../Question/QuestionsContext.js";
+import QuestionContainer from "../QuestionContainer/QuestionContainer.js";
+import QnATabIcon from "./QnATabIcon.js";
+import PollTabIcon from "./PollTabIcon.js";
+import QuestionsProvider from "../../contexts/Questions/QuestionsProvider.js";
+import PollsProvider from "../../contexts/Polls/PollsProvider.js";
+import PollContainer from "../Poll/PollContainer.js";
const TabGroupStyle = styled.div`
position: fixed;
@@ -34,7 +36,9 @@ function TabGroup({showQnABadge = true, showPollBadge}) {
-
+
+
+
);
diff --git a/frontend/guest-app/src/components/UIController/UIController.js b/frontend/guest-app/src/components/UIController/UIController.js
deleted file mode 100644
index dee874e4..00000000
--- a/frontend/guest-app/src/components/UIController/UIController.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, {createContext, useContext} from "react";
-import useToggleReducer from "../Question/useToggleReducer.js";
-
-const UIControlContext = createContext([]);
-
-const UIControlProvider = UIControlContext.Provider;
-
-function useUIControlReducers() {
- const newQuestionInputDrawer = useToggleReducer();
- const editQuestionInputDrawer = useToggleReducer();
- const questionEditMenuReducer = useToggleReducer();
- const myQuestionDrawerReducer = useToggleReducer();
-
- return {
- newQuestionInputDrawer,
- editQuestionInputDrawer,
- questionEditMenuReducer,
- myQuestionDrawerReducer,
- };
-}
-
-export function UIController(props) {
- const {children} = props;
- const UIControlReducer = useUIControlReducers();
-
- return (
-
- {children}
-
- );
-}
-
-export function useUIControllerContext() {
- return useContext(UIControlContext);
-}
diff --git a/frontend/guest-app/src/components/UserAvatar/AnonymousAvatar.js b/frontend/guest-app/src/components/UserAvatar/AnonymousAvatar.js
new file mode 100644
index 00000000..360a0882
--- /dev/null
+++ b/frontend/guest-app/src/components/UserAvatar/AnonymousAvatar.js
@@ -0,0 +1,13 @@
+import Avatar from "@material-ui/core/Avatar";
+import PersonIcon from "@material-ui/icons/Person.js";
+import React from "react";
+
+function AnonymousAvatar() {
+ return (
+
+
+
+ );
+}
+
+export default AnonymousAvatar;
diff --git a/frontend/guest-app/src/components/UserAvatar/NamedAvatar.js b/frontend/guest-app/src/components/UserAvatar/NamedAvatar.js
new file mode 100644
index 00000000..8d5a5eac
--- /dev/null
+++ b/frontend/guest-app/src/components/UserAvatar/NamedAvatar.js
@@ -0,0 +1,21 @@
+import {makeStyles} from "@material-ui/core";
+import randomMC from "random-material-color";
+import Avatar from "@material-ui/core/Avatar";
+import React from "react";
+
+function NamedAvatar({userName}) {
+ const useStyles = makeStyles({
+ avatar: {
+ margin: 10,
+ },
+ randomAvatar: {
+ backgroundColor: randomMC.getColor({text: userName}),
+ },
+ });
+ const classes = useStyles();
+ const inner = userName.slice(0, 1);
+
+ return {inner};
+}
+
+export default NamedAvatar;
diff --git a/frontend/guest-app/src/components/UserAvatar/UserAvatar.js b/frontend/guest-app/src/components/UserAvatar/UserAvatar.js
index 2d5d4abf..7d59c0df 100644
--- a/frontend/guest-app/src/components/UserAvatar/UserAvatar.js
+++ b/frontend/guest-app/src/components/UserAvatar/UserAvatar.js
@@ -1,32 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
-import {makeStyles} from "@material-ui/core";
-import Avatar from "@material-ui/core/Avatar";
-import randomMC from "random-material-color";
-import PersonIcon from "@material-ui/icons/Person";
-
-function NamedAvatar({userName}) {
- const useStyles = makeStyles({
- avatar: {
- margin: 10,
- },
- randomAvatar: {
- backgroundColor: randomMC.getColor({text: userName}),
- },
- });
- const classes = useStyles();
- const inner = userName.slice(0, 1);
-
- return {inner};
-}
-
-function AnonymousAvatar() {
- return (
-
-
-
- );
-}
+import AnonymousAvatar from "./AnonymousAvatar.js";
+import NamedAvatar from "./NamedAvatar.js";
function UserAvatar(props) {
const {userNameRef = {current: null}, userName = ""} = props;
diff --git a/frontend/guest-app/src/components/CommonComponent/CommonButtons/CancelButton.js b/frontend/guest-app/src/components/atoms/CancelButton.js
similarity index 100%
rename from frontend/guest-app/src/components/CommonComponent/CommonButtons/CancelButton.js
rename to frontend/guest-app/src/components/atoms/CancelButton.js
diff --git a/frontend/guest-app/src/components/CommonComponent/CommonButtons/ConfirmButton.js b/frontend/guest-app/src/components/atoms/ConfirmButton.js
similarity index 100%
rename from frontend/guest-app/src/components/CommonComponent/CommonButtons/ConfirmButton.js
rename to frontend/guest-app/src/components/atoms/ConfirmButton.js
diff --git a/frontend/guest-app/src/components/Question/QuestionInputArea/PaddingArea.js b/frontend/guest-app/src/components/atoms/PaddingArea.js
similarity index 100%
rename from frontend/guest-app/src/components/Question/QuestionInputArea/PaddingArea.js
rename to frontend/guest-app/src/components/atoms/PaddingArea.js
diff --git a/frontend/guest-app/src/components/TopProcessBar.js b/frontend/guest-app/src/components/atoms/TopProcessBar.js
similarity index 100%
rename from frontend/guest-app/src/components/TopProcessBar.js
rename to frontend/guest-app/src/components/atoms/TopProcessBar.js
diff --git a/frontend/guest-app/src/contexts/GlobalData/GlobalDataContext.js b/frontend/guest-app/src/contexts/GlobalData/GlobalDataContext.js
new file mode 100644
index 00000000..9aa19149
--- /dev/null
+++ b/frontend/guest-app/src/contexts/GlobalData/GlobalDataContext.js
@@ -0,0 +1,5 @@
+import React from "react";
+
+const GlobalDataContext = React.createContext({});
+
+export default GlobalDataContext;
diff --git a/frontend/guest-app/src/contexts/GlobalData/GlobalDataProvider.js b/frontend/guest-app/src/contexts/GlobalData/GlobalDataProvider.js
new file mode 100644
index 00000000..16370ff5
--- /dev/null
+++ b/frontend/guest-app/src/contexts/GlobalData/GlobalDataProvider.js
@@ -0,0 +1,44 @@
+import React from "react";
+import {useQuery} from "@apollo/react-hooks";
+import {GET_GUEST_APP_GLOBAL_DATA} from "../../apollo/gqlSchemes.js";
+import TopProgressBar from "../../components/atoms/TopProcessBar.js";
+import config from "../../config";
+import {createSocketIOClient, SocketClientProvider} from "../../socket.io";
+import GlobalDataContext from "./GlobalDataContext.js";
+
+function GlobalDataProvider(props) {
+ const {data, loading, error} = useQuery(GET_GUEST_APP_GLOBAL_DATA);
+
+ if (loading) {
+ return ;
+ }
+
+ if (error) {
+ window.location.href = config.inValidGuestRedirectURL;
+ return ;
+ }
+
+ const {event, guest} = data.guestInEvent;
+ const globalData = {event, guest};
+
+ const client = createSocketIOClient({
+ host: config.socketIOHost,
+ port: config.socketIOPort,
+ namespace: "event",
+ room: event.id,
+ });
+
+ client.on("connect", () => {
+ client.emit("joinRoom", {room: event.id});
+ });
+
+ return (
+
+
+ {props.children}
+
+
+ );
+}
+
+export default GlobalDataProvider;
diff --git a/frontend/guest-app/src/contexts/GlobalData/useGlobalData.js b/frontend/guest-app/src/contexts/GlobalData/useGlobalData.js
new file mode 100644
index 00000000..7b5dbe7e
--- /dev/null
+++ b/frontend/guest-app/src/contexts/GlobalData/useGlobalData.js
@@ -0,0 +1,8 @@
+import {useContext} from "react";
+import GlobalDataContext from "./GlobalDataContext.js";
+
+function useGlobalData() {
+ return useContext(GlobalDataContext);
+}
+
+export default useGlobalData;
diff --git a/frontend/guest-app/src/contexts/Polls/PollsContext.js b/frontend/guest-app/src/contexts/Polls/PollsContext.js
new file mode 100644
index 00000000..792ac128
--- /dev/null
+++ b/frontend/guest-app/src/contexts/Polls/PollsContext.js
@@ -0,0 +1,5 @@
+import {createContext} from "react";
+
+const PollsContext = createContext({});
+
+export default PollsContext;
diff --git a/frontend/guest-app/src/contexts/Polls/PollsProvider.js b/frontend/guest-app/src/contexts/Polls/PollsProvider.js
new file mode 100644
index 00000000..f4c7754a
--- /dev/null
+++ b/frontend/guest-app/src/contexts/Polls/PollsProvider.js
@@ -0,0 +1,27 @@
+import {useQuery} from "@apollo/react-hooks";
+import React from "react";
+import useGlobalData from "../GlobalData/useGlobalData.js";
+import PollsContext from "./PollsContext.js";
+import {POLL_QUERY} from "../../apollo/gqlSchemes.js";
+
+function PollsProvider(props) {
+ const {event, guest} = useGlobalData();
+ const options = {
+ variables: {
+ EventId: event.id,
+ guestId: guest.id,
+ },
+ };
+ const {loading, error, data} = useQuery(POLL_QUERY, options);
+
+ if (loading) return Loading...
;
+ if (error) return Error :(
;
+
+ return (
+
+ {props.children}
+
+ );
+}
+
+export default PollsProvider;
diff --git a/frontend/guest-app/src/contexts/Polls/usePolls.js b/frontend/guest-app/src/contexts/Polls/usePolls.js
new file mode 100644
index 00000000..f3af9732
--- /dev/null
+++ b/frontend/guest-app/src/contexts/Polls/usePolls.js
@@ -0,0 +1,8 @@
+import {useContext} from "react";
+import PollsContext from "./PollsContext.js";
+
+function usePolls() {
+ return useContext(PollsContext);
+}
+
+export default usePolls;
diff --git a/frontend/guest-app/src/contexts/Questions/QuestionsContext.js b/frontend/guest-app/src/contexts/Questions/QuestionsContext.js
new file mode 100644
index 00000000..cb07e0c5
--- /dev/null
+++ b/frontend/guest-app/src/contexts/Questions/QuestionsContext.js
@@ -0,0 +1,5 @@
+import {createContext} from "react";
+
+const QuestionsContext = createContext([]);
+
+export default QuestionsContext;
diff --git a/frontend/guest-app/src/components/Question/QuestionsContext.js b/frontend/guest-app/src/contexts/Questions/QuestionsProvider.js
similarity index 74%
rename from frontend/guest-app/src/components/Question/QuestionsContext.js
rename to frontend/guest-app/src/contexts/Questions/QuestionsProvider.js
index b28d737a..4267458f 100644
--- a/frontend/guest-app/src/components/Question/QuestionsContext.js
+++ b/frontend/guest-app/src/contexts/Questions/QuestionsProvider.js
@@ -1,14 +1,11 @@
-import React, {createContext, useContext, useEffect, useReducer} from "react";
+import React, {useEffect, useReducer} from "react";
import {useQuery} from "@apollo/react-hooks";
-import {GuestGlobalContext} from "../../libs/guestGlobalContext.js";
-import {
- buildQuestions,
- QUERY_INIT_QUESTIONS,
-} from "../../libs/useQueryQuestions.js";
-import {useSocket} from "../../libs/socketIoClientProvider.js";
-import QuestionsRepliesReducer from "./QuestionsRepliesReducer.js";
-
-const QuestionsContext = createContext([]);
+import {QUERY_INIT_QUESTIONS} from "../../apollo/gqlSchemes.js";
+import QuestionsRepliesReducer from "../../reducers/QuestionsRepliesReducer.js";
+import {useSocket} from "../../socket.io";
+import buildQuestions from "../../apollo/asembleGetQuestionQuerys.js";
+import QuestionsContext from "./QuestionsContext.js";
+import useGlobalData from "../GlobalData/useGlobalData.js";
const useDataLoadEffect = (dispatch, data) => {
useEffect(() => {
@@ -67,9 +64,9 @@ const useSocketHandler = (dispatch, guestGlobal) => {
});
};
-export function QuestionsProvider(props) {
+function QuestionsProvider(props) {
const {children} = props;
- const {event, guest} = useContext(GuestGlobalContext);
+ const {event, guest} = useGlobalData();
const {data, loading, error} = useQuery(QUERY_INIT_QUESTIONS, {
variables: {EventId: event.id, GuestId: guest.id},
});
@@ -78,7 +75,9 @@ export function QuestionsProvider(props) {
useDataLoadEffect(dispatch, data);
useSocketHandler(dispatch, guest);
- const questions = state.filter(question => (question.QuestionId === null && question.state === "active"));
+ const questions = state.filter(
+ question => question.QuestionId === null && question.state === "active",
+ );
const replies = state.filter(question => question.QuestionId !== null);
const value = {
@@ -96,6 +95,4 @@ export function QuestionsProvider(props) {
);
}
-export function useQuestions() {
- return useContext(QuestionsContext);
-}
+export default QuestionsProvider;
diff --git a/frontend/guest-app/src/contexts/Questions/useQuestions.js b/frontend/guest-app/src/contexts/Questions/useQuestions.js
new file mode 100644
index 00000000..9887dcab
--- /dev/null
+++ b/frontend/guest-app/src/contexts/Questions/useQuestions.js
@@ -0,0 +1,8 @@
+import {useContext} from "react";
+import QuestionsContext from "./QuestionsContext.js";
+
+function useQuestions() {
+ return useContext(QuestionsContext);
+}
+
+export default useQuestions;
diff --git a/frontend/guest-app/src/contexts/UIController/UIControllerContext.js b/frontend/guest-app/src/contexts/UIController/UIControllerContext.js
new file mode 100644
index 00000000..147261e7
--- /dev/null
+++ b/frontend/guest-app/src/contexts/UIController/UIControllerContext.js
@@ -0,0 +1,5 @@
+import {createContext} from "react";
+
+const UIControlContext = createContext([]);
+
+export default UIControlContext;
diff --git a/frontend/guest-app/src/contexts/UIController/UIControllerProvider.js b/frontend/guest-app/src/contexts/UIController/UIControllerProvider.js
new file mode 100644
index 00000000..b66365d3
--- /dev/null
+++ b/frontend/guest-app/src/contexts/UIController/UIControllerProvider.js
@@ -0,0 +1,16 @@
+import React from "react";
+import UIControlContext from "./UIControllerContext.js";
+import useUIControllerReducers from "./useUIControllerReducers.js";
+
+function UIControllerProvider(props) {
+ const {children} = props;
+ const UIControlReducer = useUIControllerReducers();
+
+ return (
+
+ {children}
+
+ );
+}
+
+export default UIControllerProvider;
diff --git a/frontend/guest-app/src/contexts/UIController/useUIController.js b/frontend/guest-app/src/contexts/UIController/useUIController.js
new file mode 100644
index 00000000..2addcc9b
--- /dev/null
+++ b/frontend/guest-app/src/contexts/UIController/useUIController.js
@@ -0,0 +1,8 @@
+import {useContext} from "react";
+import UIControlContext from "./UIControllerContext.js";
+
+function useUIController() {
+ return useContext(UIControlContext);
+}
+
+export default useUIController;
diff --git a/frontend/guest-app/src/contexts/UIController/useUIControllerReducers.js b/frontend/guest-app/src/contexts/UIController/useUIControllerReducers.js
new file mode 100644
index 00000000..256db977
--- /dev/null
+++ b/frontend/guest-app/src/contexts/UIController/useUIControllerReducers.js
@@ -0,0 +1,17 @@
+import useToggle from "../../hooks/useToggle.js";
+
+function useUIControllerReducers() {
+ const newQuestionInputDrawer = useToggle();
+ const editQuestionInputDrawer = useToggle();
+ const questionEditMenuReducer = useToggle();
+ const myQuestionDrawerReducer = useToggle();
+
+ return {
+ newQuestionInputDrawer,
+ editQuestionInputDrawer,
+ questionEditMenuReducer,
+ myQuestionDrawerReducer,
+ };
+}
+
+export default useUIControllerReducers;
diff --git a/frontend/guest-app/src/materialUIHooks/useDrawer.js b/frontend/guest-app/src/hooks/useDrawer.js
similarity index 100%
rename from frontend/guest-app/src/materialUIHooks/useDrawer.js
rename to frontend/guest-app/src/hooks/useDrawer.js
diff --git a/frontend/guest-app/src/components/Reply/useReplies.js b/frontend/guest-app/src/hooks/useReplies.js
similarity index 100%
rename from frontend/guest-app/src/components/Reply/useReplies.js
rename to frontend/guest-app/src/hooks/useReplies.js
diff --git a/frontend/guest-app/src/components/UserAvatar/useStringState.js b/frontend/guest-app/src/hooks/useStringState.js
similarity index 100%
rename from frontend/guest-app/src/components/UserAvatar/useStringState.js
rename to frontend/guest-app/src/hooks/useStringState.js
diff --git a/frontend/guest-app/src/materialUIHooks/useTabs.js b/frontend/guest-app/src/hooks/useTabs.js
similarity index 100%
rename from frontend/guest-app/src/materialUIHooks/useTabs.js
rename to frontend/guest-app/src/hooks/useTabs.js
diff --git a/frontend/guest-app/src/components/Question/useToggleReducer.js b/frontend/guest-app/src/hooks/useToggle.js
similarity index 75%
rename from frontend/guest-app/src/components/Question/useToggleReducer.js
rename to frontend/guest-app/src/hooks/useToggle.js
index 89292f68..6343a07b 100644
--- a/frontend/guest-app/src/components/Question/useToggleReducer.js
+++ b/frontend/guest-app/src/hooks/useToggle.js
@@ -1,7 +1,7 @@
import {useReducer} from "react";
-import ToggleReducer from "./ToggleReducer.js";
+import ToggleReducer from "../reducers/ToggleReducer.js";
-function useToggleReducer() {
+function useToggle() {
const [state, dispatch] = useReducer(ToggleReducer, {
state: false,
data: {},
@@ -17,4 +17,4 @@ function useToggleReducer() {
};
}
-export default useToggleReducer;
+export default useToggle;
diff --git a/frontend/guest-app/src/index.css b/frontend/guest-app/src/index.css
index fd2c06f6..60a96d27 100644
--- a/frontend/guest-app/src/index.css
+++ b/frontend/guest-app/src/index.css
@@ -11,3 +11,12 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
+
+/* focus 시 생기는 파란 외각선 제거*/
+input,
+textarea,
+select,
+a,
+button:focus {
+ outline: none;
+}
diff --git a/frontend/guest-app/src/index.js b/frontend/guest-app/src/index.js
index c6c7ea1b..54c3c7c9 100644
--- a/frontend/guest-app/src/index.js
+++ b/frontend/guest-app/src/index.js
@@ -1,25 +1,11 @@
import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import ReactDOM from "react-dom";
-import Cookies from "js-cookie";
-import {ApolloProvider} from "@apollo/react-hooks";
-import creaetApolloClient from "./libs/createApolloClient";
import "./index.css";
import App from "./App/App.js";
import * as serviceWorker from "./libs/serviceWorker.js";
-import config from "./config";
-const cookieName = "vaagle-guest";
-const token = Cookies.get(cookieName);
-const client = creaetApolloClient(config.apolloURI, token);
-
-
-ReactDOM.render(
-
-
- ,
- document.getElementById("root"),
-);
+ReactDOM.render(, document.getElementById("root"));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
diff --git a/frontend/guest-app/src/libs/guestGlobalContext.js b/frontend/guest-app/src/libs/guestGlobalContext.js
deleted file mode 100644
index f30db7cd..00000000
--- a/frontend/guest-app/src/libs/guestGlobalContext.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from "react";
-
-const GuestGlobalContext = React.createContext({});
-const GuestGlobalProvider = GuestGlobalContext.Provider;
-
-export {GuestGlobalContext, GuestGlobalProvider};
diff --git a/frontend/guest-app/src/libs/useQueryQuestions.js b/frontend/guest-app/src/libs/useQueryQuestions.js
deleted file mode 100644
index 71565aa5..00000000
--- a/frontend/guest-app/src/libs/useQueryQuestions.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import {gql} from "apollo-boost";
-import {JSONNestJoin, JSONNestJoin2} from "./utils.js";
-import _ from "lodash";
-
-export function buildQuestions(object) {
- const copyData = _.cloneDeep(object);
- let {questions, emojis, emojiPicks, guests, didILikes} = copyData;
-
- questions = JSONNestJoin2(questions, guests, "GuestId", "id", (a, b) => {
- a.guestName = b.name;
- a.isAnonymous = b.isAnonymous;
-
- return a;
- });
-
- questions = questions.map(x => {
- x.didILike = false;
- return x;
- });
-
- questions = JSONNestJoin(
- questions,
- didILikes,
- "id",
- "QuestionId",
- (x, y) => {
- x.didILike = true;
- return x;
- },
- );
-
- emojis = emojis.map(x => {
- x.key = `${x.QuestionId}_${x.name}`;
- x.didIPick = false;
- return x;
- });
- emojiPicks = emojiPicks.map(x => {
- x.key = `${x.QuestionId}_${x.name}`;
- return x;
- });
- emojis = JSONNestJoin(emojis, emojiPicks, "key", "key", (a, b) => {
- a.didIPick = true;
- return a;
- });
-
- questions.map(x => {
- x.emojis = [];
- return x;
- });
- questions = JSONNestJoin(questions, emojis, "id", "QuestionId", (a, b) => {
- a.emojis.push(b);
- return a;
- });
-
- return questions;
-}
-
-export const QUERY_INIT_QUESTIONS = gql`
- query getQuestions($EventId: ID!, $GuestId: ID!) {
- questions(EventId: $EventId) {
- id
- EventId
- GuestId
- createdAt
- content
- state
- isStared
- likeCount
- QuestionId
- }
- emojis(EventId: $EventId) {
- name
- count
- QuestionId
- createdAt
- }
- emojiPicks(EventId: $EventId, GuestId: $GuestId) {
- name
- QuestionId
- }
- guests(EventId: $EventId) {
- id
- name
- isAnonymous
- }
- didILikes(GuestId: $GuestId) {
- QuestionId
- }
- }
-`;
diff --git a/frontend/guest-app/src/libs/utils.js b/frontend/guest-app/src/libs/utils.js
deleted file mode 100644
index 08f16e9c..00000000
--- a/frontend/guest-app/src/libs/utils.js
+++ /dev/null
@@ -1,41 +0,0 @@
-function mappingByKey(object, key) {
- const mappped = {};
-
- object.forEach(x => {
- mappped[x[key]] = x;
- });
-
- return mappped;
-}
-
-function unMappingByKey(object) {
- return Object.values(object);
-}
-
-export function JSONNestJoin(parents, childs, parentKey, childKey, func) {
- const mapped = mappingByKey(parents, parentKey);
-
- childs.forEach(child => {
- const joinValue = child[childKey];
-
- if (mapped[joinValue]) {
- const parentElement = mapped[joinValue];
-
- mapped[joinValue] = func(parentElement, child);
- }
- });
-
- return unMappingByKey(mapped);
-}
-
-export function JSONNestJoin2(parents, childs, parentKey, childKey, func) {
- const mapped = mappingByKey(childs, childKey);
- parents.forEach(parent => {
- const joinValue = parent[parentKey];
- if (mapped[joinValue]) {
- const childElement = mapped[joinValue];
- parent = func(parent, childElement);
- }
- });
- return parents;
-}
diff --git a/frontend/guest-app/src/components/Poll/PollReducer.js b/frontend/guest-app/src/reducers/PollsReducer.js
similarity index 60%
rename from frontend/guest-app/src/components/Poll/PollReducer.js
rename to frontend/guest-app/src/reducers/PollsReducer.js
index f6ad4a63..c487760b 100644
--- a/frontend/guest-app/src/components/Poll/PollReducer.js
+++ b/frontend/guest-app/src/reducers/PollsReducer.js
@@ -1,12 +1,16 @@
-import {socketClient} from "../../libs/socketIoClientProvider.js";
+import {socketClient} from "../socket.io";
// allowDuplication == false, 즉, 복수선택이 아닌 경우, 이전에 vote 한 candidate가 있으면 삭제해야 함
const getCandidateToDelete = (items, candidateId) => {
- const candidate = items.filter(
+ const candidates = items.filter(
item => item.voted && item.id !== candidateId,
- )[0];
+ );
- return candidate ? candidate.id : null;
+ if (candidates.length > 0) {
+ return candidates[0].id;
+ } else {
+ return null;
+ }
};
// 복수선택이 아닌 투표의 경우, 다른 선택된 항목을 uncheck 하는 함수
@@ -30,6 +34,7 @@ const updateItems = (items, number, allowDuplication) => {
if (!allowDuplication) {
uncheckOtherItems(newItems);
}
+
newItems[number].voted = true;
newItems[number].voters++;
}
@@ -74,7 +79,7 @@ const updateFirstPlace = poll => {
let firstPlaceValue = 0;
newPoll.nItems.forEach((item, index) => {
- if (item.voters == firstPlaceValue) {
+ if (item.voters === firstPlaceValue) {
firstPlaceIndex.push(index);
} else if (item.voters > firstPlaceValue) {
firstPlaceIndex = [];
@@ -92,10 +97,47 @@ const updateFirstPlace = poll => {
newPoll.nItems[i].firstPlace = true;
});
- console.log("firstPlace", firstPlaceIndex, newPoll.nItems);
return newPoll;
};
+/**
+ *
+ * @param {dispatch의 action에 해당하는 object} vote
+ * dispatch({
+ type: "VOTE",
+ pollId: id,
+ candidateId,
+ number,
+ GuestId,
+ });
+ * @param {object} poll
+ type Candidate {
+ id: Int!
+ number: Int!
+ content: String!
+ voters: Int!
+ voted: Boolean
+ firstPlace: Boolean
+ }
+ type Poll {
+ id: Int!
+ pollName: String!
+ pollType: String!
+ selectionType: String!
+ allowDuplication: Boolean!
+ state: String!
+ pollDate: String
+ totalVoters: Int!
+ createdAt: String!
+ nItems: [Candidate]!
+ ratingValue: Int!
+ rated: Boolean!
+ }
+ * @param {int} candidateToDelete
+ * 복수선택이 안되는 투표의 경우,
+ * 이미 다른 candidate에 투표를 한 상황에서 다시 다른 candidate을 투표하는 경우,
+ * 예전에 투표한 candidate에 투표했다는 정보를 DB에서 삭제하기 위함
+ */
const emitVoteData = (vote, poll, candidateToDelete) => {
const action = poll.nItems[vote.number].voted ? "on" : "off";
const data = {
@@ -106,12 +148,48 @@ const emitVoteData = (vote, poll, candidateToDelete) => {
candidateToDelete,
};
- // console.log("emitVoteData", data);
socketClient.emit(`vote/${action}`, data);
};
+/**
+ *
+ * @param {dispatch의 action에 해당하는 object} rate
+ * dispatch({
+ type: "RATE",
+ value,
+ pollId: id,
+ GuestId,
+ });
+ * @param {object} poll
+ type Candidate {
+ id: Int!
+ number: Int!
+ content: String!
+ voters: Int!
+ voted: Boolean
+ firstPlace: Boolean
+ }
+ type Poll {
+ id: Int!
+ pollName: String!
+ pollType: String!
+ selectionType: String!
+ allowDuplication: Boolean!
+ state: String!
+ pollDate: String
+ totalVoters: Int!
+ createdAt: String!
+ nItems: [Candidate]!
+ ratingValue: Int!
+ rated: Boolean!
+ }
+ * @param {int} candidateId
+ 투표한 candidate의 id
+ * @param {int} index
+ 투표한 candidate가 array에서 위치한 index
+ */
const emitRateData = (rate, poll, candidateId, index) => {
- const action = rate.type === "RATE" ? "on" : "off"; // "on" or "off"
+ const action = rate.type === "RATE" ? "on" : "off";
const data = {
GuestId: rate.GuestId,
CandidateId: candidateId,
@@ -127,28 +205,39 @@ export default function reducer(polls, action) {
let index;
let candidateId;
- if (action.id) {
- thePoll = polls.filter(poll => poll.id === action.id)[0];
+ const {pollId} = action;
+
+ if (pollId) {
+ thePoll = polls.filter(poll => poll.id === pollId)[0];
}
switch (action.type) {
- case "NOTIFY_OPEN":
+ // host가 생성한 투표를 host가 open 함
+ case "NOTIFY_OPEN": {
return [action.poll, ...polls];
- case "NOTIFY_CLOSE":
- return polls.filter(poll => poll.id !== action.id);
- case "SOMEONE_VOTE":
+ }
+ // host가 open한 투표를 close 함
+ case "NOTIFY_CLOSE": {
+ return polls.filter(poll => poll.id !== pollId);
+ }
+ // 나 또는 남이 vote(N지선다) 했음을 알려줌
+ case "SOMEONE_VOTE": {
thePoll.totalVoters = action.poll.totalVoters;
thePoll.nItems.forEach((item, index) => {
item.voters = action.poll.nItems[index].voters;
item.firstPlace = action.poll.nItems[index].firstPlace;
});
- // console.log("SOMEONE_VOTE", thePoll);
- return polls.map(poll => (poll.id === action.id ? thePoll : poll));
- case "SOMEONE_RATE":
+
+ return polls.map(poll => (poll.id === pollId ? thePoll : poll));
+ }
+ // 나 또는 남이 rate(별점매기기) 했음을 알려줌
+ case "SOMEONE_RATE": {
thePoll.totalVoters = action.poll.totalVoters;
- // console.log("SOMEONE_RATE", thePoll);
- return polls.map(poll => (poll.id === action.id ? thePoll : poll));
- case "VOTE":
+
+ return polls.map(poll => (poll.id === pollId ? thePoll : poll));
+ }
+ // 내가 vote(N지선다) 했음
+ case "VOTE": {
const notVoted = thePoll.nItems.every(item => item.voted === false);
let candidateToDelete = null;
@@ -158,6 +247,7 @@ export default function reducer(polls, action) {
action.candidateId,
);
}
+
thePoll = {
...thePoll,
nItems: updateItems(
@@ -174,12 +264,15 @@ export default function reducer(polls, action) {
thePoll = updateFirstPlace(thePoll);
emitVoteData(action, thePoll, candidateToDelete);
- return polls.map(poll => (poll.id === action.id ? thePoll : poll));
- case "RATE":
+ return polls.map(poll => (poll.id === pollId ? thePoll : poll));
+ }
+ // 내가 rate(별점매기기) 했음
+ case "RATE": {
if (thePoll.rated) {
return polls;
}
+
thePoll = {
...thePoll,
nItems: updateRatingItem(thePoll.nItems, action.value, true),
@@ -187,17 +280,20 @@ export default function reducer(polls, action) {
ratingValue: action.value,
totalVoters: thePoll.totalVoters + 1,
};
- // console.log("RATE", action, thePoll);
- index = parseInt(action.value) - 1;
+
+ index = parseInt(action.value, 10) - 1;
candidateId = thePoll.nItems[index].id;
emitRateData(action, thePoll, candidateId, index);
- return polls.map(poll => (poll.id === action.id ? thePoll : poll));
- case "CANCEL_RATING":
+ return polls.map(poll => (poll.id === pollId ? thePoll : poll));
+ }
+ // 내가 rate(별점매기기)를 취소했음
+ case "CANCEL_RATING": {
if (!thePoll.rated) {
return polls;
}
- index = parseInt(thePoll.ratingValue) - 1;
+
+ index = parseInt(thePoll.ratingValue, 10) - 1;
thePoll = {
...thePoll,
nItems: updateRatingItem(
@@ -209,10 +305,11 @@ export default function reducer(polls, action) {
ratingValue: 0,
totalVoters: thePoll.totalVoters - 1,
};
- // console.log("CANCEL_RATE", action, thePoll);
candidateId = thePoll.nItems[index].id;
emitRateData(action, thePoll, candidateId, index);
- return polls.map(poll => (poll.id === action.id ? thePoll : poll));
+
+ return polls.map(poll => (poll.id === pollId ? thePoll : poll));
+ }
default:
throw new Error("Unhandled action.");
diff --git a/frontend/guest-app/src/components/Question/QuestionsRepliesReducer.js b/frontend/guest-app/src/reducers/QuestionsRepliesReducer.js
similarity index 89%
rename from frontend/guest-app/src/components/Question/QuestionsRepliesReducer.js
rename to frontend/guest-app/src/reducers/QuestionsRepliesReducer.js
index de9ae03f..a36887ff 100644
--- a/frontend/guest-app/src/components/Question/QuestionsRepliesReducer.js
+++ b/frontend/guest-app/src/reducers/QuestionsRepliesReducer.js
@@ -1,6 +1,6 @@
import _ from "lodash";
-const compareByDate = (a, b) => b.createdAt.localeCompare(a.createdAt);
+const compareByDate = (a, b) => a.createdAt.localeCompare(b.createdAt);
const compareByLikeCount = (a, b) => b.likeCount - a.likeCount;
@@ -16,7 +16,8 @@ const onSortByLikeCount = state => [...state.sort(compareByLikeCount)];
const onQuestionLike = (state, data) => {
const guestGlobal = data.guestGlobal;
- const newState = state.map(x => {
+
+ return state.map(x => {
const {QuestionId, GuestId} = data;
if (x.id !== QuestionId) {
@@ -33,8 +34,6 @@ const onQuestionLike = (state, data) => {
return newX;
});
-
- return newState;
};
const onUndoQuestionLike = (state, data) => {
@@ -132,7 +131,8 @@ const onRemoveQuestionEmoji = (state, data) => {
return newState;
};
-const onRemoveQuestion = (state, data) => _.cloneDeep(state).filter(x => x.id !== data.id);
+const onRemoveQuestion = (state, data) =>
+ _.cloneDeep(state).filter(x => x.id !== data.id);
const onUpdateQuestion = (state, data) => {
const newState = _.cloneDeep(state);
@@ -157,13 +157,17 @@ const onMoveQuestion = (state, data) => {
if (data.id === "all") {
return newState.map(e => {
- if (e.state === data.from) { e.state = data.to; }
+ if (e.state === data.from) {
+ e.state = data.to;
+ }
return e;
});
}
return newState.map(e => {
- if (e.id === data.id) { e.state = data.to; }
+ if (e.id === data.id) {
+ e.state = data.to;
+ }
return e;
});
};
@@ -172,7 +176,11 @@ const onToggleStarQuestion = (state, data) => {
const newState = _.cloneDeep(state);
newState.map(e => {
- if (e.id === data.id) { e.isStared = data.isStared; } else { e.isStared = false; }
+ if (e.id === data.id) {
+ e.isStared = data.isStared;
+ } else {
+ e.isStared = false;
+ }
return e;
});
@@ -199,6 +207,7 @@ const QuestionsRepliesReducer = (state, action) => {
};
if (!(type in actionTable)) {
+ // eslint-disable-next-line no-console
console.error(`unexpected action.type: ${type}`);
return state;
}
diff --git a/frontend/guest-app/src/reducers/ToggleReducer.js b/frontend/guest-app/src/reducers/ToggleReducer.js
new file mode 100644
index 00000000..c01e9bab
--- /dev/null
+++ b/frontend/guest-app/src/reducers/ToggleReducer.js
@@ -0,0 +1,48 @@
+import _ from "lodash";
+
+const actionTable = {
+ toggle: (state, data) => {
+ const newState = _.cloneDeep(state);
+
+ newState.data = _.cloneDeep(data);
+ newState.state = !newState.state;
+
+ return newState;
+ },
+ on: (state, data) => {
+ const newState = _.cloneDeep(state);
+
+ newState.data = _.cloneDeep(data);
+ newState.state = true;
+
+ return newState;
+ },
+ off: (state, data) => {
+ const newState = _.cloneDeep(state);
+
+ newState.data = _.cloneDeep(data);
+ newState.state = false;
+
+ return newState;
+ },
+};
+
+const ToggleReducer = (state, action) => {
+ const {type, data} = action;
+
+ if (!(type in actionTable)) {
+ // eslint-disable-next-line no-console
+ console.error(`unexpected action.type: ${type}`);
+ return state;
+ }
+
+ try {
+ return actionTable[type](state, data);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.error(e);
+ return state;
+ }
+};
+
+export default ToggleReducer;
diff --git a/frontend/guest-app/src/libs/socketIoClientProvider.js b/frontend/guest-app/src/socket.io/index.js
similarity index 61%
rename from frontend/guest-app/src/libs/socketIoClientProvider.js
rename to frontend/guest-app/src/socket.io/index.js
index 553cf265..8cd5953d 100644
--- a/frontend/guest-app/src/libs/socketIoClientProvider.js
+++ b/frontend/guest-app/src/socket.io/index.js
@@ -6,37 +6,50 @@ function combineURL(host, port, nameSpace) {
return nameSpace ? `${host}:${port}/${nameSpace}` : `${host}:${port}`;
}
-export function createSocketIOClient({host, port, namespace, room}) {
- const cookieName = "vaagle-guest";
- const token = Cookie.get(cookieName);
- const URL = combineURL(host, port, namespace);
- const socket = io(URL, {query: {token: token}});
-
+function addBoilerplateSocketListener({socket, URL, room}) {
socket.on("connect", async () => {
+ // eslint-disable-next-line no-console
console.log(
`socket.io client connect to ${URL} as ${process.env.NODE_ENV} mode`,
);
});
socket.on("joinRoom", () => {
+ // eslint-disable-next-line no-console
console.log(`join room success at ${room}`);
});
socket.on("leaveRoom", () => {
+ // eslint-disable-next-line no-console
console.log(`leave room success at ${room}`);
});
- socket.on("disconnect", (reason) => {
+ socket.on("disconnect", reason => {
+ // eslint-disable-next-line no-console
console.log(`io client disconnected by ${reason}`);
});
- socket.on("reconnect", (attemptNumber) => {
+ socket.on("reconnect", attemptNumber => {
+ // eslint-disable-next-line no-console
console.log(`io reconnect attempt ${attemptNumber}`);
});
- socket.on("error", (error) => {
+ socket.on("error", error => {
+ // eslint-disable-next-line no-console
console.log(`io error raise ${error}`);
});
+}
+
+export function createSocketIOClient({host, port, namespace, room}) {
+ const cookieName = "vaagle-guest";
+ const token = Cookie.get(cookieName);
+
+ const URL = combineURL(host, port, namespace);
+ const socket = io(URL, {query: {token}});
+
+ if (process.env.NODE_ENV === "development") {
+ addBoilerplateSocketListener({socket, URL, room});
+ }
return socket;
}
@@ -45,12 +58,11 @@ export let socketClient = null;
export let useSocket = null;
-export function SocketIoClientProvider(props) {
+export function SocketClientProvider(props) {
const {client, children} = props;
socketClient = client;
- useSocket = (eventName = "EMIT", handler = () => {
- }) => {
+ useSocket = (eventName = "EMIT", handler = () => {}) => {
socketClient.off(eventName);
socketClient.on(eventName, handler);
};
@@ -58,8 +70,8 @@ export function SocketIoClientProvider(props) {
const emit = socketClient.emit;
return (
- ${children}
+
+ ${children}
+
);
}
-
-
diff --git a/frontend/guest-app/yarn.lock b/frontend/guest-app/yarn.lock
index 17005bb6..6d21898a 100644
--- a/frontend/guest-app/yarn.lock
+++ b/frontend/guest-app/yarn.lock
@@ -7047,6 +7047,11 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"
+moment@^2.24.0:
+ version "2.24.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+ integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
diff --git a/frontend/host-app/package.json b/frontend/host-app/package.json
index 5840158a..61842bfd 100644
--- a/frontend/host-app/package.json
+++ b/frontend/host-app/package.json
@@ -63,6 +63,7 @@
"random-material-color": "^1.0.5",
"react": "^16.11.0",
"react-app-polyfill": "^1.0.4",
+ "react-custom-scrollbars": "^4.2.1",
"react-dev-utils": "^9.1.0",
"react-dom": "^16.11.0",
"react-icons": "^3.8.0",
diff --git a/frontend/host-app/public/android-icon-144x144.png b/frontend/host-app/public/android-icon-144x144.png
deleted file mode 100644
index b65cbf87..00000000
Binary files a/frontend/host-app/public/android-icon-144x144.png and /dev/null differ
diff --git a/frontend/host-app/public/android-icon-192x192.png b/frontend/host-app/public/android-icon-192x192.png
deleted file mode 100644
index 6f1148bd..00000000
Binary files a/frontend/host-app/public/android-icon-192x192.png and /dev/null differ
diff --git a/frontend/host-app/public/android-icon-36x36.png b/frontend/host-app/public/android-icon-36x36.png
deleted file mode 100644
index fc96f1dd..00000000
Binary files a/frontend/host-app/public/android-icon-36x36.png and /dev/null differ
diff --git a/frontend/host-app/public/android-icon-48x48.png b/frontend/host-app/public/android-icon-48x48.png
deleted file mode 100644
index 5cdde9da..00000000
Binary files a/frontend/host-app/public/android-icon-48x48.png and /dev/null differ
diff --git a/frontend/host-app/public/android-icon-72x72.png b/frontend/host-app/public/android-icon-72x72.png
deleted file mode 100644
index 6c2dcd4a..00000000
Binary files a/frontend/host-app/public/android-icon-72x72.png and /dev/null differ
diff --git a/frontend/host-app/public/android-icon-96x96.png b/frontend/host-app/public/android-icon-96x96.png
deleted file mode 100644
index 0ac97f36..00000000
Binary files a/frontend/host-app/public/android-icon-96x96.png and /dev/null differ
diff --git a/frontend/host-app/public/apple-icon.png b/frontend/host-app/public/apple-icon.png
deleted file mode 100644
index 9d0064a4..00000000
Binary files a/frontend/host-app/public/apple-icon.png and /dev/null differ
diff --git a/frontend/host-app/public/favicon-16x16.png b/frontend/host-app/public/favicon-16x16.png
deleted file mode 100644
index c0db580c..00000000
Binary files a/frontend/host-app/public/favicon-16x16.png and /dev/null differ
diff --git a/frontend/host-app/public/favicon-32x32.png b/frontend/host-app/public/favicon-32x32.png
deleted file mode 100644
index 8b271bda..00000000
Binary files a/frontend/host-app/public/favicon-32x32.png and /dev/null differ
diff --git a/frontend/host-app/public/favicon-96x96.png b/frontend/host-app/public/favicon-96x96.png
deleted file mode 100644
index 0ac97f36..00000000
Binary files a/frontend/host-app/public/favicon-96x96.png and /dev/null differ
diff --git a/frontend/host-app/public/logo192.png b/frontend/host-app/public/logo192.png
deleted file mode 100644
index fa313abf..00000000
Binary files a/frontend/host-app/public/logo192.png and /dev/null differ
diff --git a/frontend/host-app/public/logo512.png b/frontend/host-app/public/logo512.png
deleted file mode 100644
index bd5d4b5e..00000000
Binary files a/frontend/host-app/public/logo512.png and /dev/null differ
diff --git a/frontend/host-app/public/manifest.json b/frontend/host-app/public/manifest.json
index b8ac14a7..144fa033 100644
--- a/frontend/host-app/public/manifest.json
+++ b/frontend/host-app/public/manifest.json
@@ -6,48 +6,6 @@
"src": "favicon.ico",
"sizes": "96x96 32x32 16x16",
"type": "image/x-icon"
- },
- {
- "src": "\/android-icon-36x36.png",
- "sizes": "36x36",
- "type": "image\/png",
- "density": "0.75"
- },
- {
- "src": "\/android-icon-48x48.png",
- "sizes": "48x48",
- "type": "image\/png",
- "density": "1.0"
- },
- {
- "src": "\/android-icon-72x72.png",
- "sizes": "72x72",
- "type": "image\/png",
- "density": "1.5"
- },
- {
- "src": "\/android-icon-96x96.png",
- "sizes": "96x96",
- "type": "image\/png",
- "density": "2.0"
- },
- {
- "src": "\/android-icon-144x144.png",
- "sizes": "144x144",
- "type": "image\/png",
- "density": "3.0"
- },
- {
- "src": "\/android-icon-192x192.png",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
- },
- {
- "src": "\/android-icon-192x192.png",
- "sizes": "192x192",
- "type": "image\/png",
- "density": "4.0"
}
],
"start_url": ".",
diff --git a/frontend/host-app/src/App/App.css b/frontend/host-app/src/App/App.css
index 54453565..dceb6ab1 100644
--- a/frontend/host-app/src/App/App.css
+++ b/frontend/host-app/src/App/App.css
@@ -1,26 +1,3 @@
-/* .App {
- text-align: center;
-}
-
-.App-logo {
- height: 40vmin;
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #09d3ac;
-} */
-
.App {
width: 100%;
height: 100%;
diff --git a/frontend/host-app/src/App/App.js b/frontend/host-app/src/App/App.js
index 74a675a0..c5ee9274 100644
--- a/frontend/host-app/src/App/App.js
+++ b/frontend/host-app/src/App/App.js
@@ -1,61 +1,73 @@
import React, {useState} from "react";
-import {Skeleton} from "@material-ui/lab";
import {useQuery} from "@apollo/react-hooks";
import "./App.css";
-import Header from "../components/Header";
-import Nav from "../components/Nav";
-import Content from "../components/Content";
-import NewPollModal from "../components/Poll/NewPollModal";
+import Header from "../components/Header/Header";
+import NavBar from "../components/NavBar/NavBar.js";
import {HostProvider} from "../libs/hostContext";
import {getEventsByHost} from "../libs/gql";
-import EmptyContent from "../components/EmptyContent";
import {socketClient} from "../libs/socket.io-Client-wrapper";
-import SkeletonContent from "../components/SkeletonContent";
-import SkeletonTitle from "../components/SkeletionTitle";
+import AppSkeleton from "../components/Skeleton/AppSkeleton";
+import config from "../config";
+import {compareCurrentDateToTarget} from "../libs/utils";
+
+const initialValue = "";
+
+const initialLoadEvents = (events, initialValue, dispatch, data) => {
+ if (events === initialValue) {
+ dispatch(data);
+ }
+};
function App() {
- const modal = false;
const {data, loading, error} = useQuery(getEventsByHost());
- const [events, setEvents] = useState("");
- let eventNum = 0;
+ const [events, setEvents] = useState(initialValue);
+ let activeEventsNum = 0;
+ let eventsNum = 0;
+ let activeEvents = [];
if (loading) {
- return (
-
-
-
-
- );
+ return ;
} else if (error) {
- return error-page...
;
- } else {
- if (events === "") {
- setEvents(
- data.init.events,
- () => (eventNum = data.init.events.length),
- );
- }
- const hostInfo = data.init.host;
+ window.location.href = config.inValidHostRedirectURL;
+ return ;
+ }
+ initialLoadEvents(events, initialValue, setEvents, data.init.events);
+
+ const hostInfo = data.init.host;
- eventNum = events.length;
- if (eventNum) {
- const eventId = events[0].id;
+ eventsNum = events.length;
+ if (eventsNum) {
+ activeEvents = events.filter(event => {
+ const eventDeadLine = new Date(parseInt(event.endAt));
+ if (compareCurrentDateToTarget(eventDeadLine) > 0) {
+ return event;
+ }
+ });
+ activeEventsNum = activeEvents.length;
+ if (activeEventsNum) {
+ const eventId = activeEvents[0].id;
+ socketClient.emit("leaveRoom");
socketClient.emit("joinRoom", {room: eventId});
- socketClient.emit("event/initOption", eventId); // dummy Event Id:2
+ socketClient.emit("event/initOption", eventId);
}
-
- return (
-
-
-
-
- {modal && }
- {eventNum ? : }
-
-
- );
}
+
+ return (
+
+
+
+
+
+
+ );
}
export default App;
diff --git a/frontend/host-app/src/components/Column.js b/frontend/host-app/src/components/Column.js
deleted file mode 100644
index 62d95124..00000000
--- a/frontend/host-app/src/components/Column.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React, {useState} from "react";
-import Title from "./Title";
-import QuestionContainer from "./Questions/QuestionContainer";
-import ColumnFooter from "./ColumnFooter";
-import {QuestionStyle, ModerationStyle} from "./ComponentsStyle";
-import {filterStared} from "../libs/utils";
-
-function Column({type, state, stateHandler, data, dataHandler, handleStar}) {
- const [heightWeight, setHeightWeight] = useState(0);
- const ColumnStyle = ((type === "moderation") ? ModerationStyle : QuestionStyle);
-
- return (
-
-
-
-
-
-
- );
-}
-
-export default Column;
diff --git a/frontend/host-app/src/components/ColumnFooter.js b/frontend/host-app/src/components/ColumnFooter.js
deleted file mode 100644
index 15ffef35..00000000
--- a/frontend/host-app/src/components/ColumnFooter.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from "react";
-import {Icon} from "@material-ui/core";
-import {FooterBox, FooterStyle} from "./ComponentsStyle";
-import useStyles from "./Questions/useStyles";
-
-function ColumnFooter({data, handler}) {
- const classes = useStyles();
- const increaseHeight = () => handler(data + 1);
- const decreaseHeight = () => ((data > 0) && handler(data - 1));
-
- return (
-
-
- { decreaseHeight(); }}>
- remove
-
- { increaseHeight(); }}>
- add
-
-
-
- );
-}
-
-export default ColumnFooter;
diff --git a/frontend/host-app/src/components/Content.js b/frontend/host-app/src/components/Content.js
deleted file mode 100644
index 4d5a3cd3..00000000
--- a/frontend/host-app/src/components/Content.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, {useState, useContext, useReducer} from "react";
-import Column from "./Column";
-import {socketClient} from "../libs/socket.io-Client-wrapper";
-import useQueryQuestions from "../libs/useQueryQuestions";
-import {HostContext} from "../libs/hostContext";
-import {ContentStyle} from "./ComponentsStyle";
-import QuestionsReducer from "./Questions/QuestionReducer";
-import SkeletonContent from "./SkeletonContent";
-import useSocketHandler from "./useSocketHandler";
-
-
-function Inner({data, event, option}) {
- const SELECTED = true;
- const UNSELECTED = false;
- const [radioState, setRadioState] = useState([SELECTED, UNSELECTED, UNSELECTED, UNSELECTED]);
- const [moderationState, setModeration] = useState(option.moderationOption);
- const [questions, dispatch] = useReducer(QuestionsReducer, {questions: data});
- const [pollNumberStatus] = useState(0);
-
- const handleRadioState = buttonIndex => {
- setRadioState([UNSELECTED, UNSELECTED, UNSELECTED, UNSELECTED]
- .map((_, idx) => (idx === buttonIndex ? SELECTED : UNSELECTED)));
- };
-
- const typeMap = {
- moderation: {state: moderationState, stateHandler: setModeration},
- newQuestion: {state: radioState, stateHandler: handleRadioState},
- popularQuestion: {state: radioState, stateHandler: handleRadioState},
- completeQuestion: {state: radioState, stateHandler: handleRadioState},
- };
-
- useSocketHandler(dispatch);
-
- const handleQuestionDatas = (id, from, to) => {
- const questionData = questions.questions.find(e => e.id === id);
-
- socketClient.emit("question/move", {id, from, to, data: questionData});
- };
-
- const handleStar = id => {
- const toggleMsg = questions.questions.reduce((acc, e) => {
- if (e.isStared) { acc.from.push({id: e.id, isStared: !e.isStared}); }
- if (e.id === id) { acc.to.push({id: e.id, isStared: !e.isStared}); }
- return acc;
- }, {from: [], to: []});
-
- socketClient.emit("question/toggleStar", toggleMsg);
- };
-
- return (
-
- {Object.keys(typeMap)
- .map(e => (
-
- ))}
-
-
- );
-}
-
-function Content({event}) {
- const {events} = useContext(HostContext);
- const {loading, error, data} = useQueryQuestions({
- variables: {EventId: events[0].id},
- });
-
- if (loading) return ;
- if (error) return Error :(
;
-
- return (
- <>
-
- >
- );
-}
-
-export default Content;
diff --git a/frontend/host-app/src/components/CreateEventModal/ButtonField.js b/frontend/host-app/src/components/CreateEventModal/ButtonField.js
index 57a017ce..2c726aa9 100644
--- a/frontend/host-app/src/components/CreateEventModal/ButtonField.js
+++ b/frontend/host-app/src/components/CreateEventModal/ButtonField.js
@@ -12,33 +12,9 @@ const Container = styled.div`
height: 3rem;
`;
-// const CancelTextButton = styled.div`
-// font-size: 1.25rem;
-// color: balck;
-// :hover {
-// font-weight: bold;
-// }
-// width: auto;
-// cursor: pointer;
-// margin: 1rem;
-// `;
-
-// const CreateTextButton = styled.div`
-// font-size: 1.25rem;
-// color: green;
-// :hover {
-// font-weight: bold;
-// }
-// width: auto;
-// cursor: pointer;
-// margin: 1rem;
-// `;
-
function ButtonField({createEvent, onClose}) {
return (
- {/* 취소
- 확인 */}