Skip to content
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
25 changes: 19 additions & 6 deletions packages/shop/src/apis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,31 @@ namespace ShopAPIs {

/**
* 로그아웃합니다.
* @throws 401 - 로그아웃이 성공할 시에도 항상 401 에러가 발생합니다.
*/
export const signOut = (client: ShopAPIClient) => () =>
client.delete<ShopSchemas.UserSignedInStatus>("authn/social/browser/v1/auth/session");
export const signOut = (client: ShopAPIClient) => async () => {
try {
await client.delete<ShopSchemas.UserSignedInStatus>("authn/social/browser/v1/auth/session");
} catch (error) {
}
return Promise.resolve({});
}

/**
* 로그인 정보를 조회합니다.
* @returns 로그인 정보
* @throws 401 - 로그인 정보가 없습니다.
*/
export const retrieveUserInfo = (client: ShopAPIClient) => () =>
client.get<ShopSchemas.UserSignedInStatus>("authn/social/browser/v1/auth/session");
export const retrieveUserInfo = (client: ShopAPIClient) => async () => {
try {
const response = await client.get<ShopSchemas.UserSignedInStatus>("authn/social/browser/v1/auth/session");
if (response.meta.is_authenticated) {
return response;
} else {
throw new Error("User is not authenticated");
}
} catch (error) {
}
return Promise.resolve(null);
}

/**
* 노출 중인 모든 상품의 목록을 가져옵니다.
Expand Down
7 changes: 4 additions & 3 deletions packages/shop/src/components/features/cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ export const CartStatus: React.FC<{ onPaymentCompleted?: () => void }> = ({
onPaymentCompleted,
}) => {
const queryClient = useQueryClient();
const cartOrderStartMutation = ShopHooks.usePrepareCartOrderMutation();
const removeItemFromCartMutation = ShopHooks.useRemoveItemFromCartMutation();
const shopAPIClient = ShopHooks.useShopClient();
const cartOrderStartMutation = ShopHooks.usePrepareCartOrderMutation(shopAPIClient);
const removeItemFromCartMutation = ShopHooks.useRemoveItemFromCartMutation(shopAPIClient);

const removeItemFromCart = (cartProductId: string) =>
removeItemFromCartMutation.mutate({ cartProductId });
Expand Down Expand Up @@ -100,7 +101,7 @@ export const CartStatus: React.FC<{ onPaymentCompleted?: () => void }> = ({

const WrappedShopCartList: React.FC = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { data } = ShopHooks.useCart();
const { data } = ShopHooks.useCart(shopAPIClient);

return !data.hasOwnProperty("products") || data.products.length === 0 ? (
<Typography variant="body1" color="error">
Expand Down
26 changes: 13 additions & 13 deletions packages/shop/src/components/features/order.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,23 @@ const PaymentHistoryStatusTranslated: {
refunded: "환불됨",
};

const OrderItem: React.FC<{
order: ShopSchemas.Order;
disabled?: boolean;
}> = ({ order, disabled }) => {
const orderRefundMutation = ShopHooks.useOrderRefundMutation();
const oneItemRefundMutation = ShopHooks.useOneItemRefundMutation();
const optionsOfOneItemInOrderPatchMutation = ShopHooks.useOptionsOfOneItemInOrderPatchMutation();
const OrderItem: React.FC<{ order: ShopSchemas.Order; disabled?: boolean }> = ({ order, disabled }) => {
const { shopApiDomain } = ShopHooks.useShopContext();
const shopAPIClient = ShopHooks.useShopClient();
const orderRefundMutation = ShopHooks.useOrderRefundMutation(shopAPIClient);
const oneItemRefundMutation = ShopHooks.useOneItemRefundMutation(shopAPIClient);
const optionsOfOneItemInOrderPatchMutation = ShopHooks.useOptionsOfOneItemInOrderPatchMutation(shopAPIClient);

const refundOrder = () => orderRefundMutation.mutate({ order_id: order.id });
const openReceipt = () => window.open(ShopUtils.getReceiptUrlFromOrder(order), "_blank");
const openReceipt = () => window.open(`${shopApiDomain}/v1/orders/${order.id}/receipt/`, "_blank");

const isPending =
disabled ||
orderRefundMutation.isPending ||
oneItemRefundMutation.isPending ||
optionsOfOneItemInOrderPatchMutation.isPending;
const btnDisabled =
isPending || !R.isNullish(order.not_fully_refundable_reason);
const refundBtnDisabled = isPending || !R.isNullish(order.not_fully_refundable_reason);
const receipyBtnDisabled = isPending || order.current_status === "pending";
const btnText = R.isNullish(order.not_fully_refundable_reason)
? "주문 전체 환불"
: order.current_status === "refunded"
Expand Down Expand Up @@ -189,15 +188,15 @@ const OrderItem: React.FC<{
variant="contained"
sx={{ width: "100%" }}
onClick={openReceipt}
disabled={btnDisabled}
disabled={receipyBtnDisabled}
>
영수증
</Button>
<Button
variant="contained"
sx={{ width: "100%" }}
onClick={refundOrder}
disabled={btnDisabled}
disabled={refundBtnDisabled}
>
{btnText}
</Button>
Expand All @@ -209,7 +208,8 @@ const OrderItem: React.FC<{
export const OrderList: React.FC = () => {
const WrappedOrderList: React.FC = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { data } = ShopHooks.useOrders();
const shopAPIClient = ShopHooks.useShopClient();
const { data } = ShopHooks.useOrders(shopAPIClient);

return (
<List>
Expand Down
10 changes: 6 additions & 4 deletions packages/shop/src/components/features/product.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ const ProductItem: React.FC<{
const optionFormRef = React.useRef<HTMLFormElement>(null);

const queryClient = useQueryClient();
const oneItemOrderStartMutation = ShopHooks.usePrepareOneItemOrderMutation();
const addItemToCartMutation = ShopHooks.useAddItemToCartMutation();
const shopAPIClient = ShopHooks.useShopClient();
const oneItemOrderStartMutation = ShopHooks.usePrepareOneItemOrderMutation(shopAPIClient);
const addItemToCartMutation = ShopHooks.useAddItemToCartMutation(shopAPIClient);

const addItemToCart = () =>
addItemToCartMutation.mutate(
Expand Down Expand Up @@ -199,9 +200,10 @@ const ProductItem: React.FC<{
);
};

export const ProductList: React.FC = () => {
export const ProductList: React.FC<ShopSchemas.ProductListQueryParams> = (qs) => {
const WrappedProductList: React.FC = () => {
const { data } = ShopHooks.useProducts();
const shopAPIClient = ShopHooks.useShopClient();
const { data } = ShopHooks.useProducts(shopAPIClient, qs);
return (
<List>
{data.map((product) => (
Expand Down
10 changes: 6 additions & 4 deletions packages/shop/src/components/features/user_status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import ShopHooks from '../../hooks';

export const UserInfo: React.FC = () => {
const formRef = React.useRef<HTMLFormElement>(null);
const signInWithEmailMutation = ShopHooks.useSignInWithEmailMutation();
const SignInWithSNSMutation = ShopHooks.useSignInWithSNSMutation();
const signOutMutation = ShopHooks.useSignOutMutation();
const shopAPIClient = ShopHooks.useShopClient();
const signInWithEmailMutation = ShopHooks.useSignInWithEmailMutation(shopAPIClient);
const SignInWithSNSMutation = ShopHooks.useSignInWithSNSMutation(shopAPIClient);
const signOutMutation = ShopHooks.useSignOutMutation(shopAPIClient);

const signInWithGoogle = () =>
SignInWithSNSMutation.mutate({
Expand All @@ -42,7 +43,8 @@ export const UserInfo: React.FC = () => {

const WrappedUserStatus: React.FC = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { data } = ShopHooks.useUserStatus();
const shopAPIClient = ShopHooks.useShopClient();
const { data } = ShopHooks.useUserStatus(shopAPIClient);

return data && data.meta.is_authenticated === true ? (
<Stack>
Expand Down
125 changes: 48 additions & 77 deletions packages/shop/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,23 @@ import ShopContext from '../contexts';
import ShopSchemas from "../schemas";

const QUERY_KEYS = {
USER: ["query", "user"],
PRODUCT_LIST: ["query", "products"],
CART_INFO: ["query", "cart"],
ORDER_LIST: ["query", "orders"],
BASE: ["query", "shop"],
USER: ["query", "shop", "user"],
PRODUCT_LIST: ["query", "shop", "products"],
CART_INFO: ["query", "shop", "cart"],
ORDER_LIST: ["query", "shop", "orders"],
};

const MUTATION_KEYS = {
USER_SIGN_IN_EMAIL: ["mutation", "user", "sign_in", "email"],
USER_SIGN_IN_SNS: ["mutation", "user", "sign_in", "sns"],
USER_SIGN_OUT: ["mutation", "user", "sign_out"],
CART_ITEM_APPEND: ["mutation", "cart", "item", "append"],
CART_ITEM_REMOVE: ["mutation", "cart", "item", "remove"],
CART_ORDER_START: ["mutation", "cart_order", "start"],
ONE_ITEM_ORDER_START: ["mutation", "one_item_order", "start"],
ALL_ORDER_REFUND: ["mutation", "all_order_refund"],
ONE_ITEM_REFUND: ["mutation", "one_item_refund"],
USER_SIGN_IN_EMAIL: ["mutation", "shop", "user", "sign_in", "email"],
USER_SIGN_IN_SNS: ["mutation", "shop", "user", "sign_in", "sns"],
USER_SIGN_OUT: ["mutation", "shop", "user", "sign_out"],
CART_ITEM_APPEND: ["mutation", "shop", "cart", "item", "append"],
CART_ITEM_REMOVE: ["mutation", "shop", "cart", "item", "remove"],
CART_ORDER_START: ["mutation", "shop", "cart_order", "start"],
ONE_ITEM_ORDER_START: ["mutation", "shop", "one_item_order", "start"],
ALL_ORDER_REFUND: ["mutation", "shop", "all_order_refund"],
ONE_ITEM_REFUND: ["mutation", "shop", "one_item_refund"],
};

namespace ShopHooks {
Expand All @@ -35,133 +36,103 @@ namespace ShopHooks {
return context;
}

const clientDecorator = <T = CallableFunction>(func:(client: ShopAPIClient) => T): T => {
export const useShopClient = () => {
const { shopApiDomain, shopApiCSRFCookieName, shopApiTimeout } = useShopContext();
return func(new ShopAPIClient(shopApiDomain, shopApiCSRFCookieName, shopApiTimeout));
return new ShopAPIClient(shopApiDomain, shopApiCSRFCookieName, shopApiTimeout);
}

export const useUserStatus = () =>
export const useUserStatus = (client: ShopAPIClient) =>
useSuspenseQuery({
queryKey: QUERY_KEYS.USER,
queryFn: async () => {
try {
const userInfo = await clientDecorator(ShopAPIs.retrieveUserInfo)();
return userInfo.meta.is_authenticated === true ? userInfo : null;
} catch (e) {
return null;
}
},
queryFn: ShopAPIs.retrieveUserInfo(client),
retry: 3,
});

export const useSignInWithEmailMutation = () =>
export const useSignInWithEmailMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.USER_SIGN_IN_EMAIL,
mutationFn: clientDecorator(ShopAPIs.signInWithEmail),
meta: {
invalidates: [
QUERY_KEYS.USER,
QUERY_KEYS.CART_INFO,
QUERY_KEYS.ORDER_LIST,
],
},
mutationFn: ShopAPIs.signInWithEmail(client),
meta: { invalidates: [ QUERY_KEYS.BASE ] },
});

export const useSignInWithSNSMutation = () =>
export const useSignInWithSNSMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.USER_SIGN_IN_SNS,
mutationFn: clientDecorator(ShopAPIs.signInWithSNS),
meta: {
invalidates: [
QUERY_KEYS.USER,
QUERY_KEYS.CART_INFO,
QUERY_KEYS.ORDER_LIST,
],
},
mutationFn: ShopAPIs.signInWithSNS(client),
meta: { invalidates: [ QUERY_KEYS.BASE ] },
});

export const useSignOutMutation = () =>
export const useSignOutMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.USER_SIGN_OUT,
mutationFn: async () => {
try {
return await clientDecorator(ShopAPIs.signOut)();
} catch (e) {
return null;
}
},
meta: {
invalidates: [
QUERY_KEYS.USER,
QUERY_KEYS.CART_INFO,
QUERY_KEYS.ORDER_LIST,
],
},
mutationFn: ShopAPIs.signOut(client),
meta: { invalidates: [ QUERY_KEYS.BASE ] },
});

export const useProducts = (qs?: ShopSchemas.ProductListQueryParams) =>
export const useProducts = (client: ShopAPIClient, qs?: ShopSchemas.ProductListQueryParams) =>
useSuspenseQuery({
queryKey: QUERY_KEYS.PRODUCT_LIST,
queryFn: () => clientDecorator(ShopAPIs.listProducts)(qs),
queryFn: () => ShopAPIs.listProducts(client)(qs),
});

export const useCart = () =>
export const useCart = (client: ShopAPIClient) =>
useSuspenseQuery({
queryKey: QUERY_KEYS.CART_INFO,
queryFn: clientDecorator(ShopAPIs.retrieveCart),
queryFn: ShopAPIs.retrieveCart(client),
});

export const useAddItemToCartMutation = () =>
export const useAddItemToCartMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.CART_ITEM_APPEND,
mutationFn: clientDecorator(ShopAPIs.appendItemToCart),
mutationFn: ShopAPIs.appendItemToCart(client),
meta: { invalidates: [QUERY_KEYS.CART_INFO] },
});

export const useRemoveItemFromCartMutation = () =>
export const useRemoveItemFromCartMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.CART_ITEM_REMOVE,
mutationFn: clientDecorator(ShopAPIs.removeItemFromCart),
mutationFn: ShopAPIs.removeItemFromCart(client),
meta: { invalidates: [QUERY_KEYS.CART_INFO] },
});

export const usePrepareOneItemOrderMutation = () =>
export const usePrepareOneItemOrderMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.ONE_ITEM_ORDER_START,
mutationFn: clientDecorator(ShopAPIs.prepareOneItemOrder),
mutationFn: ShopAPIs.prepareOneItemOrder(client),
meta: { invalidates: [QUERY_KEYS.CART_INFO, QUERY_KEYS.ORDER_LIST] },
});

export const usePrepareCartOrderMutation = () =>
export const usePrepareCartOrderMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.CART_ORDER_START,
mutationFn: clientDecorator(ShopAPIs.prepareCartOrder),
mutationFn: ShopAPIs.prepareCartOrder(client),
meta: { invalidates: [QUERY_KEYS.CART_INFO, QUERY_KEYS.ORDER_LIST] },
});

export const useOrders = () =>
export const useOrders = (client: ShopAPIClient) =>
useSuspenseQuery({
queryKey: QUERY_KEYS.ORDER_LIST,
queryFn: clientDecorator(ShopAPIs.listOrders),
queryFn: ShopAPIs.listOrders(client),
});

export const useOneItemRefundMutation = () =>
export const useOneItemRefundMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.ONE_ITEM_REFUND,
mutationFn: clientDecorator(ShopAPIs.refundOneItemFromOrder),
mutationFn: ShopAPIs.refundOneItemFromOrder(client),
meta: { invalidates: [QUERY_KEYS.ORDER_LIST] },
});

export const useOrderRefundMutation = () =>
export const useOrderRefundMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.ALL_ORDER_REFUND,
mutationFn: clientDecorator(ShopAPIs.refundAllItemsInOrder),
mutationFn: ShopAPIs.refundAllItemsInOrder(client),
meta: { invalidates: [QUERY_KEYS.ORDER_LIST] },
});

export const useOptionsOfOneItemInOrderPatchMutation = () =>
export const useOptionsOfOneItemInOrderPatchMutation = (client: ShopAPIClient) =>
useMutation({
mutationKey: MUTATION_KEYS.CART_ITEM_APPEND,
mutationFn: clientDecorator(ShopAPIs.patchOrderOptions),
mutationFn: ShopAPIs.patchOrderOptions(client),
meta: { invalidates: [QUERY_KEYS.ORDER_LIST] },
});
}
Expand Down
6 changes: 0 additions & 6 deletions packages/shop/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as R from "remeda";

import ShopHooks from '../hooks';
import ShopSchemas from "../schemas";
import { startPortOnePurchase as _startPortOnePurchase } from "./portone";

Expand Down Expand Up @@ -30,11 +29,6 @@ namespace ShopAPIUtil {
return false;
};

export const getReceiptUrlFromOrder = (order: ShopSchemas.Order) => {
const { shopApiDomain } = ShopHooks.useShopContext();
return `${shopApiDomain}/v1/orders/${order.id}/receipt/`;
}

export const startPortOnePurchase = _startPortOnePurchase;
}

Expand Down