diff --git a/src/components/channel/addNotice.js b/src/components/channel/addNotice.js index 94a3ecefd77f173f95f8c4d0ac0d6c7616addeeb..dc203858807e71c323e7805c4fbbdfdf966d5ef7 100644 --- a/src/components/channel/addNotice.js +++ b/src/components/channel/addNotice.js @@ -1,67 +1,69 @@ import React, {useState} from 'react'; import addNoticeStyles from "./addNotice.module.css"; -const AddNotice=({isOpen, onClose})=>{ - const [formData, setFormData] = useState({ - title:'', - content: '', - image: null -}); - const handleInputChange = (e) => { - const { name, value } = e.target; - setFormData((prevData) => ({ - ...prevData, - [name]: value, - - })); -}; -const handleImageChange = (e) => { - const imageFile = e.target.files[0]; - setFormData((prevDate) => ({ - ...prevDate, - image: imageFile - })); -}; +const AddNotice = ({ isOpen, onClose }) => { + const [formData, setFormData] = useState({ + title: '', + content: '', + image: null + }); + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData((prevData) => ({ + ...prevData, + [name]: value, + })); + }; + const handleImageChange = (e) => { + const imageFile = e.target.files[0]; + setFormData((prevData) => ({ + ...prevData, + image: imageFile + })); + }; + const handleSubmit = async () => { -const handleSubmit = async (e) => { - e.preventDefault(); + if (formData.title === '') { + alert('채널명을 입력해주세요.'); + return; + } else if (formData.content === '') { + alert('소개글을 입력해주세요.'); + return; + } + const data={ + "title":formData.title, + "content":formData.title + } + + try { + const formDataToSend = new FormData(); - if(formData.title === ''){ - alert('채널명을 입력해주세요.'); - return; - } else if(formData.content === ''){ - alert('소개글을 입력해주세요.'); - return; - } - const jsonDataString = JSON.stringify(formData); - try { - const formDataToSend = new FormData(); - - formDataToSend.append('title', formData.title); - formDataToSend.append('content', formData.content); - formDataToSend.append('image', formData.image); + formDataToSend.append('data', JSON.stringify(data)); + formDataToSend.append('image', formData.image) - const response = await fetch('/api/channels/notices', { - method: 'POST', - body: formDataToSend, - }); + const response = await fetch('/api/channels/notices', { + method: 'POST', + body: formDataToSend, + }); - if (response.ok) { - // 성공적으로 모집글이 생성됨 - alert('새로운 공지가 성공적으로 생성되었습니다.'); - } else { - // 오류 처리 - alert('새로운 공지 생성에 실패하였습니다.'); + if (response.ok) { + // 성공적으로 공지가 생성됨 + alert('새로운 공지가 성공적으로 생성되었습니다.'); + onClose(); + } else { + // 오류 처리 + alert('새로운 공지 생성에 실패하였습니다.'); + } + } catch (error) { + console.error('Error:', error); + alert('오류가 발생했습니다. 나중에 다시 시도해주세요.'); } + }; + - onClose(); - } catch (error) { - console.error('Error:', error); - } -}; return( <div> @@ -73,7 +75,7 @@ const handleSubmit = async (e) => { <div className={addNoticeStyles.top}> <div>공지 생성</div> </div> - <form onSubmit={handleSubmit}> + <div className={addNoticeStyles.title}> <label>공지 제목*</label> <input type="text" name="title" onChange={handleInputChange} placeholder="채널명을 입력하세요.(50자 이내)"/> @@ -91,10 +93,10 @@ const handleSubmit = async (e) => { <div className={addNoticeStyles.button}> - <button type="submit" className={addNoticeStyles.save}>저장</button> + <button type="submit" className={addNoticeStyles.save} onClick={handleSubmit}>저장</button> <button type="button" className={addNoticeStyles.cancel} onClick={onClose}>취소</button> </div> - </form> + </div> </div> diff --git a/src/components/channel/channel.js b/src/components/channel/channel.js index 27f1cf3131c033876e9fe6d2a43a38284686cbf8..c8f52cf0300b73b84acedd7a2f357243a6fe1439 100644 --- a/src/components/channel/channel.js +++ b/src/components/channel/channel.js @@ -7,6 +7,10 @@ import Notice from './notice'; const Channel=({data})=>{ const [clickcomponent, setClickComponent] = useState('recruits'); + const [subscribeState, setSubscribeState]=useState(false); + const toggleSubscribe=()=>{ + setSubscribeState(!subscribeState); + } const exampleData={"recruits": [ { "id": 2, @@ -67,7 +71,7 @@ const Channel=({data})=>{ function handleSubscribe() { try { // 실제로 사용하는 API 엔드포인트로 변경하세요. - const apiUrl = `/api/channels/${data.data.userID}`; + const apiUrl = `/api/channels/${data.data.id}`; fetch(apiUrl, { method: 'PUT', @@ -83,8 +87,14 @@ function handleSubscribe() { return response.json(); }) .then(data => { - alert('구독이 완료되었습니다.') - console.log('Subscription successful:', data); + if(subscribeState===false){ + alert('구독이 완료되었습니다.'); + } + else{ + alert('구독 취소가 완료되었습니다.'); + } + toggleSubscribe(); + }) .catch(error => { alert('구독을 실패하였습니다'); @@ -107,18 +117,20 @@ function handleSubscribe() { <div className={channel_styles.channelbox}> <div className={channel_styles.channelpicture}> - <img src="/channel_test.png"></img> + {data.data && data.data.thumbnailImgPath && <img src={data.data.thumbnailImgPath} alt="Thumbnail"></img>} </div> <div className={channel_styles.channel_info}> - <img className={channel_styles.channelIcon} src='/id.png'></img> - <div className={channel_styles.channelTitle}>사랑유치원</div> - <div className={channel_styles.info}>구독자 35명 모집글 12개</div> - <div className={channel_styles.description}>사랑이 넘치는 사랑유치원입니다~!선생님, 학부모를 위한 페이지입니다.</div> - <button onClick={handleSubscribe}>구독중</button> - - + {data.data && data.data.title && ( + <div> + {data.data && data.data.iconImgPath && <img className={channel_styles.channelIcon} src={data.data.iconImgPath} alt="Icon"></img>} + <div className={channel_styles.channelTitle}>{data.data.title}</div> + <div className={channel_styles.info}>구독자 {data.data.followerNum}명 모집글{data.data.recruitNum}개</div> + <div className={channel_styles.description}>{data.data.content}</div> + <button onClick={handleSubscribe}>{subscribeState ? '구독 취소' : '구독중'}</button> + </div> + )} </div> <div className={channel_styles.component}> <div className={channel_styles.channeloption}> @@ -131,15 +143,13 @@ function handleSubscribe() { <div className={channel_styles.part}> <div className={channel_styles.recruitsPart}> - {clickcomponent === 'recruits' && ( - exampleData.recruits.map(item => ( - <PageItem props={item} /> - )) - )} + {clickcomponent === 'recruits' && data.recruits && data.recruits.map(item => ( + <PageItem key={item.id} props={item} /> + ))} </div> <div className={channel_styles.noticePart}> - {clickcomponent === 'notices' && ( - <Notice /> + {clickcomponent === 'notices' && data.notices && ( + <Notice data={data} /> )} </div> </div> diff --git a/src/components/channel/createChannel.js b/src/components/channel/createChannel.js index 09e956c2ea18044f2250d7ebdd753ffb9c1c7633..ee94cfa67d4a1db07958cb371d0a8ad7e5ca0675 100644 --- a/src/components/channel/createChannel.js +++ b/src/components/channel/createChannel.js @@ -10,8 +10,8 @@ function CreateChannel({ isOpen, onClose }){ const handleInputChange = (e) => { const { name, value } = e.target; setFormData((prevData) => ({ - ...prevData.data, - [name]: value, + ...prevData, + [name]: value, })); }; @@ -20,10 +20,10 @@ function CreateChannel({ isOpen, onClose }){ const handleSubmit = async (e) => { e.preventDefault(); - if(formData.data.title === ''){ + if(formData.title === ''){ alert('채널명을 입력해주세요.'); return; - } else if(formData.data.content === ''){ + } else if(formData.content === ''){ alert('소개글을 입력해주세요.'); return; } @@ -32,7 +32,7 @@ function CreateChannel({ isOpen, onClose }){ - const response = await fetch('/api/channel', { + const response = await fetch('/api/channels', { method: 'POST', body: JSON.stringify(formData), }); @@ -63,7 +63,7 @@ function CreateChannel({ isOpen, onClose }){ <div>내 채널 생성</div> </div> - <form onSubmit={handleSubmit}> + <div className={createChannelStyles.title}> <label>채널명*</label> <input type="text" name="title" onChange={handleInputChange} placeholder="채널명을 입력하세요.(50자 이내)"/> @@ -80,10 +80,10 @@ function CreateChannel({ isOpen, onClose }){ <div className={createChannelStyles.button}> - <button type="submit" className={createChannelStyles.save}>저장</button> + <button type="submit" className={createChannelStyles.save} onClick={handleSubmit}>저장</button> <button type="button" className={createChannelStyles.cancel} onClick={onClose}>취소</button> </div> - </form> + </div> </div> )} diff --git a/src/components/channel/existingChannel.js b/src/components/channel/existingChannel.js index 114d2a1f9958ffc7a691abdf789a939b8c73ea8b..98fc8dca4012a92fc0296907d6502194ef6549d7 100644 --- a/src/components/channel/existingChannel.js +++ b/src/components/channel/existingChannel.js @@ -8,7 +8,7 @@ import ChangeIcon from './iconModal'; import ChangePicture from './pictureModal'; import { AuthContext } from '../../App'; -const ExistingChannel=({isOpen, onClose, myChannelData})=>{ +const ExistingChannel=({isOpen, onClose, data})=>{ const [IsModal, setIsModal]=useState(false); const { userData } = useContext(AuthContext); const [changePicture, setChangePicture]=useState(''); @@ -83,7 +83,7 @@ const ExistingChannel=({isOpen, onClose, myChannelData})=>{ <button className={existingStyles.closeBtn} onClick={onClose}>X</button> <div className={existingStyles.bringModal}> - <Channel data={myChannelData} ></Channel> + <Channel data={data} ></Channel> </div> </div> diff --git a/src/components/channel/iconModal.js b/src/components/channel/iconModal.js index ae5233ce9280dc686ccd13aa133bd4d811b37474..ef5a1e39ab82ee3d826953700c770239c2d12f94 100644 --- a/src/components/channel/iconModal.js +++ b/src/components/channel/iconModal.js @@ -18,7 +18,7 @@ const ChangeIcon=({ isOpen, onClose})=> { // 여기에 서버의 프로필 수정 API 엔드포인트를 입력합니다. - const response = await fetch('api/mypage/icon', { + const response = await fetch('api/channels/icon', { method: 'POST', body: formData, // 필요에 따라 다른 헤더 설정이나 인증 토큰 등을 추가할 수 있습니다. @@ -34,7 +34,7 @@ const ChangeIcon=({ isOpen, onClose})=> { const successData = await response.json(); console.log(successData); alert('채널 프로필 수정을 성공하였습니다.'); - + onClose(); // 프로필 수정 후 로직 (예: 화면 갱신 등) } catch (error) { console.error(error.message); diff --git a/src/components/channel/notice.js b/src/components/channel/notice.js index 4d0afc670cc533c450d0b28ae48d73707a30e059..144e222958fc6d7e28c0289f51dfbf96d025dce0 100644 --- a/src/components/channel/notice.js +++ b/src/components/channel/notice.js @@ -1,86 +1,26 @@ import React, { useState } from "react"; import noticeStyles from './notice.module.css'; -const Notice=()=>{ - const props={ - "data":{ - "userID":5, - "title": "채널명", - "content": "소개글", - "imagePath": "uploads/recruits/default.jpg", - "channelState":1, - "follower":13, - "recruitsNum":10 - }, - "recruits": [ - { - "id": 2, - "title": "[방탈출]홍대 거상 2인구합니다", - "content": "나이, 성별 상관없습니다. 즐겁게 하실 분 구해요~", - "peopleNum": 4, - "participateNum": 1, - "regionFirst": "강원도", - "regionSecond": "양양군", - "startDate": "2023-10-17", - "endDate": "2023-12-31", - "timeCategory": "D", - "startTime": "13:00:00", - "endTime": "16:00:00", - "state": "Recruiting", - "Writer": "jk", - "imagePath": "uploads/recruits/default.jpg" - }, - { - "id": 2, - "title": "[방탈출]홍대 거상 2인구합니다", - "content": "나이, 성별 상관없습니다. 즐겁게 하실 분 구해요~", - "peopleNum": 4, - "participateNum": 1, - "regionFirst": "강원도", - "regionSecond": "양양군", - "startDate": "2023-10-17", - "endDate": "2023-12-31", - "timeCategory": "TBD", - "startTime": null, - "endTime": null, - "state": "Recruiting", - "Writer": "jk", - "imagePath": "uploads/recruits/default.jpg" - } - ], - "notices": - [ - { - "title":"title1", - "content":"content1", - "image":"uploads/recruits/default.jpg" - }, - { - "title":"title2", - "content":"content2", - "image":"uploads/recruits/default.jpg" - } - ] - -} +const Notice=(data)=>{ + console.log(data); return( <div> <div> <span className={noticeStyles.notices}> - - {props.notices.map((notice) => ( + {data.data.notices && + data.data.notices.map((notice) => ( <div className={noticeStyles.noticeBlock}> <div className={noticeStyles.profile}> - <img className={noticeStyles.channelimg} src="/id.png"></img> - <span className={noticeStyles.channelName}>사랑유치원</span> + <img className={noticeStyles.channelimg} src={data.data.data.iconImgPath}></img> + <span className={noticeStyles.channelName}>{data.data.data.title}</span> </div> <div className={noticeStyles.noticeContent}> <div className={noticeStyles.title}>{notice.title}</div> <p>{notice.content}</p> - <img src={notice.noticeimage} alt={`Image for ${notice.title}`} /> + <img src={notice.imgPath} style={{ width: '700px', height: 'auto' }} alt={`Image for ${notice.title}`} /> </div> </div> ))} diff --git a/src/components/channel/pictureModal.js b/src/components/channel/pictureModal.js index 70f7a5daa4e8d90dd04c63409a06a96736818de5..b73c2769404247ae66668c5e87cbe04181e2aa44 100644 --- a/src/components/channel/pictureModal.js +++ b/src/components/channel/pictureModal.js @@ -18,7 +18,7 @@ const ChangePicture=({ isOpen, onClose})=> { // 여기에 서버의 프로필 수정 API 엔드포인트를 입력합니다. - const response = await fetch('api/mypage/thumbnail', { + const response = await fetch('api/channels/thumbnail', { method: 'POST', body: formData, // 필요에 따라 다른 헤더 설정이나 인증 토큰 등을 추가할 수 있습니다. @@ -34,6 +34,7 @@ const ChangePicture=({ isOpen, onClose})=> { const successData = await response.json(); console.log(successData); alert('채널 배경 사진 수정을 성공하였습니다.'); + onClose(); // 프로필 수정 후 로직 (예: 화면 갱신 등) } catch (error) { diff --git a/src/components/infiniteScroll.js b/src/components/infiniteScroll.js index 6cd5a45612c7847b16ed6e7d0a44985a654f111f..611e991a049abfbcaa26409b47b39c8c18ea343f 100644 --- a/src/components/infiniteScroll.js +++ b/src/components/infiniteScroll.js @@ -20,13 +20,25 @@ function InfiniteScroll(props){ setMinId(jsonData['minId']); if(page==='channels'){ - if(newData.length>0){ - const components=newData.map((item)=>( - <ChannelItem data={item}/> - )); - setItems(prevItem => [...prevItem, ...components]); + if (newData.length > 0) { + const components = []; + for (let i = 0; i < newData.length; i += 2) { + const component = ( + + <div className={InfiniteScrollStyles.itemContainer}> + <div className={InfiniteScrollStyles.firstitem}> + <ChannelItem props={newData[i]} /></div> + <div className={InfiniteScrollStyles.seconditem}>{i + 1 < newData.length && <ChannelItem props={newData[i + 1]} />}</div> + </div> + + ); + components.push(component); + console.log('ne', newData[i]); + } + setItems((prevItem) => [...prevItem, ...components]); } - }else { + }else { + if(newData.length > 0) { const components = newData.map((item) => ( <PageItem data={item}/> @@ -61,18 +73,26 @@ function InfiniteScroll(props){ setMinId(jsonData['minId']); if(page==='channels'){ - if(newData.length>0){ - for (let i = 0; i < newData.length; i += 2) { - const component = ( - <div key={i} className="channelItemRow"> - <ChannelItem data={newData[i]} /> - {i + 1 < newData.length && <ChannelItem data={newData[i + 1]} />} - </div> - ); - setItems((prevItem) => [...prevItem, component]); - } + + if (newData.length > 0) { + const components = []; + for (let i = 0; i < newData.length; i += 2) { + const component = ( + + <div className={InfiniteScrollStyles.itemContainer}> + <div className={InfiniteScrollStyles.firstitem}> + <ChannelItem props={newData[i]} /></div> + <div className={InfiniteScrollStyles.seconditem}>{i + 1 < newData.length && <ChannelItem props={newData[i + 1]} />}</div> + </div> + + ); + components.push(component); + console.log('ne', newData[i]); + } + setItems((prevItem) => [...prevItem, ...components]); } - }else { + }else { + if(newData.length > 0) { const components = newData.map((item) => ( <PageItem data={item}/> diff --git a/src/components/mypage/my_editModal.js b/src/components/mypage/my_editModal.js index 3ea129a90cfec8c180eac5f490dfe53fb9e04a24..3b3971972f39c47e282da8b58f437bb41208ad61 100644 --- a/src/components/mypage/my_editModal.js +++ b/src/components/mypage/my_editModal.js @@ -15,6 +15,24 @@ const MypageEdittModal=({ isOpen, closeModal, onSave, user})=> { onSave({ image, nickname, statusMessage }); closeModal(); }; + const handlecheckBtn = async ()=>{ + try{ + const response = await fetch(`/api/users/mypage/${nickname}`); + const data = await response.json(); + + if (response.status === 200){ + alert(data.message); + alert("사용 가능한 닉네임입니다.") + + }else{ + alert('이미 존재하는 닉네임입니다.'); + + } + + } catch(error){ + console.log('Error during fetch:', error); + } +} return ( @@ -39,7 +57,9 @@ const MypageEdittModal=({ isOpen, closeModal, onSave, user})=> { </div> <div className={editmodal_styles.editBlock}> + <button className={editmodal_styles.check} onClick={handlecheckBtn}>중복 확인</button> <label>새로운 닉네임</label> + <input type="text" className={editmodal_styles.newnickname} @@ -47,7 +67,7 @@ const MypageEdittModal=({ isOpen, closeModal, onSave, user})=> { placeholder={user.nickname} /> - + <label>새로운 상태 메시지</label> <input diff --git a/src/components/mypage/my_editModal.module.css b/src/components/mypage/my_editModal.module.css index 27643bc4aab8640e5aac6a133df6ab9458d0b7a7..d9a3acf3605122b6a135b8dcd0c159c05aadf213 100644 --- a/src/components/mypage/my_editModal.module.css +++ b/src/components/mypage/my_editModal.module.css @@ -127,4 +127,18 @@ color: #ADA4A5; margin-bottom: 18px; -} \ No newline at end of file +} +.check{ + margin-left:75%; + font-size: 12px; + background-color:#9FB8AB; + border:none; + color: white; + width: 60px; + height: 23px; + cursor: pointer; + border: none; + border-radius: 5px; + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); /* 그림자 추가 */ + transition: background-color 0.3s, color 0.3s, transform 0.3s; +} diff --git a/src/pages/login.js b/src/pages/login.js index be69f021a69fd930d62ad59dce5ded3690f9f886..f60b603921a57c171873cf1ce7507834a715d8b0 100644 --- a/src/pages/login.js +++ b/src/pages/login.js @@ -41,6 +41,7 @@ const Login=({onLogin })=>{ } else{ console.log("Login failed", data); + alert('해당 정보의 유저가 존재하지 않습니다.'); } }catch(error){ alert('해당 정보의 유저가 존재하지 않습니다.'); diff --git a/src/pages/mypage.js b/src/pages/mypage.js index 38c6d7d0629dc03d40a6536c81e4dfae51bb3f6a..56471e28704e1c040dfaa7c0601ffd3edd72482c 100644 --- a/src/pages/mypage.js +++ b/src/pages/mypage.js @@ -55,14 +55,25 @@ const Mypage=()=>{ const handleProfileUpdate = async ({ image, nickname, statusMessage }) => { try { // FormData 객체를 생성하고 데이터를 추가합니다. + if(image === ''){ + alert('닉네임을 입력해주세요.'); + return; + } else if(statusMessage===''){ + alert('상태 메시지를 입력해주세요.'); + return; + } + const data={ + "nickname":nickname, + "statusMessage":statusMessage + } + const formData = new FormData(); - formData.append('image', image); - formData.append('nickname', nickname); - formData.append('statusMessage', statusMessage); + formData.append('data', JSON.stringify(data)); + formData.append('image', image) // 여기에 서버의 프로필 수정 API 엔드포인트를 입력합니다. - const response = await fetch('api/mypage/profile', { - method: 'POST', + const response = await fetch('api/mypage', { + method: 'PUT', body: formData, // 필요에 따라 다른 헤더 설정이나 인증 토큰 등을 추가할 수 있습니다. }); @@ -159,8 +170,7 @@ const Mypage=()=>{ <div className={mypage_styles.profileText}> <h2 className={mypage_styles.nickname}>{userData.nickname}</h2> - <p className={mypage_styles.message}>생각하는 대로 살지 않으면 - 결국 사는 대로 생각하게 된다.</p> + <p className={mypage_styles.message}>{userData.statusMessage}</p> </div> </div> </div>