@innspel/react-native 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/InnspelProvider.tsx
2
- import { createContext as createContext3, useCallback as useCallback3, useContext as useContext4, useMemo as useMemo4, useRef as useRef4, useState as useState5 } from "react";
3
- import { View as View9 } from "react-native";
2
+ import { createContext as createContext3, useCallback as useCallback3, useContext as useContext4, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
3
+ import { View as View10 } from "react-native";
4
4
 
5
5
  // src/skjermbilde.ts
6
6
  import { createContext, useContext } from "react";
@@ -355,8 +355,8 @@ import {
355
355
  InnspelApiError as InnspelApiError2,
356
356
  InnspelQueueFullError
357
357
  } from "@innspel/core";
358
- import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect2, useRef as useRef3, useState as useState4 } from "react";
359
- import { KeyboardAvoidingView, Modal, Pressable as Pressable6, View as View8 } from "react-native";
358
+ import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect2, useRef as useRef4, useState as useState4 } from "react";
359
+ import { KeyboardAvoidingView, Modal, Pressable as Pressable5, View as View9 } from "react-native";
360
360
  import { initialWindowMetrics, SafeAreaInsetsContext } from "react-native-safe-area-context";
361
361
 
362
362
  // src/Ikon.tsx
@@ -387,12 +387,21 @@ var calendar_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox=
387
387
  // ../../node_modules/ionicons/dist/svg/camera-outline.svg
388
388
  var camera_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="m350.54 148.68-26.62-42.06C318.31 100.08 310.62 96 302 96h-92c-8.62 0-16.31 4.08-21.92 10.62l-26.62 42.06C155.85 155.23 148.62 160 140 160H80a32 32 0 0 0-32 32v192a32 32 0 0 0 32 32h352a32 32 0 0 0 32-32V192a32 32 0 0 0-32-32h-59c-8.65 0-16.85-4.77-22.46-11.32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><circle cx="256" cy="272" r="80" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M124 158v-22h-24v22" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
389
389
 
390
+ // ../../node_modules/ionicons/dist/svg/chatbox-outline.svg
391
+ var chatbox_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M408 64H104a56.16 56.16 0 0 0-56 56v192a56.16 56.16 0 0 0 56 56h40v80l93.72-78.14a8 8 0 0 1 5.13-1.86H408a56.16 56.16 0 0 0 56-56V120a56.16 56.16 0 0 0-56-56Z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/></svg>';
392
+
390
393
  // ../../node_modules/ionicons/dist/svg/checkmark-circle-outline.svg
391
394
  var checkmark_circle_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M352 176 217.6 336 160 272" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
392
395
 
396
+ // ../../node_modules/ionicons/dist/svg/checkmark-outline.svg
397
+ var checkmark_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M416 128 192 384l-96-96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
398
+
393
399
  // ../../node_modules/ionicons/dist/svg/chevron-down-outline.svg
394
400
  var chevron_down_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="m112 184 144 144 144-144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>';
395
401
 
402
+ // ../../node_modules/ionicons/dist/svg/chevron-forward-outline.svg
403
+ var chevron_forward_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="m184 112 144 144-144 144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>';
404
+
396
405
  // ../../node_modules/ionicons/dist/svg/chevron-up-outline.svg
397
406
  var chevron_up_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="m112 328 144-144 144 144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>';
398
407
 
@@ -470,8 +479,14 @@ var IKONER = Object.fromEntries(
470
479
  "bug-outline": bug_outline_default,
471
480
  "calendar-outline": calendar_outline_default,
472
481
  "camera-outline": camera_outline_default,
482
+ // «Send» og «Send nytt innspill» — ikonkartet i wireframen (R8.3).
483
+ "chatbox-outline": chatbox_outline_default,
473
484
  "checkmark-circle-outline": checkmark_circle_outline_default,
485
+ // Haken ALENE: sporingslinjens passerte ledd er allerede en sirkel (R8.3).
486
+ "checkmark-outline": checkmark_outline_default,
474
487
  "chevron-down-outline": chevron_down_outline_default,
488
+ // Sporvalgets rader peker videre (R8.3, DD-63) — dekorativ, etiketten bærer meningen.
489
+ "chevron-forward-outline": chevron_forward_outline_default,
475
490
  "chevron-up-outline": chevron_up_outline_default,
476
491
  "close-circle-outline": close_circle_outline_default,
477
492
  "close-outline": close_outline_default,
@@ -544,9 +559,9 @@ function Btn({
544
559
  const tema = useTema();
545
560
  const c = tema.color;
546
561
  const forbi = useTrykkForbiForelder(onPress, !!disabled, tema.touch / 2);
547
- const bakgrunn = variant === "primary" ? c.actionPrimary : variant === "secondary" ? c.surfaceRaised : "transparent";
548
- const tekstfarge = variant === "primary" ? c.onActionPrimary : variant === "danger" ? c.danger : c.actionSecondaryText;
549
- const kant = variant === "ghost" ? "transparent" : variant === "primary" ? c.actionPrimary : c.actionSecondaryBorder;
562
+ const bakgrunn = variant === "primary" ? c.actionPrimary : variant === "tonet" ? c.brandBg : variant === "secondary" ? c.surfaceRaised : "transparent";
563
+ const tekstfarge = variant === "primary" ? c.onActionPrimary : variant === "tonet" ? c.brand : variant === "danger" ? c.danger : c.actionSecondaryText;
564
+ const kant = variant === "ghost" || variant === "tonet" ? "transparent" : variant === "primary" ? c.actionPrimary : c.actionSecondaryBorder;
550
565
  return /* @__PURE__ */ jsxs(View, { style: grow ? { flex: 1 } : void 0, children: [
551
566
  /* @__PURE__ */ jsxs(
552
567
  Pressable,
@@ -621,35 +636,142 @@ function useTrykkForbiForelder(onPress, laast, slingring) {
621
636
  [slingring]
622
637
  );
623
638
  }
624
- function H({ children, sub }) {
639
+ function H({
640
+ children,
641
+ sub,
642
+ meta,
643
+ nivaa = 2,
644
+ testID
645
+ }) {
625
646
  const tema = useTema();
626
647
  return /* @__PURE__ */ jsxs(View, { style: { gap: tema.space.xs }, children: [
627
648
  /* @__PURE__ */ jsx2(
628
649
  Text,
629
650
  {
651
+ testID,
630
652
  accessibilityRole: "header",
631
653
  style: {
632
654
  color: tema.color.textPrimary,
633
- fontSize: tema.font.h2,
634
- lineHeight: tema.lineHeight.h2,
635
- fontWeight: tema.weight.semibold
655
+ fontSize: nivaa === 2 ? tema.font.h2 : tema.font.h3,
656
+ lineHeight: nivaa === 2 ? tema.lineHeight.h2 : tema.lineHeight.h3,
657
+ fontWeight: tema.weight.bold
636
658
  },
637
659
  children
638
660
  }
639
661
  ),
640
- sub ? /* @__PURE__ */ jsx2(
641
- Text,
642
- {
643
- style: {
644
- color: tema.color.textSecondary,
645
- fontSize: tema.font.small,
646
- lineHeight: tema.lineHeight.small
647
- },
648
- children: sub
649
- }
650
- ) : null
662
+ sub ? /* @__PURE__ */ jsx2(Sek, { children: sub }) : null,
663
+ meta ? /* @__PURE__ */ jsx2(Meta, { children: meta }) : null
651
664
  ] });
652
665
  }
666
+ function Brodtekst({ children, testID }) {
667
+ const tema = useTema();
668
+ return /* @__PURE__ */ jsx2(
669
+ Text,
670
+ {
671
+ testID,
672
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body },
673
+ children
674
+ }
675
+ );
676
+ }
677
+ function Sek({ children, testID }) {
678
+ const tema = useTema();
679
+ return /* @__PURE__ */ jsx2(
680
+ Text,
681
+ {
682
+ testID,
683
+ style: { color: tema.color.textSecondary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body },
684
+ children
685
+ }
686
+ );
687
+ }
688
+ function Helt({
689
+ children,
690
+ testID,
691
+ farge,
692
+ live
693
+ }) {
694
+ const tema = useTema();
695
+ return /* @__PURE__ */ jsx2(
696
+ Text,
697
+ {
698
+ testID,
699
+ ...live ? { accessibilityRole: "alert", accessibilityLiveRegion: "polite" } : {},
700
+ style: {
701
+ color: farge ?? tema.color.textPrimary,
702
+ fontSize: tema.font.h1,
703
+ lineHeight: tema.lineHeight.h1,
704
+ fontWeight: tema.weight.bold
705
+ },
706
+ children
707
+ }
708
+ );
709
+ }
710
+ function Meta({ children, testID, farge }) {
711
+ const tema = useTema();
712
+ return /* @__PURE__ */ jsx2(
713
+ Text,
714
+ {
715
+ testID,
716
+ style: { color: farge ?? tema.color.textMuted, fontSize: tema.font.small, lineHeight: tema.lineHeight.small },
717
+ children
718
+ }
719
+ );
720
+ }
721
+ function Tekstknapp({
722
+ label,
723
+ ikon,
724
+ onPress,
725
+ noytral,
726
+ disabled,
727
+ testID,
728
+ accessibilityLabel
729
+ }) {
730
+ const tema = useTema();
731
+ const farge = disabled ? tema.color.textDisabled : noytral ? tema.color.textPrimary : tema.color.actionSecondaryText;
732
+ return /* @__PURE__ */ jsxs(
733
+ Pressable,
734
+ {
735
+ testID,
736
+ accessibilityRole: "button",
737
+ accessibilityLabel: accessibilityLabel ?? label,
738
+ accessibilityState: { disabled: !!disabled },
739
+ disabled,
740
+ onPress,
741
+ style: {
742
+ alignSelf: "flex-start",
743
+ minHeight: tema.touch,
744
+ flexDirection: "row",
745
+ alignItems: "center",
746
+ gap: tema.space.sm
747
+ },
748
+ children: [
749
+ ikon ? /* @__PURE__ */ jsx2(Ikon, { navn: ikon, storrelse: "minste", farge }) : null,
750
+ /* @__PURE__ */ jsx2(Text, { style: { color: farge, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: label })
751
+ ]
752
+ }
753
+ );
754
+ }
755
+ function Pille({ children, testID }) {
756
+ const tema = useTema();
757
+ return /* @__PURE__ */ jsx2(
758
+ Text,
759
+ {
760
+ testID,
761
+ style: {
762
+ color: tema.color.info,
763
+ backgroundColor: tema.color.infoBg,
764
+ fontSize: tema.font.small,
765
+ lineHeight: tema.lineHeight.small,
766
+ fontWeight: tema.weight.semibold,
767
+ borderRadius: tema.radius.pill,
768
+ paddingHorizontal: tema.space.sm,
769
+ overflow: "hidden"
770
+ },
771
+ children
772
+ }
773
+ );
774
+ }
653
775
  function Hint({ children }) {
654
776
  const tema = useTema();
655
777
  return /* @__PURE__ */ jsx2(
@@ -667,12 +789,16 @@ function Hint({ children }) {
667
789
  function Card({
668
790
  children,
669
791
  dashed,
670
- style
792
+ style,
793
+ testID,
794
+ accessibilityLabel
671
795
  }) {
672
796
  const tema = useTema();
673
797
  return /* @__PURE__ */ jsx2(
674
798
  View,
675
799
  {
800
+ testID,
801
+ ...accessibilityLabel ? { accessibilityLabel } : {},
676
802
  style: [
677
803
  {
678
804
  backgroundColor: tema.color.surface,
@@ -689,12 +815,19 @@ function Card({
689
815
  }
690
816
  );
691
817
  }
692
- function StatusPill({ ikon, etikett, fg, bg }) {
818
+ function StatusPill({
819
+ ikon,
820
+ etikett,
821
+ fg,
822
+ bg,
823
+ testID
824
+ }) {
693
825
  const tema = useTema();
694
826
  const farge = (navn, reserve) => tema.color[navn] ?? reserve;
695
827
  return /* @__PURE__ */ jsxs(
696
828
  View,
697
829
  {
830
+ testID,
698
831
  style: {
699
832
  flexDirection: "row",
700
833
  alignItems: "center",
@@ -741,8 +874,8 @@ function Banner({
741
874
  style: {
742
875
  flex: 1,
743
876
  color: tema.color[tone],
744
- fontSize: tema.font.small,
745
- lineHeight: tema.lineHeight.small
877
+ fontSize: tema.font.body,
878
+ lineHeight: tema.lineHeight.body
746
879
  },
747
880
  children
748
881
  }
@@ -759,30 +892,82 @@ function saksnr(id) {
759
892
  return rest.length > 8 ? rest.slice(-4) : rest;
760
893
  }
761
894
  var stor = (s) => s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
895
+ var PLATTFORM_ORD = {
896
+ android: "Android",
897
+ ios: "iOS",
898
+ web: "Web",
899
+ tvos: "TV"
900
+ };
901
+ var SPRAAK_ORD = {
902
+ nb: "Norsk (bokm\xE5l)",
903
+ nn: "Norsk (nynorsk)",
904
+ no: "Norsk",
905
+ se: "Nordsamisk",
906
+ en: "Engelsk",
907
+ sv: "Svensk",
908
+ da: "Dansk",
909
+ fi: "Finsk",
910
+ is: "Islandsk",
911
+ de: "Tysk",
912
+ nl: "Nederlandsk",
913
+ fr: "Fransk",
914
+ es: "Spansk",
915
+ it: "Italiensk",
916
+ pt: "Portugisisk",
917
+ pl: "Polsk",
918
+ lt: "Litauisk",
919
+ ru: "Russisk",
920
+ uk: "Ukrainsk",
921
+ ar: "Arabisk",
922
+ so: "Somali",
923
+ ti: "Tigrinja",
924
+ tr: "Tyrkisk",
925
+ ur: "Urdu",
926
+ fa: "Persisk",
927
+ th: "Thai",
928
+ vi: "Vietnamesisk",
929
+ zh: "Kinesisk",
930
+ ja: "Japansk",
931
+ ko: "Koreansk"
932
+ };
933
+ function plattformOrd(verdi) {
934
+ return PLATTFORM_ORD[verdi.toLowerCase()] ?? stor(verdi);
935
+ }
936
+ function spraakOrd(verdi) {
937
+ const hoved = verdi.toLowerCase().split(/[-_]/)[0] ?? verdi;
938
+ return SPRAAK_ORD[hoved] ?? stor(hoved);
939
+ }
940
+ var TALLORD = ["null", "\xE9n", "to", "tre"];
941
+ var tallord = (n) => TALLORD[n] ?? String(n);
762
942
  var tekst = {
763
943
  // 2b — første valg
764
944
  valgTittel: "Hva gjelder det?",
765
945
  sporFeil: "Noe virker ikke",
946
+ /** DD-67, produkteier 2026-09-20: dette er VALGETS tekst, ikke en hjelpetekst. */
766
947
  sporFeilUnder: "Noe er galt eller virker rart",
767
948
  sporOnske: "Jeg \xF8nsker meg noe",
768
949
  sporOnskeUnder: "Noe du savner eller vil ha annerledes",
769
- // 2c — kjente feil (DD-29, DD-30)
950
+ /**
951
+ * Anonym modus (DD-62 (3)). Portalens ordlyd, med widgetens ord. ALDRI «du er ikke logget
952
+ * inn»: anonym modus er leietakerens valg ved `init()`, og widgeten vet ikke om
953
+ * innsenderen er logget inn i vertsappen.
954
+ */
955
+ sendAnonymtHint: "Innspillet kobles ikke til deg, og du kan ikke f\xF8lge det etterp\xE5.",
956
+ // 2c — kjente feil (DD-29, DD-30). Ingen undertittel: overskriften stiller spørsmålet.
770
957
  kjenteFeilTittelFeil: "Er det dette du ser?",
771
- kjenteFeilUnderFeil: "Kjenner du igjen en av disse?",
772
958
  kjenteFeilTittelOnske: "Har noen \xF8nsket dette?",
773
- kjenteFeilUnderOnske: "Ett trykk legger deg til p\xE5 \xF8nsket \u2014 ingen ny sak.",
774
959
  svarJa: "Ja, jeg ogs\xE5",
775
960
  svarLigner: "Ligner, men ikke helt",
776
961
  svarNei: "Nei, det er noe annet",
777
962
  omvei: "Omvei:",
778
963
  rettesI: (versjon) => `Rettes i ${versjon}`,
779
964
  rettetI: (versjon) => `Rettet i ${versjon}`,
965
+ /** Hvert kort er ÉN gruppe med samlet navn; de tre svarene er knapper i den. */
966
+ kjentFeilGruppe: (tittel, status, versjon) => versjon ? `Kjent feil: ${tittel}, ${status}, ${versjon}` : `Kjent feil: ${tittel}, ${status}`,
780
967
  // 2d + 2e — feltet og kontekstlinja
781
968
  /**
782
- * «Ditt innspill», ikke «Din feil» (DD-54). «Din» festet saken til personen, og
783
- * «feil» karakteriserte den før noen hadde lest den — innsenderen leste det som
784
- * skyld. Ønskesporet beholder «Ditt ønske»: et ønske er ingen feil, og der finnes
785
- * ikke problemet. De to står aldri ved siden av hverandre; sporet velges før dette.
969
+ * «Ditt innspill», ikke «Din feil» (DD-54). «Din» festet saken til personen, og «feil»
970
+ * karakteriserte den før noen hadde lest den — innsenderen leste det som skyld.
786
971
  */
787
972
  feltLabelFeil: "Ditt innspill",
788
973
  feltLabelOnske: "Ditt \xF8nske",
@@ -794,10 +979,30 @@ var tekst = {
794
979
  /** DD-44: minimum tegn er det ENESTE kravet. */
795
980
  forKort: (min) => `Minst ${min} tegn. Ingenting annet er obligatorisk.`,
796
981
  tellerFull: " \u2014 kort og konkret holder",
797
- kontekstLinje: "Legges ved: skjerm, appversjon, plattform, OS",
798
- kontekstVis: " \u2014 Vis",
982
+ /**
983
+ * DD-05 ordrett: «Én linje «Vis» under feltet ekspanderer». Lukket er linja en
984
+ * OPPSUMMERING — den navngir det innsenderen kjenner igjen; lista er hele sannheten.
985
+ */
986
+ kontekstLinjeLukket: "Skjerm og enhet legges ved",
987
+ kontekstLinjeApen: "Dette legges ved",
988
+ kontekstVis: "Vis",
989
+ kontekstSkjul: "Skjul",
799
990
  kontekstFjern: "Fjern",
800
- kontekstAldri: "Aldri: navn, e-post, telefon, posisjon eller det som st\xE5r p\xE5 skjermen.",
991
+ kontekstFjernA11y: (etikett) => `Fjern ${etikett.toLowerCase()} fra innsendingen`,
992
+ /** K5 — skjermens ene hjelpesetning, og bare når lista står. */
993
+ kontekstAldri: "Aldri navn, e-post, telefon, posisjon eller det som st\xE5r p\xE5 skjermen.",
994
+ /**
995
+ * Etikettene er portalens: samme felt, samme ord i begge flater (DD-50, presisert
996
+ * 2026-09-20). Fram til R8.3 sto det «Plattform» og «OS» her.
997
+ */
998
+ kontekstEtiketter: {
999
+ screen: "Skjerm",
1000
+ appVersion: "Appversjon",
1001
+ platform: "Enhet",
1002
+ os: "System",
1003
+ build: "Bygg",
1004
+ locale: "Spr\xE5k"
1005
+ },
801
1006
  lenketTil: (tittel) => `Lenket til: \xAB${tittel}\xBB`,
802
1007
  fjernLenke: "Fjern lenken til den kjente feilen",
803
1008
  // 2f — skjermbilde (K4, DD-39, DD-40, DD-42)
@@ -835,11 +1040,15 @@ var tekst = {
835
1040
  monsterFjern: "Fjern",
836
1041
  monsterBehold: "Behold",
837
1042
  monsterForklaring: "Teksten endres bare hvis du trykker Fjern. Vi fjerner aldri noe stille.",
838
- // 2g — kvittering
839
- kvitteringSendt: "Sendt",
840
- kvitteringRegistrert: "Registrert",
1043
+ /* 2g — kvitteringen som KORT (DD-07, P1 (a) 2026-09-20).
1044
+ Etiketten sier hva som skjedde; HELTEN er løftets setning. */
1045
+ kvitteringSendtDato: (dato) => `Sendt ${dato}`,
1046
+ kvitteringSendtAnonymtDato: (dato) => `Sendt anonymt ${dato}`,
1047
+ kvitteringRegistrertDato: (dato) => `Registrert ${dato}`,
1048
+ kvitteringLagretDato: (dato) => `Lagret ${dato}`,
841
1049
  kvitteringFeil: "Du f\xE5r beskjed n\xE5r den er rettet, eller hvis vi trenger mer.",
842
1050
  kvitteringJaOgsa: "Du f\xE5r beskjed n\xE5r den er rettet.",
1051
+ kvitteringUnder: "Ligger under \xABMine innspill\xBB og oppdaterer seg selv.",
843
1052
  saksnummer: (nr) => `Sak ${saksnr(nr)}`,
844
1053
  tilbakeTilAppen: "Tilbake til appen",
845
1054
  /** DD-42: saken er sendt, bildet kom ikke med — aldri en blokkert innsending. */
@@ -847,9 +1056,12 @@ var tekst = {
847
1056
  tekstenErLagret: "Teksten din er lagret.",
848
1057
  vedleggFeiletBanner: "Bildet ble ikke lastet opp. Saken er sendt uten det \u2014 vil du, kan du sende et nytt innspill med bilde.",
849
1058
  saksnummerUtenVedlegg: (nr) => `Sak ${saksnr(nr)} \xB7 uten vedlegg`,
850
- // 2i — tilstander
851
- koKvitteringTittel: "Lagret \u2014 sendes n\xE5r du er p\xE5 nett",
852
- offlineBanner: "Ingen nett. Lagres og sendes automatisk \u2014 du ser det under \xABMine innspill\xBB til det er sendt.",
1059
+ /* 2i — køet uten nett (DD-41, presisert 2026-09-20). Kortet lover ikke svar, og det er
1060
+ derfor ikke kvitteringen: kvitteringen kommer når køen tømmes. */
1061
+ koIngenNett: "Ingen nett",
1062
+ koHelt: "Sendes n\xE5r du er p\xE5 nett.",
1063
+ koUnder: "Du ser den under \xABMine innspill\xBB til den er sendt.",
1064
+ offlineBanner: "Ingen nett. Lagres og sendes automatisk.",
853
1065
  offlineLagre: "Lagre \u2014 sendes n\xE5r du er p\xE5 nett",
854
1066
  /** DD-41: et skjermbilde køes aldri. */
855
1067
  offlineUtenBilde: "Skjermbilde kan ikke legges ved uten nett. Teksten sendes; bildet ble ikke lagret.",
@@ -860,18 +1072,23 @@ var tekst = {
860
1072
  /** Knappen på første steg med innspill fra før (DD-62): tallet er det som gjør den til en inngang. */
861
1073
  mineMedAntall: (n) => `Mine innspill \xB7 ${n}`,
862
1074
  mineEtikett: (n) => `Mine innspill, ${n} innspill`,
863
- mineUnder: "Status og hva du kan vente deg.",
864
- mineTom: "Du har ikke sendt noe enn\xE5.",
865
- mineIkkeSendt: "Ikke sendt enn\xE5",
866
- mineSak: (nr) => `Sak ${saksnr(nr)}`,
1075
+ mineLaster: "Henter innspillene dine",
1076
+ /** DD-19: tomheten er OVERSKRIFTEN, ikke en grå linje under tittelen. */
1077
+ mineTomTittel: "Du har ikke sendt noe enn\xE5",
1078
+ /** Ordrett portalens `mineTomHint` — én innsender, to flater, samme setning. */
1079
+ mineTomHint: (leietaker) => `Det f\xF8rste innspillet tar under et minutt. Feil eller \xF8nske \u2014 ${leietaker} svarer p\xE5 begge.`,
1080
+ mineTomHintGenerisk: "Det f\xF8rste innspillet tar under et minutt. Feil eller \xF8nske \u2014 du f\xE5r svar p\xE5 begge.",
1081
+ /** Køraden har ingen saksnummer å vise — hodet sier hva den er i stedet (DD-41). */
1082
+ mineIkkeSendtHode: (spor) => `${stor(spor)} \xB7 ikke sendt enn\xE5`,
1083
+ mineFeil: "Innspillene dine kunne ikke hentes n\xE5.",
867
1084
  /** «Feil · sak 2041» — sporet først, aldri rå id og aldri kontraktens type (DD-50). */
868
1085
  sakHode: (spor, nr) => `${stor(spor)} \xB7 sak ${saksnr(nr)}`,
869
1086
  /** F14: svaret kom siden forrige gang denne enheten viste lista. */
870
1087
  nyttSvar: "Nytt svar",
871
1088
  // Leietakeren fjernet vedlegget. Bare AT — aldri hvorfor, av hvem eller når.
872
1089
  bildeFjernet: "Bildet er fjernet.",
873
- svarFra: (leietaker) => `Svar fra ${leietaker}`,
874
- svarFraGenerisk: "Svar",
1090
+ svarFra: (leietaker, dato) => `Svar fra ${leietaker} \xB7 ${dato}`,
1091
+ svarFraGenerisk: (dato) => `Svar \xB7 ${dato}`,
875
1092
  // DD-69 — «Legg til mer»: innsenderens egne ord, ikke et svar på svaret.
876
1093
  leggTilMer: "Legg til mer",
877
1094
  leggTilMerLabel: "Legg til mer p\xE5 denne saken",
@@ -882,80 +1099,115 @@ var tekst = {
882
1099
  lagtTil: "Lagt til",
883
1100
  tilleggTak: "Du har lagt til tre ganger. Har du mer, send et nytt innspill.",
884
1101
  tilleggLukket: "Saken er avsluttet \u2014 send et nytt innspill.",
1102
+ /** F34: serverens egen setning (InnspelApiError) — aldri en rå feil. */
885
1103
  tilleggFeil: (arsak) => `Kunne ikke legge til: ${arsak} Teksten din er beholdt.`,
1104
+ tilleggIngenNett: "Ingen nett. Teksten din er beholdt \u2014 pr\xF8v igjen n\xE5r du er p\xE5 nett.",
1105
+ tilleggFeilGenerisk: "Kunne ikke legge til. Teksten din er beholdt \u2014 pr\xF8v igjen.",
886
1106
  sendNytt: "Send nytt innspill",
887
1107
  /** Tom tilstand: det finnes ikke noe «nytt» å sende når ingenting er sendt. */
888
1108
  sendForste: "Send innspill",
889
- // 3a — invitasjonsbanneret (DD-12)
1109
+ /* Sporingslinjen (DD-08/DD-28 presisert 2026-09-20). Ordene er innsenderens, aldri
1110
+ kontraktens: ingen status-enum, ingen «deadline». Samme ord som portalen. */
1111
+ sporEtikett: "Sakens gang",
1112
+ sporSvarInnen: "Svar innen",
1113
+ /** Mottatt: fristen finnes ikke ennå, og vi lover ingen dato på en sak ingen har åpnet. */
1114
+ sporDatoenSettes: "dato kommer",
1115
+ /** Planlagt/Bygges: kontrakten har ingen leveringsdato, og DD-28 forbyr en ETA. */
1116
+ sporIngenDato: "ingen dato lovet",
1117
+ sporNaarTenantTarDen: (leietaker) => `n\xE5r ${leietaker} tar den`,
1118
+ sporNaarDenTasOpp: "n\xE5r de tar den",
1119
+ /** P3 (a), produkteier 2026-09-20. Klientregel på `deadlineAt` — ingen ny status. */
1120
+ sporFristenErGatt: "Fristen er g\xE5tt",
1121
+ // 3a — invitasjonsbanneret (DD-12). Kontakttaket står IKKE her (DD-14).
890
1122
  invitasjonRegion: "Invitasjon til betaprogram",
891
1123
  invitasjonHva: (navn) => `Vil du teste \xAB${navn}\xBB?`,
892
- invitasjonKontakter: (maks) => `Vi tar kontakt maks ${maks} ganger. Du kan g\xE5 ut n\xE5r som helst.`,
1124
+ /** Én meta-linje med det kontrakten har: antall oppgaver og perioden. */
1125
+ invitasjonMeta: (oppgaver, periode2) => `${oppgaver} oppgaver \xB7 ${periode2}`,
893
1126
  lesMer: "Les mer og bli med",
894
1127
  avvisInvitasjon: "Avvis invitasjonen",
895
1128
  // 3b — aksepten (DD-13, DD-32, DD-37)
896
- akseptHva: "Hva testes",
897
- /** DD-32: tallene på én linje, FØR forklaringen — N oppgaver · ca. M min hver · dato–dato · maks K kontakter. */
898
- akseptTall: (oppgaver, minutter, periode2, kontakter) => `${oppgaver} oppgaver \xB7 ca. ${minutter} min hver \xB7 ${periode2} \xB7 maks ${kontakter} kontakter`,
1129
+ /**
1130
+ * DD-32, presisert 2026-09-20: tallene skal være SANNE. Summen når anslagene er ulike —
1131
+ * et snitt av 5, 3 og 2 er ikke sant for noen av oppgavene.
1132
+ */
1133
+ akseptTallSum: (oppgaver, minutter, periode2) => `${oppgaver} oppgaver \xB7 ca. ${minutter} min i alt \xB7 ${periode2}`,
1134
+ akseptTallHver: (oppgaver, minutter, periode2) => `${oppgaver} oppgaver \xB7 ca. ${minutter} min hver \xB7 ${periode2}`,
899
1135
  akseptOppgaver: "Hva vi ber om",
900
1136
  akseptOppgaveTid: (minutter) => `ca. ${minutter} min`,
901
- akseptKjenteFeil: (antall) => `Kjente feil (${antall})`,
902
- akseptKjenteFeilUnder: "Disse trenger du ikke melde \u2014 vi vet om dem.",
1137
+ akseptKjenteFeil: "Kjente feil vi vet om",
903
1138
  akseptInnsamling: "Hva som samles inn",
904
- akseptInnsamlingTekst: "Skjerm, appversjon, plattform, OS og hva du svarer. Aldri navn, e-post, telefon eller posisjon.",
905
- akseptVilkar: "Les vilk\xE5rene (\xE5pnes i nettleser)",
906
- akseptVilkarHint: "Bare en lenke. Ingen avkryssing, ingen signatur \u2014 \xABBli med\xBB binder deg ikke til noe.",
907
- akseptIngenVilkar: "Ingen vilk\xE5r, ingen avtale \u2014 plattformen kjenner ikke navnet ditt og kan ikke inng\xE5 \xE9n.",
908
- akseptUtgang: "Du kan g\xE5 ut n\xE5r som helst \u2014 herfra.",
1139
+ /** Samme ord som kontekstlista (DD-50): «enhet», ikke «plattform». */
1140
+ akseptInnsamlingTekst: "Skjerm, appversjon, enhet og det du svarer. Aldri navn, e-post, telefon eller posisjon.",
1141
+ akseptVilkar: "Les vilk\xE5rene",
1142
+ /**
1143
+ * Skjermens ENE hjelpesetning: taket og utgangen i én (DD-67). «høyst N» — tallet er
1144
+ * `maxContacts`, et TAK som kan senkes og aldri heves, og antall oppfølginger er malene,
1145
+ * som kan være færre. «Vi spør tre ganger» lover noe som ikke er sant (DD-14).
1146
+ */
1147
+ akseptTakOgUtgang: (maks) => `Vi sp\xF8r h\xF8yst ${tallord(maks)} ${maks === 1 ? "gang" : "ganger"} underveis. Du kan g\xE5 ut n\xE5r som helst \u2014 ingen vilk\xE5r, ingen avtale.`,
1148
+ akseptTakOgUtgangVilkar: (maks) => `Vi sp\xF8r h\xF8yst ${tallord(maks)} ${maks === 1 ? "gang" : "ganger"} underveis. Du kan g\xE5 ut n\xE5r som helst.`,
909
1149
  bliMed: "Bli med",
910
1150
  bliMedHint: "Samtykket gjelder bare dette programmet.",
911
1151
  /** DD-12: tokenet er engangs og kom i leietakerens egen kanal — plattformen sender aldri. */
912
1152
  bliMedUtenToken: "\xC5pne lenken vi sendte deg for \xE5 bli med.",
913
1153
  akseptFeil: (arsak) => `Kunne ikke bli med: ${arsak}`,
914
- // 3c (M3.1-delen) — deltakelsen og «Gå ut» (DD-36)
1154
+ // 3c — deltakelsen og «Gå ut» (DD-36). Kontakttaket står IKKE her (DD-14).
915
1155
  deltakelseRegion: "Ditt betaprogram",
916
- deltakelsePeriode: (periode2, brukt, maks) => `${periode2} \xB7 Vi tar kontakt maks ${maks} ganger \u2014 ${brukt} brukt`,
917
- deltakelseOppgaverKommer: "Oppgavene kan gj\xF8res n\xE5r det passer deg.",
918
1156
  gaaUt: "G\xE5 ut av programmet",
919
1157
  gaaUtTittel: "G\xE5 ut av programmet?",
920
1158
  gaaUtTekst: (navn) => `Du tas ut av testgruppen med en gang. \xAB${navn}\xBB sl\xE5s av for deg, og vi tar ikke kontakt igjen. Det du allerede har svart, beholdes.`,
921
1159
  bliVaerende: "Bli v\xE6rende",
922
1160
  gaaUtBekreft: "G\xE5 ut",
923
- // 3c (M3.2) — oppgavene og «Hvordan gikk det?»: tre lukkede valg, aldri en skala
1161
+ /* Programmets sporingslinje (P1 (a), produkteier 2026-09-20): deltakelsen bæres av
1162
+ linjen, ikke av et kvitteringskort — merkefargen er for det som er SENDT (DD-41). */
1163
+ programSporEtikett: "Programmets gang",
1164
+ programBleMed: "Du ble med",
1165
+ programGjort: (gjort, av) => `${gjort} av ${av} gjort`,
1166
+ programOver: "Programmet er over",
1167
+ /** Under nå-leddet, ÉN linje. Aldri «to igjen»: «1 av 3» sier alt tallet sier (DD-08). */
1168
+ programNaarDetPasser: "n\xE5r det passer",
1169
+ // 3c — oppgavene
924
1170
  oppgaverTittel: "Oppgavene",
925
- oppgaveIkkeBegynt: "Ikke begynt",
926
1171
  oppgaveGjort: "Gjort",
927
1172
  oppgaveGjortLabel: (tittel) => `Gjort: ${tittel}`,
928
- oppgaveGjortMed: (utfall) => `Pr\xF8vd \xB7 ${utfall}`,
1173
+ /** Oppgavens ENE meta-linje i `small` (DD-67). Setningen hennes står i `body` under. */
1174
+ oppgaveGjortMeta: (dato, utfall) => `Gjort ${dato} \xB7 ${utfall.toLowerCase()}`,
1175
+ oppgaveTid: (minutter, skjerm) => `ca. ${minutter} min${skjerm ? ` \xB7 ${skjerm}` : ""}`,
1176
+ oppgaveUbekreftet: "Svaret ble ikke bekreftet \u2014 merk den p\xE5 nytt",
1177
+ oppgaveRadA11y: (nr, tittel, status) => `Oppgave ${nr}: ${tittel}, ${status}`,
1178
+ oppgaveIkkeGjort: "ikke gjort",
1179
+ // 3e — «Hvordan gikk det?»: tre lukkede valg, aldri en skala (DD-15)
929
1180
  hvordanGikkDet: "Hvordan gikk det?",
930
1181
  utfallFungerte: "Fungerte",
931
1182
  utfallDelvis: "Fungerte delvis",
932
1183
  utfallIkke: "Fungerte ikke",
933
- setningLabel: "Vil du si \xE9n setning om det? (valgfritt)",
934
- setningPlaceholder: "Kopien kom, men rullesjefen manglet p\xE5 torsdag.",
1184
+ setningLabel: "Vil du si \xE9n setning om det?",
1185
+ setningValgfritt: "Valgfritt",
935
1186
  lagre: "Lagre",
936
- lagreHint: "Ferdig \u2014 ingen flere sp\xF8rsm\xE5l n\xE5.",
937
1187
  /** Etter «Ikke»: feilsporet er vertens — plattformen navigerer aldri selv. */
938
1188
  meldFeil: "Meld det som feil",
939
- meldFeilHint: "Gikk det ikke? Et innspill hjelper oss \xE5 finne ut hvorfor.",
940
1189
  svarFeil: (arsak) => `Kunne ikke lagre svaret: ${arsak}`,
941
- // 3d (M3.2) — oppfølgingskortene (DD-34): arten avgjør knappene
1190
+ // 3d — oppfølgingskortene (DD-34): arten avgjør knappene. Ingen kontaktnummer (DD-14).
942
1191
  oppfolgingRegion: "Oppf\xF8lging fra betaprogrammet",
943
- oppfolgingKontakt: (nr, maks) => `Kontakt ${nr} av ${maks} \xB7 tar under ett minutt`,
944
- oppfolgingPaaminnelseHint: (nr, maks) => `Kontakt ${nr} av ${maks} \xB7 planlagt p\xE5minnelse`,
945
- oppfolgingUtgangHint: (nr, maks) => `Kontakt ${nr} av ${maks} \xB7 den siste vi sender`,
1192
+ oppfolgingKost: "Ett sp\xF8rsm\xE5l \xB7 tar under ett minutt",
946
1193
  senere: "Senere",
947
1194
  svarNaa: "Svar n\xE5",
948
1195
  aapneOppgavene: "\xC5pne oppgavene",
949
1196
  // Felles
950
1197
  tilbake: "Tilbake",
951
1198
  lukk: "Lukk",
952
- venterPaaNett: "Venter p\xE5 nett \u2014 sendes automatisk",
1199
+ venterPaaNett: "Venter p\xE5 nett",
953
1200
  feil: "feil",
954
1201
  onske: "\xF8nske"
955
1202
  };
956
1203
  var lofte = {
957
- venterNett: "Sendes automatisk n\xE5r du er p\xE5 nett \u2014 kvitteringen kommer da."
1204
+ venterNett: "Sendes automatisk n\xE5r du er p\xE5 nett."
958
1205
  };
1206
+ function kontekstVerdi(felt, verdi) {
1207
+ if (felt === "platform") return plattformOrd(verdi);
1208
+ if (felt === "locale") return spraakOrd(verdi);
1209
+ return verdi;
1210
+ }
959
1211
 
960
1212
  // src/widget/Felt.tsx
961
1213
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -989,20 +1241,13 @@ function Felt({
989
1241
  const full = brukt >= textMaxLength;
990
1242
  const visTeller = brukt >= textMaxLength * 0.8;
991
1243
  const uavklart = funn.find((f) => !beholdt.includes(f.match));
992
- const linjer = useMemo2(() => {
993
- const etiketter = {
994
- screen: "Skjerm",
995
- appVersion: "Appversjon",
996
- platform: "Plattform",
997
- os: "OS",
998
- build: "Bygg",
999
- locale: "Spr\xE5k"
1000
- };
1001
- return Object.entries(etiketter).map(([felt, etikett]) => {
1002
- const verdi2 = kontekst[felt];
1003
- return verdi2 && !fjernedeFelter.includes(felt) ? { felt, etikett, verdi: verdi2 } : null;
1004
- }).filter((x) => x !== null);
1005
- }, [kontekst, fjernedeFelter]);
1244
+ const linjer = useMemo2(
1245
+ () => Object.entries(tekst.kontekstEtiketter).map(([felt, etikett]) => {
1246
+ const r\u00E5 = kontekst[felt];
1247
+ return r\u00E5 && !fjernedeFelter.includes(felt) ? { felt, etikett, verdi: kontekstVerdi(felt, r\u00E5) } : null;
1248
+ }).filter((x) => x !== null),
1249
+ [kontekst, fjernedeFelter]
1250
+ );
1006
1251
  return /* @__PURE__ */ jsxs2(View2, { testID: "skjema", style: { flexGrow: 1, flexShrink: 1, gap: tema.space.md }, children: [
1007
1252
  /* @__PURE__ */ jsxs2(
1008
1253
  ScrollView,
@@ -1059,8 +1304,8 @@ function Felt({
1059
1304
  accessibilityLiveRegion: "polite",
1060
1305
  style: {
1061
1306
  color: tema.color.warning,
1062
- fontSize: tema.font.small,
1063
- lineHeight: tema.lineHeight.small,
1307
+ fontSize: tema.font.body,
1308
+ lineHeight: tema.lineHeight.body,
1064
1309
  fontWeight: tema.weight.medium
1065
1310
  },
1066
1311
  children: tekst.monsterSpm[uavklart.kind]
@@ -1197,17 +1442,16 @@ function Felt({
1197
1442
  bildeNotat ? /* @__PURE__ */ jsx3(View2, { testID: "bilde-notat", children: /* @__PURE__ */ jsx3(Hint, { children: bildeNotat }) }) : null
1198
1443
  ] })
1199
1444
  ) : null,
1200
- /* @__PURE__ */ jsxs2(View2, { style: { borderTopWidth: tema.hairline, borderTopColor: tema.color.border, paddingTop: tema.space.sm }, children: [
1201
- /* @__PURE__ */ jsx3(
1445
+ /* @__PURE__ */ jsxs2(View2, { style: { borderTopWidth: tema.hairline, borderTopColor: tema.color.border, paddingTop: tema.space.xs }, children: [
1446
+ /* @__PURE__ */ jsxs2(
1202
1447
  Pressable2,
1203
1448
  {
1204
1449
  testID: "kontekst-bryter",
1205
1450
  accessibilityRole: "button",
1206
1451
  accessibilityState: { expanded: apen },
1207
- accessibilityLabel: `${tekst.kontekstLinje}${apen ? "" : tekst.kontekstVis}`,
1208
1452
  onPress: () => setApen((a) => !a),
1209
- style: { minHeight: tema.touch, justifyContent: "center" },
1210
- children: /* @__PURE__ */ jsxs2(View2, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1453
+ style: { minHeight: tema.touch, flexDirection: "row", alignItems: "center", gap: tema.space.sm },
1454
+ children: [
1211
1455
  /* @__PURE__ */ jsx3(
1212
1456
  Ikon,
1213
1457
  {
@@ -1216,11 +1460,9 @@ function Felt({
1216
1460
  farge: tema.color.textSecondary
1217
1461
  }
1218
1462
  ),
1219
- /* @__PURE__ */ jsxs2(Text2, { style: { flex: 1, color: tema.color.textSecondary, fontSize: tema.font.small }, children: [
1220
- tekst.kontekstLinje,
1221
- apen ? "" : tekst.kontekstVis
1222
- ] })
1223
- ] })
1463
+ /* @__PURE__ */ jsx3(Text2, { style: { flex: 1, color: tema.color.textSecondary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: apen ? tekst.kontekstLinjeApen : tekst.kontekstLinjeLukket }),
1464
+ /* @__PURE__ */ jsx3(Text2, { style: { color: tema.color.actionSecondaryText, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: apen ? tekst.kontekstSkjul : tekst.kontekstVis })
1465
+ ]
1224
1466
  }
1225
1467
  ),
1226
1468
  apen ? /* @__PURE__ */ jsxs2(View2, { children: [
@@ -1230,26 +1472,29 @@ function Felt({
1230
1472
  style: {
1231
1473
  flexDirection: "row",
1232
1474
  alignItems: "center",
1233
- gap: tema.space.sm,
1475
+ gap: tema.space.md,
1234
1476
  minHeight: tema.touch,
1235
- borderBottomWidth: tema.hairline,
1236
- borderBottomColor: tema.color.border
1477
+ borderTopWidth: tema.hairline,
1478
+ borderTopColor: tema.color.border
1237
1479
  },
1238
1480
  children: [
1239
- /* @__PURE__ */ jsx3(Text2, { style: { color: tema.color.textMuted, fontSize: tema.font.small, minWidth: tema.touch * 2 }, children: l.etikett }),
1240
- /* @__PURE__ */ jsx3(Text2, { style: { flex: 1, color: tema.color.textPrimary, fontSize: tema.font.small }, children: l.verdi }),
1481
+ /* @__PURE__ */ jsx3(Meta, { testID: `kontekst-etikett-${l.felt}`, children: l.etikett }),
1482
+ /* @__PURE__ */ jsx3(View2, { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx3(
1483
+ Text2,
1484
+ {
1485
+ testID: `kontekst-verdi-${l.felt}`,
1486
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.semibold },
1487
+ children: l.verdi
1488
+ }
1489
+ ) }),
1241
1490
  /* @__PURE__ */ jsx3(
1242
- Pressable2,
1491
+ Tekstknapp,
1243
1492
  {
1244
1493
  testID: `fjern-${l.felt}`,
1245
- accessibilityRole: "button",
1246
- accessibilityLabel: `${tekst.kontekstFjern} ${l.etikett.toLowerCase()} fra innsendingen`,
1247
- onPress: () => onFjernKontekst(l.felt),
1248
- style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
1249
- children: /* @__PURE__ */ jsxs2(View2, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1250
- /* @__PURE__ */ jsx3(Ikon, { navn: "close-outline", storrelse: "minste", farge: tema.color.textSecondary }),
1251
- /* @__PURE__ */ jsx3(Text2, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.kontekstFjern })
1252
- ] })
1494
+ ikon: "close-outline",
1495
+ label: tekst.kontekstFjern,
1496
+ accessibilityLabel: tekst.kontekstFjernA11y(l.etikett),
1497
+ onPress: () => onFjernKontekst(l.felt)
1253
1498
  }
1254
1499
  )
1255
1500
  ]
@@ -1281,26 +1526,23 @@ function Felt({
1281
1526
  import "react";
1282
1527
  import { Pressable as Pressable3, Text as Text3, View as View3 } from "react-native";
1283
1528
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1284
- function Valg({ onVelg }) {
1529
+ function Valg({ onVelg, anonym }) {
1285
1530
  const tema = useTema();
1286
- const flate = (spor, ikon, label, under) => /* @__PURE__ */ jsxs3(
1531
+ const rad = (spor, ikon, label, under, forst) => /* @__PURE__ */ jsxs3(
1287
1532
  Pressable3,
1288
1533
  {
1289
1534
  testID: `spor-${spor}`,
1290
1535
  accessibilityRole: "button",
1291
- accessibilityLabel: `${label}. ${under}`,
1536
+ accessibilityLabel: `${label}, ${under}`,
1292
1537
  onPress: () => onVelg(spor),
1293
1538
  style: {
1294
- flex: 1,
1295
- minHeight: tema.touch * 3,
1296
- backgroundColor: tema.color.surface,
1297
- borderWidth: tema.hairline,
1298
- borderColor: tema.color.borderStrong,
1299
- borderRadius: tema.radius.lg,
1539
+ flexDirection: "row",
1300
1540
  alignItems: "center",
1301
- justifyContent: "center",
1302
- gap: tema.space.sm,
1303
- padding: tema.space.md
1541
+ gap: tema.space.md,
1542
+ minHeight: tema.touch + tema.space.lg,
1543
+ paddingVertical: tema.space.sm,
1544
+ borderTopWidth: forst ? 0 : tema.hairline,
1545
+ borderTopColor: tema.color.border
1304
1546
  },
1305
1547
  children: [
1306
1548
  /* @__PURE__ */ jsx4(
@@ -1308,8 +1550,8 @@ function Valg({ onVelg }) {
1308
1550
  {
1309
1551
  testID: `spor-${spor}-ikonflate`,
1310
1552
  style: {
1311
- width: 2 * tema.icon.inline + 2 * tema.space.md,
1312
- height: 2 * tema.icon.inline + 2 * tema.space.md,
1553
+ width: tema.touch + tema.space.sm,
1554
+ height: tema.touch + tema.space.sm,
1313
1555
  borderRadius: tema.radius.pill,
1314
1556
  backgroundColor: tema.color.brandBg,
1315
1557
  alignItems: "center",
@@ -1318,28 +1560,21 @@ function Valg({ onVelg }) {
1318
1560
  children: /* @__PURE__ */ jsx4(Ikon, { navn: ikon, storrelse: "stor", farge: tema.color.brand })
1319
1561
  }
1320
1562
  ),
1321
- /* @__PURE__ */ jsx4(
1322
- Text3,
1323
- {
1324
- style: {
1325
- color: tema.color.textPrimary,
1326
- fontSize: tema.font.h3,
1327
- fontWeight: tema.weight.semibold,
1328
- textAlign: "center"
1329
- },
1330
- children: label
1331
- }
1332
- ),
1333
- /* @__PURE__ */ jsx4(Text3, { style: { color: tema.color.textMuted, fontSize: tema.font.small, textAlign: "center" }, children: under })
1563
+ /* @__PURE__ */ jsxs3(View3, { style: { flex: 1, minWidth: 0 }, children: [
1564
+ /* @__PURE__ */ jsx4(Text3, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.semibold }, children: label }),
1565
+ /* @__PURE__ */ jsx4(Text3, { style: { color: tema.color.textMuted, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: under })
1566
+ ] }),
1567
+ /* @__PURE__ */ jsx4(Ikon, { navn: "chevron-forward-outline", storrelse: "minste", farge: tema.color.textMuted })
1334
1568
  ]
1335
1569
  }
1336
1570
  );
1337
- return /* @__PURE__ */ jsxs3(View3, { style: { flex: 1, gap: tema.space.lg }, children: [
1571
+ return /* @__PURE__ */ jsxs3(View3, { style: { gap: tema.space.lg }, children: [
1338
1572
  /* @__PURE__ */ jsx4(H, { children: tekst.valgTittel }),
1339
- /* @__PURE__ */ jsx4(View3, { style: { flex: 1, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs3(View3, { style: { flexDirection: "row", gap: tema.space.md }, children: [
1340
- flate("feil", "bug", tekst.sporFeil, tekst.sporFeilUnder),
1341
- flate("onske", "bulb", tekst.sporOnske, tekst.sporOnskeUnder)
1342
- ] }) })
1573
+ /* @__PURE__ */ jsxs3(View3, { children: [
1574
+ rad("feil", "bug", tekst.sporFeil, tekst.sporFeilUnder, true),
1575
+ rad("onske", "bulb", tekst.sporOnske, tekst.sporOnskeUnder, false)
1576
+ ] }),
1577
+ anonym ? /* @__PURE__ */ jsx4(Hint, { children: tekst.sendAnonymtHint }) : null
1343
1578
  ] });
1344
1579
  }
1345
1580
 
@@ -1358,84 +1593,102 @@ function KjenteFeil({
1358
1593
  onNei
1359
1594
  }) {
1360
1595
  const tema = useTema();
1596
+ const tittel = spor === "onske" ? tekst.kjenteFeilTittelOnske : tekst.kjenteFeilTittelFeil;
1361
1597
  if (laster) {
1362
1598
  return /* @__PURE__ */ jsxs4(View4, { style: { flex: 1, gap: tema.space.md }, children: [
1363
- /* @__PURE__ */ jsx5(H, { sub: spor === "onske" ? tekst.kjenteFeilUnderOnske : tekst.kjenteFeilUnderFeil, children: spor === "onske" ? tekst.kjenteFeilTittelOnske : tekst.kjenteFeilTittelFeil }),
1599
+ /* @__PURE__ */ jsx5(H, { children: tittel }),
1364
1600
  /* @__PURE__ */ jsx5(ActivityIndicator, { accessibilityLabel: "Sjekker kjente feil", color: tema.color.textSecondary })
1365
1601
  ] });
1366
1602
  }
1367
1603
  return /* @__PURE__ */ jsxs4(View4, { testID: "kjente-feil", style: { flexGrow: 1, flexShrink: 1, gap: tema.space.md }, children: [
1368
- /* @__PURE__ */ jsx5(H, { sub: spor === "onske" ? tekst.kjenteFeilUnderOnske : tekst.kjenteFeilUnderFeil, children: spor === "onske" ? tekst.kjenteFeilTittelOnske : tekst.kjenteFeilTittelFeil }),
1604
+ /* @__PURE__ */ jsx5(H, { children: tittel }),
1369
1605
  /* @__PURE__ */ jsx5(
1370
1606
  ScrollView2,
1371
1607
  {
1372
1608
  testID: "kjente-feil-liste",
1373
1609
  style: { flexGrow: 0, flexShrink: 1 },
1374
- contentContainerStyle: { gap: tema.space.md },
1375
1610
  keyboardShouldPersistTaps: "handled",
1376
- children: kort.slice(0, MAKS_KORT).map((k) => {
1611
+ children: kort.slice(0, MAKS_KORT).map((k, i) => {
1377
1612
  const o = knownIssueStatus[k.status] ?? knownIssueStatus.aktiv;
1378
- const versjon = k.fixedIn ? k.status === "fikset" ? tekst.rettetI(k.fixedIn) : tekst.rettesI(k.fixedIn) : void 0;
1379
- const kontekst = versjon ? `${k.title}. ${o.etikett}. ${versjon}` : `${k.title}. ${o.etikett}`;
1380
- return /* @__PURE__ */ jsxs4(Card, { children: [
1381
- /* @__PURE__ */ jsx5(
1382
- Text4,
1383
- {
1384
- style: {
1385
- color: tema.color.textPrimary,
1386
- fontSize: tema.font.body,
1387
- lineHeight: tema.lineHeight.body,
1388
- fontWeight: tema.weight.medium
1389
- },
1390
- children: k.title
1391
- }
1392
- ),
1393
- k.workaround ? /* @__PURE__ */ jsxs4(
1394
- Text4,
1395
- {
1396
- style: {
1397
- color: tema.color.textSecondary,
1398
- fontSize: tema.font.small,
1399
- lineHeight: tema.lineHeight.small
1400
- },
1401
- children: [
1613
+ const rettet = k.status === "fikset";
1614
+ const statusOrd = rettet && k.fixedIn ? tekst.rettetI(k.fixedIn) : o.etikett;
1615
+ const tillegg = !rettet && k.fixedIn ? `\xB7 ${tekst.rettesI(k.fixedIn).toLowerCase()}` : void 0;
1616
+ const gruppe = tekst.kjentFeilGruppe(k.title, statusOrd, tillegg?.replace("\xB7 ", ""));
1617
+ return /* @__PURE__ */ jsxs4(
1618
+ View4,
1619
+ {
1620
+ testID: `kjent-feil-${k.id}`,
1621
+ style: {
1622
+ gap: tema.space.sm,
1623
+ paddingVertical: tema.space.md,
1624
+ borderTopWidth: i === 0 ? 0 : tema.hairline,
1625
+ borderTopColor: tema.color.border
1626
+ },
1627
+ children: [
1628
+ /* @__PURE__ */ jsx5(
1629
+ Text4,
1630
+ {
1631
+ testID: `kjent-feil-tittel-${k.id}`,
1632
+ style: {
1633
+ color: tema.color.textPrimary,
1634
+ fontSize: tema.font.body,
1635
+ lineHeight: tema.lineHeight.body,
1636
+ fontWeight: tema.weight.semibold
1637
+ },
1638
+ children: k.title
1639
+ }
1640
+ ),
1641
+ k.workaround ? /* @__PURE__ */ jsxs4(Sek, { testID: `kjent-feil-omvei-${k.id}`, children: [
1402
1642
  tekst.omvei,
1403
1643
  " ",
1404
1644
  k.workaround
1405
- ]
1406
- }
1407
- ) : null,
1408
- /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.sm, flexWrap: "wrap" }, children: [
1409
- /* @__PURE__ */ jsx5(StatusPill, { ikon: o.ikon, etikett: o.etikett, fg: o.fg, bg: o.bg }),
1410
- versjon ? /* @__PURE__ */ jsx5(Text4, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: versjon }) : null
1411
- ] }),
1412
- /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
1413
- /* @__PURE__ */ jsx5(
1414
- Btn,
1415
- {
1416
- grow: true,
1417
- testID: `ja-ogsa-${k.id}`,
1418
- label: tekst.svarJa,
1419
- accessibilityLabel: `${tekst.svarJa}. ${kontekst}`,
1420
- disabled: sender,
1421
- busy: sender,
1422
- onPress: () => onJaOgsa(k)
1423
- }
1424
- ),
1425
- /* @__PURE__ */ jsx5(
1426
- Btn,
1427
- {
1428
- grow: true,
1429
- variant: "secondary",
1430
- testID: `ligner-${k.id}`,
1431
- label: tekst.svarLigner,
1432
- accessibilityLabel: `${tekst.svarLigner}. ${kontekst}`,
1433
- disabled: sender,
1434
- onPress: () => onLigner(k)
1435
- }
1436
- )
1437
- ] })
1438
- ] }, k.id);
1645
+ ] }) : null,
1646
+ /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.sm, flexWrap: "wrap" }, children: [
1647
+ /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1648
+ /* @__PURE__ */ jsx5(Ikon, { navn: o.ikon, storrelse: "minste", farge: tema.color[o.fg] }),
1649
+ /* @__PURE__ */ jsx5(
1650
+ Text4,
1651
+ {
1652
+ style: {
1653
+ color: tema.color[o.fg],
1654
+ fontSize: tema.font.small,
1655
+ lineHeight: tema.lineHeight.small,
1656
+ fontWeight: tema.weight.semibold
1657
+ },
1658
+ children: statusOrd
1659
+ }
1660
+ )
1661
+ ] }),
1662
+ tillegg ? /* @__PURE__ */ jsx5(Text4, { style: { color: tema.color.textMuted, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: tillegg }) : null
1663
+ ] }),
1664
+ /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.md }, children: [
1665
+ /* @__PURE__ */ jsx5(
1666
+ Btn,
1667
+ {
1668
+ variant: "tonet",
1669
+ testID: `ja-ogsa-${k.id}`,
1670
+ label: tekst.svarJa,
1671
+ accessibilityLabel: `${tekst.svarJa}. ${gruppe}`,
1672
+ disabled: sender,
1673
+ busy: sender,
1674
+ onPress: () => onJaOgsa(k)
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ jsx5(
1678
+ Tekstknapp,
1679
+ {
1680
+ testID: `ligner-${k.id}`,
1681
+ label: tekst.svarLigner,
1682
+ accessibilityLabel: `${tekst.svarLigner}. ${gruppe}`,
1683
+ disabled: sender,
1684
+ onPress: () => onLigner(k)
1685
+ }
1686
+ )
1687
+ ] })
1688
+ ]
1689
+ },
1690
+ k.id
1691
+ );
1439
1692
  })
1440
1693
  }
1441
1694
  ),
@@ -1445,6 +1698,10 @@ function KjenteFeil({
1445
1698
 
1446
1699
  // src/widget/Kvittering.tsx
1447
1700
  import "react";
1701
+ import { Text as Text6, View as View6 } from "react-native";
1702
+
1703
+ // src/widget/Sporingslinje.tsx
1704
+ import "react";
1448
1705
  import { Text as Text5, View as View5 } from "react-native";
1449
1706
 
1450
1707
  // src/widget/status.ts
@@ -1453,6 +1710,12 @@ function formaterFrist(iso) {
1453
1710
  if (Number.isNaN(d.getTime())) return iso;
1454
1711
  return new Intl.DateTimeFormat("nb-NO", { day: "numeric", month: "long" }).format(d);
1455
1712
  }
1713
+ var KORT_MANED = ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"];
1714
+ function formaterKortFrist(iso) {
1715
+ const d = new Date(iso);
1716
+ if (Number.isNaN(d.getTime())) return iso;
1717
+ return `${d.getDate()}. ${KORT_MANED[d.getMonth()]}`;
1718
+ }
1456
1719
  function statusVisning(status, type, deadlineAt) {
1457
1720
  const o = submissionStatus[status];
1458
1721
  const spor = type === "onske" ? "onske" : "feil";
@@ -1476,67 +1739,266 @@ var venterVisning = {
1476
1739
  lofte: lofte.venterNett
1477
1740
  };
1478
1741
 
1479
- // src/widget/Kvittering.tsx
1742
+ // src/widget/Sporingslinje.tsx
1480
1743
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1744
+ var HOVEDLINJE = ["ny", "vurderes", "planlagt", "bygges", "levert"];
1745
+ function erApen(rad) {
1746
+ if (rad.pending === true) return false;
1747
+ return rad.statusType === "reviewing" || rad.statusType === "active";
1748
+ }
1749
+ function sporingsledd(rad, tenantName, naa = /* @__PURE__ */ new Date()) {
1750
+ if (rad.pending === true || !erApen(rad)) return [];
1751
+ const type = rad.type;
1752
+ const navn = (status) => statusVisning(status, type).etikett;
1753
+ const ikon = (status) => statusVisning(status, type).ikon;
1754
+ const ledd = [];
1755
+ if (rad.status === "kjent_feil") {
1756
+ ledd.push({ nokkel: "ny", etikett: navn("ny"), tilstand: "gjort", detalj: formaterFrist(rad.createdAt) });
1757
+ ledd.push({ nokkel: "kjent_feil", etikett: navn("kjent_feil"), tilstand: "naa", ikon: ikon("kjent_feil"), detalj: formaterFrist(rad.statusChangedAt) });
1758
+ ledd.push({ nokkel: "slutt", etikett: navn("levert"), tilstand: "kommer", detalj: tekst.sporIngenDato });
1759
+ return ledd;
1760
+ }
1761
+ const naaIndeks = HOVEDLINJE.indexOf(rad.status);
1762
+ if (naaIndeks < 0) return [];
1763
+ for (let i = 0; i <= naaIndeks; i++) {
1764
+ const status = HOVEDLINJE[i];
1765
+ const erNaa = i === naaIndeks;
1766
+ ledd.push({
1767
+ nokkel: status,
1768
+ etikett: navn(status),
1769
+ tilstand: erNaa ? "naa" : "gjort",
1770
+ ...erNaa ? { ikon: ikon(status) } : {},
1771
+ // Mottatt har `createdAt`, nå-leddet har `statusChangedAt`. Et passert ledd mellom dem
1772
+ // har ingen dato i kontrakten, og får derfor ingen.
1773
+ ...i === 0 ? { detalj: formaterFrist(rad.createdAt) } : erNaa ? { detalj: formaterFrist(rad.statusChangedAt) } : {}
1774
+ });
1775
+ }
1776
+ if (rad.status === "ny") {
1777
+ ledd.push({
1778
+ nokkel: "vurderes",
1779
+ etikett: navn("vurderes"),
1780
+ tilstand: "kommer",
1781
+ detalj: tenantName ? tekst.sporNaarTenantTarDen(tenantName) : tekst.sporNaarDenTasOpp
1782
+ });
1783
+ }
1784
+ if (rad.statusType === "reviewing") {
1785
+ const frist = rad.deadlineAt;
1786
+ const gatt = frist !== void 0 && rad.status === "vurderes" && new Date(frist).getTime() < naa.getTime();
1787
+ ledd.push(
1788
+ gatt ? { nokkel: "slutt", etikett: tekst.sporFristenErGatt, tilstand: "brutt", ikon: "warning-outline", tall: formaterKortFrist(frist) } : {
1789
+ nokkel: "slutt",
1790
+ etikett: tekst.sporSvarInnen,
1791
+ tilstand: "kommer",
1792
+ ...frist ? { tall: formaterKortFrist(frist) } : { detalj: tekst.sporDatoenSettes }
1793
+ }
1794
+ );
1795
+ } else {
1796
+ ledd.push({ nokkel: "slutt", etikett: navn("levert"), tilstand: "kommer", detalj: tekst.sporIngenDato });
1797
+ }
1798
+ return ledd;
1799
+ }
1800
+ function Sporingslinje({
1801
+ ledd,
1802
+ testID,
1803
+ etikett = tekst.sporEtikett
1804
+ }) {
1805
+ const tema = useTema();
1806
+ if (ledd.length === 0) return null;
1807
+ const farge = (l) => l.tilstand === "brutt" ? tema.color.warning : l.tilstand === "gjort" ? tema.color.success : l.tilstand === "naa" ? tema.color.brand : tema.color.borderStrong;
1808
+ return /* @__PURE__ */ jsx6(
1809
+ View5,
1810
+ {
1811
+ testID,
1812
+ accessibilityRole: "list",
1813
+ accessibilityLabel: etikett,
1814
+ style: { flexDirection: "row", alignItems: "flex-start", gap: tema.space.xs },
1815
+ children: ledd.map((l, i) => {
1816
+ const siste = i === ledd.length - 1;
1817
+ const c = farge(l);
1818
+ return /* @__PURE__ */ jsxs5(
1819
+ View5,
1820
+ {
1821
+ testID: testID ? `${testID}-ledd-${l.nokkel}` : void 0,
1822
+ style: siste ? { flexShrink: 0, gap: tema.space.xs } : { flex: 1, minWidth: 0, gap: tema.space.xs },
1823
+ children: [
1824
+ /* @__PURE__ */ jsxs5(View5, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1825
+ /* @__PURE__ */ jsx6(
1826
+ View5,
1827
+ {
1828
+ style: {
1829
+ width: tema.space.lg,
1830
+ height: tema.space.lg,
1831
+ borderRadius: tema.radius.pill,
1832
+ borderWidth: tema.hairline * 2,
1833
+ borderColor: c,
1834
+ borderStyle: l.tilstand === "kommer" ? "dashed" : "solid",
1835
+ backgroundColor: l.tilstand === "gjort" ? tema.color.success : "transparent",
1836
+ alignItems: "center",
1837
+ justifyContent: "center"
1838
+ },
1839
+ children: l.tilstand === "gjort" ? /* @__PURE__ */ jsx6(Ikon, { navn: "checkmark-outline", storrelse: "minste", farge: tema.color.bg }) : l.ikon ? /* @__PURE__ */ jsx6(Ikon, { navn: l.ikon, storrelse: "minste", farge: c }) : null
1840
+ }
1841
+ ),
1842
+ !siste ? /* @__PURE__ */ jsx6(
1843
+ View5,
1844
+ {
1845
+ style: {
1846
+ flex: 1,
1847
+ height: tema.hairline * 2,
1848
+ borderRadius: tema.radius.pill,
1849
+ backgroundColor: l.tilstand === "gjort" ? tema.color.success : tema.color.borderStrong
1850
+ }
1851
+ }
1852
+ ) : null
1853
+ ] }),
1854
+ /* @__PURE__ */ jsx6(
1855
+ Text5,
1856
+ {
1857
+ style: {
1858
+ color: l.tilstand === "brutt" ? tema.color.warning : l.tilstand === "kommer" ? tema.color.textMuted : tema.color.textPrimary,
1859
+ fontSize: tema.font.small,
1860
+ lineHeight: tema.lineHeight.small,
1861
+ fontWeight: l.tilstand === "naa" || l.tilstand === "brutt" ? tema.weight.semibold : tema.weight.regular
1862
+ },
1863
+ children: l.etikett
1864
+ }
1865
+ ),
1866
+ l.tall !== void 0 ? /* @__PURE__ */ jsx6(Helt, { testID: testID ? `${testID}-tall` : void 0, farge: l.tilstand === "brutt" ? tema.color.warning : tema.color.textPrimary, children: l.tall }) : l.detalj !== void 0 ? /* @__PURE__ */ jsx6(Text5, { style: { color: tema.color.textMuted, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: l.detalj }) : null
1867
+ ]
1868
+ },
1869
+ l.nokkel
1870
+ );
1871
+ })
1872
+ }
1873
+ );
1874
+ }
1875
+
1876
+ // src/widget/Kvittering.tsx
1877
+ import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1481
1878
  function Kvittering({
1482
1879
  art,
1483
1880
  saksnummer,
1484
1881
  vedlegg,
1485
1882
  frist,
1883
+ sak,
1884
+ anonym,
1885
+ tenantName,
1486
1886
  onLukk
1487
1887
  }) {
1488
1888
  const tema = useTema();
1489
- const innhold = {
1490
- feil: { h: tekst.kvitteringSendt, p: tekst.kvitteringFeil },
1491
- // Løftet er NØYAKTIG det «Mine innspill» og panelet viser for «Vurderes»:
1492
- // det leses fra temaet, så kvitteringen og statusen ikke kan si to ting.
1493
- onske: { h: tekst.kvitteringSendt, p: statusVisning("vurderes", "onske", frist).lofte },
1494
- jaOgsa: { h: tekst.kvitteringRegistrert, p: tekst.kvitteringJaOgsa },
1495
- // Køet offline: kvitteringen kan IKKE love svar på noe som ikke er sendt
1496
- // (DD-41 presiserer DD-07). Den lover bare at det sendes.
1497
- k\u00F8: { h: tekst.koKvitteringTittel, p: tekst.offlineBanner }
1889
+ const ko = art === "k\xF8";
1890
+ const helt = {
1891
+ feil: tekst.kvitteringFeil,
1892
+ // Løftet er NØYAKTIG det «Mine innspill» og panelet viser for «Vurderes»: det leses fra
1893
+ // temaet, så kvitteringen og statusen ikke kan si to ting.
1894
+ onske: statusVisning("vurderes", "onske", frist).lofte,
1895
+ jaOgsa: tekst.kvitteringJaOgsa,
1896
+ k\u00F8: tekst.koHelt
1498
1897
  }[art];
1499
- const overskrift = vedlegg === "feilet" ? tekst.kvitteringVedleggFeilet : innhold.h;
1500
- const brodtekst = vedlegg === "feilet" ? `${tekst.tekstenErLagret} ${innhold.p}` : innhold.p;
1501
- return /* @__PURE__ */ jsxs5(View5, { style: { flex: 1, justifyContent: "center", gap: tema.space.lg }, children: [
1502
- /* @__PURE__ */ jsxs5(View5, { style: { alignItems: "center", gap: tema.space.md }, children: [
1503
- /* @__PURE__ */ jsx6(
1504
- Ikon,
1505
- {
1506
- navn: art === "k\xF8" ? "swap-vertical-outline" : "checkmark-circle-outline",
1507
- storrelse: "stor",
1508
- farge: art === "k\xF8" ? tema.color.neutral : tema.color.success
1509
- }
1510
- ),
1511
- /* @__PURE__ */ jsx6(H, { children: overskrift }),
1512
- vedlegg === "feilet" ? /* @__PURE__ */ jsx6(Banner, { ikon: "warning-outline", tone: "warning", children: tekst.vedleggFeiletBanner }) : null,
1513
- vedlegg === "forkastet" ? /* @__PURE__ */ jsx6(Banner, { ikon: "image-outline", tone: "info", children: tekst.offlineUtenBilde }) : null,
1514
- /* @__PURE__ */ jsx6(
1515
- Text5,
1516
- {
1517
- testID: "kvittering-tekst",
1518
- accessibilityRole: "alert",
1519
- accessibilityLiveRegion: "polite",
1520
- style: {
1521
- color: tema.color.textPrimary,
1522
- fontSize: tema.font.body,
1523
- lineHeight: tema.lineHeight.body,
1524
- textAlign: "center"
1525
- },
1526
- children: brodtekst
1527
- }
1528
- ),
1529
- saksnummer ? /* @__PURE__ */ jsx6(Hint, { children: vedlegg === "feilet" ? tekst.saksnummerUtenVedlegg(saksnummer) : tekst.saksnummer(saksnummer) }) : null
1530
- ] }),
1531
- /* @__PURE__ */ jsx6(Btn, { testID: "tilbake-til-appen", label: tekst.tilbakeTilAppen, onPress: onLukk })
1532
- ] });
1533
- }
1534
-
1535
- // src/widget/MineInnspill.tsx
1536
- import { InnspelApiError } from "@innspel/core";
1537
- import { useEffect, useState as useState2 } from "react";
1538
- import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable4, ScrollView as ScrollView3, Text as Text6, TextInput as TextInput2, View as View6 } from "react-native";
1539
-
1898
+ const dato = formaterFrist(sak?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString());
1899
+ const etikett = vedlegg === "feilet" ? tekst.kvitteringVedleggFeilet : ko ? tekst.kvitteringLagretDato(dato) : art === "jaOgsa" ? tekst.kvitteringRegistrertDato(dato) : anonym ? tekst.kvitteringSendtAnonymtDato(dato) : tekst.kvitteringSendtDato(dato);
1900
+ const ledd = sak && !ko ? sporingsledd(sak, tenantName) : [];
1901
+ const under = anonym ? void 0 : ko ? tekst.koUnder : saksnummer ? tekst.kvitteringUnder : void 0;
1902
+ return /* @__PURE__ */ jsxs6(View6, { testID: "kvittering", style: { flex: 1, gap: tema.space.md }, children: [
1903
+ vedlegg === "feilet" ? /* @__PURE__ */ jsx7(Banner, { ikon: "warning-outline", tone: "warning", children: tekst.vedleggFeiletBanner }) : null,
1904
+ vedlegg === "forkastet" ? /* @__PURE__ */ jsx7(Banner, { ikon: "image-outline", tone: "info", children: tekst.offlineUtenBilde }) : null,
1905
+ /* @__PURE__ */ jsxs6(
1906
+ View6,
1907
+ {
1908
+ testID: "kvittering-kort",
1909
+ style: {
1910
+ backgroundColor: ko ? tema.color.surface : tema.color.brandFill,
1911
+ borderRadius: tema.radius.lg,
1912
+ borderWidth: ko ? tema.hairline : 0,
1913
+ borderStyle: ko ? "dashed" : "solid",
1914
+ borderColor: tema.color.borderInteractive,
1915
+ padding: tema.space.md,
1916
+ gap: tema.space.md
1917
+ },
1918
+ children: [
1919
+ /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: tema.space.sm }, children: [
1920
+ /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.sm, flexShrink: 1 }, children: [
1921
+ /* @__PURE__ */ jsx7(
1922
+ Ikon,
1923
+ {
1924
+ navn: ko ? "swap-vertical-outline" : "checkmark-circle-outline",
1925
+ farge: ko ? tema.color.textSecondary : tema.color.onBrandFill
1926
+ }
1927
+ ),
1928
+ tenantName ? /* @__PURE__ */ jsx7(
1929
+ Text6,
1930
+ {
1931
+ style: {
1932
+ color: ko ? tema.color.textPrimary : tema.color.onBrandFill,
1933
+ fontSize: tema.font.body,
1934
+ fontWeight: tema.weight.bold
1935
+ },
1936
+ children: tenantName
1937
+ }
1938
+ ) : null
1939
+ ] }),
1940
+ ko ? /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1941
+ /* @__PURE__ */ jsx7(Ikon, { navn: "cloud-offline-outline", storrelse: "minste", farge: tema.color.textMuted }),
1942
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textMuted, fontSize: tema.font.small, fontWeight: tema.weight.semibold }, children: tekst.koIngenNett })
1943
+ ] }) : saksnummer ? /* @__PURE__ */ jsx7(
1944
+ Text6,
1945
+ {
1946
+ style: { color: tema.color.onBrandFill, fontSize: tema.font.small, fontWeight: tema.weight.semibold },
1947
+ children: vedlegg === "feilet" ? tekst.saksnummerUtenVedlegg(saksnummer) : tekst.saksnummer(saksnummer)
1948
+ }
1949
+ ) : null
1950
+ ] }),
1951
+ /* @__PURE__ */ jsxs6(View6, { style: { gap: tema.space.xs }, children: [
1952
+ /* @__PURE__ */ jsx7(
1953
+ Text6,
1954
+ {
1955
+ style: {
1956
+ color: ko ? tema.color.textMuted : tema.color.onBrandFill,
1957
+ fontSize: tema.font.small,
1958
+ lineHeight: tema.lineHeight.small
1959
+ },
1960
+ children: etikett
1961
+ }
1962
+ ),
1963
+ /* @__PURE__ */ jsx7(Helt, { testID: "kvittering-tekst", live: true, farge: ko ? tema.color.textPrimary : tema.color.onBrandFill, children: vedlegg === "feilet" ? `${tekst.tekstenErLagret} ${helt}` : helt })
1964
+ ] }),
1965
+ under ? /* @__PURE__ */ jsxs6(Fragment, { children: [
1966
+ /* @__PURE__ */ jsx7(
1967
+ View6,
1968
+ {
1969
+ style: {
1970
+ borderTopWidth: tema.hairline,
1971
+ borderTopColor: ko ? tema.color.borderStrong : tema.color.onBrandFill,
1972
+ borderStyle: "dashed"
1973
+ }
1974
+ }
1975
+ ),
1976
+ /* @__PURE__ */ jsx7(
1977
+ Text6,
1978
+ {
1979
+ testID: "kvittering-under",
1980
+ style: {
1981
+ color: ko ? tema.color.textPrimary : tema.color.onBrandFill,
1982
+ fontSize: tema.font.body,
1983
+ lineHeight: tema.lineHeight.body
1984
+ },
1985
+ children: under
1986
+ }
1987
+ )
1988
+ ] }) : null
1989
+ ]
1990
+ }
1991
+ ),
1992
+ ledd.length > 0 ? /* @__PURE__ */ jsx7(Sporingslinje, { ledd, testID: "kvittering-spor" }) : null,
1993
+ /* @__PURE__ */ jsx7(View6, { style: { flex: 1, justifyContent: "flex-end", paddingTop: tema.space.sm }, children: /* @__PURE__ */ jsx7(Btn, { testID: "tilbake-til-appen", label: tekst.tilbakeTilAppen, onPress: onLukk }) })
1994
+ ] });
1995
+ }
1996
+
1997
+ // src/widget/MineInnspill.tsx
1998
+ import { InnspelApiError, NettverksFeil } from "@innspel/core";
1999
+ import { forwardRef, useEffect, useImperativeHandle, useRef as useRef2, useState as useState2 } from "react";
2000
+ import { ActivityIndicator as ActivityIndicator2, Keyboard, ScrollView as ScrollView3, Text as Text7, TextInput as TextInput2, View as View7 } from "react-native";
2001
+
1540
2002
  // src/widget/nyttSvar.ts
1541
2003
  var N\u00D8KKEL = "innspel:svar-sett";
1542
2004
  async function merkNyeSvar(rader, storage) {
@@ -1558,8 +2020,8 @@ async function markerSvarSett(storage, n\u00E5 = Date.now()) {
1558
2020
  }
1559
2021
 
1560
2022
  // src/widget/MineInnspill.tsx
1561
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1562
- function MineInnspill({
2023
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2024
+ var MineInnspill = forwardRef(function MineInnspill2({
1563
2025
  rader,
1564
2026
  laster,
1565
2027
  tenantName,
@@ -1568,8 +2030,9 @@ function MineInnspill({
1568
2030
  leggTil,
1569
2031
  onOppdatert,
1570
2032
  minTextLength,
1571
- textMaxLength
1572
- }) {
2033
+ textMaxLength,
2034
+ utkastLager
2035
+ }, ref) {
1573
2036
  const tema = useTema();
1574
2037
  const min = minTextLength ?? 10;
1575
2038
  const maks = textMaxLength ?? 280;
@@ -1578,6 +2041,35 @@ function MineInnspill({
1578
2041
  const [sender, setSender] = useState2(false);
1579
2042
  const [feil, setFeil] = useState2();
1580
2043
  const [lagtTil, setLagtTil] = useState2();
2044
+ const egetLager = useRef2(/* @__PURE__ */ new Map());
2045
+ const lager = utkastLager ?? egetLager.current;
2046
+ const rulleRef = useRef2(null);
2047
+ const kortY = useRef2(/* @__PURE__ */ new Map());
2048
+ const apneFelt = (id) => {
2049
+ setApen(id);
2050
+ setUtkast(lager.get(id) ?? "");
2051
+ setFeil(void 0);
2052
+ setLagtTil(void 0);
2053
+ const y = kortY.current.get(id);
2054
+ if (y !== void 0) rulleRef.current?.scrollTo({ y, animated: true });
2055
+ };
2056
+ const lukkFelt = () => {
2057
+ if (apen === null) return false;
2058
+ Keyboard.dismiss();
2059
+ if (utkast.trim()) lager.set(apen, utkast);
2060
+ else lager.delete(apen);
2061
+ setApen(null);
2062
+ setUtkast("");
2063
+ setFeil(void 0);
2064
+ return true;
2065
+ };
2066
+ const avbryt = () => {
2067
+ if (apen !== null) lager.delete(apen);
2068
+ setApen(null);
2069
+ setUtkast("");
2070
+ setFeil(void 0);
2071
+ };
2072
+ useImperativeHandle(ref, () => ({ lukkFelt }));
1581
2073
  const send = async (id) => {
1582
2074
  if (!leggTil) return;
1583
2075
  setSender(true);
@@ -1585,12 +2077,13 @@ function MineInnspill({
1585
2077
  try {
1586
2078
  const sak = await leggTil(id, utkast.trim());
1587
2079
  onOppdatert?.(sak);
2080
+ lager.delete(id);
1588
2081
  setApen(null);
1589
2082
  setUtkast("");
1590
2083
  setLagtTil(id);
1591
2084
  } catch (e) {
1592
2085
  const kode = e instanceof InnspelApiError ? e.code : void 0;
1593
- const tekstFeil = kode === "addendum_limit_reached" ? tekst.tilleggTak : kode === "submission_closed" ? tekst.tilleggLukket : tekst.tilleggFeil(e instanceof Error && e.message ? e.message : "ukjent feil.");
2086
+ const tekstFeil = kode === "addendum_limit_reached" ? tekst.tilleggTak : kode === "submission_closed" ? tekst.tilleggLukket : e instanceof InnspelApiError && e.message ? tekst.tilleggFeil(e.message) : e instanceof NettverksFeil ? tekst.tilleggIngenNett : tekst.tilleggFeilGenerisk;
1594
2087
  setFeil({ id, tekst: tekstFeil });
1595
2088
  } finally {
1596
2089
  setSender(false);
@@ -1611,9 +2104,10 @@ function MineInnspill({
1611
2104
  useEffect(() => {
1612
2105
  if (!laster && rader.length) void markerSvarSett(storage).catch(() => void 0);
1613
2106
  }, [storage, laster, rader]);
1614
- return /* @__PURE__ */ jsxs6(View6, { style: { flex: 1, gap: tema.space.md }, children: [
1615
- /* @__PURE__ */ jsx7(H, { sub: tekst.mineUnder, children: tekst.mineTittel }),
1616
- laster ? /* @__PURE__ */ jsx7(ActivityIndicator2, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ jsx7(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ jsx7(ScrollView3, { style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, children: visning.map(({ rad, nytt }) => {
2107
+ const tom = !laster && rader.length === 0;
2108
+ return /* @__PURE__ */ jsxs7(View7, { style: { flex: 1, gap: tema.space.md }, children: [
2109
+ tom ? /* @__PURE__ */ jsx8(H, { sub: tenantName ? tekst.mineTomHint(tenantName) : tekst.mineTomHintGenerisk, children: tekst.mineTomTittel }) : /* @__PURE__ */ jsx8(H, { children: tekst.mineTittel }),
2110
+ laster ? /* @__PURE__ */ jsx8(ActivityIndicator2, { accessibilityLabel: tekst.mineLaster, color: tema.color.textSecondary }) : tom ? null : /* @__PURE__ */ jsx8(ScrollView3, { ref: rulleRef, style: { flex: 1 }, contentContainerStyle: { gap: tema.space.md }, keyboardShouldPersistTaps: "handled", children: visning.map(({ rad, nytt }) => {
1617
2111
  const venter = rad.pending === true;
1618
2112
  const v = venter ? venterVisning : statusVisning(rad.status, rad.type, rad.deadlineAt);
1619
2113
  const nokkel = venter ? rad.clientRef : rad.id;
@@ -1624,196 +2118,157 @@ function MineInnspill({
1624
2118
  const taketN\u00E5dd = !venter && rad.canAddAddendum === false && tillegg.length >= 3;
1625
2119
  const feltApent = sakId !== void 0 && apen === sakId;
1626
2120
  const brukt = utkast.length;
1627
- const forKort = brukt < min;
1628
2121
  const full = brukt >= maks;
1629
2122
  const visTeller = brukt >= maks * 0.8;
1630
- return /* @__PURE__ */ jsxs6(Card, { dashed: venter, children: [
1631
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs, flexWrap: "wrap" }, children: [
1632
- /* @__PURE__ */ jsx7(Hint, { children: venter ? `${tekst.mineIkkeSendt} \xB7 ${rad.type === "onske" ? tekst.onske : tekst.feil}` : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
1633
- nytt ? /* @__PURE__ */ jsx7(
1634
- Text6,
1635
- {
1636
- testID: "nytt-svar",
1637
- style: {
1638
- color: tema.color.info,
1639
- backgroundColor: tema.color.infoBg,
1640
- fontSize: tema.font.tiny,
1641
- fontWeight: tema.weight.semibold,
1642
- borderRadius: tema.radius.pill,
1643
- paddingHorizontal: tema.space.sm
1644
- },
1645
- children: tekst.nyttSvar
1646
- }
1647
- ) : null
1648
- ] }),
1649
- /* @__PURE__ */ jsx7(
1650
- Text6,
1651
- {
1652
- style: {
1653
- color: tema.color.textPrimary,
1654
- fontSize: tema.font.body,
1655
- lineHeight: tema.lineHeight.body
1656
- },
1657
- children: rad.text
1658
- }
1659
- ),
1660
- tillegg.length > 0 ? /* @__PURE__ */ jsx7(View6, { testID: `tillegg-${sakId}`, style: { gap: tema.space.xs }, children: tillegg.map((a) => /* @__PURE__ */ jsxs6(
1661
- View6,
1662
- {
1663
- style: {
1664
- borderLeftWidth: tema.hairline * 2,
1665
- borderLeftColor: tema.color.border,
1666
- paddingLeft: tema.space.sm,
1667
- gap: tema.space.xs
1668
- },
1669
- children: [
1670
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1671
- /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.textSecondary }),
1672
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.duLaTil(formaterFrist(a.createdAt)) })
1673
- ] }),
1674
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textPrimary, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: a.text })
1675
- ]
2123
+ const ledd = venter ? [] : sporingsledd(rad, tenantName);
2124
+ return /* @__PURE__ */ jsx8(
2125
+ View7,
2126
+ {
2127
+ onLayout: (e) => {
2128
+ if (sakId !== void 0) kortY.current.set(sakId, e.nativeEvent.layout.y);
1676
2129
  },
1677
- a.id
1678
- )) }) : null,
1679
- /* @__PURE__ */ jsxs6(View6, { style: { gap: tema.space.xs }, children: [
1680
- /* @__PURE__ */ jsx7(StatusPill, { ikon: v.ikon, etikett: v.etikett, fg: v.fg, bg: v.bg }),
1681
- /* @__PURE__ */ jsx7(Hint, { children: v.lofte })
1682
- ] }),
1683
- sakId !== void 0 && lagtTil === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "polite", testID: `lagt-til-${sakId}`, style: { color: tema.color.success, fontSize: tema.font.small }, children: tekst.lagtTil }) : null,
1684
- feltApent ? /* @__PURE__ */ jsxs6(View6, { testID: `tillegg-felt-${sakId}`, style: { gap: tema.space.sm }, children: [
1685
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.leggTilMerLabel }),
1686
- /* @__PURE__ */ jsx7(
1687
- TextInput2,
1688
- {
1689
- testID: "tillegg-tekst",
1690
- accessibilityLabel: tekst.leggTilMerLabel,
1691
- value: utkast,
1692
- onChangeText: setUtkast,
1693
- maxLength: maks,
1694
- multiline: true,
1695
- numberOfLines: 3,
1696
- autoFocus: true,
1697
- placeholder: tekst.leggTilMerPlaceholder,
1698
- placeholderTextColor: tema.color.textMuted,
1699
- style: {
1700
- backgroundColor: tema.color.surfaceRaised,
1701
- borderWidth: tema.hairline,
1702
- borderColor: full ? tema.color.warning : tema.color.borderStrong,
1703
- borderRadius: tema.radius.md,
1704
- padding: tema.space.md,
1705
- color: tema.color.textPrimary,
1706
- fontSize: tema.font.body,
1707
- lineHeight: tema.lineHeight.body,
1708
- minHeight: tema.touch * 2,
1709
- textAlignVertical: "top"
1710
- }
1711
- }
1712
- ),
1713
- visTeller ? /* @__PURE__ */ jsxs6(
1714
- Text6,
1715
- {
1716
- testID: "tillegg-teller",
1717
- accessibilityLiveRegion: full ? "assertive" : "polite",
1718
- style: { alignSelf: "flex-end", color: full ? tema.color.warning : tema.color.textMuted, fontSize: tema.font.small },
1719
- children: [
1720
- brukt,
1721
- " / ",
1722
- maks,
1723
- full ? tekst.tellerFull : ""
1724
- ]
1725
- }
1726
- ) : null,
1727
- feil?.id === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "assertive", testID: `tillegg-feil-${sakId}`, style: { color: tema.color.danger, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: feil.tekst }) : null,
1728
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
1729
- /* @__PURE__ */ jsx7(
1730
- Btn,
2130
+ children: /* @__PURE__ */ jsxs7(Card, { dashed: venter, testID: `sakskort-${nokkel}`, children: [
2131
+ /* @__PURE__ */ jsxs7(View7, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.sm, flexWrap: "wrap" }, children: [
2132
+ /* @__PURE__ */ jsx8(
2133
+ Ikon,
2134
+ {
2135
+ navn: rad.type === "onske" ? "bulb" : "bug",
2136
+ storrelse: "minste",
2137
+ farge: tema.color.brand
2138
+ }
2139
+ ),
2140
+ /* @__PURE__ */ jsx8(Meta, { children: venter ? tekst.mineIkkeSendtHode(rad.type === "onske" ? tekst.onske : tekst.feil) : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
2141
+ nytt ? /* @__PURE__ */ jsx8(Pille, { testID: "nytt-svar", children: tekst.nyttSvar }) : null
2142
+ ] }),
2143
+ /* @__PURE__ */ jsx8(Brodtekst, { testID: `sakstekst-${nokkel}`, children: rad.text }),
2144
+ tillegg.length > 0 ? /* @__PURE__ */ jsx8(View7, { testID: `tillegg-${sakId}`, style: { gap: tema.space.sm }, children: tillegg.map((a) => /* @__PURE__ */ jsxs7(
2145
+ View7,
1731
2146
  {
1732
- testID: "tillegg-send",
1733
- label: sender ? tekst.sender : tekst.send,
1734
- disabled: forKort || sender,
1735
- busy: sender,
1736
- ...forKort ? { hint: tekst.forKort(min) } : {},
1737
- onPress: () => sakId !== void 0 && void send(sakId),
1738
- grow: true
1739
- }
1740
- ),
1741
- /* @__PURE__ */ jsx7(
1742
- Btn,
2147
+ style: {
2148
+ borderLeftWidth: tema.hairline * 2,
2149
+ borderLeftColor: tema.color.border,
2150
+ paddingLeft: tema.space.md,
2151
+ gap: tema.space.xs
2152
+ },
2153
+ children: [
2154
+ /* @__PURE__ */ jsx8(Meta, { children: tekst.duLaTil(formaterFrist(a.createdAt)) }),
2155
+ /* @__PURE__ */ jsx8(Brodtekst, { testID: `tillegg-tekst-${a.id}`, children: a.text })
2156
+ ]
2157
+ },
2158
+ a.id
2159
+ )) }) : null,
2160
+ svar ? /* @__PURE__ */ jsxs7(
2161
+ View7,
1743
2162
  {
1744
- testID: "tillegg-avbryt",
1745
- label: tekst.avbryt,
1746
- variant: "secondary",
1747
- onPress: () => {
1748
- setApen(null);
1749
- setUtkast("");
1750
- setFeil(void 0);
2163
+ testID: `svar-${sakId}`,
2164
+ style: {
2165
+ borderLeftWidth: tema.hairline * 2,
2166
+ borderLeftColor: tema.color.brand,
2167
+ paddingLeft: tema.space.md,
2168
+ gap: tema.space.xs
1751
2169
  },
1752
- grow: true
2170
+ children: [
2171
+ /* @__PURE__ */ jsx8(Meta, { children: tenantName ? tekst.svarFra(tenantName, formaterFrist(svar.at)) : tekst.svarFraGenerisk(formaterFrist(svar.at)) }),
2172
+ /* @__PURE__ */ jsx8(Brodtekst, { testID: `svar-tekst-${sakId}`, children: svar.text })
2173
+ ]
1753
2174
  }
1754
- )
1755
- ] }),
1756
- /* @__PURE__ */ jsx7(Hint, { children: tekst.leggTilMerHint })
1757
- ] }) : kanLeggeTil ? /* @__PURE__ */ jsxs6(
1758
- Pressable4,
1759
- {
1760
- testID: `legg-til-mer-${sakId}`,
1761
- accessibilityRole: "button",
1762
- accessibilityLabel: tekst.leggTilMerLabel,
1763
- onPress: () => {
1764
- if (sakId === void 0) return;
1765
- setApen(sakId);
1766
- setUtkast("");
1767
- setFeil(void 0);
1768
- setLagtTil(void 0);
1769
- },
1770
- style: { alignSelf: "flex-start", minHeight: tema.touch, flexDirection: "row", alignItems: "center", gap: tema.space.xs, paddingHorizontal: tema.space.sm },
1771
- children: [
1772
- /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.actionSecondaryText }),
1773
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.actionSecondaryText, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: tekst.leggTilMer })
1774
- ]
1775
- }
1776
- ) : taketN\u00E5dd ? /* @__PURE__ */ jsx7(Hint, { children: tekst.tilleggTak }) : null,
1777
- !venter && rad.attachmentRemoved ? /* @__PURE__ */ jsxs6(View6, { testID: `bilde-fjernet-${rad.id}`, style: { flexDirection: "row", gap: tema.space.xs, alignItems: "center" }, children: [
1778
- /* @__PURE__ */ jsx7(Ikon, { navn: "trash-outline", storrelse: "minste", farge: tema.color.textMuted }),
1779
- /* @__PURE__ */ jsx7(Hint, { children: tekst.bildeFjernet })
1780
- ] }) : null,
1781
- svar ? /* @__PURE__ */ jsxs6(
1782
- View6,
1783
- {
1784
- style: {
1785
- borderLeftWidth: tema.hairline * 2,
1786
- borderLeftColor: tema.color.brand,
1787
- paddingLeft: tema.space.sm,
1788
- gap: tema.space.xs
1789
- },
1790
- children: [
1791
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tenantName ? tekst.svarFra(tenantName) : tekst.svarFraGenerisk }),
1792
- /* @__PURE__ */ jsx7(
1793
- Text6,
2175
+ ) : null,
2176
+ ledd.length > 0 ? /* @__PURE__ */ jsx8(Sporingslinje, { ledd, testID: `spor-${sakId}` }) : /* @__PURE__ */ jsx8(StatusPill, { testID: `status-pille-${nokkel}`, ikon: v.ikon, etikett: v.etikett, fg: v.fg, bg: v.bg }),
2177
+ /* @__PURE__ */ jsx8(Sek, { testID: `lofte-${nokkel}`, children: v.lofte }),
2178
+ !venter && rad.attachmentRemoved ? /* @__PURE__ */ jsxs7(View7, { testID: `bilde-fjernet-${rad.id}`, style: { flexDirection: "row", gap: tema.space.xs, alignItems: "center" }, children: [
2179
+ /* @__PURE__ */ jsx8(Ikon, { navn: "trash-outline", storrelse: "minste", farge: tema.color.textMuted }),
2180
+ /* @__PURE__ */ jsx8(Hint, { children: tekst.bildeFjernet })
2181
+ ] }) : null,
2182
+ sakId !== void 0 && lagtTil === sakId ? /* @__PURE__ */ jsx8(Text7, { accessibilityLiveRegion: "polite", testID: `lagt-til-${sakId}`, style: { color: tema.color.success, fontSize: tema.font.small }, children: tekst.lagtTil }) : null,
2183
+ feltApent ? /* @__PURE__ */ jsxs7(View7, { testID: `tillegg-felt-${sakId}`, style: { gap: tema.space.sm }, children: [
2184
+ /* @__PURE__ */ jsx8(Meta, { children: tekst.leggTilMerLabel }),
2185
+ /* @__PURE__ */ jsx8(
2186
+ TextInput2,
1794
2187
  {
2188
+ testID: "tillegg-tekst",
2189
+ accessibilityLabel: tekst.leggTilMerLabel,
2190
+ value: utkast,
2191
+ onChangeText: setUtkast,
2192
+ maxLength: maks,
2193
+ multiline: true,
2194
+ numberOfLines: 3,
2195
+ autoFocus: true,
2196
+ placeholder: tekst.leggTilMerPlaceholder,
2197
+ placeholderTextColor: tema.color.textMuted,
1795
2198
  style: {
2199
+ backgroundColor: tema.color.surfaceRaised,
2200
+ borderWidth: tema.hairline,
2201
+ borderColor: full ? tema.color.warning : tema.color.borderStrong,
2202
+ borderRadius: tema.radius.md,
2203
+ padding: tema.space.md,
1796
2204
  color: tema.color.textPrimary,
1797
- fontSize: tema.font.small,
1798
- lineHeight: tema.lineHeight.small
1799
- },
1800
- children: svar.text
2205
+ fontSize: tema.font.body,
2206
+ lineHeight: tema.lineHeight.body,
2207
+ minHeight: tema.touch * 2,
2208
+ textAlignVertical: "top"
2209
+ }
1801
2210
  }
1802
- )
1803
- ]
1804
- }
1805
- ) : null
1806
- ] }, nokkel);
2211
+ ),
2212
+ visTeller ? /* @__PURE__ */ jsxs7(
2213
+ Text7,
2214
+ {
2215
+ testID: "tillegg-teller",
2216
+ accessibilityLiveRegion: full ? "assertive" : "polite",
2217
+ style: { alignSelf: "flex-end", color: full ? tema.color.warning : tema.color.textMuted, fontSize: tema.font.small },
2218
+ children: [
2219
+ brukt,
2220
+ " / ",
2221
+ maks,
2222
+ full ? tekst.tellerFull : ""
2223
+ ]
2224
+ }
2225
+ ) : null,
2226
+ feil?.id === sakId ? /* @__PURE__ */ jsx8(Text7, { accessibilityLiveRegion: "assertive", testID: `tillegg-feil-${sakId}`, style: { color: tema.color.danger, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: feil.tekst }) : null
2227
+ ] }) : kanLeggeTil ? /* @__PURE__ */ jsx8(
2228
+ Tekstknapp,
2229
+ {
2230
+ testID: `legg-til-mer-${sakId}`,
2231
+ ikon: "add-outline",
2232
+ label: tekst.leggTilMer,
2233
+ accessibilityLabel: tekst.leggTilMerLabel,
2234
+ onPress: () => sakId !== void 0 && apneFelt(sakId)
2235
+ }
2236
+ ) : taketN\u00E5dd ? /* @__PURE__ */ jsx8(Hint, { children: tekst.tilleggTak }) : null
2237
+ ] })
2238
+ },
2239
+ nokkel
2240
+ );
1807
2241
  }) }),
1808
- /* @__PURE__ */ jsx7(Btn, { testID: "send-nytt", label: rader.length === 0 ? tekst.sendForste : tekst.sendNytt, onPress: onNytt })
2242
+ apen !== null ? (
2243
+ // F32: fotens plass — én primærhandling om gangen. «Send nytt innspill» er borte til
2244
+ // tillegget er sendt eller avbrutt, så første trykk aldri treffer feil knapp.
2245
+ /* @__PURE__ */ jsxs7(View7, { testID: "tillegg-fot", style: { gap: tema.space.sm }, children: [
2246
+ /* @__PURE__ */ jsxs7(View7, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
2247
+ /* @__PURE__ */ jsx8(
2248
+ Btn,
2249
+ {
2250
+ testID: "tillegg-send",
2251
+ label: sender ? tekst.sender : tekst.send,
2252
+ disabled: utkast.length < min || sender,
2253
+ busy: sender,
2254
+ ...utkast.length < min ? { hint: tekst.forKort(min) } : {},
2255
+ onPress: () => void send(apen),
2256
+ grow: true
2257
+ }
2258
+ ),
2259
+ /* @__PURE__ */ jsx8(Btn, { testID: "tillegg-avbryt", label: tekst.avbryt, variant: "secondary", onPress: avbryt, grow: true })
2260
+ ] }),
2261
+ /* @__PURE__ */ jsx8(Hint, { children: tekst.leggTilMerHint })
2262
+ ] })
2263
+ ) : /* @__PURE__ */ jsx8(Btn, { testID: "send-nytt", ikon: "chatbox-outline", label: tom ? tekst.sendForste : tekst.sendNytt, onPress: onNytt })
1809
2264
  ] });
1810
- }
2265
+ });
1811
2266
 
1812
2267
  // src/widget/Skjermbilde.tsx
1813
2268
  import { skaler, strokTilRekter, treffer, trykkTilRekt } from "@innspel/core";
1814
- import { useCallback, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
1815
- import { Image as Image2, Pressable as Pressable5, StyleSheet, Text as Text7, View as View7 } from "react-native";
1816
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2269
+ import { useCallback, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
2270
+ import { Image as Image2, Pressable as Pressable4, StyleSheet, Text as Text8, View as View8 } from "react-native";
2271
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1817
2272
  function Skjermbilde({
1818
2273
  bilde,
1819
2274
  automaskerRot,
@@ -1830,7 +2285,7 @@ function Skjermbilde({
1830
2285
  const [allTekst, setAllTekst] = useState3(false);
1831
2286
  const [egne, setEgne] = useState3([]);
1832
2287
  const [ramme, setRamme] = useState3(null);
1833
- const strok = useRef2([]);
2288
+ const strok = useRef3([]);
1834
2289
  const visning = useMemo3(() => {
1835
2290
  if (!ramme) return null;
1836
2291
  const s = Math.min(ramme.width / bilde.width, ramme.height / bilde.height);
@@ -1872,8 +2327,8 @@ function Skjermbilde({
1872
2327
  };
1873
2328
  const knapp = (id, ikon, label) => {
1874
2329
  const valgt = id === "allTekst" ? allTekst : verktoy === id && !allTekst;
1875
- return /* @__PURE__ */ jsxs7(
1876
- Pressable5,
2330
+ return /* @__PURE__ */ jsxs8(
2331
+ Pressable4,
1877
2332
  {
1878
2333
  testID: `verktoy-${id}`,
1879
2334
  accessibilityRole: "button",
@@ -1895,9 +2350,9 @@ function Skjermbilde({
1895
2350
  backgroundColor: valgt ? tema.color.surfaceRaised : "transparent"
1896
2351
  },
1897
2352
  children: [
1898
- /* @__PURE__ */ jsx8(Ikon, { navn: ikon, farge: tema.color.textPrimary }),
1899
- /* @__PURE__ */ jsx8(
1900
- Text7,
2353
+ /* @__PURE__ */ jsx9(Ikon, { navn: ikon, farge: tema.color.textPrimary }),
2354
+ /* @__PURE__ */ jsx9(
2355
+ Text8,
1901
2356
  {
1902
2357
  style: {
1903
2358
  color: tema.color.textPrimary,
@@ -1913,16 +2368,16 @@ function Skjermbilde({
1913
2368
  );
1914
2369
  };
1915
2370
  const a11y = tekst.skjermbildeA11y(automasker.length, egne.length, allTekst);
1916
- return /* @__PURE__ */ jsxs7(View7, { testID: "skjermbilde-steg", style: { flexGrow: 1, flexShrink: 1, gap: tema.space.md }, children: [
1917
- /* @__PURE__ */ jsx8(H, { sub: kilde === "galleri" ? tekst.skjermbildeUnderGalleri : tekst.skjermbildeUnder, children: tekst.skjermbildeTittel }),
1918
- notat ? /* @__PURE__ */ jsx8(View7, { testID: "bilde-notat", children: /* @__PURE__ */ jsx8(Hint, { children: notat }) }) : null,
1919
- /* @__PURE__ */ jsxs7(View7, { accessibilityRole: "toolbar", accessibilityLabel: tekst.maskering, style: { flexDirection: "row", gap: tema.space.sm }, children: [
2371
+ return /* @__PURE__ */ jsxs8(View8, { testID: "skjermbilde-steg", style: { flexGrow: 1, flexShrink: 1, gap: tema.space.md }, children: [
2372
+ /* @__PURE__ */ jsx9(H, { sub: kilde === "galleri" ? tekst.skjermbildeUnderGalleri : tekst.skjermbildeUnder, children: tekst.skjermbildeTittel }),
2373
+ notat ? /* @__PURE__ */ jsx9(View8, { testID: "bilde-notat", children: /* @__PURE__ */ jsx9(Hint, { children: notat }) }) : null,
2374
+ /* @__PURE__ */ jsxs8(View8, { accessibilityRole: "toolbar", accessibilityLabel: tekst.maskering, style: { flexDirection: "row", gap: tema.space.sm }, children: [
1920
2375
  knapp("felt", "scan-outline", tekst.maskerFelt),
1921
2376
  knapp("pensel", "brush-outline", tekst.tegnOver),
1922
2377
  knapp("allTekst", "grid-outline", tekst.maskerAllTekst)
1923
2378
  ] }),
1924
- /* @__PURE__ */ jsx8(
1925
- View7,
2379
+ /* @__PURE__ */ jsx9(
2380
+ View8,
1926
2381
  {
1927
2382
  testID: "skjermbilde-ramme",
1928
2383
  onLayout,
@@ -1935,8 +2390,8 @@ function Skjermbilde({
1935
2390
  borderRadius: tema.radius.md,
1936
2391
  overflow: "hidden"
1937
2392
  },
1938
- children: /* @__PURE__ */ jsx8(View7, { testID: "skjermbilde-flate", pointerEvents: "box-none", style: [StyleSheet.absoluteFill, { alignItems: "center", justifyContent: "center" }], children: visning ? /* @__PURE__ */ jsxs7(
1939
- View7,
2393
+ children: /* @__PURE__ */ jsx9(View8, { testID: "skjermbilde-flate", pointerEvents: "box-none", style: [StyleSheet.absoluteFill, { alignItems: "center", justifyContent: "center" }], children: visning ? /* @__PURE__ */ jsxs8(
2394
+ View8,
1940
2395
  {
1941
2396
  ref: previewRef,
1942
2397
  collapsable: false,
@@ -1951,7 +2406,7 @@ function Skjermbilde({
1951
2406
  onResponderTerminate: onRelease,
1952
2407
  style: { width: visning.width, height: visning.height, backgroundColor: screenRules.previewBackdrop },
1953
2408
  children: [
1954
- /* @__PURE__ */ jsx8(
2409
+ /* @__PURE__ */ jsx9(
1955
2410
  Image2,
1956
2411
  {
1957
2412
  testID: "skjermbilde-bilde",
@@ -1961,8 +2416,8 @@ function Skjermbilde({
1961
2416
  accessibilityIgnoresInvertColors: true
1962
2417
  }
1963
2418
  ),
1964
- automasker.map((r, i) => /* @__PURE__ */ jsx8(
1965
- View7,
2419
+ automasker.map((r, i) => /* @__PURE__ */ jsx9(
2420
+ View8,
1966
2421
  {
1967
2422
  testID: `automask-${i}`,
1968
2423
  pointerEvents: "none",
@@ -1983,16 +2438,16 @@ function Skjermbilde({
1983
2438
  // (skjermKontrastpar i theme.ts). textSecondary var 2,2:1 (C11a).
1984
2439
  // Ikonet arver samme farge: det er unntaket i «Styling» — maskeringen
1985
2440
  // tegnes i faste signalfarger, ikke i palettens.
1986
- /* @__PURE__ */ jsxs7(View7, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1987
- /* @__PURE__ */ jsx8(Ikon, { navn: "lock-closed-outline", storrelse: "minste", farge: screenRules.autoMaskText }),
1988
- /* @__PURE__ */ jsx8(Text7, { style: { color: screenRules.autoMaskText, fontSize: tema.font.small }, numberOfLines: 1, children: tekst.maskertAvAppen })
2441
+ /* @__PURE__ */ jsxs8(View8, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
2442
+ /* @__PURE__ */ jsx9(Ikon, { navn: "lock-closed-outline", storrelse: "minste", farge: screenRules.autoMaskText }),
2443
+ /* @__PURE__ */ jsx9(Text8, { style: { color: screenRules.autoMaskText, fontSize: tema.font.small }, numberOfLines: 1, children: tekst.maskertAvAppen })
1989
2444
  ] })
1990
2445
  ) : null
1991
2446
  },
1992
2447
  `auto-${i}`
1993
2448
  )),
1994
- egne.map((r, i) => /* @__PURE__ */ jsx8(
1995
- View7,
2449
+ egne.map((r, i) => /* @__PURE__ */ jsx9(
2450
+ View8,
1996
2451
  {
1997
2452
  testID: `maske-${i}`,
1998
2453
  pointerEvents: "none",
@@ -2005,14 +2460,14 @@ function Skjermbilde({
2005
2460
  ) : null })
2006
2461
  }
2007
2462
  ),
2008
- automasker.length ? /* @__PURE__ */ jsxs7(View7, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
2009
- /* @__PURE__ */ jsx8(Ikon, { navn: "lock-closed-outline", storrelse: "minste", farge: tema.color.textMuted }),
2010
- /* @__PURE__ */ jsx8(Hint, { children: tekst.maskertAvAppenHint })
2463
+ automasker.length ? /* @__PURE__ */ jsxs8(View8, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
2464
+ /* @__PURE__ */ jsx9(Ikon, { navn: "lock-closed-outline", storrelse: "minste", farge: tema.color.textMuted }),
2465
+ /* @__PURE__ */ jsx9(Hint, { children: tekst.maskertAvAppenHint })
2011
2466
  ] }) : null,
2012
- egne.length ? /* @__PURE__ */ jsx8(Hint, { children: tekst.dittStrok }) : null,
2013
- allTekst ? /* @__PURE__ */ jsx8(Hint, { children: tekst.allTekstHint }) : null,
2014
- /* @__PURE__ */ jsxs7(View7, { testID: "skjermbilde-fot", style: { flexShrink: 0, gap: tema.space.sm }, children: [
2015
- /* @__PURE__ */ jsx8(
2467
+ egne.length ? /* @__PURE__ */ jsx9(Hint, { children: tekst.dittStrok }) : null,
2468
+ allTekst ? /* @__PURE__ */ jsx9(Hint, { children: tekst.allTekstHint }) : null,
2469
+ /* @__PURE__ */ jsxs8(View8, { testID: "skjermbilde-fot", style: { flexShrink: 0, gap: tema.space.sm }, children: [
2470
+ /* @__PURE__ */ jsx9(
2016
2471
  Btn,
2017
2472
  {
2018
2473
  variant: "secondary",
@@ -2023,7 +2478,7 @@ function Skjermbilde({
2023
2478
  onPress: () => setEgne((x) => x.slice(0, -1))
2024
2479
  }
2025
2480
  ),
2026
- /* @__PURE__ */ jsx8(
2481
+ /* @__PURE__ */ jsx9(
2027
2482
  Btn,
2028
2483
  {
2029
2484
  variant: "danger",
@@ -2034,13 +2489,13 @@ function Skjermbilde({
2034
2489
  disabled: komponerer
2035
2490
  }
2036
2491
  ),
2037
- /* @__PURE__ */ jsx8(Btn, { testID: "legg-ved", label: tekst.leggVed, onPress: onLeggVed, disabled: komponerer || !visning })
2492
+ /* @__PURE__ */ jsx9(Btn, { testID: "legg-ved", label: tekst.leggVed, onPress: onLeggVed, disabled: komponerer || !visning })
2038
2493
  ] })
2039
2494
  ] });
2040
2495
  }
2041
2496
 
2042
2497
  // src/widget/Widget.tsx
2043
- import { Fragment, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2498
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2044
2499
  var FANGST = { format: "jpg", quality: 0.85 };
2045
2500
  function Widget({
2046
2501
  client,
@@ -2054,7 +2509,7 @@ function Widget({
2054
2509
  const tema = useTema();
2055
2510
  const insets = useContext3(SafeAreaInsetsContext) ?? initialWindowMetrics?.insets ?? { top: 0, bottom: 0, left: 0, right: 0 };
2056
2511
  const skjermbilde = useSkjermbilde();
2057
- const previewRef = useRef3(null);
2512
+ const previewRef = useRef4(null);
2058
2513
  const [steg, setSteg] = useState4("valg");
2059
2514
  const [spor, setSpor] = useState4("feil");
2060
2515
  const [verdi, setVerdi] = useState4("");
@@ -2097,7 +2552,7 @@ function Widget({
2097
2552
  }, []);
2098
2553
  const [mineDirekte, setMineDirekte] = useState4(false);
2099
2554
  const [stegForMine, setStegForMine] = useState4("valg");
2100
- const stegRef = useRef3(steg);
2555
+ const stegRef = useRef4(steg);
2101
2556
  stegRef.current = steg;
2102
2557
  const harUtkast = verdi.trim().length > 0 || vedlegg !== void 0;
2103
2558
  const lukk = useCallback2(() => {
@@ -2218,9 +2673,12 @@ function Widget({
2218
2673
  setVedlegg(void 0);
2219
2674
  setSteg("felt");
2220
2675
  }, []);
2676
+ const mineRef = useRef4(null);
2677
+ const tilleggUtkast = useRef4(/* @__PURE__ */ new Map());
2221
2678
  const gaaTilbake = useCallback2(() => {
2222
2679
  setFeil(void 0);
2223
2680
  if (steg === "mine") {
2681
+ if (mineRef.current?.lukkFelt()) return;
2224
2682
  if (mineDirekte) lukk();
2225
2683
  else setSteg("valg");
2226
2684
  return;
@@ -2259,6 +2717,9 @@ function Widget({
2259
2717
  setKvittering({
2260
2718
  art: spor,
2261
2719
  nr: res.submission.id,
2720
+ // Kortet får HELE saken: sporingslinjen leser `status`, `createdAt` og
2721
+ // `statusChangedAt` derfra — ingen nye felter, ingen ny kontrakt (DD-28).
2722
+ sak: res.submission,
2262
2723
  // Tidsløftet i kvitteringen er DATOEN fra svaret, aldri «innen 90 dager» (DD-07, DD-28).
2263
2724
  ...res.submission.deadlineAt ? { frist: res.submission.deadlineAt } : {},
2264
2725
  ...res.attachment?.status === "failed" ? { vedlegg: "feilet" } : {}
@@ -2279,7 +2740,7 @@ function Widget({
2279
2740
  setSender(true);
2280
2741
  try {
2281
2742
  const res = await client.knownIssues.confirm(k.id);
2282
- setKvittering({ art: "jaOgsa", nr: res.id });
2743
+ setKvittering({ art: "jaOgsa", nr: res.id, sak: res });
2283
2744
  setSteg("kvittering");
2284
2745
  } catch (e) {
2285
2746
  setFeil(e instanceof InnspelApiError2 ? e.message : "tjeneren svarte ikke.");
@@ -2311,7 +2772,7 @@ function Widget({
2311
2772
  if (harUtkast) setSteg(stegForMine);
2312
2773
  else nullstill();
2313
2774
  }, [harUtkast, stegForMine, nullstill]);
2314
- return /* @__PURE__ */ jsx9(
2775
+ return /* @__PURE__ */ jsx10(
2315
2776
  Modal,
2316
2777
  {
2317
2778
  visible: synlig,
@@ -2319,14 +2780,14 @@ function Widget({
2319
2780
  animationType: "slide",
2320
2781
  onRequestClose: androidTilbake,
2321
2782
  accessibilityViewIsModal: true,
2322
- children: /* @__PURE__ */ jsx9(
2783
+ children: /* @__PURE__ */ jsx10(
2323
2784
  KeyboardAvoidingView,
2324
2785
  {
2325
2786
  behavior: "padding",
2326
2787
  keyboardVerticalOffset: -insets.bottom,
2327
2788
  style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end", paddingTop: insets.top },
2328
- children: /* @__PURE__ */ jsxs8(
2329
- View8,
2789
+ children: /* @__PURE__ */ jsxs9(
2790
+ View9,
2330
2791
  {
2331
2792
  testID: "innspel-widget",
2332
2793
  accessibilityViewIsModal: true,
@@ -2347,37 +2808,37 @@ function Widget({
2347
2808
  ...steg === "skjermbilde" ? { height: "92%" } : {}
2348
2809
  },
2349
2810
  children: [
2350
- /* @__PURE__ */ jsxs8(View8, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
2351
- steg !== "valg" && steg !== "kvittering" ? /* @__PURE__ */ jsx9(Btn, { variant: "ghost", testID: "tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: gaaTilbake }) : /* @__PURE__ */ jsx9(View8, {}),
2352
- /* @__PURE__ */ jsx9(
2353
- Pressable6,
2811
+ /* @__PURE__ */ jsxs9(View9, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
2812
+ steg !== "valg" && steg !== "kvittering" ? /* @__PURE__ */ jsx10(Btn, { variant: "ghost", testID: "tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: gaaTilbake }) : /* @__PURE__ */ jsx10(View9, {}),
2813
+ /* @__PURE__ */ jsx10(
2814
+ Pressable5,
2354
2815
  {
2355
2816
  testID: "lukk",
2356
2817
  accessibilityRole: "button",
2357
2818
  accessibilityLabel: tekst.lukk,
2358
2819
  onPress: steg === "kvittering" ? lukkOgNullstill : lukk,
2359
2820
  style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
2360
- children: /* @__PURE__ */ jsx9(Ikon, { navn: "close-outline", farge: tema.color.textSecondary })
2821
+ children: /* @__PURE__ */ jsx10(Ikon, { navn: "close-outline", farge: tema.color.textSecondary })
2361
2822
  }
2362
2823
  )
2363
2824
  ] }),
2364
- feil ? /* @__PURE__ */ jsx9(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.sendefeilBanner(feil) }) : null,
2365
- !online && steg !== "kvittering" && steg !== "mine" ? /* @__PURE__ */ jsx9(Banner, { ikon: "cloud-offline-outline", tone: "info", testID: "offline-banner", children: tekst.offlineBanner }) : null,
2366
- steg === "valg" ? /* @__PURE__ */ jsxs8(Fragment, { children: [
2367
- /* @__PURE__ */ jsx9(Valg, { onVelg: velgSpor }),
2368
- !client.isAnonymous ? /* @__PURE__ */ jsx9(
2825
+ feil ? /* @__PURE__ */ jsx10(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.sendefeilBanner(feil) }) : null,
2826
+ !online && steg !== "kvittering" && steg !== "mine" ? /* @__PURE__ */ jsx10(Banner, { ikon: "cloud-offline-outline", tone: "info", testID: "offline-banner", children: tekst.offlineBanner }) : null,
2827
+ steg === "valg" ? /* @__PURE__ */ jsxs9(Fragment2, { children: [
2828
+ /* @__PURE__ */ jsx10(Valg, { onVelg: velgSpor, anonym: client.isAnonymous }),
2829
+ !client.isAnonymous ? /* @__PURE__ */ jsx10(View9, { style: { flex: 1, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsx10(
2369
2830
  Btn,
2370
2831
  {
2371
- variant: mine.length > 0 ? "secondary" : "ghost",
2832
+ variant: "secondary",
2372
2833
  testID: "mine-innspill",
2373
2834
  ikon: "list-outline",
2374
2835
  label: mine.length > 0 ? tekst.mineMedAntall(mine.length) : tekst.mineTittel,
2375
2836
  accessibilityLabel: mine.length > 0 ? tekst.mineEtikett(mine.length) : tekst.mineTittel,
2376
2837
  onPress: () => void visMine()
2377
2838
  }
2378
- ) : null
2839
+ ) }) : null
2379
2840
  ] }) : null,
2380
- steg === "kjenteFeil" ? /* @__PURE__ */ jsx9(
2841
+ steg === "kjenteFeil" ? /* @__PURE__ */ jsx10(
2381
2842
  KjenteFeil,
2382
2843
  {
2383
2844
  kort,
@@ -2392,7 +2853,7 @@ function Widget({
2392
2853
  onNei: () => setSteg("felt")
2393
2854
  }
2394
2855
  ) : null,
2395
- steg === "felt" ? /* @__PURE__ */ jsx9(
2856
+ steg === "felt" ? /* @__PURE__ */ jsx10(
2396
2857
  Felt,
2397
2858
  {
2398
2859
  spor,
@@ -2416,7 +2877,7 @@ function Widget({
2416
2877
  onFjernVedlegg: fjernBilde
2417
2878
  }
2418
2879
  ) : null,
2419
- steg === "skjermbilde" && bilde ? /* @__PURE__ */ jsx9(
2880
+ steg === "skjermbilde" && bilde ? /* @__PURE__ */ jsx10(
2420
2881
  Skjermbilde,
2421
2882
  {
2422
2883
  bilde,
@@ -2430,19 +2891,24 @@ function Widget({
2430
2891
  onLeggVed: leggVedBilde
2431
2892
  }
2432
2893
  ) : null,
2433
- steg === "kvittering" && kvittering ? /* @__PURE__ */ jsx9(
2894
+ steg === "kvittering" && kvittering ? /* @__PURE__ */ jsx10(
2434
2895
  Kvittering,
2435
2896
  {
2436
2897
  art: kvittering.art,
2437
2898
  ...kvittering.nr ? { saksnummer: kvittering.nr } : {},
2438
2899
  ...kvittering.vedlegg ? { vedlegg: kvittering.vedlegg } : {},
2439
2900
  ...kvittering.frist ? { frist: kvittering.frist } : {},
2901
+ ...kvittering.sak && kvittering.sak.pending !== true ? { sak: kvittering.sak } : {},
2902
+ ...tenantName ? { tenantName } : {},
2903
+ anonym: client.isAnonymous,
2440
2904
  onLukk: lukkOgNullstill
2441
2905
  }
2442
2906
  ) : null,
2443
- steg === "mine" ? /* @__PURE__ */ jsx9(
2907
+ steg === "mine" ? /* @__PURE__ */ jsx10(
2444
2908
  MineInnspill,
2445
2909
  {
2910
+ ref: mineRef,
2911
+ utkastLager: tilleggUtkast.current,
2446
2912
  storage: client.storage,
2447
2913
  rader: mine,
2448
2914
  laster: lasterMine,
@@ -2482,7 +2948,7 @@ function fjernetKontekst(client, fjernede, skjerm) {
2482
2948
  }
2483
2949
 
2484
2950
  // src/InnspelProvider.tsx
2485
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2951
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2486
2952
  var Kontekst = createContext3(null);
2487
2953
  function InnspelProvider({
2488
2954
  client,
@@ -2496,8 +2962,8 @@ function InnspelProvider({
2496
2962
  }) {
2497
2963
  const [synlig, setSynlig] = useState5(false);
2498
2964
  const [apneOpsjoner, setApneOpsjoner] = useState5();
2499
- const registrert = useRef4(false);
2500
- const rootRef = useRef4(null);
2965
+ const registrert = useRef5(false);
2966
+ const rootRef = useRef5(null);
2501
2967
  const privat = useMemo4(createPrivateRegistry, []);
2502
2968
  const open = useCallback3(
2503
2969
  async (options) => {
@@ -2517,9 +2983,9 @@ function InnspelProvider({
2517
2983
  () => ({ adapter: screenshot ?? null, rootRef, privat }),
2518
2984
  [screenshot, privat]
2519
2985
  );
2520
- return /* @__PURE__ */ jsx10(Kontekst.Provider, { value: verdi, children: /* @__PURE__ */ jsx10(SkjermbildeContext.Provider, { value: skjermbilde, children: /* @__PURE__ */ jsxs9(TemaProvider, { value: tema, children: [
2521
- /* @__PURE__ */ jsx10(View9, { ref: rootRef, collapsable: false, style: { flex: 1 }, testID: "innspel-rot", children }),
2522
- /* @__PURE__ */ jsx10(
2986
+ return /* @__PURE__ */ jsx11(Kontekst.Provider, { value: verdi, children: /* @__PURE__ */ jsx11(SkjermbildeContext.Provider, { value: skjermbilde, children: /* @__PURE__ */ jsxs10(TemaProvider, { value: tema, children: [
2987
+ /* @__PURE__ */ jsx11(View10, { ref: rootRef, collapsable: false, style: { flex: 1 }, testID: "innspel-rot", children }),
2988
+ /* @__PURE__ */ jsx11(
2523
2989
  Widget,
2524
2990
  {
2525
2991
  client,
@@ -2544,18 +3010,18 @@ function useInnspel() {
2544
3010
  }
2545
3011
 
2546
3012
  // src/InnspelPrivate.tsx
2547
- import { useEffect as useEffect3, useRef as useRef5 } from "react";
2548
- import { View as View10 } from "react-native";
2549
- import { jsx as jsx11 } from "react/jsx-runtime";
3013
+ import { useEffect as useEffect3, useRef as useRef6 } from "react";
3014
+ import { View as View11 } from "react-native";
3015
+ import { jsx as jsx12 } from "react/jsx-runtime";
2550
3016
  function InnspelPrivate({ children, style }) {
2551
- const ref = useRef5(null);
3017
+ const ref = useRef6(null);
2552
3018
  const kontekst = useSkjermbilde();
2553
3019
  const registrer = kontekst?.privat.register;
2554
3020
  useEffect3(() => {
2555
3021
  if (!registrer) return;
2556
3022
  return registrer(ref);
2557
3023
  }, [registrer]);
2558
- return /* @__PURE__ */ jsx11(View10, { ref, collapsable: false, style, testID: "innspel-privat", children });
3024
+ return /* @__PURE__ */ jsx12(View11, { ref, collapsable: false, style, testID: "innspel-privat", children });
2559
3025
  }
2560
3026
 
2561
3027
  // src/program/InnspelProgram.tsx
@@ -2563,11 +3029,7 @@ import {
2563
3029
  InnspelApiError as InnspelApiError3
2564
3030
  } from "@innspel/core";
2565
3031
  import { useCallback as useCallback4, useEffect as useEffect4, useState as useState7 } from "react";
2566
- import { Modal as Modal4, Pressable as Pressable9, Text as Text12, View as View15 } from "react-native";
2567
-
2568
- // src/program/Aksept.tsx
2569
- import "react";
2570
- import { Linking, Modal as Modal2, Pressable as Pressable7, ScrollView as ScrollView4, Text as Text8, View as View11 } from "react-native";
3032
+ import { Modal as Modal4, Pressable as Pressable8, View as View16 } from "react-native";
2571
3033
 
2572
3034
  // src/program/periode.ts
2573
3035
  var MANEDER = [
@@ -2591,13 +3053,31 @@ function periode(opensAt, closesAt) {
2591
3053
  const sammeManed = fra.getMonth() === til.getMonth() && fra.getFullYear() === til.getFullYear();
2592
3054
  return sammeManed ? `${fra.getDate()}.\u2013${til.getDate()}. ${MANEDER[til.getMonth()]}` : `${fra.getDate()}. ${MANEDER[fra.getMonth()]} \u2013 ${til.getDate()}. ${MANEDER[til.getMonth()]}`;
2593
3055
  }
2594
- function minutterPerOppgave(tasks) {
2595
- if (tasks.length === 0) return 0;
2596
- return Math.round(tasks.reduce((sum, t2) => sum + t2.estimatedMinutes, 0) / tasks.length);
3056
+ function minutterLinje(tasks) {
3057
+ if (tasks.length === 0) return { minutter: 0, like: true };
3058
+ const forste = tasks[0].estimatedMinutes;
3059
+ const like = tasks.every((t2) => t2.estimatedMinutes === forste);
3060
+ return like ? { minutter: forste, like: true } : { minutter: tasks.reduce((sum, t2) => sum + t2.estimatedMinutes, 0), like: false };
2597
3061
  }
2598
3062
 
2599
3063
  // src/program/Aksept.tsx
2600
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3064
+ import "react";
3065
+ import { Linking, Modal as Modal2, Pressable as Pressable6, ScrollView as ScrollView4, Text as Text9, View as View12 } from "react-native";
3066
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3067
+ function Seksjon({ tittel, children }) {
3068
+ const tema = useTema();
3069
+ return /* @__PURE__ */ jsxs11(View12, { style: { gap: tema.space.sm }, children: [
3070
+ /* @__PURE__ */ jsx13(
3071
+ Text9,
3072
+ {
3073
+ accessibilityRole: "header",
3074
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.bold },
3075
+ children: tittel
3076
+ }
3077
+ ),
3078
+ children
3079
+ ] });
3080
+ }
2601
3081
  function Aksept({
2602
3082
  program,
2603
3083
  harToken,
@@ -2607,14 +3087,15 @@ function Aksept({
2607
3087
  onLukk
2608
3088
  }) {
2609
3089
  const tema = useTema();
2610
- const tall = tekst.akseptTall(
3090
+ const { minutter, like } = minutterLinje(program.tasks);
3091
+ const tall = (like ? tekst.akseptTallHver : tekst.akseptTallSum)(
2611
3092
  program.tasks.length,
2612
- minutterPerOppgave(program.tasks),
2613
- periode(program.opensAt, program.closesAt),
2614
- program.maxContacts
3093
+ minutter,
3094
+ periode(program.opensAt, program.closesAt)
2615
3095
  );
2616
- return /* @__PURE__ */ jsx12(Modal2, { visible: true, transparent: true, animationType: "slide", onRequestClose: onLukk, accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx12(View11, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs10(
2617
- View11,
3096
+ const medVilkar = !!program.termsUrl && !program.commitmentFree;
3097
+ return /* @__PURE__ */ jsx13(Modal2, { visible: true, transparent: true, animationType: "slide", onRequestClose: onLukk, accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx13(View12, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs11(
3098
+ View12,
2618
3099
  {
2619
3100
  testID: "program-aksept",
2620
3101
  accessibilityViewIsModal: true,
@@ -2628,17 +3109,17 @@ function Aksept({
2628
3109
  minHeight: "60%"
2629
3110
  },
2630
3111
  children: [
2631
- /* @__PURE__ */ jsxs10(View11, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
2632
- /* @__PURE__ */ jsx12(Btn, { variant: "ghost", testID: "aksept-tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: onLukk }),
2633
- /* @__PURE__ */ jsx12(View11, {})
3112
+ /* @__PURE__ */ jsxs11(View12, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
3113
+ /* @__PURE__ */ jsx13(Btn, { variant: "ghost", testID: "aksept-tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: onLukk }),
3114
+ /* @__PURE__ */ jsx13(View12, {})
2634
3115
  ] }),
2635
- feil ? /* @__PURE__ */ jsx12(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.akseptFeil(feil) }) : null,
2636
- /* @__PURE__ */ jsxs10(ScrollView4, { contentContainerStyle: { gap: tema.space.md }, children: [
2637
- /* @__PURE__ */ jsx12(H, { sub: tekst.akseptHva, children: program.name }),
2638
- /* @__PURE__ */ jsx12(
2639
- Text8,
3116
+ feil ? /* @__PURE__ */ jsx13(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.akseptFeil(feil) }) : null,
3117
+ /* @__PURE__ */ jsxs11(ScrollView4, { contentContainerStyle: { gap: tema.space.lg }, children: [
3118
+ /* @__PURE__ */ jsx13(H, { testID: "aksept-tittel", sub: program.hypothesis, children: program.name }),
3119
+ /* @__PURE__ */ jsx13(
3120
+ Text9,
2640
3121
  {
2641
- accessibilityRole: "text",
3122
+ testID: "aksept-tall",
2642
3123
  style: {
2643
3124
  color: tema.color.textPrimary,
2644
3125
  fontSize: tema.font.body,
@@ -2648,79 +3129,116 @@ function Aksept({
2648
3129
  children: tall
2649
3130
  }
2650
3131
  ),
2651
- /* @__PURE__ */ jsx12(Text8, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: program.hypothesis }),
2652
- /* @__PURE__ */ jsxs10(Card, { children: [
2653
- /* @__PURE__ */ jsx12(H, { children: tekst.akseptOppgaver }),
2654
- program.tasks.map((o) => /* @__PURE__ */ jsxs10(View11, { style: { gap: tema.space.xs }, children: [
2655
- /* @__PURE__ */ jsx12(Text8, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: o.title }),
2656
- /* @__PURE__ */ jsxs10(Hint, { children: [
2657
- tekst.akseptOppgaveTid(o.estimatedMinutes),
2658
- o.screenHint ? ` \xB7 ${o.screenHint}` : ""
2659
- ] })
2660
- ] }, o.id))
2661
- ] }),
2662
- program.knownIssues.length > 0 ? /* @__PURE__ */ jsxs10(Card, { children: [
2663
- /* @__PURE__ */ jsx12(H, { sub: tekst.akseptKjenteFeilUnder, children: tekst.akseptKjenteFeil(program.knownIssues.length) }),
2664
- program.knownIssues.map((k) => {
2665
- const o = knownIssueStatus[k.status] ?? knownIssueStatus.aktiv;
2666
- return /* @__PURE__ */ jsxs10(View11, { style: { gap: tema.space.xs }, children: [
2667
- /* @__PURE__ */ jsx12(Text8, { style: { color: tema.color.textPrimary, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: k.title }),
2668
- k.workaround ? /* @__PURE__ */ jsxs10(Text8, { style: { color: tema.color.textSecondary, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: [
2669
- tekst.omvei,
2670
- " ",
2671
- k.workaround
2672
- ] }) : null,
2673
- k.fixedIn ? /* @__PURE__ */ jsx12(
2674
- StatusPill,
3132
+ /* @__PURE__ */ jsx13(Seksjon, { tittel: tekst.akseptOppgaver, children: /* @__PURE__ */ jsx13(View12, { children: program.tasks.map((o, i) => /* @__PURE__ */ jsxs11(
3133
+ View12,
3134
+ {
3135
+ style: {
3136
+ flexDirection: "row",
3137
+ alignItems: "center",
3138
+ gap: tema.space.sm,
3139
+ minHeight: tema.touch + tema.space.sm,
3140
+ paddingVertical: tema.space.sm,
3141
+ borderTopWidth: i === 0 ? 0 : tema.hairline,
3142
+ borderTopColor: tema.color.border
3143
+ },
3144
+ children: [
3145
+ /* @__PURE__ */ jsx13(
3146
+ View12,
2675
3147
  {
2676
- ikon: o.ikon,
2677
- etikett: k.status === "fikset" ? tekst.rettetI(k.fixedIn) : tekst.rettesI(k.fixedIn),
2678
- fg: o.fg,
2679
- bg: o.bg
3148
+ style: {
3149
+ width: tema.space.lg,
3150
+ height: tema.space.lg,
3151
+ borderRadius: tema.radius.pill,
3152
+ borderWidth: tema.hairline * 2,
3153
+ borderStyle: "dashed",
3154
+ borderColor: tema.color.borderStrong
3155
+ }
2680
3156
  }
2681
- ) : null
2682
- ] }, k.id);
2683
- })
2684
- ] }) : null,
2685
- /* @__PURE__ */ jsxs10(Card, { children: [
2686
- /* @__PURE__ */ jsx12(H, { sub: tekst.akseptInnsamlingTekst, children: tekst.akseptInnsamling }),
2687
- /* @__PURE__ */ jsx12(Hint, { children: tekst.kontekstAldri })
2688
- ] }),
2689
- program.termsUrl && !program.commitmentFree ? /* @__PURE__ */ jsxs10(View11, { style: { gap: tema.space.xs }, children: [
2690
- /* @__PURE__ */ jsx12(
2691
- Pressable7,
3157
+ ),
3158
+ /* @__PURE__ */ jsxs11(View12, { style: { flex: 1, minWidth: 0 }, children: [
3159
+ /* @__PURE__ */ jsx13(
3160
+ Text9,
3161
+ {
3162
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.semibold },
3163
+ children: o.title
3164
+ }
3165
+ ),
3166
+ /* @__PURE__ */ jsx13(Meta, { children: tekst.oppgaveTid(o.estimatedMinutes, o.screenHint) })
3167
+ ] })
3168
+ ]
3169
+ },
3170
+ o.id
3171
+ )) }) }),
3172
+ program.knownIssues.length > 0 ? /* @__PURE__ */ jsx13(Seksjon, { tittel: tekst.akseptKjenteFeil, children: /* @__PURE__ */ jsx13(View12, { children: program.knownIssues.map((k, i) => {
3173
+ const o = knownIssueStatus[k.status] ?? knownIssueStatus.aktiv;
3174
+ const rettet = k.status === "fikset";
3175
+ const statusOrd = rettet && k.fixedIn ? tekst.rettetI(k.fixedIn) : o.etikett;
3176
+ const tillegg = !rettet && k.fixedIn ? `\xB7 ${tekst.rettesI(k.fixedIn).toLowerCase()}` : void 0;
3177
+ return /* @__PURE__ */ jsxs11(
3178
+ View12,
3179
+ {
3180
+ style: {
3181
+ gap: tema.space.xs,
3182
+ paddingVertical: tema.space.sm,
3183
+ borderTopWidth: i === 0 ? 0 : tema.hairline,
3184
+ borderTopColor: tema.color.border
3185
+ },
3186
+ children: [
3187
+ /* @__PURE__ */ jsx13(
3188
+ Text9,
3189
+ {
3190
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.semibold },
3191
+ children: k.title
3192
+ }
3193
+ ),
3194
+ k.workaround ? /* @__PURE__ */ jsxs11(Sek, { children: [
3195
+ tekst.omvei,
3196
+ " ",
3197
+ k.workaround
3198
+ ] }) : null,
3199
+ /* @__PURE__ */ jsxs11(View12, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.sm, flexWrap: "wrap" }, children: [
3200
+ /* @__PURE__ */ jsxs11(View12, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
3201
+ /* @__PURE__ */ jsx13(Ikon, { navn: o.ikon, storrelse: "minste", farge: tema.color[o.fg] }),
3202
+ /* @__PURE__ */ jsx13(
3203
+ Text9,
3204
+ {
3205
+ style: {
3206
+ color: tema.color[o.fg],
3207
+ fontSize: tema.font.small,
3208
+ lineHeight: tema.lineHeight.small,
3209
+ fontWeight: tema.weight.semibold
3210
+ },
3211
+ children: statusOrd
3212
+ }
3213
+ )
3214
+ ] }),
3215
+ tillegg ? /* @__PURE__ */ jsx13(Meta, { children: tillegg }) : null
3216
+ ] })
3217
+ ]
3218
+ },
3219
+ k.id
3220
+ );
3221
+ }) }) }) : null,
3222
+ /* @__PURE__ */ jsxs11(Seksjon, { tittel: tekst.akseptInnsamling, children: [
3223
+ /* @__PURE__ */ jsx13(Sek, { children: tekst.akseptInnsamlingTekst }),
3224
+ medVilkar ? /* @__PURE__ */ jsxs11(
3225
+ Pressable6,
2692
3226
  {
2693
3227
  testID: "vilkar-lenke",
2694
3228
  accessibilityRole: "link",
2695
3229
  accessibilityLabel: tekst.akseptVilkar,
2696
3230
  onPress: () => void Linking.openURL(String(program.termsUrl)),
2697
- style: { minHeight: tema.touch, justifyContent: "center" },
2698
- children: /* @__PURE__ */ jsxs10(View11, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
2699
- /* @__PURE__ */ jsx12(Ikon, { navn: "open-outline", farge: tema.color.textPrimary }),
2700
- /* @__PURE__ */ jsx12(
2701
- Text8,
2702
- {
2703
- style: { color: tema.color.textPrimary, fontSize: tema.font.body, textDecorationLine: "underline" },
2704
- children: tekst.akseptVilkar
2705
- }
2706
- )
2707
- ] })
2708
- }
2709
- ),
2710
- /* @__PURE__ */ jsx12(Hint, { children: tekst.akseptVilkarHint })
2711
- ] }) : /* @__PURE__ */ jsx12(Hint, { children: tekst.akseptIngenVilkar }),
2712
- /* @__PURE__ */ jsxs10(View11, { style: { flexDirection: "row", alignItems: "flex-start", gap: tema.space.sm }, children: [
2713
- /* @__PURE__ */ jsx12(Ikon, { navn: "exit-outline", farge: tema.color.textPrimary }),
2714
- /* @__PURE__ */ jsx12(
2715
- Text8,
2716
- {
2717
- style: { flex: 1, color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body },
2718
- children: tekst.akseptUtgang
3231
+ style: { minHeight: tema.touch, flexDirection: "row", alignItems: "center", gap: tema.space.sm },
3232
+ children: [
3233
+ /* @__PURE__ */ jsx13(Ikon, { navn: "open-outline", storrelse: "minste", farge: tema.color.actionSecondaryText }),
3234
+ /* @__PURE__ */ jsx13(Text9, { style: { color: tema.color.actionSecondaryText, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: tekst.akseptVilkar })
3235
+ ]
2719
3236
  }
2720
- )
3237
+ ) : null,
3238
+ /* @__PURE__ */ jsx13(Hint, { children: medVilkar ? tekst.akseptTakOgUtgangVilkar(program.maxContacts) : tekst.akseptTakOgUtgang(program.maxContacts) })
2721
3239
  ] })
2722
3240
  ] }),
2723
- /* @__PURE__ */ jsx12(
3241
+ /* @__PURE__ */ jsx13(
2724
3242
  Btn,
2725
3243
  {
2726
3244
  testID: "bli-med",
@@ -2737,8 +3255,8 @@ function Aksept({
2737
3255
 
2738
3256
  // src/program/HvordanGikkDet.tsx
2739
3257
  import { useState as useState6 } from "react";
2740
- import { Modal as Modal3, Pressable as Pressable8, Text as Text9, TextInput as TextInput3, View as View12 } from "react-native";
2741
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3258
+ import { Modal as Modal3, Pressable as Pressable7, Text as Text10, TextInput as TextInput3, View as View13 } from "react-native";
3259
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2742
3260
  var UTFALL = [
2743
3261
  { verdi: "fungerte", ikon: "checkmark-circle-outline", etikett: tekst.utfallFungerte },
2744
3262
  { verdi: "delvis", ikon: "contrast-outline", etikett: tekst.utfallDelvis },
@@ -2750,64 +3268,113 @@ function utfallEtikett(verdi) {
2750
3268
  }
2751
3269
  function HvordanGikkDet({
2752
3270
  under,
3271
+ spoersmaal,
2753
3272
  sender,
2754
3273
  feil,
2755
3274
  onLagre,
3275
+ onMeldFeil,
2756
3276
  onLukk
2757
3277
  }) {
2758
3278
  const tema = useTema();
2759
3279
  const [valgt, setValgt] = useState6();
2760
3280
  const [setning, setSetning] = useState6("");
2761
- return /* @__PURE__ */ jsx13(Modal3, { visible: true, transparent: true, animationType: "fade", onRequestClose: onLukk, accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx13(View12, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end", padding: tema.space.md }, children: /* @__PURE__ */ jsxs11(
2762
- View12,
3281
+ const tekstVerdi = () => {
3282
+ const trimmet = setning.trim();
3283
+ return trimmet.length > 0 ? trimmet : void 0;
3284
+ };
3285
+ return /* @__PURE__ */ jsx14(Modal3, { visible: true, transparent: true, animationType: "slide", onRequestClose: onLukk, accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx14(View13, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs12(
3286
+ View13,
2763
3287
  {
2764
3288
  testID: "hvordan-gikk-det",
2765
3289
  accessibilityViewIsModal: true,
2766
3290
  style: {
2767
- backgroundColor: tema.color.surface,
2768
- borderRadius: tema.radius.lg,
2769
- borderWidth: tema.hairline,
2770
- borderColor: tema.color.borderStrong,
2771
- padding: tema.space.md,
2772
- gap: tema.space.md
3291
+ backgroundColor: tema.color.bg,
3292
+ borderTopLeftRadius: tema.radius.lg * 2,
3293
+ borderTopRightRadius: tema.radius.lg * 2,
3294
+ padding: tema.screenPadding,
3295
+ gap: tema.space.md,
3296
+ maxHeight: "92%"
2773
3297
  },
2774
3298
  children: [
2775
- /* @__PURE__ */ jsx13(Btn, { variant: "ghost", testID: "hvordan-tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: onLukk }),
2776
- /* @__PURE__ */ jsx13(Hint, { children: under }),
2777
- /* @__PURE__ */ jsx13(H, { children: tekst.hvordanGikkDet }),
2778
- /* @__PURE__ */ jsx13(View12, { testID: "utfall-gruppe", accessibilityRole: "radiogroup", accessibilityLabel: tekst.hvordanGikkDet, style: { flexDirection: "row", gap: tema.space.sm }, children: UTFALL.map((u) => {
2779
- const aktiv = valgt === u.verdi;
2780
- return /* @__PURE__ */ jsxs11(
2781
- Pressable8,
2782
- {
2783
- testID: `utfall-${u.verdi}`,
2784
- accessibilityRole: "radio",
2785
- accessibilityLabel: u.etikett,
2786
- accessibilityState: { checked: aktiv },
2787
- onPress: () => setValgt(u.verdi),
2788
- style: {
2789
- flex: 1,
2790
- minHeight: tema.touch,
2791
- alignItems: "center",
2792
- justifyContent: "center",
2793
- gap: tema.space.xs,
2794
- padding: tema.space.sm,
2795
- borderRadius: tema.radius.md,
2796
- borderWidth: tema.hairline,
2797
- borderColor: aktiv ? tema.color.brand : tema.color.borderStrong,
2798
- backgroundColor: aktiv ? tema.color.brandBg : tema.color.surfaceRaised
2799
- },
2800
- children: [
2801
- /* @__PURE__ */ jsx13(Ikon, { navn: u.ikon, farge: tema.color.textPrimary }),
2802
- /* @__PURE__ */ jsx13(Text9, { style: { color: tema.color.textPrimary, fontSize: tema.font.small, fontWeight: aktiv ? tema.weight.semibold : tema.weight.regular }, children: u.etikett })
2803
- ]
2804
- },
2805
- u.verdi
2806
- );
2807
- }) }),
2808
- /* @__PURE__ */ jsxs11(View12, { style: { gap: tema.space.xs }, children: [
2809
- /* @__PURE__ */ jsx13(Text9, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.setningLabel }),
2810
- /* @__PURE__ */ jsx13(
3299
+ /* @__PURE__ */ jsxs12(View13, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
3300
+ /* @__PURE__ */ jsx14(Btn, { variant: "ghost", testID: "hvordan-tilbake", ikon: "arrow-back-outline", label: tekst.tilbake, onPress: onLukk }),
3301
+ /* @__PURE__ */ jsx14(View13, {})
3302
+ ] }),
3303
+ /* @__PURE__ */ jsxs12(View13, { style: { gap: tema.space.xs }, children: [
3304
+ under ? /* @__PURE__ */ jsx14(Meta, { children: under }) : null,
3305
+ /* @__PURE__ */ jsx14(H, { children: spoersmaal ?? tekst.hvordanGikkDet })
3306
+ ] }),
3307
+ /* @__PURE__ */ jsx14(
3308
+ View13,
3309
+ {
3310
+ testID: "utfall-gruppe",
3311
+ accessibilityRole: "radiogroup",
3312
+ accessibilityLabel: spoersmaal ?? tekst.hvordanGikkDet,
3313
+ children: UTFALL.map((u, i) => {
3314
+ const aktiv = valgt === u.verdi;
3315
+ return /* @__PURE__ */ jsxs12(
3316
+ Pressable7,
3317
+ {
3318
+ testID: `utfall-${u.verdi}`,
3319
+ accessibilityRole: "radio",
3320
+ accessibilityLabel: u.etikett,
3321
+ accessibilityState: { checked: aktiv },
3322
+ onPress: () => setValgt(u.verdi),
3323
+ style: {
3324
+ flexDirection: "row",
3325
+ alignItems: "center",
3326
+ gap: tema.space.md,
3327
+ minHeight: tema.touch + tema.space.sm,
3328
+ borderTopWidth: i === 0 ? 0 : tema.hairline,
3329
+ borderTopColor: tema.color.border
3330
+ },
3331
+ children: [
3332
+ /* @__PURE__ */ jsx14(
3333
+ View13,
3334
+ {
3335
+ testID: aktiv ? `utfall-merke-${u.verdi}` : void 0,
3336
+ style: {
3337
+ width: tema.space.lg,
3338
+ height: tema.space.lg,
3339
+ borderRadius: tema.radius.pill,
3340
+ alignItems: "center",
3341
+ justifyContent: "center",
3342
+ backgroundColor: aktiv ? tema.color.brand : "transparent",
3343
+ borderWidth: tema.hairline * 2,
3344
+ borderColor: aktiv ? tema.color.brand : tema.color.borderInteractive
3345
+ },
3346
+ children: aktiv ? /* @__PURE__ */ jsx14(Ikon, { navn: "checkmark-outline", storrelse: "minste", farge: tema.color.onBrand }) : null
3347
+ }
3348
+ ),
3349
+ /* @__PURE__ */ jsx14(Ikon, { navn: u.ikon, farge: tema.color.textSecondary }),
3350
+ /* @__PURE__ */ jsx14(
3351
+ Text10,
3352
+ {
3353
+ testID: `utfall-etikett-${u.verdi}`,
3354
+ style: {
3355
+ flex: 1,
3356
+ color: tema.color.textPrimary,
3357
+ fontSize: tema.font.body,
3358
+ lineHeight: tema.lineHeight.body,
3359
+ fontWeight: aktiv ? tema.weight.semibold : tema.weight.regular
3360
+ },
3361
+ children: u.etikett
3362
+ }
3363
+ )
3364
+ ]
3365
+ },
3366
+ u.verdi
3367
+ );
3368
+ })
3369
+ }
3370
+ ),
3371
+ /* @__PURE__ */ jsxs12(View13, { style: { gap: tema.space.sm }, children: [
3372
+ /* @__PURE__ */ jsxs12(Text10, { style: { color: tema.color.textSecondary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: [
3373
+ tekst.setningLabel,
3374
+ " ",
3375
+ /* @__PURE__ */ jsx14(Text10, { style: { color: tema.color.textMuted }, children: tekst.setningValgfritt })
3376
+ ] }),
3377
+ /* @__PURE__ */ jsx14(
2811
3378
  TextInput3,
2812
3379
  {
2813
3380
  testID: "hvordan-setning",
@@ -2816,9 +3383,7 @@ function HvordanGikkDet({
2816
3383
  onChangeText: setSetning,
2817
3384
  maxLength: SETNING_MAKS,
2818
3385
  multiline: true,
2819
- numberOfLines: 3,
2820
- placeholder: tekst.setningPlaceholder,
2821
- placeholderTextColor: tema.color.textMuted,
3386
+ numberOfLines: 2,
2822
3387
  style: {
2823
3388
  backgroundColor: tema.color.surfaceRaised,
2824
3389
  borderWidth: tema.hairline,
@@ -2828,24 +3393,33 @@ function HvordanGikkDet({
2828
3393
  color: tema.color.textPrimary,
2829
3394
  fontSize: tema.font.body,
2830
3395
  lineHeight: tema.lineHeight.body,
2831
- minHeight: tema.touch * 2,
3396
+ minHeight: tema.touch * 1.5,
2832
3397
  textAlignVertical: "top"
2833
3398
  }
2834
3399
  }
2835
3400
  )
2836
3401
  ] }),
2837
- feil ? /* @__PURE__ */ jsx13(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.svarFeil(feil) }) : null,
2838
- /* @__PURE__ */ jsx13(
3402
+ valgt === "ikke" && onMeldFeil ? /* @__PURE__ */ jsx14(
3403
+ Tekstknapp,
3404
+ {
3405
+ testID: "meld-feil",
3406
+ ikon: "bug-outline",
3407
+ label: tekst.meldFeil,
3408
+ disabled: sender,
3409
+ onPress: () => onMeldFeil("ikke", tekstVerdi())
3410
+ }
3411
+ ) : null,
3412
+ feil ? /* @__PURE__ */ jsx14(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.svarFeil(feil) }) : null,
3413
+ /* @__PURE__ */ jsx14(
2839
3414
  Btn,
2840
3415
  {
2841
3416
  testID: "hvordan-lagre",
2842
3417
  label: tekst.lagre,
2843
- hint: tekst.lagreHint,
2844
3418
  disabled: valgt === void 0 || sender,
3419
+ busy: sender,
2845
3420
  onPress: () => {
2846
3421
  if (valgt === void 0) return;
2847
- const trimmet = setning.trim();
2848
- onLagre(valgt, trimmet.length > 0 ? trimmet : void 0);
3422
+ onLagre(valgt, tekstVerdi());
2849
3423
  }
2850
3424
  }
2851
3425
  )
@@ -2856,15 +3430,13 @@ function HvordanGikkDet({
2856
3430
 
2857
3431
  // src/program/Oppfolging.tsx
2858
3432
  import "react";
2859
- import { Text as Text10, View as View13 } from "react-native";
2860
- import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
3433
+ import { View as View14 } from "react-native";
3434
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2861
3435
  function tarSvar(kind) {
2862
3436
  return kind === "hvordan_gikk_det" || kind === "sjekkpunkt";
2863
3437
  }
2864
3438
  function Oppfolging({
2865
3439
  oppfolging,
2866
- kontaktNr,
2867
- maksKontakter,
2868
3440
  onSenere,
2869
3441
  onSvar,
2870
3442
  onAapneOppgavene,
@@ -2872,45 +3444,28 @@ function Oppfolging({
2872
3444
  }) {
2873
3445
  const tema = useTema();
2874
3446
  const art = tarSvar(oppfolging.kind) ? "spoersmaal" : oppfolging.kind === "tilbud_om_utgang" ? "utgang" : "paaminnelse";
2875
- const ikon = art === "spoersmaal" ? "flask-outline" : art === "utgang" ? "exit-outline" : "calendar-outline";
2876
- const hint = art === "spoersmaal" ? tekst.oppfolgingKontakt(kontaktNr, maksKontakter) : art === "utgang" ? tekst.oppfolgingUtgangHint(kontaktNr, maksKontakter) : tekst.oppfolgingPaaminnelseHint(kontaktNr, maksKontakter);
2877
- return /* @__PURE__ */ jsxs12(
2878
- View13,
3447
+ return /* @__PURE__ */ jsxs13(
3448
+ View14,
2879
3449
  {
2880
3450
  testID: `oppfolging-${oppfolging.id}`,
2881
3451
  accessibilityLabel: tekst.oppfolgingRegion,
2882
3452
  style: {
2883
3453
  backgroundColor: tema.color.brandBg,
2884
- borderWidth: tema.hairline,
2885
- borderColor: tema.color.brand,
2886
3454
  borderRadius: tema.radius.lg,
2887
3455
  padding: tema.space.md,
2888
- gap: tema.space.sm
3456
+ gap: tema.space.md
2889
3457
  },
2890
3458
  children: [
2891
- /* @__PURE__ */ jsxs12(View13, { style: { flexDirection: "row", gap: tema.space.sm, alignItems: "flex-start" }, children: [
2892
- /* @__PURE__ */ jsx14(Ikon, { navn: ikon, farge: tema.color.textPrimary }),
2893
- /* @__PURE__ */ jsxs12(View13, { style: { flex: 1, gap: tema.space.xs }, children: [
2894
- /* @__PURE__ */ jsx14(Text10, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: oppfolging.question }),
2895
- /* @__PURE__ */ jsx14(Hint, { children: hint })
2896
- ] })
3459
+ /* @__PURE__ */ jsxs13(View14, { style: { flexDirection: "row", gap: tema.space.sm, alignItems: "flex-start" }, children: [
3460
+ /* @__PURE__ */ jsx15(View14, { style: { paddingTop: tema.space.xs }, children: /* @__PURE__ */ jsx15(Ikon, { navn: "flask-outline", farge: tema.color.brand }) }),
3461
+ /* @__PURE__ */ jsx15(View14, { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx15(H, { nivaa: 3, meta: tekst.oppfolgingKost, children: oppfolging.question }) })
2897
3462
  ] }),
2898
- /* @__PURE__ */ jsx14(View13, { style: { flexDirection: "row", gap: tema.space.sm }, children: art === "utgang" ? /* @__PURE__ */ jsxs12(Fragment2, { children: [
2899
- /* @__PURE__ */ jsx14(Btn, { grow: true, variant: "secondary", testID: `bli-vaerende-${oppfolging.id}`, label: tekst.bliVaerende, onPress: onSenere }),
2900
- /* @__PURE__ */ jsx14(
2901
- Btn,
2902
- {
2903
- grow: true,
2904
- variant: "danger",
2905
- testID: `gaa-ut-${oppfolging.id}`,
2906
- ikon: "exit-outline",
2907
- label: tekst.gaaUtBekreft,
2908
- onPress: onGaaUt
2909
- }
2910
- )
2911
- ] }) : /* @__PURE__ */ jsxs12(Fragment2, { children: [
2912
- /* @__PURE__ */ jsx14(Btn, { grow: true, variant: "secondary", testID: `senere-${oppfolging.id}`, label: tekst.senere, onPress: onSenere }),
2913
- art === "spoersmaal" ? /* @__PURE__ */ jsx14(Btn, { grow: true, testID: `svar-naa-${oppfolging.id}`, label: tekst.svarNaa, onPress: onSvar }) : /* @__PURE__ */ jsx14(Btn, { grow: true, testID: `aapne-oppgavene-${oppfolging.id}`, label: tekst.aapneOppgavene, onPress: onAapneOppgavene })
3463
+ /* @__PURE__ */ jsx15(View14, { style: { flexDirection: "row", gap: tema.space.sm }, children: art === "utgang" ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
3464
+ /* @__PURE__ */ jsx15(Btn, { grow: true, variant: "secondary", testID: `bli-vaerende-${oppfolging.id}`, label: tekst.bliVaerende, onPress: onSenere }),
3465
+ /* @__PURE__ */ jsx15(Btn, { grow: true, variant: "secondary", testID: `gaa-ut-${oppfolging.id}`, ikon: "exit-outline", label: tekst.gaaUtBekreft, onPress: onGaaUt })
3466
+ ] }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
3467
+ /* @__PURE__ */ jsx15(Btn, { grow: true, variant: "secondary", testID: `senere-${oppfolging.id}`, label: tekst.senere, onPress: onSenere }),
3468
+ art === "spoersmaal" ? /* @__PURE__ */ jsx15(Btn, { grow: true, testID: `svar-naa-${oppfolging.id}`, label: tekst.svarNaa, onPress: onSvar }) : /* @__PURE__ */ jsx15(Btn, { grow: true, testID: `aapne-oppgavene-${oppfolging.id}`, label: tekst.aapneOppgavene, onPress: onAapneOppgavene })
2914
3469
  ] }) })
2915
3470
  ]
2916
3471
  }
@@ -2919,52 +3474,73 @@ function Oppfolging({
2919
3474
 
2920
3475
  // src/program/Oppgaver.tsx
2921
3476
  import "react";
2922
- import { Text as Text11, View as View14 } from "react-native";
2923
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3477
+ import { Text as Text11, View as View15 } from "react-native";
3478
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2924
3479
  function Oppgaver({
2925
3480
  tasks,
2926
3481
  completions,
3482
+ over,
2927
3483
  onGjort
2928
3484
  }) {
2929
3485
  const tema = useTema();
2930
3486
  const ferdig = new Map(completions.map((c) => [c.taskId, c]));
2931
- return /* @__PURE__ */ jsx15(View14, { testID: "oppgaver", accessibilityLabel: tekst.oppgaverTittel, style: { gap: tema.space.sm }, children: [...tasks].sort((a, b) => a.order - b.order).map((o) => {
3487
+ return /* @__PURE__ */ jsx16(View15, { testID: "oppgaver", accessibilityLabel: tekst.oppgaverTittel, children: [...tasks].sort((a, b) => a.order - b.order).map((o, i) => {
2932
3488
  const c = ferdig.get(o.id);
2933
- return /* @__PURE__ */ jsxs13(
2934
- View14,
3489
+ const meta = c ? tekst.oppgaveGjortMeta(formaterFrist(c.at), utfallEtikett(c.outcome)) : tekst.oppgaveTid(o.estimatedMinutes, o.screenHint);
3490
+ return /* @__PURE__ */ jsxs14(
3491
+ View15,
2935
3492
  {
2936
3493
  testID: `oppgave-${o.id}`,
3494
+ accessibilityLabel: tekst.oppgaveRadA11y(i + 1, o.title, c ? meta : tekst.oppgaveIkkeGjort),
2937
3495
  style: {
2938
3496
  flexDirection: "row",
2939
3497
  alignItems: "center",
2940
3498
  gap: tema.space.sm,
2941
- paddingVertical: tema.space.xs,
2942
- borderBottomWidth: tema.hairline,
2943
- borderBottomColor: tema.color.border
3499
+ minHeight: tema.touch + tema.space.sm,
3500
+ paddingVertical: tema.space.sm,
3501
+ borderTopWidth: i === 0 ? 0 : tema.hairline,
3502
+ borderTopColor: tema.color.border
2944
3503
  },
2945
3504
  children: [
2946
- /* @__PURE__ */ jsxs13(View14, { style: { flex: 1, gap: tema.space.xs }, children: [
2947
- /* @__PURE__ */ jsx15(Text11, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: o.title }),
2948
- /* @__PURE__ */ jsxs13(Hint, { children: [
2949
- c ? tekst.oppgaveGjortMed(utfallEtikett(c.outcome)) : `${tekst.oppgaveIkkeBegynt} \xB7 ${tekst.akseptOppgaveTid(o.estimatedMinutes)}`,
2950
- c?.text ? ` \xB7 \xAB${c.text}\xBB` : ""
2951
- ] })
3505
+ /* @__PURE__ */ jsx16(
3506
+ View15,
3507
+ {
3508
+ style: {
3509
+ width: tema.space.lg,
3510
+ height: tema.space.lg,
3511
+ borderRadius: tema.radius.pill,
3512
+ alignItems: "center",
3513
+ justifyContent: "center",
3514
+ backgroundColor: c ? tema.color.success : "transparent",
3515
+ borderWidth: c ? 0 : tema.hairline * 2,
3516
+ borderStyle: "dashed",
3517
+ borderColor: tema.color.borderStrong
3518
+ },
3519
+ children: c ? /* @__PURE__ */ jsx16(Ikon, { navn: "checkmark-outline", storrelse: "minste", farge: tema.color.bg }) : null
3520
+ }
3521
+ ),
3522
+ /* @__PURE__ */ jsxs14(View15, { style: { flex: 1, minWidth: 0 }, children: [
3523
+ /* @__PURE__ */ jsx16(
3524
+ Text11,
3525
+ {
3526
+ testID: `oppgave-tittel-${o.id}`,
3527
+ style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body, fontWeight: tema.weight.semibold },
3528
+ children: o.title
3529
+ }
3530
+ ),
3531
+ /* @__PURE__ */ jsx16(Meta, { testID: `oppgave-meta-${o.id}`, children: meta }),
3532
+ c?.text ? /* @__PURE__ */ jsx16(Sek, { testID: `oppgave-setning-${o.id}`, children: c.text }) : null
2952
3533
  ] }),
2953
- c ? (
2954
- // Merket er den eneste flaten der ikonet står alene, så etiketten
2955
- // ligger på containeren: skjermleseren hører utfallet, ikke «hake».
2956
- /* @__PURE__ */ jsx15(View14, { accessibilityLabel: tekst.oppgaveGjortMed(utfallEtikett(c.outcome)), accessible: true, children: /* @__PURE__ */ jsx15(Ikon, { navn: "checkmark-circle-outline", farge: tema.color.success }) })
2957
- ) : /* @__PURE__ */ jsx15(
3534
+ !c && !over ? /* @__PURE__ */ jsx16(
2958
3535
  Btn,
2959
3536
  {
2960
- variant: "secondary",
3537
+ variant: "tonet",
2961
3538
  testID: `gjort-${o.id}`,
2962
- ikon: "checkmark-circle-outline",
2963
3539
  label: tekst.oppgaveGjort,
2964
3540
  accessibilityLabel: tekst.oppgaveGjortLabel(o.title),
2965
3541
  onPress: () => onGjort(o)
2966
3542
  }
2967
- )
3543
+ ) : null
2968
3544
  ]
2969
3545
  },
2970
3546
  o.id
@@ -2972,8 +3548,33 @@ function Oppgaver({
2972
3548
  }) });
2973
3549
  }
2974
3550
 
3551
+ // src/program/ProgramSpor.tsx
3552
+ import "react";
3553
+ import { jsx as jsx17 } from "react/jsx-runtime";
3554
+ function programErOver(deltakelse, program, naa = /* @__PURE__ */ new Date()) {
3555
+ return deltakelse.status === "fullfoert" || new Date(program.closesAt).getTime() < naa.getTime();
3556
+ }
3557
+ function programledd(deltakelse, program, naa = /* @__PURE__ */ new Date()) {
3558
+ const over = programErOver(deltakelse, program, naa);
3559
+ const gjort = deltakelse.completions.length;
3560
+ const av = program.tasks.length;
3561
+ const alt = av > 0 && gjort >= av;
3562
+ return [
3563
+ { nokkel: "ble-med", etikett: tekst.programBleMed, tilstand: "gjort", detalj: formaterFrist(deltakelse.joinedAt) },
3564
+ {
3565
+ nokkel: "gjort",
3566
+ etikett: tekst.programGjort(gjort, av),
3567
+ ...over || alt ? { tilstand: "gjort" } : { tilstand: "naa", ikon: "flask-outline", detalj: tekst.programNaarDetPasser }
3568
+ },
3569
+ over ? { nokkel: "over", etikett: tekst.programOver, tilstand: "gjort", detalj: formaterFrist(program.closesAt) } : { nokkel: "over", etikett: tekst.programOver, tilstand: "kommer", tall: formaterKortFrist(program.closesAt) }
3570
+ ];
3571
+ }
3572
+ function ProgramSpor({ deltakelse, program }) {
3573
+ return /* @__PURE__ */ jsx17(Sporingslinje, { ledd: programledd(deltakelse, program), testID: "program-spor", etikett: tekst.programSporEtikett });
3574
+ }
3575
+
2975
3576
  // src/program/InnspelProgram.tsx
2976
- import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3577
+ import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2977
3578
  function InnspelProgram({
2978
3579
  invitationToken,
2979
3580
  onEndring,
@@ -2991,10 +3592,9 @@ function InnspelProgram({
2991
3592
  const [dialog, setDialog] = useState7();
2992
3593
  const [svarFeil, setSvarFeil] = useState7();
2993
3594
  const [lagtBort, setLagtBort] = useState7(/* @__PURE__ */ new Set());
2994
- const [meldFeilFor, setMeldFeilFor] = useState7();
2995
3595
  const leggBort = useCallback4((id) => setLagtBort((s) => /* @__PURE__ */ new Set([...s, id])), []);
2996
3596
  const lagreSvar = useCallback4(
2997
- async (outcome, text) => {
3597
+ async (outcome, text, meldEtterpaa = false) => {
2998
3598
  if (!dialog || !deltakelse) return;
2999
3599
  setSender(true);
3000
3600
  setSvarFeil(void 0);
@@ -3002,7 +3602,7 @@ function InnspelProgram({
3002
3602
  if (dialog.type === "oppgave") {
3003
3603
  const ny = await client.programs.completeTask(dialog.task.id, { outcome, ...text ? { text } : {} });
3004
3604
  setDeltakelse({ ...deltakelse, completions: [...deltakelse.completions, ny] });
3005
- if (outcome === "ikke" && onMeldFeil) setMeldFeilFor(dialog.task);
3605
+ if (meldEtterpaa && onMeldFeil) onMeldFeil(dialog.task);
3006
3606
  } else {
3007
3607
  await client.programs.respond(dialog.oppfolging.id, { outcome, ...text ? { text } : {} });
3008
3608
  setMine((m) => m ? { ...m, pendingFollowUps: m.pendingFollowUps.filter((f) => f.id !== dialog.oppfolging.id) } : m);
@@ -3062,14 +3662,12 @@ function InnspelProgram({
3062
3662
  if (!program) return null;
3063
3663
  if (deltakelse) {
3064
3664
  const kort = (mine?.pendingFollowUps ?? []).filter((f) => f.programId === program.id && !lagtBort.has(f.id)).sort((a, b) => a.emittedAt.localeCompare(b.emittedAt));
3065
- const forsteKontaktNr = Math.max(1, deltakelse.contactsSent - kort.length + 1);
3066
- return /* @__PURE__ */ jsxs14(View15, { testID: "program-deltakelse", accessibilityLabel: tekst.deltakelseRegion, style: { gap: tema.space.sm }, children: [
3067
- kort.map((f, i) => /* @__PURE__ */ jsx16(
3665
+ const over = programErOver(deltakelse, program);
3666
+ return /* @__PURE__ */ jsxs15(View16, { testID: "program-deltakelse", accessibilityLabel: tekst.deltakelseRegion, style: { gap: tema.space.md }, children: [
3667
+ kort.map((f) => /* @__PURE__ */ jsx18(
3068
3668
  Oppfolging,
3069
3669
  {
3070
3670
  oppfolging: f,
3071
- kontaktNr: forsteKontaktNr + i,
3072
- maksKontakter: program.maxContacts,
3073
3671
  onSenere: () => leggBort(f.id),
3074
3672
  onSvar: () => {
3075
3673
  setSvarFeil(void 0);
@@ -3080,50 +3678,37 @@ function InnspelProgram({
3080
3678
  },
3081
3679
  f.id
3082
3680
  )),
3083
- /* @__PURE__ */ jsxs14(Card, { children: [
3084
- /* @__PURE__ */ jsx16(H, { sub: tekst.deltakelsePeriode(periode(program.opensAt, program.closesAt), deltakelse.contactsSent, program.maxContacts), children: program.name }),
3085
- /* @__PURE__ */ jsx16(
3681
+ /* @__PURE__ */ jsxs15(Card, { style: { gap: tema.space.md }, children: [
3682
+ /* @__PURE__ */ jsx18(H, { children: program.name }),
3683
+ /* @__PURE__ */ jsx18(ProgramSpor, { deltakelse, program }),
3684
+ feil ? /* @__PURE__ */ jsx18(Banner, { live: true, ikon: "warning-outline", tone: "warning", children: feil }) : null,
3685
+ /* @__PURE__ */ jsx18(
3086
3686
  Oppgaver,
3087
3687
  {
3088
3688
  tasks: program.tasks,
3089
3689
  completions: deltakelse.completions,
3690
+ over,
3090
3691
  onGjort: (task) => {
3091
3692
  setSvarFeil(void 0);
3092
3693
  setDialog({ type: "oppgave", task });
3093
3694
  }
3094
3695
  }
3095
3696
  ),
3096
- meldFeilFor && onMeldFeil ? /* @__PURE__ */ jsxs14(View15, { style: { gap: tema.space.xs }, children: [
3097
- /* @__PURE__ */ jsx16(Hint, { children: tekst.meldFeilHint }),
3098
- /* @__PURE__ */ jsx16(
3099
- Btn,
3100
- {
3101
- variant: "secondary",
3102
- testID: "meld-feil",
3103
- ikon: "bug-outline",
3104
- label: tekst.meldFeil,
3105
- onPress: () => {
3106
- const task = meldFeilFor;
3107
- setMeldFeilFor(void 0);
3108
- onMeldFeil(task);
3109
- }
3110
- }
3111
- )
3112
- ] }) : null,
3113
- /* @__PURE__ */ jsx16(Btn, { variant: "ghost", testID: "gaa-ut", ikon: "exit-outline", label: tekst.gaaUt, onPress: () => setViserGaaUt(true) })
3697
+ /* @__PURE__ */ jsx18(Tekstknapp, { noytral: true, testID: "gaa-ut", ikon: "exit-outline", label: tekst.gaaUt, onPress: () => setViserGaaUt(true) })
3114
3698
  ] }),
3115
- dialog ? /* @__PURE__ */ jsx16(
3699
+ dialog ? /* @__PURE__ */ jsx18(
3116
3700
  HvordanGikkDet,
3117
3701
  {
3118
- under: dialog.type === "oppgave" ? dialog.task.title : dialog.oppfolging.question,
3702
+ ...dialog.type === "oppgave" ? { under: dialog.task.title } : { spoersmaal: dialog.oppfolging.question },
3119
3703
  sender,
3120
3704
  ...svarFeil ? { feil: svarFeil } : {},
3705
+ ...dialog.type === "oppgave" && onMeldFeil ? { onMeldFeil: (outcome, text) => void lagreSvar(outcome, text, true) } : {},
3121
3706
  onLagre: (outcome, text) => void lagreSvar(outcome, text),
3122
3707
  onLukk: () => setDialog(void 0)
3123
3708
  }
3124
3709
  ) : null,
3125
- viserGaaUt ? /* @__PURE__ */ jsx16(Modal4, { visible: true, transparent: true, animationType: "fade", onRequestClose: () => setViserGaaUt(false), accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx16(View15, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end", padding: tema.space.md }, children: /* @__PURE__ */ jsxs14(
3126
- View15,
3710
+ viserGaaUt ? /* @__PURE__ */ jsx18(Modal4, { visible: true, transparent: true, animationType: "fade", onRequestClose: () => setViserGaaUt(false), accessibilityViewIsModal: true, children: /* @__PURE__ */ jsx18(View16, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end", padding: tema.space.md }, children: /* @__PURE__ */ jsxs15(
3711
+ View16,
3127
3712
  {
3128
3713
  testID: "gaa-ut-dialog",
3129
3714
  accessibilityViewIsModal: true,
@@ -3136,11 +3721,11 @@ function InnspelProgram({
3136
3721
  gap: tema.space.md
3137
3722
  },
3138
3723
  children: [
3139
- /* @__PURE__ */ jsx16(H, { children: tekst.gaaUtTittel }),
3140
- /* @__PURE__ */ jsx16(Text12, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: tekst.gaaUtTekst(program.name) }),
3141
- /* @__PURE__ */ jsxs14(View15, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
3142
- /* @__PURE__ */ jsx16(Btn, { grow: true, variant: "secondary", testID: "bli-vaerende", label: tekst.bliVaerende, onPress: () => setViserGaaUt(false) }),
3143
- /* @__PURE__ */ jsx16(
3724
+ /* @__PURE__ */ jsx18(H, { nivaa: 3, children: tekst.gaaUtTittel }),
3725
+ /* @__PURE__ */ jsx18(Brodtekst, { children: tekst.gaaUtTekst(program.name) }),
3726
+ /* @__PURE__ */ jsxs15(View16, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
3727
+ /* @__PURE__ */ jsx18(Btn, { grow: true, variant: "secondary", testID: "bli-vaerende", label: tekst.bliVaerende, onPress: () => setViserGaaUt(false) }),
3728
+ /* @__PURE__ */ jsx18(
3144
3729
  Btn,
3145
3730
  {
3146
3731
  grow: true,
@@ -3159,45 +3744,40 @@ function InnspelProgram({
3159
3744
  ] });
3160
3745
  }
3161
3746
  if (!invitasjon || avvist) return null;
3162
- return /* @__PURE__ */ jsxs14(Fragment3, { children: [
3163
- /* @__PURE__ */ jsxs14(
3164
- View15,
3747
+ return /* @__PURE__ */ jsxs15(Fragment4, { children: [
3748
+ /* @__PURE__ */ jsxs15(
3749
+ View16,
3165
3750
  {
3166
3751
  testID: "program-banner",
3167
3752
  accessibilityLabel: tekst.invitasjonRegion,
3168
3753
  style: {
3169
3754
  backgroundColor: tema.color.brandBg,
3170
3755
  borderRadius: tema.radius.lg,
3171
- borderWidth: tema.hairline,
3172
- borderColor: tema.color.brand,
3173
3756
  padding: tema.space.md,
3174
- gap: tema.space.sm
3757
+ gap: tema.space.md
3175
3758
  },
3176
3759
  children: [
3177
- /* @__PURE__ */ jsxs14(View15, { style: { flexDirection: "row", gap: tema.space.sm, alignItems: "flex-start" }, children: [
3178
- /* @__PURE__ */ jsx16(Ikon, { navn: "flask-outline", farge: tema.color.textPrimary }),
3179
- /* @__PURE__ */ jsxs14(View15, { style: { flex: 1, gap: tema.space.xs }, children: [
3180
- /* @__PURE__ */ jsx16(Text12, { style: { color: tema.color.textPrimary, fontSize: tema.font.body, lineHeight: tema.lineHeight.body }, children: tekst.invitasjonHva(program.name) }),
3181
- /* @__PURE__ */ jsx16(Hint, { children: tekst.invitasjonKontakter(program.maxContacts) })
3182
- ] }),
3183
- /* @__PURE__ */ jsx16(
3184
- Pressable9,
3760
+ /* @__PURE__ */ jsxs15(View16, { style: { flexDirection: "row", gap: tema.space.sm, alignItems: "flex-start" }, children: [
3761
+ /* @__PURE__ */ jsx18(View16, { style: { paddingTop: tema.space.xs }, children: /* @__PURE__ */ jsx18(Ikon, { navn: "flask-outline", farge: tema.color.brand }) }),
3762
+ /* @__PURE__ */ jsx18(View16, { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx18(H, { nivaa: 3, meta: tekst.invitasjonMeta(program.tasks.length, periode(program.opensAt, program.closesAt)), children: tekst.invitasjonHva(program.name) }) }),
3763
+ /* @__PURE__ */ jsx18(
3764
+ Pressable8,
3185
3765
  {
3186
3766
  testID: "avvis-invitasjon",
3187
3767
  accessibilityRole: "button",
3188
3768
  accessibilityLabel: tekst.avvisInvitasjon,
3189
3769
  onPress: () => setAvvist(true),
3190
3770
  style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
3191
- children: /* @__PURE__ */ jsx16(Ikon, { navn: "close-outline", farge: tema.color.textSecondary })
3771
+ children: /* @__PURE__ */ jsx18(Ikon, { navn: "close-outline", farge: tema.color.textSecondary })
3192
3772
  }
3193
3773
  )
3194
3774
  ] }),
3195
- feil && !viserAksept ? /* @__PURE__ */ jsx16(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.akseptFeil(feil) }) : null,
3196
- /* @__PURE__ */ jsx16(Btn, { variant: "secondary", testID: "les-mer", label: tekst.lesMer, onPress: () => setViserAksept(true) })
3775
+ feil && !viserAksept ? /* @__PURE__ */ jsx18(Banner, { live: true, ikon: "warning-outline", tone: "danger", children: tekst.akseptFeil(feil) }) : null,
3776
+ /* @__PURE__ */ jsx18(Btn, { testID: "les-mer", label: tekst.lesMer, onPress: () => setViserAksept(true) })
3197
3777
  ]
3198
3778
  }
3199
3779
  ),
3200
- viserAksept ? /* @__PURE__ */ jsx16(
3780
+ viserAksept ? /* @__PURE__ */ jsx18(
3201
3781
  Aksept,
3202
3782
  {
3203
3783
  program,