@africanies/angular-web-sdk 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nx/cache/13293303228070520113/dist/libs/africanies-core/README.md +85 -0
- package/.nx/cache/13293303228070520113/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs +4699 -0
- package/.nx/cache/13293303228070520113/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +1 -0
- package/.nx/cache/13293303228070520113/dist/libs/africanies-core/package.json +31 -0
- package/.nx/cache/13293303228070520113/dist/libs/africanies-core/types/africanies-africanies-core.d.ts +2748 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/README.md +46 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +249 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/package.json +35 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/tailwind-preset.cjs +330 -0
- package/.nx/cache/13387631073062967069/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +178 -0
- package/.nx/cache/16704640000606796352/dist/libs/africanies-storage/README.md +31 -0
- package/.nx/cache/16704640000606796352/dist/libs/africanies-storage/fesm2022/africanies-africanies-storage.mjs +249 -0
- package/.nx/cache/16704640000606796352/dist/libs/africanies-storage/fesm2022/africanies-africanies-storage.mjs.map +1 -0
- package/.nx/cache/16704640000606796352/dist/libs/africanies-storage/package.json +26 -0
- package/.nx/cache/16704640000606796352/dist/libs/africanies-storage/types/africanies-africanies-storage.d.ts +210 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/README.md +68 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/assets/brand/africanies-logo-mini.png +0 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/assets/brand/africanies-logo.png +0 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/assets/brand/africanies-logo.svg +5 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/assets/carriers/dhl.svg +7 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +21251 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/package.json +35 -0
- package/.nx/cache/2427575433215940812/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +5803 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/README.md +69 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/assets/icons.sprite.svg +1851 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs +839 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs.map +1 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/package.json +30 -0
- package/.nx/cache/7730350229628359718/dist/libs/africanies-icons/types/africanies-africanies-icons.d.ts +108 -0
- package/.nx/cache/run.json +35 -35
- package/.nx/cache/terminalOutputs/10603154579345867998 +397 -0
- package/.nx/cache/terminalOutputs/12354163057083828162 +80 -0
- package/.nx/cache/terminalOutputs/13293303228070520113 +21 -0
- package/.nx/cache/terminalOutputs/13387631073062967069 +21 -0
- package/.nx/cache/terminalOutputs/14876351543379349919 +176 -0
- package/.nx/cache/terminalOutputs/15336883221450327589 +21 -0
- package/.nx/cache/terminalOutputs/16208231681037145050 +86 -84
- package/.nx/cache/terminalOutputs/16704640000606796352 +21 -0
- package/.nx/cache/terminalOutputs/1811006905937373707 +74 -0
- package/.nx/cache/terminalOutputs/2005781115771702035 +8 -0
- package/.nx/cache/terminalOutputs/2360743690449633551 +21 -0
- package/.nx/cache/terminalOutputs/2427575433215940812 +21 -0
- package/.nx/cache/terminalOutputs/2981230413857865352 +8 -0
- package/.nx/cache/terminalOutputs/3243550283886864639 +8 -0
- package/.nx/cache/terminalOutputs/3380188914363501109 +231 -0
- package/.nx/cache/terminalOutputs/3699068646900552690 +8 -0
- package/.nx/cache/terminalOutputs/5175669339257931410 +8 -0
- package/.nx/cache/terminalOutputs/6040230831125637867 +8 -0
- package/.nx/cache/terminalOutputs/7730350229628359718 +21 -0
- package/.nx/cache/terminalOutputs/8098730470212963224 +87 -0
- package/.nx/cache/terminalOutputs/8928690901537686687 +21 -0
- package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db +0 -0
- package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-shm +0 -0
- package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-wal +0 -0
- package/.nx/workspace-data/d/daemon.log +2859 -0
- package/.nx/workspace-data/d/server-process.json +2 -2
- package/.nx/workspace-data/file-map.json +2155 -2183
- package/.nx/workspace-data/nx_files.nxt +0 -0
- package/.nx/workspace-data/project-graph.json +2 -2
- package/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs +60 -0
- package/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +1 -1
- package/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs +6 -0
- package/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs.map +1 -1
- package/dist/libs/africanies-storage/fesm2022/africanies-africanies-storage.mjs +6 -0
- package/dist/libs/africanies-storage/fesm2022/africanies-africanies-storage.mjs.map +1 -1
- package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +6 -0
- package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -1
- package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +297 -51
- package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -1
- package/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +12 -12
- package/libs/africanies-core/src/lib/auth/auth-token.service.ts +3 -0
- package/libs/africanies-core/src/lib/auth/auth.service.ts +3 -0
- package/libs/africanies-core/src/lib/country/country.service.ts +3 -0
- package/libs/africanies-core/src/lib/currency/currency.service.ts +3 -0
- package/libs/africanies-core/src/lib/document/document.service.ts +3 -0
- package/libs/africanies-core/src/lib/file/file.service.ts +3 -0
- package/libs/africanies-core/src/lib/filters/filter-options.resolver.ts +3 -0
- package/libs/africanies-core/src/lib/http/api-client.ts +3 -0
- package/libs/africanies-core/src/lib/mode/mode-config.service.ts +3 -0
- package/libs/africanies-core/src/lib/notification/notification.service.ts +3 -0
- package/libs/africanies-core/src/lib/overlay/route-overlay.service.ts +3 -0
- package/libs/africanies-core/src/lib/payment-method/payment-method.service.ts +3 -0
- package/libs/africanies-core/src/lib/plan/plan.service.ts +3 -0
- package/libs/africanies-core/src/lib/product/product.service.ts +3 -0
- package/libs/africanies-core/src/lib/service/service.service.ts +3 -0
- package/libs/africanies-core/src/lib/shipment-method/shipment-method.service.ts +3 -0
- package/libs/africanies-core/src/lib/shipping/shipping-mode.service.ts +3 -0
- package/libs/africanies-core/src/lib/user/user.service.ts +3 -0
- package/libs/africanies-core/src/lib/warehouse/warehouse.service.ts +3 -0
- package/libs/africanies-core/src/lib/zone/zone.service.ts +3 -0
- package/libs/africanies-icons/src/lib/africanies-icon.component.ts +3 -0
- package/libs/africanies-icons/src/lib/icon-registry.service.ts +3 -0
- package/libs/africanies-storage/src/lib/local-storage.service.ts +3 -0
- package/libs/africanies-storage/src/lib/session-storage.service.ts +3 -0
- package/libs/africanies-theme/src/lib/mode-color.service.ts +3 -0
- package/libs/africanies-theme/src/lib/theme.service.ts +3 -0
- package/libs/africanies-ui/src/index.ts +11 -11
- package/libs/africanies-ui/src/lib/accordion/accordion.component.ts +3 -0
- package/libs/africanies-ui/src/lib/action-menu/action-menu-trigger.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/action-menu/action-menu.component.ts +3 -0
- package/libs/africanies-ui/src/lib/alert/alert.component.ts +3 -0
- package/libs/africanies-ui/src/lib/avatar/avatar-menu.component.ts +3 -0
- package/libs/africanies-ui/src/lib/avatar/avatar.component.ts +3 -0
- package/libs/africanies-ui/src/lib/brand/brand-logo.component.ts +3 -0
- package/libs/africanies-ui/src/lib/button/button.component.ts +3 -0
- package/libs/africanies-ui/src/lib/carrier/carrier-logo.component.ts +3 -0
- package/libs/africanies-ui/src/lib/chip/chip.component.ts +3 -0
- package/libs/africanies-ui/src/lib/content-stack/content-stack.component.ts +3 -0
- package/libs/africanies-ui/src/lib/copy-button/copy-button.component.ts +3 -0
- package/libs/africanies-ui/src/lib/feedback/async-state.component.ts +3 -0
- package/libs/africanies-ui/src/lib/feedback/empty-state.component.ts +3 -0
- package/libs/africanies-ui/src/lib/feedback/error-indicator.component.ts +3 -0
- package/libs/africanies-ui/src/lib/feedback/error-state.component.ts +3 -0
- package/libs/africanies-ui/src/lib/feedback/loading-state.component.ts +3 -0
- package/libs/africanies-ui/src/lib/filters/filter-drawer.panel.ts +3 -0
- package/libs/africanies-ui/src/lib/filters/filter-drawer.service.ts +3 -0
- package/libs/africanies-ui/src/lib/filters/filter-query.service.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/address-input/address-input.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/address-input/google-places.service.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/checkbox/checkbox.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/date-picker/date-picker.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/file-upload/camera-capture.dialog.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/file-upload/file-preview.dialog.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/file-upload/file-upload.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/index.ts +3 -3
- package/libs/africanies-ui/src/lib/forms/number-input/number-input.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/otp-input/otp-input.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/phone-input/phone-input.component.ts +9 -6
- package/libs/africanies-ui/src/lib/forms/radio/radio.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/search-combobox/search-combobox.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/select/select.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/text-input/text-input.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/textarea/textarea.component.ts +3 -0
- package/libs/africanies-ui/src/lib/forms/toggle/toggle.component.ts +3 -0
- package/libs/africanies-ui/src/lib/image/image.component.ts +3 -0
- package/libs/africanies-ui/src/lib/info-popover/info-popover-content.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/info-popover/info-popover-trigger.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/info-popover/info-popover.component.ts +3 -0
- package/libs/africanies-ui/src/lib/layout/app-shell-content-header.component.ts +3 -0
- package/libs/africanies-ui/src/lib/layout/app-shell-header-slot.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/layout/app-shell-header.component.ts +9 -0
- package/libs/africanies-ui/src/lib/layout/app-shell.component.ts +3 -0
- package/libs/africanies-ui/src/lib/layout/header-weather.spec.ts +62 -94
- package/libs/africanies-ui/src/lib/layout/header-weather.ts +54 -61
- package/libs/africanies-ui/src/lib/layout/page-header.component.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-actions.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-feedback.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-forms.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-info-popover.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-navigation.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-stepper.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-table.module.ts +3 -0
- package/libs/africanies-ui/src/lib/modules/africanies-tooltip.module.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/breadcrumb/breadcrumb.component.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/segment/segment.component.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/shipping-mode-switch/shipping-mode-switch.component.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/side-nav/africanies-side-nav.component.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/tabs/tab-def.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/navigation/tabs/tabs.component.ts +3 -0
- package/libs/africanies-ui/src/lib/notifications/notification-drawer.panel.ts +3 -0
- package/libs/africanies-ui/src/lib/notifications/notification-drawer.service.ts +3 -0
- package/libs/africanies-ui/src/lib/overlay/confirm-dialog.component.ts +3 -0
- package/libs/africanies-ui/src/lib/overlay/confirm.service.ts +3 -0
- package/libs/africanies-ui/src/lib/overlay/drawer.service.ts +3 -0
- package/libs/africanies-ui/src/lib/overlay/modal.service.ts +3 -0
- package/libs/africanies-ui/src/lib/overlay/overlay-frame.component.ts +9 -0
- package/libs/africanies-ui/src/lib/pagination/pagination.component.ts +3 -0
- package/libs/africanies-ui/src/lib/stepper/step-def.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/stepper/stepper.component.ts +3 -0
- package/libs/africanies-ui/src/lib/table/cell-def.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/table/header-cell-def.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/table/row-detail-def.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/table/table.component.ts +3 -0
- package/libs/africanies-ui/src/lib/toast/toast-host.component.ts +4 -1
- package/libs/africanies-ui/src/lib/toast/toast-item.component.ts +3 -0
- package/libs/africanies-ui/src/lib/toast/toast.service.ts +3 -0
- package/libs/africanies-ui/src/lib/tooltip/tooltip-trigger.directive.ts +3 -0
- package/libs/africanies-ui/src/lib/tooltip/tooltip.component.ts +3 -0
- package/package.json +1 -1
|
@@ -37,12 +37,12 @@ export {
|
|
|
37
37
|
PHONE_DIAL_CODES,
|
|
38
38
|
PHONE_MAX_NATIONAL_DIGITS,
|
|
39
39
|
PHONE_MIN_NATIONAL_DIGITS,
|
|
40
|
-
type PhoneCountryOption,
|
|
41
|
-
PhoneInputComponent,
|
|
42
|
-
type PhoneNumberValue,
|
|
43
40
|
phoneCountryName,
|
|
41
|
+
type PhoneCountryOption,
|
|
44
42
|
phoneCountryOptions,
|
|
45
43
|
phoneDigitsOnly,
|
|
44
|
+
PhoneInputComponent,
|
|
45
|
+
type PhoneNumberValue,
|
|
46
46
|
phoneToE164,
|
|
47
47
|
removeDialCode,
|
|
48
48
|
} from './phone-input';
|
|
@@ -148,6 +148,9 @@ function formatWhileTyping(raw: string): {
|
|
|
148
148
|
}
|
|
149
149
|
`,
|
|
150
150
|
})
|
|
151
|
+
/**
|
|
152
|
+
* Numeric field following the shared AFRICANIES form field pattern.
|
|
153
|
+
*/
|
|
151
154
|
export class NumberInputComponent implements ControlValueAccessor {
|
|
152
155
|
protected readonly controlId = `africanies-number-input-${++nextNumberInputId}`;
|
|
153
156
|
protected readonly hintId = `${this.controlId}-hint`;
|
|
@@ -148,6 +148,9 @@ export type OtpInputVariant = 'default' | 'masked';
|
|
|
148
148
|
</div>
|
|
149
149
|
`,
|
|
150
150
|
})
|
|
151
|
+
/**
|
|
152
|
+
* One-time-passcode field — discrete digit cells, single string model.
|
|
153
|
+
*/
|
|
151
154
|
export class OtpInputComponent implements ControlValueAccessor, OnDestroy {
|
|
152
155
|
private readonly destroyRef = inject(DestroyRef);
|
|
153
156
|
private readonly cellInputs =
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CdkConnectedOverlay,
|
|
3
|
+
CdkOverlayOrigin,
|
|
4
|
+
type ConnectedPosition,
|
|
5
|
+
} from '@angular/cdk/overlay';
|
|
1
6
|
import {
|
|
2
7
|
afterNextRender,
|
|
3
8
|
booleanAttribute,
|
|
@@ -15,18 +20,13 @@ import {
|
|
|
15
20
|
untracked,
|
|
16
21
|
viewChild,
|
|
17
22
|
} from '@angular/core';
|
|
18
|
-
import {
|
|
19
|
-
CdkConnectedOverlay,
|
|
20
|
-
CdkOverlayOrigin,
|
|
21
|
-
type ConnectedPosition,
|
|
22
|
-
} from '@angular/cdk/overlay';
|
|
23
23
|
import {
|
|
24
24
|
type ControlValueAccessor,
|
|
25
25
|
NG_VALUE_ACCESSOR,
|
|
26
26
|
} from '@angular/forms';
|
|
27
27
|
|
|
28
|
-
import { AfricaniesIconComponent } from '@africanies/africanies-icons';
|
|
29
28
|
import { countryFlagUrl } from '@africanies/africanies-core';
|
|
29
|
+
import { AfricaniesIconComponent } from '@africanies/africanies-icons';
|
|
30
30
|
|
|
31
31
|
import {
|
|
32
32
|
FORM_DISABLED_CLASS,
|
|
@@ -225,6 +225,9 @@ const PANEL_POSITIONS: ConnectedPosition[] = [
|
|
|
225
225
|
</ng-template>
|
|
226
226
|
`,
|
|
227
227
|
})
|
|
228
|
+
/**
|
|
229
|
+
* International phone field — flag + dial code + national number.
|
|
230
|
+
*/
|
|
228
231
|
export class PhoneInputComponent implements ControlValueAccessor {
|
|
229
232
|
protected readonly controlId = `africanies-phone-input-${++nextPhoneInputId}`;
|
|
230
233
|
protected readonly hintId = `${this.controlId}-hint`;
|
|
@@ -118,6 +118,9 @@ let nextRadioId = 0;
|
|
|
118
118
|
</fieldset>
|
|
119
119
|
`,
|
|
120
120
|
})
|
|
121
|
+
/**
|
|
122
|
+
* Radio group following the shared AFRICANIES form field pattern.
|
|
123
|
+
*/
|
|
121
124
|
export class RadioComponent<T = string> implements ControlValueAccessor {
|
|
122
125
|
private readonly modeColor = inject(ModeColorService);
|
|
123
126
|
|
|
@@ -269,6 +269,9 @@ const PANEL_POSITIONS: ConnectedPosition[] = [
|
|
|
269
269
|
}
|
|
270
270
|
`,
|
|
271
271
|
})
|
|
272
|
+
/**
|
|
273
|
+
* Generic type-as-you-search combobox with a debounced async lookup and overlay result list.
|
|
274
|
+
*/
|
|
272
275
|
export class SearchComboboxComponent<T> implements ControlValueAccessor {
|
|
273
276
|
private readonly destroyRef = inject(DestroyRef);
|
|
274
277
|
|
|
@@ -443,6 +443,9 @@ const SELECT_PANEL_POSITIONS: ConnectedPosition[] = [
|
|
|
443
443
|
}
|
|
444
444
|
`,
|
|
445
445
|
})
|
|
446
|
+
/**
|
|
447
|
+
* Option select following the shared AFRICANIES form field pattern.
|
|
448
|
+
*/
|
|
446
449
|
export class SelectComponent<T = string> implements ControlValueAccessor {
|
|
447
450
|
private readonly modal = inject(ModalService, { optional: true });
|
|
448
451
|
protected readonly modeColor = inject(ModeColorService);
|
|
@@ -115,6 +115,9 @@ export type TextInputType =
|
|
|
115
115
|
}
|
|
116
116
|
`,
|
|
117
117
|
})
|
|
118
|
+
/**
|
|
119
|
+
* Single-line text field — **reference** form control for `@africanies/africanies-ui`.
|
|
120
|
+
*/
|
|
118
121
|
export class TextInputComponent implements ControlValueAccessor {
|
|
119
122
|
/** Stable ids so label / aria-describedby stay paired across re-renders. */
|
|
120
123
|
protected readonly controlId = `africanies-text-input-${++nextTextInputId}`;
|
|
@@ -82,6 +82,9 @@ let nextTextareaId = 0;
|
|
|
82
82
|
}
|
|
83
83
|
`,
|
|
84
84
|
})
|
|
85
|
+
/**
|
|
86
|
+
* Multi-line text field following the shared form-control pattern (`shared AFRICANIES form field pattern`). Supports prefix/suffix slots, field-level `error`, and {@link ControlValueAccessor}.
|
|
87
|
+
*/
|
|
85
88
|
export class TextareaComponent implements ControlValueAccessor {
|
|
86
89
|
protected readonly controlId = `africanies-textarea-${++nextTextareaId}`;
|
|
87
90
|
protected readonly hintId = `${this.controlId}-hint`;
|
|
@@ -105,6 +105,9 @@ let nextToggleId = 0;
|
|
|
105
105
|
</div>
|
|
106
106
|
`,
|
|
107
107
|
})
|
|
108
|
+
/**
|
|
109
|
+
* Boolean switch following the shared AFRICANIES form field pattern.
|
|
110
|
+
*/
|
|
108
111
|
export class ToggleComponent implements ControlValueAccessor {
|
|
109
112
|
private readonly modeColor = inject(ModeColorService);
|
|
110
113
|
|
|
@@ -95,6 +95,9 @@ export type ImageFit = 'cover' | 'contain';
|
|
|
95
95
|
</div>
|
|
96
96
|
`,
|
|
97
97
|
})
|
|
98
|
+
/**
|
|
99
|
+
* Image with a shaped loading frame and fallback while the asset fetches or if it fails to render.
|
|
100
|
+
*/
|
|
98
101
|
export class ImageComponent {
|
|
99
102
|
private readonly imgRef = viewChild<ElementRef<HTMLImageElement>>('img');
|
|
100
103
|
|
|
@@ -205,6 +205,9 @@ const PLACEMENT_POSITIONS: Record<InfoPopoverPlacement, ConnectedPosition[]> = {
|
|
|
205
205
|
</ng-template>
|
|
206
206
|
`,
|
|
207
207
|
})
|
|
208
|
+
/**
|
|
209
|
+
* Hover / focus / click info panel with a white card, optional title, and fully projected body content (any child component or markup).
|
|
210
|
+
*/
|
|
208
211
|
export class InfoPopoverComponent {
|
|
209
212
|
protected readonly panelId = `africanies-info-popover-${++nextInfoPopoverId}`;
|
|
210
213
|
|
|
@@ -71,6 +71,9 @@ import { PageHeaderComponent } from './page-header.component';
|
|
|
71
71
|
}
|
|
72
72
|
`,
|
|
73
73
|
})
|
|
74
|
+
/**
|
|
75
|
+
* Content chrome above the app-shell body: Back, breadcrumbs, then the page title and optional subtitle.
|
|
76
|
+
*/
|
|
74
77
|
export class AppShellContentHeaderComponent {
|
|
75
78
|
private readonly router = inject(Router);
|
|
76
79
|
|
|
@@ -38,6 +38,9 @@ export type AppShellHeaderDensity = 'mobile' | 'tablet' | 'desktop';
|
|
|
38
38
|
selector: '[africaniesAppShellHeaderStart]',
|
|
39
39
|
standalone: true,
|
|
40
40
|
})
|
|
41
|
+
/**
|
|
42
|
+
* Marks projected content as extra leading chrome in {@link AppShellHeaderComponent}.
|
|
43
|
+
*/
|
|
41
44
|
export class AppShellHeaderStartDirective {}
|
|
42
45
|
|
|
43
46
|
/**
|
|
@@ -47,6 +50,9 @@ export class AppShellHeaderStartDirective {}
|
|
|
47
50
|
selector: '[africaniesAppShellHeaderEnd]',
|
|
48
51
|
standalone: true,
|
|
49
52
|
})
|
|
53
|
+
/**
|
|
54
|
+
* Marks projected content as extra trailing chrome in {@link AppShellHeaderComponent}.
|
|
55
|
+
*/
|
|
50
56
|
export class AppShellHeaderEndDirective {}
|
|
51
57
|
|
|
52
58
|
/**
|
|
@@ -206,6 +212,9 @@ export class AppShellHeaderEndDirective {}
|
|
|
206
212
|
</div>
|
|
207
213
|
`,
|
|
208
214
|
})
|
|
215
|
+
/**
|
|
216
|
+
* Product header bar for {@link AppShellComponent}: a short time-of-day kicker plus the given name, local weather, live clock, notification inbox drawer, and avatar menu. Breadcrumbs and Back belong in the content column via {@link AppShellContentHeaderComponent}.
|
|
217
|
+
*/
|
|
209
218
|
export class AppShellHeaderComponent {
|
|
210
219
|
private readonly notificationsDrawer = inject(NotificationDrawerService);
|
|
211
220
|
private readonly destroyRef = inject(DestroyRef);
|
|
@@ -85,6 +85,9 @@ export type AppShellLayoutPreview = 'mobile' | 'tablet' | 'desktop';
|
|
|
85
85
|
},
|
|
86
86
|
templateUrl: './app-shell.component.html',
|
|
87
87
|
})
|
|
88
|
+
/**
|
|
89
|
+
* Application chrome scaffold: side nav + sticky header + constrained content.
|
|
90
|
+
*/
|
|
88
91
|
export class AppShellComponent {
|
|
89
92
|
protected readonly modeColor = inject(ModeColorService);
|
|
90
93
|
protected readonly logoMiniUrl = inject(AFRICANIES_BRAND_LOGO_MINI_URL);
|
|
@@ -66,18 +66,15 @@ describe('loadHeaderWeather', () => {
|
|
|
66
66
|
).resolves.toBeNull();
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('
|
|
69
|
+
it('does not label the device with the IP city', async () => {
|
|
70
70
|
const fetchFn = jest.fn(async (url: string) => {
|
|
71
71
|
if (String(url).includes('geojs')) {
|
|
72
72
|
return jsonResponse({
|
|
73
|
-
latitude: '
|
|
74
|
-
longitude: '
|
|
73
|
+
latitude: '6.45',
|
|
74
|
+
longitude: '3.4',
|
|
75
75
|
city: 'Lagos',
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
if (String(url).includes('bigdatacloud')) {
|
|
79
|
-
return jsonResponse({ city: 'Abuja', locality: 'Abuja' });
|
|
80
|
-
}
|
|
81
78
|
return jsonResponse({
|
|
82
79
|
current: { weather_code: 61, temperature_2m: 27.4 },
|
|
83
80
|
});
|
|
@@ -88,38 +85,18 @@ describe('loadHeaderWeather', () => {
|
|
|
88
85
|
).resolves.toEqual({
|
|
89
86
|
kind: 'rain',
|
|
90
87
|
temperatureC: 27.4,
|
|
91
|
-
city:
|
|
92
|
-
});
|
|
93
|
-
expect(fetchFn).toHaveBeenCalledTimes(3);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('falls back to the IP city when reverse geocode is empty', async () => {
|
|
97
|
-
const fetchFn = jest.fn(async (url: string) => {
|
|
98
|
-
if (String(url).includes('geojs')) {
|
|
99
|
-
return jsonResponse({ latitude: 1, longitude: 2, city: 'Lagos' });
|
|
100
|
-
}
|
|
101
|
-
if (String(url).includes('bigdatacloud')) {
|
|
102
|
-
return jsonResponse({});
|
|
103
|
-
}
|
|
104
|
-
return jsonResponse({ current: { weather_code: 0, temperature_2m: 30 } });
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
await expect(
|
|
108
|
-
loadHeaderWeather(fetchFn as unknown as typeof fetch),
|
|
109
|
-
).resolves.toEqual({
|
|
110
|
-
kind: 'clear',
|
|
111
|
-
temperatureC: 30,
|
|
112
|
-
city: 'Lagos',
|
|
88
|
+
city: undefined,
|
|
113
89
|
});
|
|
90
|
+
expect(fetchFn).not.toHaveBeenCalledWith(
|
|
91
|
+
expect.stringContaining('geocoding-api'),
|
|
92
|
+
);
|
|
114
93
|
});
|
|
115
94
|
|
|
116
|
-
it('reuses the same-hour session cache', async () => {
|
|
95
|
+
it('reuses the same-hour session cache when the device city was resolved', async () => {
|
|
96
|
+
stubDeviceAt(9.0765, 7.3986);
|
|
117
97
|
const fetchFn = jest.fn(async (url: string) => {
|
|
118
|
-
if (String(url).includes('
|
|
119
|
-
return jsonResponse({
|
|
120
|
-
}
|
|
121
|
-
if (String(url).includes('bigdatacloud')) {
|
|
122
|
-
return jsonResponse({ city: 'Accra' });
|
|
98
|
+
if (String(url).includes('geocoding-api')) {
|
|
99
|
+
return jsonResponse({ results: [{ name: 'Abuja' }] });
|
|
123
100
|
}
|
|
124
101
|
return jsonResponse({ current: { weather_code: 0, temperature_2m: 30 } });
|
|
125
102
|
});
|
|
@@ -127,17 +104,16 @@ describe('loadHeaderWeather', () => {
|
|
|
127
104
|
const first = await loadHeaderWeather(fetchFn as unknown as typeof fetch);
|
|
128
105
|
const second = await loadHeaderWeather(fetchFn as unknown as typeof fetch);
|
|
129
106
|
|
|
130
|
-
expect(first).toEqual(
|
|
131
|
-
expect(
|
|
107
|
+
expect(first).toEqual({ kind: 'clear', temperatureC: 30, city: 'Abuja' });
|
|
108
|
+
expect(second).toEqual(first);
|
|
109
|
+
expect(fetchFn).toHaveBeenCalledTimes(2);
|
|
132
110
|
});
|
|
133
111
|
|
|
134
112
|
it('fetches again when the cached hour no longer matches', async () => {
|
|
113
|
+
stubDeviceAt(9.0765, 7.3986);
|
|
135
114
|
const fetchFn = jest.fn(async (url: string) => {
|
|
136
|
-
if (String(url).includes('
|
|
137
|
-
return jsonResponse({
|
|
138
|
-
}
|
|
139
|
-
if (String(url).includes('bigdatacloud')) {
|
|
140
|
-
return jsonResponse({ city: 'Lagos' });
|
|
115
|
+
if (String(url).includes('geocoding-api')) {
|
|
116
|
+
return jsonResponse({ results: [{ name: 'Abuja' }] });
|
|
141
117
|
}
|
|
142
118
|
return jsonResponse({ current: { weather_code: 0, temperature_2m: 30.2 } });
|
|
143
119
|
});
|
|
@@ -146,7 +122,7 @@ describe('loadHeaderWeather', () => {
|
|
|
146
122
|
const cacheKey = Object.keys(sessionStorage).find((key) =>
|
|
147
123
|
key.startsWith('africanies-header-weather'),
|
|
148
124
|
);
|
|
149
|
-
expect(cacheKey).
|
|
125
|
+
expect(cacheKey).toBe('africanies-header-weather-v8');
|
|
150
126
|
const stored = JSON.parse(sessionStorage.getItem(cacheKey!) ?? '{}') as {
|
|
151
127
|
hour?: string;
|
|
152
128
|
};
|
|
@@ -154,35 +130,15 @@ describe('loadHeaderWeather', () => {
|
|
|
154
130
|
sessionStorage.setItem(cacheKey!, JSON.stringify(stored));
|
|
155
131
|
|
|
156
132
|
await loadHeaderWeather(fetchFn as unknown as typeof fetch);
|
|
157
|
-
expect(fetchFn).toHaveBeenCalledTimes(
|
|
133
|
+
expect(fetchFn).toHaveBeenCalledTimes(4);
|
|
158
134
|
});
|
|
159
135
|
|
|
160
|
-
it('uses
|
|
161
|
-
|
|
162
|
-
configurable: true,
|
|
163
|
-
value: {
|
|
164
|
-
getCurrentPosition: (success: PositionCallback) => {
|
|
165
|
-
success({
|
|
166
|
-
coords: {
|
|
167
|
-
latitude: 9.0765,
|
|
168
|
-
longitude: 7.3986,
|
|
169
|
-
accuracy: 10,
|
|
170
|
-
altitude: null,
|
|
171
|
-
altitudeAccuracy: null,
|
|
172
|
-
heading: null,
|
|
173
|
-
speed: null,
|
|
174
|
-
toJSON: () => ({}),
|
|
175
|
-
},
|
|
176
|
-
timestamp: Date.now(),
|
|
177
|
-
toJSON: () => ({}),
|
|
178
|
-
} as GeolocationPosition);
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
});
|
|
136
|
+
it('uses device coordinates and ignores the IP city', async () => {
|
|
137
|
+
stubDeviceAt(9.0765, 7.3986);
|
|
182
138
|
|
|
183
139
|
const fetchFn = jest.fn(async (url: string) => {
|
|
184
|
-
if (String(url).includes('
|
|
185
|
-
return jsonResponse({
|
|
140
|
+
if (String(url).includes('geocoding-api')) {
|
|
141
|
+
return jsonResponse({ results: [{ name: 'Abuja' }] });
|
|
186
142
|
}
|
|
187
143
|
if (String(url).includes('geojs')) {
|
|
188
144
|
return jsonResponse({
|
|
@@ -201,34 +157,15 @@ describe('loadHeaderWeather', () => {
|
|
|
201
157
|
temperatureC: 31,
|
|
202
158
|
city: 'Abuja',
|
|
203
159
|
});
|
|
160
|
+
expect(fetchFn).not.toHaveBeenCalledWith(expect.stringContaining('geojs'));
|
|
204
161
|
});
|
|
205
162
|
|
|
206
|
-
it('
|
|
207
|
-
|
|
208
|
-
configurable: true,
|
|
209
|
-
value: {
|
|
210
|
-
getCurrentPosition: (success: PositionCallback) => {
|
|
211
|
-
success({
|
|
212
|
-
coords: {
|
|
213
|
-
latitude: 9.0765,
|
|
214
|
-
longitude: 7.3986,
|
|
215
|
-
accuracy: 10,
|
|
216
|
-
altitude: null,
|
|
217
|
-
altitudeAccuracy: null,
|
|
218
|
-
heading: null,
|
|
219
|
-
speed: null,
|
|
220
|
-
toJSON: () => ({}),
|
|
221
|
-
},
|
|
222
|
-
timestamp: Date.now(),
|
|
223
|
-
toJSON: () => ({}),
|
|
224
|
-
} as GeolocationPosition);
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
});
|
|
163
|
+
it('omits the city when the device fix has no place name', async () => {
|
|
164
|
+
stubDeviceAt(9.0765, 7.3986);
|
|
228
165
|
|
|
229
166
|
const fetchFn = jest.fn(async (url: string) => {
|
|
230
|
-
if (String(url).includes('
|
|
231
|
-
return jsonResponse({
|
|
167
|
+
if (String(url).includes('geocoding-api')) {
|
|
168
|
+
return jsonResponse({ results: [{ name: '' }] });
|
|
232
169
|
}
|
|
233
170
|
if (String(url).includes('geojs')) {
|
|
234
171
|
return jsonResponse({
|
|
@@ -245,13 +182,14 @@ describe('loadHeaderWeather', () => {
|
|
|
245
182
|
).resolves.toEqual({
|
|
246
183
|
kind: 'clear',
|
|
247
184
|
temperatureC: 31,
|
|
248
|
-
city:
|
|
185
|
+
city: undefined,
|
|
249
186
|
});
|
|
187
|
+
expect(fetchFn).not.toHaveBeenCalledWith(expect.stringContaining('geojs'));
|
|
250
188
|
});
|
|
251
189
|
|
|
252
190
|
it('refetches when the hour cache has weather but no city', async () => {
|
|
253
191
|
sessionStorage.setItem(
|
|
254
|
-
'africanies-header-weather-
|
|
192
|
+
'africanies-header-weather-v8',
|
|
255
193
|
JSON.stringify({
|
|
256
194
|
hour: `${new Date().getFullYear()}-${new Date().getMonth()}-${new Date().getDate()}-${new Date().getHours()}`,
|
|
257
195
|
kind: 'cloudy',
|
|
@@ -274,7 +212,7 @@ describe('loadHeaderWeather', () => {
|
|
|
274
212
|
).resolves.toEqual({
|
|
275
213
|
kind: 'cloudy',
|
|
276
214
|
temperatureC: 25,
|
|
277
|
-
city:
|
|
215
|
+
city: undefined,
|
|
278
216
|
});
|
|
279
217
|
expect(fetchFn).toHaveBeenCalled();
|
|
280
218
|
});
|
|
@@ -304,6 +242,36 @@ describe('headerWeatherIcon', () => {
|
|
|
304
242
|
});
|
|
305
243
|
});
|
|
306
244
|
|
|
245
|
+
function stubDeviceAt(latitude: number, longitude: number): void {
|
|
246
|
+
Object.defineProperty(navigator, 'permissions', {
|
|
247
|
+
configurable: true,
|
|
248
|
+
value: {
|
|
249
|
+
query: async () => ({ state: 'granted' }),
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
Object.defineProperty(navigator, 'geolocation', {
|
|
253
|
+
configurable: true,
|
|
254
|
+
value: {
|
|
255
|
+
getCurrentPosition: (success: PositionCallback) => {
|
|
256
|
+
success({
|
|
257
|
+
coords: {
|
|
258
|
+
latitude,
|
|
259
|
+
longitude,
|
|
260
|
+
accuracy: 10,
|
|
261
|
+
altitude: null,
|
|
262
|
+
altitudeAccuracy: null,
|
|
263
|
+
heading: null,
|
|
264
|
+
speed: null,
|
|
265
|
+
toJSON: () => ({}),
|
|
266
|
+
},
|
|
267
|
+
timestamp: Date.now(),
|
|
268
|
+
toJSON: () => ({}),
|
|
269
|
+
} as GeolocationPosition);
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
307
275
|
function jsonResponse(body: unknown): Pick<Response, 'ok' | 'json'> {
|
|
308
276
|
return {
|
|
309
277
|
ok: true,
|