short share urls
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
VITE_WS_URL=wss://ws.dexorder.trade
|
||||
VITE_SERVER_URL=https://share.dexorder.trade
|
||||
VITE_SHARE_URL=https://dexorder.trade
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
VITE_WS_URL=ws://localhost:3001
|
||||
VITE_SNAPSHOT_URL=http://localhost:3001/snapshot
|
||||
REQUIRE_AUTH=NOAUTH
|
||||
VITE_SHARE_URL=http://localhost:3001
|
||||
VITE_REQUIRE_APPROVAL=NO
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
console.log('snapshot.js')
|
||||
|
||||
async function getSnapCode() {
|
||||
const formData = new FormData;
|
||||
formData.append('language', 'en');
|
||||
formData.append('timezone', 'Etc/UTC');
|
||||
formData.append('symbol', 'BTC/USD');
|
||||
formData.append('preparedImage', window.snapshotImage, 'blob');
|
||||
|
||||
try {
|
||||
const response = await fetch('https://tradingview.com/snapshot/', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
credentials: "same-origin",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('Failed to upload snapshot:', response.status, response);
|
||||
return null;
|
||||
}
|
||||
return await response.text();
|
||||
} catch (error) {
|
||||
console.error('Error uploading snapshot:', error);
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
getSnapCode().then((code)=>console.log('snapshot code', code)).catch((e)=>console.error('snapshot error', e))
|
||||
@@ -158,3 +158,23 @@ export function dateString(datetime) {
|
||||
export function logicalXOR(a, b) {
|
||||
return (a || b) && !(a && b)
|
||||
}
|
||||
|
||||
// Base62
|
||||
|
||||
// base62.js
|
||||
const base62charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
export function encodeBase62(num) {
|
||||
if (num === 0) return base62charset[0];
|
||||
let encoded = "";
|
||||
while (num > 0) {
|
||||
encoded = base62charset[num % 62] + encoded;
|
||||
num = Math.floor(num / 62);
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
export function decodeBase62(str) {
|
||||
return str.split('').reverse().reduce((acc, char, i) =>
|
||||
acc + base62charset.indexOf(char) * Math.pow(62, i), 0);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<v-btn id="share-btn" variant="text" prepend-icon="mdi-share" v-if="co.orders.length>0"
|
||||
:disabled="sharing"
|
||||
@click="shareOrder">{{sharing?'Preparing...':'Share'}}</v-btn>
|
||||
<v-tooltip activator="#share-btn" text="Copied share link!" v-model="showSharedTooltip"
|
||||
<v-tooltip activator="#share-btn" :text="shareError?'Error copying share link :(':'Copied share link!'" v-model="showSharedTooltip"
|
||||
:open-on-hover="false" :open-on-click="false"
|
||||
/>
|
||||
</template>
|
||||
@@ -205,6 +205,7 @@ async function doPlaceOrder() {
|
||||
|
||||
const sharing = ref(false)
|
||||
const showSharedTooltip = ref(false)
|
||||
const shareError = ref(false)
|
||||
const showShareDialog = ref(false)
|
||||
const shareUrl = ref(null)
|
||||
|
||||
@@ -212,6 +213,12 @@ function shareOrder() {
|
||||
sharing.value = true
|
||||
track('share')
|
||||
getShareUrl().then(url => {
|
||||
shareError.value = url === null
|
||||
if (url === null) {
|
||||
sharing.value = false
|
||||
return
|
||||
}
|
||||
console.log('share url', url)
|
||||
shareUrl.value = url
|
||||
sharing.value = false
|
||||
navigator.permissions.query({name: "clipboard-write"}).then((permission) => {
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
<template>
|
||||
<h2>Shared Order</h2>
|
||||
<p>Loading the shared order into the app...</p>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {loadShareUrl} from "@/share.js";
|
||||
import router from "@/router/index.js";
|
||||
import {socket} from "@/socket.js";
|
||||
import {useRoute} from "vue-router";
|
||||
|
||||
loadShareUrl()
|
||||
router.replace('/order')
|
||||
const route = useRoute()
|
||||
const code = route.params.code
|
||||
loadShareUrl(code).then(()=> router.replace('/order')).catch((e)=> {console.error(e); router.replace('/order')})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -16,7 +16,7 @@ const routes = [
|
||||
},
|
||||
{
|
||||
name: 'Shared',
|
||||
path: '/shared',
|
||||
path: '/shared/:code',
|
||||
component: ()=> import('@/components/chart/Shared.vue')
|
||||
},
|
||||
{
|
||||
|
||||
29
src/share.js
29
src/share.js
@@ -4,6 +4,7 @@ import {changeIntervalSecs, onChartReady, setSymbol, widget} from "@/charts/char
|
||||
import {usePrefStore, useStore} from "@/store/store.js";
|
||||
import {lookupSymbol} from "@/charts/datafeed.js";
|
||||
import {track} from "@/track.js";
|
||||
import {socket} from "@/socket.js";
|
||||
|
||||
export async function getShareUrl() {
|
||||
const co = useChartOrderStore();
|
||||
@@ -26,18 +27,18 @@ export async function getShareUrl() {
|
||||
}
|
||||
const json = JSON.stringify(data)
|
||||
console.log('sharing data', json, data)
|
||||
const compressed = compressToEncodedURIComponent(json);
|
||||
const imageFile = await takeSnapshot()
|
||||
return import.meta.env.VITE_SERVER_URL+ `/share?i=${imageFile}&d=${compressed}`;
|
||||
const snapshot = await takeSnapshot()
|
||||
|
||||
const code = await new Promise((resolve)=>socket.emit('share', data, snapshot, resolve))
|
||||
if (code===null) return null
|
||||
|
||||
return import.meta.env.VITE_SHARE_URL+ '/share/'+code;
|
||||
}
|
||||
|
||||
export function loadShareUrl() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const dataStr = urlParams.get('d');
|
||||
if (!dataStr) return
|
||||
const json = decompressFromEncodedURIComponent(dataStr);
|
||||
const data = JSON.parse(json);
|
||||
export async function loadShareUrl(code) {
|
||||
const data = await new Promise((resolve)=>socket.emit('shared', code, resolve))
|
||||
console.log('loaded shared orders data', data)
|
||||
if (data===null) return
|
||||
const co = useChartOrderStore();
|
||||
const s = useStore()
|
||||
const ticker = `${data.chainId}|${data.symbol.route.exchange}|${data.symbol.base.a}|${data.symbol.quote.a}|${data.symbol.route.fee}`;
|
||||
@@ -50,7 +51,9 @@ export function loadShareUrl() {
|
||||
const prefs = usePrefStore()
|
||||
prefs.selectedSymbol = ticker
|
||||
for (const order of data.orders) {
|
||||
// force amount to be zero so that the user MUST enter a size before confirming the placement
|
||||
order.amount = 0
|
||||
order.amountIsTokenA = true
|
||||
order.valid = false
|
||||
}
|
||||
co.orders = data.orders
|
||||
@@ -65,11 +68,5 @@ export function loadShareUrl() {
|
||||
|
||||
export async function takeSnapshot() {
|
||||
const screenshotCanvas = await widget.takeClientScreenshot();
|
||||
const image = await new Promise((resolve) => screenshotCanvas.toBlob(resolve));
|
||||
const response = await fetch(import.meta.env.VITE_SERVER_URL + '/snapshot', {
|
||||
method: 'PUT',
|
||||
body: image,
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
return response.text()
|
||||
return await new Promise((resolve) => screenshotCanvas.toBlob(resolve));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user