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

feat: 토스페이먼츠 결제 로직 #77

Merged
merged 5 commits into from
Nov 14, 2024
Merged
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
17 changes: 17 additions & 0 deletions src/apis/Bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,20 @@ export const getBuckets = async (): Promise<BucketType | null> => {
return null;
}
};

export const validateBucket = async (marketId: number): Promise<boolean> => {
try {
const res = await apiClient.get<{
sameMarketProduct: boolean;
}>(`/buckets/markets/${marketId}`);

if (!res) {
return false;
}

return res.sameMarketProduct;
} catch (error) {
console.error('Error fetching validateBucket:', error);
return false;
}
};
14 changes: 7 additions & 7 deletions src/apis/Login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const initializeNaver = ({
}: NaverLoginInitParams) => {
if (Platform.OS === 'ios') {
if (!serviceUrlSchemeIOS) {
console.log('serviceUrlSchemeIOS is missing in iOS initialize.');
console.debug('serviceUrlSchemeIOS is missing in iOS initialize.');
return;
}
RNNaverLogin.initialize(
Expand Down Expand Up @@ -65,7 +65,7 @@ const signInWithNaver = async (): Promise<SessionType | null> => {
if (loginResult.isSuccess && loginResult.successResponse) {
const {accessToken, refreshToken, expiresAtUnixSecondString} =
loginResult.successResponse;
console.log('Naver Access Token:', accessToken);
console.debug('Naver Access Token:', accessToken);
// JWT 토큰
const response = await apiClient.post<{
data: {
Expand All @@ -79,7 +79,7 @@ const signInWithNaver = async (): Promise<SessionType | null> => {
});

if (response) {
console.log('네이버 로그인 성공:', response);
console.debug('네이버 로그인 성공:', response);
const accessTokenExpiresAt = Number(expiresAtUnixSecondString) * 1000;

return {
Expand All @@ -91,11 +91,11 @@ const signInWithNaver = async (): Promise<SessionType | null> => {
jwtToken: response.data.accessToken,
};
} else {
console.log('네이버 로그인 실패');
console.debug('네이버 로그인 실패');
return null;
}
} else {
console.log('네이버 로그인 실패:', loginResult.failureResponse);
console.debug('네이버 로그인 실패:', loginResult.failureResponse);
return null;
}
} catch (error) {
Expand Down Expand Up @@ -125,7 +125,7 @@ const signInWithKakao = async (): Promise<SessionType | null> => {
});

if (response) {
console.log('카카오 로그인 성공:', response);
console.debug('카카오 로그인 성공:', response);
return {
//TODO: JWT 토큰으로 대체 필요
accessToken: token.accessToken,
Expand All @@ -136,7 +136,7 @@ const signInWithKakao = async (): Promise<SessionType | null> => {
jwtToken: response.data.accessToken,
};
} else {
console.log('카카오 로그인 실패');
console.debug('카카오 로그인 실패');
return null;
}
} catch (error) {
Expand Down
103 changes: 39 additions & 64 deletions src/apis/Order.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,9 @@
import {BucketType} from '@/types/Bucket';
import {Success} from '@tosspayments/widget-sdk-react-native';
import {PaymentInfo} from '@tosspayments/widget-sdk-react-native/lib/typescript/src/models/PaymentInfo';
import axios from 'axios';
import {CartType, OrderType} from '../types/OrderType';

const dummyCart: CartType = {
id: 1,
market: {
id: 1,
name: 'market1',
images: ['https://legacy.reactjs.org/logo-og.png'],
},
products: [
{
id: 1,
name: '김치',
image: 'https://legacy.reactjs.org/logo-og.png',
originalPrice: 10000,
discountPrice: 7000,
count: 3,
tags: [
{
id: 1,
tagName: '추천메뉴',
},
{id: 5, tagName: '김치류'},
],
},
{
id: 2,
name: '깻잎',
image: 'https://legacy.reactjs.org/logo-og.png',
originalPrice: 5000,
discountPrice: 3000,
count: 3,
tags: [
{
id: 2,
tagName: '깻잎류',
},
],
},
{
id: 3,
name: '간장게장',
image: 'https://legacy.reactjs.org/logo-og.png',
originalPrice: 20000,
discountPrice: 17000,
count: 3,
tags: [
{
id: 3,
tagName: '게장류',
},
],
},
],
};
import {OrderType} from '../types/OrderType';
import apiClient from './ApiClient';

const dummyHistoryList: OrderType[] = [
{
Expand Down Expand Up @@ -161,6 +111,13 @@ const dummyHistoryList: OrderType[] = [
},
];

const randomString = (): string => Math.random().toString(36).substr(2, 16);

const dummyPaymentInfo: PaymentInfo = {
orderId: randomString(),
orderName: '김치',
};

// TODO: fetch order history
export const getOrderHistory = async (): Promise<OrderType[] | null> => {
try {
Expand All @@ -173,7 +130,7 @@ export const getOrderHistory = async (): Promise<OrderType[] | null> => {

return new Promise(async resolve => {
await new Promise(_ => setTimeout(_, 1000));
console.log('fetch order history');
console.debug('fetch order history');
resolve(dummyHistoryList);
});
} catch (error) {
Expand All @@ -182,16 +139,34 @@ export const getOrderHistory = async (): Promise<OrderType[] | null> => {
}
};

// TODO: fetch cart
export const getCart = async (): Promise<CartType | null> => {
export const requestOrder = async (
cart: BucketType,
): Promise<PaymentInfo | null> => {
try {
return new Promise(async resolve => {
await new Promise(_ => setTimeout(_, 1000));
console.log('fetch cart');
resolve(dummyCart);
});
// TODO: uri 수정
// const res = await apiClient.post<PaymentInfo | null>('/order', cart);
apiClient.get('/utils/health');
console.debug(cart);
const res = dummyPaymentInfo;

return res;
} catch (error) {
console.error(error);
console.debug(error);
return null;
}
};

export const requestOrderSuccess = async (
success: Success,
): Promise<Boolean | null> => {
try {
// TODO: uri 수정
// const res = await apiClient.post<Boolean>('/order/success', success);
console.debug(success);
const res = true;
return res;
} catch (error) {
console.debug(error);
return null;
}
};
2 changes: 1 addition & 1 deletion src/components/common/CartNavigatorIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const CartIcon = () => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();

const handlePress = () => {
navigation.navigate('Cart');
navigation.navigate('CartRoot');
};

return (
Expand Down
34 changes: 2 additions & 32 deletions src/components/orderPage/PaymentMethod.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
import React from 'react';
import {View} from 'react-native';
import {RadioButton} from 'react-native-paper';
import S from './PaymentMethod.style';

const PaymentMethod = <T extends string>({
value,
onChange,
paymentMethodKind,
}: {
value: T;
onChange: (method: T) => void;
paymentMethodKind: {
[key in T]: string;
};
}) => {
return (
<S.Card>
<S.HeaderText>결제수단</S.HeaderText>
<View>
<RadioButton.Group
onValueChange={newValue => onChange(newValue as T)}
value={value}>
{Object.entries<string>(paymentMethodKind).map(([kind, label]) => (
<S.PaymentRadioButtonItem
key={kind}
value={kind}
label={label}
mode="android"
/>
))}
</RadioButton.Group>
</View>
</S.Card>
);
const PaymentMethod = ({children}: {children: React.ReactNode}) => {
return <S.Card>{children}</S.Card>;
};

export default PaymentMethod;
2 changes: 1 addition & 1 deletion src/navigation/CartNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const Stack = createStackNavigator<CartStackParamList>();
const CartNavigator = () => {
return (
<Stack.Navigator
initialRouteName="Market"
initialRouteName="CartRoot"
screenOptions={{headerShown: true}}>
<Stack.Screen name="Cart" component={ShoppingCartScreen} />
</Stack.Navigator>
Expand Down
3 changes: 1 addition & 2 deletions src/navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ const AppNavigator = () => {
<Stack.Screen name="Home" component={HomeNavigator} />
<Stack.Screen name="Register" component={RegisterNavigator} />
<Stack.Screen name="Detail" component={DetailNavigator} />
<Stack.Screen name="Cart" component={CartNavigator} />
{/* Add more screens here */}
<Stack.Screen name="CartRoot" component={CartNavigator} />
</Stack.Navigator>
);
};
Expand Down
42 changes: 41 additions & 1 deletion src/screens/OrderDoneScreen/OrderDoneScreen.style.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import styled from '@emotion/native';
import {Card} from 'react-native-paper';

const OrderDoneContainer = styled.View`
display: flex;
flex-direction: column;
`;

const OrderDoneCard = styled(Card)`
padding: 16px;
margin: 8px;
Expand All @@ -11,6 +16,41 @@ const OrderDoneCard = styled(Card)`
background-color: white;
`;

const S = {OrderDoneCard};
const ProductItem = styled.View`
display: flex;
flex-direction: row;

justify-content: space-between;
`;

const PriceView = styled.View`
width: 100%;

display: flex;
flex-direction: column;
`;

const PriceItem = styled.View`
display: flex;
flex-direction: row;

justify-content: space-between;
`;

const PrimaryText = styled.Text`
${({theme}) => theme.fonts.body1};
font-weight: bold;

padding: 8px 0;
`;

const S = {
OrderDoneContainer,
OrderDoneCard,
ProductItem,
PriceView,
PriceItem,
PrimaryText,
};

export default S;
44 changes: 36 additions & 8 deletions src/screens/OrderDoneScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,47 @@ import S from './OrderDoneScreen.style';
type Props = StackScreenProps<DetailStackParamList, 'OrderDone'>;

const OrderDoneScreen = ({navigation, route}: Props) => {
const {orderId} = route.params;
const {orderId, products, originalPrice, discountPrice} = route.params;

return (
<S.OrderDoneCard>
<Title>주문완료</Title>
<View>
<Text>주문이 완료되었습니다.</Text>
<Text>{`주문번호: ${orderId}`}</Text>
</View>
<S.OrderDoneContainer>
<S.OrderDoneCard>
<Title>주문완료</Title>
<View>
<Text>주문이 완료되었습니다.</Text>
<Text>{`주문번호: ${orderId}`}</Text>
</View>
</S.OrderDoneCard>
<S.OrderDoneCard>
<Title>주문 상품</Title>
{products.map(product => (
<S.ProductItem key={product.id}>
<Text>{product.name}</Text>
<Text>{`${product.count.toLocaleString()}개`}</Text>
</S.ProductItem>
))}
</S.OrderDoneCard>
<S.OrderDoneCard>
<Title>결제 정보</Title>
<S.PriceView>
<S.PriceItem>
<S.PrimaryText>결제 금액</S.PrimaryText>
<S.PrimaryText>{`${discountPrice.toLocaleString()}원`}</S.PrimaryText>
</S.PriceItem>
<S.PriceItem>
<Text>상품 금액</Text>
<Text>{`${originalPrice.toLocaleString()}원`}</Text>
</S.PriceItem>
<S.PriceItem>
<Text>할인 금액</Text>
<Text>{`- ${(originalPrice - discountPrice).toLocaleString()}원`}</Text>
</S.PriceItem>
</S.PriceView>
</S.OrderDoneCard>
<Button onPress={() => navigation.navigate('Home', {screen: 'Feed'})}>
<Text>홈으로</Text>
</Button>
</S.OrderDoneCard>
</S.OrderDoneContainer>
);
};

Expand Down
Loading
Loading