@acorex-platform/module-location-management-client 0.0.15 → 0.0.21

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.
Files changed (60) hide show
  1. package/fesm2022/acorex-platform-module-location-management-client-assign-existing-location-to-party.command-DECKrIBR.mjs +163 -0
  2. package/fesm2022/acorex-platform-module-location-management-client-assign-existing-location-to-party.command-DECKrIBR.mjs.map +1 -0
  3. package/fesm2022/acorex-platform-module-location-management-client-contracts.mjs +351 -0
  4. package/fesm2022/acorex-platform-module-location-management-client-contracts.mjs.map +1 -0
  5. package/fesm2022/acorex-platform-module-location-management-client-create-location-with-assignment.command-Cl6KfruM.mjs +200 -0
  6. package/fesm2022/acorex-platform-module-location-management-client-create-location-with-assignment.command-Cl6KfruM.mjs.map +1 -0
  7. package/fesm2022/acorex-platform-module-location-management-client.mjs +1701 -0
  8. package/fesm2022/acorex-platform-module-location-management-client.mjs.map +1 -0
  9. package/package.json +21 -5
  10. package/types/acorex-platform-module-location-management-client-contracts.d.ts +277 -0
  11. package/types/acorex-platform-module-location-management-client.d.ts +42 -0
  12. package/contracts/datasource.keys.d.ts +0 -6
  13. package/contracts/datasource.keys.js +0 -8
  14. package/contracts/entities/geographic-region/geographic-region.entity.d.ts +0 -2
  15. package/contracts/entities/geographic-region/geographic-region.entity.js +0 -725
  16. package/contracts/entities/geographic-region/geographic-region.types.d.ts +0 -27
  17. package/contracts/entities/geographic-region/geographic-region.types.js +0 -1
  18. package/contracts/entities/geographic-region/index.d.ts +0 -2
  19. package/contracts/entities/geographic-region/index.js +0 -2
  20. package/contracts/entities/index.d.ts +0 -5
  21. package/contracts/entities/index.js +0 -5
  22. package/contracts/entities/location/index.d.ts +0 -2
  23. package/contracts/entities/location/index.js +0 -2
  24. package/contracts/entities/location/location.entity.d.ts +0 -2
  25. package/contracts/entities/location/location.entity.js +0 -1075
  26. package/contracts/entities/location/location.types.d.ts +0 -30
  27. package/contracts/entities/location/location.types.js +0 -1
  28. package/contracts/entities/location-assignment/index.d.ts +0 -2
  29. package/contracts/entities/location-assignment/index.js +0 -2
  30. package/contracts/entities/location-assignment/location-assignment.entity.d.ts +0 -2
  31. package/contracts/entities/location-assignment/location-assignment.entity.js +0 -194
  32. package/contracts/entities/location-assignment/location-assignment.types.d.ts +0 -35
  33. package/contracts/entities/location-assignment/location-assignment.types.js +0 -2
  34. package/contracts/entities/location-role/index.d.ts +0 -2
  35. package/contracts/entities/location-role/index.js +0 -2
  36. package/contracts/entities/location-role/location-role.entity.d.ts +0 -2
  37. package/contracts/entities/location-role/location-role.entity.js +0 -143
  38. package/contracts/entities/location-role/location-role.types.d.ts +0 -6
  39. package/contracts/entities/location-role/location-role.types.js +0 -1
  40. package/contracts/entities/location-type/index.d.ts +0 -2
  41. package/contracts/entities/location-type/index.js +0 -2
  42. package/contracts/entities/location-type/location-type.entity.d.ts +0 -2
  43. package/contracts/entities/location-type/location-type.entity.js +0 -237
  44. package/contracts/entities/location-type/location-type.types.d.ts +0 -8
  45. package/contracts/entities/location-type/location-type.types.js +0 -1
  46. package/contracts/features.keys.d.ts +0 -1
  47. package/contracts/features.keys.js +0 -2
  48. package/contracts/index.d.ts +0 -8
  49. package/contracts/index.js +0 -10
  50. package/contracts/location-assignment.actions.d.ts +0 -8
  51. package/contracts/location-assignment.actions.js +0 -73
  52. package/contracts/location-assignment.utils.d.ts +0 -53
  53. package/contracts/location-assignment.utils.js +0 -145
  54. package/contracts/menu.keys.d.ts +0 -8
  55. package/contracts/menu.keys.js +0 -8
  56. package/contracts/package.json +0 -5
  57. package/contracts/permission.keys.d.ts +0 -33
  58. package/contracts/permission.keys.js +0 -42
  59. package/contracts/root-config.d.ts +0 -42
  60. package/contracts/root-config.js +0 -43
@@ -0,0 +1,1701 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, signal, effect, computed, HostBinding, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
3
+ import { AXP_MODULE_MANIFEST_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/core';
4
+ import { AXPEntityService, AXP_ENTITY_STORAGE_MIDDLEWARE } from '@acorex-platform/framework-client/layout/entity';
5
+ import { RootConfig, AXPPeopleOrganizationPermissionKeys, AXPLocationManagementMenuKeys, buildLocationAssignmentLocationSnapshot, buildLocationAssignmentPersonSnapshot } from '@acorex-platform/module-location-management-client/contracts';
6
+ import { AXPSearchCommandProvider, createEntityCommandOptions, AXPSettingsService, AXPClipBoardService, AXP_MENU_PROVIDER, AXP_SETTING_DEFINITION_PROVIDER, AXP_SEARCH_PROVIDER } from '@acorex-platform/framework-client/common';
7
+ import { AXP_PERMISSION_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/auth';
8
+ import { AXP_WIDGETS_EDITOR_SUB_COMPOSITE, AXP_WIDGETS_EDITOR_CATEGORY, AXPValueWidgetComponent, AXPColumnWidgetComponent, AXPWidgetCoreModule, AXP_WIDGET_DEFINITION_PROVIDER } from '@acorex-platform/framework-client/layout/widget-core';
9
+ import * as i1 from '@angular/common';
10
+ import { CommonModule } from '@angular/common';
11
+ import { provideCommandSetups } from '@acorex-platform/framework-client/runtime';
12
+ import { AXPCommonPermissionGroupKeys, AXPCommonMenuKeys } from '@acorex-platform/module-common-client/contracts';
13
+ import { get, set, defaultTo, isEmpty, isEqual, isNil, isNull } from 'lodash';
14
+ import { createSelectProperty, createBooleanProperty, AXPWidgetGroupEnum } from '@acorex-platform/framework-shared/widget-core';
15
+ import { AXP_NAME_PROPERTY, AXP_DATA_PATH_PROPERTY, AXP_DISABLED_PROPERTY, AXP_HAS_LABEL_PROPERTY, AXP_PLACEHOLDER_PROPERTY, AXP_BEHAVIOR_PROPERTY_GROUP } from '@acorex-platform/framework-client/layout/widgets';
16
+ import { AXPPlatformScope, formatAddressData, extractValue, resolveMultiLanguageString } from '@acorex-platform/framework-shared/core';
17
+ import * as i6 from '@acorex/components/button';
18
+ import { AXButtonModule } from '@acorex/components/button';
19
+ import * as i4 from '@acorex/components/decorators';
20
+ import { AXDecoratorModule } from '@acorex/components/decorators';
21
+ import * as i3 from '@acorex/components/form';
22
+ import { AXFormModule } from '@acorex/components/form';
23
+ import * as i5 from '@acorex/components/text-box';
24
+ import { AXTextBoxModule } from '@acorex/components/text-box';
25
+ import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
26
+ import { AXValidationModule } from '@acorex/core/validation';
27
+ import { AXPLayoutBuilderService, AXPLayoutRendererComponent } from '@acorex-platform/framework-client/layout/builder';
28
+ import * as i2 from '@angular/forms';
29
+ import { FormsModule } from '@angular/forms';
30
+ import * as i7 from '@acorex/components/accordion';
31
+ import { AXAccordionModule } from '@acorex/components/accordion';
32
+ import * as i1$1 from '@acorex/components/badge';
33
+ import { AXBadgeModule } from '@acorex/components/badge';
34
+
35
+ //#region ---- Imports ----
36
+ //#endregion
37
+ //#region ---- Manifest Definition ----
38
+ /**
39
+ * Location Management Module Manifest.
40
+ * Defines module metadata, features, and provider references.
41
+ */
42
+ const LocationManagementManifest = {
43
+ name: RootConfig.module.name,
44
+ version: '1.0.0',
45
+ title: RootConfig.module.title,
46
+ icon: RootConfig.module.icon,
47
+ i18n: RootConfig.config.i18n,
48
+ type: 'platform',
49
+ domain: 'platform',
50
+ required: true,
51
+ // Module dependencies (optional)
52
+ };
53
+ //#endregion
54
+
55
+ //#endregion
56
+ //#region ---- Permission Definition Provider ----
57
+ /**
58
+ * Ensures People & Organization root exists for location-management.
59
+ */
60
+ class AXMLocationManagementPermissionDefinitionProvider {
61
+ async define(context) {
62
+ const groups = AXPCommonPermissionGroupKeys;
63
+ const G = '@common:permission-groups';
64
+ context.addGroup(groups.PeopleOrganization.Root, `${G}.people-organization.title`, `${G}.people-organization.description`, { order: 10 });
65
+ }
66
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementPermissionDefinitionProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
67
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementPermissionDefinitionProvider }); }
68
+ }
69
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementPermissionDefinitionProvider, decorators: [{
70
+ type: Injectable
71
+ }] });
72
+
73
+ //#region ---- Imports ----
74
+ //#endregion
75
+ //#region ---- Menu Provider ----
76
+ class AXMLocationManagementMenuProvider {
77
+ constructor() {
78
+ this.entityService = inject(AXPEntityService);
79
+ }
80
+ async provide(context) {
81
+ const module = RootConfig.module;
82
+ const keys = AXPPeopleOrganizationPermissionKeys;
83
+ const contactsMenu = context.find(AXPCommonMenuKeys.Contacts);
84
+ if (!contactsMenu.exists) {
85
+ context.addItems([
86
+ {
87
+ name: AXPCommonMenuKeys.Contacts,
88
+ priority: 8010,
89
+ text: '@general:menus.contacts.title',
90
+ icon: 'fa-light fa-address-book',
91
+ type: 'menu',
92
+ children: [],
93
+ },
94
+ ]);
95
+ }
96
+ context.find(AXPCommonMenuKeys.Contacts).addItems([
97
+ {
98
+ name: AXPLocationManagementMenuKeys.Locations,
99
+ text: RootConfig.entities.location.titlePlural,
100
+ path: this.entityService.createPath(module.name, RootConfig.entities.location.name),
101
+ icon: RootConfig.entities.location.icon,
102
+ priority: 40,
103
+ policy: {
104
+ features: [module.name],
105
+ permissions: [keys.Setup],
106
+ },
107
+ },
108
+ ]);
109
+ context.find(AXPCommonMenuKeys.Region).addItems([
110
+ {
111
+ name: AXPLocationManagementMenuKeys.LocationTypes,
112
+ text: '@location-management:location-types.menus.location-types.title',
113
+ path: this.entityService.createPath(module.name, RootConfig.entities.locationType.name),
114
+ icon: RootConfig.entities.locationType.icon,
115
+ priority: 1,
116
+ policy: {
117
+ features: [module.name],
118
+ permissions: [keys.Setup],
119
+ },
120
+ },
121
+ {
122
+ name: AXPLocationManagementMenuKeys.LocationRoles,
123
+ text: '@location-management:location-roles.menus.location-roles.title',
124
+ path: this.entityService.createPath(module.name, RootConfig.entities.locationRole.name),
125
+ icon: RootConfig.entities.locationRole.icon,
126
+ priority: 2,
127
+ policy: {
128
+ features: [module.name],
129
+ permissions: [keys.Setup],
130
+ },
131
+ },
132
+ {
133
+ name: AXPLocationManagementMenuKeys.GeographicRegions,
134
+ text: '@location-management:geographic-regions.menus.geographic-regions.title',
135
+ path: this.entityService.createPath(module.name, RootConfig.entities.geographicRegion.name),
136
+ icon: RootConfig.entities.geographicRegion.icon,
137
+ priority: 3,
138
+ policy: {
139
+ features: [module.name],
140
+ permissions: [keys.Setup],
141
+ },
142
+ },
143
+ ]);
144
+ }
145
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementMenuProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
146
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementMenuProvider }); }
147
+ }
148
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementMenuProvider, decorators: [{
149
+ type: Injectable
150
+ }] });
151
+
152
+ class AXMSettingProvider {
153
+ async provide(context) {
154
+ // context
155
+ // // Add Form Template Group
156
+ // .addGroup('form-template', 'Form Template', 'Settings related to form templates.', RootConfig.module.icon)
157
+ // // Start Interface Section
158
+ // .addSection('interface', 'UI Interface', 'Customize the user interface for forms.')
159
+ // .addSetting({
160
+ // key: 'history-panel',
161
+ // title: 'Show History Panel',
162
+ // scope: 'U',
163
+ // isInherited: true,
164
+ // defaultValue: false,
165
+ // widget: {
166
+ // type: AXPWidgetsCatalog.toggle,
167
+ // },
168
+ // description: 'Enable or disable the history panel for forms.',
169
+ // validationRules: [
170
+ // {
171
+ // rule: 'required',
172
+ // },
173
+ // ],
174
+ // })
175
+ // .endSection()
176
+ // .endGroup();
177
+ }
178
+ }
179
+
180
+ class AXMSearchCommandProvider extends AXPSearchCommandProvider {
181
+ constructor() {
182
+ super(...arguments);
183
+ this.commands = [
184
+ {
185
+ id: 'create-location-role',
186
+ group: 'command',
187
+ title: RootConfig.entities.locationRole.title,
188
+ icon: RootConfig.entities.locationRole.icon,
189
+ description: RootConfig.entities.locationRole.titlePlural,
190
+ command: {
191
+ name: 'Entity:Create',
192
+ options: createEntityCommandOptions(`${RootConfig.module.name}.${RootConfig.entities.locationRole.name}`, {
193
+ name: RootConfig.entities.locationRole.name,
194
+ module: RootConfig.module.name,
195
+ title: RootConfig.entities.locationRole.title,
196
+ }),
197
+ },
198
+ },
199
+ {
200
+ id: 'create-location-type',
201
+ group: 'command',
202
+ title: RootConfig.entities.locationType.title,
203
+ icon: RootConfig.entities.locationType.icon,
204
+ description: RootConfig.entities.locationType.titlePlural,
205
+ command: {
206
+ name: 'Entity:Create',
207
+ options: createEntityCommandOptions(`${RootConfig.module.name}.${RootConfig.entities.locationType.name}`, {
208
+ name: RootConfig.entities.locationType.name,
209
+ module: RootConfig.module.name,
210
+ title: RootConfig.entities.locationType.title,
211
+ }),
212
+ },
213
+ },
214
+ {
215
+ id: 'create-geographic-region',
216
+ group: 'command',
217
+ title: RootConfig.entities.geographicRegion.title,
218
+ icon: RootConfig.entities.geographicRegion.icon,
219
+ description: RootConfig.entities.geographicRegion.titlePlural,
220
+ command: {
221
+ name: 'Entity:Create',
222
+ options: createEntityCommandOptions(`${RootConfig.module.name}.${RootConfig.entities.geographicRegion.name}`, {
223
+ name: RootConfig.entities.geographicRegion.name,
224
+ module: RootConfig.module.name,
225
+ title: RootConfig.entities.geographicRegion.title,
226
+ }),
227
+ },
228
+ },
229
+ ];
230
+ }
231
+ }
232
+
233
+ //#region ---- Imports ----
234
+ //#endregion
235
+ //#region ---- Feature Definition Provider ----
236
+ /**
237
+ * Location Management Feature Definition Provider.
238
+ * Provides feature definitions for the Location Management module.
239
+ */
240
+ class AXMLocationManagementFeatureDefinitionProvider {
241
+ async provide(context) {
242
+ // Management feature removed - module name is used directly as feature key
243
+ }
244
+ }
245
+ //#endregion
246
+
247
+ //#region ---- LocationAssignment nested hydration ----
248
+ const LOCATION_ASSIGNMENT_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.locationAssignment.name}`;
249
+ const LOCATION_ENTITY = `${RootConfig.module.name}.${RootConfig.entities.location.name}`;
250
+ const PERSON_ENTITY = 'PersonCore.Person';
251
+ /**
252
+ * Hydrates nested `location` and `person` on LocationAssignment rows so consumers
253
+ * (e.g. party location lists) receive computed fields such as `fullAddress` and `fullName`.
254
+ */
255
+ const locationAssignmentLocationHydrateMiddleware = {
256
+ target: { ops: ['getOne', 'getAll', 'query'], order: 13 },
257
+ execute: async (ctx, next) => {
258
+ const backend = ctx.entities;
259
+ await next();
260
+ if (ctx.entityName !== LOCATION_ASSIGNMENT_ENTITY) {
261
+ return;
262
+ }
263
+ try {
264
+ const rows = Array.isArray(ctx.result)
265
+ ? ctx.result
266
+ : Array.isArray(ctx.result?.items)
267
+ ? (ctx.result.items ?? [])
268
+ : ctx.result
269
+ ? [ctx.result]
270
+ : [];
271
+ if (!rows.length) {
272
+ return;
273
+ }
274
+ const locationIds = Array.from(new Set(rows.map((row) => get(row, 'locationId')).filter((id) => id != null)));
275
+ const personIds = Array.from(new Set(rows.map((row) => get(row, 'personId')).filter((id) => id != null)));
276
+ const locationMap = new Map();
277
+ if (locationIds.length) {
278
+ const locationResponse = await backend.query(LOCATION_ENTITY, {
279
+ skip: 0,
280
+ take: locationIds.length,
281
+ filter: { field: 'id', operator: { type: 'in' }, value: locationIds },
282
+ });
283
+ for (const item of locationResponse?.items ?? []) {
284
+ const record = item;
285
+ locationMap.set(get(record, 'id'), record);
286
+ }
287
+ }
288
+ const personMap = new Map();
289
+ if (personIds.length) {
290
+ const personResponse = await backend.query(PERSON_ENTITY, {
291
+ skip: 0,
292
+ take: personIds.length,
293
+ filter: { field: 'id', operator: { type: 'in' }, value: personIds },
294
+ });
295
+ for (const item of personResponse?.items ?? []) {
296
+ const record = item;
297
+ personMap.set(get(record, 'id'), record);
298
+ }
299
+ }
300
+ for (const row of rows) {
301
+ const locationId = get(row, 'locationId');
302
+ if (locationId != null) {
303
+ const location = locationMap.get(locationId);
304
+ if (location) {
305
+ set(row, 'location', buildLocationAssignmentLocationSnapshot(location, locationId));
306
+ }
307
+ }
308
+ const personId = get(row, 'personId');
309
+ if (personId != null) {
310
+ const person = personMap.get(personId);
311
+ if (person) {
312
+ set(row, 'person', buildLocationAssignmentPersonSnapshot(person, personId));
313
+ }
314
+ }
315
+ }
316
+ }
317
+ catch {
318
+ // swallow to avoid breaking main flow
319
+ }
320
+ },
321
+ };
322
+ //#endregion
323
+
324
+ const AXPAddressWidget = {
325
+ name: 'address-editor',
326
+ title: '@platform-layout-widgets:widgets.address-editor.title',
327
+ description: '@platform-layout-widgets:widgets.address-editor.description',
328
+ categories: AXP_WIDGETS_EDITOR_CATEGORY,
329
+ subCategory: AXP_WIDGETS_EDITOR_SUB_COMPOSITE,
330
+ groups: [AXPWidgetGroupEnum.FormElement],
331
+ icon: 'fa-light fa-location-dot',
332
+ defaultFilterWidgetName: 'string-filter',
333
+ type: 'editor',
334
+ properties: [
335
+ AXP_NAME_PROPERTY,
336
+ AXP_DATA_PATH_PROPERTY,
337
+ createSelectProperty({
338
+ name: 'mode',
339
+ title: 'Mode',
340
+ group: AXP_BEHAVIOR_PROPERTY_GROUP,
341
+ dataSource: [
342
+ { id: 'simple', title: 'Single line' },
343
+ { id: 'popup', title: 'Popup editor' },
344
+ { id: 'expandable', title: 'Expandable panel' },
345
+ ],
346
+ defaultValue: { id: 'simple', title: 'Single line' },
347
+ path: 'options.mode',
348
+ }),
349
+ createBooleanProperty({
350
+ name: 'hasLabel',
351
+ title: 'Has Label',
352
+ group: AXP_BEHAVIOR_PROPERTY_GROUP,
353
+ defaultValue: false,
354
+ path: 'options.hasLabel',
355
+ }),
356
+ createBooleanProperty({
357
+ name: 'hasMap',
358
+ title: 'Has Map',
359
+ group: AXP_BEHAVIOR_PROPERTY_GROUP,
360
+ defaultValue: true,
361
+ path: 'options.hasMap',
362
+ }),
363
+ AXP_DISABLED_PROPERTY,
364
+ AXP_HAS_LABEL_PROPERTY,
365
+ AXP_PLACEHOLDER_PROPERTY,
366
+ ],
367
+ components: {
368
+ view: {
369
+ component: () => Promise.resolve().then(function () { return addressWidgetView_component; }).then((c) => c.AXPAddressWidgetViewComponent),
370
+ },
371
+ edit: {
372
+ component: () => Promise.resolve().then(function () { return addressWidgetEdit_component; }).then((c) => c.AXPAddressWidgetEditComponent),
373
+ },
374
+ column: {
375
+ component: () => Promise.resolve().then(function () { return addressWidgetColumn_component; }).then((c) => c.AXPAddressWidgetColumnComponent),
376
+ },
377
+ designer: {
378
+ component: () => Promise.resolve().then(function () { return addressWidgetEdit_component; }).then((c) => c.AXPAddressWidgetEditComponent),
379
+ },
380
+ },
381
+ };
382
+
383
+ //#endregion
384
+
385
+ const TENANT_ORGANIZATION_ADDRESS_SETTINGS = {
386
+ street1: 'OrganizationManagement:Setting:Organization.Street1',
387
+ street2: 'OrganizationManagement:Setting:Organization.Street2',
388
+ countryId: 'OrganizationManagement:Setting:Organization.CountryId',
389
+ stateId: 'OrganizationManagement:Setting:Organization.StateId',
390
+ cityId: 'OrganizationManagement:Setting:Organization.CityId',
391
+ postalCode: 'OrganizationManagement:Setting:Organization.PostalCode',
392
+ };
393
+ const GEOGRAPHIC_REGION_ENTITY = 'LocationManagement.GeographicRegion';
394
+ //#region ---- Service ----
395
+ class AXPAddressWidgetService {
396
+ constructor() {
397
+ //#region ---- Services & Dependencies ----
398
+ this.layoutBuilder = inject(AXPLayoutBuilderService);
399
+ this.translationService = inject(AXTranslationService);
400
+ this.settingsService = inject(AXPSettingsService);
401
+ this.entityService = inject(AXPEntityService);
402
+ this.geographicDefaultsCache = null;
403
+ this.geographicTitleCache = new Map();
404
+ this.settingsService.onChanged.subscribe((event) => {
405
+ const settingKeys = Object.values(TENANT_ORGANIZATION_ADDRESS_SETTINGS);
406
+ if (event.keys.some((key) => settingKeys.includes(key))) {
407
+ this.invalidateGeographicDefaultsCache();
408
+ }
409
+ });
410
+ }
411
+ //#endregion
412
+ //#region ---- Shared address form layout (dialog + inline renderer) ----
413
+ /**
414
+ * Builds the address form content (street1, street2, country, state, city, postalCode, label, map).
415
+ * Used by both the dialog and the expandable inline layout via create().flex().build().
416
+ */
417
+ buildAddressFormContent(flex, options) {
418
+ const { hasLabel, labelEntity, hasMap, addressData } = options;
419
+ const showLabel = !!hasLabel && !!labelEntity;
420
+ flex.mode('edit').setDirection('column').setGap('12px');
421
+ //#region ---- Row 1: label + show map ----
422
+ if (showLabel || hasMap) {
423
+ flex.grid((metaRow) => {
424
+ metaRow.setColumns(12).setGap('12px');
425
+ if (showLabel) {
426
+ metaRow.formField('@location-management:locations.entities.location.fields.label', (field) => {
427
+ field.path('labelId');
428
+ field.layout(3);
429
+ field.customWidget('lookup-editor', {
430
+ entity: labelEntity,
431
+ look: 'select',
432
+ textField: 'title',
433
+ valueField: 'id',
434
+ hasClearButton: true,
435
+ allowCreate: 'quick',
436
+ create: {
437
+ enable: true,
438
+ title: '@location-management:locations.entities.location.fields.label-create-title',
439
+ },
440
+ expose: [
441
+ { source: 'id', target: 'label.id' },
442
+ { source: 'title', target: 'label.title' },
443
+ ],
444
+ validations: [{ rule: 'required', message: '@general:validation.messages.required' }],
445
+ });
446
+ });
447
+ }
448
+ if (hasMap) {
449
+ metaRow.formField('@location-management:locations.entities.location.fields.show-map', (field) => {
450
+ field.path('showMap');
451
+ field.layout(3);
452
+ field.toggleSwitch({
453
+ defaultValue: !!(addressData?.coordinates),
454
+ });
455
+ });
456
+ }
457
+ });
458
+ }
459
+ //#endregion
460
+ //#region ---- Row 2: street address + address line 2 ----
461
+ flex.grid((streetRow) => {
462
+ streetRow.setColumns(12).setGap('12px');
463
+ streetRow
464
+ .formField('@location-management:locations.entities.location.fields.street1', (field) => {
465
+ field.path('street1');
466
+ field.layout(6);
467
+ field.textBox({
468
+ validations: [{ rule: 'required', message: '@general:validation.messages.required' }],
469
+ });
470
+ })
471
+ .formField('@location-management:locations.entities.location.fields.street2', (field) => {
472
+ field.path('street2');
473
+ field.layout(6);
474
+ field.textBox({});
475
+ });
476
+ });
477
+ //#endregion
478
+ //#region ---- Row 3: postal code + country + state + city ----
479
+ flex.grid((geoRow) => {
480
+ geoRow.setColumns(12).setGap('12px');
481
+ geoRow
482
+ .formField('@location-management:locations.entities.location.fields.postal-code', (field) => {
483
+ field.path('postalCode');
484
+ field.layout(3);
485
+ field.textBox({ placeholder: 'Enter postal code' });
486
+ })
487
+ .formField('@location-management:locations.entities.location.fields.country', (field) => {
488
+ field.path('countryId');
489
+ field.layout(3);
490
+ field.customWidget('lookup-editor', {
491
+ entity: 'LocationManagement.GeographicRegion',
492
+ look: 'select',
493
+ textField: 'title',
494
+ valueField: 'id',
495
+ hasClearButton: true,
496
+ allowCreate: 'quick',
497
+ create: {
498
+ enable: true,
499
+ },
500
+ expose: [
501
+ { source: 'id', target: 'country.id' },
502
+ { source: 'title', target: 'country.title' },
503
+ ],
504
+ filter: {
505
+ logic: 'and',
506
+ filters: [{ field: 'type.code', operator: { type: 'equal' }, value: 'country' }],
507
+ },
508
+ });
509
+ })
510
+ .formField('@location-management:locations.entities.location.fields.state', (field) => {
511
+ field.path('stateId');
512
+ field.layout(3);
513
+ field.customWidget('lookup-editor', {
514
+ entity: 'LocationManagement.GeographicRegion',
515
+ look: 'select',
516
+ textField: 'title',
517
+ valueField: 'id',
518
+ hasClearButton: true,
519
+ allowCreate: 'quick',
520
+ disabled: '{{ !context.eval("countryId") }}',
521
+ create: {
522
+ enable: true,
523
+ context: {
524
+ parentId: '{{ context.eval("countryId") }}',
525
+ type: { code: 'state' },
526
+ },
527
+ },
528
+ expose: [
529
+ { source: 'id', target: 'state.id' },
530
+ { source: 'title', target: 'state.title' },
531
+ ],
532
+ filter: {
533
+ logic: 'and',
534
+ filters: [
535
+ { field: 'parentId', operator: { type: 'equal' }, value: '{{ context.eval("countryId") }}' },
536
+ { field: 'type.code', operator: { type: 'equal' }, value: 'state' },
537
+ ],
538
+ },
539
+ triggers: [
540
+ {
541
+ event: "{{ events.context('countryId') }}",
542
+ action: "{{ widget.setValue(null); context.set('state.title', null); context.set('cityId', null); context.set('city.id', null); context.set('city.title', null); widget.refresh(); }}",
543
+ },
544
+ ],
545
+ });
546
+ })
547
+ .formField('@location-management:locations.entities.location.fields.city', (field) => {
548
+ field.path('cityId');
549
+ field.layout(3);
550
+ field.customWidget('lookup-editor', {
551
+ entity: 'LocationManagement.GeographicRegion',
552
+ look: 'select',
553
+ textField: 'title',
554
+ valueField: 'id',
555
+ hasClearButton: true,
556
+ allowCreate: 'quick',
557
+ disabled: '{{ !context.eval("stateId") }}',
558
+ create: {
559
+ enable: true,
560
+ context: {
561
+ parentId: '{{ context.eval("stateId") }}',
562
+ type: { code: 'city' },
563
+ },
564
+ },
565
+ expose: [
566
+ { source: 'id', target: 'city.id' },
567
+ { source: 'title', target: 'city.title' },
568
+ ],
569
+ filter: {
570
+ logic: 'and',
571
+ filters: [
572
+ { field: 'parentId', operator: { type: 'equal' }, value: '{{ context.eval("stateId") }}' },
573
+ { field: 'type.code', operator: { type: 'equal' }, value: 'city' },
574
+ ],
575
+ },
576
+ triggers: [
577
+ {
578
+ event: "{{ events.context('stateId') }}",
579
+ action: "{{ widget.setValue(null); context.set('city.title', null); widget.refresh(); }}",
580
+ },
581
+ {
582
+ event: "{{ events.context('countryId') }}",
583
+ action: "{{ widget.setValue(null); context.set('city.title', null); widget.refresh(); }}",
584
+ },
585
+ ],
586
+ });
587
+ });
588
+ });
589
+ //#endregion
590
+ //#region ---- Map picker (when show map is enabled) ----
591
+ if (hasMap) {
592
+ flex.grid((mapRow) => {
593
+ mapRow.setColumns(12).setGap('12px');
594
+ mapRow.formField('@location-management:locations.entities.location.fields.coordinates', (field) => {
595
+ field.path('coordinates');
596
+ field.layout(12);
597
+ field.visible('{{ context.eval("showMap") }}');
598
+ field.customWidget('map', { hasDraw: true, maxPolygon: 0 });
599
+ });
600
+ });
601
+ }
602
+ //#endregion
603
+ }
604
+ /**
605
+ * Returns the address form layout node using layoutBuilder.create().flex().build() for use in axp-layout-renderer.
606
+ */
607
+ getAddressFormLayout(options) {
608
+ return this.layoutBuilder
609
+ .create()
610
+ .flex((flex) => this.buildAddressFormContent(flex, options))
611
+ .build();
612
+ }
613
+ //#endregion
614
+ //#region ---- Geographic Defaults Methods ----
615
+ /** Loads geographic defaults from tenant organization address settings. */
616
+ async getGeographicDefaults() {
617
+ if (!this.geographicDefaultsCache) {
618
+ this.geographicDefaultsCache = this.loadGeographicDefaultsFromSettings();
619
+ }
620
+ return this.geographicDefaultsCache;
621
+ }
622
+ async loadGeographicDefaultsFromSettings() {
623
+ const tenantScope = this.settingsService.scope(AXPPlatformScope.Tenant);
624
+ const [countryId, stateId, cityId, street1, street2, postalCode] = await Promise.all([
625
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.countryId),
626
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.stateId),
627
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.cityId),
628
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.street1),
629
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.street2),
630
+ tenantScope.get(TENANT_ORGANIZATION_ADDRESS_SETTINGS.postalCode),
631
+ ]);
632
+ const resolvedCountry = this.resolveSettingLookupSnapshot(countryId);
633
+ const resolvedState = this.resolveSettingLookupSnapshot(stateId);
634
+ const resolvedCity = this.resolveSettingLookupSnapshot(cityId);
635
+ const resolvedStreet1 = defaultTo(street1, '').trim();
636
+ const resolvedStreet2 = defaultTo(street2, '').trim();
637
+ const resolvedPostalCode = defaultTo(postalCode, '').trim();
638
+ if (isEmpty(resolvedCountry?.id) &&
639
+ isEmpty(resolvedState?.id) &&
640
+ isEmpty(resolvedCity?.id) &&
641
+ isEmpty(resolvedStreet1) &&
642
+ isEmpty(resolvedStreet2) &&
643
+ isEmpty(resolvedPostalCode)) {
644
+ return null;
645
+ }
646
+ return {
647
+ street1: resolvedStreet1 || undefined,
648
+ street2: resolvedStreet2 || undefined,
649
+ postalCode: resolvedPostalCode || undefined,
650
+ countryId: resolvedCountry?.id,
651
+ stateId: resolvedState?.id,
652
+ cityId: resolvedCity?.id,
653
+ country: resolvedCountry,
654
+ state: resolvedState,
655
+ city: resolvedCity,
656
+ };
657
+ }
658
+ /** Clears cached defaults (e.g. after tenant settings change). */
659
+ invalidateGeographicDefaultsCache() {
660
+ this.geographicDefaultsCache = null;
661
+ }
662
+ /**
663
+ * Applies tenant/platform geographic defaults to empty address fields only.
664
+ * Returns whether any field was updated.
665
+ */
666
+ async applyGeographicDefaultsIfNeeded(value, options) {
667
+ if (options?.enabled === false) {
668
+ return { value, applied: false };
669
+ }
670
+ const defaults = await this.getGeographicDefaults();
671
+ if (!defaults) {
672
+ return { value, applied: false };
673
+ }
674
+ const merged = this.mergeGeographicDefaults(value, defaults);
675
+ const enriched = await this.enrichGeographicLookupTitles(merged);
676
+ const applied = !isEqual(this.snapshotGeographicFields(value), this.snapshotGeographicFields(enriched));
677
+ return { value: enriched, applied };
678
+ }
679
+ /** Merges defaults into empty country/state/city (and optional street/postal) fields. */
680
+ mergeGeographicDefaults(value, defaults) {
681
+ const result = { ...value };
682
+ if (this.isLookupEmpty(result.country) && defaults.country?.id) {
683
+ result.country = defaults.country;
684
+ }
685
+ if (this.isLookupEmpty(result.state) && defaults.state?.id) {
686
+ result.state = defaults.state;
687
+ }
688
+ if (this.isLookupEmpty(result.city) && defaults.city?.id) {
689
+ result.city = defaults.city;
690
+ }
691
+ if (!result.street1?.trim() && defaults.street1?.trim()) {
692
+ result.street1 = defaults.street1;
693
+ }
694
+ if (!result.street2?.trim() && defaults.street2?.trim()) {
695
+ result.street2 = defaults.street2;
696
+ }
697
+ if (!result.postalCode?.trim() && defaults.postalCode?.trim()) {
698
+ result.postalCode = defaults.postalCode;
699
+ }
700
+ return result;
701
+ }
702
+ /** Ensures country/state/city snapshots include titles required for formatted address text. */
703
+ async enrichGeographicLookupTitles(value) {
704
+ const [country, state, city] = await Promise.all([
705
+ this.enrichLookupField(value.country),
706
+ this.enrichLookupField(value.state),
707
+ this.enrichLookupField(value.city),
708
+ ]);
709
+ if (country === value.country && state === value.state && city === value.city) {
710
+ return value;
711
+ }
712
+ return { ...value, country, state, city };
713
+ }
714
+ //#endregion
715
+ //#region ---- Geographic Cascade Methods ----
716
+ /**
717
+ * Builds layout context with flat lookup ids (countryId/stateId/cityId/labelId) required for cascade triggers.
718
+ * Same pattern as LocationManagement.Location entity fields.
719
+ */
720
+ buildAddressFormContext(addressData, options) {
721
+ return {
722
+ ...addressData,
723
+ countryId: addressData.country?.id,
724
+ stateId: addressData.state?.id,
725
+ cityId: addressData.city?.id,
726
+ labelId: addressData.label?.id,
727
+ showMap: (options?.hasMap ?? false) && !!addressData.coordinates,
728
+ };
729
+ }
730
+ /**
731
+ * Clears dependent geographic fields when a parent selection changes.
732
+ * Mirrors Location entity cascade: state depends on country, city depends on state.
733
+ */
734
+ applyGeographicCascade(previous, next) {
735
+ const result = { ...next };
736
+ const previousCountryId = previous.countryId ?? previous.country?.id;
737
+ const nextCountryId = result.countryId ?? result.country?.id;
738
+ const previousStateId = previous.stateId ?? previous.state?.id;
739
+ const nextStateId = result.stateId ?? result.state?.id;
740
+ if (previousCountryId !== nextCountryId) {
741
+ result.state = undefined;
742
+ result.city = undefined;
743
+ result.stateId = undefined;
744
+ result.cityId = undefined;
745
+ }
746
+ else if (previousStateId !== nextStateId) {
747
+ result.city = undefined;
748
+ result.cityId = undefined;
749
+ }
750
+ return result;
751
+ }
752
+ //#endregion
753
+ //#region ---- Address Formatting Methods ----
754
+ /**
755
+ * Formats address data into full address string
756
+ * Format: [street1], [street2], [country] - [state], [city], [postalCode]
757
+ * Uses titles from exposed fields, excludes coordinates
758
+ */
759
+ formatAddress(data) {
760
+ return formatAddressData(data, this.translationService.getActiveLang() || 'en-US');
761
+ }
762
+ /**
763
+ * Collapse header parts: label title (semibold in template) + full address.
764
+ */
765
+ async resolveCollapsibleHeader(value, options) {
766
+ const enriched = await this.enrichGeographicLookupTitles(value);
767
+ const full = (enriched.full?.trim() || this.formatAddress(enriched)).trim();
768
+ const addressText = full !== '' ? full : options.placeholder;
769
+ const labelText = enriched.label?.title?.trim() || null;
770
+ return { labelText, addressText };
771
+ }
772
+ //#endregion
773
+ //#region ---- Dialog & UI Methods ----
774
+ /**
775
+ * Shows address details popup dialog using the shared address form layout.
776
+ */
777
+ async showAddressDetailsPopup(addressData, options = {}) {
778
+ const { hasMap = true, hasLabel, labelEntity, useGeographicDefaults = true } = options;
779
+ const { value: addressWithDefaults } = await this.applyGeographicDefaultsIfNeeded(addressData, {
780
+ enabled: useGeographicDefaults,
781
+ });
782
+ const initialContext = this.buildAddressFormContext(addressWithDefaults, { hasMap });
783
+ const dialogTitle = await this.translationService.translateAsync('@general:terms.common.address');
784
+ const ref = await this.layoutBuilder
785
+ .create()
786
+ .dialog((dialog) => {
787
+ dialog
788
+ .setTitle(dialogTitle)
789
+ .setSize('lg')
790
+ .setContext(initialContext)
791
+ .content((layoutBuilder) => {
792
+ layoutBuilder.flex((flex) => this.buildAddressFormContent(flex, {
793
+ hasLabel,
794
+ labelEntity,
795
+ hasMap,
796
+ addressData: addressWithDefaults,
797
+ }));
798
+ })
799
+ .setActions((actions) => {
800
+ actions.cancel('@general:actions.cancel.title').submit('@general:actions.apply.title');
801
+ });
802
+ })
803
+ .show();
804
+ if (ref.action() === 'cancel') {
805
+ ref.close();
806
+ return null;
807
+ }
808
+ const result = this.applyGeographicCascade(initialContext, this.normalizeAddressData(ref.context()));
809
+ ref.close();
810
+ return result;
811
+ }
812
+ //#endregion
813
+ //#region ---- Data Normalization Methods ----
814
+ /**
815
+ * Normalizes address data from various input formats
816
+ */
817
+ normalizeAddressData(value) {
818
+ if (typeof value === 'object' && value !== null) {
819
+ const contextValue = value;
820
+ return {
821
+ street1: contextValue.street1 ?? '',
822
+ street2: contextValue.street2,
823
+ country: contextValue.country,
824
+ state: contextValue.state,
825
+ city: contextValue.city,
826
+ postalCode: contextValue.postalCode,
827
+ coordinates: contextValue.coordinates,
828
+ full: contextValue.full ?? this.formatAddress(contextValue),
829
+ label: this.resolveLabel(contextValue),
830
+ };
831
+ }
832
+ // Simple string format
833
+ return {
834
+ street1: '',
835
+ street2: '',
836
+ country: undefined,
837
+ state: undefined,
838
+ city: undefined,
839
+ postalCode: '',
840
+ coordinates: undefined,
841
+ full: value?.toString() || '',
842
+ label: undefined,
843
+ };
844
+ }
845
+ /** Resolves persisted label snapshot from lookup expose or transient labelId. */
846
+ resolveLabel(value) {
847
+ const exposed = value.label;
848
+ if (exposed?.id) {
849
+ return { id: exposed.id, title: exposed.title };
850
+ }
851
+ if (value.labelId) {
852
+ return { id: value.labelId, title: exposed?.title };
853
+ }
854
+ return undefined;
855
+ }
856
+ isLookupEmpty(value) {
857
+ return isNil(value?.id) || value.id === '';
858
+ }
859
+ snapshotGeographicFields(value) {
860
+ return {
861
+ street1: value.street1,
862
+ street2: value.street2,
863
+ postalCode: value.postalCode,
864
+ country: value.country,
865
+ state: value.state,
866
+ city: value.city,
867
+ };
868
+ }
869
+ resolveSettingLookupSnapshot(value) {
870
+ if (isNil(value) || value === '') {
871
+ return undefined;
872
+ }
873
+ if (typeof value === 'object') {
874
+ const record = value;
875
+ const id = extractValue(record.id ?? value);
876
+ const title = extractValue(record.title);
877
+ if (!id?.trim()) {
878
+ return undefined;
879
+ }
880
+ return {
881
+ id: id.trim(),
882
+ title: title?.trim() || undefined,
883
+ };
884
+ }
885
+ const id = extractValue(value);
886
+ return id?.trim() ? { id: id.trim() } : undefined;
887
+ }
888
+ async enrichLookupField(field) {
889
+ if (!field?.id) {
890
+ return field;
891
+ }
892
+ const locale = this.translationService.getActiveLang() || 'en-US';
893
+ const existing = resolveMultiLanguageString(field.title, locale).trim();
894
+ if (existing) {
895
+ return { id: field.id, title: existing };
896
+ }
897
+ const title = await this.resolveGeographicRegionTitle(field.id);
898
+ return title ? { id: field.id, title } : { id: field.id };
899
+ }
900
+ async resolveGeographicRegionTitle(id) {
901
+ if (this.geographicTitleCache.has(id)) {
902
+ const cached = this.geographicTitleCache.get(id);
903
+ return cached || undefined;
904
+ }
905
+ try {
906
+ const row = await this.entityService.withEntity(GEOGRAPHIC_REGION_ENTITY).data().byKey(id);
907
+ const locale = this.translationService.getActiveLang() || 'en-US';
908
+ const raw = get(row, 'title');
909
+ const normalized = resolveMultiLanguageString(raw, locale).trim();
910
+ this.geographicTitleCache.set(id, normalized);
911
+ return normalized || undefined;
912
+ }
913
+ catch {
914
+ this.geographicTitleCache.set(id, '');
915
+ return undefined;
916
+ }
917
+ }
918
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
919
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetService, providedIn: 'root' }); }
920
+ }
921
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetService, decorators: [{
922
+ type: Injectable,
923
+ args: [{ providedIn: 'root' }]
924
+ }], ctorParameters: () => [] });
925
+
926
+ class AXPAddressWidgetEditComponent extends AXPValueWidgetComponent {
927
+ constructor() {
928
+ super(...arguments);
929
+ this.addressService = inject(AXPAddressWidgetService);
930
+ /** Collapsible mode: true = panel collapsed (only full address visible), false = expanded (edit button visible) */
931
+ this.collapsibleCollapsed = signal(true, /* @ts-ignore */
932
+ ...(ngDevMode ? [{ debugName: "collapsibleCollapsed" }] : /* istanbul ignore next */ []));
933
+ this.collapsibleHeaderLabel = signal(null, /* @ts-ignore */
934
+ ...(ngDevMode ? [{ debugName: "collapsibleHeaderLabel" }] : /* istanbul ignore next */ []));
935
+ this.collapsibleHeaderAddress = signal('', /* @ts-ignore */
936
+ ...(ngDevMode ? [{ debugName: "collapsibleHeaderAddress" }] : /* istanbul ignore next */ []));
937
+ /** Bumped on parent discard so the nested layout renderer remounts with reverted context. */
938
+ this.layoutRendererGeneration = signal(0, /* @ts-ignore */
939
+ ...(ngDevMode ? [{ debugName: "layoutRendererGeneration" }] : /* istanbul ignore next */ []));
940
+ this.parentContextWasRestored = false;
941
+ this.geographicDefaultsInitialized = false;
942
+ this.suppressContextSync = false;
943
+ /** Blocks ax-collapse from auto-collapsing while a new empty row is opening. */
944
+ this.blockAutoCollapseUntil = 0;
945
+ /** Expand new repeater rows so users can enter values without clicking the header again. */
946
+ this.#expandEmptyAddressEffect = effect(() => {
947
+ if (this.addressMode() !== 'expandable') {
948
+ return;
949
+ }
950
+ if (this.shouldKeepExpandedForEntry(this.valueAsObject())) {
951
+ this.collapsibleCollapsed.set(false);
952
+ this.blockAutoCollapseUntil = Date.now() + 300;
953
+ }
954
+ }, /* @ts-ignore */
955
+ ...(ngDevMode ? [{ debugName: "#expandEmptyAddressEffect" }] : /* istanbul ignore next */ []));
956
+ this.#resetNestedFormOnDiscard = effect(() => {
957
+ if (this.addressMode() !== 'expandable') {
958
+ return;
959
+ }
960
+ const isRestored = this.contextService.changeEvent().state === 'restored';
961
+ if (isRestored && !this.parentContextWasRestored) {
962
+ this.layoutRendererGeneration.update((generation) => generation + 1);
963
+ }
964
+ this.parentContextWasRestored = isRestored;
965
+ }, /* @ts-ignore */
966
+ ...(ngDevMode ? [{ debugName: "#resetNestedFormOnDiscard" }] : /* istanbul ignore next */ []));
967
+ this.#collapsibleHeaderEffect = effect(() => {
968
+ const value = this.valueAsObject();
969
+ this.formattedAddress();
970
+ const placeholder = this.placeholder();
971
+ void this.addressService
972
+ .resolveCollapsibleHeader(value, { placeholder })
973
+ .then((header) => {
974
+ this.collapsibleHeaderLabel.set(header.labelText);
975
+ this.collapsibleHeaderAddress.set(header.addressText);
976
+ });
977
+ }, /* @ts-ignore */
978
+ ...(ngDevMode ? [{ debugName: "#collapsibleHeaderEffect" }] : /* istanbul ignore next */ []));
979
+ this.#applyGeographicDefaultsEffect = effect(() => {
980
+ if (!this.useGeographicDefaults() || this.geographicDefaultsInitialized) {
981
+ return;
982
+ }
983
+ const value = this.valueAsObject();
984
+ void this.addressService
985
+ .applyGeographicDefaultsIfNeeded(value, { enabled: true })
986
+ .then(({ value: merged, applied }) => {
987
+ this.geographicDefaultsInitialized = true;
988
+ if (!applied) {
989
+ return;
990
+ }
991
+ const normalized = this.addressService.normalizeAddressData(merged);
992
+ normalized.full = this.addressService.formatAddress(normalized);
993
+ this.commitAddressValue(normalized);
994
+ });
995
+ }, /* @ts-ignore */
996
+ ...(ngDevMode ? [{ debugName: "#applyGeographicDefaultsEffect" }] : /* istanbul ignore next */ []));
997
+ this.addressMode = computed(() => extractValue(this.options()['mode']) || 'simple', /* @ts-ignore */
998
+ ...(ngDevMode ? [{ debugName: "addressMode" }] : /* istanbul ignore next */ []));
999
+ this.placeholder = computed(() => this.options()['placeholder'] || 'Enter address...', /* @ts-ignore */
1000
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
1001
+ this.labelEntity = computed(() => this.options()['labelEntity'], /* @ts-ignore */
1002
+ ...(ngDevMode ? [{ debugName: "labelEntity" }] : /* istanbul ignore next */ []));
1003
+ this.useGeographicDefaults = computed(() => this.options()['useGeographicDefaults'] ?? true, /* @ts-ignore */
1004
+ ...(ngDevMode ? [{ debugName: "useGeographicDefaults" }] : /* istanbul ignore next */ []));
1005
+ this.disabled = computed(() => this.options()['disabled'] ?? false, /* @ts-ignore */
1006
+ ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1007
+ this.hasLabel = computed(() => this.options()['hasLabel'] ?? false, /* @ts-ignore */
1008
+ ...(ngDevMode ? [{ debugName: "hasLabel" }] : /* istanbul ignore next */ []));
1009
+ this.hasMap = computed(() => this.options()['hasMap'] ?? true, /* @ts-ignore */
1010
+ ...(ngDevMode ? [{ debugName: "hasMap" }] : /* istanbul ignore next */ []));
1011
+ this.format = computed(() => {
1012
+ if (this.hasLabel() ||
1013
+ this.addressMode() === 'popup' ||
1014
+ this.addressMode() === 'expandable') {
1015
+ return 'object';
1016
+ }
1017
+ return 'string';
1018
+ }, /* @ts-ignore */
1019
+ ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
1020
+ this.valueAsObject = computed(() => this.toObject(this.getValue()), /* @ts-ignore */
1021
+ ...(ngDevMode ? [{ debugName: "valueAsObject" }] : /* istanbul ignore next */ []));
1022
+ this.formattedAddress = computed(() => {
1023
+ const value = this.valueAsObject();
1024
+ return value.full || this.addressService.formatAddress(value);
1025
+ }, /* @ts-ignore */
1026
+ ...(ngDevMode ? [{ debugName: "formattedAddress" }] : /* istanbul ignore next */ []));
1027
+ /** Layout node from create().flex().build() for inline renderer (expandable mode). */
1028
+ this.addressFormLayout = computed(() => this.addressService.getAddressFormLayout({
1029
+ hasLabel: this.hasLabel(),
1030
+ labelEntity: this.labelEntity(),
1031
+ hasMap: this.hasMap(),
1032
+ }), /* @ts-ignore */
1033
+ ...(ngDevMode ? [{ debugName: "addressFormLayout" }] : /* istanbul ignore next */ []));
1034
+ /** Context for inline address form (expandable); includes showMap for map toggle. */
1035
+ this.collapsibleFormContext = computed(() => this.addressService.buildAddressFormContext(this.valueAsObject(), {
1036
+ hasMap: this.hasMap(),
1037
+ }), /* @ts-ignore */
1038
+ ...(ngDevMode ? [{ debugName: "collapsibleFormContext" }] : /* istanbul ignore next */ []));
1039
+ }
1040
+ /** Expand new repeater rows so users can enter values without clicking the header again. */
1041
+ #expandEmptyAddressEffect;
1042
+ #resetNestedFormOnDiscard;
1043
+ #collapsibleHeaderEffect;
1044
+ #applyGeographicDefaultsEffect;
1045
+ onCollapsibleFormContextChange(ctx) {
1046
+ if (ctx == null || this.suppressContextSync) {
1047
+ return;
1048
+ }
1049
+ const previous = this.addressService.buildAddressFormContext(this.valueAsObject(), {
1050
+ hasMap: this.hasMap(),
1051
+ });
1052
+ void (async () => {
1053
+ const normalized = this.addressService.normalizeAddressData(this.addressService.applyGeographicCascade(previous, ctx));
1054
+ const enriched = await this.addressService.enrichGeographicLookupTitles(normalized);
1055
+ enriched.full = this.addressService.formatAddress(enriched);
1056
+ if (isEqual(enriched, this.valueAsObject())) {
1057
+ return;
1058
+ }
1059
+ this.commitAddressValue(enriched);
1060
+ })();
1061
+ }
1062
+ onCollapsedChange(collapsed) {
1063
+ if (collapsed &&
1064
+ (Date.now() < this.blockAutoCollapseUntil ||
1065
+ this.shouldKeepExpandedForEntry(this.valueAsObject()))) {
1066
+ return;
1067
+ }
1068
+ this.collapsibleCollapsed.set(collapsed);
1069
+ }
1070
+ async handleValueChange(e) {
1071
+ const { name, value, isUserInteraction } = e;
1072
+ if (isUserInteraction) {
1073
+ const newValues = { ...this.valueAsObject(), [name]: value };
1074
+ this.setValue(this.setFormattedValue(newValues));
1075
+ }
1076
+ }
1077
+ async showDetailsPopup() {
1078
+ const currentValue = this.valueAsObject();
1079
+ const result = await this.addressService.showAddressDetailsPopup(currentValue, {
1080
+ hasMap: this.hasMap(),
1081
+ hasLabel: this.hasLabel(),
1082
+ labelEntity: this.labelEntity(),
1083
+ useGeographicDefaults: this.useGeographicDefaults(),
1084
+ });
1085
+ if (result) {
1086
+ result.full = this.addressService.formatAddress(result);
1087
+ this.setValue(this.setFormattedValue(result));
1088
+ }
1089
+ }
1090
+ generateClasses(element) {
1091
+ const isValue = element === 'value';
1092
+ const hasLabel = this.hasLabel();
1093
+ const baseClass = 'col-span-12';
1094
+ if (!hasLabel) {
1095
+ return baseClass;
1096
+ }
1097
+ return {
1098
+ [baseClass]: true,
1099
+ 'lg:col-span-7': isValue,
1100
+ 'lg:col-span-5': !isValue,
1101
+ };
1102
+ }
1103
+ commitAddressValue(value) {
1104
+ this.suppressContextSync = true;
1105
+ if (this.shouldKeepExpandedForEntry(value)) {
1106
+ this.blockAutoCollapseUntil = Date.now() + 300;
1107
+ this.collapsibleCollapsed.set(false);
1108
+ }
1109
+ this.setValue(this.setFormattedValue(value));
1110
+ window.setTimeout(() => {
1111
+ this.suppressContextSync = false;
1112
+ }, 50);
1113
+ }
1114
+ /** True while the row has no user-entered content (ignores geographic defaults). */
1115
+ shouldKeepExpandedForEntry(value) {
1116
+ return (!value.street1?.trim() &&
1117
+ !value.street2?.trim() &&
1118
+ !value.postalCode?.trim() &&
1119
+ !value.label?.id);
1120
+ }
1121
+ toObject(item) {
1122
+ return this.addressService.normalizeAddressData(item);
1123
+ }
1124
+ setFormattedValue(item) {
1125
+ if (this.format() === 'string') {
1126
+ return item.full;
1127
+ }
1128
+ return item;
1129
+ }
1130
+ get __class() {
1131
+ return 'block flex-1';
1132
+ }
1133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetEditComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1134
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPAddressWidgetEditComponent, isStandalone: true, selector: "axp-address-widget-edit", host: { properties: { "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
1135
+ @if (addressMode() === 'simple') {
1136
+ <div class="grid grid-cols-12 gap-4 auto-cols-max">
1137
+ <ax-text-box
1138
+ [ngModel]="valueAsObject().full"
1139
+ (onValueChanged)="handleValueChange($event)"
1140
+ type="text"
1141
+ name="full"
1142
+ [placeholder]="placeholder()"
1143
+ [ngClass]="generateClasses('value')"
1144
+ [disabled]="disabled()"
1145
+ >
1146
+ @for (validation of validationRules(); track $index) {
1147
+ <ax-validation-rule
1148
+ [rule]="validation.rule"
1149
+ [message]="$safeNavigationMigration(validation.options?.message)"
1150
+ [options]="validation.options"
1151
+ ></ax-validation-rule>
1152
+ }
1153
+ </ax-text-box>
1154
+ </div>
1155
+ } @else if (addressMode() === 'expandable') {
1156
+ <div class="w-full">
1157
+ <ax-accordion-group>
1158
+ <ax-accordion-item
1159
+ [headerTemplate]="collapseHeaderTemplate"
1160
+ [isCollapsed]="collapsibleCollapsed()"
1161
+ (isCollapsedChange)="onCollapsedChange($event)"
1162
+ >
1163
+ <div class="pt-1">
1164
+ @for (formKey of [layoutRendererGeneration()]; track formKey) {
1165
+ <axp-layout-renderer
1166
+ [layout]="addressFormLayout()"
1167
+ [context]="collapsibleFormContext()"
1168
+ (contextChange)="onCollapsibleFormContextChange($event)"
1169
+ />
1170
+ }
1171
+ </div>
1172
+ </ax-accordion-item>
1173
+ </ax-accordion-group>
1174
+ </div>
1175
+
1176
+ <ng-template #collapseHeaderTemplate>
1177
+ <div class="ax-accordion-header-container">
1178
+ <div class="ax-accordion-header-start">
1179
+ <span
1180
+ class="ax-accordion-header-icon fa-light fa-map-marker-alt"
1181
+ ></span>
1182
+ <span>
1183
+ @if (collapsibleHeaderLabel()) {
1184
+ <span class="font-semibold">{{
1185
+ collapsibleHeaderLabel()
1186
+ }}</span>
1187
+ @if (collapsibleHeaderAddress()) {
1188
+ <span> · {{ collapsibleHeaderAddress() }}</span>
1189
+ }
1190
+ } @else {
1191
+ {{ collapsibleHeaderAddress() }}
1192
+ }
1193
+ </span>
1194
+ </div>
1195
+ <div class="ax-accordion-header-end">
1196
+ <span
1197
+ class="ax-icon ax-icon-chevron-left ax-accordion-arrow"
1198
+ [class]="collapsibleCollapsed() ? '-rotation-90' : 'rotation-90'"
1199
+ ></span>
1200
+ </div>
1201
+ </div>
1202
+ </ng-template>
1203
+ } @else {
1204
+ <div class="grid grid-cols-12 gap-4 auto-cols-max">
1205
+ <div class="flex items-center gap-2 col-span-12">
1206
+ <ax-text-box
1207
+ [ngModel]="formattedAddress()"
1208
+ type="text"
1209
+ [readonly]="true"
1210
+ [placeholder]="placeholder()"
1211
+ class="flex-1"
1212
+ [disabled]="disabled()"
1213
+ >
1214
+ <ax-prefix>
1215
+ <ax-icon icon="fa-light fa-map-marker-alt" />
1216
+ </ax-prefix>
1217
+ <ax-suffix>
1218
+ <ax-button
1219
+ look="flat"
1220
+ size="sm"
1221
+ [disabled]="disabled()"
1222
+ (onClick)="showDetailsPopup()"
1223
+ >
1224
+ <ax-icon icon="fa-light fa-cog" />
1225
+ </ax-button>
1226
+ </ax-suffix>
1227
+ </ax-text-box>
1228
+ </div>
1229
+ </div>
1230
+ }
1231
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "directive", type: i3.AXValidationRuleDirective, selector: "ax-validation-rule", inputs: ["rule", "options", "message", "disabled"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i4.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i4.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXTextBoxModule }, { kind: "component", type: i5.AXTextBoxComponent, selector: "ax-text-box", inputs: ["disabled", "tabIndex", "readonly", "value", "state", "name", "id", "placeholder", "maxLength", "allowNull", "type", "autoComplete", "look", "maskPattern", "customTokens", "class"], outputs: ["onBlur", "onFocus", "valueChange", "stateChange", "onValueChanged", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress", "onMaskChanged"] }, { kind: "ngmodule", type: AXValidationModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i6.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXAccordionModule }, { kind: "component", type: i7.AXAccordionItemComponent, selector: "ax-accordion-item", inputs: ["isCollapsed", "icon", "textdecoration", "caption", "isLoading", "headerTemplate", "look", "disabled"], outputs: ["isCollapsedChange", "isLoadingChange", "onClick"] }, { kind: "component", type: i7.AXAccordionGroupComponent, selector: "ax-accordion-group", inputs: ["accordion", "activeIndex", "look", "collapsedOnItemClick"], outputs: ["activeIndexChange"] }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1232
+ }
1233
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetEditComponent, decorators: [{
1234
+ type: Component,
1235
+ args: [{
1236
+ selector: 'axp-address-widget-edit',
1237
+ template: `
1238
+ @if (addressMode() === 'simple') {
1239
+ <div class="grid grid-cols-12 gap-4 auto-cols-max">
1240
+ <ax-text-box
1241
+ [ngModel]="valueAsObject().full"
1242
+ (onValueChanged)="handleValueChange($event)"
1243
+ type="text"
1244
+ name="full"
1245
+ [placeholder]="placeholder()"
1246
+ [ngClass]="generateClasses('value')"
1247
+ [disabled]="disabled()"
1248
+ >
1249
+ @for (validation of validationRules(); track $index) {
1250
+ <ax-validation-rule
1251
+ [rule]="validation.rule"
1252
+ [message]="$safeNavigationMigration(validation.options?.message)"
1253
+ [options]="validation.options"
1254
+ ></ax-validation-rule>
1255
+ }
1256
+ </ax-text-box>
1257
+ </div>
1258
+ } @else if (addressMode() === 'expandable') {
1259
+ <div class="w-full">
1260
+ <ax-accordion-group>
1261
+ <ax-accordion-item
1262
+ [headerTemplate]="collapseHeaderTemplate"
1263
+ [isCollapsed]="collapsibleCollapsed()"
1264
+ (isCollapsedChange)="onCollapsedChange($event)"
1265
+ >
1266
+ <div class="pt-1">
1267
+ @for (formKey of [layoutRendererGeneration()]; track formKey) {
1268
+ <axp-layout-renderer
1269
+ [layout]="addressFormLayout()"
1270
+ [context]="collapsibleFormContext()"
1271
+ (contextChange)="onCollapsibleFormContextChange($event)"
1272
+ />
1273
+ }
1274
+ </div>
1275
+ </ax-accordion-item>
1276
+ </ax-accordion-group>
1277
+ </div>
1278
+
1279
+ <ng-template #collapseHeaderTemplate>
1280
+ <div class="ax-accordion-header-container">
1281
+ <div class="ax-accordion-header-start">
1282
+ <span
1283
+ class="ax-accordion-header-icon fa-light fa-map-marker-alt"
1284
+ ></span>
1285
+ <span>
1286
+ @if (collapsibleHeaderLabel()) {
1287
+ <span class="font-semibold">{{
1288
+ collapsibleHeaderLabel()
1289
+ }}</span>
1290
+ @if (collapsibleHeaderAddress()) {
1291
+ <span> · {{ collapsibleHeaderAddress() }}</span>
1292
+ }
1293
+ } @else {
1294
+ {{ collapsibleHeaderAddress() }}
1295
+ }
1296
+ </span>
1297
+ </div>
1298
+ <div class="ax-accordion-header-end">
1299
+ <span
1300
+ class="ax-icon ax-icon-chevron-left ax-accordion-arrow"
1301
+ [class]="collapsibleCollapsed() ? '-rotation-90' : 'rotation-90'"
1302
+ ></span>
1303
+ </div>
1304
+ </div>
1305
+ </ng-template>
1306
+ } @else {
1307
+ <div class="grid grid-cols-12 gap-4 auto-cols-max">
1308
+ <div class="flex items-center gap-2 col-span-12">
1309
+ <ax-text-box
1310
+ [ngModel]="formattedAddress()"
1311
+ type="text"
1312
+ [readonly]="true"
1313
+ [placeholder]="placeholder()"
1314
+ class="flex-1"
1315
+ [disabled]="disabled()"
1316
+ >
1317
+ <ax-prefix>
1318
+ <ax-icon icon="fa-light fa-map-marker-alt" />
1319
+ </ax-prefix>
1320
+ <ax-suffix>
1321
+ <ax-button
1322
+ look="flat"
1323
+ size="sm"
1324
+ [disabled]="disabled()"
1325
+ (onClick)="showDetailsPopup()"
1326
+ >
1327
+ <ax-icon icon="fa-light fa-cog" />
1328
+ </ax-button>
1329
+ </ax-suffix>
1330
+ </ax-text-box>
1331
+ </div>
1332
+ </div>
1333
+ }
1334
+ `,
1335
+ changeDetection: ChangeDetectionStrategy.OnPush,
1336
+ imports: [
1337
+ CommonModule,
1338
+ FormsModule,
1339
+ AXFormModule,
1340
+ AXDecoratorModule,
1341
+ AXTextBoxModule,
1342
+ AXValidationModule,
1343
+ AXTranslationModule,
1344
+ AXButtonModule,
1345
+ AXAccordionModule,
1346
+ AXPLayoutRendererComponent,
1347
+ ],
1348
+ }]
1349
+ }], propDecorators: { __class: [{
1350
+ type: HostBinding,
1351
+ args: ['class']
1352
+ }] } });
1353
+
1354
+ var addressWidgetEdit_component = /*#__PURE__*/Object.freeze({
1355
+ __proto__: null,
1356
+ AXPAddressWidgetEditComponent: AXPAddressWidgetEditComponent
1357
+ });
1358
+
1359
+ class AXPAddressWidgetViewComponent extends AXPValueWidgetComponent {
1360
+ constructor() {
1361
+ super(...arguments);
1362
+ this.addressService = inject(AXPAddressWidgetService);
1363
+ this.hasLabel = computed(() => this.options()['hasLabel'] ?? false, /* @ts-ignore */
1364
+ ...(ngDevMode ? [{ debugName: "hasLabel" }] : /* istanbul ignore next */ []));
1365
+ this.internalValue = computed(() => this.addressService.normalizeAddressData(this.getValue()), /* @ts-ignore */
1366
+ ...(ngDevMode ? [{ debugName: "internalValue" }] : /* istanbul ignore next */ []));
1367
+ this.labelText = computed(() => this.internalValue().label?.title?.trim() ?? '', /* @ts-ignore */
1368
+ ...(ngDevMode ? [{ debugName: "labelText" }] : /* istanbul ignore next */ []));
1369
+ this.formattedAddress = computed(() => {
1370
+ const value = this.internalValue();
1371
+ return value.full || this.addressService.formatAddress(value);
1372
+ }, /* @ts-ignore */
1373
+ ...(ngDevMode ? [{ debugName: "formattedAddress" }] : /* istanbul ignore next */ []));
1374
+ this.hasValue = computed(() => {
1375
+ const rawValue = this.getValue();
1376
+ if (isNull(rawValue))
1377
+ return false;
1378
+ const value = this.addressService.normalizeAddressData(rawValue);
1379
+ return !isEmpty(value.full);
1380
+ }, /* @ts-ignore */
1381
+ ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
1382
+ }
1383
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1384
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPAddressWidgetViewComponent, isStandalone: true, selector: "axp-address-widget-view", usesInheritance: true, ngImport: i0, template: `
1385
+ @if (hasValue()) {
1386
+ <div class="flex gap-2 items-center">
1387
+ <div class="flex gap-2 group items-center justify-center truncate">
1388
+ <span class="truncate">{{ formattedAddress() }}</span>
1389
+ </div>
1390
+ @if (hasLabel() && labelText()) {
1391
+ <div><ax-badge color="primary" [look]="'twotone'" [text]="labelText()"></ax-badge></div>
1392
+ }
1393
+ </div>
1394
+ } @else {
1395
+ <span class="text-muted">---</span>
1396
+ }
1397
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXBadgeModule }, { kind: "component", type: i1$1.AXBadgeComponent, selector: "ax-badge", inputs: ["color", "look", "text"] }, { kind: "ngmodule", type: AXDecoratorModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1398
+ }
1399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetViewComponent, decorators: [{
1400
+ type: Component,
1401
+ args: [{
1402
+ selector: 'axp-address-widget-view',
1403
+ template: `
1404
+ @if (hasValue()) {
1405
+ <div class="flex gap-2 items-center">
1406
+ <div class="flex gap-2 group items-center justify-center truncate">
1407
+ <span class="truncate">{{ formattedAddress() }}</span>
1408
+ </div>
1409
+ @if (hasLabel() && labelText()) {
1410
+ <div><ax-badge color="primary" [look]="'twotone'" [text]="labelText()"></ax-badge></div>
1411
+ }
1412
+ </div>
1413
+ } @else {
1414
+ <span class="text-muted">---</span>
1415
+ }
1416
+ `,
1417
+ changeDetection: ChangeDetectionStrategy.OnPush,
1418
+ imports: [FormsModule, AXBadgeModule, AXDecoratorModule],
1419
+ }]
1420
+ }] });
1421
+
1422
+ var addressWidgetView_component = /*#__PURE__*/Object.freeze({
1423
+ __proto__: null,
1424
+ AXPAddressWidgetViewComponent: AXPAddressWidgetViewComponent
1425
+ });
1426
+
1427
+ class AXPAddressWidgetColumnComponent extends AXPColumnWidgetComponent {
1428
+ constructor() {
1429
+ super(...arguments);
1430
+ this.clipboard = inject(AXPClipBoardService);
1431
+ this.addressService = inject(AXPAddressWidgetService);
1432
+ this.normalizedValue = computed(() => {
1433
+ const raw = this.rawValue;
1434
+ if (!raw)
1435
+ return null;
1436
+ return this.addressService.normalizeAddressData(raw);
1437
+ }, /* @ts-ignore */
1438
+ ...(ngDevMode ? [{ debugName: "normalizedValue" }] : /* istanbul ignore next */ []));
1439
+ this.formattedAddress = computed(() => {
1440
+ const value = this.normalizedValue();
1441
+ if (!value)
1442
+ return '';
1443
+ return value.full || this.addressService.formatAddress(value);
1444
+ }, /* @ts-ignore */
1445
+ ...(ngDevMode ? [{ debugName: "formattedAddress" }] : /* istanbul ignore next */ []));
1446
+ this.hasValue = computed(() => {
1447
+ const value = this.normalizedValue();
1448
+ if (!value)
1449
+ return false;
1450
+ return !isEmpty(value.full);
1451
+ }, /* @ts-ignore */
1452
+ ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
1453
+ }
1454
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1455
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: AXPAddressWidgetColumnComponent, isStandalone: true, selector: "axp-address-widget-column", inputs: { rawValue: "rawValue", rowData: "rowData" }, usesInheritance: true, ngImport: i0, template: `
1456
+ @if (hasValue()) {
1457
+ <div class="flex justify-start items-center gap-2 group w-fit">
1458
+ <span class="truncate" [title]="formattedAddress()">{{ formattedAddress() }}</span>
1459
+ <i
1460
+ (click)="clipboard.copy('Address', formattedAddress())"
1461
+ class="fa-solid fa-copy text-neutral-400 dark:hover:text-neutral-100 hover:text-neutral-900 group-hover:visible invisible"
1462
+ ></i>
1463
+ </div>
1464
+ } @else {
1465
+ <span class="text-muted">---</span>
1466
+ }
1467
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1468
+ }
1469
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXPAddressWidgetColumnComponent, decorators: [{
1470
+ type: Component,
1471
+ args: [{
1472
+ selector: 'axp-address-widget-column',
1473
+ template: `
1474
+ @if (hasValue()) {
1475
+ <div class="flex justify-start items-center gap-2 group w-fit">
1476
+ <span class="truncate" [title]="formattedAddress()">{{ formattedAddress() }}</span>
1477
+ <i
1478
+ (click)="clipboard.copy('Address', formattedAddress())"
1479
+ class="fa-solid fa-copy text-neutral-400 dark:hover:text-neutral-100 hover:text-neutral-900 group-hover:visible invisible"
1480
+ ></i>
1481
+ </div>
1482
+ } @else {
1483
+ <span class="text-muted">---</span>
1484
+ }
1485
+ `,
1486
+ changeDetection: ChangeDetectionStrategy.OnPush,
1487
+ inputs: ['rawValue', 'rowData'],
1488
+ }]
1489
+ }] });
1490
+
1491
+ var addressWidgetColumn_component = /*#__PURE__*/Object.freeze({
1492
+ __proto__: null,
1493
+ AXPAddressWidgetColumnComponent: AXPAddressWidgetColumnComponent
1494
+ });
1495
+
1496
+ //#endregion
1497
+ //#region ---- Location Management Widgets Provider ----
1498
+ const LOCATION_WIDGETS = [AXPAddressWidget];
1499
+ /**
1500
+ * Provider for location-management widgets (Address editor).
1501
+ * The address widget lives here because its service depends on `@acorex-platform/framework-client/layout/entity`,
1502
+ * which would otherwise create a circular dependency with `@acorex-platform/framework-client/layout/widgets`.
1503
+ */
1504
+ class AXMLocationManagementWidgetsProvider {
1505
+ getWidgets() {
1506
+ return LOCATION_WIDGETS;
1507
+ }
1508
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementWidgetsProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1509
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementWidgetsProvider }); }
1510
+ }
1511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementWidgetsProvider, decorators: [{
1512
+ type: Injectable
1513
+ }] });
1514
+
1515
+ class AXMLocationManagementModule {
1516
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1517
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementModule, imports: [CommonModule,
1518
+ AXPWidgetCoreModule] }); }
1519
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementModule, providers: [
1520
+ // Module Manifest Provider
1521
+ {
1522
+ provide: AXP_MODULE_MANIFEST_PROVIDER,
1523
+ useValue: LocationManagementManifest,
1524
+ multi: true,
1525
+ },
1526
+ // Provider references (now using tokens)
1527
+ {
1528
+ provide: AXP_PERMISSION_DEFINITION_PROVIDER,
1529
+ useClass: AXMLocationManagementPermissionDefinitionProvider,
1530
+ multi: true,
1531
+ },
1532
+ {
1533
+ provide: AXP_MENU_PROVIDER,
1534
+ useClass: AXMLocationManagementMenuProvider,
1535
+ multi: true,
1536
+ },
1537
+ {
1538
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
1539
+ multi: true,
1540
+ useValue: locationAssignmentLocationHydrateMiddleware,
1541
+ },
1542
+ {
1543
+ provide: AXP_SETTING_DEFINITION_PROVIDER,
1544
+ useClass: AXMSettingProvider,
1545
+ multi: true,
1546
+ },
1547
+ {
1548
+ provide: AXP_SEARCH_PROVIDER,
1549
+ useClass: AXMSearchCommandProvider,
1550
+ multi: true,
1551
+ },
1552
+ {
1553
+ provide: AXP_FEATURE_DEFINITION_PROVIDER,
1554
+ useClass: AXMLocationManagementFeatureDefinitionProvider,
1555
+ multi: true,
1556
+ },
1557
+ {
1558
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
1559
+ useClass: AXMLocationManagementWidgetsProvider,
1560
+ multi: true,
1561
+ },
1562
+ provideCommandSetups([
1563
+ {
1564
+ key: `${RootConfig.module.name}.${RootConfig.entities.locationAssignment.name}:AssignExistingLocation`,
1565
+ command: () => import('./acorex-platform-module-location-management-client-assign-existing-location-to-party.command-DECKrIBR.mjs').then((c) => c.AXMLocationAssignmentAssignExistingLocationCommand),
1566
+ },
1567
+ {
1568
+ key: `${RootConfig.module.name}.${RootConfig.entities.locationAssignment.name}:CreateWithNewLocation`,
1569
+ command: () => import('./acorex-platform-module-location-management-client-create-location-with-assignment.command-Cl6KfruM.mjs').then((c) => c.AXMLocationAssignmentCreateWithNewLocationCommand),
1570
+ },
1571
+ ]),
1572
+ ], imports: [CommonModule,
1573
+ AXPWidgetCoreModule] }); }
1574
+ }
1575
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementModule, decorators: [{
1576
+ type: NgModule,
1577
+ args: [{
1578
+ imports: [
1579
+ CommonModule,
1580
+ AXPWidgetCoreModule,
1581
+ ],
1582
+ exports: [],
1583
+ declarations: [],
1584
+ providers: [
1585
+ // Module Manifest Provider
1586
+ {
1587
+ provide: AXP_MODULE_MANIFEST_PROVIDER,
1588
+ useValue: LocationManagementManifest,
1589
+ multi: true,
1590
+ },
1591
+ // Provider references (now using tokens)
1592
+ {
1593
+ provide: AXP_PERMISSION_DEFINITION_PROVIDER,
1594
+ useClass: AXMLocationManagementPermissionDefinitionProvider,
1595
+ multi: true,
1596
+ },
1597
+ {
1598
+ provide: AXP_MENU_PROVIDER,
1599
+ useClass: AXMLocationManagementMenuProvider,
1600
+ multi: true,
1601
+ },
1602
+ {
1603
+ provide: AXP_ENTITY_STORAGE_MIDDLEWARE,
1604
+ multi: true,
1605
+ useValue: locationAssignmentLocationHydrateMiddleware,
1606
+ },
1607
+ {
1608
+ provide: AXP_SETTING_DEFINITION_PROVIDER,
1609
+ useClass: AXMSettingProvider,
1610
+ multi: true,
1611
+ },
1612
+ {
1613
+ provide: AXP_SEARCH_PROVIDER,
1614
+ useClass: AXMSearchCommandProvider,
1615
+ multi: true,
1616
+ },
1617
+ {
1618
+ provide: AXP_FEATURE_DEFINITION_PROVIDER,
1619
+ useClass: AXMLocationManagementFeatureDefinitionProvider,
1620
+ multi: true,
1621
+ },
1622
+ {
1623
+ provide: AXP_WIDGET_DEFINITION_PROVIDER,
1624
+ useClass: AXMLocationManagementWidgetsProvider,
1625
+ multi: true,
1626
+ },
1627
+ provideCommandSetups([
1628
+ {
1629
+ key: `${RootConfig.module.name}.${RootConfig.entities.locationAssignment.name}:AssignExistingLocation`,
1630
+ command: () => import('./acorex-platform-module-location-management-client-assign-existing-location-to-party.command-DECKrIBR.mjs').then((c) => c.AXMLocationAssignmentAssignExistingLocationCommand),
1631
+ },
1632
+ {
1633
+ key: `${RootConfig.module.name}.${RootConfig.entities.locationAssignment.name}:CreateWithNewLocation`,
1634
+ command: () => import('./acorex-platform-module-location-management-client-create-location-with-assignment.command-Cl6KfruM.mjs').then((c) => c.AXMLocationAssignmentCreateWithNewLocationCommand),
1635
+ },
1636
+ ]),
1637
+ ]
1638
+ }]
1639
+ }] });
1640
+
1641
+ class AXMLocationManagementService {
1642
+ constructor() {
1643
+ this.entityService = inject(AXPEntityService);
1644
+ this.translationService = inject(AXTranslationService);
1645
+ this.geographicRegionDataAccessor = this.entityService
1646
+ .withEntity(RootConfig.module.name, RootConfig.entities.geographicRegion.name)
1647
+ .data();
1648
+ }
1649
+ async getCountries() {
1650
+ const result = await this.geographicRegionDataAccessor.query({
1651
+ skip: 0,
1652
+ take: 1000,
1653
+ filter: { field: 'type', operator: { type: 'equal' }, value: 'country' },
1654
+ sort: [{ field: 'title', dir: 'asc' }],
1655
+ });
1656
+ return result.items.map((m) => this.toGeoLocation(m));
1657
+ }
1658
+ async getProvinces(countryId) {
1659
+ const result = await this.geographicRegionDataAccessor.query({
1660
+ skip: 0,
1661
+ take: 1000,
1662
+ filter: { field: 'type', operator: { type: 'equal' }, value: 'state' },
1663
+ sort: [{ field: 'title', dir: 'asc' }],
1664
+ });
1665
+ return result.items.map((m) => this.toGeoLocation(m));
1666
+ }
1667
+ async getCities(filter) {
1668
+ const result = await this.geographicRegionDataAccessor.query({
1669
+ skip: 0,
1670
+ take: 1000,
1671
+ filter: { field: 'type', operator: { type: 'equal' }, value: 'city' },
1672
+ sort: [{ field: 'title', dir: 'asc' }],
1673
+ });
1674
+ return result.items.map((m) => this.toGeoLocation(m));
1675
+ }
1676
+ toGeoLocation(row) {
1677
+ const locale = this.translationService.getActiveLang() || 'en-US';
1678
+ const timezone = typeof row.timezone === 'string' ? row.timezone : (row.timezone?.code ?? undefined);
1679
+ return {
1680
+ id: row.id,
1681
+ code: row.code,
1682
+ title: resolveMultiLanguageString(row.title, locale),
1683
+ timezone,
1684
+ };
1685
+ }
1686
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1687
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementService, providedIn: 'root' }); }
1688
+ }
1689
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXMLocationManagementService, decorators: [{
1690
+ type: Injectable,
1691
+ args: [{
1692
+ providedIn: 'root',
1693
+ }]
1694
+ }] });
1695
+
1696
+ /**
1697
+ * Generated bundle index. Do not edit.
1698
+ */
1699
+
1700
+ export { AXMLocationManagementMenuProvider, AXMLocationManagementModule, AXMLocationManagementService, AXMSearchCommandProvider, AXMSettingProvider };
1701
+ //# sourceMappingURL=acorex-platform-module-location-management-client.mjs.map