update ipo

This commit is contained in:
MuslemRahimi 2025-01-18 11:55:16 +01:00
parent 533bd5b455
commit 815fb7c821
4 changed files with 213 additions and 364 deletions

View File

@ -0,0 +1,25 @@
export const load = async ({ locals }) => {
const { apiKey, apiURL} = locals;
const getNews = async () => {
const postData = { newsType: "ipo-news" };
// make the POST request to the endpoint
const response = await fetch(apiURL + "/market-news", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": apiKey,
},
body: JSON.stringify(postData),
});
const output = await response.json();
return output;
};
// Make sure to return a promise
return {
getNews: await getNews(),
};
};

View File

@ -1,35 +1,25 @@
<script lang="ts"> <script lang="ts">
import { page } from "$app/stores"; import { page } from "$app/stores";
import { numberOfUnreadNotification, screenWidth } from "$lib/store"; import { numberOfUnreadNotification } from "$lib/store";
import ArrowLogo from "lucide-svelte/icons/move-up-right"; import ArrowLogo from "lucide-svelte/icons/move-up-right";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
import SEO from "$lib/components/SEO.svelte";
export let data; export let data;
let navigation = []; let navigation = [];
let displaySection = "2024"; let displaySection = "2025";
let ipoNews = data?.getNews?.slice(0, 10);
for (let year = 2024; year >= 2019; year--) { for (let year = 2025; year >= 2019; year--) {
navigation.push({ title: year, link: `/ipos/${year}` }); navigation?.push({ title: year, link: `/ipos/${year}` });
}
function scrollToItem(itemId) {
const item = document.getElementById(itemId);
if (item) {
item.scrollIntoView({ behavior: "smooth" });
window.scrollTo(0, 0);
}
}
function changeSection(state, item) {
scrollToItem(item);
displaySection = state;
} }
$: { $: {
if ($page.url.pathname) { if ($page.url.pathname) {
const parts = $page?.url?.pathname?.split("/"); const parts = $page?.url?.pathname?.split("/");
const sectionMap = { const sectionMap = {
"2025": "2025",
"2024": "2024", "2024": "2024",
"2023": "2023", "2023": "2023",
"2022": "2022", "2022": "2022",
@ -46,44 +36,11 @@
</script> </script>
<!-- HEADER FOR BETTER SEO --> <!-- HEADER FOR BETTER SEO -->
<svelte:head> <SEO
<title> title="IPOs
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""} IPOs Calendar"
Calendar · Stocknear</title description="A list of upcoming ipos on the US stock market."
> />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta
name="description"
content="A list of upcoming ipos on the US stock market."
/>
<!-- Other meta tags -->
<meta property="og:title" content="IPOs Calendar · Stocknear" />
<meta
property="og:description"
content="A list of upcoming ipos on the US stock market."
/>
<meta
property="og:image"
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 -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="IPOs Calendar · Stocknear" />
<meta
name="twitter:description"
content="A list of upcoming ipos on the US stock market."
/>
<meta
name="twitter:image"
content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"
/>
<!-- Add more Twitter meta tags as needed -->
</svelte:head>
<section <section
class="w-full max-w-3xl sm:max-w-[1400px] overflow-hidden min-h-screen pt-5 px-4 lg:px-3 mb-20" class="w-full max-w-3xl sm:max-w-[1400px] overflow-hidden min-h-screen pt-5 px-4 lg:px-3 mb-20"
@ -91,7 +48,7 @@
<div class="text-sm breadcrumbs"> <div class="text-sm breadcrumbs">
<ul> <ul>
<li><a href="/" class="text-gray-300">Home</a></li> <li><a href="/" class="text-gray-300">Home</a></li>
<li class="text-gray-300">IPO Calendar</li> <li class="text-gray-300">Recent IPOs</li>
</ul> </ul>
</div> </div>
@ -100,10 +57,10 @@
<div <div
class="relative flex justify-center items-start overflow-hidden w-full" class="relative flex justify-center items-start overflow-hidden w-full"
> >
<main class="w-full lg:w-3/4 lg:pr-5"> <main class="w-full lg:w-3/4 lg:pr-10">
<div class="mb-5"> <div class="mb-5">
<h1 class="mb-1 text-white text-2xl sm:text-3xl font-bold"> <h1 class="mb-1 text-white text-2xl sm:text-3xl font-bold">
IPO Calendar Recent IPOs
</h1> </h1>
</div> </div>
@ -116,7 +73,32 @@
<ul <ul
class="flex flex-row items-center w-full text-[1rem] sm:text-lg text-white" class="flex flex-row items-center w-full text-[1rem] sm:text-lg text-white"
> >
{#each ["2024", "2023", "2022", "2021", "2020", "2019"] as item} <a
href={`/ipos`}
on:click={() => (displaySection = "recent")}
class="p-2 px-5 cursor-pointer {displaySection === 'recent'
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
>
Recent
</a>
<a
href={`/ipos/news`}
on:click={() => (displaySection = "news")}
class="p-2 px-5 cursor-pointer {displaySection === 'news'
? 'text-white bg-primary sm:hover:bg-opacity-[0.95]'
: 'text-gray-400 sm:hover:text-white sm:hover:bg-primary sm:hover:bg-opacity-[0.95]'}"
>
News
</a>
</ul>
</nav>
<nav class=" overflow-x-scroll whitespace-nowrap">
<ul
class="flex flex-row items-center w-full text-[1rem] text-white"
>
{#each ["2025", "2024", "2023", "2022", "2021", "2020", "2019"] as item}
<a <a
href={`/ipos/${item}`} href={`/ipos/${item}`}
on:click={() => (displaySection = item)} on:click={() => (displaySection = item)}
@ -134,61 +116,30 @@
<slot /> <slot />
</main> </main>
<aside class="hidden lg:block relative fixed w-1/4 ml-4"> <aside class="hidden lg:block relative fixed w-1/4">
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial} {#if ipoNews?.length !== 0}
<div <div
on:click={() => goto("/pricing")} class="w-full sm:hover:text-white text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-inherit"
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-inherit sm:hover:bg-secondary transition ease-out duration-100"
> >
<div <div class="p-4 text-sm">
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0" <h3 class="text-xl text-white font-bold mb-3">IPO News</h3>
> <ul class="text-white">
<div class="w-full flex justify-between items-center p-3 mt-3"> {#each ipoNews?.slice(0, 10) as item}
<h2 class="text-start text-xl font-semibold text-white ml-3"> <li class="mb-3 last:mb-1">
Pro Subscription {item?.timestamp}
</h2> <br />
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" /> <a
</div> class="sm:hover:text-white text-blue-400"
<span class="text-white p-3 ml-3 mr-3"> href={item?.link}
Upgrade now for unlimited access to all data and tools. target="_blank"
</span> rel="noopener noreferrer nofollow">{item?.title}</a
>
</li>
{/each}
</ul>
</div> </div>
</div> </div>
{/if} {/if}
<div
on:click={() => goto("/analysts")}
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-inherit sm:hover:bg-secondary transition ease-out duration-100"
>
<div 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">
Wallstreet Analyst
</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 top Wall Street analyst ratings.
</span>
</div>
</div>
<div
on:click={() => goto("/politicians")}
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-inherit sm:hover:bg-secondary transition ease-out duration-100"
>
<div 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">
Congress Trading
</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 top Congress trading insights.
</span>
</div>
</div>
</aside> </aside>
</div> </div>
</div> </div>

View File

@ -1,13 +1,13 @@
<script lang="ts"> <script lang="ts">
import { goto } from "$app/navigation";
import { formatString, abbreviateNumber } from "$lib/utils"; import { formatString, abbreviateNumber } from "$lib/utils";
import { screenWidth } from "$lib/store"; import { screenWidth } from "$lib/store";
import { onMount } from "svelte"; import { onMount } from "svelte";
export let data; export let data;
let rawData; let rawData = data?.getIPOCalendar;
let ipoList; let ipoList = rawData?.slice(0, 150);
let isLoaded = false; let isLoaded = false;
async function handleScroll() { async function handleScroll() {
@ -21,10 +21,8 @@
} }
onMount(() => { onMount(() => {
rawData = data?.getIPOCalendar;
ipoList = rawData?.slice(0, 50);
isLoaded = true;
window.addEventListener("scroll", handleScroll); window.addEventListener("scroll", handleScroll);
return () => { return () => {
@ -43,22 +41,7 @@
</script> </script>
<section class="w-full overflow-hidden m-auto"> <section class="w-full overflow-hidden m-auto">
{#if isLoaded}
<div class="flex flex-col justify-center items-center p-3 sm:p-0">
<div
class="mt-0 sm:mt-5 mb-2 w-full sm:flex sm:flex-row sm:items-center m-auto text-gray-100 font-medium border border-gray-800 sm:rounded-md 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="#fff"
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
>
All {rawData?.length} IPOs on the US stock market in between 2019 - 2024.
</div>
<div class="w-full overflow-x-scroll"> <div class="w-full overflow-x-scroll">
<table <table
@ -152,15 +135,5 @@
</table> </table>
</div> </div>
</div> </div>
{:else}
<div class="flex justify-center items-center h-80">
<div class="relative">
<label
class="bg-secondary rounded-md 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>
{/if}
</section> </section>

View File

@ -1,77 +1,38 @@
<script lang="ts"> <script lang="ts">
import { formatString, abbreviateNumber } from "$lib/utils"; import { formatString, abbreviateNumber } from "$lib/utils";
import { screenWidth } from "$lib/store"; import { screenWidth } from "$lib/store";
import { page } from "$app/stores";
import { onMount } from "svelte";
import Infobox from "$lib/components/Infobox.svelte"; import Infobox from "$lib/components/Infobox.svelte";
import InfiniteLoading from "$lib/components/InfiniteLoading.svelte";
export let data; export let data;
let rawData; let rawData = data?.getIPOCalendar;
let totalIPOs = 0; let ipoList = rawData?.slice(0, 150);
let ipoList; let year = data?.getYear;
let year;
let isLoaded = false;
let displayMonth = "all";
async function infiniteHandler({ detail: { loaded, complete } }) { async function handleScroll() {
if (ipoList?.length === rawData?.length) { const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
complete(); const isBottom = window.innerHeight + window.scrollY >= scrollThreshold;
} else { if (isBottom && ipoList?.length !== rawData?.length) {
const nextIndex = ipoList?.length; const nextIndex = ipoList?.length;
const newHoldings = rawData?.slice(nextIndex, nextIndex + 50); const filteredNewResults = rawData?.slice(nextIndex, nextIndex + 50);
ipoList = [...ipoList, ...newHoldings]; ipoList = [...ipoList, ...filteredNewResults];
loaded();
} }
} }
const monthMap = { onMount(() => {
jan: "01", window.addEventListener("scroll", handleScroll);
feb: "02", return () => {
march: "03", window.removeEventListener("scroll", handleScroll);
april: "04", };
may: "05", });
june: "06",
july: "07",
aug: "08",
sept: "09",
oct: "10",
nov: "11",
dec: "12",
};
async function changeTimePeriod(event) {
isLoaded = false;
displayMonth = event.target.value;
const monthValue = monthMap[displayMonth];
if (displayMonth !== "all") {
rawData = data?.getIPOCalendar?.filter((item) =>
item?.date?.includes(`-${monthValue}-`),
);
} else {
rawData = data?.getIPOCalendar;
}
ipoList = rawData?.slice(0, 50);
isLoaded = true;
}
$: { $: {
if (typeof window !== "undefined") { if ($page?.url?.pathname) {
const monthValue = monthMap[displayMonth]; rawData = data?.getIPOCalendar;
if (displayMonth !== "all") { ipoList = rawData?.slice(0, 150);
rawData = data?.getIPOCalendar?.filter((item) =>
item?.date?.includes(`-${monthValue}-`),
);
} else {
rawData = data?.getIPOCalendar;
}
totalIPOs = data?.getIPOCalendar?.length;
ipoList = rawData?.slice(0, 50);
year = data?.getYear; year = data?.getYear;
isLoaded = true;
} }
} }
@ -79,175 +40,114 @@
</script> </script>
<section class="w-full overflow-hidden m-auto"> <section class="w-full overflow-hidden m-auto">
{#if isLoaded} <div class="flex flex-col justify-center items-center">
<div class="mt-3 mb-3"> {#if rawData?.length !== 0}
<Infobox <h2 class="text-white text-xl font- text-start mt-5 w-full font-semibold">
text={`There have been ${totalIPOs} IPOs on the US stock market in ${year}.`} {rawData?.length} IPOs
/> </h2>
</div> <div class="w-full overflow-x-scroll">
<div class="flex flex-col justify-center items-center"> <table
<div class="mr-auto flex flex-col jusitfy-start items-start mb-5 mt-5"> class="mt-5 table table-sm table-compact rounded-none sm:rounded-md w-full bg-table border border-gray-800 m-auto overflow-hidden"
<div class="text-white text-sm sm:text-[1rem] font-medium mr-2">
Select Time period
</div>
<div class="relative mt-4">
<select
class="select text-white select-bordered select-sm w-36 p-0 pl-5 overflow-y-auto bg-secondary"
on:change={changeTimePeriod}
>
<option disabled>Select time period</option>
<option value="all" selected>All</option>
<option value="jan">January</option>
<option value="feb">February</option>
<option value="march">March</option>
<option value="april">April</option>
<option value="may">May</option>
<option value="june">June</option>
<option value="july">July</option>
<option value="aug">August</option>
<option value="sept">September</option>
<option value="oct">October</option>
<option value="nov">November</option>
<option value="dec">December</option>
</select>
</div>
</div>
{#if rawData?.length !== 0}
<h2
class="text-white text-xl font- text-start mt-5 w-full font-semibold"
> >
{rawData?.length} IPOs <thead class="bg-default">
</h2> <tr>
<div class="w-full overflow-x-scroll"> <th class="text-white font-semibold text-sm text-start"
<table >IPO Date</th
class="mt-5 table table-sm table-compact rounded-none sm:rounded-md w-full bg-table border border-gray-800 m-auto overflow-hidden" >
> <th class="text-white font-semibold text-sm text-start">Symbol</th
<thead class="bg-default"> >
<tr> <th class="text-white font-semibold text-sm">Name</th>
<th class="text-white font-semibold text-sm text-start" <th class="text-white font-semibold text-end text-sm"
>IPO Date</th >IPO Price</th
>
<th class="text-white font-semibold text-end text-sm"
>Current Price</th
>
<th class="text-white font-semibold text-end text-sm"
>Return Since</th
>
</tr>
</thead>
<tbody>
{#each ipoList as item}
<tr
class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-odd border-b-[#09090B]"
>
<td
class="text-white text-sm sm:text-[1rem] whitespace-nowrap text-start border-b-[#09090B] whitespace-nowrap"
> >
<th class="text-white font-semibold text-sm text-start" {new Date(item?.date)?.toLocaleString("en-US", {
>Symbol</th month: "short",
day: "numeric",
year: "numeric",
daySuffix: "2-digit",
})}
</td>
<td
class="text-sm sm:text-[1rem] whitespace-nowrap text-start border-b-[#09090B] whitespace-nowrap"
> >
<th class="text-white font-semibold text-sm">Name</th> <a
<th class="text-white font-semibold text-end text-sm" href={"/stocks/" + item?.symbol}
>IPO Price</th class="sm:hover:text-white text-blue-400"
>
{item?.symbol}
</a>
</td>
<td
class="text-gray-200 border-b-[#09090B] whitespace-nowrap text-sm sm:text-[1rem]"
> >
<th class="text-white font-semibold text-end text-sm" <span class="text-white"
>Current Price</th >{item?.name?.length > charNumber
? formatString(item?.name?.slice(0, charNumber)) + "..."
: formatString(item?.name)}</span
>
</td>
<td
class="text-white text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B] text-end"
> >
<th class="text-white font-semibold text-end text-sm" {item?.ipoPrice !== null ? item?.ipoPrice : "-"}
>Return Since</th </td>
<td
class="text-white border-b-[#09090B] text-sm sm:text-[1rem] text-end"
> >
{item?.currentPrice !== null ? item?.currentPrice : "-"}
</td>
<td
class="text-white border-b-[#09090B] text-end flex flex-row items-center justify-end"
>
{#if item?.return >= 0 && item?.return !== null}
<span
class="inline-block text-[#00FC50] text-sm sm:text-[1rem] whitespace-nowrap"
>+{abbreviateNumber(item?.return)}%</span
>
{:else if item?.return < 0 && item?.return !== null}
<span
class="inline-block text-[#FF2F1F] text-sm sm:text-[1rem] whitespace-nowrap"
>{abbreviateNumber(item?.return)}%
</span>
{:else}
<span
class="inline-block text-white text-sm sm:text-[1rem] whitespace-nowrap"
>
-
</span>
{/if}
</td>
</tr> </tr>
</thead> {/each}
<tbody> </tbody>
{#each ipoList as item} </table>
<tr
class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-odd border-b-[#09090B]"
>
<td
class="text-white text-sm sm:text-[1rem] whitespace-nowrap text-start border-b-[#09090B] whitespace-nowrap"
>
{new Date(item?.date)?.toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
daySuffix: "2-digit",
})}
</td>
<td
class="text-sm sm:text-[1rem] whitespace-nowrap text-start border-b-[#09090B] whitespace-nowrap"
>
<a
href={"/stocks/" + item?.symbol}
class="sm:hover:text-white text-blue-400"
>
{item?.symbol}
</a>
</td>
<td
class="text-gray-200 border-b-[#09090B] whitespace-nowrap text-sm sm:text-[1rem]"
>
<span class="text-white"
>{item?.name?.length > charNumber
? formatString(item?.name?.slice(0, charNumber)) + "..."
: formatString(item?.name)}</span
>
</td>
<td
class="text-white text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B] text-end"
>
{item?.ipoPrice !== null ? item?.ipoPrice : "-"}
</td>
<td
class="text-white border-b-[#09090B] text-sm sm:text-[1rem] text-end"
>
{item?.currentPrice !== null ? item?.currentPrice : "-"}
</td>
<td
class="text-white border-b-[#09090B] text-end flex flex-row items-center justify-end"
>
{#if item?.return >= 0 && item?.return !== null}
<span
class="inline-block text-[#00FC50] text-sm sm:text-[1rem] whitespace-nowrap"
>+{abbreviateNumber(item?.return)}%</span
>
{:else if item?.return < 0 && item?.return !== null}
<span
class="inline-block text-[#FF2F1F] text-sm sm:text-[1rem] whitespace-nowrap"
>{abbreviateNumber(item?.return)}%
</span>
{:else}
<span
class="inline-block text-white text-sm sm:text-[1rem] whitespace-nowrap"
>
-
</span>
{/if}
</td>
</tr>
{/each}
<InfiniteLoading on:infinite={infiniteHandler} />
</tbody>
</table>
</div>
{:else}
<div class="flex justify-center items-center m-auto mt-10 mb-6">
<div
class="text-gray-100 text-center text-sm sm:text-[1rem] rounded-md h-auto border border-gray-600 p-4"
>
<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="#fff"
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
>
No IPOs found. Please adjust your search timeframe for the latest {year}
IPOs.
</div>
</div>
{/if}
</div>
{:else}
<div class="flex justify-center items-center h-80">
<div class="relative">
<label
class="bg-secondary rounded-md 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> {:else}
{/if} <Infobox
text={`No IPOs found. Please adjust your search timeframe for the latest ${year}
IPOs.`}
/>
{/if}
</div>
</section> </section>