Skip to content

Commit

Permalink
Merge branch 'main' into Feature/#13
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyujenius authored Sep 28, 2024
2 parents 98dd9e1 + fffbfda commit 7027c7b
Show file tree
Hide file tree
Showing 38 changed files with 1,572 additions and 257 deletions.
1 change: 1 addition & 0 deletions .github/workflows/front-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:

- name: 환경 변수 설정
run: |
echo "REACT_APP_BACKEND_SERVER_STOMP_URL=${{ secrets.REACT_APP_BACKEND_SERVER_STOMP_URL }}" >> .env
echo "REACT_APP_BACKEND_SERVER_URL=${{ secrets.REACT_APP_BACKEND_SERVER_URL }}" >> .env
echo "REACT_APP_REGION=${{ secrets.REACT_APP_REGION }}" >> .env
echo "REACT_APP_ACCESS_KEY_ID=${{ secrets.REACT_APP_ACCESS_KEY_ID }}" >> .env
Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@testing-library/user-event": "^13.5.0",
"aos": "^2.3.4",
"axios": "^1.7.7",
"js-cookie": "^3.0.5",
"lucide-react": "^0.445.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
4 changes: 3 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<div id="root"></div>
<div id="root">
<div id="portal-root"></div>
</div>
22 changes: 17 additions & 5 deletions src/api/instance.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from 'axios';
import { applyInterceptors } from './interceptor';
import axios from "axios";
import { config } from "../config/config";
// import { applyInterceptors } from "./interceptor";

//.env로 숨긴 url 주소 (backend 주소 <-> front 주소)
const BASE_URL = process.env.REACT_APP_BACKEND_SERVER_URL;
Expand All @@ -11,8 +12,19 @@ const defaultInstance = axios.create({

//디폴트 주소에서 하나 더 붙은 인스턴스를 제공해준다.
const exampleInstance = axios.create(defaultInstance.defaults);
exampleInstance.defaults.baseURL += '/example';
exampleInstance.defaults.baseURL += "/example";

applyInterceptors(exampleInstance);
// '/api/v1/rooms' 경로를 위한 인스턴스
const roomsInstance = axios.create({
baseURL: `${BASE_URL}/api/v1/rooms`,
withCredentials: config.withCredentials,
});

// '/api/v1/rooms' 경로를 위한 인스턴스
const oauth2 = axios.create({
baseURL: `${BASE_URL}/oauth2/authorization/kakao
`,
});
// applyInterceptors(exampleInstance);

export { defaultInstance, exampleInstance };
export { defaultInstance, exampleInstance, roomsInstance, oauth2 };
10 changes: 6 additions & 4 deletions src/api/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export const sendRequest = async (instance, method, url, data = {}) => {
try {
//instance, method, 추가 url, data 순으로 파라미터를 집어넣어서 데이터를 보내주며, 통일된 request를 보내준다.
const response = await instance[method](url, data);
console.log(`✅${instance.defaults.baseURL} -[${method}] success :`, response);
console.log(
`✅${instance.defaults.baseURL} -[${method}] success :`,
response
);
return response;
} catch (error) {
//에러를 케치헀을 경우엔 동일한 형식으로 에러를 cnosole에 띄워준다.
Expand All @@ -19,7 +22,6 @@ export const sendRequest = async (instance, method, url, data = {}) => {
`error_status_text: `,
error.response.statusText
);
window.location.href = '/error';
throw error;
}
};
Expand All @@ -28,6 +30,6 @@ export const sendRequest = async (instance, method, url, data = {}) => {
export const createUrl = (path, params = {}) => {
const query = Object.entries(params)
.map(([key, value]) => `${key}=${value}`)
.join('&');
return `${path}${query ? `?${query}` : ''}`;
.join("&");
return `${path}${query ? `?${query}` : ""}`;
};
28 changes: 26 additions & 2 deletions src/api/room/room.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
import { defaultInstance } from "../instance";
import { roomsInstance } from "../instance";
import { sendRequest } from "../request";

export const getInitialRoomData = async (roomId) => {
sendRequest(defaultInstance, "get", `/rooms/${roomId}/data`);
sendRequest(roomsInstance, "get", `/rooms/${roomId}/data`);
};

//TODO- 나중에 실제 roomId로 바꿔야 함.
export const sendAvartar = async (avatar_base64, uuid) => {
sendRequest(roomsInstance, "post", `/avatar`, { avatar_base64, uuid });
};
//TODO- 나중에 실제 roomId로 바꿔야 함.
export const makeRoom = async (avartar, roomId) => {
sendRequest(roomsInstance, "post", ``);
};

export const getRoom = async (avartar, roomId) => {
sendRequest(roomsInstance, "get", ``);
};

export const makeReview = async (avartar, roomId) => {
sendRequest(roomsInstance, "post", `/1/review`);
};
export const getReview = async (avartar, roomId) => {
sendRequest(roomsInstance, "post", `/1/review`);
};

export const getQuestions = async (avartar, roomId) => {
sendRequest(roomsInstance, "post", `/1/questions`);
};
17 changes: 11 additions & 6 deletions src/api/user/user.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useSetRecoilState } from 'recoil';
import { exampleState } from '../../recoil/user/userRecoilState';
import { sendRequest } from '../request';
import { exampleInstance } from '../instance';
import { useSetRecoilState } from "recoil";
import { exampleState } from "../../recoil/user/userRecoilState";
import { sendRequest } from "../request";
import { exampleInstance } from "../instance";

export const useExampleHook = () => {
//recoil은 전역 변수 상태 관리 라이브러리로 사용을 한다.
const setExampleState = useSetRecoilState(exampleState);

const exampleGet = async exampleData => {
const exampleGet = async (exampleData) => {
//디폴트 주소 + /example 에다가 API 요청을 할 건데, get 요청을 할 거다 + 그 뒤에 붙는 주소는 / 이다 .
const response = await sendRequest(exampleInstance, 'get', '/', exampleData);
const response = await sendRequest(
exampleInstance,
"get",
"/",
exampleData
);

//전역 변수에 대해서는 response.data 라는 코드를 통해서 데이터를 저렇게 설정해주고, 설정해준 전역 변수이기에 바로 View 단에서 가져와서 사용한다. -> Prop Drilling 쉽게 해결해준다.

Expand Down
85 changes: 62 additions & 23 deletions src/components/chat/cloud/QuestionCloud.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useMemo } from "react";
import React, { useState, useMemo, useCallback } from "react";
import styles from "./QuestionCloud.module.css";
import { QUESTION_LIFETIME } from "../../../constants/questionLifeTime";
import useChattingRoom from "../../../stomp/chat/useChattingRoom";
import chatCloudImage from "../../../assets/images/chat/chatCloudImage.png";
import Portal from "../../common/Portal";

const getOpacity = (remainingTime) => {
if (typeof remainingTime !== "number" || isNaN(remainingTime)) {
return 0.3; // 기본 최소 opacity 값 반환
return 0.3;
}
const maxOpacity = 1;
const minOpacity = 0.3;
Expand All @@ -16,26 +16,65 @@ const getOpacity = (remainingTime) => {
return Math.max(minOpacity, Math.min(maxOpacity, opacity));
};

export const QuestionCloud = React.memo(({ question }) => {
const { handleSendLike } = useChattingRoom();

const cloudStyle = useMemo(
() => ({
opacity: getOpacity(question.remainingTime),
backgroundImage: `url(${chatCloudImage})`,
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
backgroundPosition: "center",
}),
[question.remainingTime]
);

return (
<div className={styles.questionCloud} style={cloudStyle}>
<p>{question.title}</p>
</div>
);
});
export const QuestionCloud = React.memo(
({ question, handleSendLike, style, ...props }) => {
const [isModalOpen, setIsModalOpen] = useState(false);

const cloudStyle = useMemo(
() => ({
...style,
opacity: getOpacity(question.remainingTime),
backgroundImage: `url(${chatCloudImage})`,
}),
[question.remainingTime, style]
);

const toggleModal = useCallback(() => {
setIsModalOpen((prev) => !prev);
}, []);

const onLikeClick = useCallback(
(e) => {
e.stopPropagation();
if (typeof handleSendLike === "function") {
handleSendLike(question.questionId);
} else {
console.error("handleSendLike is not a function");
}
},
[handleSendLike, question.questionId]
);

return (
<>
<div
className={styles.questionCloud}
style={cloudStyle}
onClick={toggleModal}
{...props}
>
<p>{question.title}</p>
</div>
{isModalOpen && (
<Portal>
<div className={styles.modalOverlay} onClick={toggleModal}>
<div
className={styles.modalContent}
onClick={(e) => e.stopPropagation()}
>
<h2 className={styles.modalTitle}>{question.title}</h2>
<p className={styles.modalBody}>{question.content}</p>
<button onClick={onLikeClick} className={styles.likeButton}>
👍 공감 ({question.like_count || 0})
</button>
</div>
</div>
</Portal>
)}
</>
);
}
);

QuestionCloud.displayName = "QuestionCloud";

Expand Down
99 changes: 88 additions & 11 deletions src/components/chat/cloud/QuestionCloud.module.css
Original file line number Diff line number Diff line change
@@ -1,20 +1,97 @@
.questionCloud {
width: 10%;
height: 5vw;
background-color: hsla(0, 0%, 100%, 0);
margin-bottom: 10px;
background-repeat: no-repeat;
position: absolute;
width: 150px;
height: 100px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;

/* 추가된 부분: flexbox를 사용하여 내부 콘텐츠 중앙 정렬 */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
user-select: none;
}

.questionCloud p {
margin: 0; /* 기본 마진 제거 */
text-align: center; /* 텍스트 중앙 정렬 */
font-size: 14px;
text-align: center;
margin: 0;
padding: 10px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
max-width: 90%;
}

.questionCloud:hover {
transform: scale(1.05);
}

.modalOverlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}

.modalContent {
background-color: white;
padding: 20px;
border-radius: 10px;
max-width: 80%;
max-height: 80%;
overflow-y: auto;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.modalTitle {
font-size: 20px;
margin-bottom: 10px;
}

.modalBody {
font-size: 16px;
line-height: 1.5;
margin-bottom: 20px;
}

.likeButton {
background-color: #4caf50;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s;
}

.likeButton:hover {
background-color: #45a049;
}

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

.questionCloud {
animation: fadeIn 0.5s ease-out;
}
5 changes: 1 addition & 4 deletions src/components/chat/input/ChattingInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ export const ChattingInput = () => {
const content = value.slice(colonIndex + 1).trim();

if (title && content) {
handleSendQuestion({
title: title,
content: content,
});
handleSendQuestion({ title, content } );
console.log({
title: title,
content: content,
Expand Down
Loading

0 comments on commit 7027c7b

Please sign in to comment.