From 9000fffc48ca40d7b3dd2253e325528dcb500992 Mon Sep 17 00:00:00 2001 From: koalasat Date: Sat, 21 Jun 2025 16:33:09 +0200 Subject: [PATCH] Frontend --- api/views.py | 12 +- frontend/src/basic/OrderPage/index.tsx | 25 +- .../src/components/MakerForm/MakerForm.tsx | 27 + .../components/OrderDetails/TakeButton.tsx | 9 + .../src/components/OrderDetails/index.tsx | 475 ++++++++++-------- frontend/src/models/Maker.model.ts | 2 + frontend/src/models/Order.model.ts | 4 + frontend/static/locales/ca.json | 1 + frontend/static/locales/cs.json | 1 + frontend/static/locales/de.json | 1 + frontend/static/locales/en.json | 1 + frontend/static/locales/es.json | 1 + frontend/static/locales/eu.json | 1 + frontend/static/locales/fr.json | 1 + frontend/static/locales/it.json | 1 + frontend/static/locales/ja.json | 1 + frontend/static/locales/pl.json | 1 + frontend/static/locales/pt.json | 1 + frontend/static/locales/ru.json | 1 + frontend/static/locales/sv.json | 1 + frontend/static/locales/sw.json | 1 + frontend/static/locales/th.json | 1 + frontend/static/locales/zh-SI.json | 1 + frontend/static/locales/zh-TR.json | 1 + 24 files changed, 340 insertions(+), 231 deletions(-) diff --git a/api/views.py b/api/views.py index 603c15cd..70355d39 100644 --- a/api/views.py +++ b/api/views.py @@ -241,13 +241,7 @@ class OrderView(viewsets.ViewSet): data["is_maker"] = order.maker == request.user data["is_taker"] = order.taker == request.user or take_order.exists() data["is_participant"] = data["is_maker"] or data["is_taker"] - - # 1) If order has a password - if not data["is_participant"] and order.password is not None: - return Response( - {"bad_request": "This order is password protected"}, - status.HTTP_403_FORBIDDEN, - ) + data["has_password"] = order.password is not None # 2) If order has been cancelled if order.status == Order.Status.UCA: @@ -268,6 +262,10 @@ class OrderView(viewsets.ViewSet): if is_penalized: data["penalty"] = request.user.robot.penalty_expiration + # 1) If order has a password + if not data["is_participant"] and order.password is not None: + return Response(data, status.HTTP_200_OK) + # 3.a) If not a participant and order is not public, forbid. if ( order.maker != request.user diff --git a/frontend/src/basic/OrderPage/index.tsx b/frontend/src/basic/OrderPage/index.tsx index 3be8fd62..6c58bb28 100644 --- a/frontend/src/basic/OrderPage/index.tsx +++ b/frontend/src/basic/OrderPage/index.tsx @@ -80,6 +80,7 @@ const OrderPage = (): React.JSX.Element => { ) : ( @@ -118,11 +119,27 @@ const OrderPage = (): React.JSX.Element => { }); }} /> - {!currentOrder?.maker_hash_id && } + {!currentOrder?.maker_hash_id && !currentOrder?.bad_request && } {currentOrder?.bad_request && currentOrder.status !== 5 ? ( - - {t(currentOrder.bad_request)} - + <> + + {t(currentOrder.bad_request)} + + {currentOrder?.bad_request?.includes('password') && ( + + + {orderDetailsSpace} + + + )} + ) : null} {currentOrder?.maker_hash_id && (!currentOrder.bad_request || currentOrder.status === 5) ? ( currentOrder.is_participant ? ( diff --git a/frontend/src/components/MakerForm/MakerForm.tsx b/frontend/src/components/MakerForm/MakerForm.tsx index cb10725f..305b329e 100644 --- a/frontend/src/components/MakerForm/MakerForm.tsx +++ b/frontend/src/components/MakerForm/MakerForm.tsx @@ -41,6 +41,7 @@ import SelectCoordinator from './SelectCoordinator'; import { FederationContext, type UseFederationStoreType } from '../../contexts/FederationContext'; import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext'; import { useNavigate } from 'react-router-dom'; +import { sha256 } from 'js-sha256'; interface MakerFormProps { disableRequest?: boolean; @@ -252,6 +253,7 @@ const MakerForm = ({ latitude: maker.latitude, longitude: maker.longitude, shortAlias: maker.coordinator, + password: maker.password ? sha256(maker.password) : null, }; void slot @@ -286,6 +288,13 @@ const MakerForm = ({ }); }; + const handlePasswordChange = function (event: React.ChangeEvent): void { + setMaker({ + ...maker, + password: event.target.value, + }); + }; + const handleChangeEscrowDuration = function (date: Date): void { const d = new Date(date); const hours: number = d.getHours(); @@ -821,6 +830,24 @@ const MakerForm = ({ /> + + + + void; onClickGenerateRobot?: () => void; } @@ -41,7 +44,9 @@ interface OpenDialogsProps { const closeAll = { inactiveMaker: false, confirmation: false }; const TakeButton = ({ + password, currentOrder, + setCurrentOrder, info, onClickGenerateRobot = () => null, }: TakeButtonProps): React.JSX.Element => { @@ -317,6 +322,8 @@ const TakeButton = ({ if (currentOrder === null || slot === null) return; + if (password) currentOrder.password = sha256(password); + setLoadingTake(true); slot @@ -326,8 +333,10 @@ const TakeButton = ({ setBadRequest(order.bad_request); } else { setBadRequest(''); + setCurrentOrder(order); navigate(`/order/${order.shortAlias}/${order.id}`); } + setLoadingTake(false); }) .catch(() => { setBadRequest('Request error'); diff --git a/frontend/src/components/OrderDetails/index.tsx b/frontend/src/components/OrderDetails/index.tsx index ae3a9757..f858556b 100644 --- a/frontend/src/components/OrderDetails/index.tsx +++ b/frontend/src/components/OrderDetails/index.tsx @@ -16,6 +16,7 @@ import { IconButton, Tooltip, ListItemButton, + TextField, } from '@mui/material'; import Countdown, { type CountdownRenderProps, zeroPad } from 'react-countdown'; @@ -46,6 +47,7 @@ import { type Order } from '../../models'; interface OrderDetailsProps { shortAlias: string; currentOrder: Order; + setCurrentOrder: (currentOrder: Order) => void; onClickCoordinator?: () => void; onClickGenerateRobot?: () => void; } @@ -53,6 +55,7 @@ interface OrderDetailsProps { const OrderDetails = ({ shortAlias, currentOrder, + setCurrentOrder, onClickCoordinator = () => null, onClickGenerateRobot = () => null, }: OrderDetailsProps): React.JSX.Element => { @@ -65,6 +68,7 @@ const OrderDetails = ({ const [currencyCode, setCurrencyCode] = useState(); const [showSatsDetails, setShowSatsDetails] = useState(false); const [openWorldmap, setOpenWorldmap] = useState(false); + const [password, setPassword] = useState(); useEffect(() => { setCoordinator(federation.getCoordinator(shortAlias)); @@ -142,6 +146,10 @@ const OrderDetails = ({ ); }; + const onPasswordChange = (password: string) => { + setPassword(password); + }; + // Countdown Renderer callback with condition const countdownPenaltyRenderer = ({ minutes, @@ -294,234 +302,239 @@ const OrderDetails = ({ )} - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - -
- -
-
- 0 ? 'Amount' : 'Amount Range'} - /> - - { - setShowSatsDetails(!showSatsDetails); - }} - > - {showSatsDetails ? : } - - -
- - - + {!currentOrder.bad_request && ( + <> - - + - - {satsSummary.send} + + - - - + + + - - {satsSummary.receive} - - - + + + + + + + + - + + + +
+ + + + + - - - - - - } - secondary={ - currentOrder?.currency === 1000 - ? t('Swap destination') - : t('Accepted payment methods') - } - /> - {currentOrder?.payment_method.includes('Cash F2F') && ( - - -
- { - setOpenWorldmap(true); - }} - > - - + + +
+
- -
- )} -
- - - {/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */} - - - - - - {currentOrder?.price_now !== undefined ? ( - - ) : null} - - {currentOrder?.price_now === undefined && currentOrder?.is_explicit ? ( - - ) : null} - - {currentOrder?.price_now === undefined && !currentOrder?.is_explicit ? ( - - ) : null} - - - - - - - - - - - - - - - - - - - - - {/* if order is in a status that does not expire, do not show countdown */} - - - - - - - - + 0 ? 'Amount' : 'Amount Range'} /> - - - - + + { + setShowSatsDetails(!showSatsDetails); + }} + > + {showSatsDetails ? : } + + + + + + + + + + + {satsSummary.send} + + + + + + + {satsSummary.receive} + + + + + + + + + + + + } + secondary={ + currentOrder?.currency === 1000 + ? t('Swap destination') + : t('Accepted payment methods') + } + /> + {currentOrder?.payment_method.includes('Cash F2F') && ( + + +
+ { + setOpenWorldmap(true); + }} + > + + +
+
+
+ )} +
+ + + {/* If there is live Price and Premium data, show it. Otherwise show the order maker settings */} + + + + + + {currentOrder?.price_now !== undefined ? ( + + ) : null} + + {currentOrder?.price_now === undefined && currentOrder?.is_explicit ? ( + + ) : null} + + {currentOrder?.price_now === undefined && !currentOrder?.is_explicit ? ( + + ) : null} + + + + + + + + + + + + + + + + + + + + + {/* if order is in a status that does not expire, do not show countdown */} + + + + + + + + + + + + + + )} {/* If the user has a penalty/limit */} @@ -538,10 +551,32 @@ const OrderDetails = ({ <> )} - {!currentOrder?.is_participant ? ( + {currentOrder.bad_request?.includes('password') && ( + + onPasswordChange(e.target.value)} + /> + + )} + + {!currentOrder?.is_participant || currentOrder.bad_request?.includes('password') ? ( diff --git a/frontend/src/models/Maker.model.ts b/frontend/src/models/Maker.model.ts index 042698f4..2d698662 100644 --- a/frontend/src/models/Maker.model.ts +++ b/frontend/src/models/Maker.model.ts @@ -21,6 +21,7 @@ export interface Maker { badPremiumText: string; latitude: number; longitude: number; + password: string | null; } export const defaultMaker: Maker = { @@ -47,6 +48,7 @@ export const defaultMaker: Maker = { badSatoshisText: '', latitude: 0, longitude: 0, + password: null, }; export default Maker; diff --git a/frontend/src/models/Order.model.ts b/frontend/src/models/Order.model.ts index bceddfa9..3f414874 100644 --- a/frontend/src/models/Order.model.ts +++ b/frontend/src/models/Order.model.ts @@ -22,6 +22,7 @@ export interface SubmitActionProps { rating?: number; amount?: number; cancel_status?: number; + password?: string; } export interface TradeRobotSummary { @@ -83,6 +84,7 @@ class Order { satoshis_now: number = 0; latitude: number = 0; longitude: number = 0; + password: string | undefined = undefined; premium_now: number | undefined = undefined; premium_percentile: number = 0; num_similar_orders: number = 0; @@ -199,6 +201,7 @@ class Order { bond_size: this.bond_size, latitude: this.latitude, longitude: this.longitude, + password: this.password, }; if (slot) { @@ -223,6 +226,7 @@ class Order { ) => { return await this.submitAction(federation, slot, { action: 'take', + password: this?.password, amount: this?.currency === 1000 ? Number(takeAmount) / 100000000 : Number(takeAmount), }); }; diff --git a/frontend/static/locales/ca.json b/frontend/static/locales/ca.json index 2cee639c..2d0a3782 100644 --- a/frontend/static/locales/ca.json +++ b/frontend/static/locales/ca.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Quantitat a enviar Onchain (BTC)", "Order current rate:": "Preu actual:", "Order for ": "Ordre per ", + "Password": "Password", "Premium over Market (%)": "Prima sobre el mercat (%)", "Public Duration (HH:mm)": "Duració pública (HH:mm)", "Public order length": "Duració de l'ordre pública", diff --git a/frontend/static/locales/cs.json b/frontend/static/locales/cs.json index d5382559..d7419067 100644 --- a/frontend/static/locales/cs.json +++ b/frontend/static/locales/cs.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Aktuální kurz nabídky:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Prémium vůči tržní ceně (%)", "Public Duration (HH:mm)": "Doba zveřejnění (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/de.json b/frontend/static/locales/de.json index 7ab01c7f..07eb10e4 100644 --- a/frontend/static/locales/de.json +++ b/frontend/static/locales/de.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Aktueller Order-Kurs:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Marktpreis Aufschlag (%)", "Public Duration (HH:mm)": "Angebotslaufzeit (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/en.json b/frontend/static/locales/en.json index f0f0e0f4..04518e2f 100644 --- a/frontend/static/locales/en.json +++ b/frontend/static/locales/en.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Order current rate:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Premium over Market (%)", "Public Duration (HH:mm)": "Public Duration (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/es.json b/frontend/static/locales/es.json index 25629157..e3a80323 100644 --- a/frontend/static/locales/es.json +++ b/frontend/static/locales/es.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Cantidad onchain a enviar (BTC)", "Order current rate:": "Precio actual:", "Order for ": "Orden por ", + "Password": "Password", "Premium over Market (%)": "Prima sobre el mercado (%)", "Public Duration (HH:mm)": "Duración pública (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/eu.json b/frontend/static/locales/eu.json index 24360caf..e1353864 100644 --- a/frontend/static/locales/eu.json +++ b/frontend/static/locales/eu.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Uneko Prezioa:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Merkatuarekiko Prima (%)", "Public Duration (HH:mm)": "Iraupen publikoa (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/fr.json b/frontend/static/locales/fr.json index 10b7f31c..637f2ee1 100644 --- a/frontend/static/locales/fr.json +++ b/frontend/static/locales/fr.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain montant à envoyer (BTC)", "Order current rate:": "Commander le taux actuel:", "Order for ": "Ordre pour ", + "Password": "Password", "Premium over Market (%)": "Prime sur le marché (%)", "Public Duration (HH:mm)": "Durée publique (HH:mm)", "Public order length": "Durée de l'ordre public", diff --git a/frontend/static/locales/it.json b/frontend/static/locales/it.json index 863b7ab1..afb76d04 100644 --- a/frontend/static/locales/it.json +++ b/frontend/static/locales/it.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Importo da inviare onchain (BTC)", "Order current rate:": "Ordina al prezzo corrente:", "Order for ": "Ordina per ", + "Password": "Password", "Premium over Market (%)": "Premio sul prezzo di mercato (%)", "Public Duration (HH:mm)": "Durata pubblica (HH:mm)", "Public order length": "Durata dell'ordine pubblico", diff --git a/frontend/static/locales/ja.json b/frontend/static/locales/ja.json index 7848f515..96e7972a 100644 --- a/frontend/static/locales/ja.json +++ b/frontend/static/locales/ja.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "送信するオンチェーン量(BTC)", "Order current rate:": "現在のレート:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "マーケットに対するプレミアム(%)", "Public Duration (HH:mm)": "公開期間(HH:mm)", "Public order length": "公開注文の期間", diff --git a/frontend/static/locales/pl.json b/frontend/static/locales/pl.json index 97ec0eb0..b62a7050 100644 --- a/frontend/static/locales/pl.json +++ b/frontend/static/locales/pl.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Order current rate:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Premia nad rynkiem (%)", "Public Duration (HH:mm)": "Czas trwania publicznego (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/pt.json b/frontend/static/locales/pt.json index 9c2b5e28..05daf693 100644 --- a/frontend/static/locales/pt.json +++ b/frontend/static/locales/pt.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Valor onchain a enviar (BTC)", "Order current rate:": "Taxa atual do pedido:", "Order for ": "Ordem para ", + "Password": "Password", "Premium over Market (%)": "Prêmio sobre o mercado (%)", "Public Duration (HH:mm)": "Duração Pública (HH:mm)", "Public order length": "Tempo da ordem pública", diff --git a/frontend/static/locales/ru.json b/frontend/static/locales/ru.json index 1cbe95ae..b603a4ed 100644 --- a/frontend/static/locales/ru.json +++ b/frontend/static/locales/ru.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Сумма для отправки на ончейн (BTC)", "Order current rate:": "Текущий курс ордера:", "Order for ": "Ордер на ", + "Password": "Password", "Premium over Market (%)": "Наценка по сравнению с рынком (%)", "Public Duration (HH:mm)": "Публичная продолжительность (ЧЧ: мм)", "Public order length": "Длина общественного ордера", diff --git a/frontend/static/locales/sv.json b/frontend/static/locales/sv.json index a43118c9..69b3e36d 100644 --- a/frontend/static/locales/sv.json +++ b/frontend/static/locales/sv.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "Aktuell kurs: ", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "Premium över marknaden (%)", "Public Duration (HH:mm)": "Publikt tidsspann (HH:mm)", "Public order length": "Public order length", diff --git a/frontend/static/locales/sw.json b/frontend/static/locales/sw.json index 6a611675..b17a8041 100644 --- a/frontend/static/locales/sw.json +++ b/frontend/static/locales/sw.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Kiasi cha onchain cha kutuma (BTC)", "Order current rate:": "Kiwango cha sasa cha amri:", "Order for ": "Amri kwa ", + "Password": "Password", "Premium over Market (%)": "Faida juu ya Soko (%)", "Public Duration (HH:mm)": "Muda wa Umma (HH:mm)", "Public order length": "Urefu wa amri ya umma", diff --git a/frontend/static/locales/th.json b/frontend/static/locales/th.json index 5ce12848..231ddd3e 100644 --- a/frontend/static/locales/th.json +++ b/frontend/static/locales/th.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "Onchain amount to send (BTC)", "Order current rate:": "ราคาที่คุณกำหนด:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "ค่าพรีเมี่ยมจากท้องตลาด (%)", "Public Duration (HH:mm)": "ประกาศรายการซื้อขายมีอายุ (ชม:นาที)", "Public order length": "Public order length", diff --git a/frontend/static/locales/zh-SI.json b/frontend/static/locales/zh-SI.json index 90eeae50..7d646ff7 100644 --- a/frontend/static/locales/zh-SI.json +++ b/frontend/static/locales/zh-SI.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "链上发送金额(BTC)", "Order current rate:": "订单当前价格:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "市场溢价(%)", "Public Duration (HH:mm)": "公开时间 (HH:mm)", "Public order length": "订单公开长度", diff --git a/frontend/static/locales/zh-TR.json b/frontend/static/locales/zh-TR.json index 662b0afb..1ac21087 100644 --- a/frontend/static/locales/zh-TR.json +++ b/frontend/static/locales/zh-TR.json @@ -385,6 +385,7 @@ "Onchain amount to send (BTC)": "鏈上發送金額(BTC)", "Order current rate:": "訂單當前價格:", "Order for ": "Order for ", + "Password": "Password", "Premium over Market (%)": "市場溢價 (%)", "Public Duration (HH:mm)": "公開時間 (HH:mm)", "Public order length": "訂單公開長度",