This commit is contained in:
2025-12-04 13:38:58 -05:00
parent 4a1b5bfc24
commit ab663e7d2b
7 changed files with 365 additions and 29 deletions

View File

@@ -14,22 +14,24 @@ jobs:
- name: Verify Node.js - name: Verify Node.js
run: node -v run: node -v
- name: Install dependencies - name: Install electron-app dependencies
working-directory: electron-app working-directory: electron-app
run: npm ci run: npm ci
- name: Build Windows executable - name: Create production .env file
working-directory: electron-app working-directory: electron-app
env: run: |
WS_URL: ${{ secrets.WS_URL }} echo "WS_URL=${{ secrets.WS_URL }}" > .env
API_URL: ${{ secrets.API_URL }} echo "API_URL=${{ secrets.API_URL }}" >> .env
RELEASE_URL: ${{ secrets.RELEASE_URL }} echo "NODE_ENV=production" >> .env
NODE_ENV: production
run: npm run electron:build -- --win
- name: Upload Windows artifact - name: Build Windows portable executable
working-directory: electron-app
run: npm run build:portable
- name: Upload Windows portable artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: windows-exe name: rmtPocketWatcher-Windows-Portable
path: electron-app/release/*.exe path: electron-app/release/rmtPocketWatcher-*.exe
retention-days: 7 retention-days: 7

View File

@@ -1,5 +1,8 @@
# WebSocket connection URL # WebSocket connection URL
WS_URL=ws://localhost:3000/ws WS_URL=ws://localhost:3000/ws
# API URL
API_URL=http://localhost:3000
# Development mode # Development mode
NODE_ENV=development NODE_ENV=development

View File

@@ -27,6 +27,7 @@
"electron-rebuild": "^3.2.9", "electron-rebuild": "^3.2.9",
"react": "^19.2.1", "react": "^19.2.1",
"react-dom": "^19.2.1", "react-dom": "^19.2.1",
"rimraf": "^6.1.2",
"typescript": "^5.3.0", "typescript": "^5.3.0",
"vite": "^5.0.0", "vite": "^5.0.0",
"wait-on": "^7.2.0" "wait-on": "^7.2.0"
@@ -1054,6 +1055,29 @@
"@hapi/hoek": "^9.0.0" "@hapi/hoek": "^9.0.0"
} }
}, },
"node_modules/@isaacs/balanced-match": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@isaacs/brace-expansion": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@isaacs/balanced-match": "^4.0.1"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@isaacs/cliui": { "node_modules/@isaacs/cliui": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -1327,6 +1351,23 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0" "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
} }
}, },
"node_modules/@npmcli/move-file/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@pkgjs/parseargs": { "node_modules/@pkgjs/parseargs": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -2744,6 +2785,17 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0" "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
} }
}, },
"node_modules/cacache/node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/cacache/node_modules/glob": { "node_modules/cacache/node_modules/glob": {
"version": "8.1.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
@@ -2788,6 +2840,58 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/cacache/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/cacache/node_modules/rimraf/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/cacache/node_modules/rimraf/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/cacheable-lookup": { "node_modules/cacheable-lookup": {
"version": "5.0.4", "version": "5.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
@@ -5943,6 +6047,23 @@
"node-gyp-build-test": "build-test.js" "node-gyp-build-test": "build-test.js"
} }
}, },
"node_modules/node-gyp/node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/node-gyp/node_modules/semver": { "node_modules/node-gyp/node_modules/semver": {
"version": "7.7.3", "version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
@@ -6562,17 +6683,91 @@
} }
}, },
"node_modules/rimraf": { "node_modules/rimraf": {
"version": "3.0.2", "version": "6.1.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "integrity": "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true, "dev": true,
"license": "ISC", "license": "BlueOak-1.0.0",
"dependencies": { "dependencies": {
"glob": "^7.1.3" "glob": "^13.0.0",
"package-json-from-dist": "^1.0.1"
}, },
"bin": { "bin": {
"rimraf": "bin.js" "rimraf": "dist/esm/bin.mjs"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/glob": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz",
"integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.1.1",
"minipass": "^7.1.2",
"path-scurry": "^2.0.0"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/lru-cache": {
"version": "11.2.4",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz",
"integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/rimraf/node_modules/minimatch": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
"integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/brace-expansion": "^5.0.0"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/rimraf/node_modules/path-scurry": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz",
"integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "20 || >=22"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"

View File

@@ -9,11 +9,13 @@
"build:main": "npx tsc --project tsconfig.main.json && npx tsc --project tsconfig.preload.json", "build:main": "npx tsc --project tsconfig.main.json && npx tsc --project tsconfig.preload.json",
"build:renderer": "npx vite build", "build:renderer": "npx vite build",
"build": "npm run build:main && npm run build:renderer", "build": "npm run build:main && npm run build:renderer",
"build:portable": "npm run build && npx electron-builder --win portable",
"clean": "rimraf dist",
"clean:dev": "npm run clean && npm run build:main && concurrently \"npm run dev\" \"wait-on http://localhost:5173 && cross-env NODE_ENV=development electron dist/main/index.js\"",
"electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:5173 && cross-env NODE_ENV=development electron dist/main/index.js\"", "electron:dev": "concurrently \"npm run dev\" \"wait-on http://localhost:5173 && cross-env NODE_ENV=development electron dist/main/index.js\"",
"electron:build": "npm run build && electron-builder", "electron:build": "npm run build && electron-builder",
"publish": "npm run build && electron-builder --publish always", "publish": "npm run build && electron-builder --publish always",
"rebuild": "electron-rebuild", "rebuild": "electron-rebuild",
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
@@ -36,6 +38,7 @@
"electron-rebuild": "^3.2.9", "electron-rebuild": "^3.2.9",
"react": "^19.2.1", "react": "^19.2.1",
"react-dom": "^19.2.1", "react-dom": "^19.2.1",
"rimraf": "^6.1.2",
"typescript": "^5.3.0", "typescript": "^5.3.0",
"vite": "^5.0.0", "vite": "^5.0.0",
"wait-on": "^7.2.0" "wait-on": "^7.2.0"

View File

@@ -33,6 +33,14 @@ export function initDatabase() {
) )
`); `);
// Create settings table for custom AUEC amount
db.exec(`
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
`);
console.log('Database initialized at:', dbPath); console.log('Database initialized at:', dbPath);
} }
@@ -80,6 +88,26 @@ export function deleteAlert(id: string): void {
stmt.run(id); stmt.run(id);
} }
export function getCustomAuecAmount(): number | null {
if (!db) throw new Error('Database not initialized');
const stmt = db.prepare('SELECT value FROM settings WHERE key = ?');
const row = stmt.get('customAuecAmount') as any;
return row ? parseFloat(row.value) : null;
}
export function setCustomAuecAmount(amount: number): void {
if (!db) throw new Error('Database not initialized');
const stmt = db.prepare(`
INSERT OR REPLACE INTO settings (key, value)
VALUES (?, ?)
`);
stmt.run('customAuecAmount', amount.toString());
}
export function closeDatabase(): void { export function closeDatabase(): void {
if (db) { if (db) {
db.close(); db.close();

View File

@@ -53,6 +53,8 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
try { ipcMain.removeHandler('alerts:add'); } catch (e) { /* ignore */ } try { ipcMain.removeHandler('alerts:add'); } catch (e) { /* ignore */ }
try { ipcMain.removeHandler('alerts:update'); } catch (e) { /* ignore */ } try { ipcMain.removeHandler('alerts:update'); } catch (e) { /* ignore */ }
try { ipcMain.removeHandler('alerts:delete'); } catch (e) { /* ignore */ } try { ipcMain.removeHandler('alerts:delete'); } catch (e) { /* ignore */ }
try { ipcMain.removeHandler('settings:getCustomAuecAmount'); } catch (e) { /* ignore */ }
try { ipcMain.removeHandler('settings:setCustomAuecAmount'); } catch (e) { /* ignore */ }
// IPC handlers for renderer requests // IPC handlers for renderer requests
ipcMain.handle('ws:connect', async () => { ipcMain.handle('ws:connect', async () => {
@@ -155,6 +157,26 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
} }
}); });
// Custom AUEC amount handlers
ipcMain.handle('settings:getCustomAuecAmount', async () => {
try {
return db.getCustomAuecAmount();
} catch (error) {
console.error('Failed to get custom AUEC amount:', error);
return null;
}
});
ipcMain.handle('settings:setCustomAuecAmount', async (_event, amount: number) => {
try {
db.setCustomAuecAmount(amount);
return { success: true };
} catch (error) {
console.error('Failed to set custom AUEC amount:', error);
return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
}
});
// Auto-connect on startup // Auto-connect on startup
wsClient.connect(); wsClient.connect();
} }
@@ -181,6 +203,8 @@ export function cleanupIpcHandlers(): void {
ipcMain.removeHandler('alerts:add'); ipcMain.removeHandler('alerts:add');
ipcMain.removeHandler('alerts:update'); ipcMain.removeHandler('alerts:update');
ipcMain.removeHandler('alerts:delete'); ipcMain.removeHandler('alerts:delete');
ipcMain.removeHandler('settings:getCustomAuecAmount');
ipcMain.removeHandler('settings:setCustomAuecAmount');
} catch (error) { } catch (error) {
// Handlers may not exist, ignore // Handlers may not exist, ignore
} }

View File

@@ -52,6 +52,10 @@ export function App() {
const [alertNotification, setAlertNotification] = useState<AlertNotification | null>(null); const [alertNotification, setAlertNotification] = useState<AlertNotification | null>(null);
const alertAudioRef = useRef<HTMLAudioElement | null>(null); const alertAudioRef = useRef<HTMLAudioElement | null>(null);
// Custom AUEC Amount State
const [customAuecAmount, setCustomAuecAmount] = useState<number | null>(null);
const [customAuecInput, setCustomAuecInput] = useState('');
// Load alerts from database on mount // Load alerts from database on mount
useEffect(() => { useEffect(() => {
const loadAlerts = async () => { const loadAlerts = async () => {
@@ -65,6 +69,22 @@ export function App() {
loadAlerts(); loadAlerts();
}, []); }, []);
// Load custom AUEC amount from database on mount
useEffect(() => {
const loadCustomAmount = async () => {
try {
const amount = await window.electron.ipcRenderer.invoke('settings:getCustomAuecAmount');
if (amount) {
setCustomAuecAmount(amount);
setCustomAuecInput(amount.toString());
}
} catch (error) {
console.error('Failed to load custom AUEC amount:', error);
}
};
loadCustomAmount();
}, []);
// Fetch initial data on mount // Fetch initial data on mount
useEffect(() => { useEffect(() => {
fetchInitialData(); fetchInitialData();
@@ -374,6 +394,21 @@ export function App() {
} }
}; };
const saveCustomAuecAmount = async () => {
const amount = parseFloat(customAuecInput);
if (isNaN(amount) || amount <= 0) {
alert('Please enter a valid AUEC amount');
return;
}
try {
await window.electron.ipcRenderer.invoke('settings:setCustomAuecAmount', amount);
setCustomAuecAmount(amount);
} catch (error) {
console.error('Failed to save custom AUEC amount:', error);
}
};
const dismissNotification = () => { const dismissNotification = () => {
setAlertNotification(null); setAlertNotification(null);
}; };
@@ -769,7 +804,41 @@ export function App() {
{latestPrice && ( {latestPrice && (
<div style={{ backgroundColor: '#1a1f3a', padding: '20px', borderRadius: '8px' }}> <div style={{ backgroundColor: '#1a1f3a', padding: '20px', borderRadius: '8px' }}>
<h2 style={{ margin: '0 0 15px 0' }}>Current Listings ({latestPrice.allPrices.length})</h2> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '15px' }}>
<h2 style={{ margin: 0 }}>Current Listings ({latestPrice.allPrices.length})</h2>
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
<input
type="number"
placeholder="Enter AUEC amount"
value={customAuecInput}
onChange={(e) => setCustomAuecInput(e.target.value)}
style={{
padding: '8px 12px',
backgroundColor: '#0a0e27',
border: '1px solid #2a2f4a',
borderRadius: '4px',
color: '#fff',
fontSize: '14px',
width: '180px',
}}
/>
<button
onClick={saveCustomAuecAmount}
style={{
padding: '8px 16px',
backgroundColor: '#50e3c2',
color: '#0a0e27',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontWeight: 'bold',
fontSize: '14px',
}}
>
Set Amount
</button>
</div>
</div>
<div style={{ <div style={{
overflowX: 'auto', overflowX: 'auto',
overflowY: 'auto', overflowY: 'auto',
@@ -783,16 +852,28 @@ export function App() {
<th style={{ textAlign: 'left', padding: '12px', color: '#888', fontWeight: 'normal' }}>Platform</th> <th style={{ textAlign: 'left', padding: '12px', color: '#888', fontWeight: 'normal' }}>Platform</th>
<th style={{ textAlign: 'left', padding: '12px', color: '#888', fontWeight: 'normal' }}>Seller</th> <th style={{ textAlign: 'left', padding: '12px', color: '#888', fontWeight: 'normal' }}>Seller</th>
<th style={{ textAlign: 'right', padding: '12px', color: '#888', fontWeight: 'normal' }}>Price/1M AUEC</th> <th style={{ textAlign: 'right', padding: '12px', color: '#888', fontWeight: 'normal' }}>Price/1M AUEC</th>
{customAuecAmount && (
<th style={{ textAlign: 'right', padding: '12px', color: '#888', fontWeight: 'normal' }}>
Price for {(customAuecAmount / 1000000).toLocaleString()}M AUEC
</th>
)}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{latestPrice.allPrices.map((price) => ( {[...latestPrice.allPrices]
.sort((a, b) => a.pricePerMillion - b.pricePerMillion)
.map((price) => (
<tr key={price.id} style={{ borderBottom: '1px solid #2a2f4a' }}> <tr key={price.id} style={{ borderBottom: '1px solid #2a2f4a' }}>
<td style={{ padding: '12px' }}>{price.platform}</td> <td style={{ padding: '12px' }}>{price.platform}</td>
<td style={{ padding: '12px' }}>{price.sellerName}</td> <td style={{ padding: '12px' }}>{price.sellerName}</td>
<td style={{ textAlign: 'right', padding: '12px', color: '#50e3c2', fontWeight: 'bold' }}> <td style={{ textAlign: 'right', padding: '12px', color: '#50e3c2', fontWeight: 'bold' }}>
${price.pricePerMillion.toFixed(9)} ${price.pricePerMillion.toFixed(9)}
</td> </td>
{customAuecAmount && (
<td style={{ textAlign: 'right', padding: '12px', color: '#50e3c2', fontWeight: 'bold' }}>
${((price.pricePerMillion * customAuecAmount) / 1000000).toFixed(2)}
</td>
)}
</tr> </tr>
))} ))}
</tbody> </tbody>