instantjob-recruiter-client
Version:
a set of tools for creating an instantjob recruiter react client
175 lines (156 loc) • 4.88 kB
JSX
import 'whatwg-fetch'
import superagent from 'superagent'
import {api_path, DEV} from 'common/constants'
import store from 'common/store'
import {array_contains} from 'common/utilities'
import auto_bind from 'common/auto_bind'
export function make_url(endpoint) {
return `${api_path}/${endpoint}.json?`
}
const authentication_headers = () => {
const {token} = store.getState().authentication
if (token) {
return {
'Authorization': `Bearer ${token}`
}
}
return {}
}
const requestWithMethod = function(method, endpoint, data = {}) {
var options = {method}
let params = ""
if (method == 'GET' && data !== null) {
for (var key in data) {
params += encodeURIComponent(key) + "=" + encodeURIComponent(data[key]) + "&"
}
data = null
}
options.headers = authentication_headers()
if (data !== null) {
options.body = JSON.stringify(data)
options.headers = {
...options.headers,
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}
var request_url = `${make_url(endpoint)}${params}`
return fetch(request_url, options)
.catch((error) => {
return new Promise((resolve, reject) => {
DEV && console.log(method, request_url, data)
DEV && console.log(error)
return reject(error)
})
})
.then((response) => {
return new Promise((resolve, reject) => {
if (response == null || response.error || (array_contains([400, 404, 422, 500], response.status))) {
reject(response)
} else if (response.status != 204) {
response.json()
.then((responseObject) => {
if (responseObject == null || responseObject.error || (array_contains([400, 404, 422, 500], responseObject.status))) {
reject(responseObject)
} else {
resolve(responseObject)
}
})
.catch((error) => reject(error))
} else {
resolve(response)
}
})
})
}
const request = {
get: function(endpoint, params, callback) {
return requestWithMethod('GET', endpoint, params, callback)
},
post: function(endpoint, data, callback) {
return requestWithMethod('POST', endpoint, data, callback)
},
put: function(endpoint, data, callback) {
return requestWithMethod('PUT', endpoint, data, callback)
},
delete: function(endpoint, data, callback) {
return requestWithMethod('DELETE', endpoint, data, callback)
},
asynchronous: function(endpoint, data) {
return new Promise((resolve, reject) => {
const poll_result = (asynchronous_request_id) => requestWithMethod('GET', `asynchronous_requests/${asynchronous_request_id}`)
.then((asynchronous_request) => {
switch (asynchronous_request.status) {
case "pending":
setTimeout(() => poll_result(asynchronous_request_id), 1000)
break
case "completed":
resolve(JSON.parse(asynchronous_request.result))
break
default:
reject(asynchronous_request)
}
})
requestWithMethod('POST', endpoint, data)
.then((response) => setTimeout(() => poll_result(response.asynchronous_request_id), 1000))
})
},
get_paginated: function(endpoint, data = {}, callback) {
return new Promise((resolve, reject) => {
const request_page = (page) => requestWithMethod('GET', endpoint, {...data, page})
.then((page_results) => {
if (page_results.length == 0) {
resolve()
} else {
callback(page_results)
request_page(page + 1)
}
})
.catch(reject)
request_page(1)
})
},
upload(endpoint, file, data) {
// request won't start if `then` is not called
const request = superagent
.put(make_url(endpoint))
.set(authentication_headers())
.accept('json')
.attach('file', file)
return Object.keys(data).reduce((request, key) => request.field(key, data[key]), request)
},
delayed_put(endpoint, data) {
return new Promise((resolve, reject) => {
let delayed_request = delayed_requests[endpoint]
if (delayed_request && !delayed_request.completed) {
resolve = delayed_request.cancel(resolve)
}
delayed_requests[endpoint] = new DelayedRequest(() => request.put(endpoint, data), resolve, reject)
})
}
}
const delayed_requests = {}
class DelayedRequest {
constructor(request, resolve, reject) {
this.request = request
this.resolve = resolve
this.reject = reject
auto_bind(this)
setTimeout(this.run, 2 * 1000)
}
run() {
this.completed = true
if (!this.canceled) {
this.request()
.then(this.resolve, this.reject)
}
}
cancel(resolve) {
this.canceled = true
return (...args) => {
resolve(...args)
this.resolve(...args)
}
}
}
export default request