11import { Component } from '@angular/core' ;
2- import { MatDialog } from '@angular/material/dialog' ;
3- import { MatSnackBar } from '@angular/material/snack-bar' ;
42import { ActivatedRoute , Router } from '@angular/router' ;
5- import { Browser } from '@capacitor/browser' ;
6- import { TranslocoService } from '@ngneat/transloco' ;
7- import { UntilDestroy , untilDestroyed } from '@ngneat/until-destroy' ;
8- import { combineLatest , forkJoin , iif , of } from 'rxjs' ;
9- import { catchError , concatMap , first , map , take , tap } from 'rxjs/operators' ;
10- import { ActionsDialogComponent } from '../../../../shared/actions/actions-dialog/actions-dialog.component' ;
3+ import { UntilDestroy } from '@ngneat/until-destroy' ;
4+ import { catchError } from 'rxjs/operators' ;
115import {
126 Action ,
137 ActionsService ,
148} from '../../../../shared/actions/service/actions.service' ;
15- import { OrderHistoryService } from '../../../../shared/actions/service/order-history.service' ;
16- import { BlockingActionService } from '../../../../shared/blocking-action/blocking-action.service' ;
17- import { DiaBackendAuthService } from '../../../../shared/dia-backend/auth/dia-backend-auth.service' ;
18- import { DiaBackendSeriesRepository } from '../../../../shared/dia-backend/series/dia-backend-series-repository.service' ;
19- import {
20- DiaBackendStoreService ,
21- NetworkAppOrder ,
22- } from '../../../../shared/dia-backend/store/dia-backend-store.service' ;
23- import { DiaBackendWalletService } from '../../../../shared/dia-backend/wallet/dia-backend-wallet.service' ;
249import { ErrorService } from '../../../../shared/error/error.service' ;
25- import { OrderDetailDialogComponent } from '../../../../shared/order-detail-dialog/order-detail-dialog.component' ;
26- import { ProofRepository } from '../../../../shared/repositories/proof/proof-repository.service' ;
27- import { browserToolbarColor } from '../../../../utils/constants' ;
28- import {
29- VOID$ ,
30- isNonNullable ,
31- } from '../../../../utils/rx-operators/rx-operators' ;
32- import { InformationSessionService } from '../information/session/information-session.service' ;
3310
3411@UntilDestroy ( )
3512@Component ( {
@@ -42,270 +19,17 @@ export class ActionsPage {
4219 . getActions$ ( )
4320 . pipe ( catchError ( ( err : unknown ) => this . errorService . toastError$ ( err ) ) ) ;
4421
45- private readonly id$ = this . route . paramMap . pipe (
46- map ( params => params . get ( 'id' ) ) ,
47- isNonNullable ( )
48- ) ;
49-
5022 constructor (
5123 private readonly router : Router ,
5224 private readonly actionsService : ActionsService ,
5325 private readonly errorService : ErrorService ,
54- private readonly translocoService : TranslocoService ,
55- private readonly blockingActionService : BlockingActionService ,
56- private readonly route : ActivatedRoute ,
57- private readonly authService : DiaBackendAuthService ,
58- private readonly snackBar : MatSnackBar ,
59- private readonly dialog : MatDialog ,
60- private readonly storeService : DiaBackendStoreService ,
61- private readonly orderHistoryService : OrderHistoryService ,
62- private readonly diaBackendStoreService : DiaBackendStoreService ,
63- private readonly diaBackendSeriesRepository : DiaBackendSeriesRepository ,
64- private readonly diaBackendWalletService : DiaBackendWalletService ,
65- private readonly informationSessionService : InformationSessionService ,
66- private readonly proofRepository : ProofRepository
26+ private readonly route : ActivatedRoute
6727 ) { }
6828
69- canPerformAction$ ( action : Action ) {
70- if ( action . title_text === 'List in CaptureClub' ) {
71- /*
72- Workaround:
73- Currently there isn't a simple way to check whether an asset is listed in
74- CaptureClub or not. So I first query List all Products API with
75- associated_id parameter set to the assets cid. And then use list series
76- API and check through all nested collections. See discussion here
77- https://app.asana.com/0/0/1201558520076805/1201995911008176/f
78- */
79- return this . id$ . pipe (
80- concatMap ( cid =>
81- forkJoin ( [
82- this . diaBackendStoreService . listAllProducts$ ( {
83- associated_id : cid ,
84- service_name : 'CaptureClub' ,
85- } ) ,
86- of ( cid ) ,
87- ] )
88- ) ,
89- concatMap ( ( [ response , cid ] ) => {
90- if ( response . count > 0 ) {
91- throw new Error (
92- this . translocoService . translate ( 'message.hasListedInCaptureApp' )
93- ) ;
94- }
95- return of ( cid ) ;
96- } ) ,
97- concatMap ( async cid => {
98- let currentOffset = 0 ;
99- const limit = 100 ;
100- while ( true ) {
101- const response = await this . diaBackendSeriesRepository
102- . fetchAll$ ( { offset : currentOffset , limit } )
103- . toPromise ( ) ;
104- const listedAsSeries = response . results . some ( serie =>
105- serie . collections . some ( collection =>
106- collection . assets . some ( asset => asset . cid === cid )
107- )
108- ) ;
109- if ( listedAsSeries ) {
110- throw new Error (
111- this . translocoService . translate ( 'message.hasListedInCaptureApp' )
112- ) ;
113- }
114- if ( response . next == null ) {
115- break ;
116- }
117- currentOffset += response . results . length ;
118- }
119- return VOID$ ;
120- } ) ,
121- take ( 1 )
122- ) ;
123- }
124- return VOID$ ;
125- }
126-
127- openActionDialog$ ( action : Action ) {
128- return combineLatest ( [
129- this . actionsService . getParams$ ( action . params_list_custom_param1 ?? [ ] ) ,
130- this . authService . token$ ,
131- this . id$ ,
132- ] ) . pipe (
133- first ( ) ,
134- concatMap ( ( [ params , token , id ] ) => {
135- const dialogRef = this . dialog . open < ActionsDialogComponent > (
136- ActionsDialogComponent ,
137- {
138- disableClose : true ,
139- data : {
140- action : action ,
141- params : params ,
142- } ,
143- }
144- ) ;
145- return dialogRef . afterClosed ( ) . pipe (
146- isNonNullable ( ) ,
147- concatMap ( data =>
148- of ( {
149- networkApp : action . network_app_id_text ,
150- actionArgs : { ...data , token : token , cid : id } ,
151- } as CreateOrderInput )
152- )
153- ) ;
154- } )
155- ) ;
156- }
157-
158- openOrderDialog$ ( orderStatus : NetworkAppOrder ) {
159- const dialogRef = this . dialog . open < OrderDetailDialogComponent > (
160- OrderDetailDialogComponent ,
161- {
162- disableClose : true ,
163- data : orderStatus ,
164- width : '80%' ,
165- }
166- ) ;
167- return dialogRef . afterClosed ( ) . pipe (
168- isNonNullable ( ) ,
169- concatMap ( ( orderId : string ) => of ( orderId ) )
170- ) ;
171- }
172-
173- createOrder$ ( appName : string , actionArgs : any ) {
174- return this . storeService . createNetworkAppOrder ( appName , actionArgs ) . pipe (
175- catchError ( ( err : unknown ) =>
176- this . errorService . toastDiaBackendError$ ( err )
177- ) ,
178- isNonNullable ( )
179- ) ;
180- }
181-
182- confirmOrder$ ( id : string ) {
183- return this . storeService . confirmNetworkAppOrder ( id ) . pipe (
184- catchError ( ( err : unknown ) =>
185- this . errorService . toastDiaBackendError$ ( err )
186- ) ,
187- isNonNullable ( )
188- ) ;
189- }
190-
191- createOrderHistory$ ( networkAppOrder : NetworkAppOrder ) {
192- return this . id$ . pipe (
193- first ( ) ,
194- isNonNullable ( ) ,
195- concatMap ( cid =>
196- this . orderHistoryService . createOrderHistory$ ( networkAppOrder , cid )
197- ) ,
198- catchError ( ( err : unknown ) => {
199- return this . errorService . toastError$ ( err ) ;
200- } )
201- ) ;
202- }
203-
204- redirectToExternalUrl ( url : string , orderId : string ) {
205- this . id$
206- . pipe (
207- first ( ) ,
208- isNonNullable ( ) ,
209- tap ( cid =>
210- Browser . open ( {
211- url : `${ url } ?cid=${ cid } &order_id=${ orderId } ` ,
212- toolbarColor : browserToolbarColor ,
213- } )
214- ) ,
215- catchError ( ( err : unknown ) => {
216- return this . errorService . toastError$ ( err ) ;
217- } ) ,
218- untilDestroyed ( this )
219- )
220- . subscribe ( ) ;
221- }
222-
223- removeCapture ( ) {
224- if ( this . informationSessionService . activatedDetailedCapture ) {
225- this . informationSessionService . activatedDetailedCapture . proof$ . subscribe (
226- proof => {
227- if ( proof ) {
228- this . proofRepository . remove ( proof ) ;
229- this . router . navigate ( [ '/home' ] ) ;
230- }
231- }
232- ) ;
233- }
234- }
235-
23629 performAction ( action : Action ) {
23730 this . router . navigate ( [ 'action-details' ] , {
23831 relativeTo : this . route ,
23932 state : action ,
24033 } ) ;
24134 }
242-
243- doAction ( action : Action ) {
244- this . blockingActionService
245- . run$ ( this . canPerformAction$ ( action ) )
246- . pipe (
247- catchError ( ( err : unknown ) => {
248- return this . errorService . toastError$ ( err ) ;
249- } ) ,
250- concatMap ( ( ) => this . openActionDialog$ ( action ) ) ,
251- concatMap ( createOrderInput =>
252- this . blockingActionService . run$ (
253- forkJoin ( [
254- this . createOrder$ (
255- createOrderInput . networkApp ,
256- createOrderInput . actionArgs
257- ) ,
258- // To display "Insufficient NUM" in order confirmation dialog,
259- // we need to sync asset wallet balance if the action cost NUM.
260- iif (
261- ( ) => action . action_cost_number > 0 ,
262- this . diaBackendWalletService . syncAssetWalletBalance$ ( ) ,
263- VOID$
264- ) ,
265- ] )
266- )
267- ) ,
268- concatMap ( ( [ orderStatus , _ ] ) => this . openOrderDialog$ ( orderStatus ) ) ,
269- concatMap ( orderId =>
270- this . blockingActionService . run$ ( this . confirmOrder$ ( orderId ) )
271- ) ,
272- tap ( networkAppOrder => {
273- /*
274- Workaround:
275- Create a order history record only if the total cost is > 0 to prevent race condition
276- between app creating the order history record v.s. bubble workflow checking whether a
277- record already exists and if not create a new one, especially for network actions that
278- don't require any cost (and hence backend calls the webhook immediately). See
279- https://dt42-numbers.slack.com/archives/C0323488MEJ/p1648006014291339
280- */
281- if ( Number ( networkAppOrder . total_cost ) !== 0 ) {
282- this . createOrderHistory$ ( networkAppOrder ) . subscribe ( ) ;
283- }
284- } ) ,
285- tap ( ( ) => {
286- this . snackBar . open (
287- this . translocoService . translate ( 'message.sentSuccessfully' )
288- ) ;
289- } ) ,
290- tap ( networkAppOrder => {
291- if ( action . ext_action_destination_text ) {
292- this . redirectToExternalUrl (
293- action . ext_action_destination_text ,
294- networkAppOrder . id
295- ) ;
296- }
297- } ) ,
298- tap ( ( ) => {
299- if ( action . hide_capture_after_execution_boolean ?? false )
300- this . removeCapture ( ) ;
301- } ) ,
302- untilDestroyed ( this )
303- )
304- . subscribe ( ) ;
305- }
306- }
307-
308- interface CreateOrderInput {
309- networkApp : string ;
310- actionArgs : any ;
31135}
0 commit comments