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">
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 { goto } from "$app/navigation";
import SEO from "$lib/components/SEO.svelte";
export let data;
let navigation = [];
let displaySection = "2024";
let displaySection = "2025";
let ipoNews = data?.getNews?.slice(0, 10);
for (let year = 2024; year >= 2019; 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;
for (let year = 2025; year >= 2019; year--) {
navigation?.push({ title: year, link: `/ipos/${year}` });
}
$: {
if ($page.url.pathname) {
const parts = $page?.url?.pathname?.split("/");
const sectionMap = {
"2025": "2025",
"2024": "2024",
"2023": "2023",
"2022": "2022",
@ -46,44 +36,11 @@
</script>
<!-- HEADER FOR BETTER SEO -->
<svelte:head>
<title>
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""} IPOs
Calendar · Stocknear</title
>
<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>
<SEO
title="IPOs
Calendar"
description="A list of upcoming ipos on the US stock market."
/>
<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"
@ -91,7 +48,7 @@
<div class="text-sm breadcrumbs">
<ul>
<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>
</div>
@ -100,10 +57,10 @@
<div
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">
<h1 class="mb-1 text-white text-2xl sm:text-3xl font-bold">
IPO Calendar
Recent IPOs
</h1>
</div>
@ -116,7 +73,32 @@
<ul
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
href={`/ipos/${item}`}
on:click={() => (displaySection = item)}
@ -134,61 +116,30 @@
<slot />
</main>
<aside class="hidden lg:block relative fixed w-1/4 ml-4">
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial}
<aside class="hidden lg:block relative fixed w-1/4">
{#if ipoNews?.length !== 0}
<div
on:click={() => goto("/pricing")}
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"
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"
>
<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">
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>
<div class="p-4 text-sm">
<h3 class="text-xl text-white font-bold mb-3">IPO News</h3>
<ul class="text-white">
{#each ipoNews?.slice(0, 10) as item}
<li class="mb-3 last:mb-1">
{item?.timestamp}
<br />
<a
class="sm:hover:text-white text-blue-400"
href={item?.link}
target="_blank"
rel="noopener noreferrer nofollow">{item?.title}</a
>
</li>
{/each}
</ul>
</div>
</div>
{/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>
</div>
</div>

View File

@ -1,13 +1,13 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { formatString, abbreviateNumber } from "$lib/utils";
import { screenWidth } from "$lib/store";
import { onMount } from "svelte";
export let data;
let rawData;
let ipoList;
let rawData = data?.getIPOCalendar;
let ipoList = rawData?.slice(0, 150);
let isLoaded = false;
async function handleScroll() {
@ -21,10 +21,8 @@
}
onMount(() => {
rawData = data?.getIPOCalendar;
ipoList = rawData?.slice(0, 50);
isLoaded = true;
window.addEventListener("scroll", handleScroll);
return () => {
@ -43,22 +41,7 @@
</script>
<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">
<table
@ -152,15 +135,5 @@
</table>
</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>

View File

@ -1,77 +1,38 @@
<script lang="ts">
import { formatString, abbreviateNumber } from "$lib/utils";
import { screenWidth } from "$lib/store";
import { page } from "$app/stores";
import { onMount } from "svelte";
import Infobox from "$lib/components/Infobox.svelte";
import InfiniteLoading from "$lib/components/InfiniteLoading.svelte";
export let data;
let rawData;
let totalIPOs = 0;
let ipoList;
let year;
let isLoaded = false;
let displayMonth = "all";
let rawData = data?.getIPOCalendar;
let ipoList = rawData?.slice(0, 150);
let year = data?.getYear;
async function infiniteHandler({ detail: { loaded, complete } }) {
if (ipoList?.length === rawData?.length) {
complete();
} else {
async function handleScroll() {
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
const isBottom = window.innerHeight + window.scrollY >= scrollThreshold;
if (isBottom && ipoList?.length !== rawData?.length) {
const nextIndex = ipoList?.length;
const newHoldings = rawData?.slice(nextIndex, nextIndex + 50);
ipoList = [...ipoList, ...newHoldings];
loaded();
const filteredNewResults = rawData?.slice(nextIndex, nextIndex + 50);
ipoList = [...ipoList, ...filteredNewResults];
}
}
const monthMap = {
jan: "01",
feb: "02",
march: "03",
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;
}
onMount(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
});
$: {
if (typeof window !== "undefined") {
const monthValue = monthMap[displayMonth];
if (displayMonth !== "all") {
rawData = data?.getIPOCalendar?.filter((item) =>
item?.date?.includes(`-${monthValue}-`),
);
} else {
rawData = data?.getIPOCalendar;
}
totalIPOs = data?.getIPOCalendar?.length;
ipoList = rawData?.slice(0, 50);
if ($page?.url?.pathname) {
rawData = data?.getIPOCalendar;
ipoList = rawData?.slice(0, 150);
year = data?.getYear;
isLoaded = true;
}
}
@ -79,175 +40,114 @@
</script>
<section class="w-full overflow-hidden m-auto">
{#if isLoaded}
<div class="mt-3 mb-3">
<Infobox
text={`There have been ${totalIPOs} IPOs on the US stock market in ${year}.`}
/>
</div>
<div class="flex flex-col justify-center items-center">
<div class="mr-auto flex flex-col jusitfy-start items-start mb-5 mt-5">
<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"
<div class="flex flex-col justify-center items-center">
{#if rawData?.length !== 0}
<h2 class="text-white text-xl font- text-start mt-5 w-full font-semibold">
{rawData?.length} IPOs
</h2>
<div class="w-full overflow-x-scroll">
<table
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"
>
{rawData?.length} IPOs
</h2>
<div class="w-full overflow-x-scroll">
<table
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"
>
<thead class="bg-default">
<tr>
<th class="text-white font-semibold text-sm text-start"
>IPO Date</th
<thead class="bg-default">
<tr>
<th class="text-white font-semibold text-sm text-start"
>IPO Date</th
>
<th class="text-white font-semibold text-sm text-start">Symbol</th
>
<th class="text-white font-semibold text-sm">Name</th>
<th class="text-white font-semibold text-end text-sm"
>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"
>Symbol</th
{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"
>
<th class="text-white font-semibold text-sm">Name</th>
<th class="text-white font-semibold text-end text-sm"
>IPO Price</th
<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]"
>
<th class="text-white font-semibold text-end text-sm"
>Current Price</th
<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"
>
<th class="text-white font-semibold text-end text-sm"
>Return Since</th
{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>
</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"
>
{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>
{/each}
</tbody>
</table>
</div>
</div>
{/if}
{:else}
<Infobox
text={`No IPOs found. Please adjust your search timeframe for the latest ${year}
IPOs.`}
/>
{/if}
</div>
</section>