update notification page
This commit is contained in:
parent
6ba32d0979
commit
bd92a82458
25
src/routes/api/update-notification/+server.ts
Normal file
25
src/routes/api/update-notification/+server.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { RequestHandler } from "./$types";
|
||||||
|
|
||||||
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||||
|
const data = await request.json();
|
||||||
|
const { pb } = locals;
|
||||||
|
|
||||||
|
const notificationList = data?.unreadList;
|
||||||
|
let output;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const itemsToUpdate = notificationList?.filter((item) => !item.readed);
|
||||||
|
// Perform updates in parallel
|
||||||
|
await Promise.all(
|
||||||
|
itemsToUpdate.map((item) =>
|
||||||
|
pb.collection("notifications").update(item, { readed: "true" }),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
output = "success";
|
||||||
|
} catch (e) {
|
||||||
|
output = "failure";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(output));
|
||||||
|
};
|
||||||
@ -1,22 +1,25 @@
|
|||||||
import { redirect, error } from "@sveltejs/kit";
|
import { redirect, error } from "@sveltejs/kit";
|
||||||
|
|
||||||
export const load = async ({ locals }) => {
|
export const load = async ({ locals }) => {
|
||||||
if (!locals.pb.authStore.isValid) {
|
const { pb, user } = locals;
|
||||||
|
|
||||||
|
if (!pb.authStore.isValid) {
|
||||||
redirect(303, "/login");
|
redirect(303, "/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNotifications() {
|
async function getNotifications() {
|
||||||
const postData = { userId: locals?.user?.id };
|
let output;
|
||||||
|
|
||||||
const response = await fetch(locals?.fastifyURL + "/get-notifications", {
|
try {
|
||||||
method: "POST",
|
output = await pb.collection("notifications")?.getFullList({
|
||||||
headers: {
|
filter: `opUser="${user?.id}" `,
|
||||||
"Content-Type": "application/json",
|
expand: "user,post,comment",
|
||||||
},
|
sort: "-created",
|
||||||
body: JSON.stringify(postData),
|
});
|
||||||
});
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
const output = (await response.json())?.items;
|
output = [];
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,197 +1,215 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
import {getImageURL, formatDate} from '$lib/utils';
|
import { getImageURL, formatDate } from "$lib/utils";
|
||||||
import { goto } from '$app/navigation';
|
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||||
import InfiniteLoading from '$lib/components/InfiniteLoading.svelte';
|
import { goto } from "$app/navigation";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { numberOfUnreadNotification } from "$lib/store";
|
||||||
|
import defaultAvatar from "$lib/images/default_avatar.png";
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
export let data;
|
||||||
import {numberOfUnreadNotification, scrollToComment } from '$lib/store';
|
export let form;
|
||||||
|
|
||||||
export let data;
|
let rawData = data?.getNotifications;
|
||||||
export let form;
|
let notificationList = rawData?.slice(0, 20);
|
||||||
|
|
||||||
let rawData = data?.getNotifications;
|
async function handleScroll() {
|
||||||
let notificationList = rawData?.slice(0,20);
|
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
|
||||||
|
const isBottom = window.innerHeight + window.scrollY >= scrollThreshold;
|
||||||
let isLoaded = false;
|
if (isBottom && notificationList?.length !== rawData?.length) {
|
||||||
|
const nextIndex = notificationList?.length;
|
||||||
|
const filteredNewResults = rawData?.slice(nextIndex, nextIndex + 25);
|
||||||
|
notificationList = [...notificationList, ...filteredNewResults];
|
||||||
|
}
|
||||||
|
|
||||||
async function updateNotifications()
|
|
||||||
{
|
|
||||||
|
|
||||||
let notificationIdList = [];
|
|
||||||
|
|
||||||
for(let i = 0; i < notificationList?.length; i++)
|
|
||||||
{
|
|
||||||
if(notificationList[i]?.readed == false)
|
|
||||||
{
|
|
||||||
notificationIdList?.push(notificationList[i]?.id)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
async function updateNotifications() {
|
||||||
|
let notificationIdList = [];
|
||||||
|
|
||||||
if (notificationIdList.length !== 0)
|
for (let i = 0; i < notificationList?.length; i++) {
|
||||||
{
|
if (notificationList[i]?.readed == false) {
|
||||||
const postData = {'unreadList': notificationIdList, 'path': 'update-notifications'};
|
notificationIdList?.push(notificationList[i]?.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await fetch('/api/fastify-post-data', {
|
if (notificationIdList.length !== 0) {
|
||||||
method: 'POST',
|
const postData = {
|
||||||
headers: {
|
unreadList: notificationIdList,
|
||||||
"Content-Type": "application/json"
|
};
|
||||||
},
|
|
||||||
body: JSON.stringify(postData)
|
|
||||||
|
|
||||||
});
|
await fetch("/api/update-notification", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
$numberOfUnreadNotification = 0;
|
$numberOfUnreadNotification = 0;
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToPost(item) {
|
|
||||||
if (item?.comment && item?.notifyType === 'vote') {
|
|
||||||
$scrollToComment = item?.comment;
|
|
||||||
}
|
}
|
||||||
goto("/community/post/"+item?.post)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function infiniteHandler({ detail: { loaded, complete } })
|
|
||||||
{
|
|
||||||
if (notificationList?.length === rawData?.length) {
|
|
||||||
complete();
|
|
||||||
} else {
|
|
||||||
const nextIndex = notificationList?.length;
|
|
||||||
const newArticles = rawData?.slice(nextIndex, nextIndex + 20);
|
|
||||||
notificationList = [...notificationList, ...newArticles];
|
|
||||||
console.log(notificationList)
|
|
||||||
loaded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
await updateNotifications();
|
await updateNotifications();
|
||||||
isLoaded = true;
|
window.addEventListener("scroll", handleScroll);
|
||||||
|
return () => {
|
||||||
})
|
window.removeEventListener("scroll", handleScroll);
|
||||||
|
};
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title> {$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ''} Notifications · stocknear</title>
|
<title>
|
||||||
<meta charset="utf-8" />
|
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""} Notifications
|
||||||
<meta name="viewport" content="width=device-width" />
|
· stocknear</title
|
||||||
|
>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
|
||||||
<meta name="description" content="Free Stock Analysis">
|
<meta name="description" content="Free Stock Analysis" />
|
||||||
<!-- Other meta tags -->
|
<!-- Other meta tags -->
|
||||||
<meta property="og:title" content="Notifications · stocknear"/>
|
<meta property="og:title" content="Notifications · stocknear" />
|
||||||
<meta property="og:description" content="Free Stock Analysis">
|
<meta property="og:description" content="Free Stock Analysis" />
|
||||||
<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
|
<meta
|
||||||
<meta property="og:type" content="website"/>
|
property="og:image"
|
||||||
<!-- Add more Open Graph meta tags as needed -->
|
content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<!-- Add more Open Graph meta tags as needed -->
|
||||||
|
|
||||||
<!-- Twitter specific meta tags -->
|
<!-- Twitter specific meta tags -->
|
||||||
<meta name="twitter:card" content="summary_large_image"/>
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content="Notifications · stocknear"/>
|
<meta name="twitter:title" content="Notifications · stocknear" />
|
||||||
<meta name="twitter:description" content="Free Stock Analysis">
|
<meta name="twitter:description" content="Free Stock Analysis" />
|
||||||
<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
|
<meta
|
||||||
<!-- Add more Twitter meta tags as needed -->
|
name="twitter:image"
|
||||||
|
content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"
|
||||||
|
/>
|
||||||
|
<!-- Add more Twitter meta tags as needed -->
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<section
|
||||||
|
class="w-full max-w-3xl sm:max-w-screen-2xl overflow-hidden min-h-screen pb-20 pt-5 px-4 lg:px-3"
|
||||||
|
>
|
||||||
|
<div class="text-sm sm:text-[1rem] breadcrumbs">
|
||||||
|
<ul>
|
||||||
|
<li><a href="/" class="text-gray-300">Home</a></li>
|
||||||
|
<li class="text-gray-300">Notifications</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section class="w-full max-w-5xl overflow-hidden m-auto min-h-screen sm:pt-5 sm:pb-40 bg-[#09090B]">
|
<div class="w-full overflow-hidden m-auto mt-5">
|
||||||
|
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="relative flex justify-center items-start overflow-hidden w-full"
|
||||||
|
>
|
||||||
|
<main class="w-full lg:w-3/4 lg:pr-5">
|
||||||
|
<div class="mb-6 border-b-[2px]">
|
||||||
|
<h1 class="mb-1 text-white text-2xl sm:text-3xl font-bold">
|
||||||
|
Notification
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if notificationList?.length !== 0}
|
||||||
|
<div class="flex flex-col items-start w-full text-white">
|
||||||
|
{#each notificationList as item}
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<div
|
||||||
|
class="sm:hover:bg-[#2B2B2B] pb-3 sm:p-3 mb-6 sm:mb-3 text-gray-200 w-full {!item?.readed
|
||||||
|
? 'bg-[#F9AB00] bg-opacity-[0.1]'
|
||||||
|
: ''} "
|
||||||
|
>
|
||||||
|
<div class="flex flex-row items-center w-full">
|
||||||
|
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||||
|
<a
|
||||||
|
href={"/community/user/" + item?.expand?.user?.id}
|
||||||
|
class="avatar w-11 h-11 flex-shrink-0 cursor-pointer mr-4"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style="clip-path: circle(50%);"
|
||||||
|
class="flex-shrink-0 w-11 h-11 rounded-full inline-block"
|
||||||
|
src={item?.expand?.user?.avatar
|
||||||
|
? getImageURL(
|
||||||
|
item?.expand?.user?.collectionId,
|
||||||
|
item?.expand?.user?.id,
|
||||||
|
item?.expand?.user?.avatar,
|
||||||
|
)
|
||||||
|
: defaultAvatar}
|
||||||
|
alt="User avatar"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="text-white text-sm sm:text-[1rem]">
|
||||||
<div class="w-full max-w-3xl m-auto min-h-screen bg-[#09090B] sm:rounded-lg sm:border sm:border-gray-700 overflow-hidden sm:overflow-y-scroll scroller sm:max-h-[1100px] pt-5 sm:pb-10 sm:pt-10 sm:mt-3 sm:mb-8">
|
{#if item?.notifyType === "vote"}
|
||||||
|
<div class="flex flex-col items-start">
|
||||||
<h1 class="pl-5 text-2xl text-white font-semibold mt-2 sm:mt-0">
|
<div>
|
||||||
Notifications
|
<a
|
||||||
</h1>
|
href={"/community/user/" + item?.expand?.user?.id}
|
||||||
|
class="sm:hover:text-white text-blue-400 cursor-pointer"
|
||||||
|
>
|
||||||
<div class="w-full m-auto mb-10 bg-[#09090B] mt-10">
|
{item?.expand?.user?.username}
|
||||||
<div class="flex flex-col sm:flex-row items-center w-full">
|
</a>
|
||||||
|
<span class="text-white text-sm sm:text-[1rem]">
|
||||||
|
upvoted your {item?.comment ? "comment" : "post"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
{#if isLoaded }
|
<span class="text-sm sm:text-[1rem] text-[#A6ADBB0"
|
||||||
|
>{formatDate(item?.created)} ago</span
|
||||||
{#if notificationList?.length !== 0}
|
>
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
|
||||||
<div class="flex flex-col items-start w-full text-white">
|
|
||||||
{#each notificationList as item}
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<div on:click={()=> goToPost(item)} class="hover:bg-[#2B2B2B] p-3 mb-3 ml-1 text-gray-200 w-full {!item?.readed ? 'bg-[#F9AB00] bg-opacity-[0.1]' : ''} cursor-pointer">
|
|
||||||
<div class="flex flex-row items-center w-full">
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
|
||||||
<label on:click|stopPropagation={()=> goto("/community/user/"+item?.expand?.user?.id)} class="avatar w-8 h-8 sm:w-11 sm:h-11 flex-shrink-0 cursor-pointer mr-4">
|
|
||||||
<img style="clip-path: circle(50%);" class="flex-shrink-0 w-8 h-8 sm:w-11 sm:h-11 rounded-full inline-block"
|
|
||||||
src={item?.expand?.user?.avatar
|
|
||||||
? getImageURL(item?.expand?.user?.collectionId, item?.expand?.user?.id, item?.expand?.user?.avatar)
|
|
||||||
: `https://avatar.vercel.sh/${item?.expand?.user?.username}`}
|
|
||||||
alt="User avatar"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="text-white text-sm sm:text-[1rem]">
|
|
||||||
{#if item?.notifyType === 'vote'}
|
|
||||||
<div class="flex flex-col items-start">
|
|
||||||
<div>
|
|
||||||
<label on:click|stopPropagation={()=> goto("/community/user/"+item?.expand?.user?.id)} class="text-blue-400 cursor-pointer">
|
|
||||||
{item?.expand?.user?.username}
|
|
||||||
</label>
|
|
||||||
<span class="text-white text-xs sm:text-sm">
|
|
||||||
upvoted your {item?.comment ? 'comment' : 'post'}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="text-xs sm:text-sm text-[#A6ADBB0">{formatDate(item?.created)} ago</span>
|
|
||||||
</div>
|
|
||||||
{:else if item?.notifyType === 'priceAlert'}
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
|
||||||
<div class="flex flex-col items-start">
|
|
||||||
<div>
|
|
||||||
<label on:click|stopPropagation={()=> goto(`/${item?.liveResults?.assetType === 'stock' ? 'stocks' : 'etf'}/${item?.liveResults?.symbol}`)} class="flex flex-col items-start cursor-pointer">
|
|
||||||
<div class="text-md mt-0.5">
|
|
||||||
Price Alert triggered for <span class="text-blue-400">${item?.liveResults?.symbol}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-md mt-0.5">
|
{:else if item?.notifyType === "priceAlert"}
|
||||||
The price of <span class="font-bold">${item?.liveResults?.currentPrice}</span> is {item?.liveResults?.condition} your target of <span class="font-bold">${item?.liveResults?.targetPrice}</span>
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||||
|
<div class="flex flex-col items-start">
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href={`/${item?.liveResults?.assetType === "stock" ? "stocks" : "etf"}/${item?.liveResults?.symbol}`}
|
||||||
|
class="flex flex-col items-start cursor-pointer"
|
||||||
|
>
|
||||||
|
<div class="text-md mt-0.5">
|
||||||
|
Price Alert triggered for <span
|
||||||
|
class="sm:hover:text-white text-blue-400"
|
||||||
|
>${item?.liveResults?.symbol}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-md mt-0.5">
|
||||||
|
The price of <span class="font-bold"
|
||||||
|
>${item?.liveResults?.currentPrice}</span
|
||||||
|
>
|
||||||
|
is {item?.liveResults?.condition} your target of
|
||||||
|
<span class="font-bold"
|
||||||
|
>${item?.liveResults?.targetPrice}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm sm:text-[1rem] text-[#A6ADBB0"
|
||||||
|
>{formatDate(item?.created)} ago</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
{:else if item?.notifyType === "comment"}
|
||||||
|
<div class="flex flex-col items-start">
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href={"/community/user/" + item?.expand?.user?.id}
|
||||||
|
class="sm:hover:text-white text-blue-400 cursor-pointer"
|
||||||
|
>
|
||||||
|
{item?.expand?.user?.username}
|
||||||
|
</a>
|
||||||
|
<span class="text-white text-sm sm:text-[1rem]">
|
||||||
|
commented on your post:
|
||||||
|
</span>
|
||||||
|
{@html item?.expand?.comment?.comment?.length > 30
|
||||||
|
? item?.expand?.comment?.comment?.slice(0, 30) +
|
||||||
|
"..."
|
||||||
|
: item?.expand?.comment?.comment}
|
||||||
|
</div>
|
||||||
|
<span class="text-sm sm:text-[1rem] text-[#A6ADBB0"
|
||||||
|
>{formatDate(item?.created)} ago</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<span class="text-xs sm:text-sm text-[#A6ADBB0">{formatDate(item?.created)} ago</span>
|
<!--
|
||||||
</div>
|
|
||||||
|
|
||||||
{:else if item?.notifyType === 'comment'}
|
|
||||||
<div class="flex flex-col items-start">
|
|
||||||
<div>
|
|
||||||
<label on:click={() => goto("/community/user/"+item?.expand?.user?.id)} class="text-blue-400 hover:underline cursor-pointer">
|
|
||||||
{item?.expand?.user?.username}
|
|
||||||
</label>
|
|
||||||
<span class="text-white text-xs sm:text-sm">
|
|
||||||
commented on your post:
|
|
||||||
</span>
|
|
||||||
{@html item?.expand?.comment?.comment?.length > 30 ? item?.expand?.comment?.comment?.slice(0, 30) + "..." : item?.expand?.comment?.comment}
|
|
||||||
</div>
|
|
||||||
<span class="text-xs sm:text-sm text-[#A6ADBB0">{formatDate(item?.created)} ago</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<!--
|
|
||||||
{#if item?.expand?.post?.thumbnail}
|
{#if item?.expand?.post?.thumbnail}
|
||||||
<img
|
<img
|
||||||
src="{getImageURL(item?.expand?.post?.collectionId, item?.expand?.post?.id, item?.expand?.post?.thumbnail)}"
|
src="{getImageURL(item?.expand?.post?.collectionId, item?.expand?.post?.id, item?.expand?.post?.thumbnail)}"
|
||||||
@ -200,49 +218,89 @@ onMount(async () => {
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
-->
|
-->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{:else}
|
||||||
|
<div
|
||||||
|
class="mt-5 text-white font-semibold text-[1rem] justify-center items-center m-auto"
|
||||||
|
>
|
||||||
|
Empty just like our souls...
|
||||||
|
<svg
|
||||||
|
class="inline-block w-4 h-4 m-auto mb-2"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1200 1200"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M567.663 0v190.423h64.679V0h-64.685h.006zm-264.11 57.225l-52.992 37.103l109.203 155.946l52.963-37.104L303.553 57.225zm592.886 0L787.268 213.171l52.971 37.104L949.44 94.328l-52.992-37.103h-.009zm-296.45 185.299c-158.227 0-286.493 96.083-286.493 214.625l162.772 492.948h247.47l162.758-492.948c0-118.54-128.258-214.625-286.492-214.625h-.015zM85.465 299.673l-22.099 60.814l178.849 65.114l22.181-60.785l-178.935-65.143h.004zm1029.062 0l-178.936 65.148l22.106 60.792l178.936-65.125l-22.106-60.815zM255.756 577.681l-183.9 49.326l16.686 62.431l183.9-49.255l-16.683-62.502h-.003zm688.48 0l-16.674 62.501l183.9 49.247l16.674-62.432l-183.9-49.318v.002zM472.66 986.032v85.686h254.687v-85.673H472.661l-.001-.013zm0 128.282V1200h254.687v-85.672H472.661l-.001-.014z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</main>
|
||||||
|
|
||||||
</div>
|
<aside class="hidden lg:block relative fixed w-1/4 ml-4">
|
||||||
|
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial}
|
||||||
|
<div
|
||||||
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/pricing"
|
||||||
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
|
>
|
||||||
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
|
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
||||||
|
Pro Subscription
|
||||||
|
</h2>
|
||||||
|
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
|
Upgrade now for unlimited access to all data and tools.
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
<InfiniteLoading on:infinite={infiniteHandler} />
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
|
>
|
||||||
|
<a
|
||||||
{:else}
|
href="cramer-tracker"
|
||||||
<div class="text-white font-semibold text-lg justify-center items-center m-auto">
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
Empty just like our souls...
|
>
|
||||||
<svg class="inline-block w-4 h-4 m-auto mb-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200"><path fill="white" d="M567.663 0v190.423h64.679V0h-64.685h.006zm-264.11 57.225l-52.992 37.103l109.203 155.946l52.963-37.104L303.553 57.225zm592.886 0L787.268 213.171l52.971 37.104L949.44 94.328l-52.992-37.103h-.009zm-296.45 185.299c-158.227 0-286.493 96.083-286.493 214.625l162.772 492.948h247.47l162.758-492.948c0-118.54-128.258-214.625-286.492-214.625h-.015zM85.465 299.673l-22.099 60.814l178.849 65.114l22.181-60.785l-178.935-65.143h.004zm1029.062 0l-178.936 65.148l22.106 60.792l178.936-65.125l-22.106-60.815zM255.756 577.681l-183.9 49.326l16.686 62.431l183.9-49.255l-16.683-62.502h-.003zm688.48 0l-16.674 62.501l183.9 49.247l16.674-62.432l-183.9-49.318v.002zM472.66 986.032v85.686h254.687v-85.673H472.661l-.001-.013zm0 128.282V1200h254.687v-85.672H472.661l-.001-.014z"/></svg>
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
</div>
|
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
||||||
{/if}
|
Cramer Tracker
|
||||||
|
</h2>
|
||||||
|
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
|
Follow Jim Cramer latest stock picks
|
||||||
{:else}
|
</span>
|
||||||
<div class="flex justify-center items-center h-80">
|
</a>
|
||||||
<div class="relative">
|
|
||||||
<label class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
|
||||||
<span class="loading loading-spinner loading-md text-gray-400"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/reddit-tracker"
|
||||||
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
|
>
|
||||||
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
|
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
||||||
|
Reddit Tracker
|
||||||
|
</h2>
|
||||||
|
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
|
Get the latest trends of r/Wallstreetbets
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
.scroller {
|
|
||||||
scrollbar-width: thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -10,9 +10,8 @@
|
|||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
let isLoaded = false;
|
let rawData = data?.getSentimentTracker ?? [];
|
||||||
let rawData = [];
|
let stockList = rawData?.slice(0, 50) ?? [];
|
||||||
let stockList = [];
|
|
||||||
|
|
||||||
async function handleScroll() {
|
async function handleScroll() {
|
||||||
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
|
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
|
||||||
@ -25,11 +24,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
rawData = data?.getSentimentTracker ?? [];
|
|
||||||
stockList = rawData?.slice(0, 50) ?? [];
|
|
||||||
|
|
||||||
isLoaded = true;
|
|
||||||
|
|
||||||
if (data?.user?.tier === "Pro") {
|
if (data?.user?.tier === "Pro") {
|
||||||
window.addEventListener("scroll", handleScroll);
|
window.addEventListener("scroll", handleScroll);
|
||||||
return () => {
|
return () => {
|
||||||
@ -171,139 +165,126 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isLoaded}
|
<div
|
||||||
<div
|
class="mb-8 w-full text-center sm:text-start sm:flex sm:flex-row sm:items-center m-auto text-gray-100 border border-gray-800 sm:rounded-lg h-auto p-5"
|
||||||
class="mb-8 w-full text-center sm:text-start sm:flex sm:flex-row sm:items-center m-auto text-gray-100 border border-gray-800 sm:rounded-lg h-auto p-5"
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 inline-block sm:mr-2 flex-shrink-0"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 256 256"
|
||||||
|
><path
|
||||||
|
fill="#FBCE3C"
|
||||||
|
d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"
|
||||||
|
/></svg
|
||||||
>
|
>
|
||||||
<svg
|
We update our data in realtime to provide you with the latest trends
|
||||||
class="w-5 h-5 inline-block sm:mr-2 flex-shrink-0"
|
and the most bullish stocks being discussed on Twitter and StockTwits
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
</div>
|
||||||
viewBox="0 0 256 256"
|
|
||||||
><path
|
|
||||||
fill="#FBCE3C"
|
|
||||||
d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
We update our data in realtime to provide you with the latest trends
|
|
||||||
and the most bullish stocks being discussed on Twitter and StockTwits
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-screen sm:w-full m-auto mt-20 sm:mt-10">
|
<div class="w-screen sm:w-full m-auto mt-20 sm:mt-10">
|
||||||
<div
|
<div
|
||||||
class="w-screen sm:w-full m-auto rounded-none sm:rounded-lg mb-4 overflow-x-scroll sm:overflow-hidden"
|
class="w-screen sm:w-full m-auto rounded-none sm:rounded-lg mb-4 overflow-x-scroll sm:overflow-hidden"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
class="table table-sm table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B] m-auto"
|
||||||
>
|
>
|
||||||
<table
|
<thead>
|
||||||
class="table table-sm table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B] m-auto"
|
<TableHeader {columns} {sortOrders} {sortData} />
|
||||||
>
|
</thead>
|
||||||
<thead>
|
<tbody>
|
||||||
<TableHeader {columns} {sortOrders} {sortData} />
|
{#each stockList as item, index}
|
||||||
</thead>
|
<tr
|
||||||
<tbody>
|
class="sm:hover:bg-[#245073] border-b border-[#27272A] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] {index +
|
||||||
{#each stockList as item, index}
|
1 ===
|
||||||
<tr
|
stockList?.length && data?.user?.tier !== 'Pro'
|
||||||
class="sm:hover:bg-[#245073] border-b border-[#27272A] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] {index +
|
? 'opacity-[0.1]'
|
||||||
1 ===
|
: ''}"
|
||||||
stockList?.length && data?.user?.tier !== 'Pro'
|
>
|
||||||
? 'opacity-[0.1]'
|
<td
|
||||||
: ''}"
|
class="text-white text-sm sm:text-[1rem] font-medium text-white text-end"
|
||||||
>
|
>
|
||||||
<td
|
{item?.rank}
|
||||||
class="text-white text-sm sm:text-[1rem] font-medium text-white text-end"
|
</td>
|
||||||
>
|
|
||||||
{item?.rank}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="text-sm sm:text-[1rem] text-start">
|
<td class="text-sm sm:text-[1rem] text-start">
|
||||||
<HoverStockChart symbol={item?.symbol} />
|
<HoverStockChart symbol={item?.symbol} />
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td
|
<td
|
||||||
class="whitespace-nowrap text-white text-sm sm:text-[1rem] text-white text-start"
|
class="whitespace-nowrap text-white text-sm sm:text-[1rem] text-white text-start"
|
||||||
>
|
>
|
||||||
{item?.name?.length > charNumber
|
{item?.name?.length > charNumber
|
||||||
? item?.name?.slice(0, charNumber) + "..."
|
? item?.name?.slice(0, charNumber) + "..."
|
||||||
: item?.name}
|
: item?.name}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td
|
<td
|
||||||
class="text-end text-sm sm:text-[1rem] font-medium text-white whitespace-nowrap"
|
class="text-end text-sm sm:text-[1rem] font-medium text-white whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{abbreviateNumber(item?.marketCap)}
|
{abbreviateNumber(item?.marketCap)}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td
|
<td
|
||||||
class="text-end text-sm sm:text-[1rem] whitespace-nowrap font-medium text-white"
|
class="text-end text-sm sm:text-[1rem] whitespace-nowrap font-medium text-white"
|
||||||
>
|
>
|
||||||
{item?.price}
|
{item?.price}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td
|
<td
|
||||||
class="text-sm sm:text-[1rem] whitespace-nowrap {item?.changesPercentage >=
|
class="text-sm sm:text-[1rem] whitespace-nowrap {item?.changesPercentage >=
|
||||||
0
|
0
|
||||||
? 'text-[#00FC50]'
|
? 'text-[#00FC50]'
|
||||||
: 'text-[#FF2F1F]'} text-end"
|
: 'text-[#FF2F1F]'} text-end"
|
||||||
>
|
>
|
||||||
{item?.changesPercentage > 0
|
{item?.changesPercentage > 0
|
||||||
? "+"
|
? "+"
|
||||||
: ""}{item?.changesPercentage}%
|
: ""}{item?.changesPercentage}%
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td
|
<td
|
||||||
class="text-end text-sm sm:text-[1rem] font-medium whitespace-nowrap {item?.sentiment >=
|
class="text-end text-sm sm:text-[1rem] font-medium whitespace-nowrap {item?.sentiment >=
|
||||||
55
|
55
|
||||||
? 'text-[#00FC50]'
|
? 'text-[#00FC50]'
|
||||||
: item?.sentiment >= 50
|
: item?.sentiment >= 50
|
||||||
? 'text-[#E57C34]'
|
? 'text-[#E57C34]'
|
||||||
: 'text-[#FF2F1F]'}"
|
: 'text-[#FF2F1F]'}"
|
||||||
>
|
>
|
||||||
<div class="flex flex-row items-center justify-end">
|
<div class="flex flex-row items-center justify-end">
|
||||||
<div class="">
|
<div class="">
|
||||||
{item?.sentiment >= 80
|
{item?.sentiment >= 80
|
||||||
? "Very Bullish"
|
? "Very Bullish"
|
||||||
: item?.sentiment >= 55
|
: item?.sentiment >= 55
|
||||||
? "Bullish"
|
? "Bullish"
|
||||||
: item?.sentiment > 50
|
: item?.sentiment > 50
|
||||||
? "Mixed"
|
? "Mixed"
|
||||||
: "Bearish"}
|
: "Bearish"}
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="ml-2 px-1.5 py-1.5 border text-center rounded-lg text-xs font-semibold"
|
|
||||||
>
|
|
||||||
{item?.sentiment}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
<div
|
||||||
</tr>
|
class="ml-2 px-1.5 py-1.5 border text-center rounded-lg text-xs font-semibold"
|
||||||
{/each}
|
>
|
||||||
</tbody>
|
{item?.sentiment}
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<UpgradeToPro
|
</td>
|
||||||
{data}
|
</tr>
|
||||||
title="Get the latest stock trends from social media to never miss out the next hype"
|
{/each}
|
||||||
/>
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
<UpgradeToPro
|
||||||
<div class="flex justify-center items-center h-80">
|
{data}
|
||||||
<div class="relative">
|
title="Get the latest stock trends from social media to never miss out the next hype"
|
||||||
<label
|
/>
|
||||||
class="bg-[#09090B] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
</div>
|
||||||
>
|
|
||||||
<span class="loading loading-spinner loading-md text-gray-400"
|
|
||||||
></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<aside class="hidden lg:block relative fixed w-1/4 ml-4">
|
<aside class="hidden lg:block relative fixed w-1/4 ml-4">
|
||||||
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial}
|
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial}
|
||||||
<div
|
<div
|
||||||
on:click={() => goto("/pricing")}
|
|
||||||
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div
|
<a
|
||||||
|
href="/pricing"
|
||||||
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
>
|
>
|
||||||
<div class="w-full flex justify-between items-center p-3 mt-3">
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
@ -315,15 +296,17 @@
|
|||||||
<span class="text-white p-3 ml-3 mr-3">
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
Upgrade now for unlimited access to all data and tools.
|
Upgrade now for unlimited access to all data and tools.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
on:click={() => goto("/cramer-tracker")}
|
|
||||||
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0">
|
<a
|
||||||
|
href="cramer-tracker"
|
||||||
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
|
>
|
||||||
<div class="w-full flex justify-between items-center p-3 mt-3">
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
||||||
Cramer Tracker
|
Cramer Tracker
|
||||||
@ -333,14 +316,16 @@
|
|||||||
<span class="text-white p-3 ml-3 mr-3">
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
Follow Jim Cramer latest stock picks
|
Follow Jim Cramer latest stock picks
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
on:click={() => goto("/reddit-tracker")}
|
|
||||||
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0">
|
<a
|
||||||
|
href="/reddit-tracker"
|
||||||
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
|
>
|
||||||
<div class="w-full flex justify-between items-center p-3 mt-3">
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
<h2 class="text-start text-xl font-semibold text-white ml-3">
|
||||||
Reddit Tracker
|
Reddit Tracker
|
||||||
@ -350,7 +335,7 @@
|
|||||||
<span class="text-white p-3 ml-3 mr-3">
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
Get the latest trends of r/Wallstreetbets
|
Get the latest trends of r/Wallstreetbets
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user