diff --git a/package-lock.json b/package-lock.json
index b233376..a34d0fd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "arbeidspuls",
- "version": "1.1.0",
+ "version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "arbeidspuls",
- "version": "1.1.0",
+ "version": "1.1.1",
"dependencies": {
"lucide-react": "^0.475.0",
"react": "^19.0.0",
diff --git a/package.json b/package.json
index e7ab4f1..27b50f9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "arbeidspuls",
- "version": "1.1.0",
+ "version": "1.1.1",
"private": true,
"type": "module",
"scripts": {
diff --git a/public/service-worker.js b/public/service-worker.js
index 92c7e58..4125b7d 100644
--- a/public/service-worker.js
+++ b/public/service-worker.js
@@ -1,4 +1,4 @@
-const CACHE_NAME = "arbeidspuls-v5";
+const CACHE_NAME = "arbeidspuls-v6";
const ASSETS = ["/", "/index.html", "/manifest.webmanifest", "/icon.svg"];
self.addEventListener("install", (event) => {
diff --git a/src/App.tsx b/src/App.tsx
index 9064dcb..cf16ac7 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -37,6 +37,7 @@ import {
import {
deleteEvaluatorNote,
deleteEvaluatorProfile,
+ ensureDemoEvaluatorProfiles,
exportEvaluatorBackup,
importEvaluatorBackup,
importExportPayload,
@@ -153,20 +154,14 @@ function AppRoutes() {
return (
- {demoMode &&
changeDemoMode(false)} />}
);
@@ -1687,8 +1671,9 @@ function PrivacyPanel({ demoMode, entries, onDeleted }: { demoMode: boolean; ent
function EvaluatorApp() {
const { labels, t } = useI18n();
- const [profiles, setProfiles] = useState(() => listEvaluatorProfiles());
- const [selectedId, setSelectedId] = useState(() => listEvaluatorProfiles()[0]?.id ?? null);
+ const [demoMode, setDemoMode] = useState(() => isDemoModeEnabled());
+ const [profiles, setProfiles] = useState(() => listEvaluatorProfiles(isDemoModeEnabled()));
+ const [selectedId, setSelectedId] = useState(() => listEvaluatorProfiles(isDemoModeEnabled())[0]?.id ?? null);
const [displayName, setDisplayName] = useState("");
const [targetId, setTargetId] = useState("");
const [message, setMessage] = useState("");
@@ -1705,10 +1690,27 @@ function EvaluatorApp() {
if (selected) setPersonNote(getPersonNote(selected)?.text ?? "");
}, [selected?.id]);
- const refresh = (nextSelectedId?: string) => {
- const next = listEvaluatorProfiles();
+ useEffect(() => {
+ const next = listEvaluatorProfiles(demoMode);
setProfiles(next);
- if (nextSelectedId) setSelectedId(nextSelectedId);
+ setSelectedId((current) => (current && next.some((profile) => profile.id === current) ? current : next[0]?.id ?? null));
+ setSelectedEntryId(null);
+ }, [demoMode]);
+
+ const refresh = (nextSelectedId?: string) => {
+ const next = listEvaluatorProfiles(demoMode);
+ setProfiles(next);
+ setSelectedId((current) => nextSelectedId ?? (current && next.some((profile) => profile.id === current) ? current : next[0]?.id ?? null));
+ };
+
+ const changeDemoMode = (enabled: boolean) => {
+ setDemoModeEnabled(enabled);
+ if (enabled) {
+ ensureDemoData();
+ ensureDemoEvaluatorProfiles();
+ }
+ setDemoMode(enabled);
+ setMessage(enabled ? t("demo.notice") : "");
};
const importFile = async (event: React.ChangeEvent) => {
@@ -1716,7 +1718,7 @@ function EvaluatorApp() {
if (!file) return;
try {
- const result = importExportPayload(await file.text(), displayName, targetId || undefined);
+ const result = importExportPayload(await file.text(), displayName, targetId || undefined, demoMode);
const flagged = result.verification.modified + result.verification.missing + result.verification.unsupported + result.verification.error;
const actionText =
result.target_resolution === "matched_existing_person"
@@ -1739,8 +1741,10 @@ function EvaluatorApp() {
const file = event.target.files?.[0];
if (!file) return;
try {
- importEvaluatorBackup(await file.text());
- setMessage(t("evaluator.importedBackup"));
+ const text = await file.text();
+ const demoEntries = countEvaluatorBackupDemoEntries(text);
+ importEvaluatorBackup(text, demoMode);
+ setMessage(`${t("evaluator.importedBackup")}${demoEntries > 0 ? ` ADVARSEL: Backupen inneholder ${demoEntries} demodata-oppføringer.` : ""}`);
refresh();
} catch (error) {
setMessage(error instanceof Error ? error.message : "Backup kunne ikke importeres.");
@@ -1750,32 +1754,32 @@ function EvaluatorApp() {
};
const downloadBackup = () => {
- const blob = new Blob([exportEvaluatorBackup()], { type: "application/json" });
+ const blob = new Blob([exportEvaluatorBackup(demoMode)], { type: "application/json" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
- link.download = `arbeidsevne-veilederdata-${new Date().toISOString().slice(0, 10)}.json`;
+ link.download = `${demoMode ? "arbeidspuls-demo" : "arbeidspuls"}-veilederdata-${new Date().toISOString().slice(0, 10)}.json`;
link.click();
URL.revokeObjectURL(url);
};
const saveName = () => {
if (!selected) return;
- renameEvaluatorProfile(selected.id, selected.display_name);
+ renameEvaluatorProfile(selected.id, selected.display_name, demoMode);
refresh(selected.id);
};
const savePersonNote = () => {
if (!selected) return;
- upsertEvaluatorNote(selected.id, personNote, { note_type: "person" });
+ upsertEvaluatorNote(selected.id, personNote, { note_type: "person" }, demoMode);
setPersonNote("");
refresh(selected.id);
};
const deleteSelectedPerson = () => {
if (!deletePersonRequest) return;
- deleteEvaluatorProfile(deletePersonRequest.id);
- const remaining = listEvaluatorProfiles();
+ deleteEvaluatorProfile(deletePersonRequest.id, demoMode);
+ const remaining = listEvaluatorProfiles(demoMode);
setProfiles(remaining);
setSelectedId(remaining[0]?.id ?? null);
setSelectedEntryId(null);
@@ -1801,7 +1805,7 @@ function EvaluatorApp() {
const followupsByParent = useMemo(() => (selected ? groupFollowups(selected.reports) : new Map()), [selected]);
return (
-