handleNavigation('/dictionary')}>
+
checkAuthenticationAndNavigate('/dictionary')}
+ >
법률 용어 사전
-
handleNavigation('/price')}>
+
navigate('/price')}>
가격
diff --git a/react-app/src/components/MainSection/MainSection.jsx b/react-app/src/components/MainSection/MainSection.jsx
index 1cb8ce8..560d76f 100644
--- a/react-app/src/components/MainSection/MainSection.jsx
+++ b/react-app/src/components/MainSection/MainSection.jsx
@@ -4,14 +4,13 @@ import { css } from '@emotion/react';
const mainSectionStyle = css`
display: flex;
flex-wrap: wrap;
- width: 100vw;
- min-height: 600px; /* 최소 높이 */
+ width: 100%; /* 가로폭을 뷰포트에 맞게 조정 */
+ flex-grow: 1; /* 가능한 공간을 채우도록 설정 */
word-break: break-all;
white-space: normal;
@media (max-width: 768px) {
max-width: 768px;
-
}
`;
diff --git a/react-app/src/components/Map/Map.jsx b/react-app/src/components/Map/Map.jsx
new file mode 100644
index 0000000..95e5f3f
--- /dev/null
+++ b/react-app/src/components/Map/Map.jsx
@@ -0,0 +1,89 @@
+import React, { useEffect, useState } from 'react';
+import { fetchNearbyLegalInstitutions } from '../../apis/legalInstitution';
+import { FaMapMarkerAlt } from 'react-icons/fa';
+
+const Map = () => {
+ const [institutions, setInstitutions] = useState([]);
+ const [latitude, setLatitude] = useState(null);
+ const [longitude, setLongitude] = useState(null);
+
+ useEffect(() => {
+ const getCurrentPosition = () => {
+ if (navigator.geolocation) {
+ navigator.geolocation.getCurrentPosition(
+ (position) => {
+ setLatitude(position.coords.latitude);
+ setLongitude(position.coords.longitude);
+ },
+ (error) => {
+ console.error(error);
+ }
+ );
+ } else {
+ console.error('브라우저에서 위치를 불러올 수 없습니다.');
+ }
+ };
+ getCurrentPosition();
+ }, []);
+
+ useEffect(() => {
+ const getNearbyInstitutions = async () => {
+ if (latitude && longitude) {
+ try {
+ const data = await fetchNearbyLegalInstitutions(longitude, latitude);
+ setInstitutions(data.legalInstitutions);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+ };
+
+ getNearbyInstitutions();
+ }, [latitude, longitude]);
+
+ const handleInstitutionClick = (name, lat, lng) => {
+ const url = `https://map.kakao.com/link/map/${encodeURIComponent(
+ name
+ )},${lat},${lng}`;
+ window.open(url, '_blank');
+ };
+
+ return (
+
+
🔎 내 근처 법률 기관 찾기
+
+ 클릭하여 지도에서 위치를 확인하세요🌍
+
+
+ {institutions.map((institution) => (
+ -
+ handleInstitutionClick(
+ institution.placeName,
+ institution.latitude,
+ institution.longitude
+ )
+ }
+ >
+
+
+
+ {institution.placeName}
+
+
+ {institution.roadAddressName}
+
+
+ {institution.phoneNumber || '전화번호 없음'}
+
+
+
+ ))}
+
+
+ );
+};
+
+export default Map;
diff --git a/react-app/src/components/Pay/Pay.jsx b/react-app/src/components/Pay/Pay.jsx
index 1c8fd6a..a97d6ee 100644
--- a/react-app/src/components/Pay/Pay.jsx
+++ b/react-app/src/components/Pay/Pay.jsx
@@ -9,7 +9,6 @@ const Pay = ({ amount, setAmount, buyerName, setBuyerName, onPay }) => {
justify-content: center;
align-items: center;
width: 100%;
- height: 600px;
background-color: var(--sub);
gap: 15px;
flex-shrink: 0;
diff --git a/react-app/src/components/Price/Price.jsx b/react-app/src/components/Price/Price.jsx
index 3051a8e..05d39ad 100644
--- a/react-app/src/components/Price/Price.jsx
+++ b/react-app/src/components/Price/Price.jsx
@@ -36,7 +36,6 @@ const containerStyle = css`
justify-content: center;
align-items: center;
width: 100%;
- height: 600px;
background-color: var(--sub);
gap: 15px;
flex-shrink: 0;
diff --git a/react-app/src/components/Word/WordModal.jsx b/react-app/src/components/Word/WordModal.jsx
index 76099a6..c33b856 100644
--- a/react-app/src/components/Word/WordModal.jsx
+++ b/react-app/src/components/Word/WordModal.jsx
@@ -5,7 +5,10 @@ const WordModal = ({ isOpen, term, onClose }) => {
return (
-
+
{term.termName}
-
{term.description}
+
);
diff --git a/react-app/src/hooks/useFetchUserInfo.js b/react-app/src/hooks/useFetchUserInfo.js
index c192293..ec9aea8 100644
--- a/react-app/src/hooks/useFetchUserInfo.js
+++ b/react-app/src/hooks/useFetchUserInfo.js
@@ -1,10 +1,16 @@
import { useState, useEffect } from 'react';
import accessToken from '../apis/accessToken';
-const useFetchUserInfo = (ipAddress, springbootApiPort) => {
+const useFetchUserInfo = () => {
const [userInfo, setUserInfo] = useState(null);
const [loading, setLoading] = useState(true);
+ const ipAddress = import.meta.env.VITE_IP_ADDRESS;
+ const springbootApiPort = import.meta.env.VITE_SPRINGBOOT_HOST_PORT;
+
+ // API URL fetching
+ const updateUrl = (path) => `http://${ipAddress}:${springbootApiPort}${path}`;
+
useEffect(() => {
const token = accessToken.getToken();
if (!token) {
@@ -12,10 +18,10 @@ const useFetchUserInfo = (ipAddress, springbootApiPort) => {
} else {
fetchUserInfo(token);
}
- }, [ipAddress, springbootApiPort]);
-
+ }, []);
+
const fetchUserInfo = async (token) => {
- const apiUrl = `http://${ipAddress}:${springbootApiPort}/api/user/userinfo`;
+ const apiUrl = updateUrl('/api/user/userinfo');
try {
const response = await fetch(apiUrl, {
@@ -46,7 +52,7 @@ const useFetchUserInfo = (ipAddress, springbootApiPort) => {
};
const requestAccessTokenFromRefreshToken = async () => {
- const apiUrl = `http://${ipAddress}:${springbootApiPort}/api/auth/token`; // 재발급 API 경로
+ const apiUrl = updateUrl('/api/auth/token');
try {
const response = await fetch(apiUrl, {
diff --git a/react-app/src/pages/Chat/Chat.jsx b/react-app/src/pages/Chat/Chat.jsx
index ed7ea11..6088095 100644
--- a/react-app/src/pages/Chat/Chat.jsx
+++ b/react-app/src/pages/Chat/Chat.jsx
@@ -3,39 +3,41 @@ import { fetchPrediction, fetchChatAnswer } from '../../apis/chat';
import GraphRenderer from '../../components/GraphRenderer/GraphRenderer';
import MarkdownRenderer from '../../components/MarkdownRenderer/MarkdownRenderer';
import { FaSpinner } from 'react-icons/fa';
+import useFetchUserInfo from '../../hooks/useFetchUserInfo';
+import Map from '../../components/Map/Map';
const Chat = () => {
- const [messages, setMessages] = useState([
- {
- user: 'AI',
- text: '안녕하세요. 당신만을 위한 법률 상담 서비스 오픈로이어입니다! 어떤 문제로 어려움을 겪고 계신가요?',
- },
- ]);
+ const [messages, setMessages] = useState([]);
const [inputMessage, setInputMessage] = useState('');
const [isPredictionLoading, setIsPredictionLoading] = useState(false);
const [isAnswerLoading, setIsAnswerLoading] = useState(false);
-
const messagesEndRef = useRef(null);
-
- // 스크롤
- const scrollToBottom = () => {
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
- };
+ const { userInfo, loading } = useFetchUserInfo();
useEffect(() => {
- scrollToBottom();
- }, [messages]);
+ if (!loading && userInfo) {
+ setMessages([
+ {
+ user: 'AI',
+ text: `안녕하세요. ${userInfo.nickname}님👋 당신만을 위한 법률 상담 서비스 오픈로이어입니다! 어떤 문제로 어려움을 겪고 계신가요?`,
+ },
+ ]);
+ }
+ }, [userInfo, loading]);
// 메시지 전송 처리
const sendMessage = async (e) => {
e.preventDefault();
-
const userMessage = { user: 'User', text: inputMessage };
setMessages((prev) => [...prev, userMessage]);
setInputMessage('');
- handlePredictionAPI(inputMessage);
- handleChatAnswerAPI(inputMessage);
+ // API 호출 순서대로 대기
+ await handlePredictionAPI(inputMessage);
+ await handleChatAnswerAPI(inputMessage);
+
+ // Map
+ setMessages((prev) => [...prev, { user: 'Map', jsx:
}]);
};
// 승소 확률 API 호출
@@ -86,9 +88,9 @@ const Chat = () => {
};
return (
-
+
{/* 메시지 섹션 */}
-
+
{messages.map((msg, index) => (
{
}`}
>
{
{/* 메시지 입력 창 */}
-