@@ -3,15 +3,22 @@ import { HttpClient } from '@angular/common/http'
3
3
import { inject , Injectable } from '@angular/core'
4
4
import type { Observable } from 'rxjs'
5
5
import { catchError , map , of , ReplaySubject , Subject , takeUntil , tap } from 'rxjs'
6
+ import { ErrorService } from '@seed/services/error/error.service'
6
7
import { SnackbarService } from 'app/core/snackbar/snackbar.service'
7
8
import { naturalSort } from '../../utils'
8
9
import { UserService } from '../user'
9
10
import type {
11
+ AccessLevelNode ,
12
+ AccessLevelsByDepth ,
13
+ AccessLevelTree ,
14
+ AccessLevelTreeResponse ,
10
15
BriefOrganization ,
11
16
Organization ,
12
17
OrganizationResponse ,
13
18
OrganizationSettings ,
14
19
OrganizationsResponse ,
20
+ OrganizationUser ,
21
+ OrganizationUsersResponse ,
15
22
} from './organization.types'
16
23
17
24
@Injectable ( { providedIn : 'root' } )
@@ -20,11 +27,17 @@ export class OrganizationService {
20
27
private _userService = inject ( UserService )
21
28
private _organizations = new ReplaySubject < BriefOrganization [ ] > ( 1 )
22
29
private _currentOrganization = new ReplaySubject < Organization > ( 1 )
30
+ private _organizationUsers = new ReplaySubject < OrganizationUser [ ] > ( 1 )
31
+ private _accessLevelTree = new ReplaySubject < AccessLevelTree > ( 1 )
32
+ private _accessLevelInstancesByDepth : AccessLevelsByDepth = { }
33
+ private _errorService = inject ( ErrorService )
23
34
private readonly _unsubscribeAll$ = new Subject < void > ( )
24
35
private _snackBar = inject ( SnackbarService )
25
36
26
37
organizations$ = this . _organizations . asObservable ( )
27
38
currentOrganization$ = this . _currentOrganization . asObservable ( )
39
+ organizationUsers$ = this . _organizationUsers . asObservable ( )
40
+ accessLevelTree$ = this . _accessLevelTree . asObservable ( )
28
41
29
42
constructor ( ) {
30
43
// Fetch current org data whenever user org id changes
@@ -54,8 +67,53 @@ export class OrganizationService {
54
67
} ) ,
55
68
catchError ( ( error : HttpErrorResponse ) => {
56
69
// TODO need to figure out error handling
57
- console . error ( 'Error occurred fetching organization: ' , error . error )
58
- return of ( { } as Organization )
70
+ return this . _errorService . handleError ( error , 'Error fetching organization' )
71
+ } ) ,
72
+ )
73
+ }
74
+
75
+ getOrganizationUsers ( orgId : number ) : void {
76
+ const url = `/api/v3/organizations/${ orgId } /users/`
77
+ this . _httpClient . get < OrganizationUsersResponse > ( url )
78
+ . pipe (
79
+ map ( ( response ) => response . users . sort ( ( a , b ) => naturalSort ( a . last_name , b . last_name ) ) ) ,
80
+ tap ( ( users ) => { this . _organizationUsers . next ( users ) } ) ,
81
+ catchError ( ( error : HttpErrorResponse ) => {
82
+ return this . _errorService . handleError ( error , 'Error fetching organization users' )
83
+ } ) ,
84
+ ) . subscribe ( )
85
+ }
86
+
87
+ getOrganizationAccessLevelTree ( orgId : number ) : void {
88
+ const url = `/api/v3/organizations/${ orgId } /access_levels/tree`
89
+ this . _httpClient . get < AccessLevelTreeResponse > ( url )
90
+ . pipe (
91
+ map ( ( response ) => {
92
+ // update response to include more usable accessLevelInstancesByDepth
93
+ this . _accessLevelInstancesByDepth = this . _calculateAccessLevelInstancesByDepth ( response . access_level_tree , 0 )
94
+ return {
95
+ accessLevelNames : response . access_level_names ,
96
+ accessLevelInstancesByDepth : this . _accessLevelInstancesByDepth ,
97
+ }
98
+ } ) ,
99
+ tap ( ( accessLevelTree ) => {
100
+ this . _accessLevelTree . next ( accessLevelTree )
101
+ } ) ,
102
+ catchError ( ( error : HttpErrorResponse ) => {
103
+ return this . _errorService . handleError ( error , 'Error fetching organization access level tree' )
104
+ } ) ,
105
+ )
106
+ . subscribe ( )
107
+ }
108
+
109
+ deleteOrganizationUser ( userId : number , orgId : number ) {
110
+ const url = `/api/v3/organizations/${ orgId } /users/${ userId } /remove/`
111
+ return this . _httpClient . delete ( url ) . pipe (
112
+ tap ( ( ) => {
113
+ this . _snackBar . success ( 'Member removed from organization' )
114
+ } ) ,
115
+ catchError ( ( error : HttpErrorResponse ) => {
116
+ return this . _errorService . handleError ( error , 'Error removing member from organization' )
59
117
} ) ,
60
118
)
61
119
}
@@ -81,13 +139,24 @@ export class OrganizationService {
81
139
} )
82
140
} ) ,
83
141
catchError ( ( error : HttpErrorResponse ) => {
84
- console . error ( 'Error occurred fetching organization: ' , error . error )
85
- this . _snackBar . alert ( `An error occurred updating the organization: ${ error . error } ` )
86
- return of ( null )
142
+ return this . _errorService . handleError ( error , 'Error updating organization settings' )
87
143
} ) ,
88
144
)
89
145
}
90
146
147
+ /*
148
+ * Transform access level tree into a more usable format
149
+ */
150
+ private _calculateAccessLevelInstancesByDepth ( tree : AccessLevelNode [ ] , depth : number , result : AccessLevelsByDepth = { } ) : AccessLevelsByDepth {
151
+ if ( ! tree ) return result
152
+ if ( ! result [ depth ] ) result [ depth ] = [ ]
153
+ for ( const ali of tree ) {
154
+ result [ depth ] . push ( { id : ali . id , name : ali . name } )
155
+ this . _calculateAccessLevelInstancesByDepth ( ali . children , depth + 1 , result )
156
+ }
157
+ return result
158
+ }
159
+
91
160
private _get ( brief = false ) : Observable < ( BriefOrganization | Organization ) [ ] > {
92
161
const url = brief ? '/api/v3/organizations/?brief=true' : '/api/v3/organizations/'
93
162
return this . _httpClient . get < OrganizationsResponse > ( url ) . pipe (
0 commit comments