Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
082e946
Minor
bistaastha Jan 21, 2026
03f0a14
Minor
bistaastha Jan 21, 2026
f5879c7
Update org-user.service.spec.ts
bistaastha Jan 21, 2026
2e73a08
Minor
bistaastha Jan 21, 2026
060f63f
Merge branch 'fyle-api-integration-for-notifs' of github.com:fylein/f…
bistaastha Jan 21, 2026
178a224
Minor
bistaastha Jan 22, 2026
ce1f560
Minor
bistaastha Jan 22, 2026
249829c
Minor
bistaastha Jan 22, 2026
e112f85
Minor
bistaastha Jan 22, 2026
b8832ae
Minor
bistaastha Jan 22, 2026
56ea99a
Minor
bistaastha Jan 23, 2026
be63e04
Minor
bistaastha Jan 23, 2026
52554fb
Minor
bistaastha Jan 23, 2026
5897bb6
Merge branch 'fyle-fix-setup-keys' into fyle-add-redirection-for-noti…
bistaastha Jan 23, 2026
d787bac
Merge remote-tracking branch 'origin/fyle-fix-setup-keys' into fyle-a…
bistaastha Jan 23, 2026
b26d6e0
Merge branch 'fyle-fix-setup-keys' into fyle-add-redirection-for-noti…
bistaastha Jan 23, 2026
88cfed2
Merge branch 'fyle-fix-setup-keys' into fyle-add-redirection-for-noti…
bistaastha Jan 23, 2026
f6ec718
Minor
bistaastha Jan 27, 2026
a440a25
Minor
bistaastha Jan 27, 2026
7cf5cfa
Minor
bistaastha Jan 27, 2026
ccbf3f7
Minor
bistaastha Jan 27, 2026
2ce020f
Minor
bistaastha Jan 28, 2026
8d22251
Update push-notification.service.ts
bistaastha Jan 28, 2026
53013f3
Minor
bistaastha Jan 29, 2026
448562f
Minor
bistaastha Jan 29, 2026
2d25b9b
Merge branch 'fyle-add-redirection-for-notifications' of github.com:f…
bistaastha Jan 29, 2026
2b867db
Minor
bistaastha Jan 29, 2026
f418f33
Minor
bistaastha Jan 29, 2026
3462fde
Minor
bistaastha Jan 29, 2026
82f5600
Minor
bistaastha Jan 29, 2026
f070816
Minor
bistaastha Jan 30, 2026
721d8ac
Minor
bistaastha Jan 30, 2026
c0ba3eb
Minor
bistaastha Jan 30, 2026
0815453
Minor
bistaastha Jan 30, 2026
d4f18d1
Minor
bistaastha Jan 30, 2026
50e8495
Minor
bistaastha Jan 30, 2026
7750455
Minor
bistaastha Jan 30, 2026
bc25593
Minor
bistaastha Jan 30, 2026
a575594
Minor
bistaastha Jan 30, 2026
8d3a4ae
Minor
bistaastha Jan 30, 2026
4cbbf17
Minor
bistaastha Jan 30, 2026
d21b725
Minor
bistaastha Jan 30, 2026
afaa507
Minor
bistaastha Jan 30, 2026
e55921e
Minor
bistaastha Jan 30, 2026
b37f3c8
Minor
bistaastha Jan 30, 2026
b32f422
Minor
bistaastha Jan 31, 2026
fc141cf
Minor
bistaastha Jan 31, 2026
ba510e3
Minor
bistaastha Jan 31, 2026
adb990b
Minor
bistaastha Jan 31, 2026
ca32a7a
Minor
bistaastha Jan 31, 2026
fe356a4
Minor
bistaastha Jan 31, 2026
a44f505
Minor
bistaastha Feb 1, 2026
67d5a95
Merge remote-tracking branch 'origin/fyle-fix-setup-keys' into fyle-a…
amit429 Feb 2, 2026
99782e3
testing
amit429 Feb 2, 2026
2603fdc
Commented get device token logic for testing purposes
amit429 Feb 4, 2026
6424719
testing the deeplinks
amit429 Feb 5, 2026
3534acc
fix the redirection from app killed state
amit429 Feb 5, 2026
b280e92
testing
amit429 Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { NavController } from '@ionic/angular/standalone';
import { UserEventService } from './core/services/user-event.service';
import { DeviceService } from './core/services/device.service';
import { GmapsService } from './core/services/gmaps.service';
import { PushNotificationService } from './core/services/push-notification.service';

import { SplashScreen } from '@capacitor/splash-screen';
import { StatusBar } from '@capacitor/status-bar';
Expand Down Expand Up @@ -73,6 +74,7 @@ describe('AppComponent', () => {
let gmapsService: jasmine.SpyObj<GmapsService>;
let menuController: jasmine.SpyObj<MenuController>;
let backButtonService: jasmine.SpyObj<BackButtonService>;
let pushNotificationService: jasmine.SpyObj<PushNotificationService>;
beforeEach(waitForAsync(() => {
// Mock Capacitor plugins before component creation
// Create spies that return resolved promises
Expand Down Expand Up @@ -155,6 +157,7 @@ describe('AppComponent', () => {
const gmapsServiceSpy = jasmine.createSpyObj('GmapsService', ['loadLibrary']);
const menuControllerSpy = jasmine.createSpyObj('MenuController', ['swipeGesture']);
const backButtonServiceSpy = jasmine.createSpyObj('BackButtonService', ['showAppCloseAlert']);
const pushNotificationServiceSpy = jasmine.createSpyObj('PushNotificationService', ['unregister']);

// Configure tracking service with missing methods
trackingServiceSpy.updateIdentityIfNotPresent = jasmine.createSpy('updateIdentityIfNotPresent').and.resolveTo();
Expand Down Expand Up @@ -190,6 +193,7 @@ describe('AppComponent', () => {
{ provide: GmapsService, useValue: gmapsServiceSpy },
{ provide: MenuController, useValue: menuControllerSpy },
{ provide: BackButtonService, useValue: backButtonServiceSpy },
{ provide: PushNotificationService, useValue: pushNotificationServiceSpy },
],
})
.overrideComponent(AppComponent, {
Expand Down Expand Up @@ -220,6 +224,7 @@ describe('AppComponent', () => {
gmapsService = TestBed.inject(GmapsService) as jasmine.SpyObj<GmapsService>;
menuController = TestBed.inject(MenuController) as jasmine.SpyObj<MenuController>;
backButtonService = TestBed.inject(BackButtonService) as jasmine.SpyObj<BackButtonService>;
pushNotificationService = TestBed.inject(PushNotificationService) as jasmine.SpyObj<PushNotificationService>;
}));

describe('ngAfterViewInit', () => {
Expand Down
4 changes: 4 additions & 0 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { NgClass } from '@angular/common';
import { FyConnectionComponent } from './shared/components/fy-connection/fy-connection.component';
import { Capacitor } from '@capacitor/core';
import { AppShortcuts } from '@capawesome/capacitor-app-shortcuts';
import { PushNotificationService } from './core/services/push-notification.service';

@Component({
selector: 'app-root',
Expand All @@ -53,6 +54,8 @@ export class AppComponent implements OnInit, AfterViewInit {

private router = inject(Router);

private pushNotificationService = inject(PushNotificationService);

private activatedRoute = inject(ActivatedRoute);

private userEventService = inject(UserEventService);
Expand Down Expand Up @@ -293,6 +296,7 @@ export class AppComponent implements OnInit, AfterViewInit {
this.userEventService.onLogout(() => {
this.trackingService.onSignOut();
this.freshChatService.destroy();
this.pushNotificationService.unregister();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unregisters a token on log out

this.isSwitchedToDelegator = false;
Comment on lines 301 to 305
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle unregister promise (and avoid double-unregister).
unregister() returns a Promise; unhandled rejection can surface, and the service already auto-unregisters on logout. Pick one place, and if you keep this call, guard it.

🐛 Suggested fix (keep call, guard it)
-      this.pushNotificationService.unregister();
+      void this.pushNotificationService.unregister().catch(noop);
🤖 Prompt for AI Agents
In `@src/app/app.component.ts` around lines 296 - 300, The logout handler
registered with userEventService.onLogout calls
pushNotificationService.unregister() but doesn't handle its returned Promise and
may double-unregister; update the onLogout callback (in the block where
trackingService.onSignOut(), freshChatService.destroy(),
pushNotificationService.unregister(), isSwitchedToDelegator = false are called)
to guard and handle the promise: first check a registration state (e.g.
pushNotificationService.isRegistered or an internal flag) before calling
unregister, and if keeping the call always, ensure you handle the Promise by
awaiting it or attaching .catch(...) to swallow or log harmless "already
unregistered" errors to avoid unhandled rejections and duplicate unregister
attempts.

this.router.navigate(['/', 'auth', 'sign_in']);
});
Expand Down
13 changes: 13 additions & 0 deletions src/app/core/services/org-user.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,19 @@ describe('OrgUserService', () => {
});
});

it('sendDeviceToken(): should send device token to the backend', (done) => {
const token = 'test-device-token';
spenderPlatformV1ApiService.post.and.returnValue(of({}));

orgUserService.sendDeviceToken(token).subscribe((res) => {
expect(spenderPlatformV1ApiService.post).toHaveBeenCalledWith('/users/device_token', {
data: { token },
});
expect(res).toEqual({});
done();
});
});
Comment on lines 188 to 204
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

One test case? Naanga oru dharavai commit pannaa, noorudhavai test pannuven!

The test covers the happy path like a hero's entry scene, but Superstar needs to see some villain-fighting scenarios too:

  1. Empty tokens array: What happens when no existing tokens? Backend could return { data: { tokens: [] } } or { data: {} }
  2. Duplicate token handling: If the same token already exists in the array (if deduplication is added per previous comment)

Also, Line 192 uses as any - like fighting without knowing the enemy. Consider using proper type:

spenderPlatformV1ApiService.get.and.returnValue(
  of({ data: { tokens: existingTokens } } as PlatformApiResponse<{ tokens: string[] }>)
);
🎬 Additional test cases - Superstar collection
it('sendDeviceToken(): should handle empty existing tokens', (done) => {
  const token = 'new-device-token';

  spenderPlatformV1ApiService.get.and.returnValue(
    of({ data: { tokens: [] } } as PlatformApiResponse<{ tokens: string[] }>)
  );
  spenderPlatformV1ApiService.post.and.returnValue(of({}));

  orgUserService.sendDeviceToken(token).subscribe((res) => {
    expect(spenderPlatformV1ApiService.post).toHaveBeenCalledWith('/users/device_token', {
      data: { tokens: [token] },
    });
    done();
  });
});

it('sendDeviceToken(): should handle null tokens from backend', (done) => {
  const token = 'new-device-token';

  spenderPlatformV1ApiService.get.and.returnValue(
    of({ data: { tokens: null } } as any)
  );
  spenderPlatformV1ApiService.post.and.returnValue(of({}));

  orgUserService.sendDeviceToken(token).subscribe((res) => {
    expect(spenderPlatformV1ApiService.post).toHaveBeenCalledWith('/users/device_token', {
      data: { tokens: [token] },
    });
    done();
  });
});

Based on learnings: "In the Fyle mobile app, the migration from OrgUserSettingsService to PlatformEmployeeSettingsService introduced a potential breaking change where mileage_settings could be null or undefined... indicating this is a real-world scenario that needs defensive handling."

🤖 Prompt for AI Agents
In `@src/app/core/services/org-user.service.spec.ts` around lines 188 - 203, Add
unit tests for edge cases in orgUserService.sendDeviceToken: cover backend
returning empty tokens array, data.tokens being null/undefined, and the
duplicate-token case if deduplication is or will be implemented; update the test
stubs to use the proper response type (use PlatformApiResponse<{ tokens:
string[] }> for spenderPlatformV1ApiService.get returnValue instead of as any)
and assert that spenderPlatformV1ApiService.post is called with the expected
tokens payload (e.g., [token] when no existing tokens, or existingTokens when
duplicate handling prevents adding the same token).


it('should return false if the user is not switched to a delegator', (done) => {
jwtHelperService.decodeToken.and.returnValue(accessTokenData);
// This token contains the user details such as user id, org id, org user id, roles, scopes, etc.
Expand Down
10 changes: 10 additions & 0 deletions src/app/core/services/org-user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ export class OrgUserService {
);
}

sendDeviceToken(token: string): Observable<unknown> {
const payload = {
data: {
token,
},
};

return this.spenderPlatformV1ApiService.post('/users/device_token', payload);
}
Comment on lines 110 to 130
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for device_token and /users/device_token references
rg -n -C 3 "/users/device_token|device_token" --type=ts

Repository: fylein/fyle-mobile-app

Length of output: 1196


🏁 Script executed:

# Look for any API documentation or interface definitions related to device tokens
rg -n "tokens|deviceToken" --type=ts -A 2 -B 2 | head -100

Repository: fylein/fyle-mobile-app

Length of output: 372


🏁 Script executed:

# Check for any test files that might show expected payload
fd -e spec.ts -e test.ts | xargs rg -l "device_token\|deviceToken" 2>/dev/null

Repository: fylein/fyle-mobile-app

Length of output: 50


🏁 Script executed:

# Look for any backend API contract files or documentation
fd -e "*.json" -e "*.md" -e "*.yaml" -e "*.yml" | xargs rg -l "device_token" 2>/dev/null

Repository: fylein/fyle-mobile-app

Length of output: 154


🏁 Script executed:

cat -n src/app/core/services/org-user.service.spec.ts | sed -n '185,200p'

Repository: fylein/fyle-mobile-app

Length of output: 624


Fix the payload schema to match the expected contract.

The implementation sends { data: { tokens: [token] } } but the test expects { data: { token } }. Device token registration is broken and the test will fail.

Required fix
  const payload = {
    data: {
-     tokens: [token],
+     token,
    },
  };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sendDeviceToken(token: string): Observable<unknown> {
const payload = {
data: {
tokens: [token],
},
};
return this.spenderPlatformV1ApiService.post('/users/device_token', payload);
}
sendDeviceToken(token: string): Observable<unknown> {
const payload = {
data: {
token,
},
};
return this.spenderPlatformV1ApiService.post('/users/device_token', payload);
}
🤖 Prompt for AI Agents
In `@src/app/core/services/org-user.service.ts` around lines 104 - 112, The
sendDeviceToken implementation builds the wrong payload shape (it sends
data.tokens as an array); update sendDeviceToken to send data.token (a single
token string) to match the contract and tests. In the sendDeviceToken method
change the payload construction so payload is { data: { token } } and continue
to call spenderPlatformV1ApiService.post('/users/device_token', payload) as
before.

Comment on lines 110 to 130
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Mind it! Duplicate tokens can sneak in like a villain!

Thalaiva sees two concerns here:

  1. Line 113: The existingTokens ?? [] check is unnecessary - getDeviceTokens() already returns [] as default. Like bringing coconut to Kerala!

  2. No deduplication: If the same device token is sent twice, it gets added twice to the array. This could bloat the token list over time and cause unnecessary notifications.

🎬 Proposed fix - Superstar style
  sendDeviceToken(token: string): Observable<unknown> {
    return this.getDeviceTokens().pipe(
      map((existingTokens) => {
-       const tokens = existingTokens ?? [];
-       tokens.push(token);
-       return tokens;
+       if (existingTokens.includes(token)) {
+         return existingTokens;
+       }
+       return [...existingTokens, token];
      }),
      switchMap((tokens) =>
        this.spenderPlatformV1ApiService.post('/users/device_token', {
          data: { tokens },
        }),
      ),
    );
  }
🤖 Prompt for AI Agents
In `@src/app/core/services/org-user.service.ts` around lines 110 - 123, In
sendDeviceToken, remove the unnecessary existingTokens ?? [] fallback
(getDeviceTokens already returns an array) and ensure you deduplicate before
posting: obtain tokens from getDeviceTokens(), add the new token only if it's
not already present (or build a unique array via a Set) so duplicates aren't
sent, then call spenderPlatformV1ApiService.post('/users/device_token', { data:
{ tokens } }); reference sendDeviceToken and getDeviceTokens when making the
change.


getUserById(userId: string): Observable<EouApiResponse> {
return this.apiService.get('/eous/' + userId);
}
Expand Down
59 changes: 55 additions & 4 deletions src/app/core/services/push-notification.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { PushNotifications, Token } from '@capacitor/push-notifications';
import { DeepLinkService } from './deep-link.service';
import { TrackingService } from './tracking.service';
import { UserEventService } from './user-event.service';
import { OrgUserService } from './org-user.service';

@Injectable({
providedIn: 'root',
})
export class PushNotificationService {
private listenersInitialized = false;

private deepLinkService: DeepLinkService = inject(DeepLinkService);

private trackingService: TrackingService = inject(TrackingService);

private userEventService: UserEventService = inject(UserEventService);

private orgUserService: OrgUserService = inject(OrgUserService);

constructor() {
this.userEventService.onLogout(() => {
void this.unregister();
});
}

async initializePushNotifications(): Promise<void> {
const permission = await PushNotifications.requestPermissions();

Expand All @@ -16,18 +34,51 @@ export class PushNotificationService {
}
}

async unregister(): Promise<void> {
await PushNotifications.unregister();
}

private initListeners(): void {
if (this.listenersInitialized) {
return;
}

this.listenersInitialized = true;

PushNotifications.addListener('registration', (_token: Token) => {
// TODO: Integrate API for sending token to backend
this.addRegistrationListener();
this.addRegistrationErrorListener();
this.addNotificationClickListener();
}

private addRegistrationListener(): void {
PushNotifications.addListener('registration', (token: Token) => {
const tokenValue = token?.value;
if (tokenValue) {
this.orgUserService.sendDeviceToken(tokenValue).subscribe();
}
this.trackingService.eventTrack('Push Notification Registered');
});
}

private addRegistrationErrorListener(): void {
PushNotifications.addListener('registrationError', () => undefined);
PushNotifications.addListener('pushNotificationActionPerformed', () => undefined);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Enna boss, registration error is going silently into the void!

When push registration fails, this handler does nothing. That's like Rajini walking away without a punchline! At minimum, track the error for debugging production issues.

♻️ Proposed fix to track registration errors
 private addRegistrationErrorListener(): void {
-  PushNotifications.addListener('registrationError', () => undefined);
+  PushNotifications.addListener('registrationError', (error) => {
+    this.trackingService.eventTrack('Push Notification Registration Failed', { error: error?.error });
+  });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private addRegistrationErrorListener(): void {
PushNotifications.addListener('registrationError', () => undefined);
PushNotifications.addListener('pushNotificationActionPerformed', () => undefined);
}
private addRegistrationErrorListener(): void {
PushNotifications.addListener('registrationError', (error) => {
this.trackingService.eventTrack('Push Notification Registration Failed', { error: error?.error });
});
}
🤖 Prompt for AI Agents
In `@src/app/core/services/push-notification.service.ts` around lines 63 - 65, The
current addRegistrationErrorListener swallows errors; update
addRegistrationErrorListener so the
PushNotifications.addListener('registrationError', ...) callback accepts the
error payload and forwards it to your app's telemetry/logging (e.g., call
this.logger.error(error) and/or this.telemetryService.captureException(error)),
falling back to console.error if no logger is available; ensure you reference
PushNotifications.addListener and addRegistrationErrorListener when making the
change so the registrationError handler records the error instead of returning
undefined.


private addNotificationClickListener(): void {
PushNotifications.addListener('pushNotificationActionPerformed', (event) => {
const data = (event?.notification?.data as { url?: string; actionType?: string } | undefined) ?? {};
const url = data.url;
const actionType = data.actionType;

if (!url || typeof url !== 'string') {
return;
}

this.trackingService.eventTrack('Push Notification Clicked', { actionType });

const redirectParams = this.deepLinkService.getJsonFromUrl(url);
this.deepLinkService.redirect(redirectParams);
});
Comment on lines 116 to 134
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard deep-link parsing to avoid crash.
Line 80 can throw if the URL is malformed — wrap in try/catch so a bad payload doesn’t kill the handler.

🛡️ Suggested fix
 this.trackingService.eventTrack('Push Notification Clicked', { actionType });

-const redirectParams = this.deepLinkService.getJsonFromUrl(url);
-this.deepLinkService.redirect(redirectParams);
+try {
+  const redirectParams = this.deepLinkService.getJsonFromUrl(url);
+  this.deepLinkService.redirect(redirectParams);
+} catch (error) {
+  this.trackingService.eventTrack('Push Notification Redirect Failed', { error });
+}
🤖 Prompt for AI Agents
In `@src/app/core/services/push-notification.service.ts` around lines 68 - 82, The
push notification click handler in addNotificationClickListener uses
deepLinkService.getJsonFromUrl(url) and deepLinkService.redirect(redirectParams)
without guarding against malformed URLs; wrap the parsing and redirect logic in
a try/catch inside the PushNotifications.addListener callback so exceptions from
getJsonFromUrl or redirect are caught, log or handle the error (via
trackingService or a logger) and return gracefully instead of throwing; keep the
early checks for url and event the same and ensure
trackingService.eventTrack('Push Notification Clicked', { actionType }) still
runs before the guarded parse/redirect block.

}
}

Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
</div>
@if (showMobilePushColumn) {
<div class="email-notifications--checkbox-col-value">
<mat-checkbox [(ngModel)]="selectAllMobile" (ngModelChange)="toggleAllNotifications($event, 'push')">
<mat-checkbox [(ngModel)]="selectAllMobile" (ngModelChange)="toggleAllNotifications($event, 'mobile')">
</mat-checkbox>
</div>
}
Expand All @@ -82,8 +82,8 @@
@if (showMobilePushColumn) {
<div class="email-notifications--checkbox-col-value">
<mat-checkbox
[ngModel]="notification.push ?? true"
(ngModelChange)="toggleNotification(notification, 'push')"
[ngModel]="notification.mobile ?? true"
(ngModelChange)="toggleNotification(notification, 'mobile')"
>
</mat-checkbox>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export class NotificationsBetaPageService {
.map((notification) => ({
...notification,
email: !unsubscribedEmailEventsByUser.includes(notification.eventEnum),
push: !unsubscribedPushEventsByUser.includes(notification.eventEnum),
mobile: !unsubscribedPushEventsByUser.includes(notification.eventEnum),
}));

const expenseNotifications = processNotifications(this.getExpenseNotifications(currentEou));
Expand Down
Loading