Localize kanban, auth, backup, and admin utilities
This commit is contained in:
@@ -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>
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user