| 1 | import bytes from "bytes" |
| 2 | import { md5 } from "js-md5" |
| 3 | import _split from "lodash/split" |
| 4 | import _toNumber from "lodash/toNumber" |
| 5 | import dayjs from "@/utils/dayjs" |
| 6 | import { isTimestamp } from "@/utils/index" |
| 7 | |
| 8 | const COMMA_REGEX = /,/g |
| 9 | |
| 10 | export function formatBytes(val: string | number) { |
| 11 | return bytes(_toNumber(val)) |
| 12 | } |
| 13 | // Transform File Instance in base64 string |
| 14 | export function file2Base64(blob: Blob): Promise<string> { |
| 15 | return new Promise((resolve, reject) => { |
| 16 | const reader = new FileReader() |
| 17 | reader.readAsDataURL(blob) |
| 18 | reader.onload = () => resolve(reader.result as string) |
| 19 | reader.onerror = error => reject(error) |
| 20 | }) |
| 21 | } |
| 22 | |
| 23 | export function hashMD5(text: number | string) { |
| 24 | return md5(text.toString()) |
| 25 | } |
| 26 | |
| 27 | export function formatDate(date: Date | string | number, format: string) { |
| 28 | const parsedDate = isTimestamp(date, true) ?? date |
| 29 | |
| 30 | const dateJs = dayjs(parsedDate) |
| 31 | |
| 32 | if (!dateJs.isValid()) return date |
| 33 | |
| 34 | if (format === "x") { |
| 35 | return dateJs.valueOf() |
| 36 | } |
| 37 | |
| 38 | return dateJs.format(format) |
| 39 | } |
| 40 | |
| 41 | export function formatTimeAgo(date: Date | string | number, format: string) { |
| 42 | const timestamp = formatDate(date, "x") as number |
| 43 | |
| 44 | try { |
| 45 | const now = new Date() |
| 46 | const diffInMs = now.getTime() - timestamp |
| 47 | |
| 48 | const days = diffInMs / (1000 * 60 * 60 * 24) |
| 49 | |
| 50 | if (days < 30) { |
| 51 | return dayjs(timestamp).fromNow() |
| 52 | } else { |
| 53 | return formatDate(timestamp, format) |
| 54 | } |
| 55 | } catch { |
| 56 | return "Invalid date" |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | export function getNameInitials(name: string, cap?: number) { |
| 61 | let initials = name.slice(0, 2) |
| 62 | |
| 63 | if (name.includes(" ")) { |
| 64 | initials = name |
| 65 | .split(" ") |
| 66 | .map(chunk => chunk[0]) |
| 67 | .join() |
| 68 | } |
| 69 | |
| 70 | return (cap ? initials.slice(0, cap) : initials).toUpperCase() |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Converts a value to a boolean. |
| 75 | * Returns true if the value is "1" or "true", otherwise false. |
| 76 | * |
| 77 | * @param {string | boolean | number | null} [val] - The value to convert to boolean |
| 78 | * @returns {boolean} The resulting boolean value |
| 79 | * |
| 80 | * @example |
| 81 | * toBoolean("1") // true |
| 82 | * toBoolean("true") // true |
| 83 | * toBoolean("0") // false |
| 84 | * toBoolean(null) // false |
| 85 | */ |
| 86 | export function toBoolean(val?: string | boolean | number | null): boolean { |
| 87 | const cast = (val || 0).toString() |
| 88 | if (cast === "1") return true |
| 89 | if (cast === "true") return true |
| 90 | |
| 91 | return false |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Converts a string or number to a decimal number. |
| 96 | * Replaces commas with dots and properly handles decimal separators. |
| 97 | * |
| 98 | * @param {string | number} input - The value to convert to a number |
| 99 | * @returns {number} The converted number |
| 100 | * |
| 101 | * @example |
| 102 | * toNumber("123,45") // 123.45 |
| 103 | * toNumber("123.45") // 123.45 |
| 104 | * toNumber(123) // 123 |
| 105 | */ |
| 106 | export function toNumber(input: string | number): number { |
| 107 | return _toNumber(_split(`${input}`.replace(COMMA_REGEX, "."), ".", 2).join(".")) |
| 108 | } |