frontend/src/routes/stocks/[tickerID]/metrics/+page.svelte
2024-10-20 18:41:45 +02:00

259 lines
10 KiB
Svelte

<script lang="ts">
import {
numberOfUnreadNotification,
displayCompanyName,
stockTicker,
} from "$lib/store";
import { abbreviateNumber } from "$lib/utils";
export let data;
const names = data?.getBusinessMetrics?.revenue?.names;
const subsectionTitles = ["Overview", ...names];
const sectionMap = Object.fromEntries(
subsectionTitles.map((title) => {
const key = title.toLowerCase().replace(/ & /g, "-").replace(/ /g, "-");
return [key, key === "overview" ? "" : key];
}),
);
const dataset = data?.getBusinessMetrics?.revenue?.history;
const geographicDataset = data?.getBusinessMetrics?.geographic?.history;
const revenueNames = data?.getBusinessMetrics?.revenue?.names;
const geographicNames = data?.getBusinessMetrics?.geographic?.names;
const xData = dataset?.map((item) => item?.date);
const geographicXData = geographicDataset?.map((item) => item?.date);
const categoryValues = revenueNames.map((_, index) =>
dataset.map((item) => item.value[index]),
);
const geographiCategoryValues = geographicNames.map((_, index) =>
geographicDataset.map((item) => item.value[index]),
);
const growthValues = revenueNames?.map((_, index) =>
dataset.map((item) => item.valueGrowth[index]),
);
const geographicGrowthValues = geographicNames?.map((_, index) =>
geographicDataset?.map((item) => item.valueGrowth[index]),
);
function getHref(title) {
const key = title?.toLowerCase().replace(/ & /g, "-").replace(/ /g, "-");
const path =
key === "overview" ? "/metrics" : `/metrics/${sectionMap[key]}`;
return `/stocks/${$stockTicker}${path}`;
}
</script>
<svelte:head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
{$displayCompanyName} ({$stockTicker}) Business Metric Overview · stocknear
</title>
<meta
name="description"
content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`}
/>
<meta
property="og:title"
content={`${$displayCompanyName} (${$stockTicker}) Business Metric Overview · stocknear`}
/>
<meta
property="og:description"
content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`}
/>
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:title"
content={`${$displayCompanyName} (${$stockTicker}) Business Metric Overview · stocknear`}
/>
<meta
name="twitter:description"
content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`}
/>
</svelte:head>
<section
class="bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0 w-full"
>
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
<div
class="relative flex justify-center items-center overflow-hidden w-full"
>
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
{#if data?.getAnalystEstimate?.length !== 0}
<h2 class="mt-5 text-xl sm:text-2xl text-gray-200 font-bold mb-4">
{$displayCompanyName} Revenue Breakdown
</h2>
<div
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-scroll pr-5 sm:pr-0"
>
<table
class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]"
>
<thead>
<tr>
<th
class="bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm sm:text-[1rem] text-start"
>Quarter</th
>
{#each xData as item}
<td
class="z-20 bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm text-center bg-[#09090B]"
>{new Date(item ?? null)?.toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}</td
>
{/each}
</tr>
</thead>
<tbody class="shadow-md">
{#each revenueNames as name, index}
<tr class="bg-[#09090B] border-b-[#09090B] odd:bg-[#27272A]">
<th
class="whitespace-nowrap odd:bg-[#27272A] text-sm sm:text-[1rem] text-start font-medium border-b border-[#09090B]"
>
<a
href={getHref(name)}
class="sm:hover:text-blue-400 cursor-pointer underline underline-offset-4"
>
{name} Revenue
</a></th
>
{#each categoryValues[index] as value}
<td
class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"
>
{abbreviateNumber(value)}
</td>
{/each}
</tr>
<tr class="bg-[#09090B] border-b-[#09090B]">
<th
class="text-white whitespace-nowrap text-sm sm:text-[1rem] text-start font-medium bg-[#09090B] border-b border-[#09090B]"
>
<span class="ml-2">{name} Revenue Growth</span>
</th>
{#each growthValues[index] as growthValue}
<td
class="text-sm sm:text-[1rem] text-end {growthValue > 0
? 'text-[#37C97D]'
: growthValue < 0
? 'text-[#FF2F1F]'
: 'text-white'} font-medium border-b border-[#09090B]"
>
{growthValue > 0 ? "+" : ""}{growthValue !== null
? growthValue?.toFixed(2) + "%"
: "-"}
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
<h2 class="mt-10 text-xl sm:text-2xl text-gray-200 font-bold mb-4">
Revenue by Geography
</h2>
<div
class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-scroll pr-5 sm:pr-0"
>
<table
class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]"
>
<thead>
<tr>
<th
class="bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm sm:text-[1rem] text-start"
>Quarter</th
>
{#each geographicXData as item}
<td
class="z-20 bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm text-center bg-[#09090B]"
>{new Date(item ?? null)?.toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}</td
>
{/each}
</tr>
</thead>
<tbody class="shadow-md">
{#each geographicNames as name, index}
<tr class="bg-[#09090B] border-b-[#09090B] odd:bg-[#27272A]">
<th
class="text-white whitespace-nowrap odd:bg-[#27272A] text-sm sm:text-[1rem] text-start font-medium border-b border-[#09090B]"
>{name} Revenue</th
>
{#each geographiCategoryValues[index] as value}
<td
class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"
>
{abbreviateNumber(value)}
</td>
{/each}
</tr>
<tr class="bg-[#09090B] border-b-[#09090B]">
<th
class="text-white whitespace-nowrap text-sm sm:text-[1rem] text-start font-medium bg-[#09090B] border-b border-[#09090B]"
>
<span class="ml-2">{name} Revenue Growth</span>
</th>
{#each geographicGrowthValues[index] as growthValue}
<td
class="text-sm sm:text-[1rem] text-end {growthValue > 0
? 'text-[#37C97D]'
: growthValue < 0
? 'text-[#FF2F1F]'
: 'text-white'} font-medium border-b border-[#09090B]"
>
{growthValue > 0 ? "+" : ""}{growthValue !== null
? growthValue?.toFixed(2) + "%"
: "-"}
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
{:else}
<div
class="text-white p-3 sm:p-5 mb-10 rounded-lg sm:flex sm:flex-row sm:items-center border border-slate-800 text-sm sm:text-[1rem]"
>
<svg
class="w-6 h-6 mr-2"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 12l-2 2m0-2l2-2m2 2h6m-6 0H6"
/>
</svg>
<p class="font-medium">No estimates available.</p>
</div>
{/if}
</div>
</div>
</div>
</section>