Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEV] 이미지 데이터 전송 api #41

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/app/api/email/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NextRequest, NextResponse } from 'next/server';

export const POST = async (request: NextRequest) => {
const { headers } = request;

const body = await request.json();

const response = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_ADDRESS}:${process.env.NEXT_PUBLIC_SERVER_PORT}/api/photo-request`,
{
method: 'POST',
headers,
body: JSON.stringify(body),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stringify를 실행하는 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON.stringify를 안쓰면 에러가 났었는데 찾아보니까 JavaScript의 fetch API나 다른 네트워크 요청 라이브러리는 요청 본문을 문자열로 전송해야 한다고 하네요!
아니면 혹시 다른 방법이 있을까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 fetch 메서드에서는 객체를 직접 답을 수 없었네요. 매번 axios를 사용하다보니 잊고있었네요! 그대로 사용하면 될것 같습니다!

},
);
const jsonData = await response.json();
return NextResponse.json(jsonData, {
status: jsonData.code,
});
};
66 changes: 59 additions & 7 deletions src/app/email/page.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,85 @@
'use client';

import { useAtom, useSetAtom } from 'jotai';
import dynamic from 'next/dynamic';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { CompoundModal } from '@/components/Modal/ModalMain';
import PreviousPage from '@/components/PreviousPage';
import { ENTER_EMAIL_TITLE } from '@/constants';
import {
ENTER_EMAIL_TITLE,
GENDER_FEMALE,
GENDER_MALE,
IMG_GENERATED_ERROR_CHECK_MSG,
IMG_GENERATED_ERROR_MSG,
} from '@/constants';
import { ROUTE_TYPES } from '@/interfaces';
import {
errorCheckMessageAtom,
errorMessageAtom,
} from '@/store/atoms/errorMessageAtom';
import { imageUrlsAtom } from '@/store/atoms/imageUrlAtom';
import { selectedBoxAtom } from '@/store/atoms/selectedBoxAtom';
import useModal from '../hooks/useModal';

export default function EmailEnterView() {
export function EmailEnterView() {
const router = useRouter();
const [email, setEmail] = useState('');
const [isEmailValid, setIsEmailValid] = useState(false);
const [genderString] = useAtom(selectedBoxAtom);
const [photoOriginUrls] = useAtom(imageUrlsAtom);
const { isOpen, handleOpenModal, handleCloseModal } = useModal();
const setErrorMessage = useSetAtom(errorMessageAtom);
const setErrorCheckMessage = useSetAtom(errorCheckMessageAtom);
const storedToken = window.sessionStorage.getItem('accessToken') || '';
const gender = genderString === 'female' ? GENDER_FEMALE : GENDER_MALE;
const handleEmailEntered = (e: React.ChangeEvent<HTMLInputElement>) => {
const emailValue = e.target.value;
setEmail(emailValue);

const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
setIsEmailValid(emailPattern.test(emailValue));
};
const submitPhotoData = async () => {
if (storedToken !== '') {
try {
const response = await fetch(`/api/email?code=${storedToken}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${storedToken}`,
},
body: JSON.stringify({
email: email || null,
gender,
photoOriginUrls,
}),
});

const handleEmailSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (isEmailValid) {
router.push(ROUTE_TYPES.WAITING);
if (response.status === 200) {
router.push(ROUTE_TYPES.WAITING);
} else {
setErrorMessage(IMG_GENERATED_ERROR_MSG);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드에서는 에러 메시지는 잘 작성하셨는데 정작 중요한 에러 페이지로 라우팅이 되지 않는것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어웃 그러네요 감사합니다!

setErrorCheckMessage(IMG_GENERATED_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
}
} catch (error) {
setErrorMessage(IMG_GENERATED_ERROR_MSG);
setErrorCheckMessage(IMG_GENERATED_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
}
}
};

const handleMovePage = () => {
const handleEmailSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
await submitPhotoData();
};

const handleMovePage = async () => {
router.push(ROUTE_TYPES.WAITING);
await submitPhotoData();
};

return (
Expand Down Expand Up @@ -105,3 +154,6 @@ export default function EmailEnterView() {
</div>
);
}
export default dynamic(() => Promise.resolve(EmailEnterView), {
ssr: false,
});
Comment on lines +157 to +159
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 동적 import를 위해서 사용한 부분일까요?! 왜 이렇게 하셨는지 궁금합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저번 PR 내용에도 있던 부분인데요,
아래의 코드와 같이 토큰을 불러오는 과정에 window객체가 쓰이는데

const storedToken = window.sessionStorage.getItem('accessToken') || '';

이 코드를 useEffect안에 넣는 것보다 밖으로 빼는게 나을 것 같다고 하셔서 밖으로 빼고 저 코드를 같이 썼습니다!

Copy link
Member

@falconlee236 falconlee236 Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

계속 의문이였던게 왜 storedToken을 계속 세션 스토리지에서 불러오는지 궁금했습니다.
login/page.tsx 파일을 보시면

  useEffect(() => {
    if (storedToken !== '') {
      fetch(
        `${process.env.NEXT_PUBLIC_CLIENT_ADDRESS}:${process.env.NEXT_PUBLIC_CLIENT_PORT}/api/validate?code=${storedToken}`,
      )
        .then((response) => response.json())
        .then(async (data) => {
          if (data.loginSuccess === false) {
            const reissueResponse = await fetch(
              `${process.env.NEXT_PUBLIC_CLIENT_ADDRESS}:${process.env.NEXT_PUBLIC_CLIENT_PORT}/api/reissue?code=${storedToken}`,
            );
            if (reissueResponse.ok) {
              const reissueData = await reissueResponse.json();
              setInsertToken(reissueData.accessToken);
            } else {
              setInsertToken('');
              setErrorMessage(LOGIN_ERROR_MSG);
              setErrorCheckMessage(LOGIN_ERROR_CHECK_MSG);
              router.push(ROUTE_TYPES.ERROR);
            }
          }
        })
        .catch(() => {
          setInsertToken('');
          setErrorMessage(LOGIN_ERROR_MSG);
          setErrorCheckMessage(LOGIN_ERROR_CHECK_MSG);
          router.push(ROUTE_TYPES.ERROR);
        });
    } else {
      setInsertToken(storedToken);
    }
  }, [

맨 마지막에 storedToken을 atom에 넣기 때문에 이후에는 세션 객체를 직접 접근할 필요가 없어서 lazy loading이 필요없습니다.
혹시 이 storeToken을 담는 대상인 tokenAtom의 값을 추출해보신적이 있으신가요? #21
지금 뒤에 있는 모든 코드가 세션스토리지에서 직접 코드를 가져오는데 만약에 tokenAtom에 값이 정상적으로 있다면 이슈 파서 세션 스토리지에서 코드를 가져오는 부분을 전부 제거하고 lazy loading도 삭제하는 것이 좋아보입니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tokenAtom이 있었군요..!
지금 서버가 꺼져있어서 켜지면 수정하겠습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 이슈 파두었습니다
서버 켜질 때 다른 코드 같이 수정하겠습니다!

5 changes: 5 additions & 0 deletions src/app/list/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useSetAtom } from 'jotai/index';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import PreviousPage from '@/components/PreviousPage';
import {
Expand All @@ -16,6 +17,7 @@ import {
} from '@/store/atoms/errorMessageAtom';
import EmptyList from './_components/EmptyList';
import ImageList from './_components/ImageList';
import { ROUTE_TYPES } from '@/interfaces';

export function ListView() {
const [list, setList] = useState<string[]>([]);
Expand All @@ -24,6 +26,7 @@ export function ListView() {
const setErrorCheckMessage = useSetAtom(errorCheckMessageAtom);
const setCreatedPhoto = useSetAtom(createdPhotoAtomWithStorage);
const storedToken = window.sessionStorage.getItem('accessToken') || '';
const router = useRouter();

useEffect(() => {
if (storedToken !== '') {
Expand All @@ -40,11 +43,13 @@ export function ListView() {
} else {
setErrorMessage(NO_GENERATED_IMAGE_MSG);
setErrorCheckMessage(GENERATION_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
}
})
.catch(() => {
setErrorMessage(IMG_LIST_ERROR_MSG);
setErrorCheckMessage(GENERATION_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
})
.finally(() => setLoading(false));
}
Expand Down
2 changes: 2 additions & 0 deletions src/app/waiting/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ export function WaitingView() {
} else {
setErrorMessage(IMG_NOT_READY_MSG);
setErrorCheckMessage(GENERATION_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
}
})
.catch(() => {
setErrorMessage(GENERATION_STATUS_ERROR_MSG);
setErrorCheckMessage(GENERATION_ERROR_CHECK_MSG);
router.push(ROUTE_TYPES.ERROR);
});
}
}, [setErrorCheckMessage, setErrorMessage, storedToken]);
Expand Down
5 changes: 4 additions & 1 deletion src/constants/errorMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ export const GENERATION_ERROR_MSG: string = '프로필을 생성하는 실패했
export const GENERATION_ERROR_CHECK_MSG: string = '이미지를 다시 확인해주세요';
export const UPLOAD_ERROR_MSG: string = '이미지 업로드에 실패했습니다.';
export const UPLOAD_ERROR_CHECK_MSG: string = '이미지를 다시 확인해주세요';

export const IMG_GENERATED_ERROR_CHECK_MSG: string =
'이미지 데이터를 처리하는 중 오류가 발생했습니다';
export const IMG_GENERATED_ERROR_MSG: string =
'정보를 올바르게 입력하셨는지 확인해주세요';
2 changes: 2 additions & 0 deletions src/constants/genderValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const GENDER_MALE = 0;
export const GENDER_FEMALE = 1;
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './modalText';
export * from './guideImage';
export * from './privatePolicyContent';
export * from './image';
export * from './genderValue';