diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json
index e48f04990d..d1b992edc3 100644
--- a/web/src/config/lang/en.json
+++ b/web/src/config/lang/en.json
@@ -2286,7 +2286,9 @@
"CHECK_CONFIRM_PAYMENT_DESC_2": "After confirming below the crypto ({0} {1}) will be released.",
"CHECK_CONFIRM_DECLARATION": "I confirm that I have received the correct payment",
"P2P_ORDER_COMPLETE": "P2P Order Complete",
- "EXIST_PAYMENT_METHOD_DESC": "You’ve already added a payment method for {0}"
+ "EXIST_PAYMENT_METHOD_DESC": "You’ve already added a payment method for {0}",
+ "ADMIN_ORDER_CANCELLATION_MESSAGE": "An exchange operator has cancelled this order. The transaction is closed.",
+ "TIME_LIMIT_REACHED": "0:00 (Please contact your counter-party)"
},
"VOLUME": {
"VOLUME": "VOLUME",
diff --git a/web/src/containers/Admin/Trades/index.css b/web/src/containers/Admin/Trades/index.css
index 2b541ee076..1ff30ecbba 100644
--- a/web/src/containers/Admin/Trades/index.css
+++ b/web/src/containers/Admin/Trades/index.css
@@ -819,3 +819,26 @@
.p2p-admin-confirm-warning-popup-wrapper .ant-modal-close-x {
color: white;
}
+
+.p2p-admin-order-details-popup-wrapper
+ .p2p-admin-order-details-container
+ .title {
+ font-size: 22px;
+ margin-bottom: 3%;
+}
+
+.p2p-admin-order-details-popup-wrapper
+ .p2p-admin-order-details-container
+ .order-details {
+ margin-top: 2%;
+ display: flex;
+ align-items: center;
+}
+
+.p2p-admin-order-details-popup-wrapper
+ .p2p-admin-order-details-container
+ .order-details
+ .asset-icon {
+ position: relative;
+ top: 3px;
+}
diff --git a/web/src/containers/Admin/Trades/p2pActive.js b/web/src/containers/Admin/Trades/p2pActive.js
index fb42a2034e..a8815b7712 100644
--- a/web/src/containers/Admin/Trades/p2pActive.js
+++ b/web/src/containers/Admin/Trades/p2pActive.js
@@ -9,8 +9,9 @@ import {
} from 'containers/P2P/actions/p2pActions';
import { getToken } from 'utils/token';
import { WS_URL } from 'config/constants';
+import { Coin } from 'components';
-const dataSource = (setIsConfirmWarning, setUserData) => {
+const dataSource = (setIsConfirmWarning, setUserData, setIsOrderDetails) => {
return [
{ title: 'Order Id', dataIndex: 'id', key: 'id' },
{
@@ -51,15 +52,32 @@ const dataSource = (setIsConfirmWarning, setUserData) => {
);
},
},
+ {
+ title: 'View More',
+ render: (data) => {
+ return (
+
+ );
+ },
+ },
];
};
-const P2PActive = ({ user }) => {
+const P2PActive = ({ user, coins }) => {
const [getOrders, setGetOrders] = useState();
const [selectedTransaction, setSelectedTransaction] = useState();
const [webSocket, setWebSocket] = useState();
const [isConfirmWarning, setIsConfirmWarning] = useState(false);
const [userData, setUserData] = useState();
+ const [isOrderDetails, setIsOrderDetails] = useState(false);
const fetchData = async () => {
try {
@@ -162,7 +180,7 @@ const P2PActive = ({ user }) => {
user_status: 'cancelled',
});
fetchData();
- notificationStatus('cancelled');
+ notificationStatus('cancelled', 'admin cancel');
setSelectedTransaction(data);
} catch (error) {
console.error(error);
@@ -210,8 +228,91 @@ const P2PActive = ({ user }) => {
+ }
+ visible={isOrderDetails}
+ footer={null}
+ onCancel={() => {
+ setIsOrderDetails(false);
+ }}
+ width={450}
+ className="p2p-admin-order-details-popup-wrapper p2p-admin-confirm-warning-popup-wrapper"
+ >
+
+
Order Details
+
+
+ Transaction Id :
+
+ {userData?.transaction_id}
+
+
+ Fiat Amount:
+ {userData?.amount_fiat}
+
+ {userData?.deal?.spending_asset?.toUpperCase()}
+
+
+
+
+
+
+
+ Price:
+ {userData?.price}
+
+ {userData?.deal?.spending_asset?.toUpperCase()}
+
+
+
+
+ (per coin)
+
+ {userData?.deal?.buying_asset?.toUpperCase()}
+
+
+
+
+
+
+ Crypto Amount:
+ {userData?.amount_digital_currency}
+
+ {userData?.deal?.buying_asset?.toUpperCase()}
+
+
+
+
+
+
+
+ Payment Method:
+
+
+ {userData?.payment_method_used?.system_name}
+
+
+
+
@@ -221,6 +322,7 @@ const P2PActive = ({ user }) => {
const mapStateToProps = (state) => ({
user: state.user,
+ coins: state.app.coins,
});
export default connect(mapStateToProps)(P2PActive);
diff --git a/web/src/containers/App/MobileBarMoreOptions.js b/web/src/containers/App/MobileBarMoreOptions.js
index 9a3f3e873a..622a840a52 100644
--- a/web/src/containers/App/MobileBarMoreOptions.js
+++ b/web/src/containers/App/MobileBarMoreOptions.js
@@ -38,6 +38,7 @@ const MobileBarMoreOptions = ({
pinnedAsset,
getMarkets,
quickTrade,
+ getRemoteRoutes,
}) => {
const [search, setSearch] = useState('');
const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -274,10 +275,8 @@ const MobileBarMoreOptions = ({
STRINGS['MORE_OPTIONS_LABEL.OTHER_FUNCTIONS.SECURITY'],
],
},
- {
- icon_id: 'BUY_CRYPTO_OPTION',
- iconText: 'MORE_OPTIONS_LABEL.ICONS.BUY_CRYPTO',
- path: '/buy-crypto',
+ ...getRemoteRoutes?.map((route, index) => ({
+ ...route,
isDisplay: true,
searchContent: [
STRINGS['MARKET_OPTIONS.CARD'],
@@ -293,7 +292,7 @@ const MobileBarMoreOptions = ({
STRINGS['MORE_OPTIONS_LABEL.OTHER_FUNCTIONS.BUY_COIN'],
STRINGS['MORE_OPTIONS_LABEL.OTHER_FUNCTIONS.BUY_TOKEN'],
],
- },
+ })),
{
icon_id: 'DEFI_STAKE_OPTION_ICON',
iconText: 'MORE_OPTIONS_LABEL.ICONS.DEFI_STAKE',
@@ -731,7 +730,9 @@ const MobileBarMoreOptions = ({
const filterOptions = (options) => {
return options?.filter((option) => {
- const iconTextMatch = (STRINGS[option?.iconText] || '')
+ const iconTextMatch = (
+ STRINGS[option?.iconText ? option?.iconText : option?.string_id] || ''
+ )
?.toLowerCase()
.includes(search?.toLowerCase());
const searchContentMatch = option?.searchContent?.some((content) =>
@@ -753,7 +754,12 @@ const MobileBarMoreOptions = ({
onHandleRoute(data?.iconText, data?.path)}
+ onClick={() =>
+ onHandleRoute(
+ data?.iconText ? data?.iconText : data?.string_id,
+ data?.path
+ )
+ }
>
{fieldHasCoinIcon?.includes(data?.iconText) ? (
@@ -769,13 +775,29 @@ const MobileBarMoreOptions = ({
) : (
)}
-
- {STRINGS[data?.iconText]}
+
+ {
+ STRINGS[
+ data?.iconText ? data?.iconText : data?.string_id
+ ]
+ }
@@ -919,6 +941,7 @@ const mapStateToProps = (store) => ({
pinnedAsset: store.app.pinned_assets,
getMarkets: MarketsSelector(store),
quickTrade: store.app.quicktrade,
+ getRemoteRoutes: store.app.remoteRoutes,
});
const mapDispatchToProps = (dispatch) => ({
diff --git a/web/src/containers/App/Socket.js b/web/src/containers/App/Socket.js
index 7c5c473dfa..095c848059 100644
--- a/web/src/containers/App/Socket.js
+++ b/web/src/containers/App/Socket.js
@@ -461,6 +461,10 @@ class Container extends Component {
{data.action === 'getStatus' &&
data?.data?.status === 'appeal'
? STRINGS['P2P.APPEAL_STATUS_MESSAGE']
+ : data?.action === 'getStatus' &&
+ data?.data?.status === 'cancelled' &&
+ data?.data?.title === 'admin cancel'
+ ? STRINGS['P2P.ADMIN_ORDER_CANCELLATION_MESSAGE']
: data?.action === 'getStatus' &&
data?.data?.status === 'cancelled'
? STRINGS['P2P.CANCEL_STATUS_MESSAGE']
@@ -541,17 +545,18 @@ class Container extends Component {
notification.close(newLastNotification?.key);
notification.open({
...newLastNotification,
- icon:
- newLastNotificationMessage ===
- (STRINGS['P2P.CANCEL_STATUS_MESSAGE'] ||
- STRINGS['P2P.APPEAL_STATUS_MESSAGE']) ? (
-
- ) : newLastNotificationMessage ===
- STRINGS['P2P.NEW_MESSAGE'] ? (
-
- ) : (
-
- ),
+ icon: [
+ STRINGS['P2P.CANCEL_STATUS_MESSAGE'],
+ STRINGS['P2P.ADMIN_ORDER_CANCELLATION_MESSAGE'],
+ STRINGS['P2P.APPEAL_STATUS_MESSAGE'],
+ ]?.includes(newLastNotificationMessage) ? (
+
+ ) : newLastNotificationMessage ===
+ STRINGS['P2P.NEW_MESSAGE'] ? (
+
+ ) : (
+
+ ),
className: isMobile
? 'p2p-chat-notification-wrapper p2p-chat-notification-wrapper-mobile'
: 'p2p-chat-notification-wrapper',
@@ -583,17 +588,18 @@ class Container extends Component {
notification.close(previousNotification?.key);
notification.open({
...previousNotification,
- icon:
- previousNotificationMessage ===
- (STRINGS['P2P.CANCEL_STATUS_MESSAGE'] ||
- STRINGS['P2P.APPEAL_STATUS_MESSAGE']) ? (
-
- ) : previousNotificationMessage ===
- STRINGS['P2P.NEW_MESSAGE'] ? (
-
- ) : (
-
- ),
+ icon: [
+ STRINGS['P2P.CANCEL_STATUS_MESSAGE'],
+ STRINGS['P2P.ADMIN_ORDER_CANCELLATION_MESSAGE'],
+ STRINGS['P2P.APPEAL_STATUS_MESSAGE'],
+ ]?.includes(previousNotificationMessage) ? (
+
+ ) : previousNotificationMessage ===
+ STRINGS['P2P.NEW_MESSAGE'] ? (
+
+ ) : (
+
+ ),
className: isMobile
? 'p2p-chat-notification-wrapper p2p-chat-notification-wrapper-mobile p2p-chat-notification'
: 'p2p-chat-notification-wrapper p2p-chat-notification',
diff --git a/web/src/containers/P2P/P2POrder/P2POrder.js b/web/src/containers/P2P/P2POrder/P2POrder.js
index 40c445032a..de6ce58334 100644
--- a/web/src/containers/P2P/P2POrder/P2POrder.js
+++ b/web/src/containers/P2P/P2POrder/P2POrder.js
@@ -26,7 +26,7 @@ import {
import { formatToCurrency } from 'utils/currency';
import { getToken } from 'utils/token';
import { WS_URL } from 'config/constants';
-import { renderFeedback } from '../Utilis';
+import { renderFeedback, Timer } from '../Utilis';
import classnames from 'classnames';
import BigNumber from 'bignumber.js';
import '../_P2P.scss';
@@ -1168,12 +1168,14 @@ const P2POrder = ({
-
-
- {STRINGS['P2P.EXPECTED_TIME']}
-
-
-
+ {selectedOrder?.user_status === 'pending' && (
+
+
+ {STRINGS['P2P.EXPECTED_TIME']}
+
+
+
+ )}
{user.id === selectedOrder?.user_id && (
<>
{selectedOrder.user_status === 'pending' && (
diff --git a/web/src/containers/P2P/P2POrder/P2POrderDetails.js b/web/src/containers/P2P/P2POrder/P2POrderDetails.js
index b55ba8b250..ddf3976a67 100644
--- a/web/src/containers/P2P/P2POrder/P2POrderDetails.js
+++ b/web/src/containers/P2P/P2POrder/P2POrderDetails.js
@@ -9,6 +9,7 @@ import { CheckCircleTwoTone } from '@ant-design/icons';
import STRINGS from 'config/localizedStrings';
import { Coin, EditWrapper, Image } from 'components';
import { setIsChat } from 'actions/appActions';
+import { Timer } from '../Utilis';
const P2POrderDetails = ({
user,
@@ -321,11 +322,14 @@ const P2POrderDetails = ({
- {/*
-
- {STRINGS['P2P.EXPECTED_TIME']}
-
-
*/}
+ {selectedOrder?.user_status === 'pending' && (
+
+
+ {STRINGS['P2P.EXPECTED_TIME']}
+
+
+
+ )}
{user?.id === selectedOrder?.user_id && (
<>
diff --git a/web/src/containers/P2P/P2POrders.js b/web/src/containers/P2P/P2POrders.js
index bf3e6d766b..53c0650346 100644
--- a/web/src/containers/P2P/P2POrders.js
+++ b/web/src/containers/P2P/P2POrders.js
@@ -466,6 +466,22 @@ const P2POrders = ({
+
+
+
+ {STRINGS['P2P.PRICE']}:
+
+
+
+ {formatAmount(
+ transaction?.deal?.buying_asset,
+ transaction?.price
+ )}
+
+
+ {transaction?.deal?.buying_asset?.toUpperCase()}
+
+
@@ -479,7 +495,7 @@ const P2POrders = ({
transaction?.amount_digital_currency
)}
-
+
{transaction?.deal?.buying_asset?.toUpperCase()}
{
+ const orderCreatedDate = new Date(order?.created_at)?.getTime();
+ const [time, setTime] = useState({ min: 30, sec: 0 });
+ const [startTime] = useState(orderCreatedDate);
+ const [timeLimitReached, setTimeLimitReached] = useState(false);
+ const frameIdRef = useRef();
+
+ const cancelTimer = () => {
+ if (frameIdRef.current) {
+ cancelAnimationFrame(frameIdRef.current);
+ frameIdRef.current = null;
+ }
+ };
+
+ useEffect(() => {
+ const update = () => {
+ const now = Date.now();
+ const elapsed = Math.floor((now - startTime) / 1000);
+ const totalSeconds = 30 * 60 - elapsed;
+
+ if (totalSeconds <= 0) {
+ setTime({ min: 0, sec: 0 });
+ setTimeLimitReached(true);
+ cancelTimer();
+ } else {
+ const min = Math.floor(totalSeconds / 60);
+ const sec = totalSeconds % 60;
+ setTime({ min, sec });
+ setTimeLimitReached(false);
+ frameIdRef.current = requestAnimationFrame(update);
+ if (
+ order?.user_status === 'confirmed' ||
+ order?.transaction_status === 'expired'
+ ) {
+ setTime({ min: 0, sec: 0 });
+ setTimeLimitReached(true);
+ cancelTimer();
+ }
+ }
+ };
+
+ frameIdRef.current = requestAnimationFrame(update);
+
+ return () => cancelTimer();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [startTime, order]);
+
+ const totalSeconds = 30 * 60;
+ const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
+ const percentage = (elapsedSeconds / totalSeconds) * 100;
+
+ return (
+
+
+ {!timeLimitReached && (
+
+ )}
+
+ {timeLimitReached ? (
+
+
+ {STRINGS['P2P.TIME_LIMIT_REACHED']}
+
+
+ ) : (
+
+ {time?.min < 10 ? `0${time?.min}` : time?.min}:
+ {time?.sec < 10 ? `0${time?.sec}` : time?.sec}
+
+ )}
+
+
+
+ );
+};
+
export default NoDealsData;
diff --git a/web/src/containers/P2P/_P2P.scss b/web/src/containers/P2P/_P2P.scss
index fa127c8fbb..ab42e97809 100644
--- a/web/src/containers/P2P/_P2P.scss
+++ b/web/src/containers/P2P/_P2P.scss
@@ -1792,6 +1792,37 @@
}
.order-verification-container {
+ .order-timer-wrapper {
+ .timer-container {
+ display: flex;
+
+ .timer-details {
+ padding: 2% 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+ border-radius: 25px;
+ }
+
+ .timer-circle {
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: conic-gradient(
+ var(--labels_important-active-labels-text-graphics) 0%,
+ var(--base_background) 0%
+ );
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ border: 1px solid
+ var(--labels_important-active-labels-text-graphics);
+ }
+ }
+ }
+
.order-confirmed-container {
.order-complete-title,
.go-to-deposit-link,
@@ -3870,6 +3901,13 @@
}
.order-verification-container {
+ .order-timer-wrapper {
+ .timer-circle {
+ width: 30px;
+ height: 30px;
+ }
+ }
+
.order-confirmed-container {
.order-complete-title {
.edit-wrapper__container {
diff --git a/web/src/index.css b/web/src/index.css
index f81ddea12f..d9d478e51c 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -11928,6 +11928,25 @@ table th {
border-left: 5px solid var(--specials_checks-okay-done); }
.p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .amount-transfer-container .active-sell {
border-left: 5px solid var(--trading_selling-related-elements); }
+ .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-timer-wrapper .timer-container {
+ display: flex; }
+ .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-timer-wrapper .timer-container .timer-details {
+ padding: 2% 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+ border-radius: 25px; }
+ .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-timer-wrapper .timer-container .timer-circle {
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: conic-gradient(var(--labels_important-active-labels-text-graphics) 0%, var(--base_background) 0%);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ border: 1px solid var(--labels_important-active-labels-text-graphics); }
.p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-confirmed-container .order-complete-title,
.p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-confirmed-container .go-to-deposit-link,
.p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-confirmed-container .go-to-withdraw-link {
@@ -12560,7 +12579,7 @@ table th {
.release-amount-popup-wrapper .ReactModal__Content .release-amount-details-container .check-icon svg path:nth-child(2) {
fill: var(--specials_checks-okay-done); }
.release-amount-popup-wrapper .ReactModal__Content .release-amount-details-container .check-icon svg path:nth-child(3) {
- fill: #FFFFFF; }
+ fill: #ffffff; }
.cancel-popup-wrapper .ReactModal__Content,
.confirm-popup-wrapper .ReactModal__Content,
@@ -12573,7 +12592,7 @@ table th {
.cancel-popup-wrapper .ReactModal__Content .feedback-submit-popup-container .warning-icon,
.confirm-popup-wrapper .ReactModal__Content .feedback-submit-popup-container .warning-icon,
.confirmation-remove-deal-popup-wrapper .ReactModal__Content .feedback-submit-popup-container .warning-icon {
- background-color: #FFFFFF;
+ background-color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
@@ -13398,6 +13417,9 @@ table th {
.layout-mobile .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .confirm-notify-button-container .chat-link-container .chat-link {
color: var(--specials_buttons-links-and-highlights);
font-size: 24px; }
+ .layout-mobile .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-timer-wrapper .timer-circle {
+ width: 30px;
+ height: 30px; }
.layout-mobile .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-confirmed-container .order-complete-title .edit-wrapper__container {
font-size: 20px; }
.layout-mobile .p2p-summary-container .p2p-order-wrapper .p2p-order-container .p2p-order-details-container .order-verification-container .order-confirmed-container .go-to-deposit-link,