From ac0064bfa9fd9be419a7bc7ebdb73c16a18af79e Mon Sep 17 00:00:00 2001
From: mx00 <2784107+mx00@users.noreply.github.com>
Date: Fri, 15 May 2026 23:00:36 -0700
Subject: [PATCH 1/4] Display entry and exit prices on Trades tab in the trade
details
---
.gitignore | 1 +
src/views/Daily.vue | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/.gitignore b/.gitignore
index 9f69cbb8..b28ec4c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ dist
.vscode
logs
.idea/
+docker-compose-local-MINE.yml
diff --git a/src/views/Daily.vue b/src/views/Daily.vue
index a68afab0..525d3fa2 100644
--- a/src/views/Daily.vue
+++ b/src/views/Daily.vue
@@ -948,6 +948,9 @@ function getOHLC(date, symbol, type) {
Position |
Entry |
+ Entry Price |
+ Exit |
+ Exit Price |
P&L/Sec
@@ -1002,6 +1005,31 @@ function getOHLC(date, symbol, type) {
v-bind:data-bs-title="'Swing trade from ' + useDateCalFormat(trade.entryTime)">
+
+ | {{
+ (trade.entryPrice).toFixed(5)
+ }}{{
+ useTwoDecCurrencyFormat(trade.entryPrice)
+ }}
+ |
+
+
+ {{ useTimeFormat(trade.exitTime) }} |
+
+
+ {{
+ (trade.exitPrice).toFixed(5)
+ }}{{
+ useTwoDecCurrencyFormat(trade.exitPrice)
+ }} |
+
Date: Mon, 18 May 2026 21:36:49 -0700
Subject: [PATCH 2/4] Fix manual screenshot tag fallback
---
src/utils/daily.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/utils/daily.js b/src/utils/daily.js
index 70676857..eb23685f 100644
--- a/src/utils/daily.js
+++ b/src/utils/daily.js
@@ -542,7 +542,7 @@ export const useUpdateTags = async () => {
query.equalTo("tradeId", tradeTagsId.value)
} else {
//it's the case when changing daily tags, tradeTagsId.value is null (see useTradeTagsChange)
- query.equalTo("tradeId", tradeTagsDateUnix.value.toString())
+ query.equalTo("tradeId", (tradeTagsDateUnix.value || screenshot.dateUnix || screenshot.dateUnixDay || screenshot.name || Date.now()).toString())
}
}
const results = await query.first();
@@ -578,12 +578,12 @@ export const useUpdateTags = async () => {
}
else {
if (tradeTagsId.value) {
- object.set("dateUnix", tradeTagsDateUnix.value)
+ object.set("dateUnix", tradeTagsDateUnix.value || screenshot.dateUnix || screenshot.dateUnixDay || Date.now())
object.set("tradeId", tradeTagsId.value)
} else {
//it's the case when changing daily tags, tradeTagsId.value is null
- object.set("dateUnix", tradeTagsDateUnix.value)
- object.set("tradeId", tradeTagsDateUnix.value.toString())
+ object.set("dateUnix", tradeTagsDateUnix.value || screenshot.dateUnix || screenshot.dateUnixDay || Date.now())
+ object.set("tradeId", (tradeTagsDateUnix.value || screenshot.dateUnix || screenshot.dateUnixDay || screenshot.name || Date.now()).toString())
}
}
From ab50cf5358045d87011b3f5137e36cd7d1f99c6e Mon Sep 17 00:00:00 2001
From: mx00 <2784107+mx00@users.noreply.github.com>
Date: Mon, 18 May 2026 23:03:44 -0700
Subject: [PATCH 3/4] Fix manual chart screenshot upload linking
---
src/utils/screenshots.js | 5 +++--
src/views/Daily.vue | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/utils/screenshots.js b/src/utils/screenshots.js
index 249c57b4..05ba1c2a 100644
--- a/src/utils/screenshots.js
+++ b/src/utils/screenshots.js
@@ -182,7 +182,7 @@ async function imgFileReader(param) {
})
}
-export async function useSetupImageUpload(event, param1, param2, param3) {
+export async function useSetupImageUpload(event, param1, param2, param3, tradeId = null) {
tradeScreenshotChanged.value = true
if (pageId.value == "daily") {
saveButton.value = true
@@ -191,6 +191,7 @@ export async function useSetupImageUpload(event, param1, param2, param3) {
screenshot.dateUnix = param1
screenshot.symbol = param2
screenshot.side = param3
+ screenshot.tradeId = tradeId
}
const file = event.target.files[0];
@@ -429,7 +430,7 @@ export async function useSaveScreenshot() {
//console.log(" -> dateUnix " + screenshot.dateUnix)
- screenshot.side ? screenshot.name = "t" + screenshot.dateUnix + "_" + screenshot.symbol + "_" + screenshot.side : screenshot.name = screenshot.dateUnix + "_" + screenshot.symbol
+ screenshot.tradeId ? screenshot.name = screenshot.tradeId : (screenshot.side ? screenshot.name = "t" + screenshot.dateUnix + "_" + screenshot.symbol + "_" + screenshot.side : screenshot.name = screenshot.dateUnix + "_" + screenshot.symbol)
//console.log("name " + screenshot.name)
diff --git a/src/views/Daily.vue b/src/views/Daily.vue
index 525d3fa2..12bd240e 100644
--- a/src/views/Daily.vue
+++ b/src/views/Daily.vue
@@ -1396,7 +1396,7 @@ function getOHLC(date, symbol, type) {
+ @change="useSetupImageUpload($event, filteredTrades[itemTradeIndex].trades[tradeIndex].entryTime, filteredTrades[itemTradeIndex].trades[tradeIndex].symbol, filteredTrades[itemTradeIndex].trades[tradeIndex].side, filteredTrades[itemTradeIndex].trades[tradeIndex].id)" />
From c881229715e185d554bddd0f6c3fd4844e81dd46 Mon Sep 17 00:00:00 2001
From: mx00 <2784107+mx00@users.noreply.github.com>
Date: Sun, 24 May 2026 22:54:43 -0700
Subject: [PATCH 4/4] Fix screenshot uploads and trade screenshot linking
---
index.mjs | 8 +-
index.mjs.bak | 570 +++++++++++++++++++++++++++++++++++++++
src/utils/screenshots.js | 1 +
3 files changed, 576 insertions(+), 3 deletions(-)
create mode 100644 index.mjs.bak
diff --git a/index.mjs b/index.mjs
index 5c49cfd9..319e5eb3 100644
--- a/index.mjs
+++ b/index.mjs
@@ -46,7 +46,8 @@ console.log(' -> Database URI ' + hiddenDatabaseURI)
let tradenoteDatabase = process.env.TRADENOTE_DATABASE
var app = express();
-app.use(express.json());
+app.use(express.json({ limit: '50mb' }));
+app.use(express.urlencoded({ limit: '50mb', extended: true }));
const port = process.env.TRADENOTE_PORT;
const PROXY_PORT = 39482;
@@ -339,7 +340,8 @@ const setupApiRoutes = (app) => {
- app.use(express.json());
+ app.use(express.json({ limit: '50mb' }));
+app.use(express.urlencoded({ limit: '50mb', extended: true }));
let allUsers
const getAllUsers = async () => {
@@ -498,7 +500,7 @@ const startIndex = async () => {
resolve();
} else {
// In production, handle API routes normally
- app.use('/api/*', express.json(), (req, res, next) => {
+ app.use('/api/*', express.json({ limit: '50mb' }), express.urlencoded({ limit: '50mb', extended: true }), (req, res, next) => {
//console.log(`Received API request: ${req.method} ${req.url}`);
next(); // Pass control to specific API handlers
});
diff --git a/index.mjs.bak b/index.mjs.bak
new file mode 100644
index 00000000..5c49cfd9
--- /dev/null
+++ b/index.mjs.bak
@@ -0,0 +1,570 @@
+import express from 'express';
+import { ParseServer } from 'parse-server'
+//var ParseDashboard = require('parse-dashboard');
+import ParseNode from 'parse/node.js'
+import path from 'path'
+import fs from 'fs'
+import axios from 'axios'
+import * as Vite from 'vite'
+import { MongoClient } from "mongodb"
+import Proxy from 'http-proxy'
+import { useImportTrades, useGetExistingTradesArray, useUploadTrades } from './src/utils/addTrades.js';
+import { currentUser, uploadMfePrices } from './src/stores/globals.js';
+import { useGetTimeZone } from './src/utils/utils.js';
+import Stripe from 'stripe';
+
+
+/* STRIPE VAR */
+let stripeSk //secret key
+let stripePk // public key
+let stripePriceId
+let stripeTrialPeriod
+
+if (process.env.STRIPE_SK) {
+ stripeSk = new Stripe(process.env.STRIPE_SK);
+ stripePk = process.env.STRIPE_PK
+ stripePriceId = process.env.STRIPE_PRICE_ID
+ stripeTrialPeriod = process.env.STRIPE_TRIAL_PERIOD
+}
+
+/* END STRIPE */
+
+let databaseURI
+
+if (process.env.MONGO_URI) {
+ databaseURI = process.env.MONGO_URI
+} else if (process.env.MONGO_ATLAS) {
+ databaseURI = "mongodb+srv://" + process.env.MONGO_USER + ":" + process.env.MONGO_PASSWORD + "@" + process.env.MONGO_URL + "/" + process.env.TRADENOTE_DATABASE + "?authSource=admin"
+} else {
+ databaseURI = "mongodb://" + process.env.MONGO_USER + ":" + process.env.MONGO_PASSWORD + "@" + process.env.MONGO_URL + ":" + process.env.MONGO_PORT + "/" + process.env.TRADENOTE_DATABASE + "?authSource=admin"
+}
+
+console.log("\nCONNECTING TO MONGODB")
+let hiddenDatabaseURI = databaseURI.replace(/:\/\/[^@]*@/, "://***@")
+console.log(' -> Database URI ' + hiddenDatabaseURI)
+
+let tradenoteDatabase = process.env.TRADENOTE_DATABASE
+
+var app = express();
+app.use(express.json());
+
+const port = process.env.TRADENOTE_PORT;
+const PROXY_PORT = 39482;
+
+// SERVER
+
+let server = null
+
+export let allowRegister = false
+
+
+/**************************** APIs ****************************/
+
+const setupApiRoutes = (app) => {
+
+ app.post("/api/parseAppId", (req, res) => {
+ //console.log("\nAPI : post APP ID")
+ //console.log(process.env.APP_ID)
+ res.send(process.env.APP_ID)
+ });
+
+ app.post("/api/registerPage", (req, res) => {
+ //console.log("\nAPI : post APP ID")
+ //console.log(" REGISTER_OFF "+process.env.REGISTER_OFF)
+ res.send(process.env.REGISTER_OFF)
+ });
+
+ app.post("/api/posthog", (req, res) => {
+ //console.log("\nAPI : posthog")
+ if (process.env.ANALYTICS_OFF) {
+ res.send("off")
+ } else {
+ res.send("phc_FxkjH1O898jKu0yiELC3aWKda3vGov7waGN0weU5kw0")
+ }
+ });
+
+
+ /**********************************************
+ * CLOUD / STRIPE
+ **********************************************/
+
+ app.post("/api/checkCloudPayment", async (req, res) => {
+ // Used for checking if can access add*, in case it's a paying user
+ let currentUser = req.body.currentUser
+ //console.log(" currentUser "+JSON.stringify(currentUser))
+ //console.log(" current user " + JSON.stringify(req.body.currentUser))
+ if (process.env.STRIPE_SK) {
+ //console.log("\nAPI : checkCloudPayment")
+ // Check if user is stripe customer
+
+ // Check if user has paying customer
+ if (currentUser.hasOwnProperty("paymentService") && currentUser.paymentService.hasOwnProperty("subscriptionId")) {
+ /// if yes, let inn, status 200
+ const activeSubscription = ['active', 'trialing', 'past_due']
+ const subscription = await stripeSk.subscriptions.retrieve(currentUser.paymentService.subscriptionId)
+ if (activeSubscription.includes(subscription.status)) {
+ console.log(" -> User has valid subscription.");
+ res.status(200).send('OK');
+ } else {
+ console.log(" -> User has invalid subscription.");
+ res.status(403).send('Forbidden');
+ }
+
+ }
+
+ /// If not, check if user is within trial period
+ else {
+
+ // Convert createdAt to a Date object
+ const createdAtDate = new Date(currentUser.createdAt);
+
+ // Get the current time
+ const currentDate = new Date();
+
+ // Calculate the time difference in milliseconds
+ const timeDifference = currentDate - createdAtDate;
+
+ // Convert the time difference to days
+ const differenceInDays = timeDifference / (1000 * 60 * 60 * 24); // Milliseconds to days
+
+ //// if older, redirect to stripe / status 403
+ if (differenceInDays > stripeTrialPeriod) {
+ console.log(" -> User is past trial period.");
+ res.status(403).send('Forbidden');
+ }
+
+ //// else, let inn, status 200
+ else {
+ console.log(" -> User is within trial period.");
+ res.status(200).send('OK');
+ }
+ }
+
+
+
+
+ } else {
+ res.status(200).send('OK');
+ }
+ });
+
+ app.post('/api/create-checkout-session', async (req, res) => {
+
+ let return_url
+ if (process.env.NODE_ENV == 'dev') {
+ return_url = `http://localhost:${port}/checkoutSuccess?session_id={CHECKOUT_SESSION_ID}`
+ }else{
+ return_url = `https://app.tradenote.co/checkoutSuccess?session_id={CHECKOUT_SESSION_ID}`
+ }
+
+ //console.log(" -> return_url : "+return_url)
+ const session = await stripeSk.checkout.sessions.create({
+ ui_mode: 'embedded',
+ line_items: [
+ {
+ // Provide the exact Price ID (for example, pr_1234) of the product you want to sell
+ price: stripePriceId,
+ quantity: 1,
+ },
+ ],
+ mode: 'subscription',
+ return_url: return_url,
+ automatic_tax: { enabled: true },
+ });
+
+ res.send({ clientSecret: session.client_secret });
+ });
+
+ app.get('/api/getStripePk', async (req, res) => {
+ res.status(200).send(stripePk);
+ })
+
+ app.get('/api/session-status', async (req, res) => {
+ try {
+ console.log("Getting session status");
+ const session = await stripeSk.checkout.sessions.retrieve(req.query.session_id);
+
+ //console.log("Session retrieved:", JSON.stringify(session));
+
+ res.send({
+ session: session,
+ status: session.status,
+ customer_email: session.customer_details.email,
+ customer_id: session.customer
+ });
+ } catch (error) {
+ console.error("Error retrieving session:", error.message);
+ res.status(500).send({ error: error.message });
+ }
+ });
+
+ /******************* END CLOUD ****************************/
+
+ app.get('/api/dockerVersion', async (req, res) => {
+ console.log("Getting Docker Version");
+ await axios.get("https://hub.docker.com/v2/namespaces/eleventrading/repositories/tradenote/tags")
+ .then((response) => {
+ //console.log(" -> data " + JSON.stringify(response.data))
+ res.status(200).send(response.data);
+ })
+ .catch((error) => {
+ res.status(500).send({ error: error.message });
+ })
+ .finally(function () {
+ // always executed
+ })
+ });
+
+ app.post("/api/updateSchemas", async (req, res) => {
+
+ if (!process.env.STRIPE_SK || process.env.UPSERT_SCHEMA) {
+ console.log("\nAPI : post update schema")
+
+ let rawdata = fs.readFileSync('requiredClasses.json');
+ let schemasJson = JSON.parse(rawdata);
+ //console.log("schemasJson "+JSON.stringify(schemasJson))
+
+ let existingSchema = []
+ const getExistingSchema = await ParseNode.Schema.all()
+ //console.log(" -> Get existing schema " + JSON.stringify(getExistingSchema))
+
+ /* 1- Rename legacy names in mongoDB */
+ const renameMongoDb = (param1, param2) => {
+ return new Promise(async (resolve, reject) => {
+ console.log(" -> Renaming class " + param1 + " to " + param2)
+ MongoClient.connect(databaseURI).then(async (client) => {
+ console.log(" --> Connected to MongoDB")
+ const connect = client.db(tradenoteDatabase);
+ const allCollections = await connect.listCollections().toArray()
+ //console.log("allCollections "+JSON.stringify(allCollections))
+ let collectionExists = allCollections.filter(obj => obj.name == param1)
+ //console.log(" --> collectionExists "+collectionExists.length)
+ if (collectionExists.length > 0) {
+ const collection = connect.collection(param1);
+ collection.rename(param2).then(() => {
+ console.log(" -> Renamed class successfully");
+ resolve()
+ })
+ } else {
+ console.log(" -> Collection doesn't exist.")
+ resolve()
+ }
+
+ }).catch((err) => {
+ console.log(" -> Error renaming MongoDB class: " + err.Message);
+ reject()
+ })
+ })
+ }
+
+ for (let i = 0; i < getExistingSchema.length; i++) {
+ //console.log("Class name " + getExistingSchema[i].className)
+
+ //we check for classes/collections that need to be renamed
+ if (getExistingSchema[i].className == "setupsEntries" || getExistingSchema[i].className == "journals") {
+ let oldName = getExistingSchema[i].className
+ let newName
+
+ if (getExistingSchema[i].className == "setupsEntries") newName = "screenshots"
+ if (getExistingSchema[i].className == "journals") newName = "diaries"
+ if (getExistingSchema[i].className == "patternsMistakes") newName = "setups"
+
+ await renameMongoDb(oldName, newName)
+ } else {
+ existingSchema.push(getExistingSchema[i].className)
+ }
+ }
+ //console.log(" -> Existing Schema " + existingSchema)
+
+ /* 2- Update or save new schemas in mongoDB */
+ const updateSaveSchema = (param1, param2, param3) => {
+ return new Promise((resolve, reject) => {
+ const mySchema = new ParseNode.Schema(param1);
+ if (param2[param3].type === "String") mySchema.addString(param3)
+ if (param2[param3].type === "Number") mySchema.addNumber(param3)
+ if (param2[param3].type === "Boolean") mySchema.addBoolean(param3)
+ if (param2[param3].type === "Date") mySchema.addDate(param3)
+ if (param2[param3].type === "File") mySchema.addFile(param3)
+ if (param2[param3].type === "GeoPoint") mySchema.addGeoPoint(param3)
+ if (param2[param3].type === "Polygon") mySchema.addPolygon(param3)
+ if (param2[param3].type === "Array") mySchema.addArray(param3)
+ if (param2[param3].type === "Object") mySchema.addObject(param3)
+ if (param2[param3].type === "Pointer") mySchema.addPointer(param3, param2[param3].targetClass)
+ if (param2[param3].type === "Relation") mySchema.addRelation(param3, param2[param3].targetClass)
+
+ //console.log("existing schema "+existingSchema)
+ //console.log("includes ? "+existingSchema.includes(className))
+
+ //If ParseNode (existing) schema includes the class name from required classes then update (just in case). Else add, and then add that class to existing schema array
+ if (existingSchema.includes(param1)) {
+ mySchema.update().then((result) => {
+ console.log(" --> Updating field " + param3)
+ //console.log(" -> Updated schema " + JSON.stringify(result))
+ resolve()
+ })
+ } else {
+ mySchema.save().then((result) => {
+ //console.log(" -> Save new schema " + JSON.stringify(result))
+ console.log(" --> Saving field " + param3)
+ existingSchema.push(param1) // Once saved, we update for the rest of the fields, so we need to push to existingSchema
+ //console.log(" -> Existing Schema " + existingSchema)
+ resolve()
+ })
+ }
+ })
+ }
+
+ for (let i = 0; i < schemasJson.length; i++) {
+ //console.log("el " + schemasJson[i].className)
+ let className = schemasJson[i].className
+ console.log(" -> Upsert class/collection " + className + " in ParseNode Schema")
+ let obj = schemasJson[i].fields
+ for (const key of Object.keys(obj)) {
+ //console.log(key, obj[key]);
+ if (key != "objectId" && key != "updatedAt" && key != "createdAt" && key != "ACL") {
+ //console.log(" -> Key " + key)
+ await updateSaveSchema(className, obj, key)
+ }
+
+ }
+ }
+
+ res.send({ "existingSchema": existingSchema })
+ } else {
+ res.status(200).send('OK');
+ }
+
+ })
+
+
+
+
+ app.use(express.json());
+
+ let allUsers
+ const getAllUsers = async () => {
+ console.log(" -> Getting all users")
+ return new Promise(async (resolve, reject) => {
+ const parseObject = ParseNode.Object.extend("_User");
+ const query = new ParseNode.Query(parseObject);
+ const results = await query.find({ useMasterKey: true });
+ allUsers = JSON.parse(JSON.stringify(results))
+ resolve()
+ })
+ }
+
+ const validateApiKey = async (req, res, next) => {
+ await getAllUsers()
+ const targetKey = req.headers['api-key'] || req.query['api-key'];
+ //console.log(" -> target Key " + targetKey)
+
+ const checkIPKey = (allUsers, targetKey) => {
+ for (const user of Object.values(allUsers)) {
+ if (user.hasOwnProperty("apis")) {
+ const index = user.apis.findIndex(obj => obj.key === targetKey);
+ if (index !== -1) {
+ currentUser.value = user
+ return true;
+ }
+ }
+
+ }
+ return -1; // Return -1 if not found
+ }
+
+ // Usage example
+ const hasIPKey = checkIPKey(allUsers, targetKey);
+
+ if (hasIPKey) {
+ console.log(" -> Valid api key found :)")
+ next();
+ } else {
+ console.log(" -> Invalid api key")
+ return res.status(401).send({ error: 'Invalid API key' });
+ }
+ }
+
+ app.post('/api/trades', validateApiKey, async (req, res) => {
+ const data = req.body;
+ try {
+ if (data && !data.data.length > 0) {
+ res.status(200).send(" -> No trades to import");
+ }
+ else {
+
+ uploadMfePrices.value = data.uploadMfePrices
+
+ //console.log(" uploadMfePrices "+uploadMfePrices.value)
+ // Call the function from addTrades.js
+
+ await useGetTimeZone()
+ await useGetExistingTradesArray("api", ParseNode)
+ await useImportTrades(data.data, "api", data.selectedBroker, ParseNode)
+ await useUploadTrades("api", ParseNode)
+
+ res.status(200).send(" -> Saved Trades to ParseNode DB");
+ }
+ } catch (error) {
+ console.error(error);
+ res.status(500).send({ error: 'Error creating executions' });
+ }
+ });
+
+ app.post('/api/databento', async (req, res) => {
+ //console.log(" calling databento")
+ const data = req.body;
+ //console.log(" data "+JSON.stringify(data))
+ try {
+ const username = data.username;
+ const password = '';
+
+
+ let config = {
+ method: 'post',
+ maxBodyLength: Infinity,
+ url: "https://hist.databento.com/v0/timeseries.get_range",
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Authorization': 'Basic ' + Buffer.from(username + ':' + password).toString('base64')
+ },
+ data: data
+ };
+
+ let responseBack
+ axios.request(config)
+ .then((response) => {
+ //console.log("\n -> Resp " + response.data)
+ responseBack = response.data
+ res.status(200).send(responseBack);
+ })
+ .catch((error) => {
+ console.log(error);
+ res.status(500).send({ error: error });
+ });
+
+ } catch (error) {
+ console.error(error);
+ res.status(500).send({ error: error });
+ }
+ })
+};
+
+/**************************** END APIs ****************************/
+
+const startIndex = async () => {
+
+ const startServer = async () => {
+ console.log("\nSTARTING NODEJS SERVER")
+ return new Promise(async (resolve, reject) => {
+ server = app.listen(port, function () {
+ console.log(' -> TradeNote server started on http://localhost:' + port)
+ });
+ resolve(server)
+ })
+ }
+
+ const runServer = async () => {
+ console.log("\nRUNNING SERVER");
+
+ return new Promise(async (resolve, reject) => {
+ if (process.env.NODE_ENV == 'dev') {
+ // Set up proxy for development environment
+ const proxy = new Proxy.createProxyServer({
+ target: { host: 'localhost', port: PROXY_PORT },
+ });
+
+ // Middleware to handle API routes first (do not pass to Vite)
+ app.use('/api/*', (req, res, next) => {
+ // Handle API routes here
+ //console.log("Handling API route:", req.url);
+ next(); // Continue processing the request for /api/* routes
+ });
+
+ // Set up API routes for dev mode as well
+ setupApiRoutes(app);
+
+ // Proxy all other routes (non-API) to Vite
+ app.use((req, res, next) => {
+ if (req.url.startsWith('/api/')) {
+ return next(); // Let the /api/* routes be handled by the previous middleware
+ }
+ proxy.web(req, res); // Proxy all other routes to Vite
+ });
+
+ // Start Vite dev server
+ const vite = await Vite.createServer({ server: { port: PROXY_PORT } });
+ vite.listen();
+ console.log(" -> Running vite dev server");
+ resolve();
+ } else {
+ // In production, handle API routes normally
+ app.use('/api/*', express.json(), (req, res, next) => {
+ //console.log(`Received API request: ${req.method} ${req.url}`);
+ next(); // Pass control to specific API handlers
+ });
+
+ // Set up API routes for production
+ setupApiRoutes(app);
+
+ // Serve static files from 'dist' folder
+ app.use(express.static('dist'));
+
+ // Fallback for SPA
+ app.get('*', (req, res) => {
+ res.sendFile(path.resolve('dist', 'index.html'));
+ });
+ console.log(" -> Running prod server");
+ resolve();
+ }
+ });
+ };
+
+
+ const setupParseServer = async () => {
+ console.log("\nSTARTING PARSE SERVER")
+ return new Promise(async (resolve, reject) => {
+ const serv = new ParseServer({
+ databaseURI: databaseURI,
+ appId: process.env.APP_ID,
+ masterKey: process.env.MASTER_KEY,
+ port: port,
+ masterKeyIps: ['0.0.0.0/0', '::/0'],
+ allowClientClassCreation: false,
+ allowExpiredAuthDataToken: false
+ });
+
+ // EXPRESS USE
+ await serv.start().then(() => {
+ app.use('/parse', serv.app);
+ console.log(" -> ParseNode server started")
+ resolve()
+ })
+ })
+ }
+
+ await startServer()
+ await setupParseServer()
+ await runServer()
+
+ /*var parseDashboard = new ParseDashboard({
+ "apps": [{
+ "serverURL": "/parse",
+ "appId": process.env.APP_ID,
+ "masterKey": process.env.MASTER_KEY,
+ "appName": "TradeNote"
+ }],
+ "trustProxy": true
+ });*/
+
+
+
+ if (process.env.PARSE_DASHBOARD) app.use('/parseDashboard', parseDashboard)
+
+ //INIT
+ //console.log("\nInitializing ParseNode")
+ ParseNode.initialize(process.env.APP_ID)
+ ParseNode.serverURL = "http://localhost:" + port + "/parse"
+ ParseNode.masterKey = process.env.MASTER_KEY
+
+}
+startIndex()
diff --git a/src/utils/screenshots.js b/src/utils/screenshots.js
index 05ba1c2a..30a88346 100644
--- a/src/utils/screenshots.js
+++ b/src/utils/screenshots.js
@@ -192,6 +192,7 @@ export async function useSetupImageUpload(event, param1, param2, param3, tradeId
screenshot.symbol = param2
screenshot.side = param3
screenshot.tradeId = tradeId
+ screenshot.objectId = undefined
}
const file = event.target.files[0];
|