tango-app-api-client 3.3.3-beta.1 → 3.3.3-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,43 +1,42 @@
1
- {
2
- "name": "tango-app-api-client",
3
- "version": "3.3.3-beta.1",
4
- "description": "client",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
- },
10
- "engines": {
11
- "node": ">=18.10.0"
12
- },
13
- "author": "praveenraj",
14
- "license": "ISC",
15
- "dependencies": {
16
- "aws-sdk": "^2.1560.0",
17
- "cors": "^2.8.5",
18
- "dotenv": "^16.4.4",
19
- "express": "^4.18.2",
20
- "express-fileupload": "^1.4.3",
21
- "handlebars": "^4.7.8",
22
- "i": "^0.3.7",
23
- "joi": "^17.12.1",
24
- "joi-to-swagger": "^6.2.0",
25
- "lodash": "^4.17.21",
26
- "mongodb": "^6.3.0",
27
- "nodemon": "^3.0.3",
28
- "npm": "^10.9.1",
29
- "swagger-ui-express": "^5.0.0",
30
- "tango-api-schema": "^2.1.92",
31
- "tango-app-api-middleware": "^3.1.43-alpha.10",
32
- "winston": "^3.11.0",
33
- "winston-daily-rotate-file": "^5.0.0"
34
- },
35
- "devDependencies": {
36
- "eslint": "^8.56.0",
37
- "eslint-config-google": "^0.14.0",
38
- "eslint-config-semistandard": "^17.0.0",
39
- "eslint-config-standard": "^17.1.0",
40
- "eslint-plugin-import": "^2.29.1",
41
- "eslint-plugin-promise": "^6.1.1"
42
- }
43
- }
1
+ {
2
+ "name": "tango-app-api-client",
3
+ "version": "3.3.3-beta.11",
4
+ "description": "client",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "nodemon --exec \"eslint --fix . && node index.js\""
9
+ },
10
+ "engines": {
11
+ "node": ">=18.10.0"
12
+ },
13
+ "author": "praveenraj",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "aws-sdk": "^2.1560.0",
17
+ "cors": "^2.8.5",
18
+ "dotenv": "^16.4.4",
19
+ "express": "^4.18.2",
20
+ "express-fileupload": "^1.4.3",
21
+ "handlebars": "^4.7.8",
22
+ "joi": "^17.12.1",
23
+ "joi-to-swagger": "^6.2.0",
24
+ "lodash": "^4.17.21",
25
+ "mongodb": "^6.7.0",
26
+ "nodemon": "^3.0.3",
27
+ "npm": "^10.9.1",
28
+ "swagger-ui-express": "^5.0.0",
29
+ "tango-api-schema": "^2.2.59",
30
+ "tango-app-api-middleware": "^3.1.60",
31
+ "winston": "^3.11.0",
32
+ "winston-daily-rotate-file": "^5.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "eslint": "^8.56.0",
36
+ "eslint-config-google": "^0.14.0",
37
+ "eslint-config-semistandard": "^17.0.0",
38
+ "eslint-config-standard": "^17.1.0",
39
+ "eslint-plugin-import": "^2.29.1",
40
+ "eslint-plugin-promise": "^6.1.1"
41
+ }
42
+ }
@@ -1,5 +1,5 @@
1
1
  import { billingDetailsUpdate, brandInfoUpdate, domainDetailsConfigurationUpdate, featureConfigurationUpdate, getClientData, signatoryDetailsUpdate, ticketConfigurationUpdate, documentsUpdate, getUserData, CsmUsersGet, OpsUsersGet, userConfigurationUpdate, findClient, aggregateClient, createAuditQueue, findOne, insert, update, findOneClient, updateOneClient } from '../service/client.service.js';
2
- import { checkFileExist, fileUpload, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, sendEmailWithSES, createCustomer, createVirtualAccount } from 'tango-app-api-middleware';
2
+ import { checkFileExist, fileUpload, signedUrl, chunkArray, download, logger, getOpenSearchData, insertOpenSearchData, sendEmailWithSES, createCustomer, createVirtualAccount, getUuid } from 'tango-app-api-middleware';
3
3
  import { countDocumentsUser, findOneAndUpdateUser, findOneUser, getUserNameEmailById, updateManyUser } from '../service/user.service.js';
4
4
  import { aggregateStore, countDocumentsStore, findStore, updateManyStore } from '../service/store.service.js';
5
5
  import { aggregateCamera, countDocumentsCamera } from '../service/camera.service.js';
@@ -37,7 +37,6 @@ export async function create( req, res ) {
37
37
  ];
38
38
  const ID = await aggregateClient( countQuery );
39
39
  const count = ID[0]?.tangoId || 0;
40
- logger.info( { count: count } );
41
40
  const query = { clientName: inputData.clientName };
42
41
  const leadRecord = await findOne( query );
43
42
  const tangoId = count + 1;
@@ -71,7 +70,6 @@ export async function create( req, res ) {
71
70
  'planDetails.product': product,
72
71
  'profileDetails.website': leadRecord?.websiteUrl,
73
72
  'reportConfigs.reportName': generatedName,
74
- 'auditConfigs.queueName': generatedName,
75
73
  'auditConfigs.zoneQueueName': `${generatedName}-zone`,
76
74
  'auditConfigs.trafficQueueName': `${generatedName}-traffic`,
77
75
  'auditConfigs.traxQueueName.unattendedCustomer': `${generatedName}-unattendedCustomer`,
@@ -79,6 +77,10 @@ export async function create( req, res ) {
79
77
  'auditConfigs.traxQueueName.uniformDetection': `${generatedName}-uniformDetection`,
80
78
  'auditConfigs.traxQueueName.mobileDetection': `${generatedName}-mobileDetection`,
81
79
  'auditConfigs.traxQueueName.cameraAngleChange': `${generatedName}-cameraAngleChange`,
80
+ 'auditConfigs.traxQueueName.hygiene': `${generatedName}-hygiene`,
81
+ 'clientApi.apiKey': await getUuid(),
82
+ 'clientApi.status': true,
83
+
82
84
  };
83
85
 
84
86
  record.featureConfigs = {};
@@ -330,7 +332,6 @@ export async function create( req, res ) {
330
332
  // await deleteOneAuthentication( { user: user?._id, type: 'retail' } );
331
333
  await findOneAndUpdateUser( userQuery, userRecord );
332
334
  await Promise.all( [
333
- createAuditQueue( generatedName ),
334
335
  createAuditQueue( `${generatedName}-zone` ),
335
336
  createAuditQueue( `${generatedName}-traffic` ),
336
337
  createAuditQueue( `${generatedName}-unattendedCustomer` ),
@@ -338,7 +339,7 @@ export async function create( req, res ) {
338
339
  createAuditQueue( `${generatedName}-uniformDetection` ),
339
340
  createAuditQueue( `${generatedName}-mobileDetection` ),
340
341
  createAuditQueue( `${generatedName}-cameraAngleChange` ),
341
- ] );
342
+ createAuditQueue( `${generatedName}-hygiene` ) ] );
342
343
  return res.sendSuccess( { result: { clientId: String( tangoId ) } } );
343
344
  }
344
345
  } catch ( error ) {
@@ -395,7 +396,7 @@ export async function changeStatus( req, res, next ) {
395
396
 
396
397
  export async function getClients( req, res ) {
397
398
  try {
398
- const field = { clientName: 1, clientId: 1 };
399
+ const field = { clientName: 1, clientId: 1, traxDateRange: '$featureConfigs.traxDateRange', trafficDateRange: '$featureConfigs.trafficDateRange' };
399
400
  let result = [];
400
401
  if ( req?.user?.role === 'superadmin' ) {
401
402
  result = await findClient( {}, field );
@@ -405,18 +406,6 @@ export async function getClients( req, res ) {
405
406
  $match: {
406
407
  userEmail: req?.user?.email,
407
408
  assignedType: { $eq: 'client' },
408
- // $expr: {
409
- // $cond: {
410
- // if: {
411
- // $and: [
412
- // { $eq: [ '$userType', 'tango' ] },
413
- // { $eq: [ '$tangoUserType', 'csm' ] },
414
- // ],
415
- // },
416
- // then: { $eq: [ '$isClientApproved', true ] },
417
- // else: true,
418
- // },
419
- // },
420
409
  },
421
410
  },
422
411
  {
@@ -450,9 +439,9 @@ export async function getClients( req, res ) {
450
439
  },
451
440
  {
452
441
  $project: {
453
- _id: 0,
454
442
  clientId: 1,
455
443
  clientName: 1,
444
+ traxDateRange: '$featureConfigs.traxDateRange',
456
445
  },
457
446
  },
458
447
  ];
@@ -711,33 +700,40 @@ export async function updateBrandInfo( req, res ) {
711
700
  updateKeys.push( camelCaseToWords( element ) );
712
701
  } );
713
702
  }
703
+ const getPreCientInfo = await findOneClient( { clientId: req.params.id }, { _id: 0, registeredCompanyName: '$profileDetails.registeredCompanyName', industry: '$profileDetails.industry', clientType: '$profileDetails.clientType',
704
+ registeredAddress: '$profileDetails.registeredAddress', headQuarters: '$profileDetails.headQuarters', website: '$profileDetails.website', status: 1, averageTransactionValue: 1 } );
714
705
 
715
- const user = await getUserNameEmailById( req.userId );
716
706
 
707
+ const updateAck = await brandInfoUpdate( {
708
+ clientId: req.params?.id, registeredCompanyName: req.body?.registeredCompanyName, industry: req.body?.industry,
709
+ clientType: req.body?.clientType, registeredAddress: req.body?.registeredAddress, headQuarters: req.body?.headQuarters,
710
+ website: req.body?.website, status: req.body?.status, logo: req.files?.logo ? `brandLogo.${req.files.logo.name.split( '.' )[1]}` : undefined, averageTransactionValue: req.body?.averageTransactionValue,
711
+ } );
712
+ const getPosCientInfo = await findOneClient( { clientId: req.params.id }, { _id: 0, registeredCompanyName: '$profileDetails.registeredCompanyName', industry: '$profileDetails.industry', clientType: '$profileDetails.clientType',
713
+ registeredAddress: '$profileDetails.registeredAddress', headQuarters: '$profileDetails.headQuarters', website: '$profileDetails.website', status: 1, averageTransactionValue: 1 } );
717
714
 
718
715
  const logObj = {
719
716
  clientId: req.params?.id,
720
- userName: user?.userName,
721
- email: user?.email,
717
+ userName: req?.user?.userName,
718
+ email: req?.user?.email,
722
719
  date: new Date(),
723
720
  logType: 'brandDetails',
724
721
  logSubType: 'brandInfo',
725
722
  changes: updateKeys,
726
723
  eventType: 'update',
727
724
  showTo: [ 'client', 'tango' ],
725
+ previous: getPreCientInfo,
726
+ current: getPosCientInfo,
728
727
  };
729
-
728
+ logger.info( { previous: getPreCientInfo,
729
+ current: getPosCientInfo, logObj: logObj } );
730
730
  if ( updateKeys.length ) {
731
- await insertOpenSearchData( openSearch.activityLog, logObj );
731
+ logger.info( { updateKeys: updateKeys } );
732
+ const a =await insertOpenSearchData( openSearch.activityLog, logObj );
733
+ logger.info( { a: a } );
732
734
  }
733
735
 
734
736
 
735
- const updateAck = await brandInfoUpdate( {
736
- clientId: req.params?.id, registeredCompanyName: req.body?.registeredCompanyName, industry: req.body?.industry,
737
- clientType: req.body?.clientType, registeredAddress: req.body?.registeredAddress, headQuarters: req.body?.headQuarters,
738
- website: req.body?.website, status: req.body?.status, logo: req.files?.logo ? `brandLogo.${req.files.logo.name.split( '.' )[1]}` : undefined, averageTransactionValue: req.body?.averageTransactionValue,
739
- } );
740
-
741
737
  if ( req.body?.status === 'active' ) {
742
738
  await updateManyStore( { clientId: req.params?.id }, { status: 'active' } );
743
739
  await updateManyUser( { clientId: req.params?.id }, { isActive: true } );
@@ -889,6 +885,7 @@ export async function updateSignatoryDetails( req, res ) {
889
885
  export async function updateTicketConfiguration( req, res ) {
890
886
  try {
891
887
  const openSearch = JSON.parse( process.env.OPENSEARCH );
888
+ let findClient = await findOneClient( { clientId: req.params?.id } );
892
889
  const updateAck = await ticketConfigurationUpdate( {
893
890
  clientId: req.params?.id, MinFilesCount: req.body?.MinFilesCount, accuracyPercentage: req.body?.accuracyPercentage, downTimeType: req.body?.downTimeType,
894
891
  infraDownTime: req.body?.infraDownTime, installationReAssign: req.body?.installationReAssign, isRcaTicketAssign: req.body?.isRcaTicketAssign,
@@ -904,6 +901,7 @@ export async function updateTicketConfiguration( req, res ) {
904
901
  }
905
902
 
906
903
  const user = await getUserNameEmailById( req.userId );
904
+ let updatedClient = await findOneClient( { clientId: req.params?.id } );
907
905
 
908
906
  const logObj = {
909
907
  clientId: req.params?.id,
@@ -915,6 +913,8 @@ export async function updateTicketConfiguration( req, res ) {
915
913
  changes: updateKeys,
916
914
  eventType: 'update',
917
915
  showTo: [ 'tango' ],
916
+ current: updatedClient.ticketConfigs,
917
+ previous: findClient.ticketConfigs,
918
918
  };
919
919
 
920
920
  if ( updateKeys.length ) {
@@ -1027,6 +1027,7 @@ export async function updateFeatureConfiguration( req, res ) {
1027
1027
  export async function domainDetailsConfiguration( req, res ) {
1028
1028
  try {
1029
1029
  const openSearch = JSON.parse( process.env.OPENSEARCH );
1030
+ const getPreData = await findOneClient( { clientId: req.params?.id }, { domainName: '$domainConfig.ssoLogin.domainName', TwoFactorAuthentication: '$domainConfig.ssoLogin.isEnable', ipWhitelist: '$domainConfig.ipWhitelisting.enableWhitelisting', WhitelistesIps: '$domainConfig.ipWhitelisting.allowedIps', enableOtp: '$domainConfig.enableOtp' } );
1030
1031
  const updateAck = await domainDetailsConfigurationUpdate( {
1031
1032
  clientId: req.params?.id, domainName: req.body?.domainName, isEnable: req.body?.isEnable,
1032
1033
  enableWhitelisting: req.body?.enableWhitelisting, allowedIps: req.body?.allowedIps, enableOtp: req.body?.enableOtp,
@@ -1041,19 +1042,20 @@ export async function domainDetailsConfiguration( req, res ) {
1041
1042
  } );
1042
1043
  }
1043
1044
 
1044
- const user = await getUserNameEmailById( req.userId );
1045
-
1045
+ const getPostData = await findOneClient( { clientId: req.params?.id }, { domainName: '$domainConfig.ssoLogin.domainName', TwoFactorAuthentication: '$domainConfig.enableOtp', ipWhitelist: '$domainConfig.ipWhitelisting.enableWhitelisting', WhitelistesIps: '$domainConfig.ipWhitelisting.allowedIps', isEnable: '$domainConfig.ssoLogin.isEnable' } );
1046
1046
 
1047
1047
  const logObj = {
1048
1048
  clientId: req.params?.id,
1049
- userName: user?.userName,
1050
- email: user?.email,
1049
+ userName: req?.user?.userName,
1050
+ email: req?.user?.email,
1051
1051
  date: new Date(),
1052
1052
  logType: 'configuration',
1053
1053
  logSubType: 'domainDetails',
1054
1054
  changes: updateKeys,
1055
1055
  eventType: 'update',
1056
1056
  showTo: [ 'client', 'tango' ],
1057
+ previous: getPreData,
1058
+ current: getPostData,
1057
1059
  };
1058
1060
 
1059
1061
  if ( updateKeys.length ) {
@@ -2026,7 +2028,7 @@ export async function getActivityLogs( req, res ) {
2026
2028
  const query = {
2027
2029
  '_source': [
2028
2030
  'userId', 'userName', 'email', 'date', 'logType', 'logSubType',
2029
- 'changes', 'eventType',
2031
+ 'changes', 'eventType', 'previous', 'current',
2030
2032
  ],
2031
2033
  'query': {
2032
2034
  'bool': {
@@ -2083,9 +2085,25 @@ export async function getActivityLogs( req, res ) {
2083
2085
 
2084
2086
  const hits = logs?.body?.hits?.hits;
2085
2087
  const totalDocuments = logs?.body?.hits?.total?.value;
2088
+ let temp = [];
2086
2089
  if ( totalDocuments ) {
2087
- const dataArray = hits.map( ( hit ) => hit._source );
2088
- res.sendSuccess( { data: dataArray, count: totalDocuments } );
2090
+ hits.map( ( hit, i ) => {
2091
+ let respo ={};
2092
+
2093
+ if ( ( ( hit?._source?.eventType ).match( /update/ ) || ( hit?._source?.eventType ).match( /edit/ ) )&& hit?._source?.previous ) {
2094
+ const previous = hit?._source?.previous;
2095
+ const current=hit?._source?.current;
2096
+ const logType =hit?._source?.logType;
2097
+ const logSubType =hit?._source?.logSubType;
2098
+ respo = findDifferences( previous, current, logType, logSubType );
2099
+ hit._source.updatedValue = respo;
2100
+ temp.push( hit?._source );
2101
+ } else {
2102
+ temp.push( hit?._source );
2103
+ }
2104
+ },
2105
+ );
2106
+ res.sendSuccess( { data: temp, count: totalDocuments } );
2089
2107
  } else {
2090
2108
  res.sendError( 'No data found', 204 );
2091
2109
  }
@@ -2096,6 +2114,122 @@ export async function getActivityLogs( req, res ) {
2096
2114
  }
2097
2115
 
2098
2116
 
2117
+ function findDifferences( previous, current, logType, logSubType, path = '' ) {
2118
+ const dbKeys = JSON.parse( process.env.DB_KEYS );
2119
+ const ignoredKeys = new Set( [
2120
+ '_id', 'updatedAt', 'createdAt', 'password', 'clientId',
2121
+ 'storeId', 'refreshToken', 'employeeId', 'fcmToken', 'permission',
2122
+ ] );
2123
+ const documents = dbKeys.DOCUMENTS;
2124
+ // Get correct key mapping based on logType
2125
+ const keyMapping = logType == 'stores' ?documents.stores: logType == 'users' ?documents.users :logSubType=='reportConfig'?documents.reports: logType=='brandInfo'?documents.client:documents.client;
2126
+
2127
+ let differences = {};
2128
+
2129
+ for ( const key in current ) {
2130
+ if ( !Object.prototype.hasOwnProperty.call( current, key ) || ignoredKeys.has( key ) ) continue;
2131
+
2132
+ const prevValue = previous[key];
2133
+ const currValue = current[key];
2134
+
2135
+ if ( typeof prevValue === 'object' && typeof currValue === 'object' && prevValue !== null && currValue !== null ) {
2136
+ const nestedDiffs = findDifferences( prevValue, currValue, logType, logSubType, `${path}${key}.` );
2137
+ Object.assign( differences, nestedDiffs );
2138
+ } else if ( prevValue !== currValue ) {
2139
+ if (
2140
+ ( prevValue === '' && currValue === '' ) ||
2141
+ ( Array.isArray( prevValue ) && Array.isArray( currValue ) && prevValue.length === 0 && currValue.length === 0 )
2142
+ ) {
2143
+ continue;
2144
+ }
2145
+ differences[`${path}${key}`] = { previous: prevValue, current: currValue };
2146
+ }
2147
+ }
2148
+
2149
+ // **Transform & Filter Differences**
2150
+ let updatedDifferences = {};
2151
+ Object.keys( differences ).forEach( ( key ) => {
2152
+ let newKey = key.replace( /spocDetails\.\d+\./, 'spocDetails.' ).replace( /WhitelistesIps\.\d+/, 'Whitelisted Ips' );
2153
+ let diff = differences[key];
2154
+
2155
+ if ( newKey.toLowerCase().includes( 'isactive' ) ) {
2156
+ diff = {
2157
+ previous: diff.previous ? 'Active' : 'Deactive',
2158
+ current: diff.current ? 'Active' : 'Deactive',
2159
+ };
2160
+ }
2161
+
2162
+ const userFriendlyKey = getUserFriendlyKey( newKey, keyMapping );
2163
+ if ( userFriendlyKey ) {
2164
+ newKey = userFriendlyKey;
2165
+ }
2166
+
2167
+ if ( newKey === 'Infra Email Alert' || newKey === 'Ip Whitelist' ) {
2168
+ diff.previous = ( diff.previous == true || diff.previous == 'Enabled' ) ? 'Enabled' : 'Disabled';
2169
+ diff.current = ( diff.current == true || diff.current == 'Enabled' ) ? 'Enabled' : 'Disabled';
2170
+ }
2171
+ if ( newKey === 'Mat Enabled' ) {
2172
+ diff.previous = ( diff.previous == true || diff.previous == 'Enabled' )?'Enabled' : 'Disabled';
2173
+ diff.current = ( diff.current == true || diff.current == 'Enabled' ) ? 'Enabled' : 'Disabled';
2174
+ }
2175
+
2176
+ if ( newKey === 'Two Factor Authentication' ) {
2177
+ diff.previous = ( diff.previous == true || diff.previous == 'Enabled' ) ? 'Enabled' : 'Disabled';
2178
+ diff.current = ( diff.current == true || diff.current == 'Enabled' ) ? 'Enabled' : 'Disabled';
2179
+ }
2180
+
2181
+
2182
+ // **Transform Roles Permission Keys**
2183
+ const rolesPermissionMatch = newKey.match( /rolespermission\.(\d+)\.modules\.(\d+)\.(isAdd|isEdit)/ );
2184
+ if ( rolesPermissionMatch ) {
2185
+ const [ , roleIndex, moduleIndex, action ] = rolesPermissionMatch;
2186
+ const role = previous.rolespermission?.[roleIndex];
2187
+ const module = role?.modules?.[moduleIndex];
2188
+
2189
+ if ( module ) {
2190
+ newKey = `User's ${module.name} Module ${action === 'isAdd' ? 'Add' : 'Edit'}`;
2191
+ diff.previous = diff.previous ? 'Enabled' : 'Disabled';
2192
+ diff.current = diff.current ? 'Enabled' : 'Disabled';
2193
+ }
2194
+ }
2195
+
2196
+ if ( !newKey || ( diff.previous === '' && !diff.current ) ) return;
2197
+
2198
+ if (
2199
+ ( diff.previous === '' || diff.previous === null || ( Array.isArray( diff.previous ) && diff.previous.length === 0 ) ) &&
2200
+ diff.current === undefined
2201
+ ) {
2202
+ return;
2203
+ }
2204
+ if (
2205
+ ( diff.current === '' || diff.current === null || ( Array.isArray( diff.current ) && diff.current.length === 0 ) ) &&
2206
+ diff.previous === undefined
2207
+ ) {
2208
+ return;
2209
+ }
2210
+
2211
+ updatedDifferences[newKey] = diff;
2212
+ } );
2213
+
2214
+ return updatedDifferences;
2215
+ }
2216
+
2217
+
2218
+ function getUserFriendlyKey( keyPath, mapping ) {
2219
+ const keys = keyPath.split( '.' ); // Split the key path (e.g., storeProfile.pincode → ['storeProfile', 'pincode'])
2220
+ let value = mapping;
2221
+
2222
+ for ( const key of keys ) {
2223
+ if ( value && typeof value === 'object' && key in value ) {
2224
+ value = value[key]; // Traverse down the object
2225
+ } else {
2226
+ return null; // Return original if not found
2227
+ }
2228
+ }
2229
+
2230
+ return typeof value === 'string' ? value : keyPath; // Return mapped value or original key
2231
+ }
2232
+
2099
2233
  async function postApi( url, data ) {
2100
2234
  const requestOptions = {
2101
2235
  method: 'POST',
@@ -121,6 +121,9 @@ export const featureConfigurationSchemaBody = joi.object(
121
121
  isNewZoneV2: joi.boolean().optional(),
122
122
  isTrax: joi.boolean().optional(),
123
123
  isControlCenter: joi.boolean().optional(),
124
+ isFootfallDirectoryAudit: joi.boolean().optional(),
125
+ isFootfallDirectoryLimit: joi.boolean().optional(),
126
+ streamBy: joi.string().optional(),
124
127
  },
125
128
  );
126
129
 
@@ -1,171 +1,171 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <meta http-equiv="x-ua-compatible" content="ie=edge">
6
- <title>Your account was approved!</title>
7
- <meta name="viewport" content="width=device-width, initial-scale=1">
8
- <style type="text/css">
9
- @media screen {
10
- @font-face {
11
- font-family: 'Inter';
12
- font-style: normal;
13
- font-weight: 400;
14
- font-display: swap;
15
- src: local("Inter"), local("Inter-Regular"), url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiI2B.woff2) format('woff2');
16
- unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
17
- }
18
- }
19
-
20
- body {
21
- font-family: "Inter", sans-serif !important;
22
- }
23
-
24
- body,
25
- table,
26
- td,
27
- a {
28
- -ms-text-size-adjust: 100%;
29
- -webkit-text-size-adjust: 100%;
30
- }
31
-
32
- table,
33
- td {
34
- mso-table-rspace: 0pt;
35
- mso-table-lspace: 0pt;
36
- }
37
-
38
- img {
39
- -ms-interpolation-mode: bicubic;
40
- }
41
-
42
- a[x-apple-data-detectors] {
43
- font-family: "inherit" !important;
44
- font-size: inherit !important;
45
- font-weight: inherit !important;
46
- line-height: inherit !important;
47
- color: inherit !important;
48
- text-decoration: none !important;
49
- }
50
-
51
- div[style*="margin: 16px 0;"] {
52
- margin: 0 !important;
53
- }
54
-
55
- body {
56
- width: 100% !important;
57
- height: 100% !important;
58
- padding: 0 !important;
59
- margin: 0 !important;
60
- }
61
-
62
- table {
63
- border-collapse: collapse !important;
64
- }
65
-
66
- a {
67
- color: #1a82e2;
68
- }
69
-
70
- img {
71
- height: auto;
72
- line-height: 100%;
73
- text-decoration: none;
74
- border: 0;
75
- outline: none;
76
- }
77
- </style>
78
- </head>
79
- <body style="background-color: #dbe5ea;">
80
- <div class="preheader" style="display: none; max-width: 0; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: #fff; opacity: 0;"> Email Summary (Hidden) </div>
81
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-left:10px;padding-right:10px">
82
- <tr>
83
- <td bgcolor="#dbe5ea" style="padding:32px 10px 0 10px">
84
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" align="center">
85
- <tr>
86
- <td class="o_bg-white o_px-md o_py-md o_sans o_text" style="margin-top: 0px;margin-bottom: 0px;font-size: 16px;line-height: 24px;background-color: #ffffff;padding-left: 18px;padding-right: 24px;padding-top: 24px;padding-bottom: 24px;">
87
- <p style="margin-top: 0px;margin-bottom: 0px;">
88
- <a class="o_text-white" href="https://tangoeye.ai/" style="text-decoration: none;outline: none;color: #ffffff;">
89
- <img src={{logo}} width="200" height="100" alt="SimpleApp" style="-ms-interpolation-mode: bicubic;vertical-align: middle;border: 0;line-height: 100%;height: auto;outline: none;text-decoration: none;">
90
- </a>
91
- </p>
92
- </td>
93
- </tr>
94
- <tr>
95
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 14px; line-height: 24px;">
96
- <p class="o_heading o_mb-xxs" style="width: 544px;height: 0px;border: 1px solid #CBD5E1;flex: none;order: 1;flex-grow: 0;"></p>
97
- </td>
98
- </tr>
99
- </table>
100
- </td>
101
- </tr>
102
- <tr>
103
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
104
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
105
- <tr>
106
- <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-top: 10px;padding-bottom: 10px;">
107
- <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 20px;line-height: 28px;color: #82899a;">
108
- <span class="o_heading o_text-dark o_mb-xxs" style="font-weight: 700;margin-top: 0px;margin-bottom: 4px;color: #242b3d;line-height: 39px;"> Your account was approved!</span>
109
- </div>
110
- </td>
111
- </tr>
112
- </table>
113
- </td>
114
- </tr>
115
- <tr>
116
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
117
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
118
- <tr>
119
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
120
- <p style="margin: 0;">As a verified user, you will be among the first to receive product updates, new feature announcements, enhanced security and personalised support.
121
- <br><br>
122
- Head over to the dashboard to finish your setup. </p>
123
- </td>
124
- </tr>
125
- </table>
126
- </td>
127
- </tr>
128
- <tr>
129
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
130
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
131
- <tr>
132
- <td align="left" bgcolor="#fff" style="border-radius: 6px;padding:14px 30px">
133
- <a href={{url}} style="display: inline-block;padding: 10px 36px;font-size: 20px;color: #fff;text-decoration: none;border-radius: 6px;background-color: #00a3ff;"> Add Stores</a>
134
- </td>
135
- </tr>
136
- </table>
137
- </td>
138
- </tr>
139
- <tr>
140
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
141
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
142
- <tr>
143
- <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
144
- <p style="margin: 0;">Enjoy the full potential of Tango Traffic Module. If you have any questions or need assistance, our support team is here to help.
145
-
146
- <br><br>
147
-
148
- Happy exploring! </p>
149
- </td>
150
- </tr>
151
- </table>
152
- </td>
153
- </tr>
154
- <tr>
155
- <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 32px 10px">
156
- <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
157
- <tr>
158
- <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-bottom:15px">
159
- <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 12px;color: #202B3C;font-style: normal;font-weight: 400;font-size: 12px;line-height: 150%;">
160
- <br>
161
- <p>If you'd rather not receive this kind of email, Don’t want any more emails from TangoEye?<u style="color:#00A3FF">Unsubscribe</u>.</p>
162
- <p> © Tango Eye. All rights reserved.</p>
163
- </div>
164
- </td>
165
- </tr>
166
- </table>
167
- </td>
168
- </tr>
169
- </table>
170
- </body>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
6
+ <title>Your account was approved!</title>
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <style type="text/css">
9
+ @media screen {
10
+ @font-face {
11
+ font-family: 'Inter';
12
+ font-style: normal;
13
+ font-weight: 400;
14
+ font-display: swap;
15
+ src: local("Inter"), local("Inter-Regular"), url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiI2B.woff2) format('woff2');
16
+ unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
17
+ }
18
+ }
19
+
20
+ body {
21
+ font-family: "Inter", sans-serif !important;
22
+ }
23
+
24
+ body,
25
+ table,
26
+ td,
27
+ a {
28
+ -ms-text-size-adjust: 100%;
29
+ -webkit-text-size-adjust: 100%;
30
+ }
31
+
32
+ table,
33
+ td {
34
+ mso-table-rspace: 0pt;
35
+ mso-table-lspace: 0pt;
36
+ }
37
+
38
+ img {
39
+ -ms-interpolation-mode: bicubic;
40
+ }
41
+
42
+ a[x-apple-data-detectors] {
43
+ font-family: "inherit" !important;
44
+ font-size: inherit !important;
45
+ font-weight: inherit !important;
46
+ line-height: inherit !important;
47
+ color: inherit !important;
48
+ text-decoration: none !important;
49
+ }
50
+
51
+ div[style*="margin: 16px 0;"] {
52
+ margin: 0 !important;
53
+ }
54
+
55
+ body {
56
+ width: 100% !important;
57
+ height: 100% !important;
58
+ padding: 0 !important;
59
+ margin: 0 !important;
60
+ }
61
+
62
+ table {
63
+ border-collapse: collapse !important;
64
+ }
65
+
66
+ a {
67
+ color: #1a82e2;
68
+ }
69
+
70
+ img {
71
+ height: auto;
72
+ line-height: 100%;
73
+ text-decoration: none;
74
+ border: 0;
75
+ outline: none;
76
+ }
77
+ </style>
78
+ </head>
79
+ <body style="background-color: #dbe5ea;">
80
+ <div class="preheader" style="display: none; max-width: 0; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: #fff; opacity: 0;"> Email Summary (Hidden) </div>
81
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="padding-left:10px;padding-right:10px">
82
+ <tr>
83
+ <td bgcolor="#dbe5ea" style="padding:32px 10px 0 10px">
84
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;" align="center">
85
+ <tr>
86
+ <td class="o_bg-white o_px-md o_py-md o_sans o_text" style="margin-top: 0px;margin-bottom: 0px;font-size: 16px;line-height: 24px;background-color: #ffffff;padding-left: 18px;padding-right: 24px;padding-top: 24px;padding-bottom: 24px;">
87
+ <p style="margin-top: 0px;margin-bottom: 0px;">
88
+ <a class="o_text-white" href="https://tangoeye.ai/" style="text-decoration: none;outline: none;color: #ffffff;">
89
+ <img src={{logo}} width="200" height="100" alt="SimpleApp" style="-ms-interpolation-mode: bicubic;vertical-align: middle;border: 0;line-height: 100%;height: auto;outline: none;text-decoration: none;">
90
+ </a>
91
+ </p>
92
+ </td>
93
+ </tr>
94
+ <tr>
95
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 14px; line-height: 24px;">
96
+ <p class="o_heading o_mb-xxs" style="width: 544px;height: 0px;border: 1px solid #CBD5E1;flex: none;order: 1;flex-grow: 0;"></p>
97
+ </td>
98
+ </tr>
99
+ </table>
100
+ </td>
101
+ </tr>
102
+ <tr>
103
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
104
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
105
+ <tr>
106
+ <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-top: 10px;padding-bottom: 10px;">
107
+ <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 20px;line-height: 28px;color: #82899a;">
108
+ <span class="o_heading o_text-dark o_mb-xxs" style="font-weight: 700;margin-top: 0px;margin-bottom: 4px;color: #242b3d;line-height: 39px;"> Your account was approved!</span>
109
+ </div>
110
+ </td>
111
+ </tr>
112
+ </table>
113
+ </td>
114
+ </tr>
115
+ <tr>
116
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
117
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
118
+ <tr>
119
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
120
+ <p style="margin: 0;">As a verified user, you will be among the first to receive product updates, new feature announcements, enhanced security and personalised support.
121
+ <br><br>
122
+ Head over to the dashboard to finish your setup. </p>
123
+ </td>
124
+ </tr>
125
+ </table>
126
+ </td>
127
+ </tr>
128
+ <tr>
129
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
130
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
131
+ <tr>
132
+ <td align="left" bgcolor="#fff" style="border-radius: 6px;padding:14px 30px">
133
+ <a href={{url}} style="display: inline-block;padding: 10px 36px;font-size: 20px;color: #fff;text-decoration: none;border-radius: 6px;background-color: #00a3ff;"> Add Stores</a>
134
+ </td>
135
+ </tr>
136
+ </table>
137
+ </td>
138
+ </tr>
139
+ <tr>
140
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 0 10px">
141
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
142
+ <tr>
143
+ <td align="left" bgcolor="#ffffff" style="padding-left: 30px;padding-right: 24px; font-size: 16px;padding-top:10px; line-height: 24px;font-weight:400;color:#384860">
144
+ <p style="margin: 0;">Enjoy the full potential of Tango Traffic Module. If you have any questions or need assistance, our support team is here to help.
145
+
146
+ <br><br>
147
+
148
+ Happy exploring! </p>
149
+ </td>
150
+ </tr>
151
+ </table>
152
+ </td>
153
+ </tr>
154
+ <tr>
155
+ <td align="center" bgcolor="#dbe5ea" style="padding:0 10px 32px 10px">
156
+ <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
157
+ <tr>
158
+ <td class="o_bg-white o_px-md o_py-xl o_xs-py-md" style="background-color: #ffffff;padding-left: 30px;padding-right: 24px;padding-bottom:15px">
159
+ <div class="o_col-6s o_sans o_text-md o_text-light o_center" style="margin-top: 0px;margin-bottom: 0px;font-size: 12px;color: #202B3C;font-style: normal;font-weight: 400;font-size: 12px;line-height: 150%;">
160
+ <br>
161
+ <p>If you'd rather not receive this kind of email, Don’t want any more emails from TangoEye?<u style="color:#00A3FF">Unsubscribe</u>.</p>
162
+ <p> © Tango Eye. All rights reserved.</p>
163
+ </div>
164
+ </td>
165
+ </tr>
166
+ </table>
167
+ </td>
168
+ </tr>
169
+ </table>
170
+ </body>
171
171
  </html> `
@@ -161,6 +161,9 @@ export function featureConfigurationUpdate( query, inputData ) {
161
161
  'featureConfigs.isNewZoneV2': inputData?.isNewZoneV2,
162
162
  'featureConfigs.isTrax': inputData?.isTrax,
163
163
  'featureConfigs.isControlCenter': inputData?.isControlCenter,
164
+ 'featureConfigs.isFootfallDirectoryAudit': inputData?.isFootfallDirectoryAudit,
165
+ 'featureConfigs.isFootfallDirectoryLimit': inputData?.isFootfallDirectoryLimit,
166
+ 'featureConfigs.streamBy': inputData?.streamBy,
164
167
  },
165
168
  } );
166
169
  }