Skip to content

Commit

Permalink
GM-267 중고 거래 아이템 목록 조회
Browse files Browse the repository at this point in the history
  • Loading branch information
kgh2120 committed Feb 21, 2023
1 parent 7e7ce3a commit 65ee2b5
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 34 deletions.
15 changes: 15 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 @@ -23,6 +23,7 @@
"react-bootstrap": "^2.7.2",
"react-daum-postcode": "^3.1.1",
"react-dom": "^18.2.0",
"react-intersection-observer": "^9.4.2",
"react-redux": "^8.0.5",
"react-router-dom": "^6.8.1",
"redux": "^4.2.1",
Expand Down
32 changes: 32 additions & 0 deletions src/api/usedItemApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";
import {BASE_URL, USED_ITEM_POST_LIST} from "../util/Api";
import {getCookie} from "../util/Cookie";
import {UsedItemPost, UsedItemPostListArgs} from "../model/usedItemPost";

export const usedItemApi = createApi({
reducerPath: 'usedItemApi',
baseQuery: fetchBaseQuery({
baseUrl: BASE_URL,
prepareHeaders: (headers, { getState, endpoint, type, forced }) => {
headers.set("Authorization", 'Bearer ' + getCookie("access_token"));

const townToken = getCookie("X-TOWN-TOKEN");
if(townToken)
headers.set("X-TOWN-TOKEN", townToken);
return headers
}
}),
endpoints: (builder) => ({
getUsedItem: builder.query<UsedItemPost[],UsedItemPostListArgs>({
query: (UsedItemPostListArgs) => ({
url: USED_ITEM_POST_LIST,
method : `GET`,
params: {pageNum : UsedItemPostListArgs.pageNum,
requestTime : UsedItemPostListArgs.requestTime}
})
})

})
})


17 changes: 16 additions & 1 deletion src/component/main/home/UsedItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styled from "styled-components";
import theme from "../../../theme";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {compareLocalDateTimeToNow} from "../../../util/LocalDateTimeConverter";
import {faBox} from "@fortawesome/free-solid-svg-icons";

const UsedItemWrapper = styled.div`
display: flex;
Expand All @@ -17,6 +18,10 @@ const UsedItemImageWrapper = styled.div`
border-radius: 10px;
border: 1px solid ${theme.color.gray};
margin-right: 25px;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0,0,0,0.1);
`
const UsedItemImage = styled.img`
Expand Down Expand Up @@ -60,6 +65,11 @@ const Divider = styled.hr`
background-color: ${theme.color.gray};
`

const BlankImage = styled(FontAwesomeIcon)`
font-size: 40px;
color: rgba(0,0,0,0.6);
`

interface UsedItemProps {
postId: string;
imgUrl: string;
Expand All @@ -71,11 +81,16 @@ interface UsedItemProps {
}

function UsedItem({postId, imgUrl, title,address, createdAt, price, interestCount}: UsedItemProps) {

return (
<>
<UsedItemWrapper>
<UsedItemImageWrapper>
<UsedItemImage src={imgUrl} alt={"haha"}/>
{imgUrl !== null ? <UsedItemImage src={imgUrl} alt={"haha"}/> :
<>
<BlankImage icon={faBox}/>
</>
}
</UsedItemImageWrapper>
<UsedItemContent>
<UsedItemTitle>{title.length > 24 ? `${title.substring(0,24)}...` : title}</UsedItemTitle>
Expand Down
59 changes: 47 additions & 12 deletions src/component/main/home/UsedItemList.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,70 @@
import styled from "styled-components";
import UsedItem from "./UsedItem";
import {useState} from "react";
import {createDummyUsedItemData, UsedItemPostList} from "../../../util/Dummy";
import {createDummyUsedItemData} from "../../../util/Dummy";
import {usedItemApi} from "../../../api/usedItemApi";
import {useEffect, useRef, useState} from "react";
import {currentTime} from "../../../util/CurrentTime";
import {useInView} from "react-intersection-observer";
import {ADD, useUsedItemSelector} from "../../../store/usedItem";
import {useDispatch} from "react-redux";

const UsedItemListWrapper = styled.div`
margin: 20px;
`


function UsedItemList() {
const dummy_data = createDummyUsedItemData();


const [pageNum ,setPageNum] = useState<number>(0)
const [ref, inView] = useInView();
const usedItem = useUsedItemSelector();
const dispatch = useDispatch();


const [now,setNow]=useState<string>(currentTime());
let query = usedItemApi.useGetUsedItemQuery({
pageNum,
requestTime : now
});
useEffect(() => {
if (inView && !query.isLoading && query.data !== null) {
setPageNum(prev => prev+1);
}
}, [inView])




useEffect(()=>{
if (query.isSuccess) {
dispatch(ADD(query.data));
}
},[query.data ,pageNum])

if(query.isLoading) return <>Now Loading...</>


return (
<>

<UsedItemListWrapper>
{
dummy_data.map(d => {

usedItem.map(d => {
return <UsedItem
key={d.postListRetirveResponse.previewPost.postId}
imgUrl={d.postListRetirveResponse.previewPost.representPictureUrl}
postId={d.postListRetirveResponse.previewPost.postId}
title={d.postListRetirveResponse.previewPost.title}
address={d.postListRetirveResponse.previewPost.address}
createdAt={d.postListRetirveResponse.previewPost.createdAt}
price={d.postListRetirveResponse.previewPost.price}
interestCount={d.postListRetirveResponse.previewPostCount.interestCount}
key={d.previewPost.postId}
imgUrl={d.previewPost.representPictureUrl}
postId={d.previewPost.postId}
title={d.previewPost.title}
address={d.previewPost.address}
createdAt={d.previewPost.createdAt}
price={d.previewPost.price}
interestCount={d.previewPostCount.interestCount}
/>
})
}
<p ref={ref}></p>
</UsedItemListWrapper>

</>
Expand Down
25 changes: 25 additions & 0 deletions src/model/usedItemPost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface UsedItemPost{
previewPost : PreviewPost
previewPostCount : PreviewPostCount
}


export interface PreviewPost{
postId : string;
representPictureUrl : string;
title : string;
address : string;
createdAt : string;
price : number;
tradeStatus:string,
isHide: boolean,
}
export interface PreviewPostCount {
interestCount : number;
viewCount : number;
}

export interface UsedItemPostListArgs{
pageNum: number,
requestTime: string,
}
7 changes: 6 additions & 1 deletion src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ import {configureStore} from "@reduxjs/toolkit";
import {modeSlice} from "./mode";
import {townApi} from "../api/townApi";
import {townTokenSlice} from "./towntoken";
import {usedItemApi} from "../api/usedItemApi";
import {usedItemSlice} from "./usedItem";

export const store = configureStore({
reducer: {
mode : modeSlice.reducer,
townToken: townTokenSlice.reducer,
[townApi.reducerPath]: townApi.reducer
usedItem: usedItemSlice.reducer,
[townApi.reducerPath]: townApi.reducer,
[usedItemApi.reducerPath]: usedItemApi.reducer
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(townApi.middleware)
.concat(usedItemApi.middleware)
})

export type RootState = ReturnType<typeof store.getState>
24 changes: 24 additions & 0 deletions src/store/usedItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {createSlice} from "@reduxjs/toolkit";
import {useSelector} from "react-redux";
import {RootState} from "./index";
import {UsedItemPost} from "../model/usedItemPost";

const initialState: UsedItemPost[] = [];

export const usedItemSlice = createSlice({
name: 'usedItem',
initialState,
reducers: {
ADD: (state,action) => {
Array.prototype.push.apply(state, action.payload);
return state;
},
CLEAR: () => {
return initialState;
}

},
})
export const useUsedItemSelector = () =>
useSelector((state: RootState) => state.usedItem)
export const {ADD,CLEAR } = usedItemSlice.actions;
7 changes: 7 additions & 0 deletions src/util/CurrentTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function currentTime() {
let cur = new Date();
return `${cur.getFullYear()}-${cur.getMonth() + 1 < 10 ? "0"+(cur.getMonth() + 1)
:cur.getMonth() + 1}-${cur.getDate()<10?"0"+cur.getDate():cur.getDate()}T${cur.getHours()
<10? "0"+cur.getHours():cur.getHours()}:${cur.getMinutes()<10?
"0"+cur.getMinutes():cur.getMinutes()}:${cur.getSeconds()<10?"0"+cur.getSeconds():cur.getSeconds()}`
}
24 changes: 5 additions & 19 deletions src/util/Dummy.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import {UsedItemPostList} from "../model/usedItemPost";

interface UsedItemPost{
previewPost : {
postId : string;
representPictureUrl : string;
title : string;
address : string;
createdAt : string;
price : number;
}
previewPostCount : {
interestCount : number;
viewCount : number;
}
}
interface UsedItemPostList{
postListRetirveResponse : UsedItemPost
}

const createDummyUsedItemData = () => {
const dummy:UsedItemPostList[] = [];
Expand All @@ -28,7 +12,9 @@ const createDummyUsedItemData = () => {
title : `테스트 ${i+1}`,
address : `서초 ${i+1}동`,
createdAt : `2023-02-15T22:52:49.954301600`,
price : 30000
price : 30000,
tradeStatus: "예약중",
isHide:false,
},
previewPostCount : {
interestCount : 10,
Expand All @@ -42,4 +28,4 @@ const createDummyUsedItemData = () => {
}

export {createDummyUsedItemData};
export type { UsedItemPostList };

2 changes: 1 addition & 1 deletion src/util/LocalDateTimeConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function compareLocalDateTimeToNow(localDateTime:string) : string{
if(now.getTime() < target.getTime())
console.error("현재보다 더 이후에 생성된 게시글이 존재할 수 없습니다.")
if(gap < 60)
return `${gap}초 전`
return `${Math.floor(gap)}초 전`
if(gap < 3600)
return `${Math.floor(gap/60)}분 전`
if(gap < 3600 * 24)
Expand Down

0 comments on commit 65ee2b5

Please sign in to comment.