259 lines
10 KiB
Svelte
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>
|