Skip to content

Commit 5ab7895

Browse files
Adds majority of remaining list actions (#53)
* action group modal * move to shared dir * better analyses fxnal * bsynr analysis fxnal * simple analyses config fxnal * analyses modal fxnal * dqc from actions * update derived data fxnal * bugs * base data * label action * export modal fxnal * refresh metadata fxnal * geocode in progress * lint * lint * dev * geocode modal fxnal * valid status * geocode and merge fxnal * pinning * track settings$ * decode ubid fxnal * compare ubid fxnal * ubid editor * email modal fxnal * FEMP fxnal * lint * email refactor * prettier * Lint fixes * Remove unused code * More consistent functionality with the original code --------- Co-authored-by: Alex Swindler <Alex.Swindler@nrel.gov>
1 parent 8989c9e commit 5ab7895

61 files changed

Lines changed: 1682 additions & 192 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/@seed/api/geocode/geocode.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class GeocodeService {
1313
private _errorService = inject(ErrorService)
1414

1515
geocode(orgId: number, viewIds: number[], type: InventoryType): Observable<unknown> {
16-
const url = `/api/v3/geocode/geocode_by_ids/&organization_id=${orgId}`
16+
const url = `/api/v3/geocode/geocode_by_ids/?organization_id=${orgId}`
1717
const data = {
1818
property_view_ids: type === 'taxlots' ? [] : viewIds,
1919
taxlot_view_ids: type === 'taxlots' ? viewIds : [],

src/@seed/api/geocode/geocode.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export type ConfidenceSummary = {
2-
properties: InventoryConfidenceSummary;
3-
taxlots: InventoryConfidenceSummary;
2+
properties?: InventoryConfidenceSummary;
3+
taxlots?: InventoryConfidenceSummary;
44
}
55

66
export type InventoryConfidenceSummary = {

src/@seed/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export * from './groups'
1414
export * from './inventory'
1515
export * from './label'
1616
export * from './mapping'
17+
export * from './matching'
1718
export * from './meters'
1819
export * from './notes'
1920
export * from './organization'

src/@seed/api/inventory/inventory.service.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,4 +389,33 @@ export class InventoryService {
389389
}),
390390
)
391391
}
392+
393+
propertiesMetersExist(orgId: number, propertyViewIds: number[]): Observable<boolean> {
394+
const url = `/api/v3/properties/meters_exist/?organization_id=${orgId}`
395+
return this._httpClient.post<boolean>(url, { property_view_ids: propertyViewIds }).pipe(
396+
catchError((error: HttpErrorResponse) => {
397+
return this._errorService.handleError(error, 'Error checking if meters exist for properties')
398+
}),
399+
)
400+
}
401+
402+
evaluationExportToCts(orgId: number, viewIds: number[], filename: string): Observable<Blob> {
403+
const url = `/api/v3/properties/evaluation_export_to_cts/?organization_id=${orgId}`
404+
return this._httpClient.post(url, { filename, property_view_ids: viewIds }, { responseType: 'arraybuffer' }).pipe(
405+
map((response) => new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })),
406+
catchError((error: HttpErrorResponse) => {
407+
return this._errorService.handleError(error, 'Error exporting to CTS')
408+
}),
409+
)
410+
}
411+
412+
facilityBpsExportToCts(orgId: number, viewIds: number[], filename: string): Observable<Blob> {
413+
const url = `/api/v3/properties/facility_bps_export_to_cts/?organization_id=${orgId}`
414+
return this._httpClient.post(url, { filename, property_view_ids: viewIds }, { responseType: 'arraybuffer' }).pipe(
415+
map((response) => new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })),
416+
catchError((error: HttpErrorResponse) => {
417+
return this._errorService.handleError(error, 'Error exporting to CTS')
418+
}),
419+
)
420+
}
392421
}

src/@seed/api/matching/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './matching.service'
2+
export * from './matching.types'
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { HttpClient } from '@angular/common/http'
2+
import { inject, Injectable } from '@angular/core'
3+
import type { Observable } from 'rxjs'
4+
import { catchError, tap } from 'rxjs'
5+
import { ErrorService } from '@seed/services'
6+
import { SnackBarService } from 'app/core/snack-bar/snack-bar.service'
7+
import type { InventoryType } from 'app/modules/inventory'
8+
import type { MergingResponse } from './matching.types'
9+
10+
@Injectable({ providedIn: 'root' })
11+
export class MatchingService {
12+
private _httpClient = inject(HttpClient)
13+
private _errorService = inject(ErrorService)
14+
private _snackBar = inject(SnackBarService)
15+
16+
mergeInventory(orgId: number, viewIds: number[], type: InventoryType): Observable<MergingResponse> {
17+
const url = `/api/v3/${type}/merge/?organization_id=${orgId}`
18+
const key = type === 'taxlots' ? 'taxlot_view_ids' : 'property_view_ids'
19+
const data = { [key]: viewIds }
20+
return this._httpClient.post<MergingResponse>(url, data).pipe(
21+
tap(() => {
22+
this._snackBar.success('Successfully merged inventory')
23+
}),
24+
catchError(() => {
25+
return this._errorService.handleError(null, 'Error merging inventory')
26+
}),
27+
)
28+
}
29+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type MergingResponse = {
2+
status: string;
3+
match_link_count?: number;
4+
match_merged_count?: number;
5+
message?: string;
6+
}

src/@seed/api/organization/organization.service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
OrganizationsResponse,
2929
OrganizationUser,
3030
OrganizationUserResponse,
31+
OrganizationUserSettings,
3132
OrganizationUsersResponse,
3233
StartSavingAccessLevelInstancesRequest,
3334
UpdateAccessLevelsRequest,
@@ -44,13 +45,15 @@ export class OrganizationService {
4445

4546
private _organizations = new ReplaySubject<BriefOrganization[]>(1)
4647
private _currentOrganization = new ReplaySubject<Organization>(1)
48+
private _orgUserSettings = new ReplaySubject<OrganizationUserSettings>(1)
4749
private _organizationUsers = new ReplaySubject<OrganizationUser[]>(1)
4850
private _accessLevelTree = new ReplaySubject<AccessLevelTree>(1)
4951
private _accessLevelInstancesByDepth = new ReplaySubject<AccessLevelsByDepth>(1)
5052
private _inventoryService = inject(InventoryService)
5153

5254
organizations$ = this._organizations.asObservable()
5355
currentOrganization$ = this._currentOrganization.asObservable()
56+
orgUserSettings$ = this._orgUserSettings.asObservable()
5457
organizationUsers$ = this._organizationUsers.asObservable()
5558
accessLevelTree$ = this._accessLevelTree.asObservable()
5659
accessLevelInstancesByDepth$ = this._accessLevelInstancesByDepth.asObservable()
@@ -113,6 +116,9 @@ export class OrganizationService {
113116
const data = { settings }
114117
const url = `/api/v4/organization_users/${orgUserId}/?organization_id=${orgId}`
115118
return this._httpClient.put<OrganizationUserResponse>(url, data).pipe(
119+
tap(({ data }) => {
120+
this._orgUserSettings.next(data.settings)
121+
}),
116122
catchError((error: HttpErrorResponse) => {
117123
return this._errorService.handleError(error, 'Error updating organization user')
118124
}),

src/@seed/api/organization/organization.types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export type OrganizationUserSettings = {
107107
profile?: UserSettingsProfiles;
108108
crossCycles?: UserSettingsCrossCycles;
109109
labels?: UserLabelSettings;
110+
pins?: UserPinSettings;
110111
insights?: InsightsUserSettings;
111112
}
112113

@@ -130,6 +131,17 @@ type UserSettingsCrossCycles = {
130131
taxlots?: number[];
131132
}
132133

134+
type UserPinSettings = {
135+
properties?: {
136+
left: string[];
137+
right: string[];
138+
};
139+
taxlots?: {
140+
left: string[];
141+
right: string[];
142+
};
143+
}
144+
133145
type UserLabelSettings = { ids: number[]; operator: LabelOperator }
134146

135147
export type InsightDatasetVisibility = 'compliant' | 'non-compliant' | 'unknown' | 'whisker'

src/@seed/api/postoffice/postoffice.service.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import { inject, Injectable } from '@angular/core'
33
import { catchError, map, type Observable, ReplaySubject, Subject, takeUntil, tap } from 'rxjs'
44
import { UserService } from '@seed/api'
55
import { ErrorService } from '@seed/services'
6-
import type { CreateEmailTemplateResponse, EmailTemplate, ListEmailTemplatesResponse } from './postoffice.types'
6+
import { SnackBarService } from 'app/core/snack-bar/snack-bar.service'
7+
import type { CreateEmailTemplateResponse, EmailTemplate, ListEmailTemplatesResponse, SendEmailResponse } from './postoffice.types'
78

89
@Injectable({ providedIn: 'root' })
910
export class PostOfficeService {
1011
private _httpClient = inject(HttpClient)
1112
private _userService = inject(UserService)
1213
private _errorService = inject(ErrorService)
1314
private _emailTemplates = new ReplaySubject<EmailTemplate[]>()
15+
private _snackBar = inject(SnackBarService)
1416
private readonly _unsubscribeAll$ = new Subject<void>()
1517
orgId: number
1618
emailTemplates$ = this._emailTemplates.asObservable()
@@ -66,4 +68,26 @@ export class PostOfficeService {
6668
}),
6769
)
6870
}
71+
72+
sendEmail(orgId: number, stateIds: number[], template_id: number, inventory_type: string): Observable<SendEmailResponse> {
73+
const url = `/api/v3/postoffice_email/?organization_id=${orgId}`
74+
const data = {
75+
from_email: 'blankl@example.com', // Dummy email. The backend will assign the appropriate email.
76+
template_id,
77+
inventory_id: stateIds,
78+
inventory_type,
79+
}
80+
return this._httpClient.post<SendEmailResponse>(url, data).pipe(
81+
tap(({ status }) => {
82+
if (status === 'success') {
83+
this._snackBar.success('Successfully sent email')
84+
} else {
85+
this._snackBar.alert('Error sending email')
86+
}
87+
}),
88+
catchError((error: HttpErrorResponse) => {
89+
return this._errorService.handleError(error, 'Error sending email')
90+
}),
91+
)
92+
}
6993
}

0 commit comments

Comments
 (0)