portal-www
Version:
Nova Portal Website. Based on Next starter by Ueno
625 lines (547 loc) • 15.7 kB
text/typescript
import { ThemeColorType } from '@nova-hf/ui';
import {
addMonths,
differenceInCalendarDays,
format,
formatDistanceStrict,
subMonths,
} from 'date-fns';
import is from 'date-fns/locale/is';
import { get, isEmpty, set } from 'lodash';
import { IAmount, IRateplan, IUser } from 'typings';
import { CartItem, PurchaseInfoInput, Rateplan } from 'typings/graphql';
const locales = {
'is-IS': is,
};
interface IOpts {
showZero?: boolean;
showDecimals?: boolean;
monthly?: boolean;
unit?: string;
}
export function formatPrice(
price: number,
opts: IOpts = { showZero: true, showDecimals: false, monthly: false },
) {
if (!price || price === 0) {
return get(opts, 'showZero')
? `0 kr.${
get(opts, 'monthly') ? ` ${get(opts, 'unit') ? `/ ${get(opts, 'unit')}` : '/ mán'}` : ''
}`
: '—';
}
const isMinus = price < 0;
const decimal = opts.showDecimals ? 2 : 0;
return `${isMinus ? '-' : ''}${price
.toFixed(decimal)
.replace('.', ',')
.replace('-', '')
.replace(/./g, (c, i, a) => (i && c !== ',' && (a.length - i) % 3 === 0 ? `.${c}` : c))} kr.${
get(opts, 'monthly') ? ` ${get(opts, 'unit') ? `/ ${get(opts, 'unit')}` : '/ mán'}` : ''
}`;
}
export function formatCardExpiryDate(date: string) {
// in temoorary use while we figure out how wee will deliver expiry date
if (date.length === 4 && /^-?\d+$/.test(date)) {
return `${date.slice(0, 2)}/${date.slice(2, 4)}`;
} else return date;
}
export function isCompany(ssn: string) {
const firstDigit = parseInt(ssn[0], 10);
return !isNaN(firstDigit) && firstDigit > 3;
}
export function isStringPhoneNumber(testString: string) {
const phoneRegex = /^(\d{3})?[-.●]?(\d{3})?[-.●]?(\d{4})$/;
return phoneRegex.test(testString);
}
export function formatNumber(number: number) {
const isMinus = number < 0;
return `${isMinus ? '-' : ''}${number
.toFixed(0)
.replace('.', ',')
.replace('-', '')
.replace(/./g, (c, i, a) => (i && c !== ',' && (a.length - i) % 3 === 0 ? `.${c}` : c))}`;
}
export function formatPhone(phone: string) {
if (!phone) {
return '—';
}
return phone.replace('-', '').replace(/^(.{3})(.*)$/, '$1 $2');
}
export function formatTel(number: string) {
if (!number || isNaN(parseInt(number, 10)) || number.length !== 7) {
return number;
}
return `${number.slice(0, 3)} ${number.slice(3)}`;
}
/**
* Date-fns format localized to is-IS
* @param date
* @param formatString
*/
export function formatDate(date: Date, formatString: string) {
const dateItem = date instanceof Date ? date : new Date(date);
return format(dateItem, formatString, {
locale: locales['is-IS'],
});
}
export function formatAmount(num: number) {
return num
.toString()
.replace('.', ',')
.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.');
}
export function capitalize(str: string) {
return str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : str;
}
export function mockGenerator(id: string) {
if (id == '23cf25c9-119a-4000-9062-3d8f334035b0') {
return {
name: 'Björgvin',
service: 'AlltSaman',
pack: 'Meira',
color: 'orange',
price: '19.900 kr.',
icon: 'alltSaman',
};
}
if (id == '967af583-924a-4291-ab53-8241857d734c') {
return {
name: 'Unnur',
service: 'Ljósleiðari',
pack: '500 GB',
color: 'purple',
price: '11.790 kr.',
icon: 'internet',
};
}
if (id == 'bd36c2a5-8c47-4580-9bea-8c4bdc89e93a') {
return {
name: 'Andrea',
service: 'Frelsi',
pack: '10 GB',
color: 'pink',
price: '2.490 kr.',
icon: 'mobileStar',
};
}
if (id == 'dc1343ce-0e25-4c1f-9178-c354f332893f') {
return {
name: 'Ástþór',
service: 'Áskrift',
pack: '100 GB',
color: 'ocean',
price: '3.990 kr.',
icon: 'mobilePlus',
};
}
if (id == '9c39ba3b-2d49-471a-c2d0-08dab34e9570') {
return {
name: 'Sigurjón',
service: 'Áskrift',
pack: '150 GB',
color: 'ocean',
price: '6.990 kr.',
icon: 'mobilePlus',
};
}
if (id == 'cd6fc737-daa3-44ca-c2d1-08dab34e9570') {
return {
name: 'Hilma',
service: 'MínusÁtján',
pack: '2 GB',
color: 'pink',
price: '0 kr.',
icon: 'bestDeal',
};
}
if (id == 'b29d78bf-37fd-4ce4-c2d2-08dab34e9570') {
return {
name: 'Hrafnhildur',
service: 'Sjálfsvörn',
pack: 'Íbúð',
color: 'green',
price: '3.990 kr.',
icon: 'lock',
};
} else {
return {
name: 'Gunnþór',
service: 'Áskrift',
pack: '100 GB',
color: 'ocean',
price: '3.990 kr.',
icon: 'mobilePlus',
};
}
}
export function pages(totalCount: number, perPage: number) {
return Math.ceil(totalCount / perPage);
}
export const getMonth = (date: number | Date) => {
return format(date, 'MMMM', {
locale: locales['is-IS'],
});
};
export function getMonths(date: number | Date, count: number) {
const dateInPast = subMonths(date, count);
return Array(count + 1)
.fill(0)
.map((_, i) => {
const newdate = addMonths(dateInPast, i);
return {
month: format(newdate, 'MMMM', {
locale: locales['is-IS'],
}),
date: newdate,
};
});
}
export function formatMillisRemaining(t: number) {
const cd = 24 * 60 * 60 * 1000;
const ch = 60 * 60 * 1000;
const cmon = cd * 30;
const mon = Math.floor(t / cmon);
let d = Math.floor(t / cd);
let h = Math.floor((t - d * cd) / ch);
let m = Math.round((t - d * cd - h * ch) / 60000);
if (m === 60) {
h += 1;
m = 0;
}
if (h === 24) {
d += 1;
h = 0;
}
if (d > 31) {
if (mon === 1) {
return `${mon} mánuður`;
}
return `${mon} mánuðir`;
}
if (d > 0) {
if (d === 1) {
return `${d} dagur`;
}
return `${d} dagar`;
}
return `${d}d ${h}k ${m}m`;
}
export function objectToQuery(obj: { [key: string]: string }) {
return Object.keys(obj)
.map((key) => {
return `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`;
})
.join('&');
}
export function formElementsToObject(elements: HTMLCollectionOf<HTMLInputElement>) {
const obj = {};
Object.entries(elements).forEach(([_, field]) => {
const attr: string = get(field, ['dataset', 'key']);
if (attr !== undefined) {
if (field.type === 'checkbox') {
set(obj, attr.split('.'), field.checked);
} else if (field.type !== 'submit') {
set(obj, attr.split('.'), field.value);
}
}
});
return obj;
}
export function queryToObject(query: string) {
if (query.length < 1) {
return {};
}
const search = query.substring(1);
return JSON.parse(
`{"${decodeURI(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"')}"}`,
);
}
export function hasLocalStorage() {
const test = 'test';
try {
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
export function diffInDays(dateFrom: Date, dateTo: Date) {
return differenceInCalendarDays(dateFrom, dateTo);
}
export function profileColor(rateplan: IRateplan | Rateplan) {
if (rateplan.isVip) {
return 'viola';
}
switch (rateplan.typeId) {
case 'fiber':
return 'yellow';
case 'internet':
return 'green';
case 'mobile':
return rateplan.isPrepaid ? 'pink' : 'ocean';
case 'service_bundle':
return 'orange';
case 'vip_service_bundle':
return 'dark';
case 'forwarding':
return 'purple';
case 'unregistered':
return 'pink';
case 'tv_content_channel':
return 'pink';
default:
return 'ocean';
}
}
export function connectionColor(type: string) {
switch (type) {
case 'Mobile':
return 'pink';
case 'Internet':
return 'yellow';
case 'CallForwarding':
return 'purple';
case 'BackupConnection':
return 'ocean';
default:
return 'ocean';
}
}
/**
* @param name String
* @returns String
*/
export function formatFirstName(name: string) {
if (name) {
if (name.includes('TANKAR\\')) {
return name.split('\\')[1];
}
return name.split(' ')[0];
}
return '';
}
export function formatName(user: IUser) {
return formatFirstName(user.name);
}
export function distanceToDate(futureDate: Date, nowDate: Date) {
return formatDistanceStrict(futureDate, nowDate, {
locale: locales['is-IS'],
});
}
export function convertData(remaining: IAmount, included: IAmount) {
const base = {
B: 0,
KB: 1,
MB: 2,
GB: 3,
};
const r = base[remaining.unit];
const incl = base[included.unit];
const diff = Math.abs(incl - r);
if (diff === 0) {
return [remaining, included];
}
if (r < incl) {
const remainingResult = remaining.amount / (1024 * diff);
return [{ amount: remainingResult, unit: included.unit }, included];
}
const includedResult = included.amount / (1024 * diff);
return [remaining, { amount: includedResult, unit: remaining.unit }];
}
export function remainingPercentage(remaining: IAmount, included: IAmount) {
const base = {
B: 0,
KB: 1,
MB: 2,
GB: 3,
};
if (isEmpty(remaining) || isEmpty(included)) return 0;
const r = base[remaining.unit];
const incl = base[included.unit];
const diff = Math.abs(incl - r);
if (diff === 0) {
return (remaining.amount / included.amount) * 100;
}
if (r < incl) {
return (remaining.amount / (included.amount * (1024 * diff))) * 100;
}
return ((remaining.amount * (1024 * diff)) / included.amount) * 100;
}
export function scrollToElement(element: string, shouldScrollFromTop?: boolean) {
const scrollTop = window.pageYOffset || window.scrollY;
const domElement = typeof element === 'string' ? document.querySelector(element) : element;
if (!domElement || (!shouldScrollFromTop && domElement.getBoundingClientRect().top > 0)) {
return;
}
const num = domElement.getBoundingClientRect().top + scrollTop;
return window.scrollTo({
top: num,
left: 0,
behavior: 'smooth',
});
}
export function signupScroll(element: string, instant?: boolean) {
const domElement = typeof element === 'string' ? document.querySelector(element) : element;
if (!domElement) {
return;
}
const rect = domElement.getBoundingClientRect();
const scrollTop = window.scrollY || document.documentElement.scrollTop;
// Adjust scroll position relative to current scroll position
const num = rect.top + scrollTop - (window.innerHeight / 2 - rect.height / 2);
return window.scrollTo({
top: num,
left: 0,
behavior: instant ? 'instant' : 'smooth',
});
}
export function getOpportunityColor(category: string) {
switch (category) {
case 'vip':
return 'purple';
case 'service_bundle':
return 'orange';
case 'vip_service_bundle':
return 'dark';
case 'watch':
return 'ocean';
case 'fiber':
return 'yellow';
case 'internet':
return 'green';
case 'mobile_prepaid':
return 'pink';
case 'mobile_postpaid':
return 'ocean';
case 'unregistered':
return 'pink';
default:
return 'ocean';
}
}
export function stripTypenames(properties: any) {
if (Array.isArray(properties)) {
return properties.map(stripTypenames);
} else if (!isEmpty(properties) && typeof properties === 'object') {
const newProperties = {};
for (const property in properties) {
if (property !== '__typename') {
newProperties[property] = stripTypenames(properties[property]);
}
}
return newProperties;
}
return properties;
}
export const formatNationalId = (nationalId: string): string =>
`${nationalId.slice(0, 6)} ${nationalId.slice(6)}`;
export const isNationalIdValid = (nationalId: string): boolean => {
const pattern = /^\d{10}$/;
return pattern.test(nationalId);
};
export function emailValidate(email: string) {
return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
email,
); //eslint-disable-line
}
export function serializeObject(obj: { [key: string]: string }) {
const str: Array<string> = [];
Object.keys(obj).forEach((key) => {
if (typeof obj[key] !== 'undefined') {
str.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`);
}
});
return str.length > 0 ? `?${str.join('&')}` : '';
}
export function maritalStatusMap(status?: string) {
switch (status) {
case 'Unmarried':
return 'Ógift(ur)';
case 'IcelanderAbroadMarriedToAForeigner':
return 'Íslendingur með lögheimili erlendis í hjúskap með útlendingi sem ekki er á skrá';
case 'LegallySeparated':
return 'Skilin(n) að borði og sæng';
case 'IcelanderMarriedToAForeigner':
return 'Íslendingur í hjúskap með útlendingi';
case 'MarriedOrRegisteredCohabitation':
return 'Gift(ur) eða staðfest sambúð';
case 'Undisclosed':
return 'Hjón ekki í samvistum';
case 'MarriedNotCohabitating':
return 'Hjúskaðarstaða óupplýst';
case 'DivorcedByLaw':
return 'Skilin(n) að lögum';
case 'Widow':
return 'Ekkja eða ekkill';
default:
return 'Óþekkt';
}
}
export const textColorByBackgroundColor = (backgroundColor: ThemeColorType): ThemeColorType => {
switch (backgroundColor) {
case 'grey400':
case 'grey300':
case 'grey200':
case 'grey100':
case 'ocean':
case 'white':
case 'yellow':
return 'black100';
default:
return 'white';
}
};
export const isSignupMobileReference = (
referenceItem: CartItem | undefined,
): referenceItem is CartItem & {
purchaseInfo: {
contract: { __typename: 'SignupContract' };
service: { __typename: 'MobileServiceRequest' };
};
} => {
return (
referenceItem?.purchaseInfo?.contract?.__typename === 'SignupContract' &&
referenceItem?.purchaseInfo?.service?.__typename === 'MobileServiceRequest'
);
};
export const hasValidPurchaseInfo = (
serviceItem: { purchaseInfo?: unknown } | undefined,
): serviceItem is { purchaseInfo: PurchaseInfoInput } => {
return serviceItem?.purchaseInfo !== undefined;
};
export const hasMobileServiceRequest = (
serviceItem: CartItem | undefined,
): serviceItem is CartItem & {
purchaseInfo: {
service: {
__typename: 'MobileServiceRequest';
user: unknown;
};
};
} => {
return (
serviceItem !== undefined &&
serviceItem.purchaseInfo !== undefined &&
serviceItem.purchaseInfo !== null &&
serviceItem.purchaseInfo.service !== undefined &&
serviceItem.purchaseInfo.service !== null &&
serviceItem.purchaseInfo.service.__typename === 'MobileServiceRequest' &&
serviceItem.purchaseInfo.service.user !== undefined
);
};
export const isEighteenOrOlder = (nationalId: string): boolean => {
if (!/^\d{10}$/.test(nationalId)) return false;
const day = parseInt(nationalId.slice(0, 2), 10);
const month = parseInt(nationalId.slice(2, 4), 10);
const year = parseInt(nationalId.slice(4, 6), 10);
const century = parseInt(nationalId[9], 10) === 9 ? 1900 : 2000;
const birthYear = century + year;
const birthDate = new Date(birthYear, month - 1, day);
const today = new Date();
const age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
const d = today.getDate() - birthDate.getDate();
return age > 18 || (age === 18 && (m > 0 || (m === 0 && d >= 0)));
};