@innspel/react-native 0.9.2 → 0.9.4

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/README.md CHANGED
@@ -112,6 +112,23 @@ Innspels. Innsenderen skal se hvem som svarte.
112
112
  `fontFamily` finnes ikke som token: systemfonten er standard i React Native, og
113
113
  å sette den ville brutt med appen rundt.
114
114
 
115
+ ## Når et innspill er sendt
116
+
117
+ `onSubmitted` kalles etter en innsending — også når nettet var borte og innspillet
118
+ ligger i køen, for innsenderen trykket Send. Du får `type`, `queued`, og `id` når
119
+ saken finnes hos tjeneren. Ingen identitet: saksnummeret er sakens, og det
120
+ innsenderen alt ser i kvitteringen. «Ja, jeg også» på en kjent feil gir ikke kallet.
121
+
122
+ ```tsx
123
+ <InnspelProvider
124
+ client={innspel}
125
+ onSubmitted={({ queued }) => {
126
+ hentTellingPaaNytt(); // «Mine innspill · N» i din egen meny
127
+ if (!queued) spørOmVarslerHvisFørste(); // riktig øyeblikk — ikke ved oppstart
128
+ }}
129
+ >
130
+ ```
131
+
115
132
  ## Hva innsenderen møter
116
133
 
117
134
  | Skjerm | Hva |
package/dist/index.cjs CHANGED
@@ -836,9 +836,7 @@ var tekst = {
836
836
  fjernLenke: "Fjern lenken til den kjente feilen",
837
837
  // 2f — skjermbilde (K4, DD-39, DD-40, DD-42)
838
838
  leggVedSkjermbilde: "Legg ved skjermbilde",
839
- leggVedHint: "Bildet tas f\xF8rst n\xE5r du trykker \u2014 du ser det f\xF8r det sendes.",
840
839
  velgBilde: "Velg bilde",
841
- velgBildeHint: "Fra bildene dine. Du ser det og kan maskere det f\xF8r det sendes.",
842
840
  skjermbildeUnderGalleri: "Bildet er fra galleriet. Appen maskerer ingenting i det for deg \u2014 mal over det som ikke skal med.",
843
841
  bildeFeilet: "kunne ikke hente bildet. Du kan sende uten.",
844
842
  skjermbildeTittel: "Se over bildet",
@@ -902,6 +900,8 @@ var tekst = {
902
900
  mineSak: (nr) => `Sak ${saksnr(nr)}`,
903
901
  /** «Feil · sak 2041» — sporet først, aldri rå id og aldri kontraktens type (DD-50). */
904
902
  sakHode: (spor, nr) => `${stor(spor)} \xB7 sak ${saksnr(nr)}`,
903
+ /** F14: svaret kom siden forrige gang denne enheten viste lista. */
904
+ nyttSvar: "Nytt svar",
905
905
  // Leietakeren fjernet vedlegget. Bare AT — aldri hvorfor, av hvem eller når.
906
906
  bildeFjernet: "Bildet er fjernet.",
907
907
  svarFra: (leietaker) => `Svar fra ${leietaker}`,
@@ -1191,31 +1191,35 @@ function Felt({
1191
1191
  )
1192
1192
  ]
1193
1193
  }
1194
- ) : onSkjermbilde || onVelgBilde ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: { gap: tema.space.sm }, children: [
1195
- onSkjermbilde ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1196
- Btn,
1197
- {
1198
- variant: "secondary",
1199
- testID: "legg-ved-skjermbilde",
1200
- ikon: "camera-outline",
1201
- label: tekst.leggVedSkjermbilde,
1202
- hint: tekst.leggVedHint,
1203
- onPress: onSkjermbilde
1204
- }
1205
- ) : null,
1206
- onVelgBilde ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1207
- Btn,
1208
- {
1209
- variant: "secondary",
1210
- testID: "velg-bilde",
1211
- ikon: "images-outline",
1212
- label: tekst.velgBilde,
1213
- hint: tekst.velgBildeHint,
1214
- onPress: onVelgBilde
1215
- }
1216
- ) : null,
1217
- bildeNotat ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { testID: "bilde-notat", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hint, { children: bildeNotat }) }) : null
1218
- ] }) : null,
1194
+ ) : onSkjermbilde || onVelgBilde ? (
1195
+ // F7 (brukerreisene 2026-09-15): knappene har ingen egen hjelpetekst. Web-widgeten
1196
+ // har aldri hatt det, og Følget sender sin egen setning som `imageStepNote` — med
1197
+ // pakkens hint i tillegg sto det tre tekster under to knapper. Løftet om at bildet
1198
+ // tas ved trykk og kan maskeres står i selve steget (Skjermbilde), der det gjelder.
1199
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: { gap: tema.space.sm }, children: [
1200
+ onSkjermbilde ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1201
+ Btn,
1202
+ {
1203
+ variant: "secondary",
1204
+ testID: "legg-ved-skjermbilde",
1205
+ ikon: "camera-outline",
1206
+ label: tekst.leggVedSkjermbilde,
1207
+ onPress: onSkjermbilde
1208
+ }
1209
+ ) : null,
1210
+ onVelgBilde ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1211
+ Btn,
1212
+ {
1213
+ variant: "secondary",
1214
+ testID: "velg-bilde",
1215
+ ikon: "images-outline",
1216
+ label: tekst.velgBilde,
1217
+ onPress: onVelgBilde
1218
+ }
1219
+ ) : null,
1220
+ bildeNotat ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { testID: "bilde-notat", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Hint, { children: bildeNotat }) }) : null
1221
+ ] })
1222
+ ) : null,
1219
1223
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: { borderTopWidth: tema.hairline, borderTopColor: tema.color.border, paddingTop: tema.space.sm }, children: [
1220
1224
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1221
1225
  import_react_native3.Pressable,
@@ -1554,23 +1558,78 @@ function Kvittering({
1554
1558
  // src/widget/MineInnspill.tsx
1555
1559
  var import_react9 = require("react");
1556
1560
  var import_react_native7 = require("react-native");
1561
+
1562
+ // src/widget/nyttSvar.ts
1563
+ var N\u00D8KKEL = "innspel:svar-sett";
1564
+ async function merkNyeSvar(rader, storage) {
1565
+ let grense = 0;
1566
+ try {
1567
+ grense = Number.parseInt(await storage.get(N\u00D8KKEL) ?? "", 10) || 0;
1568
+ } catch {
1569
+ grense = 0;
1570
+ }
1571
+ const tid = (r) => r.pending === true ? NaN : Date.parse(r.reply?.at ?? "");
1572
+ const merket = rader.map((rad) => ({ rad, nytt: tid(rad) > grense }));
1573
+ return [...merket.filter((m) => m.nytt), ...merket.filter((m) => !m.nytt)];
1574
+ }
1575
+ async function markerSvarSett(storage, n\u00E5 = Date.now()) {
1576
+ try {
1577
+ await storage.set(N\u00D8KKEL, String(n\u00E5));
1578
+ } catch {
1579
+ }
1580
+ }
1581
+
1582
+ // src/widget/MineInnspill.tsx
1557
1583
  var import_jsx_runtime7 = require("react/jsx-runtime");
1558
1584
  function MineInnspill({
1559
1585
  rader,
1560
1586
  laster,
1561
1587
  tenantName,
1562
- onNytt
1588
+ onNytt,
1589
+ storage
1563
1590
  }) {
1564
1591
  const tema = useTema();
1592
+ const [visning, setVisning] = (0, import_react9.useState)(() => rader.map((rad) => ({ rad, nytt: false })));
1593
+ (0, import_react9.useEffect)(() => {
1594
+ let gjelder = true;
1595
+ void merkNyeSvar(rader, storage).then((m) => {
1596
+ if (gjelder) setVisning(m);
1597
+ }).catch(() => {
1598
+ if (gjelder) setVisning(rader.map((rad) => ({ rad, nytt: false })));
1599
+ });
1600
+ return () => {
1601
+ gjelder = false;
1602
+ };
1603
+ }, [storage, rader]);
1604
+ (0, import_react9.useEffect)(() => {
1605
+ if (!laster && rader.length) void markerSvarSett(storage).catch(() => void 0);
1606
+ }, [storage, laster, rader]);
1565
1607
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: { flex: 1, gap: tema.space.md }, children: [
1566
1608
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(H, { sub: tekst.mineUnder, children: tekst.mineTittel }),
1567
- laster ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.ActivityIndicator, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.ScrollView, { style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, children: rader.map((rad) => {
1609
+ laster ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.ActivityIndicator, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.ScrollView, { style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, children: visning.map(({ rad, nytt }) => {
1568
1610
  const venter = rad.pending === true;
1569
1611
  const v = venter ? venterVisning : statusVisning(rad.status, rad.type, rad.deadlineAt);
1570
1612
  const nokkel = venter ? rad.clientRef : rad.id;
1571
1613
  const svar = venter ? void 0 : rad.reply;
1572
1614
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Card, { dashed: venter, children: [
1573
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Hint, { children: venter ? `${tekst.mineIkkeSendt} \xB7 ${rad.type === "onske" ? tekst.onske : tekst.feil}` : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
1615
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs, flexWrap: "wrap" }, children: [
1616
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Hint, { children: venter ? `${tekst.mineIkkeSendt} \xB7 ${rad.type === "onske" ? tekst.onske : tekst.feil}` : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
1617
+ nytt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1618
+ import_react_native7.Text,
1619
+ {
1620
+ testID: "nytt-svar",
1621
+ style: {
1622
+ color: tema.color.info,
1623
+ backgroundColor: tema.color.infoBg,
1624
+ fontSize: tema.font.tiny,
1625
+ fontWeight: tema.weight.semibold,
1626
+ borderRadius: tema.radius.pill,
1627
+ paddingHorizontal: tema.space.sm
1628
+ },
1629
+ children: tekst.nyttSvar
1630
+ }
1631
+ ) : null
1632
+ ] }),
1574
1633
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1575
1634
  import_react_native7.Text,
1576
1635
  {
@@ -1860,7 +1919,8 @@ function Widget({
1860
1919
  apneOpsjoner,
1861
1920
  onLukk,
1862
1921
  tenantName,
1863
- imageStepNote
1922
+ imageStepNote,
1923
+ onSubmitted
1864
1924
  }) {
1865
1925
  const tema = useTema();
1866
1926
  const insets = (0, import_react11.useContext)(import_react_native_safe_area_context.SafeAreaInsetsContext) ?? import_react_native_safe_area_context.initialWindowMetrics?.insets ?? { top: 0, bottom: 0, left: 0, right: 0 };
@@ -2062,7 +2122,7 @@ function Widget({
2062
2122
  text: verdi,
2063
2123
  ...vedlegg ? { attachment: vedlegg } : {},
2064
2124
  ...spor === "feil" && lenketTil ? { relatedKnownIssueId: lenketTil.id } : {},
2065
- ...fjernede.length ? { context: fjernetKontekst(client, fjernede) } : {}
2125
+ context: fjernetKontekst(client, fjernede, apneOpsjoner?.screen)
2066
2126
  });
2067
2127
  if (res.status === "queued") {
2068
2128
  setKvittering({ art: "k\xF8", ...res.attachment ? { vedlegg: "forkastet" } : {} });
@@ -2076,6 +2136,7 @@ function Widget({
2076
2136
  });
2077
2137
  }
2078
2138
  setSteg("kvittering");
2139
+ onSubmitted?.(res.status === "queued" ? { type: spor, queued: true } : { type: spor, queued: false, id: res.submission.id });
2079
2140
  } catch (e) {
2080
2141
  if (e instanceof import_core2.InnspelQueueFullError) setFeil(e.userMessage);
2081
2142
  else if (e instanceof import_core2.InnspelApiError) setFeil(e.message);
@@ -2083,7 +2144,7 @@ function Widget({
2083
2144
  } finally {
2084
2145
  setSender(false);
2085
2146
  }
2086
- }, [client, spor, verdi, vedlegg, lenketTil, fjernede]);
2147
+ }, [client, spor, verdi, vedlegg, lenketTil, fjernede, apneOpsjoner?.screen, onSubmitted]);
2087
2148
  const jaOgsa = (0, import_react11.useCallback)(
2088
2149
  async (k) => {
2089
2150
  setSender(true);
@@ -2210,7 +2271,7 @@ function Widget({
2210
2271
  onEndre: endreTekst,
2211
2272
  minTextLength: innstillinger.minTextLength,
2212
2273
  textMaxLength: innstillinger.textMaxLength,
2213
- kontekst: client.context,
2274
+ kontekst: { ...client.context, ...apneOpsjoner?.screen ? { screen: apneOpsjoner.screen } : {} },
2214
2275
  fjernedeFelter: fjernede,
2215
2276
  onFjernKontekst: (f) => setFjernede((x) => [...x, f]),
2216
2277
  ...lenketTil ? { lenketTil, onFjernLenke: () => setLenketTil(void 0) } : {},
@@ -2253,6 +2314,7 @@ function Widget({
2253
2314
  steg === "mine" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2254
2315
  MineInnspill,
2255
2316
  {
2317
+ storage: client.storage,
2256
2318
  rader: mine,
2257
2319
  laster: lasterMine,
2258
2320
  ...tenantName ? { tenantName } : {},
@@ -2277,9 +2339,10 @@ function useNettstatus(client) {
2277
2339
  }, [c]);
2278
2340
  return online;
2279
2341
  }
2280
- function fjernetKontekst(client, fjernede) {
2342
+ function fjernetKontekst(client, fjernede, skjerm) {
2281
2343
  const ut = {};
2282
- for (const k of Object.keys(client.context)) {
2344
+ if (skjerm) ut["screen"] = skjerm;
2345
+ for (const k of [...Object.keys(client.context), "screen"]) {
2283
2346
  if (k !== "sdkVersion" && fjernede.includes(k)) ut[k] = void 0;
2284
2347
  }
2285
2348
  return ut;
@@ -2295,7 +2358,8 @@ function InnspelProvider({
2295
2358
  colorScheme = "dark",
2296
2359
  tenantName,
2297
2360
  screenshot,
2298
- imageStepNote
2361
+ imageStepNote,
2362
+ onSubmitted
2299
2363
  }) {
2300
2364
  const [synlig, setSynlig] = (0, import_react12.useState)(false);
2301
2365
  const [apneOpsjoner, setApneOpsjoner] = (0, import_react12.useState)();
@@ -2330,6 +2394,7 @@ function InnspelProvider({
2330
2394
  ...apneOpsjoner ? { apneOpsjoner } : {},
2331
2395
  ...tenantName ? { tenantName } : {},
2332
2396
  ...imageStepNote ? { imageStepNote } : {},
2397
+ ...onSubmitted ? { onSubmitted } : {},
2333
2398
  onLukk: close
2334
2399
  }
2335
2400
  )