update color scheme
This commit is contained in:
parent
990c818727
commit
e6d42b8f9d
@ -68,7 +68,7 @@
|
|||||||
class="stroke-current {score >= 7
|
class="stroke-current {score >= 7
|
||||||
? 'text-[#00FC50]'
|
? 'text-[#00FC50]'
|
||||||
: score >= 4
|
: score >= 4
|
||||||
? 'text-[#FF9E21]'
|
? 'text-[#FBCE3C]'
|
||||||
: 'text-[#FF2F1F]'}"
|
: 'text-[#FF2F1F]'}"
|
||||||
stroke-width="3"
|
stroke-width="3"
|
||||||
stroke-dasharray="100.48"
|
stroke-dasharray="100.48"
|
||||||
|
|||||||
@ -82,7 +82,7 @@
|
|||||||
<div class="fixed z-[100] bottom-8 sm:bottom-10 right-8 sm:right-16">
|
<div class="fixed z-[100] bottom-8 sm:bottom-10 right-8 sm:right-16">
|
||||||
<label
|
<label
|
||||||
for="feedbackInfo"
|
for="feedbackInfo"
|
||||||
class="inline-flex items-center justify-center w-12 h-12 sm:w-full sm:h-10 font-medium bg-gray-700 sm:bg-[#FFEDE5] ml-1 mr-0 sm:mr-2 rounded-full cursor-pointer"
|
class="inline-flex items-center justify-center w-12 h-12 sm:w-full sm:h-10 font-semibold bg-gray-700 sm:bg-[#FBCE3C] ml-1 mr-0 sm:mr-2 rounded-full cursor-pointer"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@ -111,10 +111,10 @@
|
|||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
for="feedbackInfo"
|
for="feedbackInfo"
|
||||||
class="cursor-pointer modal-backdrop bg-[#fff] bg-opacity-[0.05]"
|
class="cursor-pointer modal-backdrop bg-[#fff] bg-opacity-[0.1]"
|
||||||
></label>
|
></label>
|
||||||
|
|
||||||
<div class="modal-box w-full bg-[#000]">
|
<div class="modal-box w-full bg-[#09090B] border border-gray-600">
|
||||||
<div class="flex flex-row items-center pt-5">
|
<div class="flex flex-row items-center pt-5">
|
||||||
<h1 class="text-white text-xl sm:text-2xl font-bold">
|
<h1 class="text-white text-xl sm:text-2xl font-bold">
|
||||||
Your Feedback matters!
|
Your Feedback matters!
|
||||||
@ -185,10 +185,10 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
on:click={() => sendFeedback()}
|
on:click={() => sendFeedback()}
|
||||||
class="mb-4 px-3 py-2 bg-purple-600 smhover:bg-purple-700 {rating?.length !==
|
class="mb-4 px-3 py-2 bg-[#FBCE3C] sm:hover:bg-[#e8b305] {rating?.length !==
|
||||||
0 && inputValue?.length !== 0
|
0 && inputValue?.length !== 0
|
||||||
? 'opacity-100 cursor-pointer'
|
? 'opacity-100 cursor-pointer'
|
||||||
: 'opacity-60 cursor-not-allowed'} w-11/12 rounded-lg m-auto text-white font-semibold text-md"
|
: 'opacity-60 cursor-not-allowed'} w-11/12 rounded-lg m-auto text-black font-semibold text-md"
|
||||||
>
|
>
|
||||||
Send Feedback
|
Send Feedback
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { governmentContractComponent, displayCompanyName, stockTicker, screenWidth, getCache, setCache } from '$lib/store';
|
import {
|
||||||
import InfoModal from '$lib/components/InfoModal.svelte';
|
governmentContractComponent,
|
||||||
import { Chart } from 'svelte-echarts';
|
displayCompanyName,
|
||||||
|
stockTicker,
|
||||||
|
screenWidth,
|
||||||
|
getCache,
|
||||||
|
setCache,
|
||||||
|
} from "$lib/store";
|
||||||
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
import { Chart } from "svelte-echarts";
|
||||||
import { abbreviateNumber } from "$lib/utils";
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
|
||||||
import { init, use } from 'echarts/core';
|
import { init, use } from "echarts/core";
|
||||||
import { BarChart } from 'echarts/charts';
|
import { BarChart } from "echarts/charts";
|
||||||
import { GridComponent } from 'echarts/components';
|
import { GridComponent } from "echarts/components";
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
use([BarChart, GridComponent, CanvasRenderer]);
|
use([BarChart, GridComponent, CanvasRenderer]);
|
||||||
|
|
||||||
let isLoaded = false;
|
let isLoaded = false;
|
||||||
@ -15,7 +22,7 @@
|
|||||||
let optionsData;
|
let optionsData;
|
||||||
let avgNumberOfContracts = 0;
|
let avgNumberOfContracts = 0;
|
||||||
let displayMaxContracts = 0;
|
let displayMaxContracts = 0;
|
||||||
let displayYear = 'n/a';
|
let displayYear = "n/a";
|
||||||
let totalAmount;
|
let totalAmount;
|
||||||
let totalContract;
|
let totalContract;
|
||||||
|
|
||||||
@ -31,13 +38,18 @@
|
|||||||
numList?.push(item?.numOfContracts);
|
numList?.push(item?.numOfContracts);
|
||||||
});
|
});
|
||||||
|
|
||||||
totalContract = rawData?.reduce((sum, item) => sum + item?.numOfContracts, 0);
|
totalContract = rawData?.reduce(
|
||||||
|
(sum, item) => sum + item?.numOfContracts,
|
||||||
|
0,
|
||||||
|
);
|
||||||
totalAmount = rawData?.reduce((sum, item) => sum + item?.amount, 0);
|
totalAmount = rawData?.reduce((sum, item) => sum + item?.amount, 0);
|
||||||
|
|
||||||
avgNumberOfContracts = Math.floor(totalContract / rawData?.length);
|
avgNumberOfContracts = Math.floor(totalContract / rawData?.length);
|
||||||
const { year: yearWithMaxContracts, numOfContracts: maxContracts } = rawData?.reduce(
|
const { year: yearWithMaxContracts, numOfContracts: maxContracts } =
|
||||||
(max, contract) => (contract?.numOfContracts > max?.numOfContracts ? contract : max),
|
rawData?.reduce(
|
||||||
rawData?.at(0)
|
(max, contract) =>
|
||||||
|
contract?.numOfContracts > max?.numOfContracts ? contract : max,
|
||||||
|
rawData?.at(0),
|
||||||
);
|
);
|
||||||
displayYear = yearWithMaxContracts;
|
displayYear = yearWithMaxContracts;
|
||||||
displayMaxContracts = maxContracts;
|
displayMaxContracts = maxContracts;
|
||||||
@ -45,27 +57,27 @@
|
|||||||
const option = {
|
const option = {
|
||||||
silent: true,
|
silent: true,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: "axis",
|
||||||
hideDelay: 100, // Set the delay in milliseconds
|
hideDelay: 100, // Set the delay in milliseconds
|
||||||
},
|
},
|
||||||
animation: false,
|
animation: false,
|
||||||
grid: {
|
grid: {
|
||||||
left: '2%',
|
left: "2%",
|
||||||
right: $screenWidth < 640 ? '0%' : '2%',
|
right: $screenWidth < 640 ? "0%" : "2%",
|
||||||
bottom: '0%',
|
bottom: "0%",
|
||||||
top: '10%',
|
top: "10%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
data: dates,
|
data: dates,
|
||||||
type: 'category',
|
type: "category",
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: '#fff',
|
color: "#fff",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
yAxis: [
|
yAxis: [
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: "value",
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false, // Disable x-axis grid lines
|
show: false, // Disable x-axis grid lines
|
||||||
},
|
},
|
||||||
@ -74,32 +86,32 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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
|
||||||
},
|
},
|
||||||
position: 'right',
|
position: "right",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: '# of Contracts',
|
name: "# of Contracts",
|
||||||
data: numList,
|
data: numList,
|
||||||
type: 'line',
|
type: "line",
|
||||||
yAxisIndex: 1,
|
yAxisIndex: 1,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#fff', // Change bar color to white
|
color: "#fff", // Change bar color to white
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Amount',
|
name: "Amount",
|
||||||
data: amountList,
|
data: amountList,
|
||||||
type: 'bar',
|
type: "bar",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#FF9E21', // Change bar color to orange
|
color: "#FBCE3C", // Change bar color to orange
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -109,27 +121,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getGovernmentContract = async (ticker) => {
|
const getGovernmentContract = async (ticker) => {
|
||||||
const cachedData = getCache(ticker, 'getGovernmentContract');
|
const cachedData = getCache(ticker, "getGovernmentContract");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
rawData = cachedData;
|
rawData = cachedData;
|
||||||
} else {
|
} else {
|
||||||
const postData = { ticker: ticker, path: 'government-contract' };
|
const postData = { ticker: ticker, path: "government-contract" };
|
||||||
const response = await fetch('/api/ticker-data', {
|
const response = await fetch("/api/ticker-data", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData),
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
rawData = await response?.json();
|
rawData = await response?.json();
|
||||||
setCache(ticker, rawData, 'getGovernmentContract');
|
setCache(ticker, rawData, "getGovernmentContract");
|
||||||
}
|
}
|
||||||
|
|
||||||
governmentContractComponent.set(rawData?.length !== 0);
|
governmentContractComponent.set(rawData?.length !== 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($stockTicker && typeof window !== 'undefined') {
|
if ($stockTicker && typeof window !== "undefined") {
|
||||||
isLoaded = false;
|
isLoaded = false;
|
||||||
const ticker = $stockTicker;
|
const ticker = $stockTicker;
|
||||||
const asyncFunctions = [getGovernmentContract(ticker)];
|
const asyncFunctions = [getGovernmentContract(ticker)];
|
||||||
@ -141,20 +153,20 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('An error occurred:', error);
|
console.error("An error occurred:", error);
|
||||||
});
|
});
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<section class="overflow-hidden text-white h-full pb-8">
|
||||||
|
<main class="overflow-hidden">
|
||||||
<section class="overflow-hidden text-white h-full pb-8">
|
|
||||||
<main class="overflow-hidden ">
|
|
||||||
|
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<label for="governmentContractInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold">
|
<label
|
||||||
|
for="governmentContractInfo"
|
||||||
|
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
|
||||||
|
>
|
||||||
US Government Contract
|
US Government Contract
|
||||||
</label>
|
</label>
|
||||||
<InfoModal
|
<InfoModal
|
||||||
@ -165,70 +177,81 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isLoaded}
|
{#if isLoaded}
|
||||||
|
|
||||||
{#if rawData?.length !== 0}
|
{#if rawData?.length !== 0}
|
||||||
|
|
||||||
<div class="w-full flex flex-col items-start">
|
<div class="w-full flex flex-col items-start">
|
||||||
<div class="text-white text-sm sm:text-[1rem] mt-2 mb-2 w-full">
|
<div class="text-white text-sm sm:text-[1rem] mt-2 mb-2 w-full">
|
||||||
Since 2015, {$displayCompanyName} has secured a total of {totalContract} government contracts, amassing {abbreviateNumber(totalAmount,true)} in revenue. The company has averaged {avgNumberOfContracts} contracts per year, with a peak of {displayMaxContracts} contracts in {displayYear}.
|
Since 2015, {$displayCompanyName} has secured a total of {totalContract}
|
||||||
|
government contracts, amassing {abbreviateNumber(totalAmount, true)}
|
||||||
|
in revenue. The company has averaged {avgNumberOfContracts} contracts
|
||||||
|
per year, with a peak of {displayMaxContracts} contracts in {displayYear}.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pb-2 rounded-lg bg-[#09090B]">
|
<div class="pb-2 rounded-lg bg-[#09090B]">
|
||||||
|
|
||||||
|
|
||||||
<div class="app w-full h-[300px] mt-5">
|
<div class="app w-full h-[300px] mt-5">
|
||||||
<Chart {init} options={optionsData} class="chart" />
|
<Chart {init} options={optionsData} class="chart" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12">
|
<div
|
||||||
|
class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"
|
||||||
<div class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
>
|
||||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
<div
|
||||||
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||||
<span class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block">
|
>
|
||||||
|
<div
|
||||||
|
class="h-full transform -translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<span
|
||||||
|
class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block"
|
||||||
|
>
|
||||||
# of Contracts
|
# of Contracts
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
<div
|
||||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||||
<div class="w-3 h-3 bg-[#FFAD24] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
>
|
||||||
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block">
|
<div
|
||||||
|
class="h-full transform -translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 bg-[#FFAD24] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<span
|
||||||
|
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
|
||||||
|
>
|
||||||
Amount
|
Amount
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex justify-center items-center h-80">
|
<div class="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>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
|
<style>
|
||||||
.app {
|
.app {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
@ -240,5 +263,4 @@
|
|||||||
.chart {
|
.chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,28 +1,33 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { abbreviateNumber } from "$lib/utils";
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
import { swapComponent, stockTicker, screenWidth, getCache, setCache } from '$lib/store';
|
import {
|
||||||
import InfoModal from '$lib/components/InfoModal.svelte';
|
swapComponent,
|
||||||
import { Chart } from 'svelte-echarts';
|
stockTicker,
|
||||||
import { init, use } from 'echarts/core';
|
screenWidth,
|
||||||
import { ScatterChart } from 'echarts/charts';
|
getCache,
|
||||||
import { GridComponent, TooltipComponent } from 'echarts/components';
|
setCache,
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
} from "$lib/store";
|
||||||
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
import { Chart } from "svelte-echarts";
|
||||||
|
import { init, use } from "echarts/core";
|
||||||
|
import { ScatterChart } from "echarts/charts";
|
||||||
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
export let data: any; // Add type for `data` if possible
|
export let data: any; // Add type for `data` if possible
|
||||||
|
|
||||||
use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||||
|
|
||||||
let isLoaded = false;
|
let isLoaded = false;
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [{ title: "Effective Date" }, { title: "Expiration Date" }];
|
||||||
{ title: "Effective Date" },
|
|
||||||
{ title: "Expiration Date" },
|
|
||||||
];
|
|
||||||
|
|
||||||
let activeIdx = 0;
|
let activeIdx = 0;
|
||||||
|
|
||||||
function changeTab(index: number) {
|
function changeTab(index: number) {
|
||||||
activeIdx = index;
|
activeIdx = index;
|
||||||
optionsData = getPlotOptions(activeIdx === 0 ? 'effectiveDate' : 'expirationDate');
|
optionsData = getPlotOptions(
|
||||||
|
activeIdx === 0 ? "effectiveDate" : "expirationDate",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rawData: any[] = [];
|
let rawData: any[] = [];
|
||||||
@ -30,16 +35,19 @@
|
|||||||
let avgNotionalAmount: number | undefined;
|
let avgNotionalAmount: number | undefined;
|
||||||
let avgNotionalQuantity: number | undefined;
|
let avgNotionalQuantity: number | undefined;
|
||||||
|
|
||||||
|
function getPlotOptions(state: "effectiveDate" | "expirationDate") {
|
||||||
function getPlotOptions(state: 'effectiveDate' | 'expirationDate') {
|
|
||||||
const combinedData = rawData?.map((item) => ({
|
const combinedData = rawData?.map((item) => ({
|
||||||
date: state === 'effectiveDate' ? item['Effective Date'] : item['Expiration Date'],
|
date:
|
||||||
notionalAmount: item['Notional amount-Leg 1'],
|
state === "effectiveDate"
|
||||||
notionalQuantity: item['Total notional quantity-Leg 1'],
|
? item["Effective Date"]
|
||||||
|
: item["Expiration Date"],
|
||||||
|
notionalAmount: item["Notional amount-Leg 1"],
|
||||||
|
notionalQuantity: item["Total notional quantity-Leg 1"],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Group data by date and sum the values
|
// Group data by date and sum the values
|
||||||
const groupedData = combinedData.reduce((acc, curr) => {
|
const groupedData = combinedData.reduce(
|
||||||
|
(acc, curr) => {
|
||||||
const { date, notionalAmount, notionalQuantity } = curr;
|
const { date, notionalAmount, notionalQuantity } = curr;
|
||||||
|
|
||||||
if (acc[date]) {
|
if (acc[date]) {
|
||||||
@ -54,47 +62,57 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<string, any>);
|
},
|
||||||
|
{} as Record<string, any>,
|
||||||
|
);
|
||||||
|
|
||||||
const result = Object.values(groupedData);
|
const result = Object.values(groupedData);
|
||||||
|
|
||||||
result?.sort((a, b) => new Date(a?.date).getTime() - new Date(b?.date).getTime());
|
result?.sort(
|
||||||
|
(a, b) => new Date(a?.date).getTime() - new Date(b?.date).getTime(),
|
||||||
|
);
|
||||||
|
|
||||||
const dates = result?.map((item) => item?.date);
|
const dates = result?.map((item) => item?.date);
|
||||||
const notionalAmount = result?.map((item) => item?.notionalAmount);
|
const notionalAmount = result?.map((item) => item?.notionalAmount);
|
||||||
const notionalQuantity = result?.map((item) => item?.notionalQuantity);
|
const notionalQuantity = result?.map((item) => item?.notionalQuantity);
|
||||||
|
|
||||||
const totalNotionalAmount = notionalAmount?.reduce((acc, item) => acc + item, 0);
|
const totalNotionalAmount = notionalAmount?.reduce(
|
||||||
|
(acc, item) => acc + item,
|
||||||
|
0,
|
||||||
|
);
|
||||||
avgNotionalAmount = totalNotionalAmount / notionalAmount?.length;
|
avgNotionalAmount = totalNotionalAmount / notionalAmount?.length;
|
||||||
|
|
||||||
const totalNotionalQuantity = notionalQuantity?.reduce((acc, item) => acc + item, 0);
|
const totalNotionalQuantity = notionalQuantity?.reduce(
|
||||||
|
(acc, item) => acc + item,
|
||||||
|
0,
|
||||||
|
);
|
||||||
avgNotionalQuantity = totalNotionalQuantity / notionalQuantity?.length;
|
avgNotionalQuantity = totalNotionalQuantity / notionalQuantity?.length;
|
||||||
|
|
||||||
const option = {
|
const option = {
|
||||||
silent: true,
|
silent: true,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: "axis",
|
||||||
hideDelay: 100,
|
hideDelay: 100,
|
||||||
},
|
},
|
||||||
animation: false,
|
animation: false,
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
left: "3%",
|
||||||
right: '3%',
|
right: "3%",
|
||||||
bottom: '0%',
|
bottom: "0%",
|
||||||
top: '10%',
|
top: "10%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: "category",
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: dates,
|
data: dates,
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: '#fff',
|
color: "#fff",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
yAxis: [
|
yAxis: [
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: "value",
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
@ -103,11 +121,11 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: "value",
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
position: 'right',
|
position: "right",
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
@ -115,20 +133,20 @@
|
|||||||
],
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Notional Amount',
|
name: "Notional Amount",
|
||||||
type: 'scatter',
|
type: "scatter",
|
||||||
data: dates?.map((date, index) => [date, notionalAmount[index]]),
|
data: dates?.map((date, index) => [date, notionalAmount[index]]),
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#8F54F4',
|
color: "#8F54F4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Notional Quantity',
|
name: "Notional Quantity",
|
||||||
type: 'scatter',
|
type: "scatter",
|
||||||
data: dates?.map((date, index) => [date, notionalQuantity[index]]),
|
data: dates?.map((date, index) => [date, notionalQuantity[index]]),
|
||||||
yAxisIndex: 1,
|
yAxisIndex: 1,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#FF9E21',
|
color: "#FBCE3C",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -138,35 +156,35 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getSwapData(ticker: string) {
|
async function getSwapData(ticker: string) {
|
||||||
const cachedData = getCache(ticker, 'getSwapData');
|
const cachedData = getCache(ticker, "getSwapData");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
rawData = cachedData;
|
rawData = cachedData;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const postData = { ticker, path: 'swap-ticker' };
|
const postData = { ticker, path: "swap-ticker" };
|
||||||
const response = await fetch('/api/ticker-data', {
|
const response = await fetch("/api/ticker-data", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData),
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
if (!response.ok) throw new Error('API request failed');
|
if (!response.ok) throw new Error("API request failed");
|
||||||
rawData = await response.json();
|
rawData = await response.json();
|
||||||
setCache(ticker, rawData, 'getSwapData');
|
setCache(ticker, rawData, "getSwapData");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch swap data:', error);
|
console.error("Failed to fetch swap data:", error);
|
||||||
rawData = [];
|
rawData = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$swapComponent = rawData?.length !== 0; // Correct the use of `$`
|
$swapComponent = rawData?.length !== 0; // Correct the use of `$`
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if ($stockTicker && typeof window !== 'undefined') {
|
$: if ($stockTicker && typeof window !== "undefined") {
|
||||||
isLoaded = false;
|
isLoaded = false;
|
||||||
activeIdx = 0;
|
activeIdx = 0;
|
||||||
getSwapData($stockTicker).then(() => {
|
getSwapData($stockTicker).then(() => {
|
||||||
optionsData = getPlotOptions('effectiveDate');
|
optionsData = getPlotOptions("effectiveDate");
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -174,14 +192,13 @@
|
|||||||
$: charNumber = $screenWidth < 640 ? 20 : 40;
|
$: charNumber = $screenWidth < 640 ? 20 : 40;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<section class="overflow-hidden text-white h-full pb-8">
|
||||||
|
<main class="overflow-hidden">
|
||||||
|
|
||||||
<section class="overflow-hidden text-white h-full pb-8">
|
|
||||||
<main class="overflow-hidden ">
|
|
||||||
|
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<label for="swapInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold">
|
<label
|
||||||
|
for="swapInfo"
|
||||||
|
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
|
||||||
|
>
|
||||||
Swap Data
|
Swap Data
|
||||||
</label>
|
</label>
|
||||||
<InfoModal
|
<InfoModal
|
||||||
@ -192,91 +209,103 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isLoaded}
|
{#if isLoaded}
|
||||||
|
|
||||||
{#if rawData?.length !== 0}
|
{#if rawData?.length !== 0}
|
||||||
|
|
||||||
<div class="w-full flex flex-col items-start">
|
<div class="w-full flex flex-col items-start">
|
||||||
<div class="text-white text-[1rem] mt-2 mb-2 w-full">
|
<div class="text-white text-[1rem] mt-2 mb-2 w-full">
|
||||||
The swap data from the past 100 days shows an average notional amount of {abbreviateNumber(avgNotionalAmount,true)} and an average notional quantity of {abbreviateNumber(avgNotionalQuantity)}.
|
The swap data from the past 100 days shows an average notional
|
||||||
|
amount of {abbreviateNumber(avgNotionalAmount, true)} and an average
|
||||||
|
notional quantity of {abbreviateNumber(avgNotionalQuantity)}.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pb-2 rounded-lg bg-[#09090B]">
|
<div class="pb-2 rounded-lg bg-[#09090B]">
|
||||||
|
<div
|
||||||
<div class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 mt-4">
|
class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 mt-4"
|
||||||
|
>
|
||||||
{#each tabs as item, i}
|
{#each tabs as item, i}
|
||||||
<button
|
<button
|
||||||
on:click={() => changeTab(i)}
|
on:click={() => changeTab(i)}
|
||||||
class="group relative z-[1] rounded-full px-3 py-1 {activeIdx === i
|
class="group relative z-[1] rounded-full px-3 py-1 {activeIdx ===
|
||||||
|
i
|
||||||
? 'z-0'
|
? 'z-0'
|
||||||
: ''} ">
|
: ''} "
|
||||||
|
>
|
||||||
{#if activeIdx === i}
|
{#if activeIdx === i}
|
||||||
<div
|
<div class="absolute inset-0 rounded-lg bg-purple-600"></div>
|
||||||
class="absolute inset-0 rounded-lg bg-purple-600"
|
|
||||||
></div>
|
|
||||||
{/if}
|
{/if}
|
||||||
<span
|
<span
|
||||||
class="relative text-sm block font-medium duration-200 text-white">
|
class="relative text-sm block font-medium duration-200 text-white"
|
||||||
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="app w-full h-[300px] mt-5">
|
<div class="app w-full h-[300px] mt-5">
|
||||||
<Chart {init} options={optionsData} class="chart" />
|
<Chart {init} options={optionsData} class="chart" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12">
|
<div
|
||||||
|
class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"
|
||||||
<div class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
>
|
||||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
<div
|
||||||
<div class="w-3 h-3 bg-[#8F54F4] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
class="mt-3.5 sm:mt-0 flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||||
<span class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block">
|
>
|
||||||
|
<div
|
||||||
|
class="h-full transform -translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 bg-[#8F54F4] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<span
|
||||||
|
class="mt-2 sm:mt-0 text-white text-center sm:text-start text-xs sm:text-md inline-block"
|
||||||
|
>
|
||||||
Notional Amount
|
Notional Amount
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
|
<div
|
||||||
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
|
class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
|
||||||
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
|
>
|
||||||
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block">
|
<div
|
||||||
|
class="h-full transform -translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
class="w-3 h-3 bg-[#fff] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
|
||||||
|
aria-hidden="true"
|
||||||
|
></div>
|
||||||
|
<span
|
||||||
|
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
|
||||||
|
>
|
||||||
Notional Quantity
|
Notional Quantity
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex justify-center items-center h-80">
|
<div class="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>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
|
<style>
|
||||||
.app {
|
.app {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
@ -288,5 +317,4 @@
|
|||||||
.chart {
|
.chart {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
</style>
|
|
||||||
|
|||||||
@ -408,7 +408,7 @@
|
|||||||
type: "bar",
|
type: "bar",
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#FF9E21", // Change bar color to white
|
color: "#FBCE3C", // Change bar color to white
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
// Define categories in the exact order you specified
|
// Define categories in the exact order you specified
|
||||||
const categories = ["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"];
|
const categories = ["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"];
|
||||||
const colors = ["#9E190A", "#D9220E", "#FF9E21", "#31B800", "#008A00"];
|
const colors = ["#9E190A", "#D9220E", "#FBCE3C", "#31B800", "#008A00"];
|
||||||
|
|
||||||
// Create a consistent mapping for data
|
// Create a consistent mapping for data
|
||||||
const formattedData = rawAnalystList.map((item) =>
|
const formattedData = rawAnalystList.map((item) =>
|
||||||
@ -216,7 +216,7 @@
|
|||||||
color: [
|
color: [
|
||||||
[0.2, "#9E190A"],
|
[0.2, "#9E190A"],
|
||||||
[0.4, "#D9220E"],
|
[0.4, "#D9220E"],
|
||||||
[0.6, "#FF9E21"],
|
[0.6, "#FBCE3C"],
|
||||||
[0.8, "#31B800"],
|
[0.8, "#31B800"],
|
||||||
[1, "#008A00"],
|
[1, "#008A00"],
|
||||||
],
|
],
|
||||||
@ -409,7 +409,7 @@
|
|||||||
symbol: "none",
|
symbol: "none",
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
type: "dashed",
|
type: "dashed",
|
||||||
color: "#FF9E21",
|
color: "#FBCE3C",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -533,7 +533,7 @@
|
|||||||
? 'text-[#00FC50]'
|
? 'text-[#00FC50]'
|
||||||
: ['Strong Sell', 'Sell']?.includes(consensusRating)
|
: ['Strong Sell', 'Sell']?.includes(consensusRating)
|
||||||
? 'text-[#FF2F1F]'
|
? 'text-[#FF2F1F]'
|
||||||
: 'text-[#FF9E21]'}">{consensusRating}</span
|
: 'text-[#FBCE3C]'}">{consensusRating}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user