tas-uell-sdk 0.1.3 → 0.3.0

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 (29) hide show
  1. package/README.md +3 -0
  2. package/esm2020/lib/components/tas-btn/tas-btn.component.mjs +17 -15
  3. package/esm2020/lib/components/tas-feedback-modal/tas-feedback-modal.component.mjs +229 -0
  4. package/esm2020/lib/components/tas-floating-call/tas-floating-call.component.mjs +38 -3
  5. package/esm2020/lib/components/tas-incoming-appointment/tas-incoming-appointment.component.mjs +46 -8
  6. package/esm2020/lib/components/tas-videocall/tas-videocall.component.mjs +163 -43
  7. package/esm2020/lib/components/tas-waiting-room/tas-waiting-room.component.mjs +150 -34
  8. package/esm2020/lib/icons/tas-icons.mjs +17 -0
  9. package/esm2020/lib/interfaces/tas.interfaces.mjs +13 -1
  10. package/esm2020/lib/services/tas.service.mjs +127 -26
  11. package/esm2020/lib/tas-uell-sdk.module.mjs +8 -3
  12. package/esm2020/public-api.mjs +2 -1
  13. package/fesm2015/tas-uell-sdk.mjs +794 -124
  14. package/fesm2015/tas-uell-sdk.mjs.map +1 -1
  15. package/fesm2020/tas-uell-sdk.mjs +787 -123
  16. package/fesm2020/tas-uell-sdk.mjs.map +1 -1
  17. package/lib/components/tas-btn/tas-btn.component.d.ts +1 -0
  18. package/lib/components/tas-feedback-modal/tas-feedback-modal.component.d.ts +101 -0
  19. package/lib/components/tas-floating-call/tas-floating-call.component.d.ts +5 -0
  20. package/lib/components/tas-incoming-appointment/tas-incoming-appointment.component.d.ts +12 -1
  21. package/lib/components/tas-videocall/tas-videocall.component.d.ts +49 -6
  22. package/lib/components/tas-waiting-room/tas-waiting-room.component.d.ts +40 -12
  23. package/lib/icons/tas-icons.d.ts +8 -0
  24. package/lib/interfaces/tas.interfaces.d.ts +36 -3
  25. package/lib/services/tas.service.d.ts +27 -2
  26. package/lib/tas-uell-sdk.module.d.ts +5 -4
  27. package/package.json +1 -1
  28. package/public-api.d.ts +1 -0
  29. package/src/lib/styles/tas-global.scss +17 -0
@@ -47,6 +47,7 @@ export declare class TasButtonComponent implements OnInit, OnDestroy {
47
47
  * Check status endpoint to determine if button should be enabled
48
48
  */
49
49
  private checkStatus;
50
+ private handleStatusError;
50
51
  onClick(): void;
51
52
  private openWaitingRoomModal;
52
53
  private openVideoCallModal;
@@ -0,0 +1,101 @@
1
+ import { OnInit, OnDestroy } from '@angular/core';
2
+ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
3
+ import { TasService } from '../../services/tas.service';
4
+ import { TasBusinessRole, FeedbackMotive } from '../../interfaces/tas.interfaces';
5
+ import * as i0 from "@angular/core";
6
+ export declare class TasFeedbackModalComponent implements OnInit, OnDestroy {
7
+ activeModal: NgbActiveModal;
8
+ private tasService;
9
+ videoCallId: number;
10
+ tenant: string;
11
+ businessRole: TasBusinessRole;
12
+ motives: FeedbackMotive[];
13
+ filteredMotives: FeedbackMotive[];
14
+ selectedMotive: FeedbackMotive | null;
15
+ rating: number;
16
+ hoverRating: number;
17
+ observation: string;
18
+ isSubmitting: boolean;
19
+ showToast: boolean;
20
+ isDropdownOpen: boolean;
21
+ private subscriptions;
22
+ private toastTimeout;
23
+ constructor(activeModal: NgbActiveModal, tasService: TasService);
24
+ ngOnInit(): void;
25
+ ngOnDestroy(): void;
26
+ /**
27
+ * Check if current user can see all motives (BUSINESS + TECHNICAL)
28
+ * Only BACKOFFICE, ADMIN_MANAGER, MANAGER roles see BUSINESS motives
29
+ */
30
+ get canSeeBusinessMotives(): boolean;
31
+ /**
32
+ * Observation is required when "Otro problema tecnico" is selected
33
+ */
34
+ get isObservationRequired(): boolean;
35
+ /**
36
+ * Can submit if rating > 0 OR motive is selected
37
+ * If observation is required, it must not be empty
38
+ */
39
+ get canSubmit(): boolean;
40
+ /**
41
+ * Progress percentage for the divider line
42
+ * 0 = nothing selected, 50 = one selected, 100 = both selected
43
+ */
44
+ get feedbackProgress(): number;
45
+ /**
46
+ * Set star rating
47
+ */
48
+ setRating(value: number): void;
49
+ /**
50
+ * Set hover preview rating
51
+ */
52
+ setHoverRating(value: number): void;
53
+ /**
54
+ * Clear hover preview
55
+ */
56
+ clearHoverRating(): void;
57
+ /**
58
+ * Get the display rating (hover preview or actual)
59
+ */
60
+ getDisplayRating(): number;
61
+ /**
62
+ * Toggle dropdown open/close
63
+ */
64
+ toggleDropdown(): void;
65
+ /**
66
+ * Close dropdown
67
+ */
68
+ closeDropdown(): void;
69
+ /**
70
+ * Select a motive from dropdown
71
+ */
72
+ selectMotive(motive: FeedbackMotive): void;
73
+ /**
74
+ * Clear selected motive
75
+ */
76
+ clearMotive(): void;
77
+ /**
78
+ * Submit feedback
79
+ */
80
+ submit(): void;
81
+ /**
82
+ * Close modal without saving
83
+ */
84
+ dismiss(): void;
85
+ /**
86
+ * Load motives from API
87
+ */
88
+ private loadMotives;
89
+ /**
90
+ * Filter motives based on user role
91
+ * USERs see only TECHNICAL motives
92
+ * Owners (BACKOFFICE, ADMIN_MANAGER, MANAGER) see all motives
93
+ */
94
+ private filterMotives;
95
+ /**
96
+ * Show toast notification and auto-dismiss after 3s
97
+ */
98
+ private showToastNotification;
99
+ static ɵfac: i0.ɵɵFactoryDeclaration<TasFeedbackModalComponent, never>;
100
+ static ɵcmp: i0.ɵɵComponentDeclaration<TasFeedbackModalComponent, "tas-feedback-modal", never, { "videoCallId": "videoCallId"; "tenant": "tenant"; "businessRole": "businessRole"; }, {}, never, never>;
101
+ }
@@ -9,12 +9,17 @@ export declare class TasFloatingCallComponent implements OnInit, OnDestroy {
9
9
  isMuted: boolean;
10
10
  private subscriptions;
11
11
  private videoCallModalRef;
12
+ private feedbackShown;
12
13
  constructor(tasService: TasService, modalService: NgbModal);
13
14
  ngOnInit(): void;
14
15
  ngOnDestroy(): void;
15
16
  onExpand(): void;
16
17
  onHangUp(): void;
17
18
  toggleMute(): void;
19
+ /**
20
+ * Open feedback modal when call ends from PiP mode
21
+ */
22
+ private openFeedbackModal;
18
23
  private setupSubscriptions;
19
24
  private openVideoCallModal;
20
25
  private readonly PIP_MARGIN;
@@ -15,16 +15,27 @@ export declare class TasIncomingAppointmentComponent implements OnInit, OnDestro
15
15
  appointments: TasAppointment[];
16
16
  isLoading: boolean;
17
17
  hasError: boolean;
18
+ activeAppointmentId: number | null;
18
19
  private subscriptions;
19
20
  constructor(tasService: TasService);
20
21
  ngOnInit(): void;
21
22
  ngOnDestroy(): void;
22
23
  private loadAppointments;
24
+ /**
25
+ * Check status endpoint to get the active appointmentId
26
+ */
27
+ private checkStatus;
23
28
  onEnterCall(appointment: TasAppointment): void;
24
29
  /**
25
- * Check if tas-btn should be shown for an appointment (CONFIRMED or ACTIVE status)
30
+ * Check if tas-btn should be shown for an appointment.
31
+ * Only shows when appointment.id matches the activeAppointmentId from status API.
32
+ * tas-btn handles its own polling for joinable state.
26
33
  */
27
34
  shouldShowTasBtn(appointment: TasAppointment): boolean;
35
+ /**
36
+ * TrackBy function for ngFor
37
+ */
38
+ trackByAppointmentId(index: number, appointment: TasAppointment): number;
28
39
  /**
29
40
  * Format date to Spanish format: "Lunes 8 de diciembre"
30
41
  */
@@ -1,13 +1,24 @@
1
1
  import { OnInit, OnDestroy, ElementRef, AfterViewInit } from '@angular/core';
2
- import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
2
+ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
3
+ import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
3
4
  import { TasService } from '../../services/tas.service';
4
5
  import { GeolocationService } from '../../services/geolocation.service';
5
- import { CallState, TasBusinessRole, WaitingRoomUser } from '../../interfaces/tas.interfaces';
6
+ import { CallState, TasBusinessRole, WaitingRoomUser, UserGeoInfo } from '../../interfaces/tas.interfaces';
6
7
  import * as i0 from "@angular/core";
8
+ /** User geolocation panel view states */
9
+ export declare enum UserGeoViewState {
10
+ HIDDEN = "HIDDEN",
11
+ INITIAL = "INITIAL",
12
+ VERIFYING = "VERIFYING",
13
+ VERIFIED = "VERIFIED",
14
+ DENIED = "DENIED"
15
+ }
7
16
  export declare class TasVideocallComponent implements OnInit, OnDestroy, AfterViewInit {
8
17
  activeModal: NgbActiveModal;
9
18
  private tasService;
10
19
  private geolocationService;
20
+ private sanitizer;
21
+ private modalService;
11
22
  sessionId: string;
12
23
  token: string;
13
24
  appointmentId?: number;
@@ -31,12 +42,23 @@ export declare class TasVideocallComponent implements OnInit, OnDestroy, AfterVi
31
42
  geoLocationStatus: 'unknown' | 'active' | 'denied';
32
43
  geoRequestActive: boolean;
33
44
  allGeoGranted: boolean;
45
+ userGeoInfo: UserGeoInfo[];
46
+ userGeoViewState: UserGeoViewState;
47
+ UserGeoViewState: typeof UserGeoViewState;
48
+ homeIcon: SafeHtml;
49
+ devModeEnabled: boolean;
50
+ private geoPanelDismissed;
51
+ private feedbackShown;
34
52
  private subscriptions;
35
- constructor(activeModal: NgbActiveModal, tasService: TasService, geolocationService: GeolocationService);
53
+ constructor(activeModal: NgbActiveModal, tasService: TasService, geolocationService: GeolocationService, sanitizer: DomSanitizer, modalService: NgbModal);
36
54
  ngOnInit(): void;
37
55
  ngAfterViewInit(): void;
38
56
  ngOnDestroy(): void;
39
57
  hangUp(): void;
58
+ /**
59
+ * Open feedback modal when call ends
60
+ */
61
+ private openFeedbackModal;
40
62
  toggleMute(): void;
41
63
  minimize(): void;
42
64
  toggleSwap(): void;
@@ -45,6 +67,20 @@ export declare class TasVideocallComponent implements OnInit, OnDestroy, AfterVi
45
67
  * Check if current user can admit others (OWNER, BACKOFFICE, or MODERATOR)
46
68
  */
47
69
  get canAdmitUsers(): boolean;
70
+ /** Users with pending geo status */
71
+ get pendingUsers(): UserGeoInfo[];
72
+ /** Users who granted geo */
73
+ get grantedUsers(): UserGeoInfo[];
74
+ /** Users who denied geo */
75
+ get deniedUsers(): UserGeoInfo[];
76
+ /** Show location panel only if owner and there are users who haven't granted */
77
+ get shouldShowLocationPanel(): boolean;
78
+ /** Check if any user has denied geo */
79
+ get hasAnyDenied(): boolean;
80
+ /** Show user geo panel for owners when not hidden */
81
+ get shouldShowUserGeoPanel(): boolean;
82
+ /** Set user geo view state (for dev controls or close button) */
83
+ setUserGeoViewState(state: UserGeoViewState): void;
48
84
  /**
49
85
  * Admit a user from the waiting room
50
86
  */
@@ -58,19 +94,26 @@ export declare class TasVideocallComponent implements OnInit, OnDestroy, AfterVi
58
94
  */
59
95
  closeLocationPanel(): void;
60
96
  /**
61
- * Request the user to share their location
97
+ * Request the user to share their location (called by owner)
62
98
  */
63
99
  requestUserLocation(): void;
64
100
  private setupSubscriptions;
65
101
  /**
66
102
  * Handle activateGeo request from backend (for non-owner users).
67
- * If geo is already active, report it. If not, prompt user.
103
+ * Directly prompts browser for geolocation - no panel for users.
68
104
  */
69
105
  private handleActivateGeo;
106
+ /** Start geolocation verification (called from template button) */
107
+ startGeoVerification(): Promise<void>;
70
108
  /**
71
- * Report geolocation status to backend.
109
+ * Report granted geolocation to backend.
110
+ * IMPORTANT: Only call with valid coordinates.
72
111
  */
73
112
  private reportGeoStatus;
113
+ /**
114
+ * Report denied geolocation to backend.
115
+ */
116
+ private denyGeoLocation;
74
117
  private initializeCall;
75
118
  private resetVideoPositions;
76
119
  private initInteract;
@@ -26,6 +26,7 @@ export declare class TasWaitingRoomComponent implements OnInit, OnDestroy {
26
26
  state: WaitingRoomState;
27
27
  WaitingRoomState: typeof WaitingRoomState;
28
28
  errorMessage: string;
29
+ showErrorDetails: boolean;
29
30
  isJoinable: boolean;
30
31
  private resolvedSessionId;
31
32
  private resolvedAppointmentId;
@@ -34,39 +35,61 @@ export declare class TasWaitingRoomComponent implements OnInit, OnDestroy {
34
35
  private subscriptions;
35
36
  private videoCallModalRef;
36
37
  private geoPosition;
38
+ private geoWasDenied;
39
+ private geoResultSent;
40
+ private mediaPermissionsGranted;
41
+ private geoPermissionsResolved;
42
+ private retryCount;
43
+ private readonly MAX_RETRIES;
37
44
  /** Whether current user is an owner */
38
45
  get isOwner(): boolean;
46
+ /** Whether we're still requesting permissions (for template) */
47
+ get isRequestingPermissions(): boolean;
48
+ /** Whether we're waiting for admission after permissions granted (for template) */
49
+ get isWaitingForAdmission(): boolean;
39
50
  constructor(activeModal: NgbActiveModal, tasService: TasService, geolocationService: GeolocationService, modalService: NgbModal, cdr: ChangeDetectorRef);
40
51
  ngOnInit(): void;
41
52
  /**
42
53
  * Request camera and microphone permissions.
54
+ * Triggers auto-join when permissions are resolved.
43
55
  */
44
56
  private requestMediaPermissions;
45
57
  /**
46
- * Request geolocation immediately on init.
58
+ * Request geolocation permission and cache result.
47
59
  * Only for regular users (not owners/backoffice).
48
- * If user allows, store position and send to backend.
60
+ * Actual send to backend happens after we have videoCallId.
61
+ * Triggers auto-join when geolocation is resolved.
49
62
  */
50
63
  private requestGeolocation;
51
64
  /**
52
- * Send geolocation to backend via modify user endpoint.
53
- * NOTE: Endpoint call is prepared but may not be active yet.
65
+ * Send geo result to backend (granted or denied).
66
+ * Only sends if videoCallId is available and not already sent.
67
+ */
68
+ private sendGeoResultToBackend;
69
+ /**
70
+ * Send granted geolocation to backend via modify user endpoint.
54
71
  */
55
72
  private sendGeolocationToBackend;
73
+ /**
74
+ * Send geolocation denial to backend via modify user endpoint.
75
+ */
76
+ private sendGeoDenialToBackend;
56
77
  ngOnDestroy(): void;
57
78
  /**
58
79
  * Check status to get session info
59
80
  */
60
81
  private checkStatus;
61
82
  /**
62
- * Handle changes to joinable status
83
+ * Handle changes to joinable status.
84
+ * Triggers auto-join when joinable becomes true.
63
85
  */
64
86
  private handleJoinableChange;
65
87
  /**
66
- * Called when user clicks the join button.
67
- * Calls /start to get token then auto-joins.
88
+ * Attempt to auto-join the session when all conditions are met.
89
+ * - For owners: just need joinable + sessionId
90
+ * - For users: need media permissions + geo resolved + joinable + sessionId
68
91
  */
69
- joinSession(): void;
92
+ private tryAutoJoin;
70
93
  /**
71
94
  * Check if user has owner/backoffice role
72
95
  */
@@ -76,13 +99,18 @@ export declare class TasWaitingRoomComponent implements OnInit, OnDestroy {
76
99
  */
77
100
  private startSessionAndJoin;
78
101
  /**
79
- * Closes the waiting room
102
+ * Retry after an error.
103
+ * Resets retry count and restarts the flow.
80
104
  */
81
- cancel(): void;
105
+ retry(): void;
82
106
  /**
83
- * Retry after an error
107
+ * Toggle the error details dropdown visibility.
84
108
  */
85
- retry(): void;
109
+ toggleErrorDetails(): void;
110
+ /**
111
+ * Close the waiting room modal.
112
+ */
113
+ close(): void;
86
114
  private openVideoCallModal;
87
115
  static ɵfac: i0.ɵɵFactoryDeclaration<TasWaitingRoomComponent, never>;
88
116
  static ɵcmp: i0.ɵɵComponentDeclaration<TasWaitingRoomComponent, "tas-waiting-room", never, { "roomType": "roomType"; "entityId": "entityId"; "tenant": "tenant"; "businessRole": "businessRole"; "currentUser": "currentUser"; }, {}, never, never>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SVG icons used internally by TAS SDK components.
3
+ * Icons are stored as strings to avoid asset bundling complexity.
4
+ */
5
+ export declare const TAS_ICONS: {
6
+ readonly home: "<svg width=\"120\" height=\"100\" viewBox=\"0 0 120 100\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect x=\"10\" width=\"100\" height=\"100\" rx=\"50\" fill=\"#44D8E8\" fill-opacity=\"0.2\"/>\n<path d=\"M45 70C43.625 70 42.4479 69.5104 41.4688 68.5313C40.4896 67.5521 40 66.375 40 65V46.5625L37.5 48.5C36.9583 48.9167 36.3438 49.0833 35.6562 49C34.9688 48.9167 34.4167 48.5833 34 48C33.5833 47.4583 33.4271 46.8542 33.5312 46.1875C33.6354 45.5208 33.9583 44.9792 34.5 44.5625L56.9375 27.3125C57.3958 26.9792 57.8854 26.7292 58.4062 26.5625C58.9271 26.3958 59.4583 26.3125 60 26.3125C60.5417 26.3125 61.0729 26.3958 61.5938 26.5625C62.1146 26.7292 62.6042 26.9792 63.0625 27.3125L85.5 44.5C86.0417 44.9167 86.3646 45.4583 86.4688 46.125C86.5729 46.7917 86.4167 47.4167 86 48C85.5833 48.5833 85.0417 48.9063 84.375 48.9688C83.7083 49.0313 83.0833 48.8542 82.5 48.4375L60 31.25L45 42.75V65H50.0625C50.7708 65 51.3542 65.2396 51.8125 65.7188C52.2708 66.1979 52.5 66.7917 52.5 67.5C52.5 68.2083 52.2604 68.8021 51.7812 69.2813C51.3021 69.7604 50.7083 70 50 70H45ZM67.3125 73.9375C66.9792 73.9375 66.6667 73.875 66.375 73.75C66.0833 73.625 65.8125 73.4375 65.5625 73.1875L58.5 66.125C58 65.625 57.75 65.0417 57.75 64.375C57.75 63.7083 58 63.125 58.5 62.625C59 62.125 59.5833 61.875 60.25 61.875C60.9167 61.875 61.5 62.125 62 62.625L67.3125 67.875L79.6875 55.5C80.1875 55 80.7812 54.7604 81.4688 54.7813C82.1562 54.8021 82.75 55.0625 83.25 55.5625C83.75 56.0625 84 56.6458 84 57.3125C84 57.9792 83.75 58.5625 83.25 59.0625L69.0625 73.1875C68.8125 73.4375 68.5417 73.625 68.25 73.75C67.9583 73.875 67.6458 73.9375 67.3125 73.9375Z\" fill=\"white\"/>\n<path d=\"M110 5L106.575 3.425L105 0L103.425 3.425L100 5L103.425 6.575L105 10L106.575 6.575L110 5Z\" fill=\"#44D8E8\"/>\n<path d=\"M10 51L6.575 49.425L5 46L3.425 49.425L0 51L3.425 52.575L5 56L6.575 52.575L10 51Z\" fill=\"#44D8E8\"/>\n<path d=\"M95 43.5L93.2875 42.7125L92.5 41L91.7125 42.7125L90 43.5L91.7125 44.2875L92.5 46L93.2875 44.2875L95 43.5Z\" fill=\"#44D8E8\"/>\n<path d=\"M42 4.5L40.2875 3.7125L39.5 2L38.7125 3.7125L37 4.5L38.7125 5.2875L39.5 7L40.2875 5.2875L42 4.5Z\" fill=\"#44D8E8\"/>\n<path d=\"M88 83.5L86.2875 82.7125L85.5 81L84.7125 82.7125L83 83.5L84.7125 84.2875L85.5 86L86.2875 84.2875L88 83.5Z\" fill=\"#44D8E8\"/>\n<path d=\"M120 97.5L118.287 96.7125L117.5 95L116.713 96.7125L115 97.5L116.713 98.2875L117.5 100L118.287 98.2875L120 97.5Z\" fill=\"#44D8E8\"/>\n</svg>";
7
+ };
8
+ export declare type TasIconName = keyof typeof TAS_ICONS;
@@ -36,7 +36,13 @@ export declare enum UserCallAction {
36
36
  BAN = "BAN",
37
37
  CHANGE_STATUS = "CHANGE_STATUS",
38
38
  REQUEST_GEOLOCALIZATION = "REQUEST_GEOLOCALIZATION",
39
- ACTIVATE_GEOLOCATION = "ACTIVATE_GEOLOCATION"
39
+ ACTIVATE_GEOLOCATION = "ACTIVATE_GEOLOCATION",
40
+ DENY_GEOLOCATION = "DENY_GEOLOCATION"
41
+ }
42
+ export declare enum GeoStatus {
43
+ PENDING = "PENDING",
44
+ GRANTED = "GRANTED",
45
+ DENIED = "DENIED"
40
46
  }
41
47
  export declare enum RoomUserStatus {
42
48
  ASSIGNED = "ASSIGNED",
@@ -55,6 +61,10 @@ export declare enum ViewMode {
55
61
  FULLSCREEN = "FULLSCREEN",
56
62
  PIP = "PIP"
57
63
  }
64
+ export declare enum FeedbackMotiveType {
65
+ TECHNICAL = "TECHNICAL",
66
+ BUSINESS = "BUSINESS"
67
+ }
58
68
  export interface TasCurrentUser {
59
69
  id: number;
60
70
  name: string;
@@ -99,6 +109,9 @@ export interface ProxyVideoStatusUser {
99
109
  userId: number;
100
110
  rol: TasUserRole;
101
111
  status: UserStatus;
112
+ geoStatus: GeoStatus;
113
+ latitude: number | null;
114
+ longitude: number | null;
102
115
  }
103
116
  export interface ProxyVideoStatusResponse {
104
117
  content: {
@@ -109,8 +122,8 @@ export interface ProxyVideoStatusResponse {
109
122
  waitingRoomAvailable: boolean;
110
123
  appointmentId: number;
111
124
  activateGeo: boolean;
112
- geoRequestActive?: boolean;
113
- allGeoGranted?: boolean;
125
+ geoRequestActive: boolean | null;
126
+ allGeoGranted: boolean;
114
127
  users: ProxyVideoStatusUser[];
115
128
  };
116
129
  }
@@ -137,6 +150,13 @@ export interface WaitingRoomUser {
137
150
  name: string;
138
151
  status: RoomUserStatus;
139
152
  }
153
+ /** User geolocation info for owner panel */
154
+ export interface UserGeoInfo {
155
+ userId: number;
156
+ geoStatus: GeoStatus;
157
+ latitude: number | null;
158
+ longitude: number | null;
159
+ }
140
160
  export declare enum AppointmentStatus {
141
161
  CONFIRMED = "CONFIRMED",
142
162
  CANCELLED = "CANCELLED",
@@ -166,3 +186,16 @@ export interface GetAppointmentsRequest {
166
186
  toDate: string;
167
187
  entityId?: number;
168
188
  }
189
+ export interface SaveFeedbackRequest {
190
+ videoCallId: number;
191
+ motiveId: number;
192
+ motiveType?: FeedbackMotiveType;
193
+ observation: string;
194
+ rating: number;
195
+ tenant: string;
196
+ }
197
+ export interface FeedbackMotive {
198
+ id: number;
199
+ description: string;
200
+ motiveType: FeedbackMotiveType;
201
+ }
@@ -1,10 +1,10 @@
1
1
  import { TasUtilityService } from './tas-utility.service';
2
2
  import { Observable } from 'rxjs';
3
3
  import * as OT from '@opentok/client';
4
- import { GenerateTokenResponse, StartSessionRequest, FinishSessionResponse, ProxyVideoStatusRequest, ProxyVideoStatusResponse, ProxyVideoFinishRequest, ProxyVideoUserModifyRequest, UserCallAction, RoomUserStatus, TasBusinessRole, CallState, ViewMode, WaitingRoomUser, TasAppointment, GetAppointmentsRequest } from '../interfaces/tas.interfaces';
4
+ import { GenerateTokenResponse, StartSessionRequest, FinishSessionResponse, ProxyVideoStatusRequest, ProxyVideoStatusResponse, ProxyVideoFinishRequest, ProxyVideoUserModifyRequest, UserCallAction, RoomUserStatus, GeoStatus, TasBusinessRole, CallState, ViewMode, WaitingRoomUser, UserGeoInfo, TasAppointment, GetAppointmentsRequest, SaveFeedbackRequest, FeedbackMotive } from '../interfaces/tas.interfaces';
5
5
  import { TasConfig, TasHttpClient } from '../config/tas.config';
6
6
  import * as i0 from "@angular/core";
7
- export { CallState, ViewMode, TasBusinessRole, UserCallAction, RoomUserStatus };
7
+ export { CallState, ViewMode, TasBusinessRole, UserCallAction, RoomUserStatus, GeoStatus };
8
8
  export declare class TasService {
9
9
  private httpClient;
10
10
  private config;
@@ -40,12 +40,16 @@ export declare class TasService {
40
40
  geoRequestActive$: Observable<boolean>;
41
41
  private allGeoGrantedSubject;
42
42
  allGeoGranted$: Observable<boolean>;
43
+ private userGeoInfoSubject;
44
+ userGeoInfo$: Observable<UserGeoInfo[]>;
43
45
  private statusPollingInterval;
44
46
  private readonly DEFAULT_POLL_INTERVAL_MS;
45
47
  private wasOwnerPresent;
46
48
  private currentAppointmentId;
47
49
  private currentVideoCallId;
48
50
  private currentTenant;
51
+ private readonly STATUS_CACHE_TTL_MS;
52
+ private statusCache;
49
53
  constructor(httpClient: TasHttpClient, config: TasConfig, tasUtilityService: TasUtilityService);
50
54
  /**
51
55
  * Start automatic status polling for the current session.
@@ -86,8 +90,15 @@ export declare class TasService {
86
90
  * PROXY circuit token: /v2/proxy/video/start
87
91
  */
88
92
  startProxyVideoSession(payload: StartSessionRequest): Observable<GenerateTokenResponse>;
93
+ /**
94
+ * Generate cache key from request payload
95
+ */
96
+ private getStatusCacheKey;
97
+ private inflightStatusRequests;
89
98
  /**
90
99
  * PROXY circuit status: /v2/proxy/video/status
100
+ * Uses a 1-second cache to avoid redundant API calls from multiple components
101
+ * Implements request deduplication for simultaneous calls
91
102
  */
92
103
  getProxyVideoStatus(payload: ProxyVideoStatusRequest): Observable<ProxyVideoStatusResponse>;
93
104
  /**
@@ -101,6 +112,19 @@ export declare class TasService {
101
112
  * @returns Observable of appointment array
102
113
  */
103
114
  getAppointments(params: GetAppointmentsRequest): Observable<TasAppointment[]>;
115
+ /**
116
+ * Save video call feedback.
117
+ * POST /v2/proxy/video/save/feedback
118
+ * @param payload Feedback data including videoCallId, motiveId, motiveType, observation, rating (1-5), and tenant
119
+ * @returns Observable that completes on success (HTTP 200 OK, no response body)
120
+ */
121
+ saveFeedback(payload: SaveFeedbackRequest): Observable<void>;
122
+ /**
123
+ * Get available feedback motives.
124
+ * GET /v2/proxy/video/motives
125
+ * @returns Observable of feedback motives array
126
+ */
127
+ getMotives(): Observable<FeedbackMotive[]>;
104
128
  /**
105
129
  * Start automatic status polling for the current session.
106
130
  * Status is polled every STATUS_POLL_INTERVAL_MS milliseconds.
@@ -122,6 +146,7 @@ export declare class TasService {
122
146
  admitUserFromWaitingRoom(userId: number, videoCallId: number): Observable<any>;
123
147
  get appointmentId(): number | null;
124
148
  get videoCallId(): number | null;
149
+ get tenant(): string | null;
125
150
  /**
126
151
  * Connects to a TokBox video session
127
152
  */
@@ -7,9 +7,10 @@ import * as i3 from "./components/tas-floating-call/tas-floating-call.component"
7
7
  import * as i4 from "./components/tas-waiting-room/tas-waiting-room.component";
8
8
  import * as i5 from "./components/tas-avatar/tas-avatar.component";
9
9
  import * as i6 from "./components/tas-incoming-appointment/tas-incoming-appointment.component";
10
- import * as i7 from "@angular/common";
11
- import * as i8 from "@angular/forms";
12
- import * as i9 from "@ng-bootstrap/ng-bootstrap";
10
+ import * as i7 from "./components/tas-feedback-modal/tas-feedback-modal.component";
11
+ import * as i8 from "@angular/common";
12
+ import * as i9 from "@angular/forms";
13
+ import * as i10 from "@ng-bootstrap/ng-bootstrap";
13
14
  export declare class TasUellSdkModule {
14
15
  /**
15
16
  * Use forRoot() to configure the TAS SDK module with required dependencies.
@@ -45,6 +46,6 @@ export declare class TasUellSdkModule {
45
46
  httpClient: new (...args: any[]) => TasHttpClient;
46
47
  }): ModuleWithProviders<TasUellSdkModule>;
47
48
  static ɵfac: i0.ɵɵFactoryDeclaration<TasUellSdkModule, never>;
48
- static ɵmod: i0.ɵɵNgModuleDeclaration<TasUellSdkModule, [typeof i1.TasButtonComponent, typeof i2.TasVideocallComponent, typeof i3.TasFloatingCallComponent, typeof i4.TasWaitingRoomComponent, typeof i5.TasAvatarComponent, typeof i6.TasIncomingAppointmentComponent], [typeof i7.CommonModule, typeof i8.FormsModule, typeof i9.NgbTooltipModule], [typeof i1.TasButtonComponent, typeof i2.TasVideocallComponent, typeof i3.TasFloatingCallComponent, typeof i4.TasWaitingRoomComponent, typeof i5.TasAvatarComponent, typeof i6.TasIncomingAppointmentComponent]>;
49
+ static ɵmod: i0.ɵɵNgModuleDeclaration<TasUellSdkModule, [typeof i1.TasButtonComponent, typeof i2.TasVideocallComponent, typeof i3.TasFloatingCallComponent, typeof i4.TasWaitingRoomComponent, typeof i5.TasAvatarComponent, typeof i6.TasIncomingAppointmentComponent, typeof i7.TasFeedbackModalComponent], [typeof i8.CommonModule, typeof i9.FormsModule, typeof i10.NgbTooltipModule], [typeof i1.TasButtonComponent, typeof i2.TasVideocallComponent, typeof i3.TasFloatingCallComponent, typeof i4.TasWaitingRoomComponent, typeof i5.TasAvatarComponent, typeof i6.TasIncomingAppointmentComponent, typeof i7.TasFeedbackModalComponent]>;
49
50
  static ɵinj: i0.ɵɵInjectorDeclaration<TasUellSdkModule>;
50
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tas-uell-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "TAS (Telemedicine Assistance Service) SDK for Angular applications - Video call functionality using TokBox/Vonage",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
package/public-api.d.ts CHANGED
@@ -9,4 +9,5 @@ export * from './lib/components/tas-videocall/tas-videocall.component';
9
9
  export * from './lib/components/tas-floating-call/tas-floating-call.component';
10
10
  export * from './lib/components/tas-avatar/tas-avatar.component';
11
11
  export * from './lib/components/tas-incoming-appointment/tas-incoming-appointment.component';
12
+ export * from './lib/components/tas-feedback-modal/tas-feedback-modal.component';
12
13
  export * from './lib/tas-uell-sdk.module';
@@ -34,3 +34,20 @@
34
34
  padding: 0;
35
35
  }
36
36
  }
37
+
38
+ /* TAS Feedback Modal - global styles for NgbModal wrapper */
39
+ .tas-feedback-modal-wrapper {
40
+ .modal-dialog {
41
+ max-width: 480px;
42
+ }
43
+ .modal-content {
44
+ border: none;
45
+ border-radius: 20px;
46
+ background: #ffffff;
47
+ overflow: hidden;
48
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
49
+ }
50
+ .modal-body {
51
+ padding: 0;
52
+ }
53
+ }