Chore: Add basic screen and toggle
Chore: form skeleton Feat: wizard step 1 and 2 Feat: toggle button group for formik Feat: select input type Form and styling Feat: text entry page Feat: Choice list and CSS Fix: scroll to bottom on Add choice button click Feat: format data at end of wizard Feat: wizard toggle button and background blur Feat: data table for custom info requests Feat: editing and deleting custom info request Feat: add icons Fix: Wizard changes Feat: custom requests migrations Feat: fetch custom info requests Feat: add mutations Feat: add custom request option in trigger wizard Feat: show customrequests on table Feat: Triggers page code refactor Feat: integrate custom info requests on Customer graphql type Feat: Show custom info requests on user page Fix: use normal table instead of datatable Feat: modal for custom information request details Feat: poller returns custom request information details Feat: send customer custom info requests to machine Chore: add field CustomInfoRequestsData on customer updates Feat: customer custom info request data saving Chore: variable name changes and lots of fixes Feat: remove default value in query, sort request on customer profile Signed-off-by: csrapr <26280794+csrapr@users.noreply.github.com> Fix: return promise when array of ids is empty Feat: TitleSection can receive more than one button
This commit is contained in:
parent
3de2bb3d86
commit
ba8cac60f8
48 changed files with 2424 additions and 146 deletions
|
|
@ -43,6 +43,7 @@ function add (customer) {
|
|||
.then(populateOverrideUsernames)
|
||||
.then(computeStatus)
|
||||
.then(populateDailyVolume)
|
||||
.then(getCustomInfoRequestsData)
|
||||
.then(camelize)
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ function get (phone) {
|
|||
const sql = 'select * from customers where phone=$1'
|
||||
return db.oneOrNone(sql, [phone])
|
||||
.then(populateDailyVolume)
|
||||
.then(getCustomInfoRequestsData)
|
||||
.then(camelize)
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +92,7 @@ function update (id, data, userToken, txId) {
|
|||
.then(populateOverrideUsernames)
|
||||
.then(computeStatus)
|
||||
.then((it) => populateDailyVolume(it, txId))
|
||||
.then(getCustomInfoRequestsData)
|
||||
.then(camelize)
|
||||
}
|
||||
|
||||
|
|
@ -315,6 +318,7 @@ function getById (id, userToken) {
|
|||
.then(populateOverrideUsernames)
|
||||
.then(computeStatus)
|
||||
.then(populateDailyVolume)
|
||||
.then(getCustomInfoRequestsData)
|
||||
.then(camelize)
|
||||
}
|
||||
|
||||
|
|
@ -606,6 +610,7 @@ function batch () {
|
|||
return populateOverrideUsernames(customer)
|
||||
.then(computeStatus)
|
||||
.then(populateDailyVolume)
|
||||
.then(getCustomInfoRequestsData)
|
||||
.then(camelize)
|
||||
}, customers)))
|
||||
}
|
||||
|
|
@ -1001,6 +1006,12 @@ function removeCustomField (customerId, fieldId) {
|
|||
}))
|
||||
}
|
||||
|
||||
function getCustomInfoRequestsData (customer) {
|
||||
if (!customer) return
|
||||
const sql = `SELECT * FROM customers_custom_info_requests WHERE customer_id = $1`
|
||||
return db.any(sql, [customer.id]).then(res => _.set('custom_info_request_data', res, customer))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
add,
|
||||
get,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
const queries = require('../../services/customInfoRequests')
|
||||
const DataLoader = require('dataloader')
|
||||
|
||||
const customerCustomInfoRequestsLoader = new DataLoader(ids => queries.batchGetAllCustomInfoRequestsForCustomer(ids), { cache: false })
|
||||
|
||||
const customInfoRequestLoader = new DataLoader(ids => queries.batchGetCustomInfoRequest(ids), { cache: false })
|
||||
|
||||
const resolvers = {
|
||||
Customer: {
|
||||
customInfoRequests: parent => customerCustomInfoRequestsLoader.load(parent.id)
|
||||
},
|
||||
CustomRequestData: {
|
||||
customInfoRequest: parent => customInfoRequestLoader.load(parent.infoRequestId)
|
||||
},
|
||||
Query: {
|
||||
customInfoRequests: (...[, { onlyEnabled }]) => queries.getCustomInfoRequests(onlyEnabled),
|
||||
customerCustomInfoRequests: (...[, { customerId }]) => queries.getAllCustomInfoRequestsForCustomer(customerId),
|
||||
customerCustomInfoRequest: (...[, { customerId, infoRequestId }]) => queries.getCustomInfoRequestForCustomer(customerId, infoRequestId)
|
||||
},
|
||||
Mutation: {
|
||||
insertCustomInfoRequest: (...[, { customRequest }]) => queries.addCustomInfoRequest(customRequest),
|
||||
removeCustomInfoRequest: (...[, { id }]) => queries.removeCustomInfoRequest(id),
|
||||
editCustomInfoRequest: (...[, { id, customRequest }]) => queries.editCustomInfoRequest(id, customRequest),
|
||||
setAuthorizedCustomRequest: (...[, { customerId, infoRequestId, isAuthorized }]) => queries.setAuthorizedCustomRequest(customerId, infoRequestId, isAuthorized)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = resolvers
|
||||
|
|
@ -6,6 +6,7 @@ const cashbox = require('./cashbox.resolver')
|
|||
const config = require('./config.resolver')
|
||||
const currency = require('./currency.resolver')
|
||||
const customer = require('./customer.resolver')
|
||||
const customInfoRequests = require('./customInfoRequests.resolver')
|
||||
const funding = require('./funding.resolver')
|
||||
const log = require('./log.resolver')
|
||||
const loyalty = require('./loyalty.resolver')
|
||||
|
|
@ -28,6 +29,7 @@ const resolvers = [
|
|||
config,
|
||||
currency,
|
||||
customer,
|
||||
customInfoRequests,
|
||||
funding,
|
||||
log,
|
||||
loyalty,
|
||||
|
|
|
|||
54
lib/new-admin/graphql/types/customInfoRequests.type.js
Normal file
54
lib/new-admin/graphql/types/customInfoRequests.type.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
const { gql } = require('apollo-server-express')
|
||||
|
||||
const typeDef = gql`
|
||||
|
||||
type CustomInfoRequest {
|
||||
id: ID!,
|
||||
enabled: Boolean,
|
||||
customRequest: JSON
|
||||
}
|
||||
|
||||
input CustomRequestInputField {
|
||||
choiceList: [String]
|
||||
constraintType: String
|
||||
type: String
|
||||
numDigits: String
|
||||
label1: String
|
||||
label2: String
|
||||
}
|
||||
|
||||
input CustomRequestInputScreen {
|
||||
text: String
|
||||
title: String
|
||||
}
|
||||
|
||||
input CustomRequestInput {
|
||||
name: String
|
||||
input: CustomRequestInputField
|
||||
screen1: CustomRequestInputScreen
|
||||
screen2: CustomRequestInputScreen
|
||||
}
|
||||
|
||||
type CustomRequestData {
|
||||
customerId: ID
|
||||
infoRequestId: ID
|
||||
approved: Boolean
|
||||
customerData: JSON
|
||||
customInfoRequest: CustomInfoRequest
|
||||
}
|
||||
|
||||
type Query {
|
||||
customInfoRequests(onlyEnabled: Boolean): [CustomInfoRequest] @auth
|
||||
customerCustomInfoRequests(customerId: ID!): [CustomRequestData] @auth
|
||||
customerCustomInfoRequest(customerId: ID!, infoRequestId: ID!): CustomRequestData @auth
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
insertCustomInfoRequest(customRequest: CustomRequestInput!): CustomInfoRequest @auth
|
||||
removeCustomInfoRequest(id: ID!): CustomInfoRequest @auth
|
||||
editCustomInfoRequest(id: ID!, customRequest: CustomRequestInput!): CustomInfoRequest @auth
|
||||
setAuthorizedCustomRequest(customerId: ID!, infoRequestId: ID!, isAuthorized: Boolean!): Boolean @auth
|
||||
}
|
||||
`
|
||||
|
||||
module.exports = typeDef
|
||||
|
|
@ -40,6 +40,7 @@ const typeDef = gql`
|
|||
transactions: [Transaction]
|
||||
subscriberInfo: JSONObject
|
||||
customFields: [CustomerCustomField]
|
||||
customInfoRequests: [CustomRequestData]
|
||||
}
|
||||
|
||||
input CustomerInput {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ const cashbox = require('./cashbox.type')
|
|||
const config = require('./config.type')
|
||||
const currency = require('./currency.type')
|
||||
const customer = require('./customer.type')
|
||||
const customInfoRequests = require('./customInfoRequests.type')
|
||||
const funding = require('./funding.type')
|
||||
const log = require('./log.type')
|
||||
const loyalty = require('./loyalty.type')
|
||||
|
|
@ -28,6 +29,7 @@ const types = [
|
|||
config,
|
||||
currency,
|
||||
customer,
|
||||
customInfoRequests,
|
||||
funding,
|
||||
log,
|
||||
loyalty,
|
||||
|
|
|
|||
122
lib/new-admin/services/customInfoRequests.js
Normal file
122
lib/new-admin/services/customInfoRequests.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
const db = require('../../db')
|
||||
const uuid = require('uuid')
|
||||
const _ = require('lodash/fp')
|
||||
const pgp = require('pg-promise')()
|
||||
|
||||
const getCustomInfoRequests = (onlyEnabled = false) => {
|
||||
const sql = onlyEnabled
|
||||
? `SELECT * FROM custom_info_requests WHERE enabled = true ORDER BY custom_request->>'name'`
|
||||
: `SELECT * FROM custom_info_requests ORDER BY custom_request->>'name'`
|
||||
return db.any(sql).then(res => {
|
||||
return res.map(item => ({
|
||||
id: item.id,
|
||||
enabled: item.enabled,
|
||||
customRequest: item.custom_request
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
const addCustomInfoRequest = (customRequest) => {
|
||||
const sql = 'INSERT INTO custom_info_requests (id, custom_request) VALUES ($1, $2)'
|
||||
const id = uuid.v4()
|
||||
return db.none(sql, [id, customRequest]).then(() => ({ id }))
|
||||
}
|
||||
|
||||
const removeCustomInfoRequest = (id) => {
|
||||
return db.none('UPDATE custom_info_requests SET enabled = false WHERE id = $1', [id]).then(() => ({ id }))
|
||||
}
|
||||
|
||||
const editCustomInfoRequest = (id, customRequest) => {
|
||||
return db.none('UPDATE custom_info_requests SET custom_request = $1 WHERE id=$2', [customRequest, id]).then(() => ({ id, customRequest }))
|
||||
}
|
||||
|
||||
const getAllCustomInfoRequestsForCustomer = (customerId) => {
|
||||
const sql = `SELECT * FROM customers_custom_info_requests WHERE customer_id = $1`
|
||||
return db.any(sql, [customerId]).then(res => res.map(item => ({
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
})))
|
||||
}
|
||||
|
||||
const getCustomInfoRequestForCustomer = (customerId, infoRequestId) => {
|
||||
const sql = `SELECT * FROM customers_custom_info_requests WHERE customer_id = $1 AND info_request_id = $2`
|
||||
return db.one(sql, [customerId, infoRequestId]).then(item => {
|
||||
return {
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const batchGetAllCustomInfoRequestsForCustomer = (customerIds) => {
|
||||
const sql = `SELECT * FROM customers_custom_info_requests WHERE customer_id IN ($1^)`
|
||||
return db.any(sql, [_.map(pgp.as.text, customerIds).join(',')]).then(res => {
|
||||
const map = _.groupBy('customer_id', res)
|
||||
return customerIds.map(id => {
|
||||
const items = map[id] || []
|
||||
return items.map(item => ({
|
||||
customerId: item.customer_id,
|
||||
infoRequestId: item.info_request_id,
|
||||
approved: item.approved,
|
||||
customerData: item.customer_data
|
||||
}))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getCustomInfoRequest = (infoRequestId) => {
|
||||
const sql = `SELECT * FROM custom_info_requests WHERE id = $1`
|
||||
return db.one(sql, [infoRequestId]).then(item => ({
|
||||
id: item.id,
|
||||
enabled: item.enabled,
|
||||
customRequest: item.custom_request
|
||||
}))
|
||||
}
|
||||
|
||||
const batchGetCustomInfoRequest = (infoRequestIds) => {
|
||||
if (infoRequestIds.length === 0) return Promise.resolve([])
|
||||
const sql = `SELECT * FROM custom_info_requests WHERE id IN ($1^)`
|
||||
return db.any(sql, [_.map(pgp.as.text, infoRequestIds).join(',')]).then(res => {
|
||||
const map = _.groupBy('id', res)
|
||||
return infoRequestIds.map(id => {
|
||||
const item = map[id][0] // since id is primary key the array always has 1 element
|
||||
return {
|
||||
id: item.id,
|
||||
enabled: item.enabled,
|
||||
customRequest: item.custom_request
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const setAuthorizedCustomRequest = (customerId, infoRequestId, isAuthorized) => {
|
||||
const sql = `UPDATE customers_custom_info_requests SET approved = $1 WHERE customer_id = $2 AND info_request_id = $3`
|
||||
return db.none(sql, [isAuthorized, customerId, infoRequestId]).then(() => true)
|
||||
}
|
||||
|
||||
const setCustomerData = (customerId, infoRequestId, data) => {
|
||||
const sql = `
|
||||
INSERT INTO customers_custom_info_requests (customer_id, info_request_id, customer_data)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (customer_id, info_request_id)
|
||||
DO UPDATE SET customer_data = $3, approved = null`
|
||||
return db.none(sql, [customerId, infoRequestId, data])
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCustomInfoRequests,
|
||||
addCustomInfoRequest,
|
||||
removeCustomInfoRequest,
|
||||
editCustomInfoRequest,
|
||||
getAllCustomInfoRequestsForCustomer,
|
||||
getCustomInfoRequestForCustomer,
|
||||
batchGetAllCustomInfoRequestsForCustomer,
|
||||
getCustomInfoRequest,
|
||||
batchGetCustomInfoRequest,
|
||||
setAuthorizedCustomRequest,
|
||||
setCustomerData
|
||||
}
|
||||
|
|
@ -18,6 +18,13 @@ const { getTx } = require('../new-admin/services/transactions.js')
|
|||
const { getCustomerById } = require('../customers')
|
||||
const machineLoader = require('../machine-loader')
|
||||
const { loadLatestConfig } = require('../new-settings-loader')
|
||||
const customInfoRequestQueries = require('../new-admin/services/customInfoRequests')
|
||||
|
||||
function updateCustomerCustomInfoRequest (customerId, dataToSave, req, res) {
|
||||
return customInfoRequestQueries.setCustomerData(customerId, dataToSave.info_request_id, dataToSave)
|
||||
.then(() => customers.getById(customerId))
|
||||
.then(customer => respond(req, res, { customer }))
|
||||
}
|
||||
|
||||
function updateCustomer (req, res, next) {
|
||||
const id = req.params.id
|
||||
|
|
@ -27,6 +34,10 @@ function updateCustomer (req, res, next) {
|
|||
const triggers = configManager.getTriggers(req.settings.config)
|
||||
const compatTriggers = complianceTriggers.getBackwardsCompatibleTriggers(triggers)
|
||||
|
||||
if (patch.customRequestPatch) {
|
||||
return updateCustomerCustomInfoRequest(id, patch.dataToSave, req, res).catch(next)
|
||||
}
|
||||
|
||||
customers.getById(id)
|
||||
.then(customer => {
|
||||
if (!customer) { throw httpError('Not Found', 404) }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ const plugins = require('../plugins')
|
|||
const semver = require('semver')
|
||||
const state = require('../middlewares/state')
|
||||
const version = require('../../package.json').version
|
||||
const customRequestQueries = require('../new-admin/services/customInfoRequests')
|
||||
|
||||
const urlsToPing = [
|
||||
`us.archive.ubuntu.com`,
|
||||
|
|
@ -37,6 +38,24 @@ const createTerms = terms => (terms.active && terms.text) ? ({
|
|||
cancel: terms.cancelButtonText
|
||||
}) : null
|
||||
|
||||
const buildTriggers = (allTriggers) => {
|
||||
const normalTriggers = []
|
||||
const customTriggers = _.filter(o => {
|
||||
if (o.customInfoRequestId === '') normalTriggers.push(o)
|
||||
return o.customInfoRequestId !== ''
|
||||
}, allTriggers)
|
||||
|
||||
return _.flow([_.map(_.get('customInfoRequestId')), customRequestQueries.batchGetCustomInfoRequest])(customTriggers)
|
||||
.then(res => {
|
||||
res.forEach((details, index) => {
|
||||
// make sure we aren't attaching the details to the wrong trigger
|
||||
if (customTriggers[index].customInfoRequestId !== details.id) return
|
||||
customTriggers[index] = { ...customTriggers[index], customInfoRequest: details }
|
||||
})
|
||||
return [...normalTriggers, ...customTriggers]
|
||||
})
|
||||
}
|
||||
|
||||
function poll (req, res, next) {
|
||||
const machineVersion = req.query.version
|
||||
const machineModel = req.query.model
|
||||
|
|
@ -54,8 +73,8 @@ function poll (req, res, next) {
|
|||
const pi = plugins(settings, deviceId)
|
||||
const hasLightning = checkHasLightning(settings)
|
||||
|
||||
const triggers = configManager.getTriggers(settings.config)
|
||||
const triggersAutomation = configManager.getTriggersAutomation(settings.config)
|
||||
const triggersPromise = buildTriggers(configManager.getTriggers(settings.config))
|
||||
|
||||
const operatorInfo = configManager.getOperatorInfo(settings.config)
|
||||
const machineInfo = { deviceId: req.deviceId, deviceName: req.deviceName }
|
||||
|
|
@ -65,8 +84,8 @@ function poll (req, res, next) {
|
|||
|
||||
state.pids[operatorId] = { [deviceId]: { pid, ts: Date.now() } }
|
||||
|
||||
return pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel)
|
||||
.then(results => {
|
||||
return Promise.all([pi.pollQueries(serialNumber, deviceTime, req.query, machineVersion, machineModel), triggersPromise])
|
||||
.then(([results, triggers]) => {
|
||||
const cassettes = results.cassettes
|
||||
|
||||
const reboot = pid && state.reboots?.[operatorId]?.[deviceId] === pid
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue