Skip to content

Commit

Permalink
Merge pull request #1 from hanlee55/feature/beta-payment-integration
Browse files Browse the repository at this point in the history
결제 모듈 연결
  • Loading branch information
hanlee55 authored May 12, 2024
2 parents e94029f + 1becad2 commit 68c27ab
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 79 deletions.
54 changes: 35 additions & 19 deletions src/api/ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,25 @@ import { APIPayment } from "models/api/ticket";
import { Payment } from "models/ticket";

/** 결제 번호 발급 */
export function makePaymentId(): Promise<string> {
export function makePaymentId(price: number): Promise<string> {
return new Promise((resolve, reject) => {
resolve("1");
return;

// eslint-disable-next-line no-unreachable
const id = localStorage.getItem("id");
const password = localStorage.getItem("password");
axios
.post<string>("/ticket/purchase")
.then((response) => {
resolve("1");
.post<string>("/payments/", {
"price": price
}, {
headers: {
// Authorization
// load id and password from localStorage
// id:pw => base64
"Authorization": `Basic ${btoa(`${id}:${password}`)}`,
},
})
.then((response: any) => {
// get merchant_id from response(json response.data)
console.log(response.data);
resolve(response.data.merchant_id);
})
.catch((error) => {
console.error(error);
Expand All @@ -25,9 +34,6 @@ export function makePaymentId(): Promise<string> {
/** 결제 결과 전송 */
export function completePayment(paymentId: string): Promise<void> {
return new Promise((resolve, reject) => {
resolve();
return;

// eslint-disable-next-line no-unreachable
axios
.post<void>("/ticket/purchase")
Expand All @@ -44,12 +50,17 @@ export function completePayment(paymentId: string): Promise<void> {
/** 환불 요청 */
export function refundPayment(paymentId: string): Promise<void> {
return new Promise((resolve, reject) => {
resolve();
return;

// eslint-disable-next-line no-unreachable
const id = localStorage.getItem("id");
const password = localStorage.getItem("password");
axios
.post<void>("/ticket/purchase/refund")
.post<void>(`/payments/${paymentId}/refund/`, {}, {
headers: {
// Authorization
// id:pw => base64
"Authorization": `Basic ${btoa(`${id}:${password}`)}`,
},
})
.then((response) => {
resolve();
})
Expand All @@ -63,12 +74,17 @@ export function refundPayment(paymentId: string): Promise<void> {
/** 결제 내역 조회 */
export function listPayments(): Promise<Payment[]> {
return new Promise((resolve, reject) => {
resolve([]);
return;

// eslint-disable-next-line no-unreachable
const id = localStorage.getItem("id");
const password = localStorage.getItem("password");
axios
.get<APIPayment[]>("/ticket/purchase")
.get<APIPayment[]>("/payments/", {
headers: {
// Authorization
// id:pw => base64
"Authorization": `Basic ${btoa(`${id}:${password}`)}`,
},
})
.then((response) => {
resolve(Payment.fromAPIs(response.data));
})
Expand Down
8 changes: 7 additions & 1 deletion src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { getErrorMessage } from "api";
export function signIn(id: string, password: string): Promise<void> {
return new Promise((resolve, reject) => {
axios
.get<APISponsor[]>("/login")
.get<APISponsor[]>("/login/", {
headers: {
// Authorization
// id:pw => base64
"Authorization": `Basic ${btoa(`${id}:${password}`)}`,
},
})
.then((response) => {
resolve();
})
Expand Down
10 changes: 5 additions & 5 deletions src/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const Footer = () => {

return (
<Container>
<Sponsors>
{/* <Sponsors>
{sponsors === undefined ? (
<span>후원사 목록을 가져오는데 실패했습니다.</span>
) : (
Expand All @@ -77,14 +77,14 @@ const Footer = () => {
</div>
))
)}
</Sponsors>
</Sponsors> */}
<About>
<section className="left">
<table>
<tbody>
<tr>
<td>상호명</td>
<td>사단법인 파이썬 사용자모임</td>
<td>사단법인 파이썬사용자모임</td>
</tr>
<tr>
<td>사업자 등록 번호</td>
Expand All @@ -96,11 +96,11 @@ const Footer = () => {
</tr>
<tr>
<td>대표 전화 번호</td>
<td>010-2077-4788</td>
<td>031-261-2203</td>
</tr>
<tr>
<td>사업장 주소</td>
<td>서울시 강남구 강남대로84길 24-4</td>
<td>서울특별시 강남구 강남대로84길 24-4</td>
</tr>
<tr>
<td>통신판매번호</td>
Expand Down
31 changes: 25 additions & 6 deletions src/components/Nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ const Nav = () => {
);
const t = useTranslation();

// 로그인 여부 확인
// localStorage에 id가 있으면 로그인 상태로 간주
// 로그인 상태면 로그인 버튼 대신 로그아웃 버튼이 나타남
// 로그아웃 버튼 클릭 시 localStorage에서 id 삭제 후 메인 페이지로 이동
const isLogin = localStorage.getItem("id");

return (
<Container>
<Logo
Expand Down Expand Up @@ -47,12 +53,25 @@ const Nav = () => {
))}
</LeftMenus>
<RightMenus>
<Menu
onClick={() => {
navigate("/login");
}}
>
{t("로그인")}
<Menu>
{isLogin ? (
<SubMenu
onClick={() => {
localStorage.removeItem("id");
navigate("/");
}}
>
{t("로그아웃")}
</SubMenu>
) : (
<SubMenu
onClick={() => {
navigate("/login");
}}
>
{t("로그인")}
</SubMenu>
)}
</Menu>
<Menu>
Language
Expand Down
4 changes: 4 additions & 0 deletions src/components/Nav/menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ const Menus = {
name: "티켓 구매하기",
path: "buy",
},
{
name: "구매 내역",
path: "payment-list",
},
],
},
contribution: {
Expand Down
9 changes: 9 additions & 0 deletions src/locale/English/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ const EnglishTranslation = {
"튜토리얼 티켓": "Tutorial ticket",
"스프린트 티켓": "Sprint ticket",
취소: "Cancel",
"결제 내역": "Payment list",
환불: "Refund",
"환불하기": "Refund",
"환불 성공": "Refund success",
"환불 실패": "Refund failed",
"결제 번호": "Payment ID",
"결제 일시": "Payment date",
금액: "Price",
변경일: "Updated at",
};

export default EnglishTranslation;
12 changes: 11 additions & 1 deletion src/pages/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ const Login = () => {
}

await UserAPI.signIn(id, password)
.then(() => {})
.then(() => {
// save id, password to local storage
localStorage.setItem("id", id);
localStorage.setItem("password", password);

alert("로그인 성공");
// redirect to ticket page
// <Route path="/ticket/buy" element={<TicketPage />} />
document.location.href = "/ticket/buy";

})
.catch((e) => {
setAlertMessage(t("로그인 실패. 잠시 후 다시 시도해주세요."));
});
Expand Down
72 changes: 62 additions & 10 deletions src/pages/Ticket/buy.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import Page from "components/common/Page";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { tickets } from "./tickets";
import Dialog from "components/common/Dialog";
import { Link } from "react-router-dom";
import useTranslation from "utils/hooks/useTranslation";
import { TicketAPI } from "api";

// IMP 모듈을 전역으로 선언
declare global {
interface Window {
IMP: any;
}
}

type Props = {
onPaymentCompleted: () => void;
};

const BuyTicket = ({ onPaymentCompleted }: Props) => {
// load IMP module
useEffect(() => {
const script = document.createElement("script");
script.src = "https://cdn.iamport.kr/v1/iamport.js";
script.async = true;
document.body.appendChild(script);
}, []);

// 선택한 티켓 가격을 저장하는 변수
const [selectedTicket, setSelectedTicket] = useState<number>();

const t = useTranslation();
const [isDialogOpened, setIsDialogOpened] = useState<boolean>(false);
const [dialogHeader, setDialogHeader] = useState<string>("");
Expand All @@ -36,17 +54,50 @@ const BuyTicket = ({ onPaymentCompleted }: Props) => {
};

const onDialogConfirmed = async () => {
// 결제 번호 생성
await TicketAPI.makePaymentId();
// 로그인이 되지 않은 상태에서 진행할 수 없도록 막음
// 임시 - localStorage에 id가 저장되어 있는 경우 로그인 상태로 간주
if (!localStorage.getItem("id")) {
alert("로그인이 필요합니다.");
return;
}


// 결제 번호 생성 - merchant_id 받아와 변수(merchant_id)에 저장
const merchant_id = await TicketAPI.makePaymentId(selectedTicket || 0);

const price = selectedTicket || 0;

console.log(merchant_id);

const IMP = window.IMP;
console.log(IMP);
IMP.init("imp80859147");

// 결제 모듈 띄우기
// 결제 다 되면
// 결과 보내고
await TicketAPI.completePayment("1");
// dialog 닫고
setIsDialogOpened(false);
// 페이지 넘기기
onPaymentCompleted();
IMP.request_pay(
{
pg: "kcp",
pay_method: "card",
merchant_uid: merchant_id,
name: "티켓 구매",
amount: price,
},
async (rsp: any) => {
if (rsp.success) {
// 결제 성공 시
// 결제 완료 처리

// 완료 결과 보내기
// await TicketAPI.completePayment(merchant_id);
// dialog 닫고
setIsDialogOpened(false);
// 페이지 이동
onPaymentCompleted();
} else {
alert("결제에 실패하였습니다. 에러 내용: " + rsp.error_msg);
}
}
);
};

return (
Expand Down Expand Up @@ -81,6 +132,7 @@ const BuyTicket = ({ onPaymentCompleted }: Props) => {
<button
onClick={() => {
openDialog(`${v.name} 구매`, ticket.description);
setSelectedTicket(ticket.price);
}}
>
{t("구매하기")}
Expand Down
Loading

0 comments on commit 68c27ab

Please sign in to comment.