From abb1bdd0beaadbce2efc348bc5b64830ec7f27bf Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Thu, 13 Jan 2022 16:43:26 -0800 Subject: [PATCH] Add dynamic countdown. Attach countdown to expiry progress bar. --- chat/consumers.py | 10 ++- chat/urls.py | 8 +-- chat/views.py | 11 ++-- frontend/package-lock.json | 8 +++ frontend/package.json | 1 + frontend/src/components/Chat.js | 17 +++-- frontend/src/components/OrderPage.js | 93 ++++++++++++++++------------ frontend/src/components/TradeBox.js | 2 +- robosats/urls.py | 2 +- setup.md | 1 + 10 files changed, 93 insertions(+), 60 deletions(-) diff --git a/chat/consumers.py b/chat/consumers.py index 2013b34a..a65ed459 100644 --- a/chat/consumers.py +++ b/chat/consumers.py @@ -56,8 +56,16 @@ class ChatRoomConsumer(AsyncWebsocketConsumer): message = event['message'] nick = event['nick'] + # Insert a white space in words longer than 22 characters. + # Helps when messages overflow in a single line. + words = message.split(' ') + fix_message = '' + for word in words: + word = ' '.join(word[i:i+22] for i in range(0, len(word), 22)) + fix_message = fix_message +' '+ word + await self.send(text_data=json.dumps({ - 'message': message, + 'message': fix_message, 'user_nick': nick, })) diff --git a/chat/urls.py b/chat/urls.py index 4ed60135..f0107bfe 100644 --- a/chat/urls.py +++ b/chat/urls.py @@ -2,7 +2,7 @@ from django.urls import path from . import views -urlpatterns = [ - path('', views.index, name='index'), - path('/', views.room, name='order_chat'), -] \ No newline at end of file +# urlpatterns = [ +# path('', views.index, name='index'), +# path('/', views.room, name='order_chat'), +# ] \ No newline at end of file diff --git a/chat/views.py b/chat/views.py index c0f94a87..1198a822 100644 --- a/chat/views.py +++ b/chat/views.py @@ -1,10 +1,7 @@ from django.shortcuts import render -def index(request): - return render(request, 'index.html', {}) - -def room(request, order_id): - return render(request, 'chatroom.html', { - 'order_id': order_id - }) \ No newline at end of file +# def room(request, order_id): +# return render(request, 'chatroom.html', { +# 'order_id': order_id +# }) \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 69c66f59..90a612e0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6503,6 +6503,14 @@ "object-assign": "^4.1.1" } }, + "react-countdown": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/react-countdown/-/react-countdown-2.3.2.tgz", + "integrity": "sha512-Q4SADotHtgOxNWhDdvgupmKVL0pMB9DvoFcxv5AzjsxVhzOVxnttMbAywgqeOdruwEAmnPhOhNv/awAgkwru2w==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-devtools-core": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.22.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 28aa9147..15fb2128 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ "@mui/material": "^5.2.7", "@mui/system": "^5.2.6", "material-ui-image": "^3.3.2", + "react-countdown": "^2.3.2", "react-markdown": "^7.1.2", "react-native": "^0.66.4", "react-native-svg": "^12.1.1", diff --git a/frontend/src/components/Chat.js b/frontend/src/components/Chat.js index 9a1f6a66..e1b3dc22 100644 --- a/frontend/src/components/Chat.js +++ b/frontend/src/components/Chat.js @@ -13,15 +13,13 @@ export default class Chat extends Component { state = { messages: [], value:'', - orderId: 2, }; - client = new W3CWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.data.orderId + '/'); + client = new W3CWebSocket('ws://' + window.location.host + '/ws/chat/' + this.props.orderId + '/'); componentDidMount() { this.client.onopen = () => { console.log('WebSocket Client Connected') - console.log(this.props.data) } this.client.onmessage = (message) => { const dataFromServer = JSON.parse(message.data); @@ -43,11 +41,19 @@ export default class Chat extends Component { } } + componentDidUpdate() { + this.scrollToBottom(); + } + + scrollToBottom = () => { + this.messagesEnd.scrollIntoView({ behavior: "smooth" }); + } + onButtonClicked = (e) => { this.client.send(JSON.stringify({ type: "message", message: this.state.value, - nick: this.props.data.urNick, + nick: this.props.urNick, })); this.state.value = '' e.preventDefault(); @@ -60,7 +66,7 @@ export default class Chat extends Component { {this.state.messages.map(message => <> {/* If message sender is not our nick, gray color, if it is our nick, green color */} - {message.userNick == this.props.data.urNick ? + {message.userNick == this.props.urNick ? } )} +
{ this.messagesEnd = el; }}>
diff --git a/frontend/src/components/OrderPage.js b/frontend/src/components/OrderPage.js index 84f225b6..f4bee0a2 100644 --- a/frontend/src/components/OrderPage.js +++ b/frontend/src/components/OrderPage.js @@ -1,44 +1,8 @@ import React, { Component } from "react"; import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material" +import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown'; import TradeBox from "./TradeBox"; -function msToTime(duration) { - var seconds = Math.floor((duration / 1000) % 60), - minutes = Math.floor((duration / (1000 * 60)) % 60), - hours = Math.floor((duration / (1000 * 60 * 60)) % 24); - - minutes = (minutes < 10) ? "0" + minutes : minutes; - seconds = (seconds < 10) ? "0" + seconds : seconds; - - return hours + "h " + minutes + "m " + seconds + "s"; -} - -// TO DO fix Progress bar to go from 100 to 0, from total_expiration time, showing time_left -function LinearDeterminate() { - const [progress, setProgress] = React.useState(0); - - React.useEffect(() => { - const timer = setInterval(() => { - setProgress((oldProgress) => { - if (oldProgress === 0) { - return 100; - } - const diff = 1; - return Math.max(oldProgress - diff, 0); - }); - }, 500); - - return () => { - clearInterval(timer); - }; - }, []); - - return ( - - - - ); -} function getCookie(name) { let cookieValue = null; @@ -67,8 +31,9 @@ export default class OrderPage extends Component { super(props); this.state = { isExplicit: false, - delay: 2000, // Refresh every 2 seconds by default - currencies_dict: {"1":"USD"} + delay: 60000, // Refresh every 60 seconds by default + currencies_dict: {"1":"USD"}, + total_secs_expiry: 300, }; this.orderId = this.props.match.params.orderId; this.getCurrencyDict(); @@ -136,6 +101,50 @@ export default class OrderPage extends Component { window.history.back(); } + // Countdown Renderer callback with condition + countdownRenderer = ({ total, hours, minutes, seconds, completed }) => { + if (completed) { + // Render a completed state + this.getOrderDetails(); + } else { + var col = 'black' + var fraction_left = (total/1000) / this.state.total_secs_expiry + console.log(fraction_left) + // Make orange at -25% of time left + if (fraction_left < 0.25){col = 'orange'} + // Make red at 10% of time left + if (fraction_left < 0.1){col = 'red'} + // Render a countdown + return ( + fraction_left < 0.25 ? {hours}h {zeroPad(minutes)}m {zeroPad(seconds)}s + :{hours}h {zeroPad(minutes)}m {zeroPad(seconds)}s + ); + } + }; + + LinearDeterminate =()=> { + const [progress, setProgress] = React.useState(0); + + React.useEffect(() => { + const timer = setInterval(() => { + setProgress((oldProgress) => { + var left = calcTimeDelta( new Date(this.state.expiresAt)).total /1000; + return (left / this.state.total_secs_expiry) * 100; + }); + }, 1000); + + return () => { + clearInterval(timer); + }; + }, []); + + return ( + + + + ); + } + handleClickTakeOrderButton=()=>{ console.log(this.state) const requestOptions = { @@ -246,9 +255,11 @@ export default class OrderPage extends Component { - + + + - + {/* If the user has a penalty/limit */} diff --git a/frontend/src/components/TradeBox.js b/frontend/src/components/TradeBox.js index 1720270a..450bb0a3 100644 --- a/frontend/src/components/TradeBox.js +++ b/frontend/src/components/TradeBox.js @@ -377,7 +377,7 @@ handleRatingChange=(e)=>{ - + {openDisputeButton ? this.showOpenDisputeButton() : ""} diff --git a/robosats/urls.py b/robosats/urls.py index eb7315bd..2e44786c 100644 --- a/robosats/urls.py +++ b/robosats/urls.py @@ -19,6 +19,6 @@ from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), - path('chat/', include('chat.urls')), + # path('chat/', include('chat.urls')), path('', include('frontend.urls')), ] diff --git a/setup.md b/setup.md index f530c3d8..caca25f6 100644 --- a/setup.md +++ b/setup.md @@ -114,6 +114,7 @@ npm install react-qr-code npm install @mui/material npm install react-markdown npm install websocket +npm install react-countdown ``` Note we are using mostly MaterialUI V5 (@mui/material) but Image loading from V4 (@material-ui/core) extentions (so both V4 and V5 are needed)