diff --git a/config.xml b/config.xml index 7cb062033..2e850bb20 100644 --- a/config.xml +++ b/config.xml @@ -3,7 +3,7 @@ gabinete digital An awesome Ionic/Cordova app. Ionic Framework Team - + diff --git a/package.json b/package.json index 79c8f5d4b..86a9f4d4c 100644 --- a/package.json +++ b/package.json @@ -197,4 +197,4 @@ "url": "git+https://Kayaya@bitbucket.org/equilibriumito/gabinete-digital.git" }, "license": "ISC" -} \ No newline at end of file +} diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts index baae9d136..32b6ca111 100644 --- a/src/app/home/home.page.ts +++ b/src/app/home/home.page.ts @@ -22,6 +22,9 @@ import { DocumentCounterService } from '../services/worker/document-counter.serv import { PermissionService } from '../services/worker/permission.service'; import { Network } from '@ionic-native/network/ngx'; import { BackgroundService } from 'src/app/services/background.service'; +import { OfflineManagerService } from 'src/app/services/offline-manager.service'; +import { Storage } from '@ionic/storage'; +import { EventsService} from 'src/app/services/events.service'; @Component({ @@ -82,7 +85,10 @@ export class HomePage implements OnInit { private storageService: StorageService, private webNotificationPopupService: WebNotificationPopupService, private network: Network, - private backgroundservice: BackgroundService) { + private backgroundservice: BackgroundService, + private offlinemanager: OfflineManagerService, + private storage: Storage, + private eventservice: EventsService ) { this.webNotificationPopupService.askNotificationPermission() @@ -124,6 +130,35 @@ export class HomePage implements OnInit { this.webnotification.webconnection(); this.webnotification.register(); } else { + window.addEventListener('online', (on) => { + console.log('Became online',on) + this.storage.get('storedreq').then((req) =>{ + console.log('STORED REQUEST', req) + req.forEach(element => { + this.eventservice.editEvent(element,2,3).subscribe((res) =>{ + console.log('REQUEST RESULT', res) + }) + }); + + }) + this.backgroundservice.online() + }); + window.addEventListener('offline', (off) => { + console.log('Became offline',off) + this.backgroundservice.offline() + }); + if(synchro.connected === true) { + //this.offlinemanager.checkForEvents().subscribe(); + this.storage.get('storedreq').then((req) =>{ + console.log('STORED REQUEST', req) + req.forEach(element => { + this.eventservice.editEvent(element,2,3).subscribe((res) =>{ + console.log('REQUEST RESULT', res) + }) + }); + + }) + } this.mobilefirstConnect(); this.notificationsService.onReceviNotification(); } diff --git a/src/app/pages/agenda/view-event/view-event.page.ts b/src/app/pages/agenda/view-event/view-event.page.ts index 25775dc21..6207418a2 100644 --- a/src/app/pages/agenda/view-event/view-event.page.ts +++ b/src/app/pages/agenda/view-event/view-event.page.ts @@ -100,22 +100,7 @@ export class ViewEventPage implements OnInit { } ngOnInit() { - if(synchro.connected === true) { - this.loadEvent(); - console.log('Onlineee view-event') - } else { - this.sqliteservice.getEventById(this.eventId).then((event) => { - this.loadedEvent = event[0]; - console.log("Event ditails local,", event[0]) - }) - console.log('Offlineee') - } - - /* this.sqliteservice.getEventById(this.eventId).then((event) => { - this.loadedEvent = event[0]; - console.log("Event ditails local,", event[0]) - }) - this.loadEvent(); */ + this.getFromDb(); window.onresize = (event) => { @@ -158,7 +143,7 @@ export class ViewEventPage implements OnInit { const loader = this.toastService.loading(); this.eventsService.getEvent(this.eventId).subscribe(res => { this.loadedEvent = res; - this.sqliteservice.addEvent(res); + this.addEventToDb(res); console.log('Loaded one event', res) /* this.today = new Date(res.StartDate); this.customDate = this.days[this.today.getDay()]+ ", " + this.today.getDate() +" de " + ( this.months[this.today.getMonth()]); */ @@ -380,25 +365,64 @@ export class ViewEventPage implements OnInit { } + + addEventToDb(data) { + let event = { + Attendees: JSON.stringify(data.Attendees) || JSON.stringify(''), + Body: JSON.stringify(data.Body) || JSON.stringify(''), + CalendarId: data.CalendarId, + CalendarName: data.CalendarName, + Category: data.Category, + EndDate: data.EndDate, + EventId: data.EventId, + EventRecurrence: JSON.stringify(data.EventRecurrence) || JSON.stringify(''), + EventType: data.EventType, + HasAttachments: data.HasAttachments, + IsAllDayEvent: data.IsAllDayEvent, + IsMeeting: data.IsMeeting, + IsRecurring: data.IsRecurring, + Location: data.Location, + Organizer: JSON.stringify(data.Organizer) || JSON.stringify(''), + StartDate: data.StartDate, + Subject: data.Subject, + TimeZone: data.TimeZone + } - getEventsFromLocalDb() { - console.log("event id details ", this.eventId) + this.sqliteservice.updateEvent(event); + } - synchro.registerCallback('Online', () => { + + getFromDb() { + if (synchro.connected === true) { this.loadEvent(); console.log('Onlineee view-event') - - }) - - synchro.registerCallback('Offline', () => { - this.platform.ready().then(() => { - this.sqliteservice.getEventById(this.eventId).then((event) => { - this.loadedEvent = event[0]; - console.log("Event ditails local,", event[0]) - }) - console.log('Offlineee') + } else { + this.sqliteservice.getEventById(this.eventId).then((event) => { + let arrayevent = []; + let elemet = { + Attendees: JSON.parse(event[0].Attendees) || "", + Body: JSON.parse(event[0].Body) || "", + CalendarId: event[0].CalendarId, + CalendarName: event[0].CalendarName, + Category: event[0].Category, + EndDate: event[0].EndDate, + EventId: event[0].EventId, + EventRecurrence: JSON.parse(event[0].EventRecurrence) || "", + EventType: event[0].EventType, + HasAttachments: event[0].HasAttachments, + IsAllDayEvent: event[0].IsAllDayEvent, + IsMeeting: event[0].IsMeeting, + IsRecurring: event[0].IsRecurring, + Location: event[0].Location, + Organizer: JSON.parse(event[0].Organizer) || "", + StartDate: event[0].StartDate, + Subject: event[0].Subject, + TimeZone: event[0].TimeZone + } + arrayevent.push(elemet); + this.loadedEvent = arrayevent[0]; + console.log("Event ditails local,", elemet) }) - - }) - } -} + console.log('Offlineee') + } + }} diff --git a/src/app/pages/events/events.page.ts b/src/app/pages/events/events.page.ts index ffcc423df..dfb0f61cd 100644 --- a/src/app/pages/events/events.page.ts +++ b/src/app/pages/events/events.page.ts @@ -18,7 +18,7 @@ import { ExpedienteTaskPipe } from 'src/app/pipes/expediente-task.pipe'; import { ExpedienteGdStore } from 'src/app/store/expedientegd-store.service'; import { SqliteService } from 'src/app/services/sqlite.service'; import { synchro } from '../../services/socket/synchro.service'; -import { BackgroundService } from 'src/app/services/background.service' +import { NetworkConnectionService } from 'src/app/services/network-connection.service' @Component({ selector: 'app-events', @@ -69,7 +69,7 @@ export class EventsPage implements OnInit { expedienteGdStore = ExpedienteGdStore listToPresent = []; - listToPresentexpediente =[] + listToPresentexpediente = [] expedienteTaskPipe = new ExpedienteTaskPipe() @@ -93,7 +93,7 @@ export class EventsPage implements OnInit { private screenOrientation: ScreenOrientation, public platform: Platform, private sqliteservice: SqliteService, - private backgroundservice: BackgroundService + private networkconnection: NetworkConnectionService ) { this.existingScreenOrientation = this.screenOrientation.type; console.log(this.existingScreenOrientation); @@ -108,15 +108,14 @@ export class EventsPage implements OnInit { }); - /* if (this.platform.is('desktop') || this.platform.is('mobileweb')) { + if (this.platform.is('desktop') || this.platform.is('mobileweb')) { } else { try { this.sqliteservice.databaseConn(); } catch (error) { console.log("Error creating local database: ", error) } - } */ - + } } ngOnInit() { @@ -124,21 +123,19 @@ export class EventsPage implements OnInit { this.segment = "Combinada"; this.profile = "mdgpr"; - if (this.platform.is('desktop') || this.platform.is('mobileweb')) { - this.showGreeting(); + this.showGreeting(); - this.router.events.forEach((event) => { - if (event instanceof NavigationEnd && event.url == '/home/events') { - this.RefreshEvents(); - setTimeout(() => { - this.LoadList(); - }, 1500) - } - }); - this.hideSearch(); - } + this.router.events.forEach((event) => { + if (event instanceof NavigationEnd && event.url == '/home/events') { + this.RefreshEvents(); + setTimeout(() => { + this.LoadList(); + }, 1500) + } + }); + this.hideSearch(); - this.getEventsFromLocalDb(); + //this.getEventsFromLocalDb(); //this.checkScreenOrientation(); @@ -206,7 +203,7 @@ export class EventsPage implements OnInit { console.log("getAllMdOficialPessoalEvents", list) if (this.platform.is('desktop') || this.platform.is('mobileweb')) { } else { - if(list.length > 0) { + if (list.length > 0) { list.forEach(element => { this.sqliteservice.addEvent(element) }); @@ -234,7 +231,7 @@ export class EventsPage implements OnInit { console.log("getAllPrOficialPessoalEvents", list) if (this.platform.is('desktop') || this.platform.is('mobileweb')) { } else { - if(list.length > 0) { + if (list.length > 0) { list.forEach(element => { this.sqliteservice.addEvent(element) }); @@ -324,21 +321,26 @@ export class EventsPage implements OnInit { getEventsFromLocalDb() { - if (synchro.connected === true) { - this.showGreeting(); + /* window.addEventListener('online', (on) => { + this.showGreeting(); + + this.router.events.forEach((event) => { + if (event instanceof NavigationEnd && event.url == '/home/events') { + this.RefreshEvents(); + setTimeout(() => { + this.LoadList(); + + }, 1500) + } + }); + this.hideSearch(); + }); */ - this.router.events.forEach((event) => { - if (event instanceof NavigationEnd && event.url == '/home/events') { - this.RefreshEvents(); - setTimeout(() => { - this.LoadList(); - }, 1500) - } - }); - this.hideSearch(); - } else { - this.platform.ready().then(async () => { - this.sqliteservice.getAllEvents().then((event:any[]) => { + // window.addEventListener('offline', (off) => { + if (this.platform.is('desktop') || this.platform.is('mobileweb')) { + + } else { + this.sqliteservice.getAllEvents().then((event: any[]) => { this.listToPresent = event this.totalEvent = this.listToPresent.length this.currentEvent = this.listToPresent[0].Subject @@ -346,29 +348,39 @@ export class EventsPage implements OnInit { console.log("All events from local,", event) }) - this.sqliteservice.getprocessByworkflow("Expediente").then((process: any[]) => { - var expedientlist = []; - process.forEach((element) => { - let task = { - CreateDate: element.taskStartDate, - DocumentsQty: element.totalDocuments, - Senders: JSON.parse(element.workflowInstanceDataFields).Sender, - SerialNumber: element.serialNumber, - Status: JSON.parse(element.workflowInstanceDataFields).Status, - Subject: JSON.parse(element.workflowInstanceDataFields).Subject, - WorkflowName: element.workflowDisplayName, - activityInstanceName: element.activityInstanceName, - taskStartDate: element.taskStartDate, - } - expedientlist.push(task); - }) - const ExpedienteTask = expedientlist.map(e => this.expedienteTaskPipe.transform(e)) - this.listToPresentexpediente = ExpedienteTask; - - + this.sqliteservice.getAllProcess().then((res) => { + console.log('INICION ALL EVENTs', res) + }) + this.sqliteservice.getprocessByworkflow("Expediente").then((process: any[]) => { + + console.log('OFOFOFOOF', process) + + if (process.length > 0 || process != undefined) { + + var expedientlist: any = new Array(); + process.forEach((element) => { + let task = { + activityInstanceName: element.activityInstanceName, + deadline: null, + serialNumber: element.serialNumber, + taskStartDate: element.taskStartDate, + totalDocuments: element.totalDocuments, + workflowDisplayName: element.workflowDisplayName, + workflowInstanceDataFields: JSON.parse(element.workflowInstanceDataFields) + } + expedientlist.push(task); + }) + + console.log('OFOFOFOOF22222', expedientlist) + const ExpedienteTask = expedientlist.map(e => this.expedienteTaskPipe.transform(e)) + this.listToPresentexpediente = ExpedienteTask; + + } + + this.showLoader = false; }) - }); } + // }); } @@ -426,10 +438,13 @@ export class EventsPage implements OnInit { LoadList() { this.processes.GetTaskListExpediente(false).subscribe(result => { console.log("Expediente", result); + if (this.platform.is('desktop') || this.platform.is('mobileweb')) { - + } else { - this.sqliteservice.addProcess(result) + result.forEach((element) => { + this.sqliteservice.addProcess(element) + }) } const ExpedienteTask = result.map(e => this.expedienteTaskPipe.transform(e)) @@ -437,7 +452,10 @@ export class EventsPage implements OnInit { console.log("Expediente 2", ExpedienteTask); this.listToPresentexpediente = ExpedienteTask; - }); + }, ((error) => { + console.log('Getlist error', error) + this.getEventsFromLocalDb(); + })); } sortArrayISODate(myArray: any) { diff --git a/src/app/services/events.service.ts b/src/app/services/events.service.ts index c20aae32d..f2d3221e3 100644 --- a/src/app/services/events.service.ts +++ b/src/app/services/events.service.ts @@ -1,12 +1,16 @@ import { Injectable } from '@angular/core'; import { Event, EventToApproveEdit } from '../models/event.model'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; +import { Observable, from} from 'rxjs'; import { environment } from 'src/environments/environment'; import { AuthService } from '../services/auth.service'; import { UserSession } from '../models/user.model'; import { EventList } from '../models/agenda/AgendaEventList'; import { ChangeProfileService } from './change-profile.service'; +import { OfflineManagerService } from 'src/app/services/offline-manager.service'; +import { synchro } from 'src/app/services/socket/synchro.service'; +import { catchError } from "rxjs/operators"; +import { Storage } from '@ionic/storage'; @Injectable({ @@ -30,7 +34,9 @@ export class EventsService { constructor( private http: HttpClient, public user: AuthService, - private changeProfileService: ChangeProfileService) + private changeProfileService: ChangeProfileService, + private offlinemanager: OfflineManagerService, + private storage: Storage) { this.loggeduser = this.user.ValidatedUser; @@ -306,40 +312,50 @@ export class EventsService { editEvent(event: Event, conflictResolutionMode:number, sendInvitationsOrCancellationsMode:number): Observable { + let arrayReq = []; const puturl = environment.apiURL + 'calendar/PutEvent'; + if(synchro.connected === false) { + arrayReq.push(event) + return from(this.storage.set('storedreq', arrayReq)) + } else { + let params = new HttpParams(); - let params = new HttpParams(); - - params = params.set("conflictResolutionMode", conflictResolutionMode.toString()); - params = params.set("sendInvitationsOrCancellationsMode", sendInvitationsOrCancellationsMode.toString()); - params.set('CalendarId', event.CalendarId) - params.set('CalendarName', event.CalendarName) - this.headers['CalendarId'] = event.CalendarId - this.headers['CalendarName'] = event.CalendarName - - if(event.CalendarName == 'Oficial'){ - if(this.loggeduser.Profile == 'MDGPR'){ - this.headers = this.headersMdOficial; + params = params.set("conflictResolutionMode", conflictResolutionMode.toString()); + params = params.set("sendInvitationsOrCancellationsMode", sendInvitationsOrCancellationsMode.toString()); + params.set('CalendarId', event.CalendarId) + params.set('CalendarName', event.CalendarName) + this.headers['CalendarId'] = event.CalendarId + this.headers['CalendarName'] = event.CalendarName + + if(event.CalendarName == 'Oficial'){ + if(this.loggeduser.Profile == 'MDGPR'){ + this.headers = this.headersMdOficial; + } + else if(this.loggeduser.Profile == 'PR'){ + this.headers = this.headersPrOficial; + } } - else if(this.loggeduser.Profile == 'PR'){ - this.headers = this.headersPrOficial; + else{ + if(this.loggeduser.Profile == 'MDGPR'){ + this.headers = this.headersMdPessoal; + } + else if(this.loggeduser.Profile == 'PR'){ + this.headers = this.headersPrPessoal; + } } + + let options = { + headers: this.headers, + params: params + }; + + return this.http.put(`${puturl}`, event, options).pipe( + catchError(err => { + this.offlinemanager.storeRequest(puturl, 'PUT', event); + throw new Error(err); + }) + ) } - else{ - if(this.loggeduser.Profile == 'MDGPR'){ - this.headers = this.headersMdPessoal; - } - else if(this.loggeduser.Profile == 'PR'){ - this.headers = this.headersPrPessoal; - } - } - - let options = { - headers: this.headers, - params: params - }; - - return this.http.put(`${puturl}`, event, options) } changeAgenda(body:any){ diff --git a/src/app/services/network-connection.service.spec.ts b/src/app/services/network-connection.service.spec.ts new file mode 100644 index 000000000..f4a185493 --- /dev/null +++ b/src/app/services/network-connection.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { NetworkConnectionService } from './network-connection.service'; + +describe('NetworkConnectionService', () => { + let service: NetworkConnectionService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(NetworkConnectionService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/network-connection.service.ts b/src/app/services/network-connection.service.ts new file mode 100644 index 000000000..b9bfb446b --- /dev/null +++ b/src/app/services/network-connection.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs' +import { Platform } from '@ionic/angular' + +@Injectable({ + providedIn: 'root' +}) + +export class NetworkConnectionService { + online: boolean = true; + + constructor(){} + + checkOnline() { + window.addEventListener('online', (on) => { + this.online === true; + console.log('Became online'); + }); + } + + checkOffline() { + window.addEventListener('offline', (off) => { + this.online === false; + console.log('Became offline') + }); + } + +} \ No newline at end of file diff --git a/src/app/services/offline-manager.service.spec.ts b/src/app/services/offline-manager.service.spec.ts new file mode 100644 index 000000000..d6cd18851 --- /dev/null +++ b/src/app/services/offline-manager.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { OfflineManagerService } from './offline-manager.service'; + +describe('OfflineManagerService', () => { + let service: OfflineManagerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(OfflineManagerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/offline-manager.service.ts b/src/app/services/offline-manager.service.ts new file mode 100644 index 000000000..2e44f1624 --- /dev/null +++ b/src/app/services/offline-manager.service.ts @@ -0,0 +1,94 @@ +import { Injectable } from '@angular/core'; +import { Storage } from '@ionic/storage'; +import { Observable, from, of, forkJoin } from 'rxjs'; +import { switchMap, finalize } from 'rxjs/operators'; +import { HttpClient } from '@angular/common/http'; +import { ToastController } from '@ionic/angular'; +const STORAGE_REQ_KEY = 'storedreq'; + +interface StoredRequest { + url: string, + type: string, + data: any, + time: number, + id: string +} + +@Injectable({ + providedIn: 'root' +}) +export class OfflineManagerService { + + constructor( + private storage: Storage, + private http: HttpClient, + private toastController: ToastController) { } + + checkForEvents(): Observable { + return from(this.storage.get(STORAGE_REQ_KEY)).pipe( + switchMap(storedOperations => { + let storedObj = JSON.parse(storedOperations); + if (storedObj && storedObj.length > 0) { + return this.sendRequests(storedObj).pipe( + finalize(() => { + let toast = this.toastController.create({ + message: `Local data succesfully synced to API!`, + duration: 3000, + position: 'bottom' + }); + toast.then(toast => toast.present()); + + this.storage.remove(STORAGE_REQ_KEY); + }) + ); + } else { + console.log('no local events to sync'); + return of(false); + } + }) + ) + } + + storeRequest(url, type, data) { + let toast = this.toastController.create({ + message: `Your data is stored locally because you seem to be offline.`, + duration: 3000, + position: 'bottom' + }); + toast.then(toast => toast.present()); + + let action: StoredRequest = { + url: url, + type: type, + data: data, + time: new Date().getTime(), + id: Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5) + }; + + return this.storage.get(STORAGE_REQ_KEY).then(storedOperations => { + let storedObj = JSON.parse(storedOperations); + + if (storedObj) { + storedObj.push(action); + } else { + storedObj = [action]; + } + // Save old & new local transactions back to Storage + return this.storage.set(STORAGE_REQ_KEY, JSON.stringify(storedObj)); + }); + } + + sendRequests(operations: StoredRequest[]) { + let obs = []; + + for (let op of operations) { + console.log('Make one request: ', op); + let oneObs = this.http.request(op.type, op.url, op.data); + + obs.push(oneObs); + } + + // Send out all local events and return once they are finished + return forkJoin(obs); + } +} \ No newline at end of file diff --git a/src/app/services/sqlite.service.ts b/src/app/services/sqlite.service.ts index 8dc23a568..18f451a31 100644 --- a/src/app/services/sqlite.service.ts +++ b/src/app/services/sqlite.service.ts @@ -182,6 +182,20 @@ export class SqliteService { }); } + //updateevent + public updateEvent(data) { + this.dbInstance.executeSql(` + INSERT OR REPLACE INTO ${this.events} (EventId,Subject,HasAttachments,Location,CalendarId,CalendarName,StartDate,EndDate,EventType,Attendees,IsMeeting,IsRecurring,IsAllDayEvent,AppointmentState,TimeZone,Organizer,Category,EventRecurrence,Attachments,Body,Profile,HumanDate ) + VALUES ('${data.EventId}','${data.Subject}','${data.HasAttachments}','${data.Location}','${data.CalendarId}','${data.CalendarName}','${data.StartDate}','${data.EndDate}','${data.EventType}','${data.Attendees}','${data.IsMeeting}','${data.IsRecurring}', + '${data.IsAllDayEvent}','${data.AppointmentState}','${data.TimeZone}','${data.Organizer}','${data.Category}','${data.EventRecurrence}','${data.Attachments}','${data.Body}','${data.Profile}','${data.HumanDate}')`, []) + .then(() => { + console.log("event update with Success"); + + }, (e) => { + console.log(JSON.stringify(e)); + }); + } + //updateActions public updateactions(id,data) { console.log("update action data", data ) @@ -359,6 +373,7 @@ export class SqliteService { if (res.rows.length > 0) { for (var i = 0; i < res.rows.length; i++) { this.ALLPROCESS.push(res.rows.item(i)); + console.log('getEXPEDIENTE DB LOOP') } return this.ALLPROCESS; }