toast
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
import '@/bridge';
|
||||
import { router } from '@/shared/configs/sentry';
|
||||
import { Toasts } from '@/shared/ui/toasts/toasts';
|
||||
import { TopButton } from '@/widgets/top-button';
|
||||
import { useInitTheme } from './hooks';
|
||||
import { IOSStatusBar } from '@/widgets/ios-status-bar';
|
||||
import { RouterProvider } from 'react-router-dom';
|
||||
|
||||
export const App = () => {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { notiBar } from '@/shared/lib';
|
||||
import { useStore } from '@/shared/model/store';
|
||||
import { useEffect } from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
export const useNotiBar = () => {
|
||||
const [notiBarMessage, setNotiBarMessage] = useStore(
|
||||
useShallow((state: any) => [
|
||||
state.utilEventSlice.notiBarMessage,
|
||||
state.utilEventSlice.setNotiBarMessage
|
||||
])
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if(notiBarMessage) {
|
||||
notiBar(notiBarMessage);
|
||||
setNotiBarMessage('');
|
||||
}
|
||||
}, [notiBarMessage]);
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Link, useRouterState } from '@tanstack/react-router';
|
||||
import { Toasts } from '@/shared/ui/toasts/toasts';
|
||||
import { notiBar, snackBar } from '@/shared/lib/toast';
|
||||
import { ToastContainer,toast } from 'react-toastify';
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useUserFindAuthMethodMutation } from '@/entities/user/api/use-user-find
|
||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useUserModifyAuthMethodMutation } from '@/entities/user/api/use-user-modify-authmethod-mutation';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
|
||||
@@ -26,7 +25,7 @@ export const UserLoginAuthInfoWrap = ({
|
||||
const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation();
|
||||
const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({
|
||||
onSuccess: () => {
|
||||
snackBar('사용자 정보가 성공적으로 저장되었습니다.');
|
||||
// snackBar('사용자 정보가 성공적으로 저장되었습니다.');
|
||||
navigate(PATHS.account.user.manage, {
|
||||
state: {
|
||||
mid: mid,
|
||||
@@ -34,7 +33,7 @@ export const UserLoginAuthInfoWrap = ({
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.');
|
||||
// snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
|
||||
export const billingCharge = (params: BillingChargeParams) => {
|
||||
return resultify(
|
||||
axios.post<BillingChargeResponse>(API_URL_TRANSACTION.billingDetail(), params),
|
||||
axios.post<BillingChargeResponse>(API_URL_TRANSACTION.billingCharge(), params),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -59,14 +59,14 @@ export const BillingList = ({
|
||||
return (
|
||||
<>
|
||||
<div className="transaction-list">
|
||||
{ getListDateGroup() }
|
||||
<div className="apply-row bottom-padding">
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={ () => onClickToNavigate() }
|
||||
>결제 신청</button>
|
||||
</div>
|
||||
{ getListDateGroup() }
|
||||
</div>
|
||||
<div className="apply-row">
|
||||
<button
|
||||
className="btn-50 btn-blue flex-1"
|
||||
onClick={ () => onClickToNavigate() }
|
||||
>결제신청</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
useSetOnBack
|
||||
} from '@/widgets/sub-layout/use-sub-layout';
|
||||
import { useUserChangeCancelPasswordMutation } from '@/entities/user/api/use-user-change-cancel-password-mutation';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
import { useStore } from '@/shared/model/store';
|
||||
import { XKeypad, XKeypadManager, createPasswordKeypad } from '@/utils/xkeypad';
|
||||
|
||||
@@ -37,7 +36,7 @@ export const PasswordModifyCancelPasswordPage = () => {
|
||||
|
||||
const changeCancelPasswordMutation = useUserChangeCancelPasswordMutation({
|
||||
onSuccess: () => {
|
||||
snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
||||
// snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
||||
// Clear form and keypads
|
||||
setPassword('');
|
||||
setConfirmPassword('');
|
||||
@@ -49,7 +48,7 @@ export const PasswordModifyCancelPasswordPage = () => {
|
||||
navigate(PATHS.account.password.manage);
|
||||
},
|
||||
onError: (error) => {
|
||||
snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
||||
// snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
useSetOnBack
|
||||
} from '@/widgets/sub-layout/use-sub-layout';
|
||||
import { useUserChangePasswordMutation } from '@/entities/user/api/use-user-change-password-mutation';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
|
||||
export const PasswordModifyLoginPasswordPage = () => {
|
||||
const { navigate } = useNavigate();
|
||||
@@ -20,7 +19,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
||||
|
||||
const changePasswordMutation = useUserChangePasswordMutation({
|
||||
onSuccess: () => {
|
||||
snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
||||
// snackBar('비밀번호가 성공적으로 변경되었습니다.');
|
||||
// Clear form
|
||||
setCurrentPassword('');
|
||||
setNewPassword('');
|
||||
@@ -29,7 +28,7 @@ export const PasswordModifyLoginPasswordPage = () => {
|
||||
navigate(PATHS.account.password.manage);
|
||||
},
|
||||
onError: (error) => {
|
||||
snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
||||
// snackBar(error?.response?.data?.message || '비밀번호 변경에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import { VerificationItem } from '@/entities/account/model/types';
|
||||
import { useUserCreateMutation } from '@/entities/user/api/use-user-create-mutation';
|
||||
import { useUserExistsUseridQuery } from '@/entities/user/api/use-user-exists-userid-query';
|
||||
import { useLocation } from 'react-router';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
|
||||
export const UserAddAccountPage = () => {
|
||||
const { navigate } = useNavigate();
|
||||
@@ -21,10 +20,10 @@ export const UserAddAccountPage = () => {
|
||||
|
||||
const { mutateAsync: userCreate, isPending } = useUserCreateMutation({
|
||||
onSuccess: () => {
|
||||
snackBar('사용자가 성공적으로 추가되었습니다.');
|
||||
// snackBar('사용자가 성공적으로 추가되었습니다.');
|
||||
},
|
||||
onError: (error) => {
|
||||
snackBar(error?.response?.data?.message || '사용자 추가에 실패했습니다.');
|
||||
// snackBar(error?.response?.data?.message || '사용자 추가에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -382,7 +381,7 @@ export const UserAddAccountPage = () => {
|
||||
|
||||
if (response.status) {
|
||||
// 성공 시 사용자 관리 페이지로 이동
|
||||
snackBar('사용자가 성공적으로 추가되었습니다.');
|
||||
// snackBar('사용자가 성공적으로 추가되었습니다.');
|
||||
navigate(PATHS.account.user.manage);
|
||||
} else if (response.error) {
|
||||
// 에러 처리
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useLocation } from 'react-router';
|
||||
import { useUserMenuPermissionsSaveMutation } from '@/entities/user/api/use-user-menu-permission-save-mutation';
|
||||
// import { useUserMenuPermissionsMutation } from '@/entities/user/api/use-user-menu-permission-mutation';
|
||||
import { UserMenuPermissionData } from '@/entities/user/model/types';
|
||||
import { snackBar } from '@/shared/lib/toast';
|
||||
//import { snackBar } from '@/shared/lib/toast';
|
||||
|
||||
// 권한 비트 플래그 (실제 API 데이터 기준)
|
||||
const PERMISSION = {
|
||||
@@ -35,7 +35,7 @@ export const UserMenuAuthPage = () => {
|
||||
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||
const savePermissionsMutation = useUserMenuPermissionsSaveMutation({
|
||||
onSuccess: () => {
|
||||
snackBar('권한이 성공적으로 저장되었습니다.');
|
||||
//snackBar('권한이 성공적으로 저장되었습니다.');
|
||||
navigate(PATHS.account.user.accountAuth, {
|
||||
state: {
|
||||
mid,
|
||||
@@ -46,7 +46,7 @@ export const UserMenuAuthPage = () => {
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
snackBar(error?.response?.data?.message || '권한 저장에 실패했습니다.');
|
||||
// snackBar(error?.response?.data?.message || '권한 저장에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ChangeEvent, useState } from 'react';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { HeaderType } from '@/entities/common/model/types';
|
||||
import { CalendarType, HeaderType } from '@/entities/common/model/types';
|
||||
import { useBillingChargeMutation } from '@/entities/transaction/api/use-billing-charge-mutation';
|
||||
import {
|
||||
useSetOnBack,
|
||||
@@ -10,18 +10,26 @@ import {
|
||||
useSetHeaderType,
|
||||
useSetFooterMode
|
||||
} from '@/widgets/sub-layout/use-sub-layout';
|
||||
import { NumericFormat, PatternFormat } from 'react-number-format';
|
||||
import { showAlert } from '@/widgets/show-alert';
|
||||
import moment from 'moment';
|
||||
import NiceCalendar from '@/shared/ui/calendar/nice-calendar';
|
||||
import { notiBar, snackBar } from '@/shared/lib';
|
||||
|
||||
export const BillingChargePage = () => {
|
||||
const { navigate } = useNavigate();
|
||||
|
||||
const [billKey, setBillKey] = useState<string>('BIKYvattest01m');
|
||||
const [productName, setProductName] = useState<string>('테스트상품123');
|
||||
const [productAmount, setProductAmount] = useState<number>(1000000);
|
||||
const [orderNumber, setOrderNumber] = useState<string>('P146733723');
|
||||
const [buyerName, setBuyerName] = useState<string>('김테스트');
|
||||
const [paymentRequestDate, setPaymentRequestDate] = useState<string>('2025-06-08');
|
||||
const [billKey, setBillKey] = useState<string>('');
|
||||
const [productName, setProductName] = useState<string>('');
|
||||
const [productAmount, setProductAmount] = useState<number>(0);
|
||||
const [orderNumber, setOrderNumber] = useState<string>('');
|
||||
const [buyerName, setBuyerName] = useState<string>('');
|
||||
const [paymentRequestDate, setPaymentRequestDate] = useState<string>(moment().format('YYYY.MM.DD'));
|
||||
const [installmentMonth, setInstallmentMonth] = useState<string>('00');
|
||||
|
||||
const [calendarOpen, setCalendarOpen] = useState<boolean>(false);
|
||||
|
||||
|
||||
useSetHeaderTitle('빌링 결제 신청');
|
||||
useSetHeaderType(HeaderType.RightClose);
|
||||
useSetOnBack(() => {
|
||||
@@ -31,23 +39,64 @@ export const BillingChargePage = () => {
|
||||
|
||||
const { mutateAsync: billingCharge } = useBillingChargeMutation();
|
||||
|
||||
const setNewDate = (date: string) => {
|
||||
setPaymentRequestDate(moment(date).format('YYYY.MM.DD'));
|
||||
setCalendarOpen(false);
|
||||
};
|
||||
const onClickToOpenCalendar = () => {
|
||||
setCalendarOpen(true);
|
||||
};
|
||||
|
||||
const onClickToBillingCharge = () => {
|
||||
if(!billKey){
|
||||
showAlert('빌키는 필수 입력 항목입니다.');
|
||||
return;
|
||||
}
|
||||
else if(!productName){
|
||||
showAlert('상품명은 필수 입력 항목입니다.');
|
||||
}
|
||||
else if(!productAmount){
|
||||
showAlert('상품금액은 필수 입력 항목입니다.');
|
||||
}
|
||||
else if(productAmount <= 0){
|
||||
showAlert('상품금액은 0보다 커야 합니다.');
|
||||
}
|
||||
else if(!orderNumber){
|
||||
showAlert('주문번호는 필수 입력 항목입니다.');
|
||||
}
|
||||
else if(!buyerName){
|
||||
showAlert('구매자명은 필수 입력 항목입니다.');
|
||||
}
|
||||
|
||||
let params = {
|
||||
billKey: billKey,
|
||||
productName: productName,
|
||||
productAmount: productAmount,
|
||||
orderNumber: orderNumber,
|
||||
buyerName: buyerName,
|
||||
paymentRequestDate: paymentRequestDate,
|
||||
paymentRequestDate: moment(paymentRequestDate).format('YYYYMMDD'),
|
||||
installmentMonth: installmentMonth
|
||||
};
|
||||
billingCharge(params).then((rs) => {
|
||||
console.log(rs);
|
||||
alert('성공')
|
||||
navigate(PATHS.transaction.billing.list);
|
||||
}).catch((e: any) => {
|
||||
/*
|
||||
if(e.response?.data?.message){
|
||||
showAlert(e.response?.data?.message);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeBillKey = (value: string) => {
|
||||
const pattern = /^[A-Za-z0-9]+$/;
|
||||
if(pattern.test(value) || value === ''){
|
||||
setBillKey(value);
|
||||
}
|
||||
};
|
||||
|
||||
const makeInstallmentMonthSelect = () => {
|
||||
let rs = [];
|
||||
|
||||
@@ -88,8 +137,8 @@ export const BillingChargePage = () => {
|
||||
<div className="billing-field">
|
||||
<input
|
||||
type="text"
|
||||
readOnly={ true }
|
||||
value={ billKey }
|
||||
onChange={ (e: ChangeEvent<HTMLInputElement>) => onChangeBillKey(e.target.value) }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,11 +155,12 @@ export const BillingChargePage = () => {
|
||||
<div className="billing-row">
|
||||
<div className="billing-label">상품금액 <span>*</span></div>
|
||||
<div className="billing-field">
|
||||
<input
|
||||
type="text"
|
||||
<NumericFormat
|
||||
value={ productAmount }
|
||||
allowNegative={ false }
|
||||
displayType="input"
|
||||
onChange={ (e: ChangeEvent<HTMLInputElement>) => setProductAmount(parseInt(e.target.value)) }
|
||||
/>
|
||||
></NumericFormat>
|
||||
</div>
|
||||
</div>
|
||||
<div className="billing-row">
|
||||
@@ -140,13 +190,14 @@ export const BillingChargePage = () => {
|
||||
<div className="input-wrapper date wid-100">
|
||||
<input
|
||||
type="text"
|
||||
placeholder=""
|
||||
placeholder="날짜 선택"
|
||||
value={ paymentRequestDate }
|
||||
readOnly={ true }
|
||||
/>
|
||||
<button
|
||||
className="date-btn"
|
||||
type="button"
|
||||
|
||||
onClick={ () => onClickToOpenCalendar() }
|
||||
>
|
||||
<img
|
||||
src={ IMAGE_ROOT + '/ico_date.svg' }
|
||||
@@ -179,6 +230,12 @@ export const BillingChargePage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<NiceCalendar
|
||||
calendarOpen={ calendarOpen }
|
||||
setCalendarOpen={ setCalendarOpen }
|
||||
calendarType={ CalendarType.Single }
|
||||
setNewDate={ setNewDate }
|
||||
></NiceCalendar>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -32,9 +32,9 @@ export const BillingListPage = () => {
|
||||
const [mid, setMid] = useState<string>(userMid);
|
||||
const [searchType, setSearchType] = useState<BillingSearchType>(BillingSearchType.ALL);
|
||||
const [searchKeyword, setSearchKeyword] = useState<string>('');
|
||||
// const [startDate, setStartDate] = useState(moment().subtract(1, 'month').format('YYYY-MM-DD'));
|
||||
const [startDate, setStartDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [startDate, setStartDate] = useState(moment().subtract(1, 'month').format('YYYYMMDD'));
|
||||
//const [startDate, setStartDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [requestStatus, setRequestStatus] = useState<BillingRequestStatus>(BillingRequestStatus.ALL);
|
||||
const [processResult, setProcessResult] = useState<BillingProcessResult>(BillingProcessResult.ALL);
|
||||
const [paymentMethod, setPaymentMethod] = useState<BillingPaymentMethod>(BillingPaymentMethod.ALL);
|
||||
@@ -76,8 +76,9 @@ export const BillingListPage = () => {
|
||||
maxAmount: newMaxAmount,
|
||||
page: pageParam
|
||||
};
|
||||
|
||||
if(listParams.page){
|
||||
listParams.page.sortType = (option?.sortType)? option.sortType: sortType;
|
||||
listParams.page.sortType = option?.sortType || sortType;
|
||||
setPageParam(listParams.page);
|
||||
}
|
||||
|
||||
@@ -114,6 +115,14 @@ export const BillingListPage = () => {
|
||||
useEffect(() => {
|
||||
callList();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
callList();
|
||||
}, [
|
||||
mid, searchType, searchKeyword,
|
||||
startDate, endDate,
|
||||
requestStatus, processResult, paymentMethod,
|
||||
minAmount, maxAmount
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -5,7 +5,18 @@ import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { CashReceiptList } from '@/entities/transaction/ui/cash-receipt-list';
|
||||
import { CashReceiptListItem, TransactionCategory, CashReceiptPurposeType, CashReceiptProcessResult, ListItemProps, CashReceiptListParams, CashReceiptTransactionType, CashReceiptSearchNumberType, CashReceiptSummaryParams, CashReceiptListResponse, CashReceiptSummaryResponse } from '@/entities/transaction/model/types';
|
||||
import {
|
||||
TransactionCategory,
|
||||
CashReceiptPurposeType,
|
||||
CashReceiptProcessResult,
|
||||
ListItemProps,
|
||||
CashReceiptListParams,
|
||||
CashReceiptTransactionType,
|
||||
CashReceiptSearchNumberType,
|
||||
CashReceiptSummaryParams,
|
||||
CashReceiptListResponse,
|
||||
CashReceiptSummaryResponse
|
||||
} from '@/entities/transaction/model/types';
|
||||
import { useCashReceiptListMutation } from '@/entities/transaction/api/use-cash-receipt-list-mutation';
|
||||
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
|
||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||
@@ -127,9 +138,8 @@ export const CashReceiptListPage = () => {
|
||||
callList();
|
||||
}, [
|
||||
mid, startDate, endDate,
|
||||
purposeType, transactionType,
|
||||
processResult, searchNumberType,
|
||||
searchNumber
|
||||
purposeType, transactionType, processResult,
|
||||
searchNumberType, searchNumber
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,15 @@ import { IMAGE_ROOT } from '@/shared/constants/common';
|
||||
import { PATHS } from '@/shared/constants/paths';
|
||||
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
|
||||
import { EscrowList } from '@/entities/transaction/ui/escrow-list';
|
||||
import { EscrowListItem, TransactionCategory, EscrowDeliveryStatus, EscrowSearchType, EscrowSettlementStatus, ListItemProps } from '@/entities/transaction/model/types';
|
||||
import {
|
||||
TransactionCategory,
|
||||
EscrowDeliveryStatus,
|
||||
EscrowSearchType,
|
||||
EscrowSettlementStatus,
|
||||
ListItemProps,
|
||||
EscrowListParams,
|
||||
EscrowListResponse
|
||||
} from '@/entities/transaction/model/types';
|
||||
import { useEscrowListMutation } from '@/entities/transaction/api/use-escrow-list-mutation';
|
||||
import { useDownloadExcelMutation } from '@/entities/transaction/api/use-download-excel-mutation';
|
||||
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
|
||||
@@ -32,9 +40,9 @@ export const EscrowListPage = () => {
|
||||
const [mid, setMid] = useState<string>(userMid);
|
||||
const [searchType, setSearchType] = useState<EscrowSearchType>(EscrowSearchType.ALL);
|
||||
const [searchKeyword, setSearchKeyword] = useState<string>('');
|
||||
//const [startDate, setStartDate] = useState(moment().subtract(1, 'month').format('YYYY-MM-DD'));
|
||||
const [startDate, setStartDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYY-MM-DD'));
|
||||
const [startDate, setStartDate] = useState(moment().subtract(1, 'month').format('YYYYMMDD'));
|
||||
// const [startDate, setStartDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [endDate, setEndDate] = useState(moment().format('YYYYMMDD'));
|
||||
const [deliveryStatus, setDeliveryStatus] = useState<EscrowDeliveryStatus>(EscrowDeliveryStatus.ALL);
|
||||
const [settlementStatus, setSettlementStatus] = useState<EscrowSettlementStatus>(EscrowSettlementStatus.ALL);
|
||||
const [minAmount, setMinAmount] = useState<number>();
|
||||
@@ -62,7 +70,7 @@ export const EscrowListPage = () => {
|
||||
if(!!maxAmount && typeof(maxAmount) === 'string'){
|
||||
newMaxAmount = parseInt(maxAmount);
|
||||
}
|
||||
let listParams = {
|
||||
let listParams: EscrowListParams = {
|
||||
mid: mid,
|
||||
searchType: 'ORDER_NUMBER',
|
||||
searchKeyword: searchKeyword,
|
||||
@@ -74,12 +82,13 @@ export const EscrowListPage = () => {
|
||||
maxAmount: newMaxAmount,
|
||||
page: pageParam
|
||||
};
|
||||
|
||||
if(listParams.page){
|
||||
listParams.page.sortType = (option?.sortType)? option.sortType: sortType;
|
||||
listParams.page.sortType = option?.sortType || sortType;
|
||||
setPageParam(listParams.page);
|
||||
}
|
||||
|
||||
escrowList(listParams).then((rs) => {
|
||||
escrowList(listParams).then((rs: EscrowListResponse) => {
|
||||
setListItems(rs.content);
|
||||
});
|
||||
};
|
||||
@@ -112,6 +121,14 @@ export const EscrowListPage = () => {
|
||||
useEffect(() => {
|
||||
callList();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
callList();
|
||||
}, [
|
||||
mid, searchType, searchKeyword,
|
||||
startDate, endDate,
|
||||
deliveryStatus, settlementStatus,
|
||||
minAmount, maxAmount
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -3,7 +3,7 @@ import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'ax
|
||||
import { WHITE_LIST_URLS } from '@/shared/api/urls';
|
||||
import { StorageKeys } from '@/shared/constants/local-storage';
|
||||
import { checkIsAxiosError, getLocalStorage, setLocalStorage } from '@/shared/lib';
|
||||
import { finalizeConfig, extractAccessToken, extractRequestId } from './utils';
|
||||
import { finalizeConfig } from './utils';
|
||||
import { HEADER_USER_AGENT } from '@/shared/constants/url';
|
||||
import { appBridge } from '@/utils/appBridge';
|
||||
import { useAppBridge } from '@/hooks';
|
||||
@@ -30,22 +30,10 @@ const onRequestFulfilled = (config: InternalAxiosRequestConfig) => {
|
||||
};
|
||||
|
||||
const onRequestRejected = (error: any) => {
|
||||
const { method, url, params, data, headers } = error.config;
|
||||
/*
|
||||
Sentry.setContext('API Request Detail', {
|
||||
method,
|
||||
url,
|
||||
params,
|
||||
data,
|
||||
headers,
|
||||
});
|
||||
*/
|
||||
return Promise.reject(error);
|
||||
};
|
||||
|
||||
const onResponseFulfilled = (response: AxiosResponse) => {
|
||||
extractAccessToken(response);
|
||||
extractRequestId(response);
|
||||
return {
|
||||
...response,
|
||||
data: response.data.data || response.data,
|
||||
@@ -73,22 +61,13 @@ const onResponseRejected = (error: AxiosError) => {
|
||||
});
|
||||
|
||||
}
|
||||
/*
|
||||
else if (error?.response) {
|
||||
const { data, status } = error.response;
|
||||
extractRequestId(error?.response);
|
||||
Sentry.setContext('API Response Detail', {
|
||||
status,
|
||||
data,
|
||||
});
|
||||
}
|
||||
*/
|
||||
return new Promise((_resolve, reject) => {
|
||||
if (checkIsAxiosError(error)) {
|
||||
if(checkIsAxiosError(error)){
|
||||
// iOS의 경우 window에서 unload event가 일어날때 네트워크 에러가 발생하곤 해서 이런 케이스를 방지하기 위해 지연시킴
|
||||
// location.href, location.reload 등으로 unload event가 일어나면 자바스크립트 런타임이 초기화되므로 settimeout으로 인한 네트워크 에러가 트리거 x
|
||||
setTimeout(() => reject(error), 300);
|
||||
} else {
|
||||
}
|
||||
else{
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { InternalAxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { StorageKeys } from '@/shared/constants/local-storage';
|
||||
import { setLocalStorage } from '@/shared/lib';
|
||||
import { InternalAxiosRequestConfig } from 'axios';
|
||||
|
||||
export const finalizeConfig = (config: InternalAxiosRequestConfig) => {
|
||||
const { params, data } = config;
|
||||
@@ -9,21 +7,4 @@ export const finalizeConfig = (config: InternalAxiosRequestConfig) => {
|
||||
params,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
export const extractAccessToken = (response: AxiosResponse): void => {
|
||||
const authHeader = response?.headers?.['authorization'];
|
||||
if (authHeader) {
|
||||
const accessToken = authHeader.substring(7);
|
||||
setLocalStorage(StorageKeys.Jwt, accessToken);
|
||||
}
|
||||
};
|
||||
|
||||
export const extractRequestId = (response: AxiosResponse): void => {
|
||||
const requestIdHeader = response?.headers?.['x-request-id'];
|
||||
if (requestIdHeader) {
|
||||
const requestId = requestIdHeader.replaceAll(', *', '');
|
||||
console.log('requestId --> ', requestId);
|
||||
setLocalStorage(StorageKeys.RequestId, requestId);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -8,15 +8,15 @@ import {
|
||||
export type NavigateTo = PathType | -1 | 0;
|
||||
|
||||
export const goBackWebview = (goBack: () => void) => {
|
||||
if (!window.ReactNativeWebView) {
|
||||
if (window.history.state?.idx > 0) {
|
||||
goBack();
|
||||
return;
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
if(window.history.state?.idx > 0){
|
||||
goBack();
|
||||
return;
|
||||
}
|
||||
else{
|
||||
window.close();
|
||||
}
|
||||
return;
|
||||
|
||||
};
|
||||
|
||||
export const useNavigate = () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @cspell/spellchecker */
|
||||
import { toast } from 'react-toastify';
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
export const snackBar = (text: string) => {
|
||||
toast.dismiss({ containerId: 'snackbar' });
|
||||
toast(text, { containerId: 'snackbar' });
|
||||
@@ -7,5 +7,5 @@ export const snackBar = (text: string) => {
|
||||
|
||||
export const notiBar = (text: string) => {
|
||||
toast.dismiss({ containerId: 'notibar' });
|
||||
toast(text);
|
||||
};
|
||||
toast(text, { containerId: 'notibar' });
|
||||
};
|
||||
@@ -1,21 +1,22 @@
|
||||
/* eslint-disable @cspell/spellchecker */
|
||||
import { Slide, ToastContainer } from 'react-toastify';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledNotiBar = styled(ToastContainer)`
|
||||
// https://styled-components.com/docs/faqs#how-can-i-override-styles-with-higher-specificity
|
||||
&&&.Toastify__toast-container {
|
||||
transform: translateX(2.5%);
|
||||
|
||||
}
|
||||
.Toastify__toast {
|
||||
min-height: auto;
|
||||
width: 95%;
|
||||
width: calc(100% - 32px);
|
||||
height: auto;
|
||||
|
||||
background-color: #262d42;
|
||||
margin-top: 20px;
|
||||
background-color: rgba(45, 52, 54, 0.8);
|
||||
box-sizing: border-box;
|
||||
color: #ffffff;
|
||||
|
||||
border-radius: 0px 0px 20px 20px;
|
||||
border-radius: 20px 20px 20px 20px;
|
||||
text-align: center;
|
||||
-webkit-box-shadow: 1px 1px 10px 0px rgba(43, 38, 38, 0.5);
|
||||
-moz-box-shadow: 1px 1px 10px 0px rgba(43, 38, 38, 0.5);
|
||||
@@ -23,7 +24,7 @@ const StyledNotiBar = styled(ToastContainer)`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
padding: 6px 0 9px 0;
|
||||
}
|
||||
.Toastify__toast-body {
|
||||
padding: 0;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @cspell/spellchecker */
|
||||
import { cssTransition, ToastContainer } from 'react-toastify';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -8,12 +7,14 @@ const StyledSnackBar = styled(ToastContainer)`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
bottom: 20px;
|
||||
bottom: 30px;
|
||||
pointer-events: none;
|
||||
margin-bottom: calc(env(safe-area-inset-top) / 3);
|
||||
z-index: 1000;
|
||||
}
|
||||
.Toastify__toast {
|
||||
pointer-events: none;
|
||||
calc(100% - 32px);
|
||||
height: auto;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
@@ -23,8 +24,9 @@ const StyledSnackBar = styled(ToastContainer)`
|
||||
min-height: auto;
|
||||
border-radius: 50px;
|
||||
padding: 10px 20px;
|
||||
background-color: rgba(34, 37, 56, 0.555);
|
||||
background-color: rgba(45, 52, 54, 0.8);
|
||||
width: 85%;
|
||||
color: #ffffff
|
||||
}
|
||||
.Toastify__toast-body {
|
||||
padding: 0;
|
||||
@@ -53,7 +55,7 @@ export const SnackBar = () => {
|
||||
return (
|
||||
<StyledSnackBar
|
||||
position="bottom-center"
|
||||
autoClose={2000}
|
||||
autoClose={3000}
|
||||
limit={1}
|
||||
hideProgressBar
|
||||
newestOnTop={false}
|
||||
@@ -62,7 +64,6 @@ export const SnackBar = () => {
|
||||
pauseOnFocusLoss={false}
|
||||
draggable={false}
|
||||
pauseOnHover={false}
|
||||
transition={fade}
|
||||
containerId={'snackbar'}
|
||||
draggablePercent={10}
|
||||
closeButton={false}
|
||||
|
||||
@@ -8,7 +8,7 @@ type CommonErrorProps = FallbackProps & {
|
||||
height?: number;
|
||||
};
|
||||
export const APIError = ({ error, resetErrorBoundary }: CommonErrorProps) => {
|
||||
const { navigateBack } = useNavigate();
|
||||
const { reload } = useNavigate();
|
||||
const msg = useMemo(() => {
|
||||
let message: Partial<DialogProps> = {
|
||||
title: '일시적인 오류가 발생하였습니다.',
|
||||
@@ -21,7 +21,7 @@ export const APIError = ({ error, resetErrorBoundary }: CommonErrorProps) => {
|
||||
}, [error]);
|
||||
|
||||
const handleCancel = () => {
|
||||
navigateBack();
|
||||
reload();
|
||||
resetErrorBoundary();
|
||||
};
|
||||
|
||||
@@ -30,8 +30,8 @@ export const APIError = ({ error, resetErrorBoundary }: CommonErrorProps) => {
|
||||
afterLeave={() => null}
|
||||
open={true}
|
||||
onClose={() => null}
|
||||
onConfirmClick={resetErrorBoundary}
|
||||
onCancelClick={handleCancel}
|
||||
onConfirmClick={ resetErrorBoundary }
|
||||
onCancelClick={ handleCancel }
|
||||
message={msg.message}
|
||||
buttonLabel={['취소', '재시도']}
|
||||
/>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Fragment } from 'react/jsx-runtime';
|
||||
import { useAppColor } from '@/shared/lib/hooks/use-change-bg-color';
|
||||
|
||||
export const IOSStatusBar = () => {
|
||||
const [appColor] = useAppColor();
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
||||
|
||||
if(!isIOS){
|
||||
return <Fragment></Fragment>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ios-status-bar" style={{ backgroundColor: appColor }}></div>
|
||||
);
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
interface EventListeners {
|
||||
element: HTMLElement | null;
|
||||
onScroll: () => void;
|
||||
onTouchStart: () => void;
|
||||
onTouchMove: () => void;
|
||||
onTouchEnd: () => void;
|
||||
}
|
||||
|
||||
export const addEventListeners = ({ element, onScroll, onTouchStart, onTouchMove, onTouchEnd }: EventListeners) => {
|
||||
element?.addEventListener('scroll', onScroll);
|
||||
element?.addEventListener('touchstart', onTouchStart, { passive: true });
|
||||
element?.addEventListener('touchmove', onTouchMove, { passive: true });
|
||||
element?.addEventListener('touchend', onTouchEnd, { passive: true });
|
||||
};
|
||||
|
||||
export const removeEventListeners = ({ element, onScroll, onTouchStart, onTouchMove, onTouchEnd }: EventListeners) => {
|
||||
element?.removeEventListener('scroll', onScroll);
|
||||
element?.removeEventListener('touchstart', onTouchStart);
|
||||
element?.removeEventListener('touchmove', onTouchMove);
|
||||
element?.removeEventListener('touchend', onTouchEnd);
|
||||
};
|
||||
@@ -1,103 +0,0 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { AnimatePresence, motion, useMotionValue } from 'framer-motion';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
import { useRouteChangeEffect } from './use-route-change-effect';
|
||||
import { useScrollEventListeners } from './use-scroll-event-listeners';
|
||||
import { useScrollTarget } from './use-scroll-target';
|
||||
|
||||
const TIME_OUT = 5000;
|
||||
const THRASH_HOLD = 30;
|
||||
|
||||
let isScrollingBackToTop = false;
|
||||
let lastScrollY = 0;
|
||||
let isTouching = false;
|
||||
|
||||
export const TopButton = () => {
|
||||
const scrollTarget = useScrollTarget();
|
||||
const scrollY = useMotionValue(scrollTarget.current?.scrollTop ?? 0);
|
||||
|
||||
const scrollTimeOutRef = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
const [showButton, setShowButton] = useState<boolean | undefined>();
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setShowButton(false);
|
||||
isScrollingBackToTop = false;
|
||||
isTouching = false;
|
||||
if (scrollTarget.current) {
|
||||
scrollTarget.current.scrollTop = 0;
|
||||
}
|
||||
clearTimeout(scrollTimeOutRef.current);
|
||||
}, []);
|
||||
|
||||
const initialize = useCallback(() => {
|
||||
reset();
|
||||
lastScrollY = 0;
|
||||
}, []);
|
||||
|
||||
const scrollBackToTop = useCallback(() => {
|
||||
reset();
|
||||
}, []);
|
||||
|
||||
const onScroll = () => {
|
||||
if (isTouching) return;
|
||||
const currentScrollY = scrollTarget.current?.scrollTop ?? 0;
|
||||
const direction = currentScrollY > lastScrollY ? 'down' : 'up';
|
||||
lastScrollY = currentScrollY <= 0 ? 0 : currentScrollY;
|
||||
|
||||
scrollY.set(currentScrollY);
|
||||
clearTimeout(scrollTimeOutRef.current);
|
||||
|
||||
setShowButton(direction === 'down' ? false : currentScrollY > THRASH_HOLD);
|
||||
|
||||
if (!isScrollingBackToTop && direction === 'down') {
|
||||
scrollTimeOutRef.current = setTimeout(() => {
|
||||
setShowButton(true);
|
||||
}, TIME_OUT);
|
||||
}
|
||||
if (currentScrollY === 0) {
|
||||
isScrollingBackToTop = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onTouchStart = useCallback(() => {
|
||||
isTouching = true;
|
||||
}, []);
|
||||
const onTouchMove = useCallback(() => {
|
||||
isTouching = true;
|
||||
}, []);
|
||||
const onTouchEnd = useCallback(() => {
|
||||
isTouching = false;
|
||||
}, []);
|
||||
|
||||
useScrollEventListeners({
|
||||
scrollTarget,
|
||||
onScroll,
|
||||
onTouchStart,
|
||||
onTouchMove,
|
||||
onTouchEnd,
|
||||
});
|
||||
|
||||
useRouteChangeEffect({
|
||||
scrollTarget,
|
||||
onScroll,
|
||||
onTouchStart,
|
||||
onTouchMove,
|
||||
onTouchEnd,
|
||||
callback: initialize,
|
||||
});
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{showButton && (
|
||||
<motion.button
|
||||
onClick={scrollBackToTop}
|
||||
className={'btn goto-top-btn'}
|
||||
initial={{ translateY: '110%' }}
|
||||
animate={{ translateY: '0%' }}
|
||||
>
|
||||
위로
|
||||
</motion.button>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useIsFetching, useIsMutating } from '@tanstack/react-query';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { useRouterListener } from '@/shared/lib/hooks';
|
||||
import { addEventListeners, removeEventListeners } from './handle-event-listeners';
|
||||
|
||||
interface RouteChangeEffect {
|
||||
scrollTarget: React.MutableRefObject<HTMLElement | null>;
|
||||
onScroll: () => void;
|
||||
onTouchStart: () => void;
|
||||
onTouchMove: () => void;
|
||||
onTouchEnd: () => void;
|
||||
callback: () => void;
|
||||
}
|
||||
|
||||
export const useRouteChangeEffect = ({
|
||||
scrollTarget,
|
||||
onScroll,
|
||||
onTouchStart,
|
||||
onTouchMove,
|
||||
onTouchEnd,
|
||||
callback,
|
||||
}: RouteChangeEffect) => {
|
||||
const isFetching = useIsFetching();
|
||||
const isMutating = useIsMutating();
|
||||
const isLoading = isFetching > 0 || isMutating > 0;
|
||||
|
||||
const resetScrollTarget = useCallback(() => {
|
||||
const rootEl = document.getElementById('root') as HTMLElement;
|
||||
const pullToRefreshEl = document.getElementsByClassName('ptr__children')[0] as HTMLElement;
|
||||
|
||||
scrollTarget.current = rootEl;
|
||||
if (pullToRefreshEl?.scrollHeight > window.innerHeight) {
|
||||
scrollTarget.current = pullToRefreshEl;
|
||||
addEventListeners({ element: pullToRefreshEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
removeEventListeners({ element: rootEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
} else {
|
||||
addEventListeners({ element: rootEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
removeEventListeners({ element: pullToRefreshEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (isLoading) return;
|
||||
resetScrollTarget();
|
||||
}, [isLoading]);
|
||||
|
||||
useRouterListener(() => {
|
||||
setTimeout(() => {
|
||||
callback?.();
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { MutableRefObject, useEffect } from 'react';
|
||||
|
||||
import { addEventListeners, removeEventListeners } from './handle-event-listeners';
|
||||
|
||||
interface EventListeners {
|
||||
scrollTarget: MutableRefObject<HTMLElement | null>;
|
||||
onScroll: () => void;
|
||||
onTouchStart: () => void;
|
||||
onTouchMove: () => void;
|
||||
onTouchEnd: () => void;
|
||||
}
|
||||
export const useScrollEventListeners = ({
|
||||
scrollTarget,
|
||||
onScroll,
|
||||
onTouchStart,
|
||||
onTouchMove,
|
||||
onTouchEnd,
|
||||
}: EventListeners) => {
|
||||
useEffect(() => {
|
||||
if(!scrollTarget.current){
|
||||
return () => {};
|
||||
}
|
||||
addEventListeners({ element: scrollTarget.current, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
|
||||
return () => {
|
||||
const rootEl = document.getElementById('root') as HTMLElement;
|
||||
const pullToRefreshEl = document.getElementsByClassName('ptr__children')[0] as HTMLElement;
|
||||
removeEventListeners({ element: rootEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
removeEventListeners({ element: pullToRefreshEl, onScroll, onTouchStart, onTouchMove, onTouchEnd });
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export const useScrollTarget = () => {
|
||||
const scrollTarget = useRef<HTMLElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const rootEl = document.getElementById('root') as HTMLElement;
|
||||
const pullToRefreshEl = document.getElementsByClassName('ptr__children')[0] as HTMLElement;
|
||||
|
||||
let target: HTMLElement | null = rootEl;
|
||||
if (pullToRefreshEl?.scrollHeight > window.innerHeight) {
|
||||
target = pullToRefreshEl;
|
||||
}
|
||||
scrollTarget.current = target;
|
||||
|
||||
return () => {
|
||||
scrollTarget.current = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return scrollTarget;
|
||||
};
|
||||
Reference in New Issue
Block a user