+
-
-
-
![]()
-
+{{ additionaAttachmentCount }}
-
-
-
+ @if (firstAttachmentUrl()) {
+
+
+
![]()
+ @if (additionaAttachmentCount() && showAdditionalAttachmentCount()) {
+
+{{ additionaAttachmentCount() }}
+ }
+
+
+ }
+
-
-
- {{ topHeader | formatDate | async }}
-
-
-
- {{ masl }} {{ "MAP_CENTER_INFO.ABOVE_SEA_LEVEL" | translate }}
-
+ @if (registration()?.DtObsTime) {
+
+
+ {{ registration()?.DtObsTime! | formatDate | async }}
+
+ }
+ @if (masl) {
+
+
+ {{ masl }} {{ "MAP_CENTER_INFO.ABOVE_SEA_LEVEL" | translate }}
+
+ }
- {{ title }}
+ {{ title() }}
@@ -43,10 +49,13 @@ {{ title }}
src="/assets/icon/user.svg"
[svgStyle]="{ 'width.px': 16, 'height.px': 16 }"
>
- {{ name }}
+ {{ registration()?.NickName }}
diff --git a/src/app/components/map-item-bar/map-item-bar.component.ts b/src/app/components/map-item-bar/map-item-bar.component.ts
index 6a5188a88..a75826922 100644
--- a/src/app/components/map-item-bar/map-item-bar.component.ts
+++ b/src/app/components/map-item-bar/map-item-bar.component.ts
@@ -1,15 +1,14 @@
import { IonGrid, IonRow, IonCol, IonLabel } from '@ionic/angular/standalone';
-import { Component, OnInit, NgZone, OnDestroy, inject } from '@angular/core';
-import { Subscription, firstValueFrom, map } from 'rxjs';
+import { Component, OnInit, inject, input, signal, computed, output } from '@angular/core';
+import { firstValueFrom, map } from 'rxjs';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { MapItem } from '../../core/models/map-item.model';
import { Router } from '@angular/router';
-import { AppMode, GeoHazard } from 'src/app/modules/common-core/models';
-import { AtAGlanceViewModel, AttachmentViewModel, KdvElement } from 'src/app/modules/common-regobs-api/models';
-import { UserSettingService } from '../../core/services/user-setting/user-setting.service';
+import { GeoHazard } from 'src/app/modules/common-core/models';
+import { AttachmentViewModel, KdvElement } from 'src/app/modules/common-regobs-api/models';
import { StarRatingHelper } from '../competence/star-helper';
import { KdvService } from 'src/app/modules/common-registration/registration.services';
-import { NgIf, NgClass, AsyncPipe } from '@angular/common';
+import { NgClass, AsyncPipe } from '@angular/common';
import { SvgIconComponent } from 'angular-svg-icon';
import { CompetenceComponent } from '../competence/competence.component';
import { TranslatePipe } from '@ngx-translate/core';
@@ -28,7 +27,6 @@ import { FormatDatePipe } from '../../modules/shared/pipes/format-date/format-da
IonLabel,
IonRow,
NgClass,
- NgIf,
SvgIconComponent,
TranslatePipe,
],
@@ -38,67 +36,49 @@ import { FormatDatePipe } from '../../modules/shared/pipes/format-date/format-da
* To show this, klick on a registrations icon in the map.
* Also include an image slider if registration contain images.
*/
-export class MapItemBarComponent implements OnInit, OnDestroy {
+export class MapItemBarComponent implements OnInit {
+ cardClicked = output();
private kdvService = inject(KdvService);
private router = inject(Router);
- private zone = inject(NgZone);
- private userSettingService = inject(UserSettingService);
private sanitizer = inject(DomSanitizer);
+ registration = input
();
- visible: boolean;
- topHeader?: string;
- title?: string;
distanceAndType?: string;
- firstAttachmentUrl?: SafeUrl;
- additionaAttachmentCount?: number;
- name?: string;
+ firstAttachmentUrl = signal(undefined);
+ additionaAttachmentCount = computed(() => {
+ const attachmentCount = this.registration()?.AttachmentsCount;
+ if (!attachmentCount) {
+ return 0;
+ }
+ return attachmentCount > 1 ? attachmentCount - 1 : 0;
+ });
id?: number;
geoHazard?: GeoHazard;
attachments: AttachmentViewModel[] = [];
masl?: number;
- starCount?: number;
- showAdditionalAttachmentCount?: boolean;
-
- private subscription?: Subscription;
- private appMode?: AppMode;
- competenceLevelName?: string;
-
- // TODO: Rewrite this component to use observable. Maybe put visibleMapItem observable in map service?
-
- constructor() {
- this.visible = false;
- }
-
- ngOnInit() {
- this.subscription = this.userSettingService.appModeLanguageAndCurrentGeoHazard$.subscribe(([appMode, _, __]) => {
- this.appMode = appMode;
- this.hide();
- });
- }
-
- ngOnDestroy(): void {
- if (this.subscription) {
- this.subscription.unsubscribe();
+ showAdditionalAttachmentCount = signal(true);
+
+ title = computed(() => this.registration()?.FormNames?.join(', '));
+ starCount = computed(() => StarRatingHelper.getStarRating(this.registration()?.CompetenceLevelTID));
+ competenceLevelName?: string = undefined;
+
+ async ngOnInit() {
+ if (this.registration()?.CompetenceLevelTID) {
+ const competence = this.registration()?.CompetenceLevelTID;
+ if (!competence) return;
+ const competenceLevelName = await this.getCompetenceKdvById(competence);
+ this.competenceLevelName = competenceLevelName.Name;
}
- }
-
- getTitle(item: AtAGlanceViewModel) {
- return item.FormNames?.join(', ');
- }
-
- getAdditionalAttachmentsCount(count?: number): number {
- if (!count) {
- return 0;
- }
- return count > 1 ? count - 1 : 0;
+ this.firstAttachmentUrl.set(this.sanitize(this.registration()?.FirstAttachmentUrl));
}
handleMissingImage() {
- this.firstAttachmentUrl = './assets/images/broken-image-w-bg.svg';
- this.showAdditionalAttachmentCount = false;
+ this.firstAttachmentUrl.set('./assets/images/broken-image-w-bg.svg');
+ this.showAdditionalAttachmentCount.set(false);
}
- private sanitize(url: string): SafeUrl {
+ private sanitize(url: string | undefined): SafeUrl | undefined {
+ if (!url) return;
return this.sanitizer.bypassSecurityTrustUrl(url);
}
@@ -112,35 +92,13 @@ export class MapItemBarComponent implements OnInit, OnDestroy {
);
}
- show(item: MapItem) {
- this.showAdditionalAttachmentCount = true;
- this.zone.run(async () => {
- this.id = item.RegId;
- this.topHeader = item.DtObsTime;
- this.title = this.getTitle(item);
- this.name = item.NickName;
- this.starCount = item.CompetenceLevelTID && StarRatingHelper.getStarRating(item.CompetenceLevelTID);
- this.competenceLevelName = item.CompetenceLevelTID
- ? (await this.getCompetenceKdvById(item.CompetenceLevelTID))?.Name
- : undefined;
- this.geoHazard = item.GeoHazardTID;
- // this.masl = item.ObsLocation ? item.ObsLocation.Height : undefined;
- // this.setDistanceAndType(item);
- this.attachments = [];
- this.firstAttachmentUrl = item.FirstAttachmentUrl ? this.sanitize(item.FirstAttachmentUrl) : undefined;
- this.additionaAttachmentCount = this.getAdditionalAttachmentsCount(item.AttachmentsCount);
- this.visible = true;
- });
- }
-
- hide() {
- this.zone.run(() => {
- this.visible = false;
- });
- }
-
navigateToItem() {
- this.router.navigateByUrl(`view-observation/${this.id}`);
+ const targetUrl = `view-observation/${this.registration()?.RegId}`;
+ this.router.navigateByUrl(targetUrl).then((navigationSuccess) => {
+ if (navigationSuccess) {
+ this.cardClicked.emit();
+ }
+ });
}
// TODO
diff --git a/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.html b/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.html
index 2f174a162..682600464 100644
--- a/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.html
+++ b/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.html
@@ -9,16 +9,20 @@
>
@for (attachment of attachments(); track attachment.Url) {
- @if (isAttachmentSnowProfile(attachment)) {
+ @if (attachment.Href) {
} @else {
-
+
}
}
diff --git a/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.ts b/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.ts
index c403d2bc9..bc0dc8cdd 100644
--- a/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.ts
+++ b/src/app/components/observation/observation-image-carousel/observation-image-carousel.component.ts
@@ -15,7 +15,7 @@ import { AttachmentViewModel, RegistrationViewModel } from 'src/app/modules/comm
import { SwiperContainer } from 'swiper/element';
import { addIcons } from 'ionicons';
import { close, downloadOutline, openOutline, eyeOutline } from 'ionicons/icons';
-import { TranslatePipe } from '@ngx-translate/core';
+import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
import { KeyValueComponent } from '../key-value/key-value.component';
import { settings } from 'src/settings';
@@ -37,21 +37,18 @@ export class ObservationImageCarouselComponent {
isImageListView = computed(() => this.router.url.includes('search/pictures'));
attachments = input<(AttachmentViewModel & { Href?: string })[]>([]);
plotService = inject(PlotService);
+ translateService = inject(TranslateService);
registration = input();
attachmentIndex = model(0);
-
- // Bruker linkedSignal her for å gjøre det mulig å overstyre hva urlen er dersom kall til plot-api feiler
- snowProfileUrl = linkedSignal(() => {
- const reg = this.registration();
- if (!reg) return undefined;
- return this.plotService.getSnowProfileSvgUrl(reg);
- });
-
- useFallbackSnowProfileImage(attachment: AttachmentViewModel) {
+ useFallbackSnowProfileImage(attachment: AttachmentViewModel, event: Event) {
+ const target = event.target as HTMLImageElement;
+ if (target.src === attachment.Url) {
+ attachment.Url = 'assets/images/broken-image-w-bg.svg';
+ attachment.Alt = this.translateService.instant('REGISTRATION.COULD_NOT_DOWNLOAD_IMAGE');
+ }
this.snowProfileUrl.set(attachment.Url as string);
}
-
roundedDownOrientationValue = computed(() => {
const aspectValue = this.currentAttachmentData().Aspect; //256
if (!aspectValue) return '';
@@ -61,6 +58,7 @@ export class ObservationImageCarouselComponent {
});
currentAttachmentData = computed(() => this.attachments()?.[this.attachmentIndex()]);
+
comment = computed(() => {
// Prioriter kommentar fra bilde dersom det er lagt til
if (this.currentAttachmentData().Comment) {
@@ -68,7 +66,7 @@ export class ObservationImageCarouselComponent {
}
// Vis kommentar fra snøprofil-skjema dersom det finnes
- if (this.isAttachmentSnowProfile(this.currentAttachmentData())) {
+ if (this.currentAttachmentData().Href) {
return this.registration()?.SnowProfile2?.Comment;
}
@@ -87,14 +85,21 @@ export class ObservationImageCarouselComponent {
const customEvent = e as CustomEvent;
const activeIndex = customEvent.detail[0].activeIndex;
this.attachmentIndex.set(activeIndex);
+ this;
}
ngAfterViewInit() {
this.swiper()?.nativeElement.swiper.slideTo(this.attachmentIndex());
}
- isAttachmentSnowProfile(attachment: AttachmentViewModel & { Href?: string }) {
- // Kun snøprofil har Href
- return !!attachment.Href;
+ snowProfileUrl = linkedSignal(() => {
+ const reg = this.registration();
+ if (!reg) return undefined;
+ return this.plotService.getSnowProfileSvgUrl(reg);
+ });
+
+ setFallbackImage(attachment: AttachmentViewModel) {
+ attachment.Url = 'assets/images/broken-image-w-bg.svg';
+ attachment.Alt = this.translateService.instant('REGISTRATION.COULD_NOT_DOWNLOAD_IMAGE');
}
}
diff --git a/src/app/components/observation/observation/observation.component.css b/src/app/components/observation/observation/observation.component.css
index f07ae8fc1..f869c65f9 100644
--- a/src/app/components/observation/observation/observation.component.css
+++ b/src/app/components/observation/observation/observation.component.css
@@ -1,7 +1,7 @@
:host {
display: block;
- margin-left: 0;
- margin-right: 0;
+ max-width: var(--desktop-max-width);
+ margin: 0 auto;
margin-top: 16px;
background-color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
@@ -60,6 +60,10 @@ b {
font-weight: 600;
}
+ion-button ion-icon {
+ margin-right: 4px;
+}
+
ion-chip ion-label + ion-label {
margin-left: 8px;
}
@@ -78,11 +82,14 @@ ion-chip.chip-disabled {
.buttons {
display: flex;
- justify-content: space-between;
/* Knapperaden har ion-color-light klasse som endrer --ion-background-color */
background-color: var(--ion-background-color);
}
+.reg-id {
+ margin-left: auto;
+}
+
@media only screen and (max-width: 415px) {
/* On small screens, constrain the edit button size so that the share button is not pushed outside of the obs card */
.edit-button {
@@ -97,3 +104,16 @@ ion-chip.chip-disabled {
.buttons:has(> :last-child:nth-child(1)) {
flex-direction: row-reverse;
}
+
+/* Her må vi overskrive ion-chip der hvor man skal ha en lenke på stjerner - grunnen fordi pointer-events er blokkert som default
+derfor vises ikke riktig cursor når hover over stjerner */
+.competence-chip {
+ pointer-events: auto;
+}
+.competence-chip:hover {
+ background-color: rgba(0, 66, 95, 0.08);
+}
+
+.competence-link {
+ text-decoration: none;
+}
diff --git a/src/app/components/observation/observation/observation.component.html b/src/app/components/observation/observation/observation.component.html
index b52cff347..23604ff7c 100644
--- a/src/app/components/observation/observation/observation.component.html
+++ b/src/app/components/observation/observation/observation.component.html
@@ -19,7 +19,13 @@
@for (attachment of attachments(); track attachment.AttachmentId; let index = $index) {
-
+
}
@@ -70,11 +76,17 @@
-
+