mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[MOBILEAPPS-1701] Custom URL schema issues fixed (#2998)
* Custom URL schema issues * code implementation changes for checkForMobileAppFlag * updated test cases * requested changed addressed * requested changed addressed * cspell changes * review comments addressed
This commit is contained in:
parent
472a19b67d
commit
04907df376
130
cspell.json
130
cspell.json
@ -2,82 +2,84 @@
|
||||
"version": "0.1",
|
||||
"language": "en",
|
||||
"words": [
|
||||
"Kerberos",
|
||||
"succes",
|
||||
"sharedlinks",
|
||||
"Redistributable",
|
||||
"fullscreen",
|
||||
"LGPL",
|
||||
"mincount",
|
||||
"QNAME",
|
||||
"PNAME",
|
||||
"ADDFEATURES",
|
||||
"CHECKIN",
|
||||
"thumbnailed",
|
||||
"superadmin",
|
||||
"SUPERADMIN",
|
||||
"hruser",
|
||||
"salesuser",
|
||||
"networkidle",
|
||||
"domcontentloaded",
|
||||
"mimetype",
|
||||
|
||||
"ngrx",
|
||||
"ngstack",
|
||||
"sidenav",
|
||||
"injectable",
|
||||
"iosamw",
|
||||
"truthy",
|
||||
"cryptodoc",
|
||||
"mysites",
|
||||
"afts",
|
||||
"androidamw",
|
||||
"cardview",
|
||||
"CHECKIN",
|
||||
"classlist",
|
||||
"folderlink",
|
||||
"filelink",
|
||||
"formcontrolname",
|
||||
"datetimepicker",
|
||||
"cryptodoc",
|
||||
"datatable",
|
||||
"repo",
|
||||
"snackbar",
|
||||
"promisify",
|
||||
"xdescribe",
|
||||
"unfavorite",
|
||||
"dateitem",
|
||||
"datetimepicker",
|
||||
"denysvuika",
|
||||
"devtools",
|
||||
"gitter",
|
||||
"jira",
|
||||
"markdownlint",
|
||||
"uploader",
|
||||
"nginx",
|
||||
"docx",
|
||||
"SOLR",
|
||||
"simpletask",
|
||||
"titlecase",
|
||||
|
||||
"unshare",
|
||||
"qshare",
|
||||
"validators",
|
||||
"domcontentloaded",
|
||||
"errored",
|
||||
"erroredSpy",
|
||||
"exif",
|
||||
"filelink",
|
||||
"folderlink",
|
||||
"formcontrolname",
|
||||
"fullscreen",
|
||||
"gitter",
|
||||
"guid",
|
||||
"hruser",
|
||||
"injectable",
|
||||
"iosamw",
|
||||
"jira",
|
||||
"jsonp",
|
||||
"Kerberos",
|
||||
"keycodes",
|
||||
"LGPL",
|
||||
"markdownlint",
|
||||
"mimetype",
|
||||
"mincount",
|
||||
"mobileapps",
|
||||
"mysites",
|
||||
"networkidle",
|
||||
"nginx",
|
||||
"ngrx",
|
||||
"ngstack",
|
||||
"noderef",
|
||||
"pdfjs",
|
||||
"PNAME",
|
||||
"polyfill",
|
||||
"polyfills",
|
||||
"jsonp",
|
||||
"pdfjs",
|
||||
"xpath",
|
||||
"tooltip",
|
||||
"tooltips",
|
||||
"unindent",
|
||||
"exif",
|
||||
"cardview",
|
||||
"webm",
|
||||
"keycodes",
|
||||
"denysvuika",
|
||||
"promisify",
|
||||
"QNAME",
|
||||
"qshare",
|
||||
"Redistributable",
|
||||
"repo",
|
||||
"salesuser",
|
||||
"sharedlinks",
|
||||
"sidenav",
|
||||
"simpletask",
|
||||
"snackbar",
|
||||
"SOLR",
|
||||
"submenu",
|
||||
"submenus",
|
||||
"dateitem",
|
||||
"succes",
|
||||
"superadmin",
|
||||
"thumbnailed",
|
||||
"titlecase",
|
||||
"tooltip",
|
||||
"tooltips",
|
||||
"truthy",
|
||||
"unfavorite",
|
||||
"unindent",
|
||||
"unshare",
|
||||
"uploader",
|
||||
"validators",
|
||||
"versionable",
|
||||
"erroredSpy",
|
||||
"errored",
|
||||
"noderef"
|
||||
"webm",
|
||||
"xdescribe",
|
||||
"xpath"
|
||||
],
|
||||
"dictionaries": ["html", "en-gb", "en_US"]
|
||||
"dictionaries": [
|
||||
"html",
|
||||
"en-gb",
|
||||
"en_US"
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<div class="container">
|
||||
<button mat-button (click)="openInApp()" data-automation-id="open-in-app-button">
|
||||
<span>{{ 'APP.DIALOGS.MOBILE_APP.MOBILE_APP_BUTTON_LABEL' }}</span>
|
||||
<button mat-button (click)="openInApp()" data-automation-id="open-in-app-button" class="open-in-app">
|
||||
<span>{{ 'APP.DIALOGS.MOBILE_APP.MOBILE_APP_BUTTON_LABEL' | translate }}</span>
|
||||
</button>
|
||||
<button mat-button mat-dialog-close>
|
||||
<button mat-button (click)="onCloseDialog()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -6,8 +6,12 @@
|
||||
}
|
||||
|
||||
.mat-dialog-container{
|
||||
padding: 12px;
|
||||
padding: 5px;
|
||||
border-radius: 36px;
|
||||
background-color: var(--theme-blue-button-color);
|
||||
color: var(--theme-about-panel-background-color);
|
||||
}
|
||||
|
||||
.open-in-app.mat-button {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
@ -1,16 +1,29 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { OpenInAppComponent } from './open-in-app.component';
|
||||
import { initialState, LibTestingModule } from '../../testing/lib-testing-module';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
describe('OpenInAppComponent', () => {
|
||||
let fixture: ComponentFixture<OpenInAppComponent>;
|
||||
let component: OpenInAppComponent;
|
||||
|
||||
const mockDialogRef = {
|
||||
close: jasmine.createSpy('close'),
|
||||
open: jasmine.createSpy('open')
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [OpenInAppComponent],
|
||||
providers: [{ provide: MAT_DIALOG_DATA, useValue: { redirectUrl: 'mockRedirectUrl' } }]
|
||||
imports: [LibTestingModule, TranslateModule],
|
||||
providers: [
|
||||
provideMockStore({ initialState }),
|
||||
{ provide: MAT_DIALOG_DATA, useValue: { redirectUrl: 'mockRedirectUrl' } },
|
||||
{ provide: MatDialogRef, useValue: mockDialogRef }
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(OpenInAppComponent);
|
||||
@ -35,4 +48,11 @@ describe('OpenInAppComponent', () => {
|
||||
|
||||
expect(currentLocation).toBe('mockRedirectUrl');
|
||||
});
|
||||
|
||||
it('should set the value `mobile_notification_expires_in` in session storage on dialog close', async () => {
|
||||
sessionStorage.clear();
|
||||
component.onCloseDialog();
|
||||
expect(sessionStorage.getItem('mobile_notification_expires_in')).not.toBeNull();
|
||||
expect(mockDialogRef.close).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
export interface OpenInAppDialogOptions {
|
||||
redirectUrl: string;
|
||||
@ -41,7 +41,8 @@ export class OpenInAppComponent {
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: OpenInAppDialogOptions
|
||||
public data: OpenInAppDialogOptions,
|
||||
private dialog: MatDialogRef<OpenInAppComponent>
|
||||
) {
|
||||
if (data) {
|
||||
this.redirectUrl = data.redirectUrl;
|
||||
@ -51,4 +52,10 @@ export class OpenInAppComponent {
|
||||
openInApp(): void {
|
||||
this.window.location.href = this.redirectUrl;
|
||||
}
|
||||
|
||||
onCloseDialog(): void {
|
||||
const time: number = new Date().getTime();
|
||||
sessionStorage.setItem('mobile_notification_expires_in', time.toString());
|
||||
this.dialog.close();
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ describe('AcaMobileAppSwitcherService', () => {
|
||||
spyOnProperty(window.navigator, 'userAgent').and.returnValue('iphone');
|
||||
const url: string = window.location.href;
|
||||
const iphoneUrl: string = appConfig.config.mobileAppSwitch.iphoneUrl + url;
|
||||
service.showAppNotification();
|
||||
service.identifyBrowserAndSetRedirectURL();
|
||||
expect(service.redirectUrl).toEqual(iphoneUrl);
|
||||
});
|
||||
|
||||
@ -68,38 +68,49 @@ describe('AcaMobileAppSwitcherService', () => {
|
||||
spyOnProperty(window.navigator, 'userAgent').and.returnValue('android');
|
||||
const url: string = window.location.href;
|
||||
const androidUrl: string = appConfig.config.mobileAppSwitch.androidUrlPart1 + url + appConfig.config.mobileAppSwitch.androidUrlPart2;
|
||||
service.showAppNotification();
|
||||
service.identifyBrowserAndSetRedirectURL();
|
||||
expect(service.redirectUrl).toEqual(androidUrl);
|
||||
});
|
||||
|
||||
it('should check if `showAppNotification` function is called', () => {
|
||||
const showAppNotificationSpy: jasmine.Spy<() => void> = spyOn(service, 'showAppNotification');
|
||||
service.checkForMobileApp();
|
||||
expect(showAppNotificationSpy).toHaveBeenCalled();
|
||||
it('should check if `identifyBrowserAndSetRedirectURL` function is called', () => {
|
||||
const identifyBrowserAndSetRedirectURLSpy: jasmine.Spy<() => void> = spyOn(service, 'identifyBrowserAndSetRedirectURL');
|
||||
service.resolveExistenceOfDialog();
|
||||
expect(identifyBrowserAndSetRedirectURLSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not display `openInApp` dialog box when timeDifference is less than the session time', () => {
|
||||
service.checkForMobileApp();
|
||||
const showAppNotificationSpy: jasmine.Spy<() => void> = spyOn(service, 'showAppNotification');
|
||||
service.checkForMobileApp();
|
||||
expect(showAppNotificationSpy).not.toHaveBeenCalled();
|
||||
it('should not display `openInApp` dialog box after closing the same and time difference less than session time', () => {
|
||||
const time: number = new Date().getTime();
|
||||
sessionStorage.setItem('mobile_notification_expires_in', time.toString());
|
||||
const identifyBrowserAndSetRedirectURLSpy: jasmine.Spy<() => void> = spyOn(service, 'identifyBrowserAndSetRedirectURL');
|
||||
service.verifySessionExistsForDialog();
|
||||
expect(identifyBrowserAndSetRedirectURLSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should check if `openInApp` dialog box is getting opened with `iphone` url', () => {
|
||||
const openInAppSpy: jasmine.Spy<(redirectUrl: string) => void> = spyOn(service, 'openInApp');
|
||||
const url: string = window.location.href;
|
||||
service.redirectUrl = appConfig.config.mobileAppSwitch.iphoneUrl + url;
|
||||
service.showAppNotification();
|
||||
expect(openInAppSpy).toHaveBeenCalled();
|
||||
service.identifyBrowserAndSetRedirectURL();
|
||||
expect(mockDialogRef.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should check if `openInApp` dialog box is getting opened with `android` url', () => {
|
||||
const openInAppSpy: jasmine.Spy<(redirectUrl: string) => void> = spyOn(service, 'openInApp');
|
||||
const url: string = window.location.href;
|
||||
service.redirectUrl = appConfig.config.mobileAppSwitch.androidUrlPart1 + url + appConfig.config.mobileAppSwitch.androidUrlPart2;
|
||||
service.showAppNotification();
|
||||
expect(openInAppSpy).toHaveBeenCalled();
|
||||
service.identifyBrowserAndSetRedirectURL();
|
||||
expect(mockDialogRef.open).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not display Open in app dialog when the web application is opened within mobile application', () => {
|
||||
spyOn(service, 'getCurrentUrl').and.returnValue('localhost?mobileapps=true');
|
||||
const verifySessionExistsForDialogSpy: jasmine.Spy<() => void> = spyOn(service, 'verifySessionExistsForDialog');
|
||||
service.resolveExistenceOfDialog();
|
||||
expect(verifySessionExistsForDialogSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should display Open in app dialog when the web application is opened in mobile browser', () => {
|
||||
spyOn(service, 'getCurrentUrl').and.returnValue('localhost');
|
||||
const verifySessionExistsForDialogSpy: jasmine.Spy<() => void> = spyOn(service, 'verifySessionExistsForDialog');
|
||||
service.resolveExistenceOfDialog();
|
||||
expect(verifySessionExistsForDialogSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -46,31 +46,42 @@ export class AcaMobileAppSwitcherService {
|
||||
this.mobileAppSwitchConfig = this.config.get<MobileAppSwitchConfigurationOptions>('mobileAppSwitch');
|
||||
}
|
||||
|
||||
checkForMobileApp(): void {
|
||||
const currentTime: number = new Date().getTime();
|
||||
const sessionTime: string = sessionStorage.getItem('mobile_notification_expires_in');
|
||||
resolveExistenceOfDialog(): void {
|
||||
const url: string = this.getCurrentUrl();
|
||||
const queryParams: string = url.split('?')[1];
|
||||
let queryParamsList = [];
|
||||
let hideBanner = false;
|
||||
if (queryParams !== null && queryParams !== undefined) {
|
||||
queryParamsList = queryParams.split('&');
|
||||
hideBanner = queryParamsList.some((param) => param.split('=')[0] === 'mobileapps' && param.split('=')[1] === 'true');
|
||||
}
|
||||
if (!hideBanner) {
|
||||
this.verifySessionExistsForDialog();
|
||||
}
|
||||
}
|
||||
|
||||
verifySessionExistsForDialog(): void {
|
||||
const sessionTime: string = sessionStorage.getItem('mobile_notification_expires_in');
|
||||
if (sessionTime !== null) {
|
||||
const currentTime: number = new Date().getTime();
|
||||
const sessionConvertedTime: number = parseFloat(sessionTime);
|
||||
const timeDifference: number = (currentTime - sessionConvertedTime) / (1000 * 60 * 60);
|
||||
const sessionTimeForOpenAppDialogDisplay: number = parseFloat(this.mobileAppSwitchConfig.sessionTimeForOpenAppDialogDisplay);
|
||||
|
||||
if (timeDifference > sessionTimeForOpenAppDialogDisplay) {
|
||||
this.showAppNotification();
|
||||
this.clearSessionExpireTime();
|
||||
this.identifyBrowserAndSetRedirectURL();
|
||||
}
|
||||
} else {
|
||||
this.showAppNotification();
|
||||
this.identifyBrowserAndSetRedirectURL();
|
||||
}
|
||||
}
|
||||
|
||||
showAppNotification(): void {
|
||||
identifyBrowserAndSetRedirectURL(): void {
|
||||
const ua: string = navigator.userAgent.toLowerCase();
|
||||
const isAndroid: boolean = ua.indexOf('android') > -1;
|
||||
const isIOS: boolean = ua.indexOf('iphone') > -1 || ua.indexOf('ipad') > -1 || ua.indexOf('ipod') > -1;
|
||||
const currentUrl: string = window.location.href;
|
||||
const time: number = new Date().getTime();
|
||||
|
||||
sessionStorage.setItem('mobile_notification_expires_in', time.toString());
|
||||
const currentUrl: string = this.getCurrentUrl();
|
||||
|
||||
if (isIOS === true) {
|
||||
this.redirectUrl = this.mobileAppSwitchConfig.iphoneUrl + currentUrl;
|
||||
@ -79,22 +90,27 @@ export class AcaMobileAppSwitcherService {
|
||||
}
|
||||
|
||||
if (this.redirectUrl !== undefined && this.redirectUrl !== null) {
|
||||
this.openInApp(this.redirectUrl);
|
||||
this.openDialog(this.redirectUrl);
|
||||
}
|
||||
}
|
||||
|
||||
openInApp(redirectUrl: string): void {
|
||||
openDialog(redirectUrl: string): void {
|
||||
this.dialog.open(OpenInAppComponent, {
|
||||
data: {
|
||||
redirectUrl
|
||||
},
|
||||
width: '75%',
|
||||
hasBackdrop: false,
|
||||
width: 'auto',
|
||||
role: 'dialog',
|
||||
position: { bottom: '50px' }
|
||||
position: { bottom: '20px' }
|
||||
});
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
clearSessionExpireTime(): void {
|
||||
sessionStorage.removeItem('mobile_notification_expires_in');
|
||||
}
|
||||
|
||||
getCurrentUrl(): string {
|
||||
return window.location.href;
|
||||
}
|
||||
}
|
||||
|
@ -182,9 +182,9 @@ export class AppService implements OnDestroy {
|
||||
|
||||
const isMobileSwitchEnabled: boolean = this.config.get<boolean>('mobileAppSwitch.enabled', false);
|
||||
if (isMobileSwitchEnabled) {
|
||||
this.acaMobileAppSwitcherService.checkForMobileApp();
|
||||
this.acaMobileAppSwitcherService.resolveExistenceOfDialog();
|
||||
} else {
|
||||
this.acaMobileAppSwitcherService.reset();
|
||||
this.acaMobileAppSwitcherService.clearSessionExpireTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,11 @@ import { OpenInAppComponent } from './components/open-in-app/open-in-app.compone
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@NgModule({
|
||||
imports: [ContextActionsModule, MatButtonModule, MatIconModule, MatDialogModule],
|
||||
exports: [ContextActionsModule, MatButtonModule, MatIconModule, MatDialogModule],
|
||||
imports: [ContextActionsModule, MatButtonModule, MatIconModule, MatDialogModule, TranslateModule],
|
||||
exports: [ContextActionsModule, MatButtonModule, MatIconModule, MatDialogModule, TranslateModule],
|
||||
declarations: [OpenInAppComponent]
|
||||
})
|
||||
export class SharedModule {
|
||||
|
Loading…
x
Reference in New Issue
Block a user