Skip to content

Commit

Permalink
[#49] �fix : 로그인 오류 수정 및 로그아웃 모달추가 (#56)
Browse files Browse the repository at this point in the history
* Release test 0.0.1 (#41)

* feat: 기본 컴포넌트 생성

* feat: 지도 구현

* Update README.md

* Update README.md

* Update README.md

* feat: marker 이미지 추가

* feat: only icon marker 디자인 완료

* feat: name marker 디자인 완료

* refactor: 지도에 보이는 방식 변경

* feat: 업체 리스트 디자인 완료

하트 상태 useState로 관리

* Create pull_request_template.md

* feat: 검색창 구현

* feat: 픽한업체 디자인

* refactor: 겹치는 코드 분리

size 인수로 받는 함수 만들어서 그 사이즈에 맞게 이미지 코드 반환

* feat: 필터 디자인 완료

* feat: 스크롤바 디자인

* style: store list 디자인 변경사항 반영

* style: 이름 마커 디자인 수정

* feat: 라우터 설정

* feat: 가게 정보 디자인 완료

* style: heart -> 👍 으로 디자인 변경

* fix: 지도 안뜨는 문제 해결

* refact: 공통 컴포넌트 분리 (필터, 검색창)

* refact: 이름 마커 컴포넌트 공통으로 리팩토링

* refact: children props 넘겨주는 방식 변경

* refact: icon marker 코드 하나로 분리

* chore: 해당하는 마커만 지도에 띄우기

* fix: 우선 error는 안뜨도록 수정

* fix: 같은 매장 여러번 클릭할 수 있도록 수정

* fix: 기본값 설정

* docs: PR template update

체크리스트 추가

* [#17] feat: 헤더 #17 (#21)

* feat : 화면 구현

* feat : 헤더 구현

* style : 알림 아이콘 추가

* [#3] feat: 제휴가게 페이지  (#13)

* feat: component 구성

* style: 타이틀 디자인 구현 완성

* style: 필터, 검색, 버튼 디자인 완료

* style: store 컴포넌트 디자인 완료

* style: 변경된 디자인 반영

* feat: 가게 검색 모달 창 디자인 완료

* feat: 공통 버튼 컴포넌트 분리

* feat: [제휴가게 조회] 컴포넌트 구성

* style: [제휴가게 조회] 화면 디자인 완료

* feat: 스탬프 모달 완성

* feat: 조건 박스 추가

* refact: modal 폴더 생성

* feat: 제휴 종료 모달 완성

* fix: 버튼 스타일링 변경

* refact: && 연산자로 변경

* [#22] feat: 가게 찾기 페이지 API 연결 (#25)

* fix: img 오류 수정

* feat: api data 형식 추가 및 적용

* feat: 가게 전체 조회 api 연결

* style: 제목 div 깨짐 수정

* feat: map type filter 설정

* feat: filter API 설정

* feat: 위도 경도 연결

* refact: 전체 필터용으로 api 방식 수정

* feat: 픽한업체 필터 설정

* feat: 검색어 필터 연결

/contact 부분 props 수정 필요

* feat: storeInfo와 filter 예외처리

storeInfo가 열려있는 상태로 filter를 누르면 지도 내용이 누른 filter를 반영하도록 변경

* chore: 사용안하는 코드 삭제

* feat: 픽한 업체 API 연결

* feat: 가게 상세 정보 조회 API 연결

* fix: 선택한 가게 기본값 설정

* feat: 이름 마커 zindex 설정

* feat: 맨 위 데이터 "이름 마커" 로 뜨는 조건

* style: 디자인적 요소 수정

cursor 포인터로, 도보 시간 0분으로 안뜨도록, 픽한 업체 글자 눌렀을때도 클릭 되도록

* [#24] feat : 팝업관리, 쿠폰관리, 마이페이지, 대시보드 화면 구현 (#29)

* feat : 화면 구현

* feat : 헤더 구현

* feat : 로그인 모달 구현

* feat : 회원가입 화면 구현

* style : header 알림 아이콘 추가

* style : 로그인 모달 세부 디자인 수정

* feat : api 설정 및 부분 연동

* feat : 로그인 액세스토큰 세션 스토리지에 저장

* feat : 대시보드 레이아웃 잡기

* feat : 첫번째 박스 구현

* feat : 두번째 박스 구현

* feat : 대시보드 화면 완성

* feat : 쿠폰관리 리스트 화면 구현

* feat : 팝업관리 화면 구현

* feat : popup api 연동

* feat : 쿠폰 등록 화면 구현

* feat : 비었을때 보여줄 컴포넌트 삽입

* feat : 팝업등록 화면 구현

* feat : 마이페이지 화면 구현

* feat : 팝업관리 화면 구현, 일부 api 연동

* [#16] feat: 팝업관리 페이지 디자인 구현 (#31)

* feat: 가게 검색 모달 창 디자인 완료

* feat: 스탬프 모달 완성

* feat: 조건 박스 추가

* refact: modal 폴더 생성

* feat: 컴포넌트 구성

* feat: 팝업 관리 페이지 디자인 완료

* feat: 환경 설정

package json 수정, base api 수정

* [#28] feat: 제휴가게 API 연결 (#37)

* fix: icon 에러 수정

* feat: 제휴가게리스트 API 연결

* feat: 라우터 연결

* fix: img 오류 수정

* feat: 제휴가게 상세 API 연결

* feat: modal api 연결 및 디자인 수정

* style: checkbox 적용

* [#39] fix : 서브메뉴 디자인 변경 및 링크추가 (#40)

* style : 팝업 / 쿠폰 관리 삭제박스 추가

* fix : 헤더 디자인 수정 및 링크 추가

---------

Co-authored-by: Ethan Lim <[email protected]>

* fix : 타입 오류 수정

* fix: error 수정

* fix : 타입 오류 수정

* fix: modal error

* fix: npm run build error

* fix: build error 해결

* fix: 위치 에러 수정

* feat : 가게 대시보드 구현

* style : 대시보드 가게 메뉴 추가

* feat : 쿠폰 삭제 api 연동

* feat : 가게 조회 api 및 훅 추가

* fix : 가게 가져오기 훅 수정

* fix : 로그인 여부에 따라서 로그인/로그아웃

* fix : 로그인 여부 세션 스토리지 말고, 전역변수에서 가져옴

* fix : 헤더 로그인 관련 하이드레이션 오류 수정

* fix : 로그인 하이드레이션 에러 해결

* fix : 로그인 시 리로드

* feat : 헤더 로그아웃 모달 추가

---------

Co-authored-by: SuJin <[email protected]>
  • Loading branch information
Ethan-KerryFather and SujinKim1127 authored Nov 23, 2023
1 parent fda535f commit 28db27b
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 115 deletions.
16 changes: 1 addition & 15 deletions components/hooks/useCouponData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface CouponContent {
couponStore: string;
couponCondition: Array<string>;
couponQuantity: number;
couponId: number;
}

export const useCouponData = () => {
Expand All @@ -33,18 +34,3 @@ export const useCouponData = () => {
return { coupons };
};

// // 예시 데이터
// const exData: CouponContent[] = [
// {
// couponName: "엽떡 10000원 할인",
// couponStore: "엽기 떡볶이",
// couponCondition: ["10만원 이상 구매시", "4명 이상이 오면"],
// couponQuantity: 50,
// },
// {
// couponName: "소소 떡볶이 10000원 할인",
// couponStore: "엽기 떡볶이",
// couponCondition: ["10만원 이상 구매시", "4명 이상이 오면"],
// couponQuantity: 50,
// },
// ];
39 changes: 39 additions & 0 deletions components/hooks/useStores.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getFoods } from "@/pages/api/others";
import { useEffect, useState } from "react";

interface CouponProps {
isPicked: boolean;
name: string;
category: "FOOD" | "CAFE" | "BEAUTY" | "CULTURE" | "ETC";
pageSize: number;
pageNumber: number;
}

export const useStores = async ({
isPicked,
name,
category,
pageSize,
pageNumber,
}: CouponProps) => {
const [data, setData] = useState<CouponProps | null>();

useEffect(() => {
const fetchData = async () => {
const result = await getFoods({
isPicked,
name,
category,
pageSize,
pageNumber,
});

setData(result.coupons);
console.log(result.coupons);
};

fetchData();
}, []);

return { data };
};
101 changes: 90 additions & 11 deletions components/organisms/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import styled from "@emotion/styled";
import Link from "next/link";

import React, { useEffect, useState } from "react";
import NotificationsNoneOutlinedIcon from "@mui/icons-material/NotificationsNoneOutlined";
import Logo from "@/components/atoms/Logo.svg";
import { useRouter } from "next/router";
import { useModal } from "../hooks/useModal";
import { useSetRecoilState } from "recoil";
import { useRecoilState } from "recoil";
import { initialState } from "@/state/user/user";

import { Logout } from "@/pages/api/login";
import { Box, Button, Modal } from "@mui/material";
import { css } from "@emotion/css";

/*
TODO:
1. 로그인 - 세션스토리지 안에 로그인 여부에 따라서 다르게
*/

const Header = () => {
const [modalOpen, setModalOpen] = useState(false);
const handleOpen = () => {
setModalOpen(true);
};
const handleClose = () => {
setModalOpen(false);
};

const router = useRouter();
const { openModal } = useModal();
const [userSessionData, setUserSessionData] = useState<string | null>(null);

const setLogout = useSetRecoilState(initialState);
const [logData, setLogData] = useRecoilState(initialState);

useEffect(() => {
setUserSessionData(window.sessionStorage?.getItem("userSession"));
Expand All @@ -32,21 +37,75 @@ const Header = () => {
}, [userSessionData]);

const logoutHandler = async () => {
console.log("logout");
const response = await Logout();
console.log(response);

setLogout({
console.log("logout합니다");
const result = await Logout();
console.log(result);

setLogData({

logined: false,
email: "",
type: "",
typeName: "",
token: "",
});
sessionStorage.clear();
setUserSessionData(null);
};

return (
<HeaderFrame>
<Modal
open={modalOpen}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
className={css`
display: flex;
justify-content: center;
align-items: center;
`}
>
<div
className={css`
width: 406px;
height: 186px;
display: flex;
flex-flow: column nowrap;
background-color: white;
border-radius: 15px;
align-items: center;
justify-content: center;
`}
>
<ModalTitle>정말 로그아웃 하시겠습니까?</ModalTitle>
<ModalSubTitle>로그인한 모든 곳에서 로그아웃됩니다.</ModalSubTitle>
<div
className={css`
display: flex;
margin-top: 40px;
width: 100%;
padding: 0px 20px;
column-gap: 10px;
`}
>
<Button variant="outlined" fullWidth>
취소
</Button>
<Button
variant="contained"
fullWidth
onClick={() => {
logoutHandler();
setModalOpen(false);
}}
>
확인
</Button>
</div>
</div>
</Modal>
<Logo
onClick={() => {
router.push("/");
Expand All @@ -61,6 +120,8 @@ const Header = () => {
<UpperMenuItem
onClick={() => {
if (userSessionData) {

setModalOpen(true);
logoutHandler();

} else {
Expand Down Expand Up @@ -113,6 +174,24 @@ const Header = () => {
);
};

const ModalTitle = styled.p`
color: var(--, #3d4149);
text-align: center;
font-family: Pretendard;
font-size: 20px;
font-style: normal;
font-weight: 600;
`;

const ModalSubTitle = styled.p`
color: #afafaf;
text-align: center;
font-family: Pretendard Variable;
font-size: 13.984px;
font-style: normal;
font-weight: 400;
`;

const HeaderFrame = styled.div`
padding: 1rem 10rem 1rem 10rem;
Expand Down
9 changes: 5 additions & 4 deletions components/organisms/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Logo from "@/components/atoms/Logo.svg";
import ModalCloseButton from "@/components/atoms/ModalCloseBtn.svg";
import { login } from "@/pages/api/login";
import { initialState } from "@/state/user/user";
import { useRouter } from "next/router";

interface ModalProps {
children?: React.ReactNode;
Expand All @@ -18,6 +19,8 @@ const LoginModal: React.FC<ModalProps> = () => {

const { closeModal } = useModal();

const router = useRouter();

const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const setLoginedUserState = useSetRecoilState(initialState);
Expand All @@ -27,18 +30,16 @@ const LoginModal: React.FC<ModalProps> = () => {
const result = await login({ email: email, password: password });
setLoginedUserState((prev) => ({
...prev,
logined: true,
token: result.accessToken,
}));
router.reload();
return result.data;
} catch (error) {
console.error(error);
}
};

useEffect(() => {
console.log(`${email} + ${password}`);
}, []);

if (!isOpen) return null;
return (
<Container>
Expand Down
40 changes: 23 additions & 17 deletions pages/api/coupon.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
import axios from "axios";

const apiBase = () => {
const userSession = sessionStorage.getItem("userSession");
let token: string = "";
if (userSession) {
const parsedSession = JSON.parse(userSession);
token = parsedSession.user?.token || "";
} else {
console.log("유저세션 없음");
}
import { axiosInstance } from "./axiosInstance";

return axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
timeout: 3000,
headers: { Authorization: `Bearer ${token}` },
});
};

interface CouponProps {
type: "COUPON";
Expand All @@ -30,7 +16,9 @@ export const getCoupons = async ({
}: CouponProps) => {
try {
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_GET_COUPONS}?type=${type}&pageSize=${pageSize}&pageNumber=${pageNumber}`;
const response = await apiBase().get(url);

const response = await axiosInstance().get(url);

return response.data;
} catch (e) {
console.error(`Error 코드 : ${e}`);
Expand Down Expand Up @@ -59,7 +47,9 @@ export const createCoupon = async ({
}: EventProps) => {
try {
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_POST_COUPON}`;
const response = await apiBase().post(url, {

const response = await axiosInstance().post(url, {

storeId,
type,
name,
Expand All @@ -72,3 +62,19 @@ export const createCoupon = async ({
console.error(`Error 코드 : ${e}`);
}
};


interface DeleteProps {
items: number[];
}

export const deleteCoupons = async ({ items }: DeleteProps) => {
try {
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_DELETE_COUPONS}?type=COUPON&ids=${items}`;
const response = await axiosInstance().delete(url);
return response.data;
} catch (e) {
console.error(`Error 코드 : ${e}`);
}
};

24 changes: 5 additions & 19 deletions pages/api/login.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from "axios";
import { axiosInstance } from "./axiosInstance";

const apiBase = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
Expand Down Expand Up @@ -89,28 +90,13 @@ export const CreateImage = async (file: File) => {

// 로그아웃
export const Logout = async () => {
const userSession = sessionStorage.getItem("userSession");
let token: string = "";
if (userSession) {
const parsedSession = JSON.parse(userSession);
token = parsedSession.user?.token || "";
} else {
console.log("유저세션 없음");
}
try {
const response = await apiBase.post(

`${process.env.NEXT_PUBLIC_LOGOUT_ENDPOINT}`,

{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
try {
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_LOGOUT_ENDPOINT}`;
const response = await axiosInstance().post(url);
return response.data;
} catch (e) {
console.error(`에러코드 : ${e}`);
console.error(`Error 코드 : ${e}`);
}
};

Loading

0 comments on commit 28db27b

Please sign in to comment.