diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index f93984a..2d0adce 100755 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -9,20 +9,22 @@ android { apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { + implementation project(':capacitor-community-facebook-login') + implementation project(':capacitor-community-http') implementation project(':capacitor-app') + implementation project(':capacitor-browser') + implementation project(':capacitor-camera') + implementation project(':capacitor-filesystem') + implementation project(':capacitor-geolocation') implementation project(':capacitor-haptics') implementation project(':capacitor-keyboard') + implementation project(':capacitor-preferences') + implementation project(':capacitor-splash-screen') implementation project(':capacitor-status-bar') - implementation "com.squareup.okhttp3:okhttp-urlconnection:3.10.0" - implementation "com.android.support:support-v4:27.+" - implementation "com.facebook.android:facebook-android-sdk:5.13.0" - implementation "com.google.android.gms:play-services-auth:15.0.1" - implementation "com.google.android.gms:play-services-identity:15.0.1" - implementation "com.google.android.gms:play-services-location:16.+" - implementation "com.onesignal:OneSignal:3.16.0" + implementation project(':codetrix-studio-capacitor-google-auth') + implementation "com.onesignal:OneSignal:5.1.38" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10" } -apply from: "../../node_modules/cordova-plugin-googlemaps/src/android/frameworks/tbxml-android.gradle" -apply from: "../../node_modules/cordova-plugin-googlemaps/src/android/frameworks/pgm-custom.gradle" apply from: "../../node_modules/onesignal-cordova-plugin/build-extras-onesignal.gradle" if (hasProperty('postBuildExtras')) { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4d7ca38..e818f91 100755 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:usesCleartextTraffic="true" + android:networkSecurityConfig="@xml/network_security_config" android:theme="@style/AppTheme"> + + + + + + + + 192.168.10.207 + + diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index bd35873..a9d71e2 100755 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -2,14 +2,41 @@ include ':capacitor-android' project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') +include ':capacitor-community-facebook-login' +project(':capacitor-community-facebook-login').projectDir = new File('../node_modules/@capacitor-community/facebook-login/android') + +include ':capacitor-community-http' +project(':capacitor-community-http').projectDir = new File('../node_modules/@capacitor-community/http/android') + include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') +include ':capacitor-browser' +project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/browser/android') + +include ':capacitor-camera' +project(':capacitor-camera').projectDir = new File('../node_modules/@capacitor/camera/android') + +include ':capacitor-filesystem' +project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android') + +include ':capacitor-geolocation' +project(':capacitor-geolocation').projectDir = new File('../node_modules/@capacitor/geolocation/android') + include ':capacitor-haptics' project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android') include ':capacitor-keyboard' project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android') +include ':capacitor-preferences' +project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android') + +include ':capacitor-splash-screen' +project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android') + include ':capacitor-status-bar' project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') + +include ':codetrix-studio-capacitor-google-auth' +project(':codetrix-studio-capacitor-google-auth').projectDir = new File('../node_modules/@codetrix-studio/capacitor-google-auth/android') diff --git a/android/variables.gradle b/android/variables.gradle index 5946ada..58af7a5 100755 --- a/android/variables.gradle +++ b/android/variables.gradle @@ -1,7 +1,7 @@ ext { minSdkVersion = 22 - compileSdkVersion = 33 - targetSdkVersion = 33 + compileSdkVersion = 34 + targetSdkVersion = 34 androidxActivityVersion = '1.7.0' androidxAppCompatVersion = '1.6.1' androidxCoordinatorLayoutVersion = '1.2.0' diff --git a/capacitor.config.ts b/capacitor.config.ts index d1d227d..9e798d3 100755 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -7,6 +7,11 @@ const config: CapacitorConfig = { server: { androidScheme: 'https' }, + plugins: { + CapacitorHttp: { + enabled: true + } + }, cordova: { preferences: { ScrollEnabled: 'false', diff --git a/package-lock.json b/package-lock.json index 50ac65d..c6dffac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@angular/platform-browser-dynamic": "~18.2.14", "@angular/router": "~18.2.14", "@capacitor-community/facebook-login": "^7.0.1", + "@capacitor-community/http": "^1.4.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/browser": "^6.0.0", @@ -33,6 +34,7 @@ "@ionic/angular": "^8.7.17", "@ngx-translate/core": "~14.0.0", "@ngx-translate/http-loader": "~7.0.0", + "onesignal-cordova-plugin": "^5.2.19", "rxjs": "~7.8.1", "swiper": "^11.2.10", "tslib": "^2.6.0", @@ -3110,6 +3112,45 @@ "tslib": "^2.1.0" } }, + "node_modules/@capacitor-community/http": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@capacitor-community/http/-/http-1.4.1.tgz", + "integrity": "sha512-+pCkBXrwfm97UfjOgjV950H/qZ8SE36Mrcb46BlL1ps3VIsGuIO+AulL8GqTC6LewheRVtGJpRspNtneXQotNA==", + "license": "MIT", + "dependencies": { + "@capacitor/android": "^3.0.0", + "@capacitor/core": "^3.0.0", + "@capacitor/filesystem": "^1.0.0", + "@capacitor/ios": "^3.0.0" + } + }, + "node_modules/@capacitor-community/http/node_modules/@capacitor/android": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.9.0.tgz", + "integrity": "sha512-YTPyrh1NozEuYXWGtfqN27TLXUrLbZX9fggyd4JQ1yMaUZTmLPm5dCuznONhQ49aPkJnUJB02JfpHy/qGwa2Lw==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^3.9.0" + } + }, + "node_modules/@capacitor-community/http/node_modules/@capacitor/core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.9.0.tgz", + "integrity": "sha512-j1lL0+/7stY8YhIq1Lm6xixvUqIn89vtyH5ZpJNNmcZ0kwz6K9eLkcG6fvq1UWMDgSVZg9JrRGSFhb4LLoYOsw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@capacitor-community/http/node_modules/@capacitor/filesystem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.1.0.tgz", + "integrity": "sha512-8O3UuvL8HNUEJvZnmn8yUmvgB1evtXfcF0oxIo3YbSlylqywJwS3JTiuhKmsvSxCdpbTy8IaTsutVh3gZgWbKg==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^3.0.0" + } + }, "node_modules/@capacitor/android": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.2.1.tgz", @@ -3214,6 +3255,15 @@ "@capacitor/core": "^6.0.0" } }, + "node_modules/@capacitor/ios": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.9.0.tgz", + "integrity": "sha512-GezPCJIujRHnF4wbrKJx6Q/mgFz0f9rmh/steTTXQZI+nEl6mHk6NWh8235p7YbhonYi5WD0rFNirrjGg1EaGw==", + "license": "MIT", + "peerDependencies": { + "@capacitor/core": "^3.9.0" + } + }, "node_modules/@capacitor/keyboard": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-6.0.4.tgz", @@ -12587,6 +12637,34 @@ "wrappy": "1" } }, + "node_modules/onesignal-cordova-plugin": { + "version": "5.2.19", + "resolved": "https://registry.npmjs.org/onesignal-cordova-plugin/-/onesignal-cordova-plugin-5.2.19.tgz", + "integrity": "sha512-RGaEJTD3bFwxhsOZNgCB9XR31fLg8fy/PXclXMZfc8ohoKUq6jhEz0aE4AWON9XZx7eO+wbmd3dxn2U5AlZMKg==", + "engines": [ + { + "name": "cordova-android", + "version": ">=4.0.0" + }, + { + "name": "apple-xcode", + "version": ">=8.0.0" + }, + { + "name": "apple-ios", + "version": ">=7.0.0" + }, + { + "name": "cordova", + "version": ">=6.4.0" + }, + { + "name": "cordova-ios", + "version": ">=4.3.0" + } + ], + "license": "MIT" + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -18633,6 +18711,37 @@ } } }, + "@capacitor-community/http": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@capacitor-community/http/-/http-1.4.1.tgz", + "integrity": "sha512-+pCkBXrwfm97UfjOgjV950H/qZ8SE36Mrcb46BlL1ps3VIsGuIO+AulL8GqTC6LewheRVtGJpRspNtneXQotNA==", + "requires": { + "@capacitor/android": "^3.0.0", + "@capacitor/core": "^3.0.0", + "@capacitor/filesystem": "^1.0.0", + "@capacitor/ios": "^3.0.0" + }, + "dependencies": { + "@capacitor/android": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.9.0.tgz", + "integrity": "sha512-YTPyrh1NozEuYXWGtfqN27TLXUrLbZX9fggyd4JQ1yMaUZTmLPm5dCuznONhQ49aPkJnUJB02JfpHy/qGwa2Lw==" + }, + "@capacitor/core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.9.0.tgz", + "integrity": "sha512-j1lL0+/7stY8YhIq1Lm6xixvUqIn89vtyH5ZpJNNmcZ0kwz6K9eLkcG6fvq1UWMDgSVZg9JrRGSFhb4LLoYOsw==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@capacitor/filesystem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.1.0.tgz", + "integrity": "sha512-8O3UuvL8HNUEJvZnmn8yUmvgB1evtXfcF0oxIo3YbSlylqywJwS3JTiuhKmsvSxCdpbTy8IaTsutVh3gZgWbKg==" + } + } + }, "@capacitor/android": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-6.2.1.tgz", @@ -18701,6 +18810,11 @@ "resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-6.0.3.tgz", "integrity": "sha512-6yKF0+lRUZEEx1GDFWgnKHia974np7o1OgmRl/btL9cSMZh0TSDZTyDMH/qcy4AM39CfuIeLs4N4h5lwixXLuQ==" }, + "@capacitor/ios": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.9.0.tgz", + "integrity": "sha512-GezPCJIujRHnF4wbrKJx6Q/mgFz0f9rmh/steTTXQZI+nEl6mHk6NWh8235p7YbhonYi5WD0rFNirrjGg1EaGw==" + }, "@capacitor/keyboard": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-6.0.4.tgz", @@ -25067,6 +25181,11 @@ "wrappy": "1" } }, + "onesignal-cordova-plugin": { + "version": "5.2.19", + "resolved": "https://registry.npmjs.org/onesignal-cordova-plugin/-/onesignal-cordova-plugin-5.2.19.tgz", + "integrity": "sha512-RGaEJTD3bFwxhsOZNgCB9XR31fLg8fy/PXclXMZfc8ohoKUq6jhEz0aE4AWON9XZx7eO+wbmd3dxn2U5AlZMKg==" + }, "onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", diff --git a/package.json b/package.json index 4577c8e..f462c10 100755 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser-dynamic": "~18.2.14", "@angular/router": "~18.2.14", "@capacitor-community/facebook-login": "^7.0.1", + "@capacitor-community/http": "^1.4.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/browser": "^6.0.0", @@ -37,6 +38,7 @@ "@ionic/angular": "^8.7.17", "@ngx-translate/core": "~14.0.0", "@ngx-translate/http-loader": "~7.0.0", + "onesignal-cordova-plugin": "^5.2.19", "rxjs": "~7.8.1", "swiper": "^11.2.10", "tslib": "^2.6.0", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 67302cf..2eda5d1 100755 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -9,6 +9,7 @@ import { LanguageService } from './services/language.service'; import { AlertService } from './services/alert.service'; import { TranslateService } from '@ngx-translate/core'; import { Capacitor } from '@capacitor/core'; +import { OneSignalService } from './services/onesignal.service'; @Component({ selector: 'app-root', @@ -29,9 +30,12 @@ export class AppComponent { private events: EventService, private alertService: AlertService, private loadingCtrl: LoadingController, + private oneSignalService: OneSignalService, ) { this.initializeApp(); this.events.subscribe('set_role', role => { + // Set OneSignal user tags when role is set (user logged in) + this.setupOneSignalUser(role); if (role >= 2){ this.appPages = [ { @@ -104,23 +108,32 @@ export class AppComponent { await StatusBar.setStyle({ style: Style.Light }); await StatusBar.setOverlaysWebView({ overlay: false }); await StatusBar.setBackgroundColor({ color: '#0080ff' }); - // TODO: Implement OneSignal with Capacitor plugin - // this.handlerNotifications(); + + // Initialize OneSignal push notifications + await this.oneSignalService.init(); } this.languageService.getDefaultLanguage(); this.authService.getToken(); } + private async setupOneSignalUser(role: number) { + if (this.authService.token && this.authService.token.user_id) { + await this.oneSignalService.setUserId(this.authService.token.user_id); + await this.oneSignalService.setUserRole(role); + } + } + // When Logout Button is pressed async logout() { this.loading = await this.loadingCtrl.create(); await this.loading.present(); this.authService.logout().subscribe( - data => { + async data => { this.alertService.presentToast(this.translateService.instant('alerts.logout')); - // TODO: Implement OneSignal tag clearing with Capacitor + // Clear OneSignal user tags on logout + await this.oneSignalService.logout(); }, error => { this.loading.dismiss(); @@ -136,7 +149,4 @@ export class AppComponent { async openUrl(url: string) { await Browser.open({ url }); } - - // TODO: Re-implement push notifications with OneSignal Capacitor plugin - // private handlerNotifications() { ... } } diff --git a/src/app/services/env.service.ts b/src/app/services/env.service.ts index 1c5746f..044ac95 100755 --- a/src/app/services/env.service.ts +++ b/src/app/services/env.service.ts @@ -4,13 +4,11 @@ import { Injectable } from '@angular/core'; providedIn: 'root' }) export class EnvService { - // Usa el mismo host pero puerto 8080 para el API - API_URL = (typeof window !== 'undefined' && window.location.hostname !== 'localhost') - ? `http://${window.location.hostname}:8080/api/` - : 'http://localhost:8080/api/'; + API_URL = 'http://192.168.10.207:8080/api/'; SECRET = 'wBIIKuDbrxNKzQhAUGiZLoaoQ4MichAN3wP2AP7B'; MERCHANT_ID = 'm9k4beuso5az0wjqztvt'; PUBLIC_API_KEY = 'pk_9465179493384689a8d2da9adc825411'; + ONESIGNAL_APP_ID = 'c854ae89-7ff7-4216-a70e-5fdff0cd8e10'; constructor() { } } diff --git a/src/app/services/onesignal.service.ts b/src/app/services/onesignal.service.ts new file mode 100644 index 0000000..a5e7d4b --- /dev/null +++ b/src/app/services/onesignal.service.ts @@ -0,0 +1,132 @@ +import { Injectable } from '@angular/core'; +import { Capacitor } from '@capacitor/core'; +import { EnvService } from './env.service'; +import { Router } from '@angular/router'; + +declare var OneSignalPlugin: any; + +@Injectable({ + providedIn: 'root' +}) +export class OneSignalService { + private initialized = false; + + constructor( + private env: EnvService, + private router: Router + ) { } + + async init(): Promise { + if (this.initialized || !Capacitor.isNativePlatform()) { + return; + } + + try { + // Initialize OneSignal + OneSignalPlugin.initialize(this.env.ONESIGNAL_APP_ID); + + // Request notification permission + OneSignalPlugin.Notifications.requestPermission(true).then((accepted: boolean) => { + console.log('OneSignal notification permission:', accepted ? 'accepted' : 'denied'); + }); + + // Handle notification clicks + OneSignalPlugin.Notifications.addEventListener('click', (event: any) => { + console.log('OneSignal notification clicked:', event); + this.handleNotificationClick(event); + }); + + // Handle foreground notifications + OneSignalPlugin.Notifications.addEventListener('foregroundWillDisplay', (event: any) => { + console.log('OneSignal notification received in foreground:', event); + // Display the notification + event.getNotification().display(); + }); + + this.initialized = true; + console.log('OneSignal initialized successfully'); + } catch (error) { + console.error('Error initializing OneSignal:', error); + } + } + + async setUserId(userId: number | string): Promise { + if (!Capacitor.isNativePlatform()) { + return; + } + + try { + // Set user tag for targeting + OneSignalPlugin.User.addTag('iChamba_ID', String(userId)); + console.log('OneSignal user tag set:', userId); + } catch (error) { + console.error('Error setting OneSignal user tag:', error); + } + } + + async setUserRole(roleId: number | string): Promise { + if (!Capacitor.isNativePlatform()) { + return; + } + + try { + OneSignalPlugin.User.addTag('iChamba_Role', String(roleId)); + console.log('OneSignal role tag set:', roleId); + } catch (error) { + console.error('Error setting OneSignal role tag:', error); + } + } + + async clearTags(): Promise { + if (!Capacitor.isNativePlatform()) { + return; + } + + try { + OneSignalPlugin.User.removeTags(['iChamba_ID', 'iChamba_Role']); + console.log('OneSignal tags cleared'); + } catch (error) { + console.error('Error clearing OneSignal tags:', error); + } + } + + async logout(): Promise { + await this.clearTags(); + } + + private handleNotificationClick(event: any): void { + const data = event?.notification?.additionalData; + + if (data) { + // Handle navigation based on notification data + if (data.route) { + this.router.navigate([data.route]); + } else if (data.type) { + switch (data.type) { + case 'contract': + this.router.navigate(['/contracts']); + break; + case 'postulation': + this.router.navigate(['/postulations']); + break; + default: + this.router.navigate(['/dashboard']); + } + } + } + } + + async getPlayerId(): Promise { + if (!Capacitor.isNativePlatform()) { + return null; + } + + try { + const deviceState = await OneSignalPlugin.User.pushSubscription.getId(); + return deviceState || null; + } catch (error) { + console.error('Error getting OneSignal player ID:', error); + return null; + } + } +}