Portalmenyn i två nivåer: arbetet synligt, administrationen under Settings
Tio länkar i tre brutna rader var ingen meny. Nivå ett är nu arbetet — Dashboard, Analysis, Warranty, Insurance, Diagnostics — plus Settings, som samlar det som konfigurerar organisationen: kunskapskällor, integration, abonnemang, fakturor och supportärenden mot plattformen. Settings har en översiktssida där varje område är en hel klickbar rad med en mening om vad man uträttar där, och inne i inställningarna visas områdena som en egen, alltid synlig rad med det aktiva markerat — ingen fällmeny. Områdeslistan ligger i en egen modul och bär huvudmenyns markering, inställningsraden och översiktssidan ur samma data. Nya vyn står bakom portalvakten och ingår i genomgångens telefonmätning och portalspärrens kontroll. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
This commit is contained in:
@@ -494,6 +494,7 @@ try {
|
|||||||
"/alva/portal/garantier",
|
"/alva/portal/garantier",
|
||||||
"/alva/portal/forsakring",
|
"/alva/portal/forsakring",
|
||||||
"/alva/portal/support",
|
"/alva/portal/support",
|
||||||
|
"/alva/portal/installningar",
|
||||||
"/alva/impressum",
|
"/alva/impressum",
|
||||||
"/alva/utgavor",
|
"/alva/utgavor",
|
||||||
]) {
|
]) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ const VYER = [
|
|||||||
"/alva/portal/garantier",
|
"/alva/portal/garantier",
|
||||||
"/alva/portal/forsakring",
|
"/alva/portal/forsakring",
|
||||||
"/alva/portal/support",
|
"/alva/portal/support",
|
||||||
|
"/alva/portal/installningar",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Nycklarna är plattformsklientens egna (src/felsokning/plattform.ts).
|
// Nycklarna är plattformsklientens egna (src/felsokning/plattform.ts).
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import AlvaUtgavor from "./pages/alva/Utgavor";
|
|||||||
import AlvaSprak from "./pages/alva/Sprak";
|
import AlvaSprak from "./pages/alva/Sprak";
|
||||||
import AlvaForsakring from "./pages/alva/Forsakring";
|
import AlvaForsakring from "./pages/alva/Forsakring";
|
||||||
import AlvaSupport from "./pages/alva/Support";
|
import AlvaSupport from "./pages/alva/Support";
|
||||||
|
import AlvaInstallningar from "./pages/alva/Installningar";
|
||||||
import { Portalvakt } from "./pages/alva/Portalvakt";
|
import { Portalvakt } from "./pages/alva/Portalvakt";
|
||||||
import { PaymentTestModeBanner } from "@/components/PaymentTestModeBanner";
|
import { PaymentTestModeBanner } from "@/components/PaymentTestModeBanner";
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ function AppContent() {
|
|||||||
<Route path="/alva/portal/garantier" element={<Portalvakt><AlvaGarantier /></Portalvakt>} />
|
<Route path="/alva/portal/garantier" element={<Portalvakt><AlvaGarantier /></Portalvakt>} />
|
||||||
<Route path="/alva/portal/forsakring" element={<Portalvakt><AlvaForsakring /></Portalvakt>} />
|
<Route path="/alva/portal/forsakring" element={<Portalvakt><AlvaForsakring /></Portalvakt>} />
|
||||||
<Route path="/alva/portal/support" element={<Portalvakt><AlvaSupport /></Portalvakt>} />
|
<Route path="/alva/portal/support" element={<Portalvakt><AlvaSupport /></Portalvakt>} />
|
||||||
|
<Route path="/alva/portal/installningar" element={<Portalvakt><AlvaInstallningar /></Portalvakt>} />
|
||||||
<Route path="/felsokning" element={<Arendelista />} />
|
<Route path="/felsokning" element={<Arendelista />} />
|
||||||
<Route path="/felsokning/nytt" element={<NyttArende />} />
|
<Route path="/felsokning/nytt" element={<NyttArende />} />
|
||||||
<Route path="/felsokning/arende/:id" element={<ArendeSida />} />
|
<Route path="/felsokning/arende/:id" element={<ArendeSida />} />
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// Portalens inställningsöversikt.
|
||||||
|
//
|
||||||
|
// Sidan finns för att menyordet "Settings" ska hålla vad det lovar utan
|
||||||
|
// att besökaren behöver veta systemets egna namn i förväg. Fem områden,
|
||||||
|
// vart och ett en hel klickbar rad med en mening om vad man uträttar
|
||||||
|
// där — inte en ikonmatta och inte en fällmeny.
|
||||||
|
//
|
||||||
|
// Områdeslistan ägs av installningsomraden.ts: samma data bär
|
||||||
|
// huvudmenyns markering, inställningsraden och den här sidan. En
|
||||||
|
// lista, tre användningar — annars glider de isär vid nästa område
|
||||||
|
// som tillkommer.
|
||||||
|
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { Etikett, FARG, Rubrik, Symbol } from "@/alva/komponenter";
|
||||||
|
import { INSTALLNINGAR } from "./installningsomraden";
|
||||||
|
import { Ram } from "./Ram";
|
||||||
|
|
||||||
|
export default function Installningar() {
|
||||||
|
return (
|
||||||
|
<Ram portal>
|
||||||
|
<div className="mx-auto max-w-[1040px] px-6 py-12">
|
||||||
|
<div className="mb-8">
|
||||||
|
<Etikett>Organization</Etikett>
|
||||||
|
<div className="mt-2">
|
||||||
|
<Rubrik niva={1}>Settings</Rubrik>
|
||||||
|
</div>
|
||||||
|
<p className="mt-4 max-w-[640px] text-[13px] leading-[24px]" style={{ color: FARG.steel }}>
|
||||||
|
Everything that configures the organization is gathered here. Nothing under Settings
|
||||||
|
touches an individual case — casework lives under Diagnostics.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="grid gap-4">
|
||||||
|
{INSTALLNINGAR.map((p) => (
|
||||||
|
<li key={p.till}>
|
||||||
|
<Link
|
||||||
|
to={p.till}
|
||||||
|
className="flex items-center justify-between gap-4 border p-6"
|
||||||
|
style={{ borderColor: FARG.lightSteel, background: FARG.white }}
|
||||||
|
>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span
|
||||||
|
className="block text-[13px] font-semibold uppercase tracking-[0.08em]"
|
||||||
|
style={{ color: FARG.blue }}
|
||||||
|
>
|
||||||
|
{p.text}
|
||||||
|
</span>
|
||||||
|
<span className="mt-2 block text-[13px] leading-[24px]" style={{ color: FARG.steel }}>
|
||||||
|
{p.beskrivning}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<Symbol ikon="nasta" ton={FARG.blue} />
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</Ram>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import { loggaUtPlattform, plattformKonto } from "@/felsokning/plattform";
|
|||||||
import { ALVA, PLATTFORMSVERSION } from "@/alva/system";
|
import { ALVA, PLATTFORMSVERSION } from "@/alva/system";
|
||||||
import { FARG } from "@/alva/komponenter";
|
import { FARG } from "@/alva/komponenter";
|
||||||
import { useWebbSprak, sattWebbSprak } from "@/alva/webbsprak";
|
import { useWebbSprak, sattWebbSprak } from "@/alva/webbsprak";
|
||||||
|
import { INSTALLNINGAR, INSTALLNINGSVAG } from "./installningsomraden";
|
||||||
import { SPRAK, oversattare } from "../../../../services/gemensam/sprak/index.mjs";
|
import { SPRAK, oversattare } from "../../../../services/gemensam/sprak/index.mjs";
|
||||||
|
|
||||||
type Sprakpost = { kod: string; namn: string; egetNamn: string; granskat: boolean };
|
type Sprakpost = { kod: string; namn: string; egetNamn: string; granskat: boolean };
|
||||||
@@ -28,17 +29,18 @@ const PUBLIKT = [
|
|||||||
{ till: "/alva/logga-in", nyckel: "webb.loggain" },
|
{ till: "/alva/logga-in", nyckel: "webb.loggain" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Portalens nivå ett är ARBETET: översikt, analys, de två register man
|
||||||
|
// slår i under ett ärende, och verktyget självt. Allt som KONFIGURERAR
|
||||||
|
// organisationen — källor, integrationer, abonnemang, fakturor och
|
||||||
|
// supportärenden mot plattformen — ligger samlat under Settings. Tio
|
||||||
|
// länkar i tre brutna rader var ingen meny, det var en ordlista.
|
||||||
const PORTAL = [
|
const PORTAL = [
|
||||||
{ till: "/alva/portal", text: "Dashboard" },
|
{ till: "/alva/portal", text: "Dashboard" },
|
||||||
{ till: "/alva/portal/analys", text: "Analysis" },
|
{ till: "/alva/portal/analys", text: "Analysis" },
|
||||||
{ till: "/alva/portal/kunskapskallor", text: "Knowledge sources" },
|
|
||||||
{ till: "/alva/portal/integration", text: "Integration" },
|
|
||||||
{ till: "/alva/portal/garantier", text: "Warranty" },
|
{ till: "/alva/portal/garantier", text: "Warranty" },
|
||||||
{ till: "/alva/portal/forsakring", text: "Insurance" },
|
{ till: "/alva/portal/forsakring", text: "Insurance" },
|
||||||
{ till: "/alva/portal/support", text: "Support" },
|
|
||||||
{ till: "/alva/portal/abonnemang", text: "Subscription" },
|
|
||||||
{ till: "/alva/portal/fakturor", text: "Invoices" },
|
|
||||||
{ till: "/felsokning", text: "Diagnostics" },
|
{ till: "/felsokning", text: "Diagnostics" },
|
||||||
|
{ till: INSTALLNINGSVAG, text: "Settings" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const FOT = [
|
const FOT = [
|
||||||
@@ -59,6 +61,10 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal?
|
|||||||
// plattform finns ingen, och då visas ingen utloggning heller — en
|
// plattform finns ingen, och då visas ingen utloggning heller — en
|
||||||
// knapp som inte loggar ut något är samma sorts sken som m-9 gällde.
|
// knapp som inte loggar ut något är samma sorts sken som m-9 gällde.
|
||||||
const konto = portal ? plattformKonto() : null;
|
const konto = portal ? plattformKonto() : null;
|
||||||
|
// Var i portalen inställningarna börjar. Styr både markeringen av
|
||||||
|
// SETTINGS i huvudraden och den egna raden med områdena — den som
|
||||||
|
// står i en inställningsvy ska aldrig behöva undra var den är.
|
||||||
|
const iInstallningar = portal && (plats.pathname === INSTALLNINGSVAG || INSTALLNINGAR.some((p) => plats.pathname === p.till));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// `alva-yta` bär typografin ur ALVA-SPEC-001 och håller den skild
|
// `alva-yta` bär typografin ur ALVA-SPEC-001 och håller den skild
|
||||||
@@ -86,7 +92,7 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal?
|
|||||||
<nav aria-label={portal ? "Portal" : "Site"} className="w-full sm:w-auto">
|
<nav aria-label={portal ? "Portal" : "Site"} className="w-full sm:w-auto">
|
||||||
<ul className="flex flex-wrap justify-between gap-x-4 gap-y-2 sm:justify-end sm:gap-6">
|
<ul className="flex flex-wrap justify-between gap-x-4 gap-y-2 sm:justify-end sm:gap-6">
|
||||||
{(portal ? PORTAL : PUBLIKT).map((l) => {
|
{(portal ? PORTAL : PUBLIKT).map((l) => {
|
||||||
const aktiv = plats.pathname === l.till;
|
const aktiv = l.till === INSTALLNINGSVAG ? iInstallningar : plats.pathname === l.till;
|
||||||
const text = "nyckel" in l ? t(l.nyckel) : l.text;
|
const text = "nyckel" in l ? t(l.nyckel) : l.text;
|
||||||
return (
|
return (
|
||||||
<li key={l.till}>
|
<li key={l.till}>
|
||||||
@@ -106,6 +112,42 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal?
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
{/* Inne i inställningarna visas områdena som en egen, alltid synlig
|
||||||
|
rad — ingen fällmeny att träffa rätt i, inget läge att gissa.
|
||||||
|
Raden börjar med SETTINGS, som är länken tillbaka till
|
||||||
|
översikten, följt av de fem områdena med det aktiva markerat. */}
|
||||||
|
{iInstallningar && (
|
||||||
|
<nav aria-label="Settings" className="border-b" style={{ borderColor: FARG.lightSteel, background: FARG.white }}>
|
||||||
|
<ul className="mx-auto flex max-w-[1040px] flex-wrap items-center gap-x-4 gap-y-2 px-6 py-2">
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={INSTALLNINGSVAG}
|
||||||
|
aria-current={plats.pathname === INSTALLNINGSVAG ? "page" : undefined}
|
||||||
|
className="text-[11px] font-semibold uppercase tracking-[0.08em]"
|
||||||
|
style={{ color: plats.pathname === INSTALLNINGSVAG ? FARG.blue : FARG.graphite }}
|
||||||
|
>
|
||||||
|
Settings /
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
{INSTALLNINGAR.map((p) => {
|
||||||
|
const aktiv = plats.pathname === p.till;
|
||||||
|
return (
|
||||||
|
<li key={p.till}>
|
||||||
|
<Link
|
||||||
|
to={p.till}
|
||||||
|
aria-current={aktiv ? "page" : undefined}
|
||||||
|
className="text-[11px] uppercase tracking-[0.08em]"
|
||||||
|
style={{ color: aktiv ? FARG.blue : FARG.steel }}
|
||||||
|
>
|
||||||
|
{p.text}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
)}
|
||||||
|
|
||||||
{konto && (
|
{konto && (
|
||||||
<div className="border-b" style={{ borderColor: FARG.lightSteel, background: FARG.white }}>
|
<div className="border-b" style={{ borderColor: FARG.lightSteel, background: FARG.white }}>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Inställningsområdena — en lista, tre användningar: huvudmenyns
|
||||||
|
// SETTINGS-markering, inställningsraden i ramen och översiktssidan.
|
||||||
|
// Ligger i egen modul (inte i Ram.tsx) så att ramen förblir en ren
|
||||||
|
// komponentfil; beskrivningarna finns för att ett namn i en meny säger
|
||||||
|
// vart man kommer, inte vad man kan uträtta där — och det är det
|
||||||
|
// senare som avgör om man klickar rätt.
|
||||||
|
|
||||||
|
export const INSTALLNINGSVAG = "/alva/portal/installningar";
|
||||||
|
|
||||||
|
export const INSTALLNINGAR = [
|
||||||
|
{
|
||||||
|
till: "/alva/portal/kunskapskallor",
|
||||||
|
text: "Knowledge sources",
|
||||||
|
beskrivning: "Connect the organization's licensed information sources and validate their coverage.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
till: "/alva/portal/integration",
|
||||||
|
text: "Integration",
|
||||||
|
beskrivning: "Interfaces to the workshop's surrounding systems — with validation status stated per profile.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
till: "/alva/portal/abonnemang",
|
||||||
|
text: "Subscription",
|
||||||
|
beskrivning: "Plan, user licenses and invoice e-mail. Payment status is stated first.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
till: "/alva/portal/fakturor",
|
||||||
|
text: "Invoices",
|
||||||
|
beskrivning: "What the organization pays for, line by line, with the basis for every amount.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
till: "/alva/portal/support",
|
||||||
|
text: "Support",
|
||||||
|
beskrivning: "The organization's reported platform issues and their current status.",
|
||||||
|
},
|
||||||
|
];
|
||||||
Reference in New Issue
Block a user