first commit

This commit is contained in:
ryanwong
2022-11-26 01:23:44 -05:00
commit 02843b95c9
2776 changed files with 102795 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
// setup methods for external use of Axios
import axios from 'axios';
import { cookieExists } from 'Utils/cookies';
// import qs from "qs";
// axios global
export const baseURL = process.env.REACT_APP_API_URL;
export const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
};
// axios api instance
const instance = axios.create({
baseURL,
headers,
withCredentials: true,
});
// making the api request
const request = async (url: string, requestData: object = {}, requestType = 'get', options = {}) =>
await instance[requestType](url, requestData, options);
// await axios.get('https://httpbin.org/get', { params: { answer: 42 } });
// const request = async (url: string, requestData: object = {}, requestType = 'get', callBack = defaultCallBack) =>
// await addCatch(instance[requestType](url, requestData), callBack);
// default error handling
// const defaultCallBack = (err: any) => {
// console.log(err);
// };
// add an error handling callback to existing promise
// const addCatch = (promise: any, callBack: any) => {
// return promise.catch((err: any) => {
// callBack(err);
// });
// };
// Perform a get and return the data
const get = async (url: string, params = {}) => await request(url, params);
// const get = async (url: string, params: object) =>
// await instance.get(url, {
// params,
// paramsSerializer: (params) => qs.stringify(params, { arrayFormat: "repeat" }),
// });
const post = async (url: string, data: object, options?: object) => await request(url, data, 'post', options);
const put = async (url: string, data: object, options?: object) => await request(url, data, 'put', options);
// delete is a key word and cannot be used in strict mode. Hence deleteFn
const deleteFn = async (url: string, data = {}, options = {}) => await request(url, data, 'delete', options);
// Set the Authorization token
const setAuthorizationToken = (token: string = '') => {
instance.defaults.headers.Authorization = `Bearer ${token}`;
};
// Remove the Authorization token
const resetAuthorizationToken = () => {
// enable this to have a new token on each login
delete instance?.defaults?.headers?.Authorization;
};
// Get the initial headers and cookies setup for csrf
const csrfHeader = async () => {
await request(process.env.REACT_APP_SANCTUM_URL);
// Check for the cookie XSRF-TOKEN
return cookieExists('XSRF-TOKEN');
};
export const Api = {
get,
post,
put,
delete: deleteFn,
setAuthorizationToken,
resetAuthorizationToken,
csrfHeader,
};
+100
View File
@@ -0,0 +1,100 @@
// setup methods for external use of Axios
import axios from 'axios';
import { Api, baseURL, headers } from 'Utils/api';
import { Buffer } from 'buffer';
// Create a custom instance, without the withCredentials attribute. AWS doesn't like it
const instance = axios.create({
baseURL,
headers,
withCredentials: false,
});
interface Options {
bucket?: string;
contentType?: string;
expires?: string;
visibility?: string;
headers?: any;
options?: any;
cancelToken?: any;
progress?: (progress: number) => void;
}
export const awsStore = async (file: any, binaryFileString: any, options: Options = {}) => {
const buf = Buffer.from(binaryFileString.replace(/^data:image\/\w+;base64,/, ''), 'base64');
// Use our api to get a response from our backend.
// const optionStore = { progress: () => {}, ...options };
const response = await Api.post(
process.env.REACT_VAPOR_URL,
{
bucket: options?.bucket || '',
content_type: options?.contentType || file.type,
expires: options?.expires || '',
visibility: options?.visibility || '',
},
{
baseURL: null,
headers: options?.headers || {},
...options?.options,
}
);
const headers = response.data.headers;
if ('Host' in headers) {
delete headers.Host;
}
if (typeof options.progress === 'undefined') {
options.progress = () => {};
}
const cancelToken = options.cancelToken || '';
const fileName = file.name.trim();
// Find the last period, so we can get the extension of the file
const lastPeriod = fileName.lastIndexOf('.');
// Get the file extension. Slice will return everything after the period.
const fileExtension = fileName.slice(lastPeriod);
// Get the file name, without the extension
const name = fileName.slice(0, lastPeriod);
const data = {
cancelToken,
headers,
// @ts-ignore
uuid: response.uuid,
key: response.key,
bucket: response.bucket,
name: fileName,
extension: fileExtension,
content_type: file.type,
};
// Only add the upload progess if the method is part of options
if (options.progress) {
// eslint-disable-next-line
data['onUploadProgress'] = (progressEvent: any) => {
options.progress(progressEvent.loaded / progressEvent.total);
};
}
// Send the file and update it's data on AWS
await instance.put(response.data.url, buf, {
cancelToken,
headers,
// @ts-ignore
uuid: response.uuid,
key: response.key,
bucket: response.bucket,
name: fileName,
extension: fileExtension,
content_type: file.type,
});
response.data.name = name;
response.data.extension = fileExtension;
response.data.file = fileName;
return response.data;
};
+6
View File
@@ -0,0 +1,6 @@
export const PROJECT_DASHBOARD = "/projectDashboard";
export const PHOTO_MANAGEMENT = "/photoManagement";
export const ALL_LOCATIONS = "/allLocations";
export const ADD_LOCATIONS = "/addLocations";
export const SINGLE = "/single";
export const MULTI_UNIT = "/multiUnit";
+3
View File
@@ -0,0 +1,3 @@
export const cookieExists = (name: string) =>
// Use find to get the first instance of the named cookie
document.cookie.split(';').find((item) => item.trim().startsWith(`${name}=`)) !== undefined;
+88
View File
@@ -0,0 +1,88 @@
const addresses = [
{
id: 1,
name: '857 Beatty Street',
path: '/projects/857 Beatty Street',
},
{
id: 2,
name: 'Eatons Centre',
path: '/projects/Eatons Centre',
},
{
id: 3,
name: 'Harbour Centre',
path: '/projects/Harbour Centre',
},
{
id: 4,
name: '364 King Street W',
path: '/projects/364 King Street W',
},
{
id: 5,
name: '205 Adelaide Ave',
path: '/projects/205 Adelaide Ave',
},
];
const countries = [
{
id: 1,
name: 'United States',
code: 1,
flag: 'usa',
alpha_2: 'US',
country_code: '+1',
},
{
id: 2,
name: 'Canada',
code: 1,
flag: 'canada',
alpha_2: 'CA',
country_code: '+1',
},
{
id: 3,
name: 'United Kingdom',
code: 44,
flag: 'uk',
alpha_2: 'GB',
country_code: '+44',
},
{
id: 4,
name: 'Australia',
code: 61,
flag: 'aus',
alpha_2: 'AAU',
country_code: '+61',
},
{
id: 5,
name: 'New Zealand',
code: 64,
flag: 'nz',
alpha_2: 'NZ',
country_code: '+64',
},
];
// Property Data
const projectClassifications = [
{
id: 1,
value: 'Residential',
},
{
id: 2,
value: 'Commercial',
},
{
id: 3,
value: 'Both',
},
];
export { addresses, countries, projectClassifications };
+11
View File
@@ -0,0 +1,11 @@
// Using Intl.DateTimeFormat()
const getDateFromMilliseconds = (milliseconds: number) =>
new Date(milliseconds).toLocaleString('en-US', {
day: 'numeric',
month: 'short',
year: 'numeric',
hour12: true,
hour: 'numeric',
minute: '2-digit',
});
export default getDateFromMilliseconds;
+3
View File
@@ -0,0 +1,3 @@
import debouncer from 'lodash/debounce';
export const debounce = (fn: any, wait = 300) => debouncer(fn, wait);
+10
View File
@@ -0,0 +1,10 @@
// Other Node Modules
import deepEqual from 'deep-equal';
import isMatch from 'lodash/isMatch';
export const areEqual = (objectOne: any, objectTwo: any) => deepEqual(objectOne, objectTwo, { strict: true });
export const areEqualNotStrict = (objectOne: any, objectTwo: any) => deepEqual(objectOne, objectTwo);
// This will do a deep check of the two objects and determine if they are equal
export const areEqualShallow = (obj1: any, obj2: any) => isMatch(obj1, obj2);
+26
View File
@@ -0,0 +1,26 @@
import Geocode from 'react-geocode';
import { AddressModal } from 'Containers/Projects/Modals';
import { parseNumber } from 'Utils/numbers';
Geocode.setApiKey(process.env.REACT_GOOGLE_API_KEY);
// Google autocomplete restrictions
export const componentRestrictions: any = { country: ['ca', 'us', 'aus', 'uk', 'nz'] };
// Get latitude or longitude from address.
export const getCoordinatesFromAddress = (address: AddressModal, setLat, setLng) => {
const { address: addressOne, city, state, zip, country } = address;
return Geocode.fromAddress(`${addressOne}, ${city}, ${state}, ${zip}, ${country}`)
.then(({ results }: any) => {
const [result] = results;
const {
geometry: {
location: { lat, lng },
},
} = result;
setLat(parseNumber(lat));
setLng(parseNumber(lng));
})
.catch(() => null);
};
+87
View File
@@ -0,0 +1,87 @@
import { setFetching, setToaster, setFormErrors as setErrors } from 'Containers/Core/actions';
import { logout } from 'Containers/Auth';
import { createBrowserHistory } from 'history';
import { Api } from 'Utils/api';
const history = createBrowserHistory();
const {
location: { pathname },
} = window;
const HTTP_ERROR_CODES = [401, 403, 404, 429, 500];
// to handle the async API calls,
// dispatch is mandatory
// apiRequest is mandatory
// types are optional and FORM_ERRORS are default for all the forms.
// you can send additional types for specific container to handle multiple API errors in a single form or multiple forms
export const handleApiRequest = async (
dispatch,
apiRequest,
errorType = 'FORM_ERRORS',
fetchingType = 'SET_FETCHING',
setErrorsCallback = null
) => {
// before make the api call set the loader, progress bars etc...
dispatch(setFetching(true, fetchingType || 'SET_FETCHING'));
// clear form errors for the type
dispatch(setErrors(undefined, errorType || 'FORM_ERRORS'));
if (setErrorsCallback) setErrorsCallback({});
try {
const { data } = await apiRequest;
// turn of the loader, progress bars etc...
dispatch(setFetching(false, fetchingType || 'SET_FETCHING'));
// Destructure any object inside thunks
return data;
} catch (error: any) {
// turn of the loader, progress bars etc...
dispatch(setFetching(false, fetchingType || 'SET_FETCHING'));
if (error?.response) {
// Request made and server responded
const {
status,
data: { message, errors },
} = error.response;
// set thunk based error objects
// based on this conditionally show error messages
if (HTTP_ERROR_CODES.includes(status) && message) {
dispatch(setErrors(true, errorType || 'FORM_ERRORS'));
}
// show toast with the error message, need to add more use cases
if (status === 403 && message) {
dispatch(setToaster(message, false));
}
if (status === 500 && message) {
dispatch(setToaster(message, false));
}
// set form errors for a given type from the thunk if the status code is 422
if (status === 422 && (errors || message)) {
dispatch(setErrors(errors || message, errorType || 'FORM_ERRORS'));
if (setErrorsCallback) setErrorsCallback(errors);
}
// logout user if api returns 401 status
if (status === 401 && message) {
if (pathname.length > 1 && !pathname.includes('invite')) {
dispatch(setToaster(message, false));
}
if (!pathname.includes('invite')) {
dispatch(logout());
await Api.csrfHeader();
history.push('/');
}
}
} else {
dispatch(setToaster('Something went wrong, please try again or check back later!', false));
}
return null;
}
};
+276
View File
@@ -0,0 +1,276 @@
import { format, getUnixTime, parseISO } from 'date-fns';
import * as uuid from 'uuid';
import { parsePhoneNumber, formatPhoneNumberIntl } from 'react-phone-number-input';
import { PhotoModal } from 'Containers/PhotoViewCarousel/Models';
export const getFirstLetterUppercase = (value: string) => (value ? value.charAt(0).toLocaleUpperCase() : '');
export const convertFirstLetterUppercase = (value: string) =>
value ? getFirstLetterUppercase(value) + value.slice(1) : '';
export const convertWordsFirstLetterUppercase = (value: string) => {
if (!value) {
return '';
}
const words = value.split(' ');
if (words.length === 0) {
return '';
}
return words.map((word: any) => convertFirstLetterUppercase(word)).join(' ');
};
export const formatDate = (dateString: string, dateFormat: string) => format(new Date(dateString), dateFormat);
// convert a date string in ISO 8601 format to a Date object
export const parseISODate = (dateString: string) => parseISO(dateString);
export const getPhotosCount = (albumPhotosCount: number, internalPhotosCount: number) => {
const result = albumPhotosCount - internalPhotosCount;
return result !== -1 ? result : 0;
};
export const getUnixTimeFromString = (date: string) => getUnixTime(new Date(date));
export const compareTwoDates = (dateOne: string, dateTwo: string) =>
getUnixTime(new Date(dateOne)) === getUnixTime(new Date(dateTwo));
export const convertPhoneNumber = (countryCode: string, phone: string) => {
if (phone && countryCode) {
let phoneAlt = phone.replace(countryCode, '');
phoneAlt = phoneAlt.replace(/-/g, '');
phoneAlt = phoneAlt.replace(/ /g, '');
phoneAlt = phoneAlt.replace('+', '');
if (phoneAlt.length < 10) return '';
if (countryCode && phoneAlt) {
const phoneNumber = parsePhoneNumber(countryCode + phoneAlt)?.number;
return phoneNumber;
}
}
return '';
};
export const formatPhoneInternationalWithCountryCode = (countryCode: string, phone: string) => {
if (phone) {
return formatPhoneNumberIntl(phone).replace(`${countryCode} `, '');
}
return '';
};
export const formatPhoneNumberInternational = (phone: string) => {
if (phone) {
return formatPhoneNumberIntl(phone);
}
return '';
};
export const formatPhone = (phone) => {
if (phone) {
const phoneAlt = phone.replace('+1', '');
// const phoneAlt = parsePhoneNumber(phone).nationalNumber;
const part1 = phoneAlt.length > 2 ? phoneAlt.substring(0, 3) : phoneAlt;
const part2 = phoneAlt.length > 3 ? `-${phoneAlt.substring(3, 6)}` : '';
const part3 = phoneAlt.length > 6 ? `-${phoneAlt.substring(6, 10)}` : '';
return `${part1}${part2}${part3}`;
}
return '';
};
export const getPhotoShareBreadCrumb = ({ photoable: room, albums }: PhotoModal, showAlbum = true) => {
const {
room_type: { name: roomName },
morphable: unit,
} = room;
const { name: unitName } = unit;
// getting the first album
const [album] = albums;
let levelName = '';
if (room.level && room.level?.name) {
const { level } = room;
levelName = level.name;
}
return `${unitName} / ${levelName ? `${levelName} / ` : ''} ${roomName} Photos ${
showAlbum ? `${album?.name} / ` : ''
}`;
};
export const getPhotoShareAlbum = ({ albums }: PhotoModal) => {
if (albums.length === 0) {
return '';
}
// getting the first album
const [album] = albums;
return `${album.name}`;
};
export const trimAndToLowerCase = (value: string) => value.replace(/\s/g, '').toLocaleLowerCase();
export const floorNumbers = (min = -25, max = 150, step = 1) =>
Array.from({ length: (max - min) / step + 1 }, (_, i) => min + i).map((item) => ({
id: item,
name: `${item}`,
}));
export const initials = (firstName, lastName) => getFirstLetterUppercase(firstName) + getFirstLetterUppercase(lastName);
export const validateImageFileType = (file) => !!(file.type === 'image/png' || file.type === 'image/jpeg');
export const validateImageResolution = (width, height) => !(width > 4000 || height > 4000);
// text limit for notes dropdown placeholder
export const limitText = (text: string, limit: number) => {
if (text.length > limit) {
return `${text.substring(0, limit)}...`;
}
return text;
};
// will get auth user details only if the routes are not match to below
export const shouldGetAuth = (pathname) =>
pathname.includes('/photo-share') ||
pathname.includes('/reset-password') ||
pathname.includes('/invite') ||
pathname.includes('/signinemail') ||
pathname.includes('/phoneverification') ||
pathname.includes('/phoneverificationcode');
// add or remove an item from an array
export const addOrRemoveFromArray = (previousItems: any[], newItem: any) => {
if (typeof newItem === 'object') {
return previousItems.some((prevItem: any) => prevItem.id.toString() === newItem.id.toString())
? previousItems.filter((prevItem: any) => prevItem.id.toString() !== newItem.id.toString())
: [...previousItems, newItem];
}
return previousItems.includes(newItem)
? previousItems.filter((prevId: any) => prevId.toString() !== newItem.toString())
: [...previousItems, newItem];
};
export const getDisplayedRolesArray = (
allRoles: any,
excludedRoles = ['super-admin', 'employee'],
roleRenameMapping = { 'company-admin': 'Admin' }
) => {
const filteredRoles = allRoles.filter((role) => !excludedRoles.includes(role.name));
if (filteredRoles.length === 0) {
return [];
}
return filteredRoles.map((role) => ({
id: role.id,
name: roleRenameMapping[role.name] ?? role.display_name,
}));
};
export const checkGalleryEnabled = (albumId: number, photoAlbums: any[]) =>
photoAlbums?.some((album: any) => album.id === albumId && album.enabled === 1);
export const galleryShouldShow = (
galleryId: number,
selectedFilterIds: any[],
galleryEnabled: boolean,
isInEditMode: boolean
) => {
if (selectedFilterIds.length === 0) {
// only show all galleries in edit mode if the "all photos" filter is selected
return galleryEnabled || isInEditMode;
}
return selectedFilterIds.includes(galleryId) && galleryEnabled;
};
export const chunkArray = (array, size) =>
array.length <= size ? [array] : [array.slice(0, size), ...chunkArray(array.slice(size), size)];
export const getPhotosChunkSize = (array) => {
if (array.length <= 20) {
return 10;
}
return Math.round(array.length / 2);
};
export const checkIfPhotoSelected = (
photo: any,
selectedPhotos: any[],
unSelectedPhotos: any[],
selectPhotosMode: boolean,
selectAllMode: boolean
) => {
if (!selectPhotosMode) {
return false;
}
if (selectAllMode) {
return !unSelectedPhotos.some((item: any) => item.id === photo.id);
}
return selectPhotosMode && selectedPhotos.some((item: any) => item.id === photo.id);
};
export const generateUUID = () => uuid.v4();
export const compareArrays = (array1: any[], array2: any[]) => {
if (array1.length !== array2.length) return false;
for (let i = 0; i < array1.length; i += 1) {
if (array1[i] !== array2[i]) return false;
}
return true;
};
export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export const getTimeout = (length: number) => {
if (length < 3) {
return 100;
}
if (length < 5) {
return 300;
}
if (length < 10) {
return 1500;
}
return 3000;
};
// download a pdf, or doc etc...
export const download = async (url: string, fileName: string, setLoading: any = undefined) => {
try {
const response = await fetch(url);
const blob = await response.blob();
const blobUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobUrl;
link.setAttribute('download', fileName);
// Append to html link element page
document.body.appendChild(link);
// Start download
link.click();
// Clean up and remove the link
link.parentNode.removeChild(link);
// clear loading if given
if (setLoading) setLoading(false);
} catch (errors: any) {
setLoading(false);
alert('Something went wrong. Unable download the file. Please try again later.');
}
};
+54
View File
@@ -0,0 +1,54 @@
// const axios = require('axios');
/*
class Vapor {
//Store a file in S3 and return its UUID, key, and other information.
async store(file, options = {}) {
const response = await axios.post(
'/vapor/signed-storage-url',
{
bucket: options.bucket || '',
content_type: options.contentType || file.type,
expires: options.expires || '',
visibility: options.visibility || '',
},
{
baseURL: options.baseURL || null,
headers: options.headers || {},
...options.options,
}
);
let headers = response.data.headers;
if ('Host' in headers) {
delete headers.Host;
}
if (typeof options.progress === 'undefined') {
options.progress = () => {};
}
const cancelToken = options.cancelToken || '';
await axios.put(response.data.url, file, {
cancelToken: cancelToken,
headers: headers,
onUploadProgress: (progressEvent) => {
options.progress(progressEvent.loaded / progressEvent.total);
},
});
response.data.extension = file.name.split('.').pop();
return response.data;
}
}
module.exports = new Vapor();
*/
// Temp for now to allow the project to compile
// module.exports = {};
export {};
+14
View File
@@ -0,0 +1,14 @@
export const navItems = [
{
id: 2,
title: 'Projects',
path: '/projects',
icon: 'projects',
},
{
id: 3,
title: 'People',
path: '/people',
icon: 'people',
},
];
+1
View File
@@ -0,0 +1 @@
export const parseNumber = (value) => Number(value) || 0;
+132
View File
@@ -0,0 +1,132 @@
/* eslint-disable */
import { SET_AUTHENTICATED, SET_AUTHENTICATION_TYPE, SOCIAL_LOGIN_ERRORS } from 'Containers/Auth/actions';
import { SET_FETCHING } from 'Containers/Core/actions';
import { height, width } from 'Utils/screen';
import { userDetails } from 'Containers/User';
// popup window global settings
// feel free to modify this
const windowFeatures = `toolbar=no, menubar=no, width=${width}, height=${height}`;
// Oauth2 will handle the social media login for all the available providers. Currently working providers are 'google', 'facebook', 'apple'
export const Oauth2 =
(provider: string) =>
(dispatch: any, _getState = null, _utils: any) => {
provider = provider.toLocaleLowerCase();
// popup window parameters
const URL = `${process.env.REACT_APP_BASE_URL}oauth2/redirect/${provider}`;
const windowName = `${provider}Window`;
// popup window variables
let windowObjectReference = null;
let previousUrl = null;
// handle window event listener
const receiveMessage = (event: any) => {
const { status } = event.data;
// update redux on successful login
if (status === 200) {
// important to call this function whenever user authenticates successfully
dispatch(userDetails());
// set progress bars, loaders
dispatch({
type: SET_FETCHING,
payload: true,
});
// reset error messages
dispatch({
type: SOCIAL_LOGIN_ERRORS,
payload: {
error: false,
message: '',
},
});
// we'll close the window
windowObjectReference.close();
// timeout is optional --this will take it time to show the progress bars, loaders etc...
setTimeout(() => {
// set app authentication state
dispatch({
type: SET_AUTHENTICATED,
payload: true,
});
// set app authentication type
dispatch({
type: SET_AUTHENTICATION_TYPE,
payload: 'social',
});
// set progress bars, loaders
dispatch({
type: SET_FETCHING,
payload: false,
});
}, 1000);
}
// handle any errors on unsuccessful login
if (status === 500) {
const { message } = event.data?.body;
// we'll close the window
windowObjectReference.close();
// set errors
dispatch({
type: SOCIAL_LOGIN_ERRORS,
payload: {
errors: true,
message: message,
},
});
// disable progress bars, loaders
dispatch({
type: SET_FETCHING,
payload: false,
});
}
};
// window functions
const openSignInWindow = (url, name) => {
// remove any existing event listeners
window.removeEventListener('message', receiveMessage);
if (windowObjectReference === null || windowObjectReference.closed) {
/* if the pointer to the window object in memory does not exist
or if such pointer exists but the window was closed */
windowObjectReference = window.open(url, name, windowFeatures);
} else if (previousUrl !== URL) {
/* if the resource to load is different,
then we load it in the already opened secondary window and then
we bring such window back on top/in front of its parent window. */
windowObjectReference = window.open(url, name, windowFeatures);
windowObjectReference.focus();
} else {
/* else the window reference must exist and the window
is not closed; therefore, we can bring it back on top of any other
window with the focus() method. There would be no need to re-create
the window or to reload the referenced resource. */
windowObjectReference.focus();
}
// add the listener for receiving a message from the popup
window.addEventListener('message', (event) => receiveMessage(event), false);
// assign the previous URL
previousUrl = url;
};
// call the window function
openSignInWindow(URL, windowName);
};
+15
View File
@@ -0,0 +1,15 @@
/* eslint-disable */
//The linter has an issue with the email-validator.
import { validate } from "email-validator";
import passwordValidator from "password-validator";
//Validate emails
export { validate as emailValidator };
//Password validation
const passwordValidation = new passwordValidator();
//Current business rules says each password must be at least 8 chars
//If there are any new business rules, add them here.
//See this for examples https://www.npmjs.com/package/password-validator
passwordValidation.is().min(8); //Must have a password that is a min 8 chars long
export { passwordValidation as passwordEightCharactersValidator };
@@ -0,0 +1,104 @@
const legacyFlooringWhitelist = ['Carpet', 'Laminate', 'Engineered', 'Hardwood', 'Concrete'];
const legacyWallsWhitelist = ['Interior Wall', 'Fire Wall', 'Exterior Wall'];
const legacyCeilingWhitelist = [
'Flat Drywall Ceiling',
'Textured Drywall',
'Ceiling Tile',
'Concrete',
'Concrete Textured',
];
const legacyPlumbingWhitelist = ['Countertop', 'Vanity Unit'];
const legacyStructuralWhitelist = [
'Baseboard',
'Countertop',
'Door Trim',
'Drywall',
'Full Height Cabinetry',
'Insulation',
'Lower Cabinetry',
'Shelving',
'Upper Cabinetry',
'Vanity Unit',
'Window Board',
];
export const legacyWhitelists = {
flooring: legacyFlooringWhitelist,
walls: legacyWallsWhitelist,
ceiling: legacyCeilingWhitelist,
plumbing: legacyPlumbingWhitelist,
structural: legacyStructuralWhitelist,
};
const carpentryWhitelist = [
'Door',
'Door - Double',
'Crown Molding',
'Window board',
'Door trim',
'Baseboard',
'Cabinetry - lower',
'Cabinetry - upper',
'Cabinetry - full height',
'Toe kick',
'Door - Bifold',
'Countertop - Laminate',
'Vanity unit',
'Furring strip',
];
const ceilingWhitelist = [
'Ceiling tile',
'Concrete',
'Concrete Textured',
'Flat Drywall',
'Popcorn ceiling',
'Textured ceiling',
'Textured drywall',
];
const flooringWhitelist = [
'Carpet',
'Carpet pad',
'Lift carpet for drying',
'Underlay',
'Hardwood',
'Tackless strip',
'Engineered wood flooring',
'Floating floor',
'Concrete',
];
const plumbingWhitelist = ['Countertop', 'Vanity Unit'];
const wallsWhitelist = [
'5/8" drywall',
'5/8" drywall - 4"',
'5/8" drywall - 2\'',
'1/2" - drywall - 4"',
'Insulation - Batt',
'1/2" drywall',
'1/2" - drywall - 2\'',
'Tape joint for new to existing drywall',
'Texture drywall - smooth / skim coat',
'Drywall Installer / Finisher - per hour',
'Tile',
'Wainscoting',
'Dado rail',
'Insulation - Loose-fill',
'Insulation - Rigid foams',
'Insulation - Spray foam',
];
export const dryingWhitelists = {
carpentry: carpentryWhitelist,
ceiling: ceilingWhitelist,
flooring: flooringWhitelist,
plumbing: plumbingWhitelist,
walls: wallsWhitelist,
};
// Appliances, Cleaning, Electrical, Misc, Mitigation, Protection don't have dryable materials
+4
View File
@@ -0,0 +1,4 @@
import { UserRoleModal } from 'Containers/User/Models/UserModel/UserModel';
export const isCompanyAdmin = (roles: Array<UserRoleModal>) =>
roles?.length > 0 ? roles.some(({ name }: UserRoleModal) => name.toLocaleLowerCase() === 'company-admin') : false;
+4
View File
@@ -0,0 +1,4 @@
import ScreenSizeDetector from 'screen-size-detector';
const { height, width } = new ScreenSizeDetector();
export { height, width };
+179
View File
@@ -0,0 +1,179 @@
export const reportTableHeaders = [
{
id: 1,
displayName: 'Name',
column: 'name',
canSort: false,
action: false,
},
{
id: 2,
displayName: 'Author',
column: 'creator',
canSort: false,
action: false,
},
{
id: 3,
displayName: 'Date Created',
column: 'created',
canSort: true,
action: false,
},
{
id: 4,
displayName: 'Style',
column: 'style',
canSort: false,
action: false,
},
{
id: 5,
displayName: 'Status',
column: 'status',
canSort: false,
action: false,
},
{
id: 6,
displayName: 'Download',
column: 'download',
canSort: false,
action: true,
},
{
id: 7,
displayName: 'Share',
column: 'share',
canSort: false,
action: true,
},
{
id: 8,
displayName: 'Delete',
column: 'delete',
canSort: false,
action: true,
},
];
export const externalAtmosphericTableHeaders = [
{
id: 1,
displayName: 'Date',
column: 'date',
canSort: false,
action: false,
},
{
id: 2,
displayName: 'Relative Humidity',
column: 'rhumidity',
canSort: false,
action: false,
},
{
id: 3,
displayName: 'Temp',
column: 'temp',
canSort: false,
action: false,
},
{
id: 4,
displayName: 'Pressure',
column: 'pressure',
canSort: false,
action: false,
},
{
id: 5,
displayName: 'Wind Speed',
column: 'windspeed',
canSort: false,
action: false,
},
];
export const internalAtmosphericTableHeaders = [
{
id: 1,
displayName: 'Date',
column: 'date',
canSort: false,
action: false,
},
{
id: 2,
displayName: 'Relative Humidity',
column: 'rhumidity',
canSort: false,
action: false,
},
{
id: 3,
displayName: 'Temp',
column: 'temp',
canSort: false,
action: false,
},
{
id: 4,
displayName: 'GPP',
column: 'gpp',
canSort: false,
action: false,
},
{
id: 5,
displayName: 'Dew Point',
column: 'dewpoint',
canSort: false,
action: false,
},
// {
// id: 6,
// displayName: 'View Photo',
// column: 'viewphoto',
// canSort: false,
// action: false,
// },
];
export const moistureLogTableHeaders = [
{
id: 1,
displayName: 'Material',
column: 'material',
canSort: false,
action: false,
},
{
id: 2,
displayName: 'Date',
column: 'date',
canSort: false,
action: false,
},
{
id: 3,
displayName: 'Goal Average',
column: 'goalaverage',
canSort: false,
action: false,
},
{
id: 4,
displayName: 'Average',
column: 'average',
canSort: false,
action: false,
},
// {
// id: 5,
// displayName: 'View Photo',
// column: 'viewphoto',
// canSort: false,
// action: false,
// },
];
+29
View File
@@ -0,0 +1,29 @@
export const projectTabs = [
// {
// title: 'Project Dashboard',
// tab: 'projects-dashboard',
// },
{
title: 'Notes',
tab: 'notes',
},
{
title: 'Crew',
tab: 'crew',
},
{
title: 'Project/Loss Info',
tab: 'project-data',
},
];
export const userProfileTabs = [
{
title: 'Account',
tab: 'account',
},
{
title: 'About Company',
tab: 'about',
},
];
+246
View File
@@ -0,0 +1,246 @@
export type CountryCode =
| 'AC'
| 'AD'
| 'AE'
| 'AF'
| 'AG'
| 'AI'
| 'AL'
| 'AM'
| 'AO'
| 'AR'
| 'AS'
| 'AT'
| 'AU'
| 'AW'
| 'AX'
| 'AZ'
| 'BA'
| 'BB'
| 'BD'
| 'BE'
| 'BF'
| 'BG'
| 'BH'
| 'BI'
| 'BJ'
| 'BL'
| 'BM'
| 'BN'
| 'BO'
| 'BQ'
| 'BR'
| 'BS'
| 'BT'
| 'BW'
| 'BY'
| 'BZ'
| 'CA'
| 'CC'
| 'CD'
| 'CF'
| 'CG'
| 'CH'
| 'CI'
| 'CK'
| 'CL'
| 'CM'
| 'CN'
| 'CO'
| 'CR'
| 'CU'
| 'CV'
| 'CW'
| 'CX'
| 'CY'
| 'CZ'
| 'DE'
| 'DJ'
| 'DK'
| 'DM'
| 'DO'
| 'DZ'
| 'EC'
| 'EE'
| 'EG'
| 'EH'
| 'ER'
| 'ES'
| 'ET'
| 'FI'
| 'FJ'
| 'FK'
| 'FM'
| 'FO'
| 'FR'
| 'GA'
| 'GB'
| 'GD'
| 'GE'
| 'GF'
| 'GG'
| 'GH'
| 'GI'
| 'GL'
| 'GM'
| 'GN'
| 'GP'
| 'GQ'
| 'GR'
| 'GT'
| 'GU'
| 'GW'
| 'GY'
| 'HK'
| 'HN'
| 'HR'
| 'HT'
| 'HU'
| 'ID'
| 'IE'
| 'IL'
| 'IM'
| 'IN'
| 'IO'
| 'IQ'
| 'IR'
| 'IS'
| 'IT'
| 'JE'
| 'JM'
| 'JO'
| 'JP'
| 'KE'
| 'KG'
| 'KH'
| 'KI'
| 'KM'
| 'KN'
| 'KP'
| 'KR'
| 'KW'
| 'KY'
| 'KZ'
| 'LA'
| 'LB'
| 'LC'
| 'LI'
| 'LK'
| 'LR'
| 'LS'
| 'LT'
| 'LU'
| 'LV'
| 'LY'
| 'MA'
| 'MC'
| 'MD'
| 'ME'
| 'MF'
| 'MG'
| 'MH'
| 'MK'
| 'ML'
| 'MM'
| 'MN'
| 'MO'
| 'MP'
| 'MQ'
| 'MR'
| 'MS'
| 'MT'
| 'MU'
| 'MV'
| 'MW'
| 'MX'
| 'MY'
| 'MZ'
| 'NA'
| 'NC'
| 'NE'
| 'NF'
| 'NG'
| 'NI'
| 'NL'
| 'NO'
| 'NP'
| 'NR'
| 'NU'
| 'NZ'
| 'OM'
| 'PA'
| 'PE'
| 'PF'
| 'PG'
| 'PH'
| 'PK'
| 'PL'
| 'PM'
| 'PR'
| 'PS'
| 'PT'
| 'PW'
| 'PY'
| 'QA'
| 'RE'
| 'RO'
| 'RS'
| 'RU'
| 'RW'
| 'SA'
| 'SB'
| 'SC'
| 'SD'
| 'SE'
| 'SG'
| 'SH'
| 'SI'
| 'SJ'
| 'SK'
| 'SL'
| 'SM'
| 'SN'
| 'SO'
| 'SR'
| 'SS'
| 'ST'
| 'SV'
| 'SX'
| 'SY'
| 'SZ'
| 'TA'
| 'TC'
| 'TD'
| 'TG'
| 'TH'
| 'TJ'
| 'TK'
| 'TL'
| 'TM'
| 'TN'
| 'TO'
| 'TR'
| 'TT'
| 'TV'
| 'TW'
| 'TZ'
| 'UA'
| 'UG'
| 'US'
| 'UY'
| 'UZ'
| 'VA'
| 'VC'
| 'VE'
| 'VG'
| 'VI'
| 'VN'
| 'VU'
| 'WF'
| 'WS'
| 'XK'
| 'YE'
| 'YT'
| 'ZA'
| 'ZM'
| 'ZW';