diff --git a/.vscode/settings.json b/.vscode/settings.json index 9439716aa..b65d66ac8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,6 @@ "deno.unstable": true, "deno.config": "apps/picsa-server/supabase/functions/deno.jsonc", "angular.enable-strict-mode-prompt": false, - "css.customData": [".vscode/tailwind.json"] + "css.customData": [".vscode/tailwind.json"], + "typescript.tsdk": "node_modules\\typescript\\lib" } diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 11eeeb4f8..2258ef75f 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -1,6 +1,7 @@ /* eslint-disable @nx/enforce-module-boundaries */ import { Component, Injector, OnInit, signal } from '@angular/core'; import { Router } from '@angular/router'; +import { Capacitor } from '@capacitor/core'; import { PicsaMigrationService } from '@picsa/migrations'; import { MonitoringToolService } from '@picsa/monitoring/src/app/services/monitoring-tool.service'; import { ResourcesToolService } from '@picsa/resources/src/app/services/resources-tool.service'; @@ -51,7 +52,9 @@ export class AppComponent implements OnInit { this.monitoringService.ready(); // delay push notification as will prompt for permissions setTimeout(() => { - this.pushNotificationService.initializePushNotifications(); + if (Capacitor.isNativePlatform()) { + this.pushNotificationService.initializePushNotifications(); + } }, 1000); } diff --git a/apps/picsa-apps/extension-app/src/app/components/layout.html b/apps/picsa-apps/extension-app/src/app/components/layout.html index 799fd1df2..0bf73adc0 100644 --- a/apps/picsa-apps/extension-app/src/app/components/layout.html +++ b/apps/picsa-apps/extension-app/src/app/components/layout.html @@ -30,7 +30,7 @@ diff --git a/apps/picsa-apps/extension-app/src/app/components/layout.ts b/apps/picsa-apps/extension-app/src/app/components/layout.ts index 895103430..9160a1c45 100644 --- a/apps/picsa-apps/extension-app/src/app/components/layout.ts +++ b/apps/picsa-apps/extension-app/src/app/components/layout.ts @@ -45,7 +45,7 @@ export class AppLayoutComponent { ) ); public userType = computed(() => this.configurationService.userSettings().user_type); - public version = APP_VERSION; + public version = APP_VERSION.semver; constructor( private router: Router, @@ -53,24 +53,21 @@ export class AppLayoutComponent { componentService: PicsaCommonComponentsService, viewContainer: ViewContainerRef ) { - effect( - () => { - // Inject menu button into global header when on farmer or extension home - const { cdkPortalStart } = componentService.headerOptions(); - if (this.showMenuButton()) { - if (!cdkPortalStart) { - componentService.patchHeader({ - cdkPortalStart: new TemplatePortal(this.menuButtonTemplate(), viewContainer), - }); - } - } else { - if (cdkPortalStart) { - componentService.patchHeader({ cdkPortalStart: undefined }); - } + effect(() => { + // Inject menu button into global header when on farmer or extension home + const { cdkPortalStart } = componentService.headerOptions(); + if (this.showMenuButton()) { + if (!cdkPortalStart) { + componentService.patchHeader({ + cdkPortalStart: new TemplatePortal(this.menuButtonTemplate(), viewContainer), + }); } - }, - { allowSignalWrites: true } - ); + } else { + if (cdkPortalStart) { + componentService.patchHeader({ cdkPortalStart: undefined }); + } + } + }); } public toggleUserType() { diff --git a/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts b/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts index 7e34d2cfa..4dce2d9e0 100644 --- a/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts +++ b/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts @@ -15,17 +15,14 @@ export class HomePageComponent { showContent = signal(false); constructor(public configurationService: ConfigurationService, router: Router) { - effect( - () => { - // navigate to /extension or /farmer tool home if configured - const { deployment_id, user_type } = this.configurationService.userSettings(); - if (deployment_id && user_type) { - router.navigate(['/', user_type], { replaceUrl: true }); - } else { - this.showContent.set(true); - } - }, - { allowSignalWrites: true } - ); + effect(() => { + // navigate to /extension or /farmer tool home if configured + const { deployment_id, user_type } = this.configurationService.userSettings(); + if (deployment_id && user_type) { + router.navigate(['/', user_type], { replaceUrl: true }); + } else { + this.showContent.set(true); + } + }); } } diff --git a/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts b/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts index 52da3c19a..090e2733a 100644 --- a/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts +++ b/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts @@ -1,35 +1,5 @@ import { arrayToHashmap } from '../../../../../../libs/utils'; - -const MW_DISTRICTS = [ - { id: 'balaka', label: 'Balaka' }, - { id: 'blantyre', label: 'Blantyre' }, - { id: 'chikwawa', label: 'Chikwawa' }, - { id: 'chiradzulu', label: 'Chiradzulu' }, - { id: 'chitipa', label: 'Chitipa' }, - { id: 'dedza', label: 'Dedza' }, - { id: 'dowa', label: 'Dowa' }, - { id: 'karonga', label: 'Karonga' }, - { id: 'kasungu', label: 'Kasungu' }, - { id: 'likoma', label: 'Likoma' }, - { id: 'lilongwe', label: 'Lilongwe' }, - { id: 'machinga', label: 'Machinga' }, - { id: 'mangochi', label: 'Mangochi' }, - { id: 'mchinji', label: 'Mchinji' }, - { id: 'mulanje', label: 'Mulanje' }, - { id: 'mwanza', label: 'Mwanza' }, - { id: 'mzimba', label: 'Mzimba' }, - { id: 'neno', label: 'Neno' }, - { id: 'nkhata_bay', label: 'Nkhata Bay' }, - { id: 'nkhotakota', label: 'Nkhotakota' }, - { id: 'nsanje', label: 'Nsanje' }, - { id: 'ntcheu', label: 'Ntcheu' }, - { id: 'ntchisi', label: 'Ntchisi' }, - { id: 'phalombe', label: 'Phalombe' }, - { id: 'rumphi', label: 'Rumphi' }, - { id: 'salima', label: 'Salima' }, - { id: 'thyolo', label: 'Thyolo' }, - { id: 'zomba', label: 'Zomba' }, -]; +import MW_DISTRICTS from '../../../../../../libs/data/geoLocation/mw/districts'; export const DISTRICTS = { mw: arrayToHashmap(MW_DISTRICTS, 'label'), diff --git a/apps/picsa-tools/budget-tool/src/app/store/budget.store.ts b/apps/picsa-tools/budget-tool/src/app/store/budget.store.ts index cc9bc3075..3e08b9b20 100644 --- a/apps/picsa-tools/budget-tool/src/app/store/budget.store.ts +++ b/apps/picsa-tools/budget-tool/src/app/store/budget.store.ts @@ -1,4 +1,4 @@ -import { effect, Injectable, OnDestroy } from '@angular/core'; +import { effect, Injectable } from '@angular/core'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { ConfigurationService } from '@picsa/configuration'; import { IDeploymentSettings, MONTH_DATA } from '@picsa/data'; @@ -305,10 +305,10 @@ export class BudgetStore { // attempt to reload any hardcoded data present in the app private async checkForUpdates() { const version = await this.db.getDoc('_appMeta', 'VERSION'); - const updateRequired = !version || version.value !== APP_VERSION.number; + const updateRequired = !version || version.value !== APP_VERSION.semver; if (updateRequired) { await this.setHardcodedData(); - const update: IAppMeta = { _key: 'VERSION', value: APP_VERSION.number }; + const update: IAppMeta = { _key: 'VERSION', value: APP_VERSION.semver }; this.db.setDoc('_appMeta', update); } } diff --git a/apps/picsa-tools/budget-tool/src/app/store/templates.ts b/apps/picsa-tools/budget-tool/src/app/store/templates.ts index aeb7ffc4d..0219e3276 100644 --- a/apps/picsa-tools/budget-tool/src/app/store/templates.ts +++ b/apps/picsa-tools/budget-tool/src/app/store/templates.ts @@ -21,7 +21,7 @@ export const PERIOD_DATA_TEMPLATE: IBudgetPeriodData = { // don't assert type so missing _key field picked up in create new budget from store export const NEW_BUDGET_TEMPLATE: IBudget = { apiVersion: BUDGET_API_VERSION, - _appVersion: APP_VERSION.number, + _appVersion: APP_VERSION.semver, data: [], meta: { title: '', diff --git a/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts index dd949c956..0c6ce4c19 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts @@ -65,29 +65,26 @@ export class ClimateSiteViewComponent implements OnDestroy, AfterViewInit { private viewContainer: ViewContainerRef, private cdr: ChangeDetectorRef ) { - effect( - async () => { - const viewId = this.viewId(); - const siteId = this.siteId(); - if (siteId && viewId) { - // same site, just view changed - if (siteId === this._siteId) { - await this.loadView(viewId); - } - // site changed - else { - this._siteId = siteId; - await this.chartService.setStation(siteId); - await this.loadView(viewId); - await _wait(50); - this.checkOrientation(); - } + effect(async () => { + const viewId = this.viewId(); + const siteId = this.siteId(); + if (siteId && viewId) { + // same site, just view changed + if (siteId === this._siteId) { + await this.loadView(viewId); } + // site changed + else { + this._siteId = siteId; + await this.chartService.setStation(siteId); + await this.loadView(viewId); + await _wait(50); + this.checkOrientation(); + } + } - this.cdr.markForCheck(); - }, - { allowSignalWrites: true } - ); + this.cdr.markForCheck(); + }); } ngAfterViewInit() { diff --git a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts index 783623e9e..2b36bc76d 100644 --- a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts +++ b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts @@ -57,8 +57,7 @@ export class CropProbabilityStationSelectComponent { if (stationOptions.length > 0) { this.handleStationChange(stationOptions[0].id); } - }, - { allowSignalWrites: true } + } ); } diff --git a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.html b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.html index c140dad1a..cb76c4933 100644 --- a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.html +++ b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.html @@ -66,6 +66,6 @@

diff --git a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts index f6091e756..80d4a7fbc 100644 --- a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts +++ b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts @@ -144,7 +144,7 @@ export class ExtensionHomeComponent implements AfterViewInit, OnDestroy { /** List of home page display links, filtered when running in production */ public picsaLinks = PAGE_LINKS; public additionalLinks = ADDITIONAL_LINKS; - public version = APP_VERSION; + public version = APP_VERSION.semver; @ViewChild('headerContent') headerContent: ElementRef; diff --git a/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts b/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts index 5d8aa3a82..59ee91aa0 100644 --- a/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts +++ b/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts @@ -68,27 +68,21 @@ export class FarmerContentModuleHomeComponent implements OnInit, OnDestroy { private tourService: TourService ) { // load content on slug change and fix tour implementation - effect( - (onCleanup) => { - const { slug } = this.params() || {}; - this.loadContentBySlug(slug); - // update the tour service to allow triggering tour from inside mat-tab component - this.tourService.useInMatTab = true; - onCleanup(() => { - this.tourService.useInMatTab = false; - }); - }, - { allowSignalWrites: true } - ); + effect((onCleanup) => { + const { slug } = this.params() || {}; + this.loadContentBySlug(slug); + // update the tour service to allow triggering tour from inside mat-tab component + this.tourService.useInMatTab = true; + onCleanup(() => { + this.tourService.useInMatTab = false; + }); + }); // If tool tab selected handle side-effects (routing and header) - effect( - () => { - const selectedTabIndex = this.selectedIndex(); - const contentBlocks = this.tabs()[selectedTabIndex]; - this.handleContentChangeEffects(contentBlocks); - }, - { allowSignalWrites: true } - ); + effect(() => { + const selectedTabIndex = this.selectedIndex(); + const contentBlocks = this.tabs()[selectedTabIndex]; + this.handleContentChangeEffects(contentBlocks); + }); } ngOnInit() { diff --git a/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts b/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts index ec60690c3..45f885729 100644 --- a/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts +++ b/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts @@ -164,7 +164,7 @@ export class ResourcesToolService extends PicsaAsyncService { // Use caching system to only populate once per app version launch in production const assetsCacheVersion = this.getAssetResourcesVersion(); - if (ENVIRONMENT.production && assetsCacheVersion === APP_VERSION.number) { + if (ENVIRONMENT.production && assetsCacheVersion === APP_VERSION.semver) { return; } // Update DB with hardcoded entries @@ -235,7 +235,7 @@ export class ResourcesToolService extends PicsaAsyncService { } private setAssetResourcesVersion() { - return localStorage.setItem(`picsa-resources-tool||assets-cache-version`, APP_VERSION.number); + return localStorage.setItem(`picsa-resources-tool||assets-cache-version`, APP_VERSION.semver); } public async shareLink(url: string) { diff --git a/libs/environments/src/version.ts b/libs/environments/src/version.ts index ac8327088..e4068afd8 100644 --- a/libs/environments/src/version.ts +++ b/libs/environments/src/version.ts @@ -1,8 +1,8 @@ // tslint:disable no-var-requires import packageJson from '../../../package.json'; -// e.g. 1.0.1 - even though called a number is stored as a string export const APP_VERSION = { - number: packageJson.version, + /** Semver code for current app version, e.g. 3.26.0 */ + semver: packageJson.version, date: '2025-02-15', }; diff --git a/libs/migrations/migrations.service.ts b/libs/migrations/migrations.service.ts index 318475deb..59e525e5b 100644 --- a/libs/migrations/migrations.service.ts +++ b/libs/migrations/migrations.service.ts @@ -75,7 +75,7 @@ export class PicsaMigrationService { // HACK - As first install only tracked from v3.52, fallback to v3.0.0 if the user is not // a first-time user but does not have accurate first install version const previousUser = localStorage.getItem('picsa_user_settings'); - firstInstallVersion = previousUser ? '3.0.0' : APP_VERSION.number; + firstInstallVersion = previousUser ? '3.0.0' : APP_VERSION.semver; localStorage.setItem('picsa_app_first_install_version', firstInstallVersion); return firstInstallVersion; } diff --git a/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts b/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts index 34ad4b1bf..db02296e4 100644 --- a/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts +++ b/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts @@ -26,22 +26,19 @@ export class PhotoViewComponent { @ViewChild('dialogTemplate') dialogTemplate!: TemplateRef; constructor(private service: PhotoService, private dialog: PicsaDialogService, public photoDialog: MatDialog) { - effect( - async (onCleanup) => { - const photo = this.photo; - const uri = await this.service.getPhotoAttachment(photo().id); - if (uri) { - this.uri.set(uri); - } else { - console.error('[Photo] not found', this.photo); - this.errorMsg.set(`Photo not found`); - } - onCleanup(() => { - this.service.revokePhotoAttachment(photo().id); - }); - }, - { allowSignalWrites: true } - ); + effect(async (onCleanup) => { + const photo = this.photo; + const uri = await this.service.getPhotoAttachment(photo().id); + if (uri) { + this.uri.set(uri); + } else { + console.error('[Photo] not found', this.photo); + this.errorMsg.set(`Photo not found`); + } + onCleanup(() => { + this.service.revokePhotoAttachment(photo().id); + }); + }); } openPhotoDialog() { diff --git a/libs/shared/src/services/core/analytics.service.ts b/libs/shared/src/services/core/analytics.service.ts index 67545cd8b..9583745d4 100644 --- a/libs/shared/src/services/core/analytics.service.ts +++ b/libs/shared/src/services/core/analytics.service.ts @@ -32,7 +32,7 @@ export class AnalyticsService { this.firebaseAnalytics.setScreenName({ screenName: location.pathname }); this.firebaseAnalytics.logEvent({ name: 'picsa_screen_view', - params: { screen_name: location.pathname, app_version: APP_VERSION }, + params: { screen_name: location.pathname, app_version: APP_VERSION.semver }, }); } });