feat(virtualq): add actions to manage waiters
This commit is contained in:
@@ -0,0 +1,134 @@
|
|||||||
|
import defineAction from '../../../../helpers/define-action.js';
|
||||||
|
|
||||||
|
export default defineAction({
|
||||||
|
name: 'Create waiter',
|
||||||
|
key: 'createWaiter',
|
||||||
|
description: 'Enqueues a waiter to the line with the selected line.',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
label: 'Line',
|
||||||
|
key: 'lineId',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
description: 'The line to join',
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listLines',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Phone',
|
||||||
|
key: 'phone',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
description:
|
||||||
|
"The caller's phone number including country code (for example +4017111112233)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Channel',
|
||||||
|
key: 'channel',
|
||||||
|
type: 'dropdown',
|
||||||
|
description:
|
||||||
|
'Option describing if the waiter expects a callback or will receive a text message',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
options: [
|
||||||
|
{ label: 'Call back', value: 'CallBack' },
|
||||||
|
{ label: 'Call in', value: 'CallIn' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Source',
|
||||||
|
key: 'source',
|
||||||
|
type: 'dropdown',
|
||||||
|
description: 'Option describing the source where the caller came from',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
options: [
|
||||||
|
{ label: 'Widget', value: 'Widget' },
|
||||||
|
{ label: 'Phone', value: 'Phone' },
|
||||||
|
{ label: 'Mobile', value: 'Mobile' },
|
||||||
|
{ label: 'App', value: 'App' },
|
||||||
|
{ label: 'Other', value: 'Other' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Appointment',
|
||||||
|
key: 'appointment',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
value: false,
|
||||||
|
description:
|
||||||
|
'If set to true, then this marks this as an appointment. If appointment_time is set, this is automatically set to true.',
|
||||||
|
options: [
|
||||||
|
{ label: 'Yes', value: true },
|
||||||
|
{ label: 'No', value: false },
|
||||||
|
],
|
||||||
|
additionalFields: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicFields',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listAppointmentFields',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'parameters.appointment',
|
||||||
|
value: '{parameters.appointment}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Service phone to call',
|
||||||
|
key: 'servicePhoneToCall',
|
||||||
|
type: 'string',
|
||||||
|
description:
|
||||||
|
"If set, callback uses this number instead of the line's service phone number",
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async run($) {
|
||||||
|
const {
|
||||||
|
lineId,
|
||||||
|
phone,
|
||||||
|
channel,
|
||||||
|
source,
|
||||||
|
appointment,
|
||||||
|
appointmentTime,
|
||||||
|
servicePhoneToCall,
|
||||||
|
} = $.step.parameters;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
data: {
|
||||||
|
type: 'waiters',
|
||||||
|
attributes: {
|
||||||
|
line_id: lineId,
|
||||||
|
phone,
|
||||||
|
channel,
|
||||||
|
source,
|
||||||
|
appointment,
|
||||||
|
servicePhoneToCall,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (appointment) {
|
||||||
|
body.data.attributes.appointmentTime = appointmentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await $.http.post('/v2/waiters', body);
|
||||||
|
|
||||||
|
$.setActionItem({ raw: data });
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import defineAction from '../../../../helpers/define-action.js';
|
||||||
|
|
||||||
|
export default defineAction({
|
||||||
|
name: 'Delete waiter',
|
||||||
|
key: 'deleteWaiter',
|
||||||
|
description:
|
||||||
|
'Cancels waiting. The provided waiter will be removed from the queue.',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
label: 'Waiter',
|
||||||
|
key: 'waiterId',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listWaiters',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async run($) {
|
||||||
|
const waiterId = $.step.parameters.waiterId;
|
||||||
|
|
||||||
|
const { data } = await $.http.delete(`/v2/waiters/${waiterId}`);
|
||||||
|
|
||||||
|
$.setActionItem({ raw: { output: data } });
|
||||||
|
},
|
||||||
|
});
|
||||||
6
packages/backend/src/apps/virtualq/actions/index.js
Normal file
6
packages/backend/src/apps/virtualq/actions/index.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import createWaiter from './create-waiter/index.js';
|
||||||
|
import deleteWaiter from './delete-waiter/index.js';
|
||||||
|
import showWaiter from './show-waiter/index.js';
|
||||||
|
import updateWaiter from './update-waiter/index.js';
|
||||||
|
|
||||||
|
export default [createWaiter, deleteWaiter, showWaiter, updateWaiter];
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import defineAction from '../../../../helpers/define-action.js';
|
||||||
|
|
||||||
|
export default defineAction({
|
||||||
|
name: 'Show waiter',
|
||||||
|
key: 'showWaiter',
|
||||||
|
description: 'Returns the complete waiter information.',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
label: 'Waiter',
|
||||||
|
key: 'waiterId',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listWaiters',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async run($) {
|
||||||
|
const waiterId = $.step.parameters.waiterId;
|
||||||
|
|
||||||
|
const { data } = await $.http.get(`/v2/waiters/${waiterId}`);
|
||||||
|
|
||||||
|
$.setActionItem({ raw: data });
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import defineAction from '../../../../helpers/define-action.js';
|
||||||
|
|
||||||
|
export default defineAction({
|
||||||
|
name: 'Update waiter',
|
||||||
|
key: 'updateWaiter',
|
||||||
|
description: 'Updates a waiter to the line with the selected line.',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
label: 'Waiter',
|
||||||
|
key: 'waiterId',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listWaiters',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Line',
|
||||||
|
key: 'lineId',
|
||||||
|
type: 'dropdown',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
description: 'Used to find caller if 0 is used for waiter field',
|
||||||
|
source: {
|
||||||
|
type: 'query',
|
||||||
|
name: 'getDynamicData',
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
value: 'listLines',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Phone',
|
||||||
|
key: 'phone',
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
description: 'Used to find caller if 0 is used for waiter field',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'EWT',
|
||||||
|
key: 'serviceWaiterEwt',
|
||||||
|
type: 'string',
|
||||||
|
description: 'EWT as calculated by the service',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'State',
|
||||||
|
key: 'serviceWaiterState',
|
||||||
|
type: 'dropdown',
|
||||||
|
description: 'State of caller in the call center',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
options: [
|
||||||
|
{ label: 'Waiting', value: 'Waiting' },
|
||||||
|
{ label: 'Connected', value: 'Connected' },
|
||||||
|
{ label: 'Transferred', value: 'Transferred' },
|
||||||
|
{ label: 'Timeout', value: 'Timeout' },
|
||||||
|
{ label: 'Canceled', value: 'Canceled' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Wait time',
|
||||||
|
key: 'waitTimeWhenUp',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Wait time in seconds before being transferred to agent',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Talk time',
|
||||||
|
key: 'talkTime',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Time in seconds spent talking with Agent',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Agent',
|
||||||
|
key: 'agentId',
|
||||||
|
type: 'string',
|
||||||
|
description: 'Agent where call was transferred to',
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Service phone to call',
|
||||||
|
key: 'servicePhoneToCall',
|
||||||
|
type: 'string',
|
||||||
|
description:
|
||||||
|
"If set, callback uses this number instead of the line's service phone number",
|
||||||
|
required: false,
|
||||||
|
variables: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
async run($) {
|
||||||
|
const {
|
||||||
|
waiterId,
|
||||||
|
lineId,
|
||||||
|
phone,
|
||||||
|
serviceWaiterEwt,
|
||||||
|
serviceWaiterState,
|
||||||
|
waitTimeWhenUp,
|
||||||
|
talkTime,
|
||||||
|
agentId,
|
||||||
|
servicePhoneToCall,
|
||||||
|
} = $.step.parameters;
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
data: {
|
||||||
|
type: 'waiters',
|
||||||
|
attributes: {
|
||||||
|
line_id: lineId,
|
||||||
|
phone,
|
||||||
|
service_phone_to_call: servicePhoneToCall,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (serviceWaiterEwt) {
|
||||||
|
body.data.attributes.service_waiter_ewt = serviceWaiterEwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serviceWaiterState) {
|
||||||
|
body.data.attributes.service_waiter_state = serviceWaiterState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (talkTime) {
|
||||||
|
body.data.attributes.talk_time = talkTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agentId) {
|
||||||
|
body.data.attributes.agent_id = agentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitTimeWhenUp) {
|
||||||
|
body.data.attributes.wait_time_when_up = waitTimeWhenUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await $.http.put(`/v2/waiters/${waiterId}`, body);
|
||||||
|
|
||||||
|
$.setActionItem({ raw: data });
|
||||||
|
},
|
||||||
|
});
|
||||||
35
packages/backend/src/apps/virtualq/assets/favicon.svg
Normal file
35
packages/backend/src/apps/virtualq/assets/favicon.svg
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 229.2 57.3">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 { fill: #2E3D59; } .cls-2 { fill: #f5d05e; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<g id="Ebene_1">
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo" class="cls-1" d="M16.3,40.4c-.2.5-.6.8-1.1.8h-4.3c-.5,0-1-.2-1.2-.8L0,17.9c-.2-.4.1-.8.5-.8h4.3c.5,0,1,.2,1.1.8l6.9,16.6,6.9-16.6c.2-.5.6-.8,1.1-.8h4.3c.4,0,.7.4.5.8l-9.6,22.5h0Z"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-2" class="cls-1" d="M219.7,19.2c-5.3,0-9.6-4.3-9.6-9.6S214.4,0,219.7,0s9.6,4.3,9.6,9.6-4.3,9.6-9.6,9.6ZM219.7,1c-4.7,0-8.6,3.8-8.6,8.6s3.8,8.6,8.6,8.6,8.6-3.8,8.6-8.6-3.8-8.6-8.6-8.6Z"/>
|
||||||
|
<path id="fullLogo-3" class="cls-2" d="M185.7,35.9c-7.8,0-14.2-6.4-14.2-14.2s6.4-14.2,14.2-14.2,14.2,6.4,14.2,14.2-.8,5.3-2.2,7.5l-2.2-2.1c-1.4-1.3-3.7-1.3-5,.1-1.3,1.4-1.3,3.7.1,5l2,1.8c-2,1.1-4.4,1.8-6.9,1.8M202.9,34c2.5-3.5,4-7.7,4-12.3,0-11.7-9.5-21.2-21.2-21.2s-21.2,9.5-21.2,21.2,9.5,21.2,21.2,21.2,8.7-1.4,12.1-3.8l3.1,2.9c.7.6,1.6,1,2.4,1s1.9-.4,2.6-1.1c1.3-1.4,1.3-3.7-.1-5l-2.9-2.7h0Z"/>
|
||||||
|
<path id="fullLogo-4" class="cls-1" d="M37.8,40.4c0,.5-.3.8-.8.8h-3.9c-.5,0-.8-.3-.8-.8v-22.4c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v22.4ZM35,4.2c1.9,0,3.4,1.5,3.4,3.4s-1.5,3.4-3.4,3.4-3.4-1.5-3.4-3.4,1.5-3.4,3.4-3.4"/>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-5" class="cls-1" d="M106.8,29.9v-11.9c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v11.9c0,8-5.1,12-11.8,12s-11.8-4-11.8-12v-11.9c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v11.9c0,5.5,3.6,6.7,6.3,6.7s6.3-1.2,6.3-6.7"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-6" class="cls-1" d="M131.7,21.7c-3.1,0-7.2,1.8-7.2,7.5s3.4,7.5,6.4,7.6c3,.2,7.7-1.5,7.7-7.5s-3.9-7.6-7-7.6M144.3,40.4c0,.5-.3.8-.8.8h-3.9c-.5,0-.8-.3-.8-.8v-2.4c-2,3.2-5.8,3.9-8.2,3.9-7.5,0-11.6-6-11.6-12.5s5.7-12.9,12.8-12.9,12.5,4.3,12.5,13v11h0Z"/>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-7" class="cls-1" d="M156.8,4.2h-3.9c-.5,0-.8.3-.8.8v35.3c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8V5c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-8" class="cls-1" d="M83.1,17.1h-6.4V5c0-.5-.3-.8-.8-.8h-3.9c-.5,0-.8.3-.8.8v12.1h-6.4c-.5,0-.8.3-.8.8v3.6c0,.5.3.8.8.8h6.4v17.9c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8v-17.9h6.4c.5,0,.8-.3.8-.8v-3.6c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-9" class="cls-1" d="M58.4,17.1h-6.4c-4.5,0-7.9,3.4-7.9,10v13.2c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8v-.9s0,0,0,0v-12.3c0-3,1.8-4.7,3.9-4.7h4.9c.5,0,.8-.3.8-.8v-3.6c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-39" class="cls-1" d="M218.8,6.9c0-.1-.1-.2-.3-.2h-1c-.1,0-.2,0-.3.2l-2.3,5.3c0,0,0,.2.1.2h1c.1,0,.2,0,.3-.2l1.6-3.9,1.6,3.9c0,.1.1.2.3.2h1c0,0,.2,0,.1-.2l-2.3-5.3h0Z"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-40" class="cls-1" d="M223.8,12.2c0,.1,0,.2-.2.2h-.9c-.1,0-.2,0-.2-.2v-5.3c0-.1,0-.2.2-.2h.9c.1,0,.2,0,.2.2v5.3Z"/>
|
||||||
|
<path id="fullLogo-41" class="cls-1" d="M219.7,10.2c0,0,.1,0,.1.2v.9c0,.1,0,.2-.1.2h-3.4c0,0-.1,0-.1-.2v-.9c0-.1,0-.2.1-.2h3.4Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
21
packages/backend/src/apps/virtualq/auth/index.js
Normal file
21
packages/backend/src/apps/virtualq/auth/index.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import verifyCredentials from './verify-credentials.js';
|
||||||
|
import isStillVerified from './is-still-verified.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'apiKey',
|
||||||
|
label: 'API Key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
readOnly: false,
|
||||||
|
value: null,
|
||||||
|
placeholder: null,
|
||||||
|
description: 'API key of the VirtualQ API service.',
|
||||||
|
clickToCopy: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
verifyCredentials,
|
||||||
|
isStillVerified,
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import verifyCredentials from './verify-credentials.js';
|
||||||
|
|
||||||
|
const isStillVerified = async ($) => {
|
||||||
|
await verifyCredentials($);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default isStillVerified;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const verifyCredentials = async ($) => {
|
||||||
|
const response = await $.http.get('/v2/call_centers');
|
||||||
|
|
||||||
|
const callCenterNames = response.data.data
|
||||||
|
.map((callCenter) => callCenter.attributes.name)
|
||||||
|
.join(' - ');
|
||||||
|
|
||||||
|
await $.auth.set({
|
||||||
|
screenName: callCenterNames,
|
||||||
|
apiKey: $.auth.data.apiKey,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default verifyCredentials;
|
||||||
15
packages/backend/src/apps/virtualq/common/add-auth-header.js
Normal file
15
packages/backend/src/apps/virtualq/common/add-auth-header.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const addAuthHeader = ($, requestConfig) => {
|
||||||
|
if ($.auth.data?.apiKey) {
|
||||||
|
requestConfig.headers['X-API-Key'] = $.auth.data.apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestConfig.method === 'post' || requestConfig.method === 'put') {
|
||||||
|
requestConfig.headers['Content-Type'] = 'application/vnd.api+json';
|
||||||
|
}
|
||||||
|
|
||||||
|
requestConfig.headers['X-Keys-Format'] = 'underscore';
|
||||||
|
|
||||||
|
return requestConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default addAuthHeader;
|
||||||
4
packages/backend/src/apps/virtualq/dynamic-data/index.js
Normal file
4
packages/backend/src/apps/virtualq/dynamic-data/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import listLines from './list-lines/index.js';
|
||||||
|
import listWaiters from './list-waiters/index.js';
|
||||||
|
|
||||||
|
export default [listLines, listWaiters];
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
name: 'List lines',
|
||||||
|
key: 'listLines',
|
||||||
|
|
||||||
|
async run($) {
|
||||||
|
const response = await $.http.get('/v2/lines');
|
||||||
|
|
||||||
|
const lines = response.data.data.map((line) => ({
|
||||||
|
value: line.id,
|
||||||
|
name: line.attributes.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { data: lines };
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
name: 'List waiters',
|
||||||
|
key: 'listWaiters',
|
||||||
|
|
||||||
|
async run($) {
|
||||||
|
const response = await $.http.get('/v2/waiters');
|
||||||
|
|
||||||
|
const lines = response.data.data.map((line) => ({
|
||||||
|
value: line.id,
|
||||||
|
name: line.attributes.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { data: lines };
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import listAppointmentFields from './list-appointment-fields/index.js';
|
||||||
|
|
||||||
|
export default [listAppointmentFields];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export default {
|
||||||
|
name: 'List appointment fields',
|
||||||
|
key: 'listAppointmentFields',
|
||||||
|
|
||||||
|
async run($) {
|
||||||
|
if ($.step.parameters.appointment) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Appointment Time',
|
||||||
|
key: 'appointmentTime',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
variables: true,
|
||||||
|
description:
|
||||||
|
'Overrides the estimated up time with this time. Specify number of seconds since 1970 UTC.',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
22
packages/backend/src/apps/virtualq/index.js
Normal file
22
packages/backend/src/apps/virtualq/index.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import defineApp from '../../helpers/define-app.js';
|
||||||
|
import addAuthHeader from './common/add-auth-header.js';
|
||||||
|
import auth from './auth/index.js';
|
||||||
|
import actions from './actions/index.js';
|
||||||
|
import dynamicData from './dynamic-data/index.js';
|
||||||
|
import dynamicFields from './dynamic-fields/index.js';
|
||||||
|
|
||||||
|
export default defineApp({
|
||||||
|
name: 'VirtualQ',
|
||||||
|
key: 'virtualq',
|
||||||
|
iconUrl: '{BASE_URL}/apps/virtualq/assets/favicon.svg',
|
||||||
|
authDocUrl: '{DOCS_URL}/apps/virtualq/connection',
|
||||||
|
supportsConnections: true,
|
||||||
|
baseUrl: 'https://www.virtualq.io',
|
||||||
|
apiBaseUrl: 'https://api.virtualq.io/api/',
|
||||||
|
primaryColor: '#2E3D59',
|
||||||
|
beforeRequest: [addAuthHeader],
|
||||||
|
auth,
|
||||||
|
actions,
|
||||||
|
dynamicData,
|
||||||
|
dynamicFields,
|
||||||
|
});
|
||||||
35
packages/docs/pages/public/favicons/virtualq.svg
Normal file
35
packages/docs/pages/public/favicons/virtualq.svg
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 229.2 57.3">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 { fill: #2E3D59; } .cls-2 { fill: #f5d05e; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<g id="Ebene_1">
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo" class="cls-1" d="M16.3,40.4c-.2.5-.6.8-1.1.8h-4.3c-.5,0-1-.2-1.2-.8L0,17.9c-.2-.4.1-.8.5-.8h4.3c.5,0,1,.2,1.1.8l6.9,16.6,6.9-16.6c.2-.5.6-.8,1.1-.8h4.3c.4,0,.7.4.5.8l-9.6,22.5h0Z"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-2" class="cls-1" d="M219.7,19.2c-5.3,0-9.6-4.3-9.6-9.6S214.4,0,219.7,0s9.6,4.3,9.6,9.6-4.3,9.6-9.6,9.6ZM219.7,1c-4.7,0-8.6,3.8-8.6,8.6s3.8,8.6,8.6,8.6,8.6-3.8,8.6-8.6-3.8-8.6-8.6-8.6Z"/>
|
||||||
|
<path id="fullLogo-3" class="cls-2" d="M185.7,35.9c-7.8,0-14.2-6.4-14.2-14.2s6.4-14.2,14.2-14.2,14.2,6.4,14.2,14.2-.8,5.3-2.2,7.5l-2.2-2.1c-1.4-1.3-3.7-1.3-5,.1-1.3,1.4-1.3,3.7.1,5l2,1.8c-2,1.1-4.4,1.8-6.9,1.8M202.9,34c2.5-3.5,4-7.7,4-12.3,0-11.7-9.5-21.2-21.2-21.2s-21.2,9.5-21.2,21.2,9.5,21.2,21.2,21.2,8.7-1.4,12.1-3.8l3.1,2.9c.7.6,1.6,1,2.4,1s1.9-.4,2.6-1.1c1.3-1.4,1.3-3.7-.1-5l-2.9-2.7h0Z"/>
|
||||||
|
<path id="fullLogo-4" class="cls-1" d="M37.8,40.4c0,.5-.3.8-.8.8h-3.9c-.5,0-.8-.3-.8-.8v-22.4c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v22.4ZM35,4.2c1.9,0,3.4,1.5,3.4,3.4s-1.5,3.4-3.4,3.4-3.4-1.5-3.4-3.4,1.5-3.4,3.4-3.4"/>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-5" class="cls-1" d="M106.8,29.9v-11.9c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v11.9c0,8-5.1,12-11.8,12s-11.8-4-11.8-12v-11.9c0-.5.3-.8.8-.8h3.9c.5,0,.8.3.8.8v11.9c0,5.5,3.6,6.7,6.3,6.7s6.3-1.2,6.3-6.7"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-6" class="cls-1" d="M131.7,21.7c-3.1,0-7.2,1.8-7.2,7.5s3.4,7.5,6.4,7.6c3,.2,7.7-1.5,7.7-7.5s-3.9-7.6-7-7.6M144.3,40.4c0,.5-.3.8-.8.8h-3.9c-.5,0-.8-.3-.8-.8v-2.4c-2,3.2-5.8,3.9-8.2,3.9-7.5,0-11.6-6-11.6-12.5s5.7-12.9,12.8-12.9,12.5,4.3,12.5,13v11h0Z"/>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-7" class="cls-1" d="M156.8,4.2h-3.9c-.5,0-.8.3-.8.8v35.3c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8V5c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-8" class="cls-1" d="M83.1,17.1h-6.4V5c0-.5-.3-.8-.8-.8h-3.9c-.5,0-.8.3-.8.8v12.1h-6.4c-.5,0-.8.3-.8.8v3.6c0,.5.3.8.8.8h6.4v17.9c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8v-17.9h6.4c.5,0,.8-.3.8-.8v-3.6c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-9" class="cls-1" d="M58.4,17.1h-6.4c-4.5,0-7.9,3.4-7.9,10v13.2c0,.5.3.8.8.8h3.9c.5,0,.8-.3.8-.8v-.9s0,0,0,0v-12.3c0-3,1.8-4.7,3.9-4.7h4.9c.5,0,.8-.3.8-.8v-3.6c0-.5-.3-.8-.8-.8"/>
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<path id="fullLogo-39" class="cls-1" d="M218.8,6.9c0-.1-.1-.2-.3-.2h-1c-.1,0-.2,0-.3.2l-2.3,5.3c0,0,0,.2.1.2h1c.1,0,.2,0,.3-.2l1.6-3.9,1.6,3.9c0,.1.1.2.3.2h1c0,0,.2,0,.1-.2l-2.3-5.3h0Z"/>
|
||||||
|
</a>
|
||||||
|
<path id="fullLogo-40" class="cls-1" d="M223.8,12.2c0,.1,0,.2-.2.2h-.9c-.1,0-.2,0-.2-.2v-5.3c0-.1,0-.2.2-.2h.9c.1,0,.2,0,.2.2v5.3Z"/>
|
||||||
|
<path id="fullLogo-41" class="cls-1" d="M219.7,10.2c0,0,.1,0,.1.2v.9c0,.1,0,.2-.1.2h-3.4c0,0-.1,0-.1-.2v-.9c0-.1,0-.2.1-.2h3.4Z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
Reference in New Issue
Block a user