CatPtain's picture
Upload 100 files
ccefd0b verified
import { rankItem } from "@tanstack/match-sorter-utils";
import domtoimage from "dom-to-image";
export function formatNumberNoMagnitude(value: number | string) {
if (typeof value === "string") {
const suffix = value.replace(/[^a-zA-Z]/g, "").trim();
const magnitude = ["", "K", "M", "B", "T"].indexOf(
suffix.replace(/\s/g, ""),
);
value =
Number(value.replace(/[^0-9.]/g, "").trim()) *
Math.pow(10, magnitude * 3);
}
return value;
}
export function formatNumberMagnitude(value: number | string, column?: string) {
if (typeof value === "string") {
value = Number(formatNumberNoMagnitude(value));
}
if (value % 1 !== 0) {
const decimalPlaces = Math.max(
2,
value.toString().split(".")[1]?.length || 0,
);
const toFixed = Math.min(4, decimalPlaces);
if (value < 5) {
return value.toFixed(toFixed) || 0;
}
value = Number(value.toFixed(2));
}
if (
(value > 100_000 || value < -100_000) &&
!includesPriceNames(column || "")
) {
const magnitude = Math.min(4, Math.floor(Math.log10(Math.abs(value)) / 3));
const suffix = ["", "K", "M", "B", "T"][magnitude];
const formatted = (value / 10 ** (magnitude * 3)).toFixed(3);
return `${formatted.replace(/\.?0+$/, "")} ${suffix}`;
}
if (value > 1000 || value < -1000) return formatNumber(value);
return value;
}
export function formatNumber(value: number) {
if (value > 1000 || value < -1000) {
const parts = value.toString().split(".");
const integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const decimalPart = parts[1] ? `.${parts[1]}` : "";
return `${integerPart}${decimalPart}`;
}
return value;
}
export function includesDateNames(column: string) {
return ["date", "day", "time", "timestamp", "year"].some((dateName) =>
column?.toLowerCase().includes(dateName),
);
}
export function includesPriceNames(column: string) {
return ["price", "open", "close"].some((priceName) =>
column?.toLowerCase().includes(priceName),
);
}
function loadingOverlay(message?: string, is_close?: boolean) {
const loading = window.document.getElementById("loading") as HTMLElement;
const loading_text = window.document.getElementById(
"loading_text",
) as HTMLElement;
return new Promise((resolve) => {
if (is_close) {
loading.classList.remove("show");
} else {
// @ts-ignore
loading_text.innerHTML = message;
loading.classList.add("show");
}
const is_loaded = setInterval(function () {
if (
is_close
? !loading.classList.contains("show")
: loading.classList.contains("show")
) {
clearInterval(is_loaded);
resolve(true);
}
}, 0.01);
});
}
export function isEqual(a: any, b: any) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a?.length !== b?.length) return false;
for (let i = 0; i < a?.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
export const fuzzyFilter = (
row: any,
columnId: string,
value: string,
addMeta: any,
): any => {
const itemRank = rankItem(row.getValue(columnId), value);
addMeta(itemRank);
return itemRank;
};
const exportNativeFileSystem = async ({
fileHandle,
blob,
}: {
fileHandle?: FileSystemFileHandle | null;
blob: Blob;
}) => {
if (!fileHandle) {
return;
}
await writeFileHandler({ fileHandle, blob });
};
const writeFileHandler = async ({
fileHandle,
blob,
}: {
fileHandle: FileSystemFileHandle;
blob: Blob;
}) => {
const writer = await fileHandle.createWritable();
await writer.write(blob);
await writer.close();
};
const IMAGE_TYPE: FilePickerAcceptType[] = [
{
description: "PNG Image",
accept: {
"image/png": [".png"],
},
},
{
description: "JPEG Image",
accept: {
"image/jpeg": [".jpeg"],
},
},
];
const getNewFileHandle = ({
filename,
is_image,
}: {
filename: string;
is_image?: boolean;
}): Promise<FileSystemFileHandle | null> => {
try {
if ("showSaveFilePicker" in window) {
const opts: SaveFilePickerOptions = {
suggestedName: filename,
types: is_image
? IMAGE_TYPE
: [
{
description: "CSV File",
accept: {
"image/csv": [".csv"],
},
},
],
excludeAcceptAllOption: true,
};
return showSaveFilePicker(opts);
}
} catch (error) {
console.error(error);
}
return new Promise((resolve) => {
resolve(null);
});
};
export const saveToFile = (
blob: Blob,
fileName: string,
fileHandle?: FileSystemFileHandle,
) => {
try {
if (fileHandle === null) {
throw new Error("Cannot access filesystem");
}
exportNativeFileSystem({ fileHandle, blob });
} catch (error) {
console.error("oops, something went wrong!", error);
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.setAttribute("href", url);
link.setAttribute("download", fileName);
link.style.visibility = "hidden";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
return new Promise((resolve) => {
resolve(true);
});
};
export async function downloadData(
type: "csv",
columns: any,
data: any,
downloadFinished: (changed: boolean) => void,
) {
const headers = columns;
const rows = data.map((row: any) =>
headers.map((column: any) => row[column]),
);
const csvData = [headers, ...rows];
if (type === "csv") {
const csvContent = csvData.map((e) => e.join(",")).join("\n");
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
const filename = `${window.title}.csv`;
try {
const fileHandle = await getNewFileHandle({
filename: filename,
});
let ext = "csv";
if (fileHandle !== null) {
// @ts-ignore
ext = fileHandle.name.split(".").pop();
}
await loadingOverlay(`Saving ${ext.toUpperCase()}`);
// @ts-ignore
non_blocking(async function () {
// @ts-ignore
saveToFile(blob, filename, fileHandle).then(async function () {
await new Promise((resolve) => setTimeout(resolve, 1500));
await loadingOverlay("", true);
if (!fileHandle) {
downloadFinished(true);
}
});
}, 2)();
} catch (error) {
console.error(error);
}
return;
}
}
export async function downloadImage(
id: string,
downloadFinished: (change: boolean) => void,
) {
const table = document.getElementById(id);
const filename = `${window.title}.png`;
try {
const fileHandle = await getNewFileHandle({
filename: filename,
is_image: true,
});
let extension = "png";
if (fileHandle !== null) {
// @ts-ignore
extension = fileHandle.name.split(".").pop();
}
await loadingOverlay(`Saving ${extension.toUpperCase()}`);
non_blocking(async function () {
// @ts-ignore
domtoimage.toBlob(table).then(function (blob: Blob) {
// @ts-ignore
saveToFile(blob, filename, fileHandle).then(async function () {
await new Promise((resolve) => setTimeout(resolve, 1500));
await loadingOverlay("", true);
if (!fileHandle) {
downloadFinished(true);
}
});
});
}, 2)();
} catch (error) {
console.error(error);
}
}
export const non_blocking = (func: Function, delay: number) => {
let timeout: number;
return function () {
// @ts-ignore
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
};