Skip to content

Instantly share code, notes, and snippets.

@jsuryahyd
Last active August 17, 2023 06:44
Show Gist options
  • Save jsuryahyd/8388967a2d3c5a43dc9990bb81d449c6 to your computer and use it in GitHub Desktop.
Save jsuryahyd/8388967a2d3c5a43dc9990bb81d449c6 to your computer and use it in GitHub Desktop.
Utils
export function uniqueItems(objArray, key) {
if (!objArray || !key) {
console.error("no args", objArray, key);
return objArray;
}
return objArray.reduce((result, obj) => {
if (result.find((o) => o[key] == obj[key])) {
return result;
}
return [...result, obj];
}, []);
}
export function string_to_slug(str = "", separator = "-") {
if (!str) return str;
str = str.trim();
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
const from = "åàáãäâèéëêìíïîòóöôùúüûñç·/_,:;";
const to = "aaaaaaeeeeiiiioooouuuunc------";
for (let i = 0, l = from.length; i < l; i++) {
str = str.replace(new RegExp(from.charAt(i), "g"), to.charAt(i));
}
return str
.replace(/[^a-z0-9 -]/g, "") // remove invalid chars
.replace(/\s+/g, "-") // collapse whitespace and replace by -
.replace(/-+/g, "-") // collapse dashes
.replace(/^-+/, "") // trim - from start of text
.replace(/-+$/, "") // trim - from end of text
.replace(/-/g, separator);
}
/**
*
* @param {{}|[]} obj
* @returns {({}|[])} obj
*/
export function cloneObject(obj) {
var clone = Array.isArray(obj) ? [] : {};
for (var i in obj) {
if (obj[i] != null && typeof obj[i] == "object")
clone[i] = cloneObject(obj[i]);
else clone[i] = obj[i];
}
return clone;
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
function deepFreeze(object) {
// Retrieve the property names defined on object
const propNames = Object.getOwnPropertyNames(object);
// Freeze properties before freezing self
for (const name of propNames) {
const value = object[name];
if (value && typeof value === "object") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
/**
* @description adds a unique_id key if the objects in array doesnot have id key.
* @param {Object[]} listOfObjects
*/
export function addIdKey(listOfObjects, keyName = "id") {
return listOfObjects.map((i, idx) => ({
...i,
[keyName]: i[keyName] || new Date().getTime() + "" + getUniqueNumber() + ""+ Math.random(),
}));
}
/**
* https://stackoverflow.com/a/49860927/7314900
* @param {HTMLElement|Element} element
* @param {("top"|"bottom"|"left"|"right")} direction
* todo: direction should be calculated basing on its position and offset inparent.
*/
export function scrollToTargetWithOffset(element, direction) {
var headerOffset = 30;
var elementPosition = element.getBoundingClientRect()[direction];
var offsetPosition = ["top", "left"].includes(direction)
? elementPosition - headerOffset
: elementPosition + headerOffset;
element.parentElement.scrollTo({
[direction]: offsetPosition,
behavior: "smooth",
});
}
export function sleep(ms = 500) {
return new Promise((resolve, reject) => {
let wait = setTimeout(() => {
clearTimeout(wait);
resolve("waited for atleast " + ms + " milliseconds");
}, ms);
});
}
export function downloadFileFromData(binaryData, fileName) {
const url = window.URL.createObjectURL(new Blob([binaryData]));
const link = document.createElement("a");
link.href = url;
//todo: set proper name
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
link.remove();
}
/*
https://stackoverflow.com/a/61613914/7314900
*/
export function reorder(array, sourceIndex, destinationIndex) {
const smallerIndex = Math.min(sourceIndex, destinationIndex);
const largerIndex = Math.max(sourceIndex, destinationIndex);
return [
...array.slice(0, smallerIndex),
...(sourceIndex < destinationIndex
? array.slice(smallerIndex + 1, largerIndex + 1)
: []),
array[sourceIndex],
...(sourceIndex > destinationIndex
? array.slice(smallerIndex, largerIndex)
: []),
...array.slice(largerIndex + 1),
];
}
export function getUniqueNumber() {
const u = (window.__UNIQUE_NUMBER__ =
(window.__UNIQUE_NUMBER__ || 0) + 1);
return u;
}
export function mapToLabelValue(d) {
if (!Array.isArray(d)) {
console.error("mapToLabelValue :not an array", d);
return [];
}
return d.map((d) => ({ value: d.id || d.value, label: d.name || d.label }));
}
export function getNestedValue(obj, path) {
// console.log(obj, path);
if (!obj) {
console.log("no object passed", obj);
return null;
}
if (!path) {
// console.log("no path", obj);
return obj;
}
const properties = typeof path == "string" ? path.split(".") : path;
return getNestedValue(obj[properties.shift()], properties.join("."));
}
/**
* https://stackoverflow.com/a/46008856/7314900
* Dynamically sets a deeply nested value in an object.
* Optionally "bores" a path to it if its undefined.
* @function
* @param {!object} obj - The object which contains the value you want to change/set.
* @param {!array|string} path - The array representation of path to the value you want to change/set.
* @param {!mixed} value - The value you want to set it to.
* @param {boolean} setrecursively - If true, will set value of non-existing path as well.
*/
export function setDeep(
obj,
path,
value,
setrecursively = false,
returnObj = true
) {
obj = JSON.parse(JSON.stringify(obj));
if (typeof path == "string") path = path.split(".");
path.reduce((a, b, level) => {
if (
setrecursively &&
typeof a[b] === "undefined" &&
level !== (path.length-1)
) {
a[b] = {};
return a[b];
}
if (level === (path.length-1)) {
a[b] = value;
return value;
}
return a[b];
}, obj);
if (returnObj) {
return obj;
}
}
// https://stackoverflow.com/a/59590002/7314900
export function camelToTitleCase(str) {
return str
.replace(/[0-9]{2,}/g, match => ` ${match} `)
.replace(/[^A-Z0-9][A-Z]/g, match => `${match[0]} ${match[1]}`)
.replace(/[A-Z][A-Z][^A-Z0-9]/g, match => `${match[0]} ${match[1]}${match[2]}`)
.replace(/[ ]{2,}/g, match => ' ')
.replace(/\s./g, match => match.toUpperCase())
.replace(/^./, match => match.toUpperCase())
.trim();
}
//https://stackoverflow.com/a/46790470
export function replaceOccurrence(string, regex, n, replace) {
var i = 0;
return string.replace(regex, function(match) {
i+=1;
if(i===n) return replace;
return match;
});
}
export function getMinSecHrs(milliseconds) {
if (milliseconds <= 0) {
return {
sec: 0,
min: 0,
hrs: 0,
};
}
const ms = Math.floor((milliseconds % 1000) / 100),
sec = Math.floor((milliseconds / 1000) % 60),
min = Math.floor((milliseconds / (1000 * 60)) % 60),
hrs = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);
return {
min,
sec,
hrs,
ms
};
}
export function padNumber(number, len = 2) {
return '0'.repeat(Math.max(len - (number + '').length,0)) + number;
}
/**
*
* @param {string} path
* @param {T} obj
* @returns {T} deep copied obj
* @description requires getPathArr method defined below.
*/
function removeAt(path, obj) {
const pathSegments = getPathArr(path)
const _obj = lodashCloneDeep(obj)
let target = _obj
while (pathSegments.length > 1) {
const _path = pathSegments.shift()
target = target[_path]
}
if (!target) {
console.error('no target', path, obj)
return _obj
}
if (Array.isArray(target)) {
target.splice(pathSegments[0], 1)
} else {
delete target[pathSegments[0]]
}
return _obj
}
/**
*
* @param {string} pathStr takes in the format of `conditions[0].name` and gives ['conditions',0,'name']
* @returns {(string|number)[]}
*/
function getPathArr(pathStr) {
let result = []
let segment = ''
let isNumberSeg = false
for (let i = 0; i < pathStr.length; i++) {
const char = pathStr[i]
if (char === '.') {
segment.length && result.push(segment)
segment = ''
} else if (char === '[') {
segment.length && result.push(segment)
segment = ''
isNumberSeg = true
} else if (char === ']') {
segment.length && result.push(Number(segment))
isNumberSeg = false
segment = ''
} else {
segment += char
}
}
segment.length && result.push(segment) //last segment will not be delimited with .,[,] etc
return result
}
const { inspect: Inspect } = require("util");
const { errorLog } = require("./logger");
const util = require("util");
const bcrypt = require("bcryptjs");
const Request = require("request");
class Utils {
async getHashedPwd(pwd) {
if (!pwd) {
throw "no pwd string given for hashing";
}
let saltErr;
const salt = await bcrypt.genSalt(10).catch(err => (saltErr = err));
if (!salt || saltErr) {
throw (saltErr || {}).message || "Error while generating Salt";
}
let hashErr;
const hash = await bcrypt.hash(pwd, salt).catch(err => (hashErr = err));
if (hashErr) throw (hashErr || {}).message;
return hash;
}
containsSpecialCharacters(str) {
if (!str) errorLog.error("no string given for special characters check");
return new RegExp(/[0-9-!$%^&\*\(\)_\+|~=`\{\}\[\]:\/;<>?,.@#]+/g).test(
str
);
}
/**
* comparePwd
*/
async comparePwd(inputPwd, hashedPwdFromDb) {
if (!inputPwd || !hashedPwdFromDb) {
errorLog.error("undefined params" + arguments);
}
return await bcrypt.compare(inputPwd, hashedPwdFromDb);
}
toCapitalCase(str) {
return str[0].toUpperCase() + str.substring(1).toLowerCase();
}
//get key in the dict that have the given value
mapKey(map, value) {
for (var i in map) {
if (map[i] === value) {
return i;
}
}
}
tokenGenerator(l) {
if (!l) l = 32;
let text = "";
let possible = "abcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < l; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
otpGenerator(length) {
length = length || 6;
let text = "";
let possible = "0123456789";
for (let i = 0; i < length; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
//sdk|api specific to the service provider
sendMessage(phone, message) {
return new Promise((resolve, reject) => {
if (!message) {
return reject(new Error("Missing data" + Inspect(arguments)));
}
process.env.ENV == "DEVELOPMENT"
? resolve("6666666")
: Request.get(
{
url: encodeURI(
`${process.env.SMS_GATEWAY_URL}?User=${process.env.SMS_GATEWAY_USERNAME}&passwd=${process.env.SMS_GATEWAY_PASSWORD}&mobilenumber=${phone}&message=${message}&DR=Y&mtype=LNG`
) //type=lng required for non-english characters
},
(err, response, body) => {
if (err) return reject(err);
if (!body.startsWith("OK:")) {
return reject(body);
}
resolve(body.split("OK:")[1]);
}
);
});
}
/**
* deep objectCompare
* @link https://gist.github.com/nicbell/6081098
*/
objectCompare(obj1, obj2) {
//Loop through properties in object 1
for (var p in obj1) {
//Check property exists on both objects
if (
Object.prototype.hasOwnProperty.call(obj1, p) !==
Object.prototype.hasOwnProperty.call(obj2, p)
)
return false;
switch (typeof obj1[p]) {
//Deep compare objects
case 'object':
if (!objectCompare(obj1[p], obj2[p])) return false;
break;
//Compare function code
case 'function':
if (
typeof obj2[p] == 'undefined' ||
obj1[p].toString() != obj2[p].toString()
)
return false;
break;
//Compare values
default:
if (obj1[p] != obj2[p]) return false;
}
}
//Check object 2 for any extra properties
for (var v in obj2) {
if (typeof obj1[v] == 'undefined') return false;
}
return true;
}
cloneObject(obj) {
var clone = {};
for(var i in obj) {
if(obj[i] != null && typeof(obj[i])=="object")
clone[i] = cloneObject(obj[i]);
else
clone[i] = obj[i];
}
return clone;
}
phoneValidationError(val) {
let err =
!val ||
val.length < 6 ||
val.length > 16 ||
!new RegExp(/^[0-9]+$/).test(val) //new RegExp(/^[\+-]{0,1}[0-9]+$/)
? "Please input valid Phone Number"
: null;
return err;
}
emailValidationError(email) {
if (!email) return "Enter Email.";
let valid = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);
if (!valid) return "Enter a valid Email";
return undefined;
}
until(promiseOrPromiseList) {
//array of promises
if (Array.isArray(promiseOrPromiseList)) {
return Promise.all(promiseOrPromiseList)
.then(data => {
return [null, data];
})
.catch(err => {
return [err,promiseOrPromiseList.map(p=>undefined)];
});
}
//single promise call
return promiseOrPromiseList
.then(data => {
// console.log(data);
return [null, data];
})
.catch(err => {
// console.log(err)
return [err];
});
}
getPromisifiedConnection(pool) {
return util.promisify(pool.getConnection).bind(pool);
}
getPromisifiedBeginTransaction(connection) {
return util.promisify(connection.beginTransaction.bind(connection));
}
getPromisifiedQuery(connection) {
util.promisify((sql, options, cb) =>
connection.query(sql, options, (err, results) => cb(err, results))
);
}
getPromisifiedRollBack(connection) {
util.promisify(connection.rollback.bind(connection));
}
getPromisifiedCommit(connection) {
util.promisify(connection.commit.bind(connection));
}
/**
*
* @param {import('mysql').Pool} pool
*
* @typedef {object} dbFuncs
* @property {import('mysql').PoolConnection} connection
* @property {import('mysql').Pool} pool
// * @property {Promise<import('mysql').Pool>}
*
* @returns {dbFuncs} dbFunctions
*
*/
async getPromisifiedDbFuncs(pool) {
const getConnection = util.promisify(pool.getConnection).bind(pool);
/** @type {import('mysql').PoolConnection} */
const connection = await getConnection().catch(
/** @type {import('mysql').MysqlError} */ err => errorLog.error(err)
);
if (!connection) throw new Error("could not get pool connection");
//bindings are important.
const beginTransactionPromise = util.promisify(
connection.beginTransaction.bind(connection)
);
// const queryPromise = util.promisify(connection.query.bind(connection));
const queryPromise = util.promisify((sql, options, cb) =>
connection.query(sql, options, function(err, results) {
cb(err, results);
// console.log(this.sql)
})
);
const rollBackPromise = util.promisify(
connection.rollback.bind(connection)
);
const commitPromise = util.promisify(connection.commit.bind(connection));
return {
beginTransactionPromise,
queryPromise,
rollBackPromise,
commitPromise,
connection,
pool
};
}
imgPathValidation(val, { req, location, path }) {
const imageName = val.split("/").reverse()[0];
if (!imageName) {
throw new Error("Invalid Image Uri");
}
if (
!["jpg", "jpeg", "webp", "gif", "png"].includes(
imageName.split(".").reverse()[0]
)
) {
throw new Error(
"Invalid file type. Please upload an image for category picture"
);
}
return true;
}
countDownTimer(element,endTime){
const milliseconds = endTime - Date.now();
if (milliseconds <= 0) {
element.textContent =
'Temporary Mail expired. Generate again';
return clearInterval(timerRef.current);
}
const min = Math.floor(milliseconds / 60000);
const sec = ((milliseconds % 60000) / 1000).toFixed(0);
element.textContent = `${
sec === 60 ? min + 1 : min
} min ${
sec === 60 ? '00' : sec < 10 ? '0' + sec : sec
} sec remaining`;
}
}
module.exports = new Utils();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment