update metrics page

This commit is contained in:
MuslemRahimi 2024-10-20 18:41:45 +02:00
parent b8c6ed7658
commit 48fe6ca96e
4 changed files with 508 additions and 355 deletions

View File

@ -1,5 +1,5 @@
export const load = async ({ locals, params }) => { export const load = async ({ locals, params }) => {
const getAnalystEstimate = async () => { const getBusinessMetrics = async () => {
const { apiURL, apiKey } = locals; const { apiURL, apiKey } = locals;
const postData = { const postData = {
@ -7,7 +7,7 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch(apiURL + "/analyst-estimate", { const response = await fetch(apiURL + "/business-metrics", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -23,6 +23,6 @@ export const load = async ({ locals, params }) => {
// Make sure to return a promise // Make sure to return a promise
return { return {
getAnalystEstimate: await getAnalystEstimate(), getBusinessMetrics: await getBusinessMetrics(),
}; };
}; };

View File

@ -1,27 +1,31 @@
<script lang="ts"> <script lang="ts">
import { stockTicker, screenWidth } from "$lib/store"; import { stockTicker, screenWidth } from "$lib/store";
import { page } from "$app/stores"; import { page } from "$app/stores";
import { goto } from "$app/navigation";
const subsectionTitles = ['Overview', 'Data Center', 'Gaming', 'Visualization', 'Automotive', 'OEM & Other']; export let data;
const names = data?.getBusinessMetrics?.revenue?.names;
const subsectionTitles = ["Overview", ...names];
const sectionMap = Object.fromEntries( const sectionMap = Object.fromEntries(
subsectionTitles.map(title => { subsectionTitles.map((title) => {
const key = title.toLowerCase().replace(/ & /g, '-').replace(/ /g, '-'); const key = title.toLowerCase().replace(/ & /g, "-").replace(/ /g, "-");
return [key, key === 'overview' ? '' : key]; return [key, key === "overview" ? "" : key];
}) }),
); );
let displaySubSection = "overview"; let displaySubSection = "overview";
function changeSubSection(state) { function changeSubSection(state) {
displaySubSection = state; displaySubSection = state;
const path = state === "overview" ? "/metrics" : `/metrics/${sectionMap[state]}`; const path =
state === "overview" ? "/metrics" : `/metrics/${sectionMap[state]}`;
// Navigate programmatically using SvelteKit's goto function // Navigate programmatically using SvelteKit's goto function
} }
function getHref(section) { function getHref(section) {
const path = section === "overview" ? "/metrics" : `/metrics/${sectionMap[section]}`; const path =
section === "overview" ? "/metrics" : `/metrics/${sectionMap[section]}`;
return `/stocks/${$stockTicker}${path}`; return `/stocks/${$stockTicker}${path}`;
} }
@ -30,33 +34,56 @@
const parts = $page.url.pathname.split("/"); const parts = $page.url.pathname.split("/");
// Filter out empty strings from URL parts and look for the section // Filter out empty strings from URL parts and look for the section
const foundSection = parts.find(part => part && Object.values(sectionMap).includes(part)); const foundSection = parts.find(
(part) => part && Object.values(sectionMap).includes(part),
);
// If a valid section is found in the URL, update the displaySubSection // If a valid section is found in the URL, update the displaySubSection
displaySubSection = Object.keys(sectionMap).find(key => sectionMap[key] === foundSection) || "overview"; displaySubSection =
Object.keys(sectionMap).find(
(key) => sectionMap[key] === foundSection,
) || "overview";
} }
} }
</script> </script>
<!-- Rest of the component remains the same --> <!-- Rest of the component remains the same -->
<section class="w-auto max-w-5xl bg-[#09090B] overflow-hidden text-black h-full mb-40"> <section
class="w-auto max-w-5xl bg-[#09090B] overflow-hidden text-black h-full mb-40"
>
<div class="m-auto h-full overflow-hidden"> <div class="m-auto h-full overflow-hidden">
<main class="w-fit sm:w-full sm:max-w-2xl"> <main class="w-fit sm:w-full sm:max-w-2xl">
<div class="m-auto"> <div class="m-auto">
<div class="-ml-2 sm:ml-8 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : ''} mb-2"> <div
<ul class="pr-4 sm:pr-0 w-screen flex flex-row items-center bg-[#09090B] overflow-x-scroll sm:overflow-hidden space-x-4 rtl:space-x-reverse py-2"> class="-ml-2 sm:ml-8 w-screen sm:w-full {$screenWidth < 640
? 'overflow-auto scrollbar'
: ''} mb-2"
>
<ul
class="pr-4 sm:pr-0 w-screen flex flex-row items-center bg-[#09090B] overflow-x-scroll sm:overflow-hidden space-x-4 rtl:space-x-reverse py-2"
>
{#each subsectionTitles as title} {#each subsectionTitles as title}
{@const sectionKey = title.toLowerCase().replace(/ & /g, '-').replace(/ /g, '-')} {@const sectionKey = title
.toLowerCase()
.replace(/ & /g, "-")
.replace(/ /g, "-")}
<li class="cursor-pointer flex flex-col items-center"> <li class="cursor-pointer flex flex-col items-center">
<a <a
href={getHref(sectionKey)} href={getHref(sectionKey)}
on:click={() => changeSubSection(sectionKey)} on:click={() => changeSubSection(sectionKey)}
class="px-2 text-sm sm:text-[1rem] whitespace-nowrap font-medium text-gray-400 sm:hover:text-white {displaySubSection === sectionKey ? 'text-white' : 'bg-[#09090B]'}" class="px-2 text-sm sm:text-[1rem] whitespace-nowrap font-medium text-gray-400 sm:hover:text-white {displaySubSection ===
sectionKey
? 'text-white'
: 'bg-[#09090B]'}"
> >
{title} {title}
</a> </a>
<div class="{displaySubSection === sectionKey ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]" /> <div
class="{displaySubSection === sectionKey
? 'bg-[#75D377]'
: 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3rem]"
/>
</li> </li>
{/each} {/each}
</ul> </ul>

View File

@ -1,24 +1,54 @@
<script lang="ts"> <script lang="ts">
import { numberOfUnreadNotification, displayCompanyName, stockTicker } from "$lib/store"; import {
numberOfUnreadNotification,
displayCompanyName,
stockTicker,
} from "$lib/store";
import { abbreviateNumber } from "$lib/utils"; import { abbreviateNumber } from "$lib/utils";
export let data; export let data;
const dataset = [{'date': '2024-06-30', 'value': [26272000000, 2880000000, 454000000, 346000000, 88000000], 'valueGrowth': [16.44, 8.8, 6.32, 5.17, 12.82]}, {'date': '2024-03-31', 'value': [22563000000, 2647000000, 427000000, 329000000, 78000000], 'valueGrowth': [22.6, -7.61, -7.78, 17.08, -13.33]}, {'date': '2023-12-31', 'value': [18404000000, 2865000000, 463000000, 281000000, 90000000], 'valueGrowth': [26.8, 0.32, 11.3, 7.66, 23.29]}, {'date': '2023-09-30', 'value': [14514000000, 2856000000, 416000000, 261000000, 73000000], 'valueGrowth': [40.6, 14.88, 9.76, 3.16, 10.61]}, {'date': '2023-06-30', 'value': [10323000000, 2486000000, 379000000, 253000000, 66000000], 'valueGrowth': [324.81, -41.97, -83.08, -14.24, -77.7]}, {'date': '2022-12-31', 'value': [3616000000, 1831000000, 226000000, 294000000, 84000000], 'valueGrowth': [-5.66, 16.33, 13.0, 17.13, 15.07]}, {'date': '2022-09-30', 'value': [3833000000, 1574000000, 200000000, 251000000, 73000000], 'valueGrowth': [0.71, -22.92, -59.68, 14.09, -47.86]}, {'date': '2022-06-30', 'value': [3806000000, 2042000000, 496000000, 220000000, 140000000], 'valueGrowth': [1.49, -43.59, -20.26, 59.42, -11.39]}, {'date': '2022-03-31', 'value': [3750000000, 3620000000, 622000000, 138000000, 158000000], 'valueGrowth': [14.92, 5.85, -3.27, 10.4, -17.71]}, {'date': '2021-12-31', 'value': [3263000000, 3420000000, 643000000, 125000000, 192000000], 'valueGrowth': [11.14, 6.18, 11.44, -7.41, -17.95]}, {'date': '2021-09-30', 'value': [2936000000, 3221000000, 577000000, 135000000, 234000000], 'valueGrowth': [24.09, 5.23, 11.18, -11.18, -42.79]}, {'date': '2021-06-30', 'value': [2366000000, 3061000000, 519000000, 152000000, 409000000], 'valueGrowth': [15.53, 10.91, 39.52, -1.3, 25.08]}, {'date': '2021-03-31', 'value': [2048000000, 2760000000, 372000000, 154000000, 327000000], 'valueGrowth': [-32.72, -28.01, -39.41, -48.67, 12.37]}, {'date': '2020-12-31', 'value': [3044000000, 3834000000, 614000000, 300000000, 291000000], 'valueGrowth': [60.21, 68.82, 160.17, 140.0, 50.0]}, {'date': '2020-09-30', 'value': [1900000000, 2271000000, 236000000, 125000000, 194000000], 'valueGrowth': [8.45, 37.3, 16.26, 12.61, 32.88]}, {'date': '2020-06-30', 'value': [1752000000, 1654000000, 203000000, 111000000, 146000000], 'valueGrowth': [null, null, null, null, null]}];
const geographicDataset = [{'date': '2024-06-30', 'value': [13022000000, 3667000000, 13351000000], 'valueGrowth': [-3.51, 47.21, 32.75]}, {'date': '2024-03-31', 'value': [13496000000, 2491000000, 10057000000], 'valueGrowth': [10.3, 28.01, 4.8]}, {'date': '2023-12-31', 'value': [12236000000, 1946000000, 9596000000], 'valueGrowth': [94.16, -51.71, 23.22]}, {'date': '2023-09-30', 'value': [6302000000, 4030000000, 7788000000], 'valueGrowth': [4.29, 47.08, 64.86]}, {'date': '2023-06-30', 'value': [6043000000, 2740000000, 4724000000], 'valueGrowth': [153.38, 72.33, 46.84]}, {'date': '2023-03-31', 'value': [2385000000, 1590000000, 3217000000], 'valueGrowth': [7.24, 66.67, -27.72]}, {'date': '2022-12-31', 'value': [2224000000, 954000000, 4451000000], 'valueGrowth': [3.54, -16.9, 68.92]}, {'date': '2022-09-30', 'value': [2148000000, 1148000000, 2635000000], 'valueGrowth': [8.05, -28.34, -15.38]}, {'date': '2022-06-30', 'value': [1988000000, 1602000000, 3114000000], 'valueGrowth': [2.9, -23.02, -27.16]}, {'date': '2022-03-31', 'value': [1932000000, 2081000000, 4275000000], 'valueGrowth': [32.42, 4.94, 39.89]}, {'date': '2021-12-31', 'value': [1459000000, 1983000000, 3056000000], 'valueGrowth': [29.57, -1.69, -44.95]}, {'date': '2021-09-30', 'value': [1126000000, 2017000000, 5551000000], 'valueGrowth': [13.05, 17.27, 6.89]}, {'date': '2021-06-30', 'value': [996000000, 1720000000, 5193000000], 'valueGrowth': [29.69, 23.65, 66.39]}, {'date': '2021-03-31', 'value': [768000000, 1391000000, 3121000000], 'valueGrowth': [-44.35, -27.48, -28.5]}, {'date': '2020-12-31', 'value': [1380000000, 1918000000, 4365000000], 'valueGrowth': [55.06, 72.33, 76.29]}, {'date': '2020-09-30', 'value': [890000000, 1113000000, 2476000000], 'valueGrowth': [-5.72, 30.18, 35.52]}, {'date': '2020-06-30', 'value': [944000000, 855000000, 1827000000], 'valueGrowth': [null, null, null]}]
const categories = ['Data Center', 'Gaming', 'Visualization', 'Automotive', 'OEM and Other']; const names = data?.getBusinessMetrics?.revenue?.names;
const geographicCategories = ['United States', 'China', 'Other Countries']; const subsectionTitles = ["Overview", ...names];
const xData = dataset?.map(item => item?.date); const sectionMap = Object.fromEntries(
const geographicXData = geographicDataset?.map(item => item?.date); subsectionTitles.map((title) => {
const key = title.toLowerCase().replace(/ & /g, "-").replace(/ /g, "-");
return [key, key === "overview" ? "" : key];
}),
);
const categoryValues = categories.map((_, index) => dataset.map(item => item.value[index])); const dataset = data?.getBusinessMetrics?.revenue?.history;
const geographiCategoryValues = geographicCategories.map((_, index) => geographicDataset.map(item => item.value[index]));
const geographicDataset = data?.getBusinessMetrics?.geographic?.history;
const growthValues = categories?.map((_, index) => dataset.map(item => item.valueGrowth[index])); const revenueNames = data?.getBusinessMetrics?.revenue?.names;
const geographicGrowthValues = geographicCategories?.map((_, index) => geographicDataset?.map(item => item.valueGrowth[index]));
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> </script>
<svelte:head> <svelte:head>
@ -28,54 +58,105 @@
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""} {$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
{$displayCompanyName} ({$stockTicker}) Business Metric Overview · stocknear {$displayCompanyName} ({$stockTicker}) Business Metric Overview · stocknear
</title> </title>
<meta name="description" content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`} /> <meta
<meta property="og:title" content={`${$displayCompanyName} (${$stockTicker}) Business Metric Overview · stocknear`} /> name="description"
<meta property="og:description" content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`} /> 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 property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={`${$displayCompanyName} (${$stockTicker}) Business Metric Overview · stocknear`} /> <meta
<meta name="twitter:description" content={`View unique business metrics for ${displayCompanyName} (${$stockTicker}) stock, including revenue breakdown, operating income, revenue by geography.`} /> 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> </svelte:head>
<section class="bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0 w-full"> <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="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="relative flex justify-center items-center overflow-hidden w-full"
>
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0"> <div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
{#if data?.getAnalystEstimate?.length !== 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>
<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"
<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]"> <table
class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]"
>
<thead> <thead>
<tr> <tr>
<th class="bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm sm:text-[1rem] text-start">Quarter</th> <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} {#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', { <td
month: 'short', class="z-20 bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm text-center bg-[#09090B]"
day: 'numeric', >{new Date(item ?? null)?.toLocaleString("en-US", {
year: 'numeric', month: "short",
})}</td> day: "numeric",
year: "numeric",
})}</td
>
{/each} {/each}
</tr> </tr>
</thead> </thead>
<tbody class="shadow-md"> <tbody class="shadow-md">
{#each categories as category, index} {#each revenueNames as name, index}
<tr class="bg-[#09090B] border-b-[#09090B] odd:bg-[#27272A]"> <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] sm:hover:text-blue-400 cursor-pointer underline underline-offset-4">{category} Revenue</th> <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} {#each categoryValues[index] as value}
<td class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"> <td
class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"
>
{abbreviateNumber(value)} {abbreviateNumber(value)}
</td> </td>
{/each} {/each}
</tr> </tr>
<tr class="bg-[#09090B] border-b-[#09090B]"> <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]"> <th
<span class="ml-2">{category} Revenue Growth</span> 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> </th>
{#each growthValues[index] as growthValue} {#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]"> <td
{growthValue > 0 ? '+' : ''}{growthValue !== null ? growthValue?.toFixed(2) + '%' : '-'} 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> </td>
{/each} {/each}
</tr> </tr>
@ -84,42 +165,66 @@
</table> </table>
</div> </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"
<h2 class="mt-10 text-xl sm:text-2xl text-gray-200 font-bold mb-4">Revenue by Geography</h2> >
<table
<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"> class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]"
<table class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]"> >
<thead> <thead>
<tr> <tr>
<th class="bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm sm:text-[1rem] text-start">Quarter</th> <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} {#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', { <td
month: 'short', class="z-20 bg-[#09090B] border-b border-[#09090B] text-white font-semibold text-sm text-center bg-[#09090B]"
day: 'numeric', >{new Date(item ?? null)?.toLocaleString("en-US", {
year: 'numeric', month: "short",
})}</td> day: "numeric",
year: "numeric",
})}</td
>
{/each} {/each}
</tr> </tr>
</thead> </thead>
<tbody class="shadow-md"> <tbody class="shadow-md">
{#each geographicCategories as category, index} {#each geographicNames as name, index}
<tr class="bg-[#09090B] border-b-[#09090B] odd:bg-[#27272A]"> <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]">{category} Revenue</th> <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} {#each geographiCategoryValues[index] as value}
<td class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"> <td
class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]"
>
{abbreviateNumber(value)} {abbreviateNumber(value)}
</td> </td>
{/each} {/each}
</tr> </tr>
<tr class="bg-[#09090B] border-b-[#09090B]"> <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]"> <th
<span class="ml-2">{category} Revenue Growth</span> 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> </th>
{#each geographicGrowthValues[index] as growthValue} {#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]"> <td
{growthValue > 0 ? '+' : ''}{growthValue !== null ? growthValue?.toFixed(2) + '%' : '-'} 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> </td>
{/each} {/each}
</tr> </tr>
@ -128,9 +233,21 @@
</table> </table>
</div> </div>
{:else} {: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]"> <div
<svg class="w-6 h-6 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> 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]"
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 12l-2 2m0-2l2-2m2 2h6m-6 0H6" /> >
<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> </svg>
<p class="font-medium">No estimates available.</p> <p class="font-medium">No estimates available.</p>
</div> </div>

View File

@ -1,47 +1,43 @@
<script lang="ts"> <script lang="ts">
import {numberOfUnreadNotification,displayCompanyName, stockTicker} from '$lib/store'; import {
import { abbreviateNumber } from '$lib/utils'; numberOfUnreadNotification,
displayCompanyName,
import { Chart } from 'svelte-echarts' stockTicker,
} from "$lib/store";
import { init, use } from 'echarts/core' import { abbreviateNumber } from "$lib/utils";
import { LineChart, BarChart } from 'echarts/charts'
import { GridComponent, TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import { onMount } from 'svelte';
use([LineChart, BarChart, GridComponent,TooltipComponent, CanvasRenderer])
import { Chart } from "svelte-echarts";
import { init, use } from "echarts/core";
import { LineChart, BarChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { onMount } from "svelte";
use([LineChart, BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
export let data; export let data;
let isLoaded = false; let isLoaded = false;
let optionsData; let optionsData;
let rawData = [{'date': '2024-06-30', 'value': [26272000000, 2880000000, 454000000, 346000000, 88000000], 'valueGrowth': [16.44, 8.8, 6.32, 5.17, 12.82]}, {'date': '2024-03-31', 'value': [22563000000, 2647000000, 427000000, 329000000, 78000000], 'valueGrowth': [22.6, -7.61, -7.78, 17.08, -13.33]}, {'date': '2023-12-31', 'value': [18404000000, 2865000000, 463000000, 281000000, 90000000], 'valueGrowth': [26.8, 0.32, 11.3, 7.66, 23.29]}, {'date': '2023-09-30', 'value': [14514000000, 2856000000, 416000000, 261000000, 73000000], 'valueGrowth': [40.6, 14.88, 9.76, 3.16, 10.61]}, {'date': '2023-06-30', 'value': [10323000000, 2486000000, 379000000, 253000000, 66000000], 'valueGrowth': [324.81, -41.97, -83.08, -14.24, -77.7]}, {'date': '2022-12-31', 'value': [3616000000, 1831000000, 226000000, 294000000, 84000000], 'valueGrowth': [-5.66, 16.33, 13.0, 17.13, 15.07]}, {'date': '2022-09-30', 'value': [3833000000, 1574000000, 200000000, 251000000, 73000000], 'valueGrowth': [0.71, -22.92, -59.68, 14.09, -47.86]}, {'date': '2022-06-30', 'value': [3806000000, 2042000000, 496000000, 220000000, 140000000], 'valueGrowth': [1.49, -43.59, -20.26, 59.42, -11.39]}, {'date': '2022-03-31', 'value': [3750000000, 3620000000, 622000000, 138000000, 158000000], 'valueGrowth': [14.92, 5.85, -3.27, 10.4, -17.71]}, {'date': '2021-12-31', 'value': [3263000000, 3420000000, 643000000, 125000000, 192000000], 'valueGrowth': [11.14, 6.18, 11.44, -7.41, -17.95]}, {'date': '2021-09-30', 'value': [2936000000, 3221000000, 577000000, 135000000, 234000000], 'valueGrowth': [24.09, 5.23, 11.18, -11.18, -42.79]}, {'date': '2021-06-30', 'value': [2366000000, 3061000000, 519000000, 152000000, 409000000], 'valueGrowth': [15.53, 10.91, 39.52, -1.3, 25.08]}, {'date': '2021-03-31', 'value': [2048000000, 2760000000, 372000000, 154000000, 327000000], 'valueGrowth': [-32.72, -28.01, -39.41, -48.67, 12.37]}, {'date': '2020-12-31', 'value': [3044000000, 3834000000, 614000000, 300000000, 291000000], 'valueGrowth': [60.21, 68.82, 160.17, 140.0, 50.0]}, {'date': '2020-09-30', 'value': [1900000000, 2271000000, 236000000, 125000000, 194000000], 'valueGrowth': [8.45, 37.3, 16.26, 12.61, 32.88]}, {'date': '2020-06-30', 'value': [1752000000, 1654000000, 203000000, 111000000, 146000000], 'valueGrowth': [null, null, null, null, null]}] let rawData = data?.getBusinessMetrics?.revenue?.history;
let dataset = [];
let dataset = []
let tableList = []; let tableList = [];
function convertToTitleCase(str) { function convertToTitleCase(str) {
return str return str
?.split('-') // Split the string by hyphen ?.split("-") // Split the string by hyphen
?.map(word => word.charAt(0).toUpperCase() + word.slice(1)) // Capitalize the first letter of each word ?.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) // Capitalize the first letter of each word
?.join(' ') ?.join(" ")
?.replace('Oem', 'OEM') ?.replace("Oem", "OEM");
} }
function plotData() {
const plotDataset = [...dataset]?.sort(
(a, b) => new Date(a?.date) - new Date(b?.date),
function plotData() );
{ const xData = plotDataset?.map((item) => item?.date);
const plotDataset = [...dataset]?.sort((a, b) => new Date(a?.date) - new Date(b?.date));
const xData = plotDataset?.map(item => item?.date);
let valueList = []; let valueList = [];
for (let i = 0; i < plotDataset?.length; i++) { for (let i = 0; i < plotDataset?.length; i++) {
valueList.push(plotDataset[i]?.value); valueList.push(plotDataset[i]?.value);
@ -50,43 +46,43 @@ function plotData()
const options = { const options = {
animation: false, animation: false,
grid: { grid: {
left: '0%', left: "0%",
right: '2%', right: "2%",
bottom: '2%', bottom: "2%",
top: '10%', top: "10%",
containLabel: true containLabel: true,
}, },
xAxis: { xAxis: {
axisLabel: { axisLabel: {
color: '#fff', color: "#fff",
}, },
data: xData, data: xData,
type: 'category', type: "category",
}, },
yAxis: [ yAxis: [
{ {
type: 'value', type: "value",
splitLine: { splitLine: {
show: false, // Disable x-axis grid lines show: false, // Disable x-axis grid lines
}, },
axisLabel: { axisLabel: {
show: false // Hide y-axis labels show: false, // Hide y-axis labels
} },
}, },
], ],
series: [ series: [
{ {
name: 'Revenue', name: "Revenue",
data: valueList, data: valueList,
type: 'line', type: "line",
areaStyle: { opacity: 0.2 }, areaStyle: { opacity: 0.2 },
smooth: true, smooth: true,
symbol: 'none', symbol: "none",
}, },
], ],
tooltip: { tooltip: {
trigger: 'axis', trigger: "axis",
hideDelay: 100, hideDelay: 100,
}, },
}; };
@ -94,65 +90,81 @@ function plotData()
return options; return options;
} }
$: { $: {
if($stockTicker && data?.getParams && typeof window !== 'undefined') { if ($stockTicker && data?.getParams && typeof window !== "undefined") {
console.log('yes')
isLoaded = false; isLoaded = false;
dataset = []; dataset = [];
tableList = []; tableList = [];
dataset = rawData?.map(entry => ({ dataset = rawData?.map((entry) => ({
date: entry.date, date: entry.date,
value: data?.getParams === 'data-center' ? entry?.value[0] value:
: data?.getParams === 'gaming' ? entry?.value[1] data?.getParams === "data-center"
: data?.getParams === 'visualization' ? entry?.value[2] ? entry?.value[0]
: data?.getParams === 'automotive' ? entry?.value[3] : data?.getParams === "gaming"
: data?.getParams === 'oem-other' ? entry?.value[4] ? entry?.value[1]
: data?.getParams === "visualization"
? entry?.value[2]
: data?.getParams === "automotive"
? entry?.value[3]
: data?.getParams === "oem-other"
? entry?.value[4]
: null, : null,
valueGrowth: data?.getParams === 'data-center' ? entry?.valueGrowth[0] valueGrowth:
: data?.getParams === 'gaming' ? entry?.valueGrowth[1] data?.getParams === "data-center"
: data?.getParams === 'visualization' ? entry?.valueGrowth[2] ? entry?.valueGrowth[0]
: data?.getParams === 'automotive' ? entry?.valueGrowth[3] : data?.getParams === "gaming"
: data?.getParams === 'oem-other' ? entry?.valueGrowth[4] ? entry?.valueGrowth[1]
: null : data?.getParams === "visualization"
? entry?.valueGrowth[2]
: data?.getParams === "automotive"
? entry?.valueGrowth[3]
: data?.getParams === "oem-other"
? entry?.valueGrowth[4]
: null,
})); }));
tableList = [...dataset]; tableList = [...dataset];
tableList = tableList?.sort((a, b) => new Date(b?.date) - new Date(a?.date)); tableList = tableList?.sort(
optionsData= plotData() (a, b) => new Date(b?.date) - new Date(a?.date),
);
optionsData = plotData();
isLoaded = true; isLoaded = true;
} }
} }
</script> </script>
<svelte:head> <svelte:head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<title> <title>
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ''} {$displayCompanyName} ({$stockTicker}) Revenue Breakdown · stocknear {$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
{$displayCompanyName} ({$stockTicker}) Revenue Breakdown · stocknear
</title> </title>
<meta name="description" content={`Revenue & Geographic Breakdown`} /> <meta name="description" content={`Revenue & Geographic Breakdown`} />
<meta property="og:title" content={`${$displayCompanyName} (${$stockTicker}) Revenue Breakdown · stocknear`}/> <meta
property="og:title"
content={`${$displayCompanyName} (${$stockTicker}) Revenue Breakdown · stocknear`}
/>
<meta property="og:description" content={`Revenue & Geographic Breakdown`} /> <meta property="og:description" content={`Revenue & Geographic Breakdown`} />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={`${$displayCompanyName} (${$stockTicker}) Revenue Breakdown · stocknear`}/> <meta
name="twitter:title"
content={`${$displayCompanyName} (${$stockTicker}) Revenue Breakdown · stocknear`}
/>
<meta name="twitter:description" content={`Revenue & Geographic Breakdown`} /> <meta name="twitter:description" content={`Revenue & Geographic Breakdown`} />
</svelte:head> </svelte:head>
<section
<section class="bg-[#09090B] w-full overflow-hidden text-white h-full pb-40 sm:mb-0"> class="bg-[#09090B] w-full overflow-hidden text-white h-full pb-40 sm:mb-0"
>
<div class="w-full flex justify-center w-full sm-auto h-full overflow-hidden"> <div class="w-full flex justify-center w-full sm-auto h-full overflow-hidden">
<div class="w-full relative flex justify-center items-center overflow-hidden"> <div
class="w-full relative flex justify-center items-center overflow-hidden"
>
{#if isLoaded} {#if isLoaded}
<main class="w-full"> <main class="w-full">
<div class="sm:p-7 m-auto mt-2 sm:mt-0"> <div class="sm:p-7 m-auto mt-2 sm:mt-0">
@ -164,89 +176,95 @@ $: {
{#if rawData?.length !== 0} {#if rawData?.length !== 0}
<div class="grid grid-cols-1 gap-2"> <div class="grid grid-cols-1 gap-2">
<div class="app w-full"> <div class="app w-full">
<Chart {init} options={optionsData} class="chart" /> <Chart {init} options={optionsData} class="chart" />
</div> </div>
<h2 class="mt-10 text-xl text-gray-200 font-bold">History</h2>
<h2 class="mt-10 text-xl text-gray-200 font-bold">
History
</h2>
<div class="w-full overflow-x-scroll"> <div class="w-full overflow-x-scroll">
<table class="table table-sm table-compact rounded-none sm:rounded-md w-full border-bg-[#09090B] m-auto mt-4 "> <table
class="table table-sm table-compact rounded-none sm:rounded-md w-full border-bg-[#09090B] m-auto mt-4"
>
<thead> <thead>
<tr class="border border-slate-800"> <tr class="border border-slate-800">
<th class="text-white font-semibold text-start text-sm sm:text-[1rem]">Quarter</th> <th
<th class="text-white font-semibold text-end text-sm sm:text-[1rem]">Value</th> class="text-white font-semibold text-start text-sm sm:text-[1rem]"
<th class="text-white font-semibold text-end text-sm sm:text-[1rem]">% Change</th> >Quarter</th
>
<th
class="text-white font-semibold text-end text-sm sm:text-[1rem]"
>Value</th
>
<th
class="text-white font-semibold text-end text-sm sm:text-[1rem]"
>% Change</th
>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each tableList as item, index} {#each tableList as item, index}
<!-- row --> <!-- row -->
<tr class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B] shake-ticker cursor-pointer"> <tr
class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B] shake-ticker cursor-pointer"
<td class="text-white font-medium text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B]"> >
{new Date(item?.date ?? null)?.toLocaleString('en-US', { <td
month: 'short', class="text-white font-medium text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B]"
day: 'numeric', >
year: 'numeric', {new Date(item?.date ?? null)?.toLocaleString(
})} "en-US",
{
month: "short",
day: "numeric",
year: "numeric",
},
)}
</td> </td>
<td class="text-white text-sm sm:text-[1rem] text-right whitespace-nowrap border-b-[#09090B]"> <td
class="text-white text-sm sm:text-[1rem] text-right whitespace-nowrap border-b-[#09090B]"
>
{abbreviateNumber(item?.value)} {abbreviateNumber(item?.value)}
</td> </td>
<td class="text-white text-sm sm:text-[1rem] whitespace-nowrap font-medium text-end border-b-[#09090B]"> <td
class="text-white text-sm sm:text-[1rem] whitespace-nowrap font-medium text-end border-b-[#09090B]"
>
{#if item?.valueGrowth > 0} {#if item?.valueGrowth > 0}
<span class="text-[#37C97D]"> <span class="text-[#37C97D]">
+{(item?.valueGrowth)?.toFixed(2)}% +{item?.valueGrowth?.toFixed(2)}%
</span> </span>
{:else if item?.valueGrowth < 0} {:else if item?.valueGrowth < 0}
<span class="text-[#FF2F1F]"> <span class="text-[#FF2F1F]">
{(item?.valueGrowth)?.toFixed(2)}% {item?.valueGrowth?.toFixed(2)}%
</span> </span>
{:else} {:else}
- -
{/if} {/if}
</td> </td>
</tr> </tr>
{/each} {/each}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
{:else} {:else}
<h2 class="mt-16 flex justify-center items-center text-2xl font-medium text-white mb-5 m-auto"> <h2
class="mt-16 flex justify-center items-center text-2xl font-medium text-white mb-5 m-auto"
>
No data available No data available
</h2> </h2>
{/if} {/if}
</div> </div>
</main> </main>
{:else} {:else}
<div class="w-full flex justify-center items-center h-80"> <div class="w-full flex justify-center items-center h-80">
<div class="relative"> <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"> <label
<span class="loading loading-spinner loading-md text-gray-400"></span> 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> </label>
</div> </div>
</div> </div>
@ -255,15 +273,6 @@ $: {
</div> </div>
</section> </section>
<style> <style>
.app { .app {
height: 400px; height: 400px;