Localize kanban, auth, backup, and admin utilities

This commit is contained in:
cesnimda
2026-03-23 21:05:49 +01:00
parent 9661a321da
commit 2c03379504
11 changed files with 181 additions and 75 deletions
@@ -6,6 +6,7 @@ import { api } from "../api";
import { getAuthToken } from "../auth";
import { useToast } from "../toast";
import { useDialogActions } from "../dialogs";
import { useI18n } from "../i18n/I18nProvider";
type UserDto = {
id: string;
@@ -18,6 +19,7 @@ type UserDto = {
export default function UserManagementCard() {
const { toast } = useToast();
const { confirmAction } = useDialogActions();
const { t } = useI18n();
const token = getAuthToken();
const [supported, setSupported] = useState<boolean | null>(null);
@@ -41,7 +43,7 @@ export default function UserManagementCard() {
if (status === 401 || status === 403) {
setSupported(false);
} else {
toast("Failed to load users.", "error");
toast(t("adminUsersLoadFailed"), "error");
setSupported(false);
}
} finally {
@@ -65,21 +67,21 @@ export default function UserManagementCard() {
return (
<Paper sx={{ mt: 2, p: 2 }}>
<Typography variant="h6" sx={{ mb: 1 }}>
User management
{t("adminUsersTitle")}
</Typography>
<Typography sx={{ color: "text.secondary", mb: 2 }}>
Admin-only.
{t("adminUsersSubtitle")}
</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1.5 }}>
<TextField
label="Email"
label={t("profileEmail")}
value={newEmail}
onChange={(e) => setNewEmail(e.target.value)}
fullWidth
/>
<TextField
label="Password"
label={t("adminUsersPassword")}
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
type="password"
@@ -92,7 +94,7 @@ export default function UserManagementCard() {
variant={newIsAdmin ? "contained" : "outlined"}
onClick={() => setNewIsAdmin((v) => !v)}
>
{newIsAdmin ? "Admin: Yes" : "Admin: No"}
{newIsAdmin ? t("adminUsersAdminYes") : t("adminUsersAdminNo")}
</Button>
<Button
variant="contained"
@@ -107,21 +109,21 @@ export default function UserManagementCard() {
setNewEmail("");
setNewPassword("");
setNewIsAdmin(false);
toast("User created.", "success");
toast(t("adminUsersCreated"), "success");
await load();
} catch (e: any) {
const msg = e?.response?.data || e?.message || "Failed to create user.";
const msg = e?.response?.data || e?.message || t("adminUsersCreateFailed");
toast(String(msg), "error");
}
}}
>
Create user
{t("adminUsersCreateUser")}
</Button>
</Box>
<Box sx={{ mt: 2, display: "flex", flexDirection: "column", gap: 1 }}>
{users.length === 0 ? (
<Typography sx={{ color: "text.secondary" }}>No users.</Typography>
<Typography sx={{ color: "text.secondary" }}>{t("adminUsersNoUsers")}</Typography>
) : (
users.map((u) => (
<Box
@@ -140,10 +142,10 @@ export default function UserManagementCard() {
>
<Box>
<Typography sx={{ fontWeight: 900, lineHeight: 1.2 }}>
{u.email || u.userName || u.id}
{u.userName || u.email || u.id}
</Typography>
<Typography variant="caption" sx={{ color: "text.secondary" }}>
Roles: {u.roles?.length ? u.roles.join(", ") : "—"}
{t("adminUsersRolesLabel")}: {u.roles?.length ? u.roles.join(", ") : "—"}
</Typography>
</Box>
@@ -151,17 +153,17 @@ export default function UserManagementCard() {
variant="outlined"
color="error"
onClick={async () => {
if (!(await confirmAction("Delete this user?", { title: "Delete user", confirmLabel: "Delete", destructive: true }))) return;
if (!(await confirmAction(t("adminUsersDeleteConfirmBody"), { title: t("adminUsersDeleteConfirmTitle"), confirmLabel: t("adminUsersDelete"), destructive: true }))) return;
try {
await api.delete(`/users/${u.id}`);
toast("User deleted.", "info");
toast(t("adminUsersDeleted"), "info");
await load();
} catch {
toast("Failed to delete user.", "error");
toast(t("adminUsersDeleteFailed"), "error");
}
}}
>
Delete
{t("adminUsersDelete")}
</Button>
<Button
@@ -169,14 +171,14 @@ export default function UserManagementCard() {
onClick={async () => {
try {
await api.post(`/users/${u.id}/send-password-reset`);
toast("Password reset email sent.", "success");
toast(t("adminUsersResetSent"), "success");
} catch (e: any) {
const msg = e?.response?.data || e?.message || "Failed to send reset email.";
const msg = e?.response?.data || e?.message || t("adminUsersResetFailed");
toast(String(msg), "error");
}
}}
>
Send reset
{t("adminUsersSendReset")}
</Button>
</Box>
))