/ src / components / lib / chart / helpers.ts
helpers.ts
  1  import { DATE_URL } from "./data-url";
  2  import {
  3    BlockchainInfo,
  4    Difficulty,
  5    Issuance,
  6    IssuanceParsed,
  7    LockBox,
  8    NetInOutflow,
  9    NodeCountData,
 10    ShieldedAmountDatum,
 11    ShieldedTransactionDatum,
 12    ShieldedTxCount,
 13    SupplyData,
 14  } from "./types";
 15  
 16  export async function getBlockchainData(
 17    url: string,
 18    signal?: AbortSignal
 19  ): Promise<BlockchainInfo | null> {
 20    try {
 21      const res = await fetch(url, {
 22        signal,
 23      });
 24      if (!res.ok) return null;
 25      const json = await res.json();
 26      return json.data as BlockchainInfo;
 27    } catch {
 28      return null;
 29    }
 30  }
 31  export async function getIssuanceData(
 32    url: string,
 33    signal?: AbortSignal
 34  ): Promise<IssuanceParsed[] | null> {
 35    try {
 36      const res = await fetch(url, {
 37        signal,
 38      });
 39      if (!res.ok) return null;
 40      const data: Issuance[] = await res.json();
 41  
 42      const parsed = data.map((entry) => ({
 43        Date: entry.Date,
 44        zecIssuance: parseFloat(entry["ZEC  Supply"]),
 45        zecSupply: parseFloat(entry["ZEC  Supply"]),
 46        inflation: parseFloat(entry["Current Inflation (%)"]),
 47      }));
 48  
 49      return parsed;
 50    } catch {
 51      return null;
 52    }
 53  }
 54  
 55  export async function getZcashCirculationCount(
 56    url: string,
 57    signal?: AbortSignal
 58  ): Promise<number | null> {
 59    try {
 60      const res = await fetch(url, {
 61        signal,
 62      });
 63      if (!res.ok) return null;
 64      const json = await res.json();
 65      return parseInt(json.chainSupply.chainValueZat, 10) * 1e-8;
 66    } catch {
 67      return null;
 68    }
 69  }
 70  
 71  export async function getSupplyData(
 72    url: string,
 73    signal?: AbortSignal
 74  ): Promise<SupplyData[]> {
 75    try {
 76      const res = await fetch(url, {
 77        signal,
 78      });
 79      if (!res.ok) return [];
 80      return (await res.json()) as SupplyData[];
 81    } catch {
 82      return [];
 83    }
 84  }
 85  
 86  export async function getLastUpdatedDate(
 87    url: string,
 88    signal?: AbortSignal
 89  ): Promise<string> {
 90    try {
 91      const res = await fetch(url, {
 92        signal,
 93      });
 94      if (!res.ok) return "N/A";
 95      const d = await res.json();
 96  
 97      console.log("djson", d);
 98      return d[0]?.commit?.committer?.date ?? "N/A";
 99    } catch {
100      return "N/A";
101    }
102  }
103  
104  export function getCommitUrlForTab(tabLabel: string): string {
105    const urlMap: Record<string, string> = {
106      "total supply": DATE_URL.namadaSupplyUrl,
107      "Shielded Supply": DATE_URL.namadaSupplyUrl,
108      "transparant supply": DATE_URL.namadaSupplyUrl,
109      rewards: DATE_URL.namadaRewardUrl,
110    };
111  
112    return urlMap[tabLabel] || DATE_URL.namadaSupplyUrl;
113  }
114  
115  export async function getShieldedTxCount(
116    url: string,
117    signal?: AbortSignal
118  ): Promise<ShieldedTxCount[] | null> {
119    try {
120      const res = await fetch(url, {
121        signal,
122      });
123      if (!res.ok) return null;
124      return (await res.json()) as ShieldedTxCount[];
125    } catch {
126      return null;
127    }
128  }
129  
130  export async function getNodeCountData(
131    url: string,
132    signal?: AbortSignal
133  ): Promise<NodeCountData[]> {
134    try {
135      const res = await fetch(url, {
136        signal,
137      });
138      if (!res.ok) return [];
139      return (await res.json()) as NodeCountData[];
140    } catch {
141      return [];
142    }
143  }
144  
145  export async function getLockboxData(
146    url: string,
147    signal?: AbortSignal
148  ): Promise<LockBox[]> {
149    try {
150      const res = await fetch(url, { signal });
151  
152      if (!res.ok) {
153        console.warn(`Fetch failed: ${res.status} ${res.statusText}`);
154        return [];
155      }
156  
157      const data: any[] = await res.json();
158      return data;
159    } catch (err: any) {
160      if (err.name === "AbortError") {
161        console.warn("Fetch aborted.");
162      } else {
163        console.error(err.message || err);
164      }
165      return [];
166    }
167  }
168  export async function getNetInOutflowData(
169    url: string,
170    signal?: AbortSignal
171  ): Promise<NetInOutflow[]> {
172    try {
173      const res = await fetch(url, { signal });
174  
175      if (!res.ok) {
176        console.warn(`Fetch failed: ${res.status} ${res.statusText}`);
177        return [];
178      }
179  
180      const data: any[] = await res.json();
181      return data;
182    } catch (err: any) {
183      if (err.name === "AbortError") {
184        console.warn("Fetch aborted.");
185      } else {
186        console.error(err.message || err);
187      }
188      return [];
189    }
190  }
191  export async function getDifficultyData(
192    url: string,
193    signal?: AbortSignal
194  ): Promise<Difficulty[]> {
195    try {
196      const res = await fetch(url, { signal });
197  
198      if (!res.ok) {
199        console.warn(`Fetch failed: ${res.status} ${res.statusText}`);
200        return [];
201      }
202  
203      const data: any[] = await res.json();
204      return data;
205    } catch (err: any) {
206      if (err.name === "AbortError") {
207        console.warn("Fetch aborted.");
208      } else {
209        console.error(err.message || err);
210      }
211      return [];
212    }
213  }
214  
215  export async function getNamadaSupply(
216    url: string,
217    signal?: AbortSignal
218  ): Promise<any[]> {
219    try {
220      const res = await fetch(url, { signal });
221  
222      if (!res.ok) {
223        console.warn(`Fetch failed: ${res.status} ${res.statusText}`);
224        return [];
225      }
226  
227      const data: any[] = await res.json();
228      return data;
229    } catch (err: any) {
230      if (err.name === "AbortError") {
231        console.warn("Fetch aborted.");
232      } else {
233        console.error("Error fetching Namada supply:", err.message || err);
234      }
235      return [];
236    }
237  }
238  
239  export async function fetchTransactionData(
240    url: string
241  ): Promise<Array<ShieldedTransactionDatum>> {
242    const response = await fetch(url);
243    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
244    return await response.json();
245  }
246  /**
247   * Loads the historic shielded pool data from a public json file in Github repo
248   * @returns Promise of shielded pool data
249   */
250  export async function fetchShieldedSupplyData(
251    url: string,
252    signal?: AbortSignal
253  ): Promise<Array<ShieldedAmountDatum>> {
254    const response = await fetch(url);
255    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
256    return await response.json();
257  }
258  
259  export function formatDate(s: string | null): string {
260    if (!s) return "N/A";
261    const d = new Date(s);
262    return isNaN(d.getTime()) ? "N/A" : d.toLocaleDateString();
263  }
264  
265  export function transformSupplyData(
266    d: SupplyData | null
267  ): { timestamp: string; supply: number } | null {
268    return d ? { timestamp: d.close, supply: d.supply } : null;
269  }
270  
271  export type PoolType = "sprout" | "sapling" | "orchard";
272  export const getColorForPool = (poolKey: PoolType): string => {
273    switch (poolKey) {
274      case "sprout":
275        return "hsl(var(--chart-1))";
276      case "sapling":
277        return "hsl(var(--chart-2))";
278      case "orchard":
279        return "hsl(var(--chart-3))";
280      default:
281        return "#999999"; // fallback gray
282    }
283  };
284  
285  export function formatNumberShort(num: number): string {
286    const absNum = Math.abs(num);
287    const sign = num < 0 ? "-" : "";
288  
289    if (absNum >= 1_000_000_000)
290      return `${sign}${(absNum / 1_000_000_000).toFixed(1)}B`;
291    if (absNum >= 1_000_000) return `${sign}${(absNum / 1_000_000).toFixed(1)}M`;
292    if (absNum >= 1_000) return `${sign}${(absNum / 1_000).toFixed(1)}k`;
293  
294    return `${sign}${absNum.toLocaleString()}`;
295  }