update watchlist page to add more indicators efficiently
This commit is contained in:
parent
2ce87f8187
commit
e3dc2347fe
@ -4,7 +4,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
const data = await request.json();
|
const data = await request.json();
|
||||||
const { apiURL, apiKey } = locals;
|
const { apiURL, apiKey } = locals;
|
||||||
|
|
||||||
const postData = { watchListId: data?.watchListId };
|
const postData = { watchListId: data?.watchListId, ruleOfList: data?.ruleOfList };
|
||||||
const response = await fetch(apiURL + "/get-watchlist", {
|
const response = await fetch(apiURL + "/get-watchlist", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
20
src/routes/api/indicator-data/+server.ts
Normal file
20
src/routes/api/indicator-data/+server.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||||
|
const data = await request.json();
|
||||||
|
const { apiURL, apiKey } = locals;
|
||||||
|
|
||||||
|
const postData = { tickerList: data?.tickerList, ruleOfList: data?.ruleOfList };
|
||||||
|
const response = await fetch(apiURL + "/indicator-data", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
const output = await response.json();
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(output));
|
||||||
|
};
|
||||||
@ -30,7 +30,15 @@ let allRows = [
|
|||||||
{ name: 'AI Score', rule: 'score' },
|
{ name: 'AI Score', rule: 'score' },
|
||||||
{ name: 'Revenue', rule: 'revenue'},
|
{ name: 'Revenue', rule: 'revenue'},
|
||||||
{ name: 'Net Income', rule: 'netIncome'},
|
{ name: 'Net Income', rule: 'netIncome'},
|
||||||
{ name: 'Free Cash Flow', rule: 'freeCashFlow'}
|
{ name: 'Free Cash Flow', rule: 'freeCashFlow'},
|
||||||
|
{ name: 'Industry', rule: 'industry'},
|
||||||
|
{ name: 'Sector', rule: 'sector'},
|
||||||
|
{ name: 'Price Change 1W', rule: 'change1W' },
|
||||||
|
{ name: 'Price Change 1M', rule: 'change1M' },
|
||||||
|
{ name: 'Price Change 3M', rule: 'change3M' },
|
||||||
|
{ name: 'Price Change 6M', rule: 'change6M' },
|
||||||
|
{ name: 'Price Change 1Y', rule: 'change1Y' },
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let ruleOfList = [
|
let ruleOfList = [
|
||||||
@ -40,14 +48,20 @@ let ruleOfList = [
|
|||||||
{ name: 'Change', rule: 'changesPercentage' },
|
{ name: 'Change', rule: 'changesPercentage' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const excludedRules = new Set(['volume', 'price', 'changesPercentage', 'eps']);
|
||||||
|
const proOnlyItems = new Set(
|
||||||
|
allRows
|
||||||
|
?.filter(item => !excludedRules?.has(item?.rule)) // Exclude the items based on the rule
|
||||||
|
?.map(item => item?.name) // Map the remaining items to their names
|
||||||
|
);
|
||||||
|
|
||||||
let isLoaded = false;
|
let isLoaded = false;
|
||||||
let searchDataLoaded = false; // Flag to track data loading
|
let searchDataLoaded = false; // Flag to track data loading
|
||||||
//let downloadWorker: Worker | undefined;
|
let downloadWorker: Worker | undefined;
|
||||||
let displayWatchList;
|
let displayWatchList;
|
||||||
let allList = data?.getAllWatchlist;
|
let allList = data?.getAllWatchlist;
|
||||||
|
|
||||||
/*
|
|
||||||
const handleDownloadMessage = (event) => {
|
const handleDownloadMessage = (event) => {
|
||||||
isLoaded = false;
|
isLoaded = false;
|
||||||
watchList = event?.data?.watchlistData ?? [];
|
watchList = event?.data?.watchlistData ?? [];
|
||||||
@ -57,7 +71,7 @@ const handleDownloadMessage = (event) => {
|
|||||||
const updateStockScreenerData = async () => {
|
const updateStockScreenerData = async () => {
|
||||||
downloadWorker.postMessage({ ruleOfList: ruleOfList, tickerList: watchList?.map(item => item?.symbol)});
|
downloadWorker.postMessage({ ruleOfList: ruleOfList, tickerList: watchList?.map(item => item?.symbol)});
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
async function loadSearchData() {
|
async function loadSearchData() {
|
||||||
@ -80,9 +94,8 @@ async function loadSearchData() {
|
|||||||
|
|
||||||
async function getWatchlistData()
|
async function getWatchlistData()
|
||||||
{
|
{
|
||||||
const postData = {'watchListId': displayWatchList?.id}
|
|
||||||
|
|
||||||
|
|
||||||
|
const postData = {'watchListId': displayWatchList?.id, 'ruleOfList': ruleOfList?.map(item => item?.rule)}
|
||||||
const response = await fetch('/api/get-watchlist', {
|
const response = await fetch('/api/get-watchlist', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -358,9 +371,14 @@ onMount(async () => {
|
|||||||
const savedRules = localStorage?.getItem('watchlist-ruleOfList');
|
const savedRules = localStorage?.getItem('watchlist-ruleOfList');
|
||||||
if (savedRules) {
|
if (savedRules) {
|
||||||
ruleOfList = JSON.parse(savedRules);
|
ruleOfList = JSON.parse(savedRules);
|
||||||
|
if (data?.user?.tier !== 'Pro') {
|
||||||
|
//Check if user was Pro Member and has past checks of previous paywalled features. If so remove them from the ruleOfList
|
||||||
|
ruleOfList = ruleOfList.filter(item => excludedRules.has(item?.rule)); // Use Set to filter
|
||||||
|
console.log(ruleOfList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log(ey)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkedItems = new Set(ruleOfList.map(item => item.name))
|
checkedItems = new Set(ruleOfList.map(item => item.name))
|
||||||
@ -374,13 +392,14 @@ if(allList?.length !== 0)
|
|||||||
displayWatchList = '';
|
displayWatchList = '';
|
||||||
}
|
}
|
||||||
await getWatchlistData();
|
await getWatchlistData();
|
||||||
/*
|
|
||||||
if (!downloadWorker) {
|
if (!downloadWorker) {
|
||||||
const DownloadWorker = await import('./workers/downloadWorker?worker');
|
const DownloadWorker = await import('./workers/downloadWorker?worker');
|
||||||
downloadWorker = new DownloadWorker.default();
|
downloadWorker = new DownloadWorker.default();
|
||||||
downloadWorker.onmessage = handleDownloadMessage;
|
downloadWorker.onmessage = handleDownloadMessage;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
});
|
});
|
||||||
@ -420,19 +439,18 @@ function isChecked(item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sortIndicatorCheckMarks(allRows) {
|
function sortIndicatorCheckMarks(allRows) {
|
||||||
const priorityItems = new Set(['AI Score', 'Revenue', 'Net Income', 'Free Cash Flow']);
|
|
||||||
|
|
||||||
return allRows.sort((a, b) => {
|
return allRows.sort((a, b) => {
|
||||||
const isAChecked = checkedItems.has(a.name);
|
const isAChecked = checkedItems.has(a?.name);
|
||||||
const isBChecked = checkedItems.has(b.name);
|
const isBChecked = checkedItems.has(b?.name);
|
||||||
|
|
||||||
// Sort checked items first
|
// Sort checked items first
|
||||||
if (isAChecked !== isBChecked) return isAChecked ? -1 : 1;
|
if (isAChecked !== isBChecked) return isAChecked ? -1 : 1;
|
||||||
|
|
||||||
// Check if the user is not Pro
|
// Check if the user is not Pro
|
||||||
if (data?.user?.tier !== 'Pro') {
|
if (data?.user?.tier !== 'Pro') {
|
||||||
const isAPriority = priorityItems.has(a.name);
|
const isAPriority = proOnlyItems.has(a?.name);
|
||||||
const isBPriority = priorityItems.has(b.name);
|
const isBPriority = proOnlyItems.has(b?.name);
|
||||||
|
|
||||||
// If both are priority items or both are not, sort alphabetically
|
// If both are priority items or both are not, sort alphabetically
|
||||||
if (isAPriority === isBPriority) return a.name.localeCompare(b.name);
|
if (isAPriority === isBPriority) return a.name.localeCompare(b.name);
|
||||||
@ -459,9 +477,8 @@ async function handleChangeValue(value) {
|
|||||||
allRows = [...allRows];
|
allRows = [...allRows];
|
||||||
ruleOfList = [...ruleOfList];
|
ruleOfList = [...ruleOfList];
|
||||||
|
|
||||||
|
await updateStockScreenerData()
|
||||||
allRows = sortIndicatorCheckMarks(allRows)
|
allRows = sortIndicatorCheckMarks(allRows)
|
||||||
|
|
||||||
saveRules()
|
saveRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,7 +729,7 @@ function search() {
|
|||||||
{#each (searchQuery?.length !== 0 ? testList : allRows) as item}
|
{#each (searchQuery?.length !== 0 ? testList : allRows) as item}
|
||||||
<DropdownMenu.Item class="sm:hover:bg-[#27272A]" >
|
<DropdownMenu.Item class="sm:hover:bg-[#27272A]" >
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
{#if (data?.user?.tier === 'Pro') || (item.rule !== 'revenue' && item.rule !== 'netIncome' && item.rule !== 'freeCashFlow' && item.rule !== 'score')}
|
{#if (data?.user?.tier === 'Pro') || excludedRules?.has(item?.rule)}
|
||||||
<label on:click|capture={(event) => { event.preventDefault(); handleChangeValue(item?.name) }} class="cursor-pointer text-white" for={item?.name}>
|
<label on:click|capture={(event) => { event.preventDefault(); handleChangeValue(item?.name) }} class="cursor-pointer text-white" for={item?.name}>
|
||||||
<input type="checkbox" class="rounded" checked={isChecked(item?.name)}>
|
<input type="checkbox" class="rounded" checked={isChecked(item?.name)}>
|
||||||
<span class="ml-2">{item?.name}</span>
|
<span class="ml-2">{item?.name}</span>
|
||||||
@ -810,9 +827,11 @@ function search() {
|
|||||||
{#if item?.[row?.rule] !== undefined && item?.[row?.rule] !== null}
|
{#if item?.[row?.rule] !== undefined && item?.[row?.rule] !== null}
|
||||||
{#if ['marketCap', 'volume','revenue','netIncome','freeCashFlow'].includes(row?.rule)}
|
{#if ['marketCap', 'volume','revenue','netIncome','freeCashFlow'].includes(row?.rule)}
|
||||||
{abbreviateNumber(item[row?.rule])}
|
{abbreviateNumber(item[row?.rule])}
|
||||||
|
{:else if ['industry','sector'].includes(row?.rule)}
|
||||||
|
{item[row?.rule] !== null ? item[row?.rule] : '-'}
|
||||||
{:else if ['eps', 'pe', 'price','freeCashFlow'].includes(row?.rule)}
|
{:else if ['eps', 'pe', 'price','freeCashFlow'].includes(row?.rule)}
|
||||||
{item[row?.rule] !== null ? item[row?.rule]?.toFixed(2) : '-'}
|
{item[row?.rule] !== null ? item[row?.rule]?.toFixed(2) : '-'}
|
||||||
{:else if ['changesPercentage'].includes(row?.rule)}
|
{:else if ['changesPercentage','change1W','change1M','change3M','change6M','change1Y','change3Y'].includes(row?.rule)}
|
||||||
{#if item[row?.rule] >= 0}
|
{#if item[row?.rule] >= 0}
|
||||||
<span class="text-[#37C97D]">+{item[row?.rule]?.toFixed(2)}%</span>
|
<span class="text-[#37C97D]">+{item[row?.rule]?.toFixed(2)}%</span>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ const getWatchlistData = async (rules, tickerList) => {
|
|||||||
|
|
||||||
// Extract the rule names
|
// Extract the rule names
|
||||||
let getRuleOfList = rules?.map((rule) => rule.rule) || [];
|
let getRuleOfList = rules?.map((rule) => rule.rule) || [];
|
||||||
|
|
||||||
// Convert the rule set into a string key for the cache
|
// Convert the rule set into a string key for the cache
|
||||||
const ruleKey = JSON.stringify(getRuleOfList);
|
const ruleKey = JSON.stringify(getRuleOfList);
|
||||||
|
|
||||||
@ -27,7 +26,6 @@ const getWatchlistData = async (rules, tickerList) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const output = await response.json();
|
const output = await response.json();
|
||||||
console.log(output);
|
|
||||||
// Store the new data in the cache
|
// Store the new data in the cache
|
||||||
cache.set(ruleKey, output);
|
cache.set(ruleKey, output);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user