mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(oidc): update settings dialog with OIDC user handling and logout flow
This commit is contained in:
@@ -28,7 +28,7 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
|
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
import { apiDelete, apiGet, apiPost, apiPut, clearToken } from "@/lib/api";
|
import { apiDelete, apiGet, apiPost, apiPut, clearToken, formatHeaders } from "@/lib/api";
|
||||||
import { cn, copyToClipboard } from "@/lib/utils";
|
import { cn, copyToClipboard } from "@/lib/utils";
|
||||||
import { useAnalyticsStore } from "@/stores/analytics-store";
|
import { useAnalyticsStore } from "@/stores/analytics-store";
|
||||||
import { useSettingsStore } from "@/stores/settings-store";
|
import { useSettingsStore } from "@/stores/settings-store";
|
||||||
@@ -194,6 +194,10 @@ interface UserEntry {
|
|||||||
username: string;
|
username: string;
|
||||||
role: string;
|
role: string;
|
||||||
team: string;
|
team: string;
|
||||||
|
authProvider?: string;
|
||||||
|
email?: string;
|
||||||
|
hasLocalPassword?: boolean;
|
||||||
|
hasOidcLink?: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,10 +239,25 @@ function GeneralSection() {
|
|||||||
]).finally(() => setLoading(false));
|
]).finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = async () => {
|
||||||
clearToken();
|
try {
|
||||||
localStorage.removeItem("snapotter-username");
|
const res = await fetch("/api/auth/logout", {
|
||||||
window.location.href = "/login";
|
method: "POST",
|
||||||
|
headers: formatHeaders(),
|
||||||
|
});
|
||||||
|
const data = await res.json().catch(() => ({}));
|
||||||
|
clearToken();
|
||||||
|
localStorage.removeItem("snapotter-username");
|
||||||
|
if (data.logoutUrl) {
|
||||||
|
window.location.href = data.logoutUrl;
|
||||||
|
} else {
|
||||||
|
window.location.href = "/login";
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
clearToken();
|
||||||
|
localStorage.removeItem("snapotter-username");
|
||||||
|
window.location.href = "/login";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = useCallback(async () => {
|
const handleSave = useCallback(async () => {
|
||||||
@@ -1078,6 +1097,16 @@ function PeopleSection() {
|
|||||||
{u.username.charAt(0).toUpperCase()}
|
{u.username.charAt(0).toUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm font-medium text-foreground truncate">{u.username}</span>
|
<span className="text-sm font-medium text-foreground truncate">{u.username}</span>
|
||||||
|
{u.hasOidcLink && u.hasLocalPassword !== false && (
|
||||||
|
<span className="ml-1.5 text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground">
|
||||||
|
Local + OIDC
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{u.hasOidcLink && u.hasLocalPassword === false && (
|
||||||
|
<span className="ml-1.5 text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground">
|
||||||
|
OIDC
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Role badge */}
|
{/* Role badge */}
|
||||||
@@ -1130,18 +1159,20 @@ function PeopleSection() {
|
|||||||
<Pencil className="h-3.5 w-3.5" />
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
Edit Role / Team
|
Edit Role / Team
|
||||||
</button>
|
</button>
|
||||||
<button
|
{u.hasLocalPassword !== false && (
|
||||||
type="button"
|
<button
|
||||||
onClick={() => {
|
type="button"
|
||||||
setResetPasswordUser(u);
|
onClick={() => {
|
||||||
setResetPassword("");
|
setResetPasswordUser(u);
|
||||||
setOpenMenuId(null);
|
setResetPassword("");
|
||||||
}}
|
setOpenMenuId(null);
|
||||||
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
}}
|
||||||
>
|
className="flex items-center gap-2 w-full px-3 py-2 text-sm text-foreground hover:bg-muted transition-colors"
|
||||||
<RotateCcw className="h-3.5 w-3.5" />
|
>
|
||||||
Reset Password
|
<RotateCcw className="h-3.5 w-3.5" />
|
||||||
</button>
|
Reset Password
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<div className="border-t border-border my-1" />
|
<div className="border-t border-border my-1" />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
Reference in New Issue
Block a user