Gå til innholdet

Session Timeout

Dette er tingen hver store organisasjon bygger selv, og gjør feil. Enten kommer det ingen advarsel, og brukeren mister et halvutfylt søknadsskjema. Eller dialogen stjeler fokus midt i en setning. Eller skjermleseren leser nedtellingen hvert eneste sekund.

// main.ts, kjøres én gang når appen starter
import { defineFsSessionTimeout } from "@fristil/designsystem/session-timeout"
import "@fristil/designsystem/session-timeout.css"
defineFsSessionTimeout()

De fleste komponentene i Fristil rører ikke DOM-en serveren har sendt. Denne gjør, og grunnen er at nedtellingen er klientens klokke. Tallet endrer seg hvert sekund ut fra når brukeren sist rørte tastaturet, og det er en tilstand ingen server kan sende. Å patche den over en strøm hvert sekund ville vært meningsløst.

Derfor setter byggefunksjonen data-ignore-morph. Det ber Datastar la innholdet være, slik at en patch ikke river dialogen bort mens den står åpen. Se Markup og oppførsel for hele regelen.

<fs-session-timeout class="fs-session-timeout" warn-at="1500" expires-at="1800"
data-ignore-morph></fs-session-timeout>
AttributtBetydningStandard
warn-atSekunder uten aktivitet før varselet kommer1500 (25 minutter)
expires-atSekunder uten aktivitet før økten er ute1800 (30 minutter)

Aktivitet er tastetrykk, klikk og rulling. Mens dialogen står åpen teller ikke aktivitet, ellers ville et tilfeldig museklikk forlenget økten uten at brukeren mente det.

HendelseNårHva du gjør
session-warnDialogen åpner segSom regel ingenting
session-extendBrukeren velger å fortsetteBe serveren forlenge økten
session-logoutBrukeren velger å logge utSend brukeren til utloggingen
session-expiredTiden er uteSend brukeren til innloggingen

Komponenten vet ikke hvordan økten din forlenges. Den sier fra, du gjør kallet.

<fs-session-timeout class="fs-session-timeout" warn-at="1500" expires-at="1800"
data-ignore-morph></fs-session-timeout>
<script type="module">
import { defineFsSessionTimeout } from "@fristil/designsystem/session-timeout"
defineFsSessionTimeout()
const okt = document.querySelector("fs-session-timeout")
okt.addEventListener("session-extend", async () => {
await fetch("/api/forleng-okt", { method: "POST" })
})
okt.addEventListener("session-expired", () => {
location.href = "/logg-inn?arsak=utlopt"
})
</script>

Dialogen er en ekte <dialog> åpnet med showModal(), så fokusfellen, Escape og topplaget kommer fra nettleseren. Den har role="alertdialog", fordi den avbryter noe brukeren ikke ba om å bli avbrutt i.

Tre ting er gjort med vilje, og alle tre er grunner til at dette er vanskelig å få riktig selv:

  • Fokus går tilbake dit brukeren var. Uten det starter neste tastetrykk på toppen av siden, midt i et skjema.
  • Nedtellingen leses ikke opp hvert sekund. Tallet på skjermen har aria-hidden, og et eget område melder fra ved to minutter, ett minutt, 30 sekunder og 10 sekunder. En opplesning i sekundet gjør dialogen ubrukelig.
  • Knappen som forlenger står først. Det er den de fleste vil ha, og den skal være det første tastaturet treffer.
KlasseHva det er
.fs-session-timeoutVertselementet. Ligger som display: contents og tar ingen plass
.fs-session-timeout__dialogSelve dialogen
.fs-session-timeout__titleOverskriften
.fs-session-timeout__textAvsnittet med nedtellingen i
.fs-session-timeout__countTallet som teller ned
.fs-session-timeout__actionsRaden med knapper

Form og størrelse leses fra komponentvariabler, med systemets verdi som reserve:

VariabelReserve
--fs-session-timeout-width26rem
--fs-session-timeout-paddingvar(--size-5)
--fs-session-timeout-radiusvar(--size-1)
.fs-session-timeout__dialog {
--fs-session-timeout-width: 32rem;
}