adding realtime chart updates

This commit is contained in:
MuslemRahimi 2024-10-16 21:45:44 +02:00
parent a9af5001c2
commit f8cbe87a60
3 changed files with 560 additions and 178 deletions

View File

@ -44,6 +44,7 @@ export const clearCache = () => {
}; };
export const showCookieConsent = writable(<boolean>false); export const showCookieConsent = writable(<boolean>false);
export const shouldUpdatePriceChart = writable(<boolean>false);
export const executiveClicked = writable(<boolean>false); export const executiveClicked = writable(<boolean>false);
export const secFilingsClicked = writable(<boolean>false); export const secFilingsClicked = writable(<boolean>false);
@ -76,6 +77,7 @@ export const loginData = writable({});
export const replyCommentClicked = writable({}); export const replyCommentClicked = writable({});
export const editCommentClicked = writable({}); export const editCommentClicked = writable({});
export const priceChartData = writable({});
export const fundamentalAnalysisComponent = writable(<boolean>false); export const fundamentalAnalysisComponent = writable(<boolean>false);
export const priceAnalysisComponent = writable(<boolean>false); export const priceAnalysisComponent = writable(<boolean>false);

View File

@ -1,5 +1,23 @@
<script lang="ts"> <script lang="ts">
import { wsBidPrice, wsAskPrice, searchBarData, globalForm, scoreComponent, screenWidth, openPriceAlert, currentPortfolioPrice, realtimePrice, isCrosshairMoveActive, currentPrice, priceIncrease, displayCompanyName, stockTicker, isOpen } from "$lib/store"; import {
wsBidPrice,
wsAskPrice,
searchBarData,
globalForm,
scoreComponent,
screenWidth,
openPriceAlert,
currentPortfolioPrice,
realtimePrice,
isCrosshairMoveActive,
currentPrice,
priceIncrease,
displayCompanyName,
stockTicker,
isOpen,
shouldUpdatePriceChart,
priceChartData,
} from "$lib/store";
import { onMount, onDestroy, afterUpdate } from "svelte"; import { onMount, onDestroy, afterUpdate } from "svelte";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
@ -109,65 +127,61 @@ function handleTypeOfTrade(state:string)
} }
} }
async function toggleUserWatchlist(watchListId: string) { async function toggleUserWatchlist(watchListId: string) {
try { try {
isTickerIncluded = !isTickerIncluded; isTickerIncluded = !isTickerIncluded;
const watchlistIndex = userWatchList?.findIndex(item => item?.id === watchListId); const watchlistIndex = userWatchList?.findIndex(
(item) => item?.id === watchListId,
);
if (watchlistIndex !== -1) { if (watchlistIndex !== -1) {
const existingTickerIndex = userWatchList[watchlistIndex]?.ticker?.indexOf($stockTicker); const existingTickerIndex =
userWatchList[watchlistIndex]?.ticker?.indexOf($stockTicker);
if (existingTickerIndex !== -1) { if (existingTickerIndex !== -1) {
// If the $stockTicker exists, remove it from the array // If the $stockTicker exists, remove it from the array
userWatchList[watchlistIndex]?.ticker?.splice(existingTickerIndex, 1); userWatchList[watchlistIndex]?.ticker?.splice(existingTickerIndex, 1);
} else { } else {
// If the $stockTicker doesn't exist, add it to the array // If the $stockTicker doesn't exist, add it to the array
userWatchList[watchlistIndex]?.ticker?.push($stockTicker); userWatchList[watchlistIndex]?.ticker?.push($stockTicker);
}
// Update the userWatchList
userWatchList = [...userWatchList];
} }
// Update the userWatchList const postData = {
userWatchList = [...userWatchList]; watchListId: watchListId,
ticker: $stockTicker,
};
const response = await fetch("/api/update-watchlist", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(postData),
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const output = await response.json();
// Update the userWatchList with the response from the server
if (watchlistIndex !== -1) {
userWatchList[watchlistIndex] = output;
userWatchList = [...userWatchList];
} else {
userWatchList = [...userWatchList, output];
}
} catch (error) {
console.error("An error occurred:", error);
// Handle the error appropriately (e.g., show an error message to the user)
} }
const postData = {
'watchListId': watchListId,
'ticker': $stockTicker,
};
const response = await fetch('/api/update-watchlist', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(postData),
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const output = await response.json();
// Update the userWatchList with the response from the server
if( watchlistIndex !== -1)
{
userWatchList[watchlistIndex] = output;
userWatchList = [...userWatchList];
}
else {
userWatchList = [...userWatchList, output];
}
} catch (error) {
console.error('An error occurred:', error);
// Handle the error appropriately (e.g., show an error message to the user)
} }
}
function sendMessage(message) { function sendMessage(message) {
if (socket && socket.readyState === WebSocket.OPEN) { if (socket && socket.readyState === WebSocket.OPEN) {
@ -193,11 +207,31 @@ async function toggleUserWatchlist(watchListId: string) {
const data = event.data; const data = event.data;
//console.log('Received message:', data); //console.log('Received message:', data);
try { try {
$realtimePrice = typeof JSON.parse(data)?.lp !== "undefined" ? JSON.parse(data)?.lp : null; $realtimePrice =
$wsBidPrice = typeof JSON.parse(data)?.bp !== "undefined" ? JSON.parse(data)?.bp : null; typeof JSON.parse(data)?.lp !== "undefined"
$wsAskPrice = typeof JSON.parse(data)?.ap !== "undefined" ? JSON.parse(data)?.ap : null; ? JSON.parse(data)?.lp
//console.log('Received message:', $realtimePrice); : null;
$wsBidPrice =
typeof JSON.parse(data)?.bp !== "undefined"
? JSON.parse(data)?.bp
: null;
$wsAskPrice =
typeof JSON.parse(data)?.ap !== "undefined"
? JSON.parse(data)?.ap
: null;
//console.log("Received message:", JSON.parse(data));
$priceChartData = {
time:
typeof JSON.parse(data)?.time !== "undefined"
? JSON.parse(data)?.time
: null,
price:
typeof JSON.parse(data)?.lp !== "undefined"
? Number(JSON.parse(data)?.lp)
: null,
};
//console.log($priceChartData);
shouldUpdatePriceChart.set(true);
if ($realtimePrice > previousRealtimePrice) { if ($realtimePrice > previousRealtimePrice) {
$priceIncrease = true; $priceIncrease = true;
previousRealtimePrice = $realtimePrice; previousRealtimePrice = $realtimePrice;
@ -234,12 +268,11 @@ async function toggleUserWatchlist(watchListId: string) {
//SellTrade = (await import('$lib/components/SellTrade.svelte')).default; //SellTrade = (await import('$lib/components/SellTrade.svelte')).default;
PriceAlert = (await import("$lib/components/PriceAlert.svelte")).default; PriceAlert = (await import("$lib/components/PriceAlert.svelte")).default;
} }
if ($isOpen) { if ($isOpen) {
//&& currentDateTime > startTime && currentDateTime < endTime //&& currentDateTime > startTime && currentDateTime < endTime
await websocketRealtimeData(); await websocketRealtimeData();
} }
}); });
afterUpdate(async () => { afterUpdate(async () => {
@ -255,7 +288,7 @@ async function toggleUserWatchlist(watchListId: string) {
await websocketRealtimeData(); await websocketRealtimeData();
console.log("connecting again"); console.log("connecting again");
} }
$wsAskPrice = null; $wsAskPrice = null;
$wsBidPrice = null; $wsBidPrice = null;
} }
}); });
@ -272,13 +305,17 @@ async function toggleUserWatchlist(watchListId: string) {
$currentPortfolioPrice = null; $currentPortfolioPrice = null;
$currentPrice = null; $currentPrice = null;
$priceIncrease = null; $priceIncrease = null;
$wsAskPrice = null; $wsAskPrice = null;
$wsBidPrice = null; $wsBidPrice = null;
//$traded = false //$traded = false
}); });
$: { $: {
if ($stockTicker && $stockTicker?.length !== 0 && typeof window !== "undefined") { if (
$stockTicker &&
$stockTicker?.length !== 0 &&
typeof window !== "undefined"
) {
// add a check to see if running on client-side // add a check to see if running on client-side
stockDeck = data?.getStockDeck; stockDeck = data?.getStockDeck;
similarstock = data?.getSimilarStock; similarstock = data?.getSimilarStock;
@ -287,14 +324,19 @@ async function toggleUserWatchlist(watchListId: string) {
} }
} }
$: isTickerIncluded = userWatchList?.some((item) => item.user === data?.user?.id && item.ticker?.includes($stockTicker)); $: isTickerIncluded = userWatchList?.some(
(item) =>
item.user === data?.user?.id && item.ticker?.includes($stockTicker),
);
$: charNumber = $screenWidth < 640 ? 12 : 25; $: charNumber = $screenWidth < 640 ? 12 : 25;
$: { $: {
if ($stockTicker && typeof window !== "undefined" && $page.url.pathname === `/stocks/${$stockTicker}`) { if (
$stockTicker &&
typeof window !== "undefined" &&
$page.url.pathname === `/stocks/${$stockTicker}`
) {
displaySection = "overview"; displaySection = "overview";
} }
} }
@ -310,7 +352,10 @@ async function toggleUserWatchlist(watchListId: string) {
forecast: "forecast", forecast: "forecast",
news: "news", news: "news",
}; };
displaySection = sectionMap[parts?.find((part) => Object?.keys(sectionMap)?.includes(part))] || "overview"; displaySection =
sectionMap[
parts?.find((part) => Object?.keys(sectionMap)?.includes(part))
] || "overview";
} }
} }
@ -319,7 +364,9 @@ async function toggleUserWatchlist(watchListId: string) {
<svelte:window bind:scrollY={y} /> <svelte:window bind:scrollY={y} />
<body class="bg-[#09090B] pb-40 w-full max-w-screen min-h-screen sm:max-w-7xl xl:max-w-screen-2xl overflow-hidden"> <body
class="bg-[#09090B] pb-40 w-full max-w-screen min-h-screen sm:max-w-7xl xl:max-w-screen-2xl overflow-hidden"
>
<!-- Page wrapper --> <!-- Page wrapper -->
<div class="flex flex-col w-full mt-5 relative"> <div class="flex flex-col w-full mt-5 relative">
<main class="grow w-full"> <main class="grow w-full">
@ -329,23 +376,47 @@ async function toggleUserWatchlist(watchListId: string) {
<!--Start Mobile Navbar--> <!--Start Mobile Navbar-->
<div class="fixed top-0 left-0 right-0 z-20 bg-[#09090B] sm:hidden"> <div class="fixed top-0 left-0 right-0 z-20 bg-[#09090B] sm:hidden">
<div class="navbar w-full px-4 py-2"> <div class="navbar w-full px-4 py-2">
<div class="{isScrolled ? 'border-b border-slate-800 ease-in' : 'ease-out'} m-auto w-full"> <div
<div class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2"> class="{isScrolled
<label on:click={() => goto("/")} class="ml-2 cursor-pointer"> ? 'border-b border-slate-800 ease-in'
<svg class="w-5 h-5 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" : 'ease-out'} m-auto w-full"
>
<div
class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2"
>
<label
on:click={() => goto("/")}
class="ml-2 cursor-pointer"
>
<svg
class="w-5 h-5 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1024 1024"
><g transform="rotate(-90 512 512)" ><g transform="rotate(-90 512 512)"
><path fill="white" d="M104.704 685.248a64 64 0 0 0 90.496 0l316.8-316.8l316.8 316.8a64 64 0 0 0 90.496-90.496L557.248 232.704a64 64 0 0 0-90.496 0L104.704 594.752a64 64 0 0 0 0 90.496z" /></g ><path
fill="white"
d="M104.704 685.248a64 64 0 0 0 90.496 0l316.8-316.8l316.8 316.8a64 64 0 0 0 90.496-90.496L557.248 232.704a64 64 0 0 0-90.496 0L104.704 594.752a64 64 0 0 0 0 90.496z"
/></g
></svg ></svg
> >
</label> </label>
<div class={!isScrolled ? "hidden" : "flex flex-col items-center ml-6 transition-transform ease-in"}> <div
<span class="text-white text-[0.70rem] font-medium text-opacity-[0.6]"> class={!isScrolled
? "hidden"
: "flex flex-col items-center ml-6 transition-transform ease-in"}
>
<span
class="text-white text-[0.70rem] font-medium text-opacity-[0.6]"
>
{$stockTicker} {$stockTicker}
</span> </span>
<span class="text-white font-medium text-sm"> <span class="text-white font-medium text-sm">
{#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0} {#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0}
{$stockTicker?.includes(".DE") || $stockTicker?.includes(".F") ? `${$currentPortfolioPrice}` : ` $${$currentPortfolioPrice}`} {$stockTicker?.includes(".DE") ||
$stockTicker?.includes(".F")
? `${$currentPortfolioPrice}€`
: ` $${$currentPortfolioPrice}`}
{:else} {:else}
{data?.getStockQuote?.price} {data?.getStockQuote?.price}
{/if} {/if}
@ -353,16 +424,39 @@ async function toggleUserWatchlist(watchListId: string) {
</div> </div>
<!--Start Search Button--> <!--Start Search Button-->
<label on:click={loadSearchData} class="ml-auto mr-4" for="searchBarModal"> <label
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" on:click={loadSearchData}
><path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m21 21l-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314" /></svg class="ml-auto mr-4"
for="searchBarModal"
>
<svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path
fill="none"
stroke="white"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="m21 21l-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314"
/></svg
> >
</label> </label>
<!--End Search Button--> <!--End Search Button-->
<!--Start Share Button--> <!--Start Share Button-->
<label class="mr-4" on:click={() => shareContent("https://stocknear.com/stocks/" + $stockTicker)}> <label
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="mr-4"
on:click={() =>
shareContent(
"https://stocknear.com/stocks/" + $stockTicker,
)}
>
<svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
><path ><path
fill="none" fill="none"
stroke="white" stroke="white"
@ -380,16 +474,25 @@ async function toggleUserWatchlist(watchListId: string) {
{#if data?.user} {#if data?.user}
<div class="flex flex-col mr-4"> <div class="flex flex-col mr-4">
{#if userWatchList?.length !== 0} {#if userWatchList?.length !== 0}
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0"> <label
for="addWatchListModal"
class="cursor-pointer flex-shrink-0"
>
{#if isTickerIncluded} {#if isTickerIncluded}
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="#FBCE3C" fill="#FBCE3C"
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
/></svg /></svg
> >
{:else} {:else}
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -398,16 +501,25 @@ async function toggleUserWatchlist(watchListId: string) {
{/if} {/if}
</label> </label>
{:else if userWatchList?.length === 0} {:else if userWatchList?.length === 0}
<label on:click={() => toggleUserWatchlist("firstList")} class="cursor-pointer flex-shrink-0"> <label
on:click={() => toggleUserWatchlist("firstList")}
class="cursor-pointer flex-shrink-0"
>
{#if isTickerIncluded} {#if isTickerIncluded}
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="#FBCE3C" fill="#FBCE3C"
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
/></svg /></svg
> >
{:else} {:else}
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -418,8 +530,14 @@ async function toggleUserWatchlist(watchListId: string) {
{/if} {/if}
</div> </div>
{:else} {:else}
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white mr-4"> <label
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" for="userLogin"
class="cursor-pointer flex-shrink-0 text-white mr-4"
>
<svg
class="w-6 h-6 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -430,9 +548,27 @@ async function toggleUserWatchlist(watchListId: string) {
<!--End Watchlist--> <!--End Watchlist-->
<!--Start Price Alert--> <!--Start Price Alert-->
<label on:click={() => ($openPriceAlert = true)} for={data?.user ? "priceAlertModal" : "userLogin"} class="mr-2"> <label
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7 inline-block mt-1" viewBox="0 0 24 24" on:click={() => ($openPriceAlert = true)}
><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3" /><circle cx="12" cy="13" r="8" /><path d="M9.5 13h5M12 10.5v5" /></g></svg for={data?.user ? "priceAlertModal" : "userLogin"}
class="mr-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-7 h-7 inline-block mt-1"
viewBox="0 0 24 24"
><g
fill="none"
stroke="white"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
><path d="M3 5.231L6.15 3M21 5.231L17.85 3" /><circle
cx="12"
cy="13"
r="8"
/><path d="M9.5 13h5M12 10.5v5" /></g
></svg
> >
</label> </label>
<!--End Price Alert --> <!--End Price Alert -->
@ -442,34 +578,52 @@ async function toggleUserWatchlist(watchListId: string) {
</div> </div>
<!--End Mobile Navbar--> <!--End Mobile Navbar-->
<div class="pt-14 sm:pt-0 w-auto max-w-3xl lg:max-w-content 2xl:max-w-6xl px-3 sm:px-0"> <div
<div class="md:flex md:justify-between md:divide-x md:divide-slate-800"> class="pt-14 sm:pt-0 w-auto max-w-3xl lg:max-w-content 2xl:max-w-6xl px-3 sm:px-0"
>
<div
class="md:flex md:justify-between md:divide-x md:divide-slate-800"
>
<!-- Main content --> <!-- Main content -->
<div class="pb-12 md:pb-20 w-full 2xl:max-w-5xl"> <div class="pb-12 md:pb-20 w-full 2xl:max-w-5xl">
<div class="md:pr-6 lg:pr-10"> <div class="md:pr-6 lg:pr-10">
<!-----Start-Header-CandleChart-Indicators------> <!-----Start-Header-CandleChart-Indicators------>
<div class="m-auto pl-0 sm:pl-4 overflow-hidden mb-3 md:mt-10 xl:pr-7"> <div
<div class="hidden sm:flex flex-row w-full justify-between items-center "> class="m-auto pl-0 sm:pl-4 overflow-hidden mb-3 md:mt-10 xl:pr-7"
>
<div
class="hidden sm:flex flex-row w-full justify-between items-center"
>
<Markethour /> <Markethour />
<!--Start Watchlist--> <!--Start Watchlist-->
{#if data?.user} {#if data?.user}
<div class="flex flex-col ml-auto mr-2"> <div class="flex flex-col ml-auto mr-2">
{#if userWatchList?.length !== 0} {#if userWatchList?.length !== 0}
<div class="flex-shrink-0 rounded-full sm:hover:bg-white sm:hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"> <div
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0"> class="flex-shrink-0 rounded-full sm:hover:bg-white sm:hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
>
<label
for="addWatchListModal"
class="cursor-pointer flex-shrink-0"
>
{#if isTickerIncluded} {#if isTickerIncluded}
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-7 h-7 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="#FBCE3C" fill="#FBCE3C"
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
/></svg /></svg
> >
{:else} {:else}
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-7 h-7 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -479,17 +633,29 @@ async function toggleUserWatchlist(watchListId: string) {
</label> </label>
</div> </div>
{:else if userWatchList?.length === 0} {:else if userWatchList?.length === 0}
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"> <div
<label on:click={() => toggleUserWatchlist("firstList")} class="cursor-pointer flex-shrink-0"> class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
>
<label
on:click={() =>
toggleUserWatchlist("firstList")}
class="cursor-pointer flex-shrink-0"
>
{#if isTickerIncluded} {#if isTickerIncluded}
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-7 h-7 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="#FBCE3C" fill="#FBCE3C"
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
/></svg /></svg
> >
{:else} {:else}
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" <svg
class="w-7 h-7 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -501,9 +667,17 @@ async function toggleUserWatchlist(watchListId: string) {
{/if} {/if}
</div> </div>
{:else} {:else}
<div class="flex-shrink-0 ml-auto mr-2 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"> <div
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white"> class="flex-shrink-0 ml-auto mr-2 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
<label
for="userLogin"
class="cursor-pointer flex-shrink-0 text-white"
>
<svg
class="w-7 h-7 inline-block"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
><path ><path
fill="white" fill="white"
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
@ -516,10 +690,30 @@ async function toggleUserWatchlist(watchListId: string) {
<!--Start Price Alert --> <!--Start Price Alert -->
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"> <div
<label on:click={() => ($openPriceAlert = true)} for={data?.user ? "priceAlertModal" : "userLogin"} class="cursor-pointer flex-shrink-0 text-white"> class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center"
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 inline-block" viewBox="0 0 24 24" >
><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3" /><circle cx="12" cy="13" r="8" /><path d="M9.5 13h5M12 10.5v5" /></g></svg <label
on:click={() => ($openPriceAlert = true)}
for={data?.user ? "priceAlertModal" : "userLogin"}
class="cursor-pointer flex-shrink-0 text-white"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-8 h-8 inline-block"
viewBox="0 0 24 24"
><g
fill="none"
stroke="white"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
><path
d="M3 5.231L6.15 3M21 5.231L17.85 3"
/><circle cx="12" cy="13" r="8" /><path
d="M9.5 13h5M12 10.5v5"
/></g
></svg
> >
</label> </label>
</div> </div>
@ -530,30 +724,47 @@ async function toggleUserWatchlist(watchListId: string) {
<!-- svelte-ignore a11y-label-has-associated-control --> <!-- svelte-ignore a11y-label-has-associated-control -->
<div class="flex items-center w-full mt-3"> <div class="flex items-center w-full mt-3">
<div class="flex flex-row justify-start w-full items-center "> <div
class="flex flex-row justify-start w-full items-center"
>
<!--<img class="rounded-full w-10 h-10" src={logoUrl} alt="" />--> <!--<img class="rounded-full w-10 h-10" src={logoUrl} alt="" />-->
<div class="flex-shrink-0 rounded-full w-10 h-10 relative bg-[#141417] flex items-center justify-center border border-slate-800"> <div
<img style="clip-path: circle(50%);" class="avatar w-6 h-6" src={`https://financialmodelingprep.com/image-stock/${$stockTicker?.toUpperCase()}.png`} alt=" " loading="lazy" /> class="flex-shrink-0 rounded-full w-10 h-10 relative bg-[#141417] flex items-center justify-center border border-slate-800"
>
<img
style="clip-path: circle(50%);"
class="avatar w-6 h-6"
src={`https://financialmodelingprep.com/image-stock/${$stockTicker?.toUpperCase()}.png`}
alt=" "
loading="lazy"
/>
</div> </div>
<div class="flex flex-col items-start ml-2 sm:ml-3"> <div class="flex flex-col items-start ml-2 sm:ml-3">
<span class="text-xs text-blue-400"> <span class="text-xs text-blue-400">
{$stockTicker?.toUpperCase()} {$stockTicker?.toUpperCase()}
</span> </span>
<span class="text-sm sm:text-xl font-medium text-slate-100"> <span
{$displayCompanyName?.length > charNumber ? $displayCompanyName?.slice(0, charNumber) + "..." : $displayCompanyName} class="text-sm sm:text-xl font-medium text-slate-100"
>
{$displayCompanyName?.length > charNumber
? $displayCompanyName?.slice(0, charNumber) +
"..."
: $displayCompanyName}
</span> </span>
</div> </div>
<div class="ml-auto {$scoreComponent === false ? 'invisible' : ''}"> <div
<AIScore score={data?.getStockDeck?.at(0)?.score} tier={data?.user?.tier}/> class="ml-auto {$scoreComponent === false
? 'invisible'
: ''}"
>
<AIScore
score={data?.getStockDeck?.at(0)?.score}
tier={data?.user?.tier}
/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-----End-Header-CandleChart-Indicators------> <!-----End-Header-CandleChart-Indicators------>
@ -561,82 +772,139 @@ async function toggleUserWatchlist(watchListId: string) {
<!--Start Ticker Section--> <!--Start Ticker Section-->
<!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">--> <!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">-->
<div class="-ml-2 sm:ml-4 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : ''} mb-2"> <div
<ul class="pr-4 sm:pr-0 w-screen font-medium flex flex-row items-center bg-[#09090B] space-x-3 rtl:space-x-reverse py-2"> class="-ml-2 sm:ml-4 w-screen sm:w-full {$screenWidth <
640
? 'overflow-auto scrollbar'
: ''} mb-2"
>
<ul
class="pr-4 sm:pr-0 w-screen font-medium flex flex-row items-center bg-[#09090B] space-x-3 rtl:space-x-reverse py-2"
>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}`} href={`/stocks/${$stockTicker}`}
id="item1" id="item1"
on:click={() => changeSection("overview", "item1")} on:click={() => changeSection("overview", "item1")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'overview' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'overview'
? 'text-white '
: 'bg-[#09090B]'}"
> >
Overview Overview
</a> </a>
<div class="{displaySection === 'overview' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4.2rem]" /> <div
class="{displaySection === 'overview'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4.2rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/stats`} href={`/stocks/${$stockTicker}/stats`}
id="item2" id="item2"
on:click={() => changeSection("fundamental", "item2")} on:click={() =>
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'fundamental' ? 'text-white ' : 'bg-[#09090B]'}">Fundamental</a changeSection("fundamental", "item2")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'fundamental'
? 'text-white '
: 'bg-[#09090B]'}">Fundamental</a
> >
<div class="{displaySection === 'fundamental' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" /> <div
class="{displaySection === 'fundamental'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/forecast`} href={`/stocks/${$stockTicker}/forecast`}
id="item3" id="item3"
on:click={() => changeSection("forecast", "item3")} on:click={() => changeSection("forecast", "item3")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'forecast' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'forecast'
? 'text-white '
: 'bg-[#09090B]'}"
> >
Forecast Forecast
</a> </a>
<div class="{displaySection === 'forecast' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" /> <div
class="{displaySection === 'forecast'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/options`} href={`/stocks/${$stockTicker}/options`}
id="item3" id="item3"
on:click={() => changeSection("options", "item3")} on:click={() => changeSection("options", "item3")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'options' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'options'
? 'text-white '
: 'bg-[#09090B]'}"
> >
Options Options
</a> </a>
<div class="{displaySection === 'options' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" /> <div
class="{displaySection === 'options'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/insider`} href={`/stocks/${$stockTicker}/insider`}
id="item4" id="item4"
on:click={() => changeSection("insider", "item4")} on:click={() => changeSection("insider", "item4")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'insider' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'insider'
? 'text-white '
: 'bg-[#09090B]'}"
> >
Insider Insider
</a> </a>
<div class="{displaySection === 'insider' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" /> <div
class="{displaySection === 'insider'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/dividends`} href={`/stocks/${$stockTicker}/dividends`}
id="item5" id="item5"
on:click={() => changeSection("dividends", "item5")} on:click={() => changeSection("dividends", "item5")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'dividends' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'dividends'
? 'text-white '
: 'bg-[#09090B]'}"
> >
Dividends Dividends
</a> </a>
<div class="{displaySection === 'dividends' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]" /> <div
class="{displaySection === 'dividends'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]"
/>
</li> </li>
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={`/stocks/${$stockTicker}/news`} href={`/stocks/${$stockTicker}/news`}
id="item7" id="item7"
on:click={() => changeSection("news", "item7")} on:click={() => changeSection("news", "item7")}
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'news' ? 'text-white ' : 'bg-[#09090B]'}" class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection ===
'news'
? 'text-white '
: 'bg-[#09090B]'}"
> >
News News
</a> </a>
<div class="{displaySection === 'news' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" /> <div
class="{displaySection === 'news'
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]"
/>
</li> </li>
</ul> </ul>
</div> </div>
@ -647,24 +915,23 @@ async function toggleUserWatchlist(watchListId: string) {
</div> </div>
</div> </div>
<aside class="hidden lg:block w-fit max-w-xl xl:w-[120px] md:pt-10 pb-12 md:pb-20"> <aside
<div class="sm:pl-10"> class="hidden lg:block w-fit max-w-xl xl:w-[120px] md:pt-10 pb-12 md:pb-20"
>
<!--Start Company Info --> <div class="sm:pl-10">
<Sidecard <!--Start Company Info -->
data = {data} <Sidecard
stockDeck = {stockDeck} {data}
lastPrice = {data?.getStockQuote?.price} {stockDeck}
analystRating ={data?.getAnalystRating} lastPrice={data?.getStockQuote?.price}
similarstock = {similarstock} analystRating={data?.getAnalystRating}
topETFHolder = {topETFHolder} {similarstock}
/> {topETFHolder}
<!--End Company Info --> />
<!--End Company Info -->
</div>
</div> </aside>
</aside> <!--
<!--
{#if $screenWidth < 640 && MobileStockNavbar} {#if $screenWidth < 640 && MobileStockNavbar}
<MobileStockNavbar <MobileStockNavbar
logoUrl={logoUrl} logoUrl={logoUrl}
@ -810,36 +1077,82 @@ async function toggleUserWatchlist(watchListId: string) {
<!--Start Add Watchlist Modal--> <!--Start Add Watchlist Modal-->
<input type="checkbox" id="addWatchListModal" class="modal-toggle" /> <input type="checkbox" id="addWatchListModal" class="modal-toggle" />
<dialog id="addWatchListModal" class="modal modal-bottom sm:modal-middle bg-[#000] bg-opacity-[0.5]"> <dialog
<label id="addWatchListModal" for="addWatchListModal" class="cursor-pointer modal-backdrop"></label> id="addWatchListModal"
class="modal modal-bottom sm:modal-middle bg-[#000] bg-opacity-[0.5]"
>
<label
id="addWatchListModal"
for="addWatchListModal"
class="cursor-pointer modal-backdrop"
></label>
<div class="modal-box w-full bg-[#191919] sm:border sm:border-gray-800"> <div class="modal-box w-full bg-[#191919] sm:border sm:border-gray-800">
<label for="addWatchListModal" class="cursor-pointer bg-[#191919] absolute right-5 top-2 text-[1.8rem] text-white"></label> <label
for="addWatchListModal"
class="cursor-pointer bg-[#191919] absolute right-5 top-2 text-[1.8rem] text-white"
>
</label>
<div class="text-white"> <div class="text-white">
<h3 class="font-semibold text-lg sm:text-xl mb-10">Add to Watchlist</h3> <h3 class="font-semibold text-lg sm:text-xl mb-10">Add to Watchlist</h3>
<div class="flex flex-col items-center w-full max-w-3xl bg-[#191919]"> <div class="flex flex-col items-center w-full max-w-3xl bg-[#191919]">
{#each userWatchList as item} {#each userWatchList as item}
<label on:click|stopPropagation={() => toggleUserWatchlist(item?.id)} class="cursor-pointer w-full flex flex-row justify-start items-center mb-5"> <label
<div class="flex flex-row items-center w-full bg-[#313131] p-3 rounded-lg {item?.ticker?.includes($stockTicker) ? 'ring-2 ring-[#04E000]' : ''}"> on:click|stopPropagation={() => toggleUserWatchlist(item?.id)}
class="cursor-pointer w-full flex flex-row justify-start items-center mb-5"
>
<div
class="flex flex-row items-center w-full bg-[#313131] p-3 rounded-lg {item?.ticker?.includes(
$stockTicker,
)
? 'ring-2 ring-[#04E000]'
: ''}"
>
<div class="flex flex-col items-center w-full"> <div class="flex flex-col items-center w-full">
<span class="ml-1 text-white font-medium mr-auto"> <span class="ml-1 text-white font-medium mr-auto">
{item?.title} {item?.title}
</span> </span>
<span class="ml-1 text-white text-opacity-40 text-sm font-medium mr-auto"> <span
class="ml-1 text-white text-opacity-40 text-sm font-medium mr-auto"
>
{item?.ticker?.length} {item?.ticker?.length}
{item?.ticker?.length !== 1 ? "Companies" : "Company"} {item?.ticker?.length !== 1 ? "Companies" : "Company"}
</span> </span>
</div> </div>
<div class="rounded-full w-8 h-8 relative border border-[#737373]"> <div
class="rounded-full w-8 h-8 relative border border-[#737373]"
>
{#if item?.ticker?.includes($stockTicker)} {#if item?.ticker?.includes($stockTicker)}
<svg class="w-full h-full rounded-full" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#09090B000" <svg
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> class="w-full h-full rounded-full"
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <title>ic_fluent_checkmark_circle_48_filled</title> <desc>Created with Sketch.</desc> viewBox="0 0 48 48"
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> version="1.1"
<g id="ic_fluent_checkmark_circle_48_filled" fill="#04E000" fill-rule="nonzero"> xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="#09090B000"
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g><g id="SVGRepo_iconCarrier">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<title>ic_fluent_checkmark_circle_48_filled</title>
<desc>Created with Sketch.</desc>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="ic_fluent_checkmark_circle_48_filled"
fill="#04E000"
fill-rule="nonzero"
>
<path <path
d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z" d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z"
> >
@ -896,4 +1209,4 @@ async function toggleUserWatchlist(watchListId: string) {
::-webkit-scrollbar-corner { ::-webkit-scrollbar-corner {
background: #09090b; background: #09090b;
} }
</style> </style>

View File

@ -1,6 +1,10 @@
<script lang="ts"> <script lang="ts">
import { AreaSeries, Chart, PriceLine } from "svelte-lightweight-charts"; import { AreaSeries, Chart, PriceLine } from "svelte-lightweight-charts";
import { TrackingModeExitMode, ColorType } from "lightweight-charts"; import {
TrackingModeExitMode,
ColorType,
CrosshairMode,
} from "lightweight-charts";
import { import {
getCache, getCache,
setCache, setCache,
@ -32,8 +36,10 @@
isOpen, isOpen,
isBeforeMarketOpen, isBeforeMarketOpen,
isWeekend, isWeekend,
shouldUpdatePriceChart,
priceChartData,
} from "$lib/store"; } from "$lib/store";
import { onDestroy } from "svelte"; import { onDestroy, onMount } from "svelte";
import BullBearSay from "$lib/components/BullBearSay.svelte"; import BullBearSay from "$lib/components/BullBearSay.svelte";
import NextEarnings from "$lib/components/NextEarnings.svelte"; import NextEarnings from "$lib/components/NextEarnings.svelte";
import EarningsSurprise from "$lib/components/EarningsSurprise.svelte"; import EarningsSurprise from "$lib/components/EarningsSurprise.svelte";
@ -370,7 +376,6 @@
low: item?.low !== null ? item?.low : NaN, low: item?.low !== null ? item?.low : NaN,
close: item?.close !== null ? item?.close : NaN, close: item?.close !== null ? item?.close : NaN,
})); }));
displayData = displayData =
oneDayPrice?.length === 0 && sixMonthPrice?.length !== 0 ? "6M" : "1D"; oneDayPrice?.length === 0 && sixMonthPrice?.length !== 0 ? "6M" : "1D";
//lastValue = oneDayPrice[oneDayPrice?.length - 1]?.value; //lastValue = oneDayPrice[oneDayPrice?.length - 1]?.value;
@ -659,6 +664,7 @@
onDestroy(async () => { onDestroy(async () => {
$priceIncrease = null; $priceIncrease = null;
$globalForm = []; $globalForm = [];
shouldUpdatePriceChart.set(false);
}); });
$: dataMapping = { $: dataMapping = {
@ -673,6 +679,7 @@
$: { $: {
if ($stockTicker && typeof window !== "undefined") { if ($stockTicker && typeof window !== "undefined") {
// add a check to see if running on client-side // add a check to see if running on client-side
shouldUpdatePriceChart.set(false);
oneDayPrice = []; oneDayPrice = [];
oneWeekPrice = []; oneWeekPrice = [];
oneMonthPrice = []; oneMonthPrice = [];
@ -751,6 +758,65 @@
}); });
} }
} }
function updateClosePrice(data, extendPriceChart) {
const newDateParsedUTC = Date?.parse(extendPriceChart?.time + "Z") / 1000; // Parse the incoming time
const closePrice = extendPriceChart?.price; // Store the close price for easier reference
let foundMatch = false;
let lastNonNullCloseIndex = null;
// Iterate through data to find the right time slot
for (let i = 0; i < data.length; i++) {
// Check if the timestamp matches
if (data[i].time === newDateParsedUTC) {
data[i].close = closePrice; // Update the existing close price
foundMatch = true;
break; // Exit loop once matched
}
// Keep track of the last non-null close price
if (data[i].close !== null) {
lastNonNullCloseIndex = i;
}
}
// If no matching timestamp was found, add new data
if (!foundMatch) {
// Only update the last non-null close if it exists
if (lastNonNullCloseIndex !== null) {
data[lastNonNullCloseIndex].close = closePrice; // Update with the latest close price
} else {
// If there's no previous close data, add a new entry
data.push({ time: newDateParsedUTC, close: closePrice }); // Add new data
}
}
return data; // Return updated data
}
onMount(() => {
// Subscribe to the store
shouldUpdatePriceChart.subscribe(async (value) => {
if (
value &&
chart !== null &&
$realtimePrice !== null &&
oneDayPrice?.length > 0 &&
$priceChartData?.time !== null &&
$priceChartData?.price !== null
) {
// Create a new array and update oneDayPrice to trigger reactivity
const updatedPrice = updateClosePrice(oneDayPrice, $priceChartData);
oneDayPrice = [...updatedPrice]; // Reassign the updated array to trigger reactivity
try {
chart?.update(oneDayPrice); // Update the chart with the new prices
} catch (e) {
// Handle error if chart update fails
//console.error("Chart update error:", e);
}
shouldUpdatePriceChart.set(false); // Reset the update flag
}
});
});
</script> </script>
<svelte:head> <svelte:head>
@ -1068,11 +1134,12 @@
<Chart <Chart
{...options} {...options}
autoSize={true} autoSize={true}
ref={(ref) => (chart = ref)} ref={(api) => (chart = api)}
on:crosshairMove={handleCrosshairMove} on:crosshairMove={handleCrosshairMove}
> >
{#if displayData === "1D"} {#if displayData === "1D"}
<AreaSeries <AreaSeries
reactive={true}
data={oneDayPrice?.map(({ time, close }) => ({ data={oneDayPrice?.map(({ time, close }) => ({
time, time,
value: close, value: close,