Skip to content

Commit

Permalink
feat: Add SlotCommitment info to LandingSlotSection
Browse files Browse the repository at this point in the history
  • Loading branch information
msarcev committed Feb 23, 2024
1 parent 869022c commit cd8289a
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 32 deletions.
20 changes: 19 additions & 1 deletion client/src/app/components/nova/landing/LandingSlotSection.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,39 @@
margin: 0 20px 20px;

.slots-feed__item {
display: flex;
display: grid;
grid-template-columns: 1fr 3fr 1fr 1fr;
margin: 0px 12px;
align-items: center;
line-height: 32px;
justify-content: center;
background-color: $gray-5;
border-radius: 4px;

&.basic {
grid-template-columns: none;
}

&.transparent {
background-color: transparent;
}

&:not(:last-child) {
margin-bottom: 20px;
}

.slot__index,
.slot__commitment-id,
.slot__rmc,
.slot__status {
display: flex;
margin: 0 auto;
justify-content: center;
}

.slot__commitment-id {
width: 220px;
}
}
}
}
37 changes: 28 additions & 9 deletions client/src/app/components/nova/landing/LandingSlotSection.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from "react";
import useSlotsFeed from "~/helpers/nova/hooks/useSlotsFeed";
import "./LandingSlotSection.scss";
import ProgressBar from "./ProgressBar";
import { Utils } from "@iota/sdk-wasm-nova/web";
import Spinner from "../../Spinner";
import TruncatedId from "../../stardust/TruncatedId";
import "./LandingSlotSection.scss";

const LandingSlotSection: React.FC = () => {
const { currentSlot, currentSlotProgressPercent, latestSlots } = useSlotsFeed();
const { currentSlotIndex, currentSlotProgressPercent, latestSlotIndexes, latestSlotCommitments } = useSlotsFeed();

if (currentSlot === null || currentSlotProgressPercent === null) {
if (currentSlotIndex === null || currentSlotProgressPercent === null) {
return null;
}

Expand All @@ -15,13 +18,29 @@ const LandingSlotSection: React.FC = () => {
<h2 className="slots-section__header">Latest Slots</h2>
<div className="slots-feed__wrapper">
<ProgressBar progress={currentSlotProgressPercent} showLabel={false}>
<div className="slots-feed__item transparent">{currentSlot}</div>
</ProgressBar>
{latestSlots?.map((slot) => (
<div key={`slot-key-${slot}`} className="slots-feed__item">
{slot}
<div className="slots-feed__item transparent basic">
<div className="slot__index">{currentSlotIndex}</div>
</div>
))}
</ProgressBar>
{latestSlotIndexes?.map((slot) => {
const commitment = latestSlotCommitments?.find((commitment) => commitment.slot === slot) ?? null;
const commitmentId = !commitment ? (
<Spinner compact />
) : (
<TruncatedId id={Utils.computeSlotCommitmentId(commitment)} showCopyButton />
);
const referenceManaCost = !commitment ? <Spinner compact /> : commitment.referenceManaCost.toString();
const slotStatus = !commitment ? "pending" : "committed";

return (
<div key={`slot-key-${slot}`} className="slots-feed__item">
<div className="slot__index">{slot}</div>
<div className="slot__commitment-id">{commitmentId}</div>
<div className="slot__rmc">{referenceManaCost}</div>
<div className="slot__status">{slotStatus}</div>
</div>
);
})}
</div>
</div>
);
Expand Down
89 changes: 67 additions & 22 deletions client/src/helpers/nova/hooks/useSlotsFeed.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,98 @@
import { SlotCommitment } from "@iota/sdk-wasm-nova/web";
import moment from "moment";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { ServiceFactory } from "~/factories/serviceFactory";
import { useIsMounted } from "~/helpers/hooks/useIsMounted";
import { NOVA } from "~/models/config/protocolVersion";
import { NovaApiClient } from "~/services/nova/novaApiClient";
import { useNetworkInfoNova } from "../networkInfo";
import { useNovaTimeConvert } from "./useNovaTimeConvert";

const DEFAULT_SLOT_LIMIT = 10;
const MAX_LATEST_SLOT_COMMITMENTS = 20;

const CHECK_SLOT_INDEX_INTERVAL = 950;
const CHECK_SLOT_COMMITMENTS_INTERVAL = 3500;

export default function useSlotsFeed(slotsLimit: number = DEFAULT_SLOT_LIMIT): {
currentSlot: number | null;
currentSlotIndex: number | null;
currentSlotProgressPercent: number | null;
latestSlots: number[] | null;
latestSlotIndexes: number[] | null;
latestSlotCommitments: SlotCommitment[];
} {
const isMounted = useIsMounted();
const { name: network } = useNetworkInfoNova((s) => s.networkInfo);
const [apiClient] = useState(ServiceFactory.get<NovaApiClient>(`api-client-${NOVA}`));
const { unixTimestampToSlotIndex, slotIndexToUnixTimeRange } = useNovaTimeConvert();
const [currentSlot, setCurrentSlot] = useState<number | null>(null);
const [latestSlots, setLatestSlots] = useState<number[] | null>(null);
const [currentSlotIndex, setCurrentSlotIndex] = useState<number | null>(null);
const [latestSlotIndexes, setLatestSlotIndexes] = useState<number[] | null>(null);

const [latestSlotCommitments, setLatestSlotCommitments] = useState<SlotCommitment[]>([]);

const [currentSlotProgressPercent, setCurrentSlotProgressPercent] = useState<number | null>(null);
const [slotTimeUpdateHandle, setSlotTimeUpdateHandle] = useState<NodeJS.Timeout | null>(null);

const checkCurrentSlot = () => {
const [slotIndexCheckerHandle, setSlotIndexCheckerHandle] = useState<NodeJS.Timeout | null>(null);
const [slotCommitmentsCheckerHandle, setSlotCommitmentsCheckerHandle] = useState<NodeJS.Timeout | null>(null);

const checkCurrentSlotIndex = () => {
if (unixTimestampToSlotIndex && slotIndexToUnixTimeRange) {
const now = moment().unix();
const currentSlotIndex = unixTimestampToSlotIndex(now);
const slotTimeRange = slotIndexToUnixTimeRange(currentSlotIndex);

const slotProgressPercent = Math.trunc(((now - slotTimeRange.from) / (slotTimeRange.to - 1 - slotTimeRange.from)) * 100);
setCurrentSlot(currentSlotIndex);
setCurrentSlotProgressPercent(slotProgressPercent);
setLatestSlots(Array.from({ length: slotsLimit - 1 }, (_, i) => currentSlotIndex - 1 - i));

if (isMounted) {
setCurrentSlotIndex(currentSlotIndex);
setCurrentSlotProgressPercent(slotProgressPercent);
setLatestSlotIndexes(Array.from({ length: slotsLimit - 1 }, (_, i) => currentSlotIndex - 1 - i));
}
}
};

const getLatestSlotCommitments = useCallback(async () => {
if (apiClient) {
const latestSlotCommitments = await apiClient.latestSlotCommitments(network);
if (isMounted && latestSlotCommitments.slotCommitments && latestSlotCommitments.slotCommitments.length > 0) {
setLatestSlotCommitments(latestSlotCommitments.slotCommitments.slice(0, MAX_LATEST_SLOT_COMMITMENTS));
}
}
}, [network]);

useEffect(() => {
if (slotTimeUpdateHandle === null) {
checkCurrentSlot();
const intervalTimerHandle = setInterval(() => {
checkCurrentSlot();
}, 950);
if (slotIndexCheckerHandle === null) {
getLatestSlotCommitments();
checkCurrentSlotIndex();

const slotCommitmentCheckerHandle = setInterval(() => {
getLatestSlotCommitments();
}, CHECK_SLOT_COMMITMENTS_INTERVAL);

const slotIndexIntervalHandle = setInterval(() => {
checkCurrentSlotIndex();
}, CHECK_SLOT_INDEX_INTERVAL);

setSlotTimeUpdateHandle(intervalTimerHandle);
setSlotCommitmentsCheckerHandle(slotCommitmentCheckerHandle);
setSlotIndexCheckerHandle(slotIndexIntervalHandle);
}

return () => {
if (slotTimeUpdateHandle) {
clearInterval(slotTimeUpdateHandle);
if (slotCommitmentsCheckerHandle) {
clearInterval(slotCommitmentsCheckerHandle);
}
setSlotTimeUpdateHandle(null);
setCurrentSlot(null);

if (slotIndexCheckerHandle) {
clearInterval(slotIndexCheckerHandle);
}

setSlotCommitmentsCheckerHandle(null);
setSlotIndexCheckerHandle(null);
setCurrentSlotIndex(null);
setCurrentSlotProgressPercent(null);
setLatestSlots(null);
setLatestSlotIndexes(null);
setLatestSlotCommitments([]);
};
}, []);

return { currentSlot, currentSlotProgressPercent, latestSlots };
return { currentSlotIndex, currentSlotProgressPercent, latestSlotIndexes, latestSlotCommitments };
}
6 changes: 6 additions & 0 deletions client/src/models/api/nova/ILatestSlotCommitmentsResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { SlotCommitment } from "@iota/sdk-wasm-nova/web";
import { IResponse } from "../IResponse";

export interface ILatestSlotCommitmentResponse extends IResponse {
slotCommitments: SlotCommitment[];
}
10 changes: 10 additions & 0 deletions client/src/services/nova/novaApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { IFoundriesResponse } from "~/models/api/nova/foundry/IFoundriesResponse
import { IFoundriesRequest } from "~/models/api/nova/foundry/IFoundriesRequest";
import { ICongestionRequest } from "~/models/api/nova/ICongestionRequest";
import { ICongestionResponse } from "~/models/api/nova/ICongestionResponse";
import { ILatestSlotCommitmentResponse } from "~/models/api/nova/ILatestSlotCommitmentsResponse";

/**
* Class to handle api communications on nova.
Expand Down Expand Up @@ -148,6 +149,15 @@ export class NovaApiClient extends ApiClient {
);
}

/**
* Get the latest slot commitments.
* @param network The network in context.
* @returns The latest slot commitments response.
*/
public async latestSlotCommitments(network: string): Promise<ILatestSlotCommitmentResponse> {
return this.callApi<unknown, ILatestSlotCommitmentResponse>(`nova/commitment/latest/${network}`, "get");
}

/**
* Get the account congestion.
* @param request The request to send.
Expand Down

0 comments on commit cd8289a

Please sign in to comment.