198 lines
4.5 KiB
TypeScript
198 lines
4.5 KiB
TypeScript
import {Prisma} from '@prisma/client'
|
||
import bcrypt from 'bcryptjs'
|
||
import {type ClassValue, clsx} from 'clsx'
|
||
import {getLocale} from 'next-intl/server'
|
||
import slugify from 'slugify'
|
||
import striptags from 'striptags'
|
||
import {twMerge} from 'tailwind-merge'
|
||
|
||
import {i18nDefaultLocale} from '@/i18n-config'
|
||
|
||
/**
|
||
* Just output dump using pretty output
|
||
*
|
||
* @param variable
|
||
*/
|
||
export function dump(variable: any): [string, string] {
|
||
return [
|
||
(new Error().stack?.split('\n')[2]?.trim().split(' ')[1] as string) + ' ',
|
||
JSON.stringify(variable, null, 2)
|
||
]
|
||
}
|
||
|
||
export const toPrice = (price: any) => parseFloat(price).toFixed(2)
|
||
|
||
/**
|
||
* Create fallback avatar for showing during login process or in case if empty
|
||
*
|
||
* @param name
|
||
*/
|
||
export const avatarFallback = (name: string): string =>
|
||
name
|
||
? name
|
||
.split(' ')
|
||
.slice(0, 2)
|
||
.map(w => w[0])
|
||
.join('')
|
||
.toUpperCase()
|
||
: 'U'
|
||
|
||
export function cn(...inputs: ClassValue[]) {
|
||
return twMerge(clsx(inputs))
|
||
}
|
||
|
||
/**
|
||
* Slugify the string based on locale using kebab case
|
||
*
|
||
* @param string
|
||
* @param locale
|
||
*/
|
||
export function slug(string: string, locale: string = 'uk'): string {
|
||
return slugify(string, {
|
||
lower: true,
|
||
strict: true,
|
||
locale
|
||
})
|
||
}
|
||
|
||
export const formatNumberWithDecimal = (num: number): string => {
|
||
const [int, decimal] = num.toString().split('.')
|
||
return decimal ? `$(num).${decimal.padEnd(2, '0')}` : int
|
||
}
|
||
|
||
export const toInt = (input: unknown): number | null => {
|
||
let output = NaN
|
||
|
||
if (typeof input === 'string' || typeof input === 'number') {
|
||
output = parseInt(input as string, 10)
|
||
}
|
||
|
||
if (isNaN(output)) {
|
||
console.log('input invalid type: ', typeof input)
|
||
return null
|
||
}
|
||
|
||
return output
|
||
}
|
||
|
||
export const hashPassword = async (value: string): Promise<string> => {
|
||
return bcrypt.hash(value, 10)
|
||
}
|
||
|
||
export const verifyHashedPassword = async (
|
||
value: string,
|
||
hashPassword: string
|
||
): Promise<boolean> => {
|
||
return await bcrypt.compare(value, hashPassword)
|
||
}
|
||
|
||
/**
|
||
* Remove empty properties from the object
|
||
*
|
||
* @param queryParams
|
||
*/
|
||
export const cleanEmptyParams = (queryParams: any) => {
|
||
return Object.keys(queryParams)
|
||
.filter(key => queryParams[key] != '')
|
||
.reduce((acc, key) => Object.assign(acc, {[key]: queryParams[key]}), {})
|
||
}
|
||
|
||
/**
|
||
* Replace null value with empty string for the object and array of them as well
|
||
*
|
||
* @param data
|
||
*/
|
||
export const toEmptyParams = (data: object | object[]) => {
|
||
const result = []
|
||
const isArray = Array.isArray(data)
|
||
const toProcess: object[] = isArray ? data : [data]
|
||
|
||
for (let x in toProcess) {
|
||
const norm = Object.keys(toProcess[x]).reduce(
|
||
(obj: {}, key: string) =>
|
||
Object.assign(obj, {
|
||
// @ts-ignore
|
||
[key]: toProcess[x][key] === null ? '' : toProcess[x][key]
|
||
}),
|
||
{}
|
||
)
|
||
|
||
if (!isArray) return norm
|
||
result.push(norm)
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
export const thisLocales = async (locales: any) => {
|
||
const loc = await getLocale()
|
||
return locales.filter((locale: any) => locale.lang === loc)
|
||
}
|
||
|
||
export const thisLocale = async (locales: any) => {
|
||
const loc = await getLocale()
|
||
return locales.find((locale: any) => locale.lang === loc)
|
||
}
|
||
|
||
export const dbErrorHandling = (e: unknown, message?: string | null) => {
|
||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||
return {error: `${e.code}: ${e.message}`}
|
||
} else if ((e as {code: string}).code === 'ETIMEDOUT') {
|
||
return {
|
||
error:
|
||
'Неможливо підключитися до бази даних. Будь ласка, спробуйте згодом.'
|
||
}
|
||
} else if ((e as {code: string}).code === '503') {
|
||
return {
|
||
error: 'Сервіс тимчасово недоступний. Будь ласка, спробуйте згодом.'
|
||
}
|
||
} else {
|
||
return {error: 'Сталася несподівана помилка. Будь ласка, спробуйте згодом.'}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Check if the object is empty
|
||
*
|
||
* @param obj
|
||
*/
|
||
export const isEmptyObj = (obj: object): boolean =>
|
||
Object.keys(obj).length === 0
|
||
|
||
/**
|
||
* To convert letter on typing from latin to cyr
|
||
* TODO: need to complete
|
||
*
|
||
* @param term
|
||
*/
|
||
export const replacerLat2Cyr = (term: string): string => {
|
||
const obj = {g: 'п', e: 'у', o: 'щ', f: 'а'}
|
||
|
||
return term
|
||
.split('')
|
||
.map((ch: PropertyKey): string => {
|
||
return obj.hasOwnProperty(ch as PropertyKey)
|
||
? (obj[ch as never] as string)
|
||
: (ch as string)
|
||
})
|
||
.join('')
|
||
}
|
||
|
||
type NormalizeConfigType =
|
||
| {
|
||
stripTags?: boolean
|
||
}
|
||
| undefined
|
||
| null
|
||
|
||
export function normalizeData(
|
||
data: string | null,
|
||
config?: NormalizeConfigType
|
||
): string {
|
||
if (config?.stripTags) {
|
||
data = striptags(data as string)
|
||
}
|
||
|
||
return data as string
|
||
}
|