thm-p3-configurator 0.0.203 → 0.0.205

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.
@@ -47,6 +47,7 @@ var _helpers__ = require("../../__helpers__");
47
47
  var _product = require("../../__helpers__/product");
48
48
  var _ui = require("../../__helpers__/ui");
49
49
  var _useIsTmg = require("../../__hooks__/useIsTmg");
50
+ var _AddressLookupService = _interopRequireDefault(require("../../__services__/AddressLookupService"));
50
51
  var _LicensePlateValidator = _interopRequireDefault(require("../../__services__/LicensePlateValidator"));
51
52
  var _LocalStorageWorker = require("../../__services__/LocalStorageWorker");
52
53
  var _InternalAppointmentSuccessModal = _interopRequireDefault(require("./InternalAppointmentSuccessModal"));
@@ -124,6 +125,7 @@ function _toPrimitive(t, r) {
124
125
  return ("string" === r ? String : Number)(t);
125
126
  }
126
127
  const licensePlateValidator = new _LicensePlateValidator.default();
128
+ const addressLookupService = new _AddressLookupService.default();
127
129
  const internalAppointmentFormSchema = (0, _yup.object)({
128
130
  ownershipType: (0, _yup.string)().required(_constants__.FORM_ERROR_MESSAGES.required),
129
131
  leaseNumber: (0, _yup.string)().nullable(),
@@ -174,6 +176,8 @@ const InternalAppointmentForm = _ref => {
174
176
  const [refreshKey, setRefreshKey] = (0, _react.useState)(Date.now());
175
177
  const [companySearchTerm, setCompanySearchTerm] = (0, _react.useState)('');
176
178
  const [isCompanyInputFocused, setIsCompanyInputFocused] = (0, _react.useState)(false);
179
+ const [addressLookupLoading, setAddressLookupLoading] = (0, _react.useState)(false);
180
+ const [addressLookupTimeoutId, setAddressLookupTimeoutId] = (0, _react.useState)(null);
177
181
  const {
178
182
  customerAgreed,
179
183
  customer,
@@ -557,6 +561,62 @@ const InternalAppointmentForm = _ref => {
557
561
  label: marketingChannels === null || marketingChannels === void 0 || (_marketingChannels$fi = marketingChannels.find(marketingC => (marketingC === null || marketingC === void 0 ? void 0 : marketingC.entityId) === (channel === null || channel === void 0 ? void 0 : channel.channelId))) === null || _marketingChannels$fi === void 0 ? void 0 : _marketingChannels$fi.title,
558
562
  value: marketingChannels === null || marketingChannels === void 0 ? void 0 : marketingChannels.find(marketingC => (marketingC === null || marketingC === void 0 ? void 0 : marketingC.entityId) === (channel === null || channel === void 0 ? void 0 : channel.channelId))
559
563
  } : null;
564
+
565
+ /**
566
+ * @description Debounced address lookup function
567
+ */
568
+ const performAddressLookup = async (postcode, houseNumber) => {
569
+ if (!postcode || !houseNumber) return;
570
+ try {
571
+ setAddressLookupLoading(true);
572
+ const addressInfo = await addressLookupService.lookup(postcode, houseNumber);
573
+ if (addressInfo && addressInfo.street && addressInfo.city) {
574
+ // Auto-fill street and city fields
575
+ dispatch({
576
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_STREET_NAME,
577
+ payload: {
578
+ streetName: addressInfo.street
579
+ }
580
+ });
581
+ dispatch({
582
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_CITY,
583
+ payload: {
584
+ city: addressInfo.city
585
+ }
586
+ });
587
+ }
588
+ } catch (error) {
589
+ console.error('Address lookup failed:', error);
590
+ } finally {
591
+ setAddressLookupLoading(false);
592
+ }
593
+ };
594
+
595
+ /**
596
+ * @description Handles address lookup with debouncing
597
+ */
598
+ const handleAddressLookup = (postcode, houseNumber) => {
599
+ // Clear existing timeout
600
+ if (addressLookupTimeoutId) {
601
+ clearTimeout(addressLookupTimeoutId);
602
+ }
603
+
604
+ // Set new timeout for debounced lookup
605
+ const newTimeoutId = setTimeout(() => {
606
+ performAddressLookup(postcode, houseNumber);
607
+ }, 800); // 800ms delay
608
+
609
+ setAddressLookupTimeoutId(newTimeoutId);
610
+ };
611
+
612
+ // Cleanup timeout on unmount
613
+ (0, _react.useEffect)(() => {
614
+ return () => {
615
+ if (addressLookupTimeoutId) {
616
+ clearTimeout(addressLookupTimeoutId);
617
+ }
618
+ };
619
+ }, [addressLookupTimeoutId]);
560
620
  return /*#__PURE__*/_react.default.createElement("div", {
561
621
  className: (0, _helpers__.withStyle)('row gx-5 mt-3 mt-lg-5')
562
622
  }, /*#__PURE__*/_react.default.createElement("div", {
@@ -1129,12 +1189,18 @@ const InternalAppointmentForm = _ref => {
1129
1189
  placeholder: "",
1130
1190
  value: customer.zipCode,
1131
1191
  name: "zipCode",
1132
- onChange: value => dispatch({
1133
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1134
- payload: {
1135
- zipCode: value
1192
+ onChange: value => {
1193
+ dispatch({
1194
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1195
+ payload: {
1196
+ zipCode: value
1197
+ }
1198
+ });
1199
+ // Trigger address lookup if house number is also available
1200
+ if (customer.houseNumber) {
1201
+ handleAddressLookup(value, customer.houseNumber);
1136
1202
  }
1137
- }),
1203
+ },
1138
1204
  key: "zipCode-".concat(refreshKey),
1139
1205
  isRequired: true,
1140
1206
  label: "Postcode:",
@@ -1143,12 +1209,18 @@ const InternalAppointmentForm = _ref => {
1143
1209
  placeholder: "",
1144
1210
  value: customer.houseNumber,
1145
1211
  name: "houseNumber",
1146
- onChange: value => dispatch({
1147
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1148
- payload: {
1149
- houseNumber: value
1212
+ onChange: value => {
1213
+ dispatch({
1214
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1215
+ payload: {
1216
+ houseNumber: value
1217
+ }
1218
+ });
1219
+ // Trigger address lookup if postcode is also available
1220
+ if (customer.zipCode) {
1221
+ handleAddressLookup(customer.zipCode, value);
1150
1222
  }
1151
- }),
1223
+ },
1152
1224
  key: "houseNumber-".concat(refreshKey),
1153
1225
  isRequired: true,
1154
1226
  label: "Huisnummer:",
@@ -1168,7 +1240,7 @@ const InternalAppointmentForm = _ref => {
1168
1240
  label: "Huisnummer toevoeging:",
1169
1241
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['houseNumberAddition']
1170
1242
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1171
- placeholder: "",
1243
+ placeholder: addressLookupLoading ? 'Adres wordt opgezocht...' : '',
1172
1244
  value: customer.streetName,
1173
1245
  name: "streetName",
1174
1246
  onChange: value => dispatch({
@@ -1179,10 +1251,10 @@ const InternalAppointmentForm = _ref => {
1179
1251
  }),
1180
1252
  key: "streetName-".concat(refreshKey),
1181
1253
  isRequired: true,
1182
- label: "Straat:",
1254
+ label: "Straat:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1183
1255
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['streetName']
1184
1256
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1185
- placeholder: "",
1257
+ placeholder: addressLookupLoading ? 'Stad wordt opgezocht...' : '',
1186
1258
  value: customer.city,
1187
1259
  name: "city",
1188
1260
  onChange: value => dispatch({
@@ -1193,7 +1265,7 @@ const InternalAppointmentForm = _ref => {
1193
1265
  }),
1194
1266
  key: "city-".concat(refreshKey),
1195
1267
  isRequired: true,
1196
- label: "Stad:",
1268
+ label: "Stad:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1197
1269
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['city']
1198
1270
  }), /*#__PURE__*/_react.default.createElement(_DropdownInput.default, {
1199
1271
  key: "country-business-".concat((customer === null || customer === void 0 ? void 0 : customer.countryId) || 'default'),
@@ -1221,12 +1293,18 @@ const InternalAppointmentForm = _ref => {
1221
1293
  placeholder: "",
1222
1294
  value: customer.zipCode,
1223
1295
  name: "zipCode",
1224
- onChange: value => dispatch({
1225
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1226
- payload: {
1227
- zipCode: value
1296
+ onChange: value => {
1297
+ dispatch({
1298
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1299
+ payload: {
1300
+ zipCode: value
1301
+ }
1302
+ });
1303
+ // Trigger address lookup if house number is also available
1304
+ if (customer.houseNumber) {
1305
+ handleAddressLookup(value, customer.houseNumber);
1228
1306
  }
1229
- }),
1307
+ },
1230
1308
  key: "zipCode-".concat(refreshKey),
1231
1309
  isRequired: true,
1232
1310
  label: "Postcode:",
@@ -1235,12 +1313,18 @@ const InternalAppointmentForm = _ref => {
1235
1313
  placeholder: "",
1236
1314
  value: customer.houseNumber,
1237
1315
  name: "houseNumber",
1238
- onChange: value => dispatch({
1239
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1240
- payload: {
1241
- houseNumber: value
1316
+ onChange: value => {
1317
+ dispatch({
1318
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1319
+ payload: {
1320
+ houseNumber: value
1321
+ }
1322
+ });
1323
+ // Trigger address lookup if postcode is also available
1324
+ if (customer.zipCode) {
1325
+ handleAddressLookup(customer.zipCode, value);
1242
1326
  }
1243
- }),
1327
+ },
1244
1328
  key: "houseNumber-".concat(refreshKey),
1245
1329
  isRequired: true,
1246
1330
  label: "Huisnummer:",
@@ -1260,7 +1344,7 @@ const InternalAppointmentForm = _ref => {
1260
1344
  label: "Huisnummer toevoeging:",
1261
1345
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['houseNumberAddition']
1262
1346
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1263
- placeholder: "",
1347
+ placeholder: addressLookupLoading ? 'Adres wordt opgezocht...' : '',
1264
1348
  value: customer.streetName,
1265
1349
  name: "streetName",
1266
1350
  onChange: value => dispatch({
@@ -1271,10 +1355,10 @@ const InternalAppointmentForm = _ref => {
1271
1355
  }),
1272
1356
  key: "streetName-".concat(refreshKey),
1273
1357
  isRequired: true,
1274
- label: "Straat:",
1358
+ label: "Straat:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1275
1359
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['streetName']
1276
1360
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1277
- placeholder: "",
1361
+ placeholder: addressLookupLoading ? 'Stad wordt opgezocht...' : '',
1278
1362
  value: customer.city,
1279
1363
  name: "city",
1280
1364
  onChange: value => dispatch({
@@ -1285,7 +1369,7 @@ const InternalAppointmentForm = _ref => {
1285
1369
  }),
1286
1370
  key: "city-".concat(refreshKey),
1287
1371
  isRequired: true,
1288
- label: "Stad:",
1372
+ label: "Stad:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1289
1373
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['city']
1290
1374
  }), /*#__PURE__*/_react.default.createElement(_DropdownInput.default, {
1291
1375
  key: "country-lease-".concat((customer === null || customer === void 0 ? void 0 : customer.countryId) || 'default'),
@@ -1327,12 +1411,18 @@ const InternalAppointmentForm = _ref => {
1327
1411
  placeholder: "",
1328
1412
  value: customer.zipCode,
1329
1413
  name: "zipCode",
1330
- onChange: value => dispatch({
1331
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1332
- payload: {
1333
- zipCode: value
1414
+ onChange: value => {
1415
+ dispatch({
1416
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_ZIP_CODE,
1417
+ payload: {
1418
+ zipCode: value
1419
+ }
1420
+ });
1421
+ // Trigger address lookup if house number is also available
1422
+ if (customer.houseNumber) {
1423
+ handleAddressLookup(value, customer.houseNumber);
1334
1424
  }
1335
- }),
1425
+ },
1336
1426
  key: "zipCode-".concat(refreshKey),
1337
1427
  isRequired: true,
1338
1428
  label: "Postcode:",
@@ -1341,12 +1431,18 @@ const InternalAppointmentForm = _ref => {
1341
1431
  placeholder: "",
1342
1432
  value: customer.houseNumber,
1343
1433
  name: "houseNumber",
1344
- onChange: value => dispatch({
1345
- type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1346
- payload: {
1347
- houseNumber: value
1434
+ onChange: value => {
1435
+ dispatch({
1436
+ type: _OrderSessionContext.orderSessionActions.SET_CUSTOMER_HOUSE_NUMBER,
1437
+ payload: {
1438
+ houseNumber: value
1439
+ }
1440
+ });
1441
+ // Trigger address lookup if postcode is also available
1442
+ if (customer.zipCode) {
1443
+ handleAddressLookup(customer.zipCode, value);
1348
1444
  }
1349
- }),
1445
+ },
1350
1446
  key: "houseNumber-".concat(refreshKey),
1351
1447
  isRequired: true,
1352
1448
  label: "Huisnummer:",
@@ -1366,7 +1462,7 @@ const InternalAppointmentForm = _ref => {
1366
1462
  label: "Huisnummer toevoeging:",
1367
1463
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['houseNumberAddition']
1368
1464
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1369
- placeholder: "",
1465
+ placeholder: addressLookupLoading ? 'Adres wordt opgezocht...' : '',
1370
1466
  value: customer.streetName,
1371
1467
  name: "streetName",
1372
1468
  onChange: value => dispatch({
@@ -1377,10 +1473,10 @@ const InternalAppointmentForm = _ref => {
1377
1473
  }),
1378
1474
  key: "streetName-".concat(refreshKey),
1379
1475
  isRequired: true,
1380
- label: "Straat:",
1476
+ label: "Straat:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1381
1477
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['streetName']
1382
1478
  }), /*#__PURE__*/_react.default.createElement(_TextInput.default, {
1383
- placeholder: "",
1479
+ placeholder: addressLookupLoading ? 'Stad wordt opgezocht...' : '',
1384
1480
  value: customer.city,
1385
1481
  name: "city",
1386
1482
  onChange: value => dispatch({
@@ -1391,7 +1487,7 @@ const InternalAppointmentForm = _ref => {
1391
1487
  }),
1392
1488
  key: "city-".concat(refreshKey),
1393
1489
  isRequired: true,
1394
- label: "Stad:",
1490
+ label: "Stad:".concat(addressLookupLoading ? ' (wordt opgezocht...)' : ''),
1395
1491
  errorMessage: errors === null || errors === void 0 ? void 0 : errors['city']
1396
1492
  }), /*#__PURE__*/_react.default.createElement(_DropdownInput.default, {
1397
1493
  key: "country-personal-".concat((customer === null || customer === void 0 ? void 0 : customer.countryId) || 'default'),
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ require("core-js/modules/es.parse-int.js");
4
+ require("core-js/modules/es.promise.js");
5
+ require("core-js/modules/es.regexp.exec.js");
6
+ require("core-js/modules/es.regexp.test.js");
7
+ require("core-js/modules/es.string.replace.js");
8
+ require("core-js/modules/web.dom-collections.iterator.js");
9
+ Object.defineProperty(exports, "__esModule", {
10
+ value: true
11
+ });
12
+ exports.default = void 0;
13
+ require("core-js/modules/es.parse-int.js");
14
+ require("core-js/modules/es.promise.js");
15
+ require("core-js/modules/es.regexp.exec.js");
16
+ require("core-js/modules/es.regexp.test.js");
17
+ require("core-js/modules/es.string.replace.js");
18
+ require("core-js/modules/web.dom-collections.iterator.js");
19
+ class AddressLookupService {
20
+ constructor() {
21
+ this.cache = new Map();
22
+ }
23
+
24
+ /**
25
+ * @description Validates Dutch postcode format
26
+ * @param {string} postcode - The postcode to validate
27
+ * @returns {boolean} - True if valid Dutch postcode format
28
+ */
29
+ isValidPostcode(postcode) {
30
+ if (!postcode || typeof postcode !== 'string') return false;
31
+ const cleanPostcode = postcode.replace(/\s/g, '').toUpperCase();
32
+ const dutchPostcodeRegex = /^[1-9][0-9]{3}[A-Z]{2}$/;
33
+ return dutchPostcodeRegex.test(cleanPostcode);
34
+ }
35
+
36
+ /**
37
+ * @description Validates house number
38
+ * @param {string|number} houseNumber - The house number to validate
39
+ * @returns {boolean} - True if valid house number
40
+ */
41
+ isValidHouseNumber(houseNumber) {
42
+ if (!houseNumber) return false;
43
+ const num = typeof houseNumber === 'string' ? parseInt(houseNumber, 10) : houseNumber;
44
+ return !isNaN(num) && num > 0 && num <= 99999;
45
+ }
46
+
47
+ /**
48
+ * @description Creates a cache key for the lookup
49
+ * @param {string} postcode - The postcode
50
+ * @param {string|number} houseNumber - The house number
51
+ * @returns {string} - Cache key
52
+ */
53
+ getCacheKey(postcode, houseNumber) {
54
+ const cleanPostcode = postcode.replace(/\s/g, '').toUpperCase();
55
+ return "".concat(cleanPostcode, "-").concat(houseNumber);
56
+ }
57
+
58
+ /**
59
+ * @description Lookup using PDOK BAG API (free Dutch government service)
60
+ * @param {string} postcode - The Dutch postcode
61
+ * @param {string|number} houseNumber - The house number
62
+ * @returns {Promise<{street: string, city: string} | null>} - Address information or null if not found
63
+ */
64
+ async lookupAddressPDOK(postcode, houseNumber) {
65
+ try {
66
+ if (!this.isValidPostcode(postcode) || !this.isValidHouseNumber(houseNumber)) {
67
+ return null;
68
+ }
69
+ const cacheKey = this.getCacheKey(postcode, houseNumber);
70
+ if (this.cache.has(cacheKey)) {
71
+ return this.cache.get(cacheKey);
72
+ }
73
+ const cleanPostcode = postcode.replace(/\s/g, '').toUpperCase();
74
+ const url = "https://api.pdok.nl/bzk/locatieserver/search/v3_1/suggest?q=".concat(cleanPostcode, " ").concat(houseNumber, "&fl=weergavenaam,straatnaam,woonplaatsnaam,postcode,huisnummer&rows=1");
75
+ const response = await fetch(url, {
76
+ method: 'GET',
77
+ headers: {
78
+ Accept: 'application/json'
79
+ }
80
+ });
81
+ if (!response.ok) {
82
+ console.warn('PDOK lookup failed:', response.status);
83
+ return null;
84
+ }
85
+ const data = await response.json();
86
+ let addressInfo = null;
87
+ if (data && data.response && data.response.docs && data.response.docs.length > 0) {
88
+ const doc = data.response.docs[0];
89
+ if (doc.postcode === cleanPostcode && String(doc.huisnummer) === String(houseNumber)) {
90
+ addressInfo = {
91
+ street: doc.straatnaam,
92
+ city: doc.woonplaatsnaam
93
+ };
94
+ }
95
+ }
96
+ this.cache.set(cacheKey, addressInfo);
97
+ return addressInfo;
98
+ } catch (error) {
99
+ console.error('PDOK address lookup error:', error);
100
+ return null;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * @description Main lookup method that tries PDOK API first, then fallback to mock data
106
+ * @param {string} postcode - The Dutch postcode
107
+ * @param {string|number} houseNumber - The house number
108
+ * @returns {Promise<{street: string, city: string} | null>} - Address information or null if not found
109
+ */
110
+ async lookup(postcode, houseNumber) {
111
+ if (!this.isValidPostcode(postcode) || !this.isValidHouseNumber(houseNumber)) {
112
+ return null;
113
+ }
114
+ const cacheKey = this.getCacheKey(postcode, houseNumber);
115
+ if (this.cache.has(cacheKey)) {
116
+ return this.cache.get(cacheKey);
117
+ }
118
+ let result = null;
119
+ try {
120
+ result = await this.lookupAddressPDOK(postcode, houseNumber);
121
+ console.log('looking up address with PDOK');
122
+ if (result) {
123
+ return result;
124
+ }
125
+ } catch (error) {
126
+ console.warn('PDOK lookup failed, using mock data...');
127
+ }
128
+ return result;
129
+ }
130
+
131
+ /**
132
+ * @description Clears the cache
133
+ */
134
+ clearCache() {
135
+ this.cache.clear();
136
+ }
137
+ }
138
+ var _default = exports.default = AddressLookupService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thm-p3-configurator",
3
- "version": "0.0.203",
3
+ "version": "0.0.205",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "author": "EnoRm.",