Skip to content
32 changes: 29 additions & 3 deletions pages/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BackgroundImage from '@components/common/BackgroundImage';
import { DefaultButton } from '@components/common/DefaultButton';
import { DefaultHeader } from '@components/common/DefaultHeader';
import { HeaderBackButton } from '@components/common/HeaderBackButton';
import QuerySuspenseErrorBoundary from '@components/hoc/QuerySuspenseErrorBoundary';
Expand All @@ -10,6 +11,7 @@ import ProfileTab from '@components/profile/ProfileTab';
import styled from '@emotion/styled';
import { GetServerSideProps } from 'next';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useRef } from 'react';
import { useScroll } from 'react-use';

Expand All @@ -28,18 +30,27 @@ const Container = styled.div`
const ProfileInfoContainer = styled.div`
display: flex;
flex-direction: column;
height: 200px;
width: 100%;
`;

const RightAreaContainer = styled.div`
display: flex;
height: 100%;
justify-content: flex-end;
padding: 0 8px;
align-items: center;
cursor: pointer;
`;

const ProfileLoginButtonWrapper = styled.div`
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
height: 120px;
padding: 0 30px;
`;

const RightArea = () => {
return (
<Link href={'/setting'}>
Expand All @@ -51,14 +62,29 @@ const RightArea = () => {
const Profile = () => {
const scrollRef = useRef(null);
const { y } = useScroll(scrollRef);
const { push } = useRouter();
const onClickLoginButton = () => {
push('/signin');
};

return (
<Container ref={scrollRef}>
<DefaultHeader leftArea={<HeaderBackButton />} rightArea={<RightArea />} />
<BackgroundImage scrollY={y} src="/images/profile/profilebackground.jpg" height={200} />
<ProfileInfoContainer>
<QuerySuspenseErrorBoundary
errorFallback={ProfileError}
errorFallback={({ error }) => {
if (error?.response?.status === 401) {
return (
<ProfileLoginButtonWrapper>
<DefaultButton
text="로그인 하러 가기"
onClick={onClickLoginButton}
/>
</ProfileLoginButtonWrapper>
);
}
}}
suspenseFallback={<ProfileLoading />}
>
<ProfileInfo />
Expand All @@ -79,7 +105,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
return {
redirect: {
permanent: false,
destination: '/profile?category=situation&role=HOST',
destination: '/profile?category=situation&role=VOLUNTEER&status=RECRUIT',
},
};
}
Expand Down
24 changes: 24 additions & 0 deletions src/api/getPartyCurrentSituation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import defaultRequest from 'src/lib/axios/defaultRequest';
import { GetPartyCurrentSituationResponse } from 'types/party';

type GetPartyCurrentSituationRequestRole = 'HOST' | 'VOLUNTEER';
export type GetPartyCurrentSituationRequestStatus = 'RECRUIT' | 'RECRUIT_FINISH' | 'PARTY_FINISH';
interface GetPartyCurrentSituationParameter {
page: number;
size: number;
role: GetPartyCurrentSituationRequestRole;
status: GetPartyCurrentSituationRequestStatus;
}

export const API_GET_PARTY_STATUS_KEY = '/api/party/party-status';

const getPartyStatus = async (params: GetPartyCurrentSituationParameter) => {
const { data } = await defaultRequest.get<
InfinitePaginationDataType<'partyList', GetPartyCurrentSituationResponse>
>(API_GET_PARTY_STATUS_KEY, {
params,
});
return data;
};

export default getPartyStatus;
29 changes: 16 additions & 13 deletions src/api/getPartyJoin.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import variableAssignMent from "@utils/variableAssignment";
import defaultRequest from "src/lib/axios/defaultRequest";
import { PartyJoinResponse } from "types/party/join/PartyJoinResponse";
import variableAssignMent from '@utils/variableAssignment';
import defaultRequest from 'src/lib/axios/defaultRequest';
import { PartyJoinResponse } from 'types/party/join/PartyJoinResponse';

interface getPartyJoinParameter {
role: string;
type GetPartyJoinRequestRole = 'HOST' | 'VOLUNTEER';
interface GetPartyJoinParameter {
page: number;
size: number;
role: GetPartyJoinRequestRole;
}

export const API_GET_PARTY_JOIN_KEY = "/api/party/party-join?role={{role}}";
export const API_GET_PARTY_JOIN_KEY = '/api/party/party-join';

const getPartyJoin = async ({
role,
}: getPartyJoinParameter): Promise<PartyJoinResponse[]> => {
const { data } = await defaultRequest.get(
variableAssignMent(API_GET_PARTY_JOIN_KEY, { role: role })
);
return data;
const getPartyJoin = async (params: GetPartyJoinParameter) => {
const { data } = await defaultRequest.get<
InfinitePaginationDataType<'partyList', PartyJoinResponse>
>(API_GET_PARTY_JOIN_KEY, {
params,
});
return data;
};

export default getPartyJoin;
33 changes: 14 additions & 19 deletions src/api/getPartyMainPage.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
import variableAssignMent from "@utils/variableAssignment";
import defaultRequest from "src/lib/axios/defaultRequest";
import { PartyListResponse } from "types/common/PartyListResponse";
import variableAssignMent from '@utils/variableAssignment';
import defaultRequest from 'src/lib/axios/defaultRequest';
import { PartyListResponse } from 'types/common/PartyListResponse';

interface GetMainPageParameter {
longitude: number;
latitude: number;
lastPartyId?: number;
size?: number;
longitude: number;
latitude: number;
page?: number;
size?: number;
}

export const API_GET_MAIN_PAGE =
"/api/main";
export const API_GET_MAIN_PAGE = '/api/main';

const getMainPageData = async (params: GetMainPageParameter) => {
const { data } = await defaultRequest.get<
InfinitePaginationDataType<"partyList", PartyListResponse>
>(
API_GET_MAIN_PAGE, {
params:{
...params
}
}
);
return data;
const { data } = await defaultRequest.get<
InfinitePaginationDataType<'partyList', PartyListResponse>
>(API_GET_MAIN_PAGE, {
params,
});
return data;
};

export default getMainPageData;
20 changes: 0 additions & 20 deletions src/api/getPartyStatus.ts

This file was deleted.

21 changes: 0 additions & 21 deletions src/api/getProfileReviewList.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/api/getReviewList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import defaultRequest from 'src/lib/axios/defaultRequest';
import { GetReviewListResponse } from 'types/review';

export type ReviewListRequestType = 'SENDER' | 'RECEIVER';

interface GetReviewListParameter {
reviewType: ReviewListRequestType;
page: number;
size: number;
}

export const API_GET_REVIEW_LIST_KEY = '/api/review';

const getReviewList = async (params: GetReviewListParameter) => {
const { data } = await defaultRequest.get<
InfinitePaginationDataType<'reviewGetResList', GetReviewListResponse>
>(API_GET_REVIEW_LIST_KEY, {
params,
});
return data;
};

export default getReviewList;
12 changes: 8 additions & 4 deletions src/components/common/card/ReviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import styled from '@emotion/styled';
import dayjs from 'dayjs';
import Image from 'next/image';
import { useRouter } from 'next/router';
import React, { FC, MouseEventHandler, useCallback, useState } from 'react';
import React, { FC, MouseEventHandler, useCallback, useMemo, useState } from 'react';
import { GetReviewListResponse } from 'types/review';

interface ReviewCardProps {
Expand Down Expand Up @@ -87,6 +87,10 @@ const ReviewCard: FC<ReviewCardProps> = ({ data, onClickEditButton, onClickDelet
push(`/review/${data.reviewId}`);
};

const formattedImage = useMemo(() => {
return data.reviewImg.map((image) => ({ id: crypto.randomUUID(), imageUrl: image }));
}, [data.reviewImg]);

return (
<Container>
<ContentsSection>
Expand Down Expand Up @@ -137,9 +141,9 @@ const ReviewCard: FC<ReviewCardProps> = ({ data, onClickEditButton, onClickDelet
<ReviewTextContainer>
<DefaultText text={data.content} size={13} />
</ReviewTextContainer>
{data.reviewImg.length > 0 ? (
{formattedImage.length > 0 ? (
<ReviewImageContainer>
{data.reviewImg.map((reviewImage, index) => {
{formattedImage.map((reviewImage, index) => {
const handler = () => {
onClickImage(index);
};
Expand Down Expand Up @@ -173,7 +177,7 @@ const ReviewCard: FC<ReviewCardProps> = ({ data, onClickEditButton, onClickDelet
<DefaultModalContainer>
<PhotoGallery
initialSlideNumber={selectedImageIndex}
imageData={data.reviewImg}
imageData={formattedImage}
onClickCloseIcon={onCloseGallery}
/>
</DefaultModalContainer>
Expand Down
75 changes: 41 additions & 34 deletions src/components/hoc/QuerySuspenseErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,48 @@
import DefaultError from "@components/common/DefaultError";
import DefaultLoading from "@components/common/DefaultLoading";
import { Suspense } from "@suspensive/react";
import { QueryErrorResetBoundary } from "@tanstack/react-query"; // (*)
import { FC, PropsWithChildren, ReactEventHandler } from "react";
import { ErrorBoundary } from "react-error-boundary";
import DefaultError from '@components/common/DefaultError';
import DefaultLoading from '@components/common/DefaultLoading';
import { Suspense } from '@suspensive/react';
import { QueryErrorResetBoundary } from '@tanstack/react-query'; // (*)
import { AxiosError } from 'axios';
import { FC, PropsWithChildren, ReactEventHandler } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

interface QuerySuspenseErrorBoundaryProps {
children: React.ReactNode;
suspenseFallback?: React.ReactNode | string;
errorFallback?: (
resetErrorBoundary: ReactEventHandler<HTMLButtonElement>
) => React.ReactNode;
children: React.ReactNode;
suspenseFallback?: React.ReactNode | string;
errorFallback?: ({
resetErrorBoundary,
error,
}: {
resetErrorBoundary: ReactEventHandler<HTMLButtonElement>;
error?: AxiosError;
}) => React.ReactNode;
}

const QuerySuspenseErrorBoundary: FC<
PropsWithChildren<QuerySuspenseErrorBoundaryProps>
> = ({ children, suspenseFallback, errorFallback }) => {
return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ resetErrorBoundary }) =>
errorFallback ? (
errorFallback(resetErrorBoundary)
) : (
<DefaultError onClick={resetErrorBoundary} />
)
}
>
<Suspense.CSROnly fallback={suspenseFallback ?? <DefaultLoading />}>
{children}
</Suspense.CSROnly>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
);
const QuerySuspenseErrorBoundary: FC<PropsWithChildren<QuerySuspenseErrorBoundaryProps>> = ({
children,
suspenseFallback,
errorFallback,
}) => {
return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={({ resetErrorBoundary, error }) =>
errorFallback ? (
errorFallback({ resetErrorBoundary, error })
) : (
<DefaultError onClick={resetErrorBoundary} />
)
}
>
<Suspense.CSROnly fallback={suspenseFallback ?? <DefaultLoading />}>
{children}
</Suspense.CSROnly>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
);
};

export default QuerySuspenseErrorBoundary;
Loading