Skip to content

Commit

Permalink
feat: improve offline trek and outdoor
Browse files Browse the repository at this point in the history
  • Loading branch information
bastyen committed Jan 16, 2025
1 parent 7b816de commit a031397
Show file tree
Hide file tree
Showing 5 changed files with 392 additions and 249 deletions.
8 changes: 8 additions & 0 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,8 +709,10 @@ declare global {
"coursesIsInViewport": boolean;
"downloadConfirm": number;
"downloadedSuccessConfirm": number;
"downloadedErrorConfirm": number;
"deleteConfirm": number;
"deleteSuccessConfirm": number;
"deleteErrorConfirm": number;
}
interface HTMLGrwOutdoorSiteDetailElement extends Components.GrwOutdoorSiteDetail, HTMLStencilElement {
addEventListener<K extends keyof HTMLGrwOutdoorSiteDetailElementEventMap>(type: K, listener: (this: HTMLGrwOutdoorSiteDetailElement, ev: GrwOutdoorSiteDetailCustomEvent<HTMLGrwOutdoorSiteDetailElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -903,8 +905,10 @@ declare global {
"parentTrekPress": number;
"downloadConfirm": number;
"downloadedSuccessConfirm": number;
"downloadedErrorConfirm": number;
"deleteConfirm": number;
"deleteSuccessConfirm": number;
"deleteErrorConfirm": number;
}
interface HTMLGrwTrekDetailElement extends Components.GrwTrekDetail, HTMLStencilElement {
addEventListener<K extends keyof HTMLGrwTrekDetailElementEventMap>(type: K, listener: (this: HTMLGrwTrekDetailElement, ev: GrwTrekDetailCustomEvent<HTMLGrwTrekDetailElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -1221,8 +1225,10 @@ declare namespace LocalJSX {
"isLargeView"?: boolean;
"onCoursesIsInViewport"?: (event: GrwOutdoorSiteDetailCustomEvent<boolean>) => void;
"onDeleteConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onDeleteErrorConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onDeleteSuccessConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onDownloadConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onDownloadedErrorConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onDownloadedSuccessConfirm"?: (event: GrwOutdoorSiteDetailCustomEvent<number>) => void;
"onInformationPlacesIsInViewport"?: (event: GrwOutdoorSiteDetailCustomEvent<boolean>) => void;
"onPoiIsInViewport"?: (event: GrwOutdoorSiteDetailCustomEvent<boolean>) => void;
Expand Down Expand Up @@ -1421,9 +1427,11 @@ declare namespace LocalJSX {
"grwApp"?: boolean;
"isLargeView"?: boolean;
"onDeleteConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onDeleteErrorConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onDeleteSuccessConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onDescriptionIsInViewport"?: (event: GrwTrekDetailCustomEvent<boolean>) => void;
"onDownloadConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onDownloadedErrorConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onDownloadedSuccessConfirm"?: (event: GrwTrekDetailCustomEvent<number>) => void;
"onInformationPlacesIsInViewport"?: (event: GrwTrekDetailCustomEvent<boolean>) => void;
"onParentTrekPress"?: (event: GrwTrekDetailCustomEvent<number>) => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, Event, EventEmitter, Fragment, Host, Listen, Prop, State, h } from '@stencil/core';
import { translate } from 'i18n/i18n';
import state from 'store/store';
import { Mode } from 'types/types';

@Component({
Expand All @@ -11,6 +13,7 @@ export class GrwOfflineConfirmModal {
@State() showConfirmModal = false;
@State() showLoaderModal = false;
@State() showSuccessModal = false;
@State() showErrorModal = false;
@State() showConfirmDeleteModal = false;
@State() showDeletingMessage = false;
@State() showDeleteSuccessMessage = false;
Expand Down Expand Up @@ -38,6 +41,12 @@ export class GrwOfflineConfirmModal {
this.showSuccessModal = true;
}

@Listen('downloadedErrorConfirm', { target: 'window' })
downloadedErrorConfirm() {
this.showLoaderModal = false;
this.showErrorModal = true;
}

@Listen('deleteConfirm', { target: 'window' })
onDeleteConfirm() {
this.showLoaderModal = false;
Expand All @@ -56,6 +65,13 @@ export class GrwOfflineConfirmModal {
this.showDeleteSuccessMessage = true;
}

@Listen('deleteErrorConfirm', { target: 'window' })
deleteErrorConfirm() {
this.showLoaderModal = false;
this.showSuccessModal = true;
this.showDeleteSuccessMessage = true;
}

handleOkDeleteModal() {
this.showDeletingMessage = true;
this.showConfirmDeleteModal = false;
Expand Down Expand Up @@ -84,31 +100,29 @@ export class GrwOfflineConfirmModal {
{this.showConfirmModal && !this.showConfirmDeleteModal && (
<Fragment>
<div class="modal-message-container">{`${
this.mode === 'treks'
? 'Êtes-vous sûr de vouloir rendre cet itinéraire disponible hors ligne ?'
: 'Êtes-vous sûr de vouloir rendre cet outdoor disponible hors ligne ?'
this.mode === 'treks' ? translate[state.language].offline.downloadRouteQuestion : translate[state.language].offline.downloadOutdoorQuestion
}`}</div>
<div class="modal-buttons-container">
<button part="modal-button" class="modal-button" onClick={() => this.handleCancelModal()}>
ANNULER
{translate[state.language].offline.cancel}
</button>
<button part="modal-button" class="modal-button" onClick={() => this.handleOkDownloadModal()}>
OK
{translate[state.language].offline.ok}
</button>
</div>
</Fragment>
)}
{this.showConfirmDeleteModal && (
<Fragment>
<div class="modal-message-container">{`${
this.mode === 'treks' ? 'Êtes-vous sûr de vouloir supprimer cet itinéraire du hors ligne ?' : 'Êtes-vous sûr de vouloir supprimer cet outdoor du hors ligne ?'
this.mode === 'treks' ? translate[state.language].offline.deleteRouteQuestion : translate[state.language].offline.deleteRouteQuestion
}`}</div>
<div class="modal-buttons-container">
<button part="modal-button" class="modal-button" onClick={() => this.handleCancelModal()}>
ANNULER
{translate[state.language].offline.cancel}
</button>
<button part="modal-button" class="modal-button" onClick={() => this.handleOkDeleteModal()}>
OK
{translate[state.language].offline.ok}
</button>
</div>
</Fragment>
Expand All @@ -117,7 +131,7 @@ export class GrwOfflineConfirmModal {
<Fragment>
<div class="modal-message-container">
<div class="modal-loader"></div>
{this.showDeletingMessage ? 'Suppression en cours' : 'Téléchargement en cours'}
{this.showDeletingMessage ? translate[state.language].offline.deleting : translate[state.language].offline.downloading}
</div>
</Fragment>
)}
Expand All @@ -126,15 +140,34 @@ export class GrwOfflineConfirmModal {
<div class="modal-message-container">
{this.showDeleteSuccessMessage
? this.mode === 'treks'
? "L'itinéraire est supprimé du hors ligne"
: "L'outdoor est supprimé du hors ligne"
? translate[state.language].offline.offlineRouteDeleted
: translate[state.language].offline.offlineOutdoorDeleted
: this.mode === 'treks'
? translate[state.language].offline.routeAvailableOffline
: translate[state.language].offline.outdoorAvailableOffline}
</div>
<div class="modal-button-container">
<button part="modal-button" class="modal-button" onClick={() => this.handleCancelModal()}>
{translate[state.language].offline.ok}
</button>
</div>
</Fragment>
)}

{this.showErrorModal && (
<Fragment>
<div class="modal-message-container">
{this.showDeleteSuccessMessage
? this.mode === 'treks'
? translate[state.language].offline.deleteRouteError
: translate[state.language].offline.deleteOutdoorError
: this.mode === 'treks'
? "L'itinéraire est disponible hors ligne"
: "L'outdoor est disponible hors ligne"}
? translate[state.language].offline.downloadRouteError
: translate[state.language].offline.downloadOutdoorError}
</div>
<div class="modal-button-container">
<button part="modal-button" class="modal-button" onClick={() => this.handleCancelModal()}>
OK
{translate[state.language].offline.ok}
</button>
</div>
</Fragment>
Expand Down
126 changes: 68 additions & 58 deletions src/components/grw-outdoor-site-detail/grw-outdoor-site-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,11 @@ export class GrwOutdoorSiteDetail {

@Event() downloadConfirm: EventEmitter<number>;
@Event() downloadedSuccessConfirm: EventEmitter<number>;
@Event() downloadedErrorConfirm: EventEmitter<number>;

@Event() deleteConfirm: EventEmitter<number>;
@Event() deleteSuccessConfirm: EventEmitter<number>;
@Event() deleteErrorConfirm: EventEmitter<number>;

@State() showTouristicContentDetailsModal = false;
@State() showTouristicEventDetailsModal = false;
Expand Down Expand Up @@ -591,53 +593,57 @@ export class GrwOutdoorSiteDetail {
}

async downloadOutdoorSite(outdoorSiteId) {
const controller = new AbortController();
const signal = controller.signal;
const init: RequestInit = { cache: Build.isDev ? 'force-cache' : 'default', signal: signal };

const outdoorSite: OutdoorSite = await getOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json());
await this.downloadOutdoorSiteTiles(this.defaultBackgroundLayerUrl, this.defaultBackgroundLayerAttribution, outdoorSite.geometry);
await writeOrUpdateFilesInStore(outdoorSite, imagesRegExp, true, ['url']);

const pois = (await getPoisNearSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateDataInStore('pois', pois);
await writeOrUpdateFilesInStore(pois, imagesRegExp, true, ['url']);

const touristicContents = (await getTouristicContentsNearOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateFilesInStore(touristicContents, imagesRegExp, true, ['url']);
touristicContents.forEach(touristicContent => {
touristicContent.offline = true;
});
await writeOrUpdateDataInStore('touristicContents', touristicContents);
const touristicEvents = (await getTouristicEventsNearOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateFilesInStore(touristicEvents, imagesRegExp, true, ['url']);
touristicEvents.forEach(touristicEvent => {
touristicEvent.offline = true;
});
await writeOrUpdateDataInStore('touristicEvents', touristicEvents);

await writeOrUpdateDataInStore('outdoorSites', [
{
...outdoorSite,
offline: true,
pois: pois.map(poi => poi.id),
touristicContents: touristicContents.map(trekTouristicContent => trekTouristicContent.id),
touristicEvents: touristicEvents.map(trekTouristicEvent => trekTouristicEvent.id),
},
]);
try {
const controller = new AbortController();
const signal = controller.signal;
const init: RequestInit = { cache: Build.isDev ? 'force-cache' : 'default', signal: signal };

const outdoorSite: OutdoorSite = await getOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json());
await this.downloadOutdoorSiteTiles(this.defaultBackgroundLayerUrl, this.defaultBackgroundLayerAttribution, outdoorSite.geometry);
await writeOrUpdateFilesInStore(outdoorSite, imagesRegExp, true, ['url']);

const pois = (await getPoisNearSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateDataInStore('pois', pois);
await writeOrUpdateFilesInStore(pois, imagesRegExp, true, ['url']);

const touristicContents = (await getTouristicContentsNearOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateFilesInStore(touristicContents, imagesRegExp, true, ['url']);
touristicContents.forEach(touristicContent => {
touristicContent.offline = true;
});
await writeOrUpdateDataInStore('touristicContents', touristicContents);
const touristicEvents = (await getTouristicEventsNearOutdoorSite(state.api, state.language, outdoorSiteId, init).then(response => response.json())).results;
await writeOrUpdateFilesInStore(touristicEvents, imagesRegExp, true, ['url']);
touristicEvents.forEach(touristicEvent => {
touristicEvent.offline = true;
});
await writeOrUpdateDataInStore('touristicEvents', touristicEvents);

await writeOrUpdateDataInStore('outdoorSites', [
{
...outdoorSite,
offline: true,
pois: pois.map(poi => poi.id),
touristicContents: touristicContents.map(trekTouristicContent => trekTouristicContent.id),
touristicEvents: touristicEvents.map(trekTouristicEvent => trekTouristicEvent.id),
},
]);

if (outdoorSite.courses && outdoorSite.courses.length > 0) {
for (let index = 0; index < outdoorSite.courses.length; index++) {
const outdoorCourseId = outdoorSite.courses[index];
await this.downloadOutdoorCourse(outdoorCourseId);
if (outdoorSite.courses && outdoorSite.courses.length > 0) {
for (let index = 0; index < outdoorSite.courses.length; index++) {
const outdoorCourseId = outdoorSite.courses[index];
await this.downloadOutdoorCourse(outdoorCourseId);
}
}
}

if (outdoorSite.children && outdoorSite.children.length > 0) {
for (let index = 0; index < outdoorSite.children.length; index++) {
const outdoorSiteId = outdoorSite.children[index];
await this.downloadOutdoorSite(outdoorSiteId);
if (outdoorSite.children && outdoorSite.children.length > 0) {
for (let index = 0; index < outdoorSite.children.length; index++) {
const outdoorSiteId = outdoorSite.children[index];
await this.downloadOutdoorSite(outdoorSiteId);
}
}
} catch (error) {
this.downloadedSuccessConfirm.emit(this.currentOutdoorSite.id);
}
}

Expand Down Expand Up @@ -678,24 +684,28 @@ export class GrwOutdoorSiteDetail {
}

async deleteOutdoorSite() {
const outdoorSitesInStore: OutdoorSites = [];
const outdoorSiteInStore = await getDataInStore('outdoorSites', this.currentOutdoorSite.id);
this.deleteOfflineOutdoorSiteProperties(outdoorSiteInStore);
outdoorSitesInStore.push(outdoorSiteInStore);
try {
const outdoorSitesInStore: OutdoorSites = [];
const outdoorSiteInStore = await getDataInStore('outdoorSites', this.currentOutdoorSite.id);
this.deleteOfflineOutdoorSiteProperties(outdoorSiteInStore);
outdoorSitesInStore.push(outdoorSiteInStore);

await writeOrUpdateDataInStore('outdoorSites', outdoorSitesInStore);
await writeOrUpdateDataInStore('outdoorSites', outdoorSitesInStore);

if (state.outdoorSites) {
delete state.outdoorSites.find(outdoorSite => outdoorSite.id === this.currentOutdoorSite.id).offline;
if (state.outdoorSites) {
delete state.outdoorSites.find(outdoorSite => outdoorSite.id === this.currentOutdoorSite.id).offline;

if (!state.currentOutdoorSites) {
state.currentOutdoorSites = state.outdoorSites;
if (!state.currentOutdoorSites) {
state.currentOutdoorSites = state.outdoorSites;
}
delete state.currentOutdoorSites.find(trek => trek.id === this.currentOutdoorSite.id).offline;
}
delete state.currentOutdoorSites.find(trek => trek.id === this.currentOutdoorSite.id).offline;
}

this.offline = false;
this.deleteSuccessConfirm.emit();
this.offline = false;
this.deleteSuccessConfirm.emit();
} catch (error) {
this.deleteErrorConfirm.emit(this.currentOutdoorSite.id);
}
}

async downloadGlobalTiles(url, attribution) {
Expand Down Expand Up @@ -874,15 +884,15 @@ export class GrwOutdoorSiteDetail {
<button part="offline-button" class="offline-button" onClick={() => this.displayDownloadModal()}>
<span part="icon" class="icon" innerHTML={DownloadForOfflineIcon}></span>
<span part="label" class="label">
RENDRE DISPONIBLE HORS LIGNE
{translate[state.language].offline.downloadOffline}
</span>
</button>
)}
{this.enableOffline && this.offline && (!this.currentOutdoorSite.parents || this.currentOutdoorSite.parents.length === 0) && (
<button part="offline-button" class="offline-button" onClick={() => this.displayDeleteModal()}>
<span part="icon" class="icon" innerHTML={DeleteIcon}></span>
<span part="label" class="label">
SUPPRIMER DU HORS LIGNE
{translate[state.language].offline.deleteOffline}
</span>
</button>
)}
Expand Down
Loading

0 comments on commit a031397

Please sign in to comment.