@@ -8,35 +8,50 @@ import styled from "styled-components";
88import recipientsService from "../../api/services/recipientsService" ; // get 요청
99
1010const CardContainer = styled . div `
11- width: min(100%, 1200px);
12- margin-inline: auto;
13- padding: 0 24px;
14- box-sizing: border-box;
11+ margin: auto;
1512 display: flex;
1613 align-items: center;
1714 justify-content: center;
1815
19- @media (max-width: 1248px) {
20- padding: 0 24px;
16+ padding: 100px 24px;
17+ width: 100%;
18+ box-sizing: border-box;
19+ @media (max-width: 768px) {
20+ background-attachment: scroll;
2121 }
2222` ;
2323
2424const DivWrap = styled . div `
2525 display: grid;
2626 grid-template-columns: repeat(3, 1fr);
27- grid-template-rows: repeat(2, auto);
2827 gap: 28px;
29- padding-top: 112px;
30-
28+
3129 @media (max-width: 1248px) {
3230 grid-template-columns: repeat(2, 1fr);
3331 }
3432
33+ opacity: ${ ( { isLoaded } ) => ( isLoaded ? 1 : 0 ) } ;
34+ transition: opacity 0.5s ease-in-out;
35+ ` ;
36+
37+ const BackgroundWrap = styled . div `
38+ background-image: ${ ( { backgroundImageURL } ) =>
39+ backgroundImageURL
40+ ? `linear-gradient(180deg, rgba(0, 0, 0, 0.54) 0%, rgba(0, 0, 0, 0.54) 100%), url(${ backgroundImageURL } )`
41+ : "ffffff" } ;
42+ background-color: ${ ( { bgColor } ) => bgColor || "#ffffff" } ;
43+ min-height: calc(100vh - 65px);
44+ background-size: cover;
45+ background-repeat: no-repeat;
46+ background-position: center top;
47+ background-attachment: fixed;
48+
3549 @media (max-width: 768px) {
3650 grid-template-columns: 1fr;
3751 }
3852` ;
3953
54+
4055const BackgroundWrap = styled . div . withConfig ( {
4156 shouldForwardProp : ( prop ) =>
4257 ! [ "bgColor" , "backgroundImageURL" ] . includes ( prop ) ,
@@ -49,105 +64,80 @@ const BackgroundWrap = styled.div.withConfig({
4964 background-position: center;
5065` ;
5166
67+ const colorMap = {
68+ beige : "#FFE2AD" ,
69+ purple : "#ECD9FF" ,
70+ blue : "#B1E4FF" ,
71+ green : "#D0F5C3" ,
72+ } ;
73+
74+
5275function RollingPaperDetailPage ( ) {
5376 const { id } = useParams ( ) ;
54- const postData = null ;
5577 const [ loading , setLoading ] = useState ( true ) ;
56- const [ isRecipientLoading , setIsRecipientLoading ] = useState ( true ) ;
57- const [ page , setPage ] = useState ( 1 ) ;
5878 const [ recipientData , setRecipientData ] = useState ( { } ) ;
5979
6080 const [ messages , setMessages ] = useState ( [ ] ) ;
61- const colorMap = {
62- beige : "#FFE2AD" ,
63- purple : "#ECD9FF" ,
64- blue : "#B1E4FF" ,
65- green : "#D0F5C3" ,
66- } ;
67-
68- // 무한 스크롤 때 사용합니다다
69- const observer = useRef ( null ) ;
70-
71- // API 호출 함수
72- const fetchMessages = async ( page ) => {
73- try {
74- const limit = 10 ;
75- const offset = ( page - 1 ) * limit ;
76-
77- const [ messagesResponse , recipientResponse ] = await Promise . all ( [
78- recipientsService . getRecipientsMessages ( id , limit , offset ) ,
79- recipientsService . getRecipientsId ( id ) ,
80- ] ) ;
81+ const [ nextUrl , setNextUrl ] = useState ( null ) ;
82+ const [ isLoaded , setIsLoaded ] = useState ( false ) ;
83+ const lastMessageRef = useRef ( null ) ;
84+ const isFetchingRef = useRef ( false ) ;
8185
82- setMessages ( ( prevMessages ) => {
83- const newMessages = messagesResponse . data . results ;
84-
85- const uniqueMessages = [
86- ...prevMessages ,
87- ...newMessages . filter (
88- ( message ) =>
89- ! prevMessages . some ( ( prevMessage ) => prevMessage . id === message . id )
90- ) ,
91- ] ;
92-
93- return uniqueMessages ;
94- } ) ;
86+ useEffect ( ( ) => {
87+ async function fetchInitialData ( ) {
88+ try {
89+ const [ messagesResponse , recipientResponse ] = await Promise . all ( [
90+ recipientsService . getRecipientsMessages ( id , 5 , 0 ) ,
91+ recipientsService . getRecipientsId ( id ) ,
92+ ] ) ;
93+ setMessages ( messagesResponse . data . results ) ;
94+ setNextUrl ( messagesResponse . data . next ) ;
95+ setRecipientData ( recipientResponse . data ) ;
96+ } catch ( error ) {
97+ console . error ( "Error fetching messages:" , error ) ;
98+ } finally {
99+ setLoading ( false ) ;
100+ }
101+ }
102+ if ( id ) fetchInitialData ( ) ;
103+ } , [ id ] ) ;
95104
96- setRecipientData ( recipientResponse . data ) ;
105+
97106
98- setLoading ( false ) ;
99- setIsRecipientLoading ( false ) ;
107+ // 메시지 로드 함수
108+ const loadMoreMessages = async ( ) => {
109+ if ( ! nextUrl || isFetchingRef . current ) return ;
110+ isFetchingRef . current = true ;
111+ try {
112+ const response = await axios . get ( nextUrl ) ;
113+ setMessages ( ( prev ) => [ ...prev , ...response . data . results ] ) ;
114+ setNextUrl ( response . data . next ) ;
100115 } catch ( error ) {
101- setLoading ( false ) ;
116+ console . error ( "Error loading messages:" , error ) ;
117+ } finally {
118+ isFetchingRef . current = false ;
102119 }
103120 } ;
104121
105- // 메시지 로드 함수
106- const loadMoreMessages = ( ) => {
107- if ( loading ) return ;
108- setLoading ( true ) ;
109- setPage ( ( prev ) => prev + 1 ) ;
110- } ;
111-
112122 useEffect ( ( ) => {
113- if ( ! id ) return ;
114-
115- fetchMessages ( page ) ;
116- } , [ page , loading ] ) ;
117-
118- // 밑에 무한 스크롤 할 수 있음
119- useEffect ( ( ) => {
120- if ( ! observer . current ) {
121- observer . current = new IntersectionObserver (
122- ( entries ) => {
123- if ( entries [ 0 ] . isIntersecting ) {
124- loadMoreMessages ( ) ;
125- }
126- } ,
127- { rootMargin : "100px" }
128- ) ;
129- }
123+ if ( ! lastMessageRef . current ) return ;
124+ const observer = new IntersectionObserver (
125+ ( [ entry ] ) => entry . isIntersecting && loadMoreMessages ( ) ,
126+ { root : null , rootMargin : "100px" }
127+ ) ;
128+ observer . observe ( lastMessageRef . current ) ;
129+ return ( ) => observer . disconnect ( ) ;
130+ } , [ messages ] ) ;
130131
131- const lastCardElement = document . getElementById ( "last-card" ) ;
132- if ( lastCardElement ) {
133- observer . current . observe ( lastCardElement ) ;
134- }
135-
136- return ( ) => {
137- if ( observer . current && lastCardElement ) {
138- observer . current . unobserve ( lastCardElement ) ;
139- }
140- } ;
141- } , [ ] ) ;
142132
143133 useEffect ( ( ) => {
144134 setTimeout ( ( ) => setIsLoaded ( true ) , 100 ) ;
145135 } , [ ] ) ;
146136
147137 return (
148138 < BackgroundWrap
149- bgColor = { colorMap [ recipientData ?. backgroundColor ] ?? colorMap . beige }
150- backgroundImageURL = { recipientData ?. backgroundImageUrl ?? null }
139+ bgColor = { colorMap [ recipientData ?. backgroundColor ] ?? "#ffffff" }
140+ backgroundImageURL = { recipientData ?. backgroundImageURL ?? null }
151141 >
152142 < InformationBar
153143 name = { recipientData ?. name ?? "" }
@@ -159,15 +149,11 @@ function RollingPaperDetailPage() {
159149 setRecipientData = { setRecipientData }
160150 />
161151 < CardContainer >
162- < DivWrap >
163- < Card postData = { postData } />
164- { messages ?. map ( ( message ) => (
165- < div key = { message . id } >
166- < CardWrite
167- key = { message . id }
168- message = { message }
169- fontFamily = { message . font }
170- />
152+ < DivWrap isLoaded = { isLoaded } >
153+ < Card postData = { null } />
154+ { messages . map ( ( message , index ) => (
155+ < div key = { message . id } ref = { index === messages . length - 1 ? lastMessageRef : null } >
156+ < CardWrite message = { message } fontFamily = { message . font } />
171157 </ div >
172158 ) ) }
173159 { messages ?. length > 0 && < div id = "last-card" > </ div > }
@@ -177,4 +163,4 @@ function RollingPaperDetailPage() {
177163 ) ;
178164}
179165
180- export default RollingPaperDetailPage ;
166+ export default RollingPaperDetailPage ;
0 commit comments