Created
February 15, 2024 00:49
-
-
Save NathBabs/4a1041ff58af94444f6abb6c7021859f to your computer and use it in GitHub Desktop.
General Utilities
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fs from "fs"; | |
import path from "path"; | |
import crypto from "crypto"; | |
import GoogleLibPhone from "google-libphonenumber"; | |
import moment from "moment"; | |
/** | |
* get date instance by timezone | |
* @param date | |
* @param timeZone | |
* @returns {Date} | |
*/ | |
export const dateInstanceByTimeZone = ({ date, timeZone = "Africa/Lagos" }) => | |
new Date( | |
(typeof date === "string" | |
? new Date(date) | |
: date || new Date() | |
).toLocaleString("en-US", { | |
timeZone, | |
}) | |
); | |
export const convertToBase64 = (value: string) => { | |
const buffer = Buffer.from(value); | |
return buffer.toString("base64"); | |
}; | |
export const formatMorningDate = (date: string): string => | |
`${date}T00:00:00.000Z`; | |
export const formatNightDate = (date: string): string => | |
`${date}T23:59:00.000Z`; | |
export const genPassword = (length) => | |
Math.round(36 ** length + 1 - Math.random() * 36 ** length) | |
.toString(36) | |
.slice(1); | |
export const getMainWallet = (stores) => { | |
// eslint-disable-next-line no-restricted-syntax | |
for (const store of stores) { | |
const wallets = store.wallet; | |
const main = wallets.find((wallet) => wallet.type === "MAIN"); | |
if (main) { | |
return main; | |
} | |
} | |
return null; | |
}; | |
export const hash512 = (data: string) => { | |
const hash = crypto.createHash("sha512"); | |
const updatedHash = hash.update(data, "utf-8"); | |
return updatedHash.digest("hex"); | |
}; | |
export const transformValueToArrayLowercase = (object) => | |
Object.values(object).map((data) => data.toLocaleLowerCase()); | |
// sample format :Sun Dec 01 00:00:00 GMT+01:00 2017 | |
export const formatDate = (dateInString) => { | |
const dateInstance = new Date(dateInString); | |
const dateByZone = dateInstanceByTimeZone({ date: dateInstance }); | |
const date = `${dateByZone}` | |
.replace("(West Africa Standard Time)", "") | |
.trim(); | |
const dateArr = date.split(" "); | |
return `${dateArr[0]} ${dateArr[1]} ${dateArr[2]} 00:00:00 GMT+01:00 ${dateArr[3]}`; | |
}; | |
const phoneUtil = GoogleLibPhone.PhoneNumberUtil.getInstance(); | |
const PNF = GoogleLibPhone.PhoneNumberFormat; | |
export const validatePhone = ({ phone, countryCode = "NG" }) => { | |
const formatPhoneNumber = phoneUtil.parse(phone, countryCode); | |
const isValid = phoneUtil.isValidNumber(formatPhoneNumber); | |
if (!isValid) { | |
throw new Error(`Phone number ${phone} is not valid`); | |
} | |
return phoneUtil.format(formatPhoneNumber, PNF.INTERNATIONAL); | |
}; | |
export const numberOfDaysDiff = ({ startDate, endDate }) => { | |
const date1 = new Date(startDate).getTime(); | |
const date2 = new Date(endDate).getTime(); | |
const dateDiff = date2 - date1; | |
return dateDiff / (1000 * 3600 * 24); | |
}; | |
export const checkIfMonthIsWithinRange = ( | |
startDate, | |
endDate, | |
limit | |
): Boolean => { | |
const diff = numberOfDaysDiff({ startDate, endDate }); | |
return Math.floor(diff / 30) <= limit; | |
}; | |
export const capitalize = (s) => { | |
if (typeof s !== "string") return ""; | |
return s.charAt(0).toUpperCase() + s.slice(1); | |
}; | |
export const getPastTimeInMilli = (minutesToAdd: number) => { | |
const currentDate = Date.now(); | |
return currentDate - minutesToAdd * 60000; | |
}; | |
export const encodeBase64 = (data) => Buffer.from(data).toString("base64"); | |
export const DecodeBase64 = (data) => | |
Buffer.from(data, "base64").toString("ascii"); | |
export const friendlyDate = (date) => { | |
const almostNow = moment(date, "YYYYMMDD"); | |
return almostNow.fromNow(); | |
}; | |
export const morning = () => { | |
const fromDate = new Date(); | |
fromDate.setHours(0, 0, 0, 0); | |
return fromDate; | |
}; | |
export const formatDateByFormat = ({ date, format }) => | |
moment(date).format(format || "YYYY-MM-DD"); | |
export const getCurrentDate = (format) => { | |
const date = morning(); | |
return moment(date).format(format || "YYYY-MM-DD"); | |
}; | |
export const twoDaysAgo = () => { | |
const formattedDate = moment().tz("Africa/Lagos"); | |
return formattedDate.subtract(2, "day").valueOf(); | |
}; | |
export const generateKey = () => { | |
const primeLength = 200; | |
const diffHell = crypto.createDiffieHellman(primeLength); | |
diffHell.generateKeys("base64"); | |
const secretKey = diffHell.getPrivateKey("hex"); | |
return `GRUPPSECK_${secretKey}`; | |
}; | |
export const getFileContent = (fileName: string) => | |
fs.readFileSync(path.join(__dirname, fileName), "utf8"); | |
/** | |
* Function to get the past 12 months, starting from the current month | |
* | |
*/ | |
export const getPast12Months = () => { | |
const today = new Date(); | |
const months = []; | |
for (let i = 0; i < 12; i += 1) { | |
const firstDay = new Date(today.getFullYear(), today.getMonth() - i, 1); | |
const tmp = firstDay.toISOString().split("T")[0]; | |
const lastDay = new Date(today.getFullYear(), today.getMonth() - i + 1, 0) | |
.toISOString() | |
.split("T")[0]; | |
const month = firstDay.toLocaleString("default", { month: "long" }); | |
months.push({ firstDay: tmp, lastDay, month }); | |
} | |
return months; | |
}; | |
// get past 7 days starting from today and label them with the day of the week with the date | |
export const getPast7Days = () => { | |
const today = new Date(); | |
const days = []; | |
for (let i = 0; i < 7; i += 1) { | |
const day = new Date( | |
today.getFullYear(), | |
today.getMonth(), | |
today.getDate() - i | |
); | |
const dayOfWeek = day.toLocaleString("default", { weekday: "short" }); | |
const date = moment(day).format("YYYY-MM-DD"); | |
days.push({ dayOfWeek, date }); | |
} | |
return days; | |
}; | |
// get days within range of startDate and endDate labeled with the day of the week with the date | |
/** | |
* | |
* @param {{startDate: Date, endDate: Date}} param0 | |
* @returns | |
*/ | |
export const getDaysWithinRange = ({ startTime, endTime }) => { | |
const days = []; | |
const start = new Date(startTime); | |
const end = new Date(endTime); | |
const diff = end.getTime() - start.getTime(); | |
const daysDiff = Math.floor(diff / (1000 * 3600 * 24)); | |
for (let i = 0; i < daysDiff; i += 1) { | |
const day = new Date( | |
start.getFullYear(), | |
start.getMonth(), | |
start.getDate() + i | |
); | |
const dayOfWeek = day.toLocaleString("default", { weekday: "short" }); | |
const date = moment(day).format("YYYY-MM-DD"); | |
days.push({ dayOfWeek, date }); | |
} | |
return days; | |
}; | |
// get begining and end of each month within a time range even across years including the current month | |
// get begining and end of each month within a time range even across years including the current month | |
export const getMonthsWithinRange = (startDate, endDate) => { | |
const months = []; | |
const start = moment(startDate); | |
const end = moment(endDate).add(1, "month"); | |
const current = moment(start); | |
while (current <= end) { | |
const firstDay = current.startOf("month"); | |
const lastDay = current.endOf("month"); | |
const month = firstDay.format("MMMM"); // toLocaleString("default", { month: "long" }); | |
months.push({ | |
firstDay: firstDay.format("YYYY-MM-01"), | |
lastDay: lastDay.format("YYYY-MM-DD"), | |
month, | |
}); | |
current.add(1, "month"); | |
} | |
return months; | |
}; | |
/** | |
* A Function that formats the data for the monthly summary and returns | |
* an array of objects, containing the date, value, and volume property | |
* @param data | |
* @returns {{date: String, value: Number, volume: Number}[]} | |
* | |
*/ | |
export const formatTimeTransaction = (data) => { | |
const formattedData = []; | |
data.forEach((time) => { | |
formattedData.push({ | |
date: time.date, | |
value: time.data.totalValue.value, | |
volume: time.data.aggs.value, | |
}); | |
}); | |
return formattedData; | |
}; | |
// calculate percentage change in volume | |
/** | |
* Function that calculates the percentage change in volume. | |
* The array must be reversed, because the current month is at the first | |
* index, which will mean you'll be calculating percentage change backward. | |
* @param {*} data | |
* @returns {{date: String, value: Number, volume: Number, percentageChange: String}[]} | |
*/ | |
export const calculatePercentageChange = (data) => { | |
const formattedData = []; | |
data.forEach((month) => { | |
const previousMonth = data[data.indexOf(month) - 1]; | |
let percentageChange = "0.00%"; | |
if (previousMonth) { | |
if (previousMonth.volume === 0) { | |
if (month.volume > 0) { | |
percentageChange = "100.00%"; | |
formattedData.push({ | |
date: month.date, | |
volume: month.volume, | |
value: month.value, | |
percentageChange, | |
dayOfWeek: month?.dayOfWeek, | |
}); | |
return; | |
} | |
percentageChange = "0.00%"; | |
formattedData.push({ | |
date: month.date, | |
volume: month.volume, | |
value: month.value, | |
percentageChange, | |
dayOfWeek: month?.dayOfWeek, | |
}); | |
return; | |
} | |
const currentChangeInPercentage = ( | |
((month.value - previousMonth.value) / previousMonth.value) * | |
100 | |
).toFixed(2); | |
percentageChange = `${Math.abs(currentChangeInPercentage)}%`; | |
} else { | |
percentageChange = "0.00%"; | |
} | |
formattedData.push({ | |
date: month.date, | |
volume: month.volume, | |
value: month.value, | |
percentageChange, | |
dayOfWeek: month?.dayOfWeek, | |
}); | |
}); | |
return formattedData; | |
}; | |
/** | |
* recursive function to flatten an object to dot notation | |
* e.g {bio: { name: "James", age: 12, gender: "male" }} becomes | |
* { bio.name: "James", bio.age: 12, bio.gender: "male" } | |
* {@link https://stackoverflow.com/questions/44134212} | |
* @param {*} ob | |
* @param {*} prefix | |
* @param {*} result | |
* @returns | |
*/ | |
export function dotify(ob, prefix = false, result = null) { | |
const finalResult = result || {}; | |
// Preserve empty objects and arrays, they are lost otherwise | |
if ( | |
prefix && | |
typeof ob === "object" && | |
ob !== null && | |
Object.keys(ob).length === 0 | |
) { | |
finalResult[prefix] = Array.isArray(ob) ? [] : {}; | |
return finalResult; | |
} | |
const prefixChar = prefix ? `${prefix}.` : ""; | |
const keys = Object.keys(ob); | |
const values = Object.values(ob); | |
for (let i = 0; i < keys.length; i += 1) { | |
if (Object.prototype.hasOwnProperty.call(values, i)) { | |
if (typeof values[i] === "object" && values[i] !== null) { | |
// Recursion on deeper objects | |
dotify(values[i], prefixChar + keys[i], finalResult); | |
} else { | |
finalResult[prefixChar + keys[i]] = values[i]; | |
} | |
} | |
} | |
return finalResult; | |
} | |
export const getLastThreeMonth = () => { | |
const date = new Date(); | |
date.setMonth(date.getMonth() - 3); | |
date.setDate(1); | |
return formatDateByFormat({ date }); | |
}; | |
export const getLastSeventhDate = () => { | |
const date = new Date(); | |
date.setDate(date.getDate() - 7); | |
return formatDateByFormat({ date }); | |
}; | |
// duration is assumed to be of this format yyyy-mm-dd | |
export const getFirstAndLastDateOfTheMonth = ({ duration }) => { | |
const tonight = formatMorningDate(duration); | |
const date = new Date(tonight); | |
const startDate = new Date(date.getTime()); | |
const endDate = new Date(date.getTime()); | |
endDate.setMonth(endDate.getMonth() + 1); | |
return { startDate, endDate }; | |
}; | |
export const isDateValid = ({ date }) => { | |
const dateInstance = new Date(date); | |
return dateInstance instanceof Date && !Number.isNaN(dateInstance); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment