Initial commit
This commit is contained in:
426
website/src/helpers/Api.js
Normal file
426
website/src/helpers/Api.js
Normal file
@@ -0,0 +1,426 @@
|
||||
import EventEmitter from 'eventemitter3'
|
||||
import io from 'socket.io-client'
|
||||
|
||||
const authToken = 'deightonAuthToken'
|
||||
|
||||
class NetworkError extends Error {
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = this.constructor.name
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
} else {
|
||||
this.stack = (new Error(message)).stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ApiError extends Error {
|
||||
constructor(status, message) {
|
||||
super(message || '')
|
||||
this.status = status || 500
|
||||
this.name = this.constructor.name
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
} else {
|
||||
this.stack = (new Error(message)).stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Api extends EventEmitter {
|
||||
constructor() {
|
||||
super()
|
||||
this.user = null
|
||||
|
||||
let token = localStorage.getItem(authToken) || sessionStorage.getItem(authToken)
|
||||
|
||||
if (token) {
|
||||
this.token = token
|
||||
this.user = { pending: true }
|
||||
|
||||
this.who()
|
||||
.then((user) => {
|
||||
this.user = user
|
||||
this.connectSocket()
|
||||
this.emit('login')
|
||||
})
|
||||
.catch(() => {
|
||||
localStorage.removeItem(authToken)
|
||||
sessionStorage.removeItem(authToken)
|
||||
this.token = null
|
||||
this.user = null
|
||||
this.socket = null
|
||||
this.emit('logout')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
connectSocket() {
|
||||
this.socket = io(window.location.origin, {
|
||||
path: '/api/socketio',
|
||||
query: {
|
||||
auth_token: this.token
|
||||
}
|
||||
})
|
||||
this.socket.on('disconnect', (reason) => {
|
||||
// Could happen if the auth_token is bad
|
||||
this.socket = null
|
||||
})
|
||||
this.socket.on('notify', (message) => {
|
||||
const { eventName, eventData } = message
|
||||
|
||||
// Filter the few massages that affect our cached user data to avoid a server round trip
|
||||
switch (eventName) {
|
||||
case 'newThumbnailImage':
|
||||
this.user.thumbnailImageId = eventData.imageId
|
||||
break
|
||||
case 'newProfileImage':
|
||||
this.user.imageId = eventData.imageId
|
||||
break
|
||||
default:
|
||||
// Nothing to see here...
|
||||
break
|
||||
}
|
||||
|
||||
this.emit(message.eventName, message.eventData)
|
||||
})
|
||||
}
|
||||
|
||||
disconnectSocket() {
|
||||
if (this.socket) {
|
||||
this.socket.disconnect()
|
||||
this.socket = null
|
||||
}
|
||||
}
|
||||
|
||||
get loggedInUser() {
|
||||
return this.user
|
||||
}
|
||||
|
||||
makeImageUrl(id, size) {
|
||||
if (id) {
|
||||
return '/api/assets/' + id + '?access_token=' + this.token
|
||||
} else if (size && size.width && size.height) {
|
||||
return `/api/placeholders/${size.width}x${size.height}?access_token=${this.token}`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
makeAssetUrl(id) {
|
||||
return id ? '/api/assets/' + id + '?access_token=' + this.token : null
|
||||
}
|
||||
|
||||
static makeParams(params) {
|
||||
return params ? '?' + Object.keys(params).map((key) => (
|
||||
[key, params[key]].map(encodeURIComponent).join('=')
|
||||
)).join('&') : ''
|
||||
}
|
||||
|
||||
request(method, path, requestBody, requestOptions) {
|
||||
requestOptions = requestOptions || {}
|
||||
var promise = new Promise((resolve, reject) => {
|
||||
let fetchOptions = {
|
||||
method: method,
|
||||
mode: 'cors',
|
||||
cache: 'no-store'
|
||||
}
|
||||
let headers = new Headers()
|
||||
if (this.token) {
|
||||
headers.set('Authorization', 'Bearer ' + this.token)
|
||||
}
|
||||
if (method === 'POST' || method === 'PUT') {
|
||||
if (requestOptions.binary) {
|
||||
headers.set('Content-Type', 'application/octet-stream')
|
||||
headers.set('Content-Length', requestOptions.binary.length)
|
||||
headers.set('Range', 'byte ' + requestOptions.binary.offset)
|
||||
fetchOptions.body = requestBody
|
||||
} else {
|
||||
headers.set('Content-Type', 'application/json')
|
||||
fetchOptions.body = JSON.stringify(requestBody)
|
||||
}
|
||||
}
|
||||
fetchOptions.headers = headers
|
||||
fetch('/api' + path, fetchOptions).then((res) => {
|
||||
return Promise.all([ Promise.resolve(res), (requestOptions.binary && method === 'GET') ? res.blob() : res.json() ])
|
||||
}).then((arr) => {
|
||||
let [ res, responseBody ] = arr
|
||||
if (res.ok) {
|
||||
if (requestOptions.wantHeaders) {
|
||||
resolve({ body: responseBody, headers: res.headers })
|
||||
} else {
|
||||
resolve(responseBody)
|
||||
}
|
||||
} else {
|
||||
reject(new ApiError(res.status, responseBody.message))
|
||||
}
|
||||
}).catch((error) => {
|
||||
reject(new NetworkError(error.message))
|
||||
})
|
||||
})
|
||||
return promise
|
||||
}
|
||||
|
||||
post(path, requestBody, options) {
|
||||
return this.request('POST', path, requestBody, options)
|
||||
}
|
||||
put(path, requestBody, options) {
|
||||
return this.request('PUT', path, requestBody, options)
|
||||
}
|
||||
get(path, options) {
|
||||
return this.request('GET', path, options)
|
||||
}
|
||||
delete(path, options) {
|
||||
return this.request('DELETE', path, options)
|
||||
}
|
||||
|
||||
login(email, password, remember) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.post('/auth/login', { email, password }, { wantHeaders: true }).then((response) => {
|
||||
// Save bearer token for later use
|
||||
const authValue = response.headers.get('Authorization')
|
||||
const [ scheme, token ] = authValue.split(' ')
|
||||
|
||||
if (scheme !== 'Bearer' || !token) {
|
||||
reject(new ApiError('Unexpected Authorization scheme or token'))
|
||||
}
|
||||
|
||||
if (remember) {
|
||||
localStorage.setItem(authToken, token)
|
||||
} else {
|
||||
sessionStorage.setItem(authToken, token)
|
||||
}
|
||||
this.token = token
|
||||
this.user = response.body
|
||||
this.connectSocket()
|
||||
this.emit('login')
|
||||
resolve(response.body)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
logout() {
|
||||
let cb = () => {
|
||||
// Regardless of response, always logout in the client
|
||||
localStorage.removeItem(authToken)
|
||||
sessionStorage.removeItem(authToken)
|
||||
this.token = null
|
||||
this.user = null
|
||||
this.disconnectSocket()
|
||||
this.emit('logout')
|
||||
}
|
||||
return this.delete('/auth/login').then(cb, cb)
|
||||
}
|
||||
who() {
|
||||
return this.get('/auth/who')
|
||||
}
|
||||
confirmEmail(emailToken) {
|
||||
return this.post('/auth/email/confirm/', { emailToken })
|
||||
}
|
||||
sendConfirmEmail(emails) {
|
||||
return this.post('/auth/email/send', emails)
|
||||
}
|
||||
changePassword(passwords) {
|
||||
return this.post('/auth/password/change', passwords)
|
||||
}
|
||||
sendResetPassword(email) {
|
||||
return this.post('/auth/password/send', { email })
|
||||
}
|
||||
resetPassword(passwords) {
|
||||
return this.post('/auth/password/reset', passwords)
|
||||
}
|
||||
|
||||
getUser(_id) {
|
||||
return this.get('/users/' + _id)
|
||||
}
|
||||
listUsers() {
|
||||
return this.get('/users')
|
||||
}
|
||||
listBrokerUsers() {
|
||||
return this.get('/users/brokers')
|
||||
}
|
||||
createUser(user) {
|
||||
return this.post('/users', user)
|
||||
}
|
||||
updateUser(user) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.put('/users', user).then((user) => {
|
||||
// If we just updated ourselves, update the internal cached copy
|
||||
if (user._id === this.user._id) {
|
||||
this.user = user
|
||||
this.emit('login')
|
||||
}
|
||||
resolve(user)
|
||||
}).catch((reason) => {
|
||||
reject(reason)
|
||||
})
|
||||
})
|
||||
}
|
||||
deleteUser(_id) {
|
||||
return this.delete('/users/' + _id)
|
||||
}
|
||||
setUserImage(details) {
|
||||
return this.put('/users/set-image', details)
|
||||
}
|
||||
enterRoom(roomName) {
|
||||
return this.put('/users/enter-room/' + (roomName || ''))
|
||||
}
|
||||
leaveRoom() {
|
||||
return this.put('/users/leave-room')
|
||||
}
|
||||
|
||||
getItemsForPathname(pathname) {
|
||||
return this.get('/fingerprint' + pathname)
|
||||
}
|
||||
|
||||
getCorporation(_id, params) {
|
||||
return this.get('/corporations/' + _id + Api.makeParams(params))
|
||||
}
|
||||
listCorporations(params) {
|
||||
return this.get('/corporations' + Api.makeParams(params))
|
||||
}
|
||||
createCorporation(corporation) {
|
||||
return this.post('/corporations', corporation)
|
||||
}
|
||||
updateCorporation(corporation) {
|
||||
return this.put('/corporations', corporation)
|
||||
}
|
||||
deleteCorporation(_id) {
|
||||
return this.delete('/corporations/' + _id)
|
||||
}
|
||||
setCorporationImage(details) {
|
||||
// _id: corporation id
|
||||
// imageId: image asset id
|
||||
// size: desired size of image { width, height }
|
||||
return this.put('/corporations/set-image', details)
|
||||
}
|
||||
|
||||
getBranch(_id, params) {
|
||||
return this.get('/branches/' + _id + Api.makeParams(params))
|
||||
}
|
||||
listBranches(params) {
|
||||
return this.get('/branches' + Api.makeParams(params))
|
||||
}
|
||||
createBranch(branch) {
|
||||
return this.post('/branches', branch)
|
||||
}
|
||||
updateBranch(branch) {
|
||||
return this.put('/branches', branch)
|
||||
}
|
||||
deleteBranch(_id) {
|
||||
return this.delete('/branches/' + _id)
|
||||
}
|
||||
|
||||
getProject(projectId, params) {
|
||||
return this.get('/projects/' + projectId)
|
||||
}
|
||||
getPopulatedProject(projectId, params) {
|
||||
return this.get('/projects/' + projectId + '/populated')
|
||||
}
|
||||
getProjectBrokerClientData(projectId, brokerId) {
|
||||
return this.get('/projects/' + projectId + '/broker/' + brokerId)
|
||||
}
|
||||
signOffProjectBrokerClientData(projectId, brokerId) {
|
||||
return this.post('/projects/' + projectId + '/broker/' + brokerId + '/sign-off', {})
|
||||
}
|
||||
createProjectPackages(projectId) {
|
||||
return this.post('/projects/' + projectId + '/create-packages', {})
|
||||
}
|
||||
resetProjectPackages(projectId) {
|
||||
return this.post('/projects/' + projectId + '/reset-packages', {})
|
||||
}
|
||||
buildProjectPDFs(projectId) {
|
||||
return this.post('/projects/' + projectId + '/build-pdfs', {})
|
||||
}
|
||||
listProjects(params) {
|
||||
return this.get('/projects' + Api.makeParams(params))
|
||||
}
|
||||
listDashboardProjects() {
|
||||
return this.get('/projects/dashboard')
|
||||
}
|
||||
listBrokerProjects(brokerId) {
|
||||
return this.get('/projects/broker/' + brokerId)
|
||||
}
|
||||
createProject(project) {
|
||||
return this.post('/projects', project)
|
||||
}
|
||||
importProjectClientData(importData) {
|
||||
return this.post('/projects/import-client-data', importData)
|
||||
}
|
||||
updateProject(project) {
|
||||
return this.put('/projects', project)
|
||||
}
|
||||
deleteProject(_id) {
|
||||
return this.delete('/projects/' + _id)
|
||||
}
|
||||
|
||||
getPackage(_id, params) {
|
||||
return this.get('/packages/' + _id + Api.makeParams(params))
|
||||
}
|
||||
listPackages(params) { // Example: listPackages({ projectId: '59c2faa32d27b9d10bd764b3' })
|
||||
return this.get('/packages' + Api.makeParams(params))
|
||||
}
|
||||
|
||||
getFormSet(formSetId) {
|
||||
return this.get('/formsets/' + formSetId)
|
||||
}
|
||||
getForm(formSetId, formId) {
|
||||
return this.get('/formsets/' + formSetId + '/form/' + formId)
|
||||
}
|
||||
listFormSets(params) {
|
||||
return this.get('/formsets' + Api.makeParams(params))
|
||||
}
|
||||
setFormPDF(formSetId, formId, pdfAssetId) {
|
||||
return this.post('/formsets/' + formSetId + '/form/' + formId, { pdfAssetId })
|
||||
}
|
||||
|
||||
upload(file, progressCallback) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunkSize = 32 * 1024
|
||||
let reader = new FileReader()
|
||||
const fileSize = file.size
|
||||
const numberOfChunks = Math.ceil(fileSize / chunkSize)
|
||||
let chunk = 0
|
||||
let uploadId = null
|
||||
|
||||
reader.onload = (e) => {
|
||||
const buffer = e.target.result
|
||||
const bytesRead = buffer.byteLength
|
||||
|
||||
this.post('/assets/upload/' + uploadId, buffer, {
|
||||
binary: { offset: chunk * chunkSize, length: bytesRead }
|
||||
}).then((uploadData) => {
|
||||
chunk++
|
||||
if (!progressCallback(uploadData)) {
|
||||
return Promise.reject(new Error('Upload was canceled'))
|
||||
}
|
||||
if (chunk < numberOfChunks) {
|
||||
let start = chunk * chunkSize
|
||||
let end = Math.min(fileSize, start + chunkSize)
|
||||
reader.readAsArrayBuffer(file.slice(start, end))
|
||||
} else {
|
||||
resolve(uploadData)
|
||||
}
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
this.post('/assets/upload', {
|
||||
fileName: file.name,
|
||||
fileSize,
|
||||
contentType: file.type,
|
||||
numberOfChunks
|
||||
}).then((uploadData) => {
|
||||
uploadId = uploadData.uploadId
|
||||
reader.readAsArrayBuffer(file.slice(0, chunkSize))
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export let api = new Api()
|
||||
75
website/src/helpers/Constants.js
Normal file
75
website/src/helpers/Constants.js
Normal file
@@ -0,0 +1,75 @@
|
||||
export class Constants {
|
||||
static stateOptions = [
|
||||
{ value: '', text: '' },
|
||||
{ value: 'AL', text: 'Alabama' },
|
||||
{ value: 'AK', text: 'Alaska' },
|
||||
{ value: 'AS', text: 'American Samoa' },
|
||||
{ value: 'AZ', text: 'Arizona' },
|
||||
{ value: 'AR', text: 'Arkansas' },
|
||||
{ value: 'CA', text: 'California' },
|
||||
{ value: 'CO', text: 'Colorado' },
|
||||
{ value: 'CT', text: 'Connecticut' },
|
||||
{ value: 'DE', text: 'Delaware' },
|
||||
{ value: 'DC', text: 'District of Columbia' },
|
||||
{ value: 'FM', text: 'Federated States of Micronesia' },
|
||||
{ value: 'FL', text: 'Florida' },
|
||||
{ value: 'GA', text: 'Georgia' },
|
||||
{ value: 'GU', text: 'Guam' },
|
||||
{ value: 'HI', text: 'Hawaii' },
|
||||
{ value: 'ID', text: 'Idaho' },
|
||||
{ value: 'IL', text: 'Illinois' },
|
||||
{ value: 'IN', text: 'Indiana' },
|
||||
{ value: 'IA', text: 'Iowa' },
|
||||
{ value: 'KS', text: 'Kansas' },
|
||||
{ value: 'KY', text: 'Kentucky' },
|
||||
{ value: 'LA', text: 'Louisiana' },
|
||||
{ value: 'ME', text: 'Maine' },
|
||||
{ value: 'MH', text: 'Marshall Islands' },
|
||||
{ value: 'MD', text: 'Maryland' },
|
||||
{ value: 'MA', text: 'Massachusetts' },
|
||||
{ value: 'MI', text: 'Michigan' },
|
||||
{ value: 'MN', text: 'Minnesota' },
|
||||
{ value: 'MS', text: 'Missippi' },
|
||||
{ value: 'MO', text: 'Missouri' },
|
||||
{ value: 'MT', text: 'Montana' },
|
||||
{ value: 'NE', text: 'Nebraska' },
|
||||
{ value: 'NV', text: 'Nevada' },
|
||||
{ value: 'NH', text: 'New Hampshire' },
|
||||
{ value: 'NJ', text: 'New Jersey' },
|
||||
{ value: 'NM', text: 'New Mexico' },
|
||||
{ value: 'NY', text: 'New York' },
|
||||
{ value: 'NC', text: 'North Carolina' },
|
||||
{ value: 'ND', text: 'North Dakota' },
|
||||
{ value: 'MP', text: 'Northern Mariana Islands' },
|
||||
{ value: 'OH', text: 'Ohio' },
|
||||
{ value: 'OK', text: 'Oklahoma' },
|
||||
{ value: 'OR', text: 'Oregon' },
|
||||
{ value: 'PW', text: 'Palau' },
|
||||
{ value: 'PA', text: 'Pennsylvania' },
|
||||
{ value: 'PR', text: 'Puerto Rico' },
|
||||
{ value: 'RI', text: 'Rhode Island' },
|
||||
{ value: 'SC', text: 'South Carolina' },
|
||||
{ value: 'SD', text: 'South Dakota' },
|
||||
{ value: 'TN', text: 'Tennessee' },
|
||||
{ value: 'TX', text: 'Texas' },
|
||||
{ value: 'UT', text: 'Utah' },
|
||||
{ value: 'VT', text: 'Vermont' },
|
||||
{ value: 'VI', text: 'Virgin Islands' },
|
||||
{ value: 'VA', text: 'Virginia' },
|
||||
{ value: 'WA', text: 'Washington' },
|
||||
{ value: 'WV', text: 'West Virginia' },
|
||||
{ value: 'WI', text: 'Wisconsin' },
|
||||
{ value: 'WY', text: 'Wyoming' }
|
||||
]
|
||||
|
||||
static accessLevels = [
|
||||
{ value: 'broker', text: 'Broker' },
|
||||
{ value: 'employee', text: 'Employee' },
|
||||
{ value: 'administrator', text: 'Administrator' },
|
||||
{ value: 'executive', text: 'Executive' }
|
||||
]
|
||||
|
||||
static logoImageSize = { width: 200, height: 50 }
|
||||
static bigUserImageSize = { width: 300, height: 300 }
|
||||
static smallUserImageSize = { width: 25, height: 25 }
|
||||
}
|
||||
2
website/src/helpers/index.js
Normal file
2
website/src/helpers/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { api, NetworkError, ApiError } from './Api'
|
||||
export { Constants } from './Constants'
|
||||
Reference in New Issue
Block a user