Initial commit
This commit is contained in:
137
resources/js/components/admin/users/AdminUserForm.tsx
Normal file
137
resources/js/components/admin/users/AdminUserForm.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Button, Checkbox, Input } from "@heroui/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type UserItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
is_admin: boolean;
|
||||
is_active: boolean;
|
||||
};
|
||||
|
||||
type FormMode = "create" | "edit";
|
||||
|
||||
type Props = {
|
||||
mode: FormMode;
|
||||
editing: UserItem | null;
|
||||
submitting: boolean;
|
||||
serverError: string | null;
|
||||
onSubmit: (payload: {
|
||||
name: string;
|
||||
email: string;
|
||||
password?: string;
|
||||
is_admin: boolean;
|
||||
is_active: boolean;
|
||||
}) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
|
||||
export default function AdminUserForm({
|
||||
mode,
|
||||
editing,
|
||||
submitting,
|
||||
serverError,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: Props) {
|
||||
const { t } = useTranslation("common");
|
||||
const [name, setName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [isActive, setIsActive] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === "edit" && editing) {
|
||||
setName(editing.name);
|
||||
setEmail(editing.email);
|
||||
setPassword("");
|
||||
setIsAdmin(editing.is_admin);
|
||||
setIsActive(editing.is_active);
|
||||
} else {
|
||||
setName("");
|
||||
setEmail("");
|
||||
setPassword("");
|
||||
setIsAdmin(false);
|
||||
setIsActive(true);
|
||||
}
|
||||
}, [mode, editing]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
const payload = {
|
||||
name: name.trim(),
|
||||
email: email.trim(),
|
||||
is_admin: isAdmin,
|
||||
is_active: isActive,
|
||||
} as {
|
||||
name: string;
|
||||
email: string;
|
||||
password?: string;
|
||||
is_admin: boolean;
|
||||
is_active: boolean;
|
||||
};
|
||||
|
||||
if (password.trim()) {
|
||||
payload.password = password.trim();
|
||||
}
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded border border-divider p-4 space-y-3">
|
||||
<div className="text-sm font-semibold">
|
||||
{mode === "edit"
|
||||
? t("admin_users_edit_title") ?? "Upravit uživatele"
|
||||
: t("admin_users_create_title") ?? "Nový uživatel"}
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3">
|
||||
<Input
|
||||
label={t("admin_users_name") ?? "Jméno"}
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
size="sm"
|
||||
/>
|
||||
<Input
|
||||
label={t("admin_users_email") ?? "Email"}
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
size="sm"
|
||||
/>
|
||||
<Input
|
||||
label={t("admin_users_password") ?? "Heslo"}
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
size="sm"
|
||||
placeholder={
|
||||
mode === "edit"
|
||||
? t("admin_users_password_hint") ?? "Nech prázdné pro beze změny"
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<div className="flex gap-6">
|
||||
<Checkbox isSelected={isAdmin} onValueChange={setIsAdmin}>
|
||||
{t("admin_users_is_admin") ?? "Admin"}
|
||||
</Checkbox>
|
||||
<Checkbox isSelected={isActive} onValueChange={setIsActive}>
|
||||
{t("admin_users_is_active") ?? "Aktivní"}
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{serverError && <div className="text-red-600 text-sm">{serverError}</div>}
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button color="primary" isDisabled={submitting} onPress={handleSubmit}>
|
||||
{submitting ? t("admin_users_saving") ?? "Ukládám…" : t("admin_users_save") ?? "Uložit"}
|
||||
</Button>
|
||||
<Button variant="light" onPress={onCancel}>
|
||||
{t("admin_form_close") ?? "Zavřít formulář"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
67
resources/js/components/admin/users/AdminUsersTable.tsx
Normal file
67
resources/js/components/admin/users/AdminUsersTable.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
import { Button, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@heroui/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type UserItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
is_admin: boolean;
|
||||
is_active: boolean;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
items: UserItem[];
|
||||
loading: boolean;
|
||||
onEdit: (item: UserItem) => void;
|
||||
onDeactivate: (item: UserItem) => void;
|
||||
};
|
||||
|
||||
export default function AdminUsersTable({ items, loading, onEdit, onDeactivate }: Props) {
|
||||
const { t } = useTranslation("common");
|
||||
|
||||
return (
|
||||
<Table aria-label="Users table">
|
||||
<TableHeader>
|
||||
<TableColumn>{t("admin_users_name") ?? "Jméno"}</TableColumn>
|
||||
<TableColumn>{t("admin_users_email") ?? "Email"}</TableColumn>
|
||||
<TableColumn>{t("admin_users_is_admin") ?? "Admin"}</TableColumn>
|
||||
<TableColumn>{t("admin_users_is_active") ?? "Aktivní"}</TableColumn>
|
||||
<TableColumn>{t("admin_users_actions") ?? "Akce"}</TableColumn>
|
||||
</TableHeader>
|
||||
<TableBody
|
||||
items={items}
|
||||
emptyContent={
|
||||
loading
|
||||
? t("admin_users_loading") ?? "Načítám..."
|
||||
: t("admin_users_empty") ?? "Žádní uživatelé."
|
||||
}
|
||||
>
|
||||
{(item) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell>{item.name}</TableCell>
|
||||
<TableCell>{item.email}</TableCell>
|
||||
<TableCell>{item.is_admin ? "ANO" : "NE"}</TableCell>
|
||||
<TableCell>{item.is_active ? "ANO" : "NE"}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="bordered" onPress={() => onEdit(item)}>
|
||||
{t("admin_users_edit") ?? "Upravit"}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
color="danger"
|
||||
variant="light"
|
||||
onPress={() => onDeactivate(item)}
|
||||
isDisabled={!item.is_active}
|
||||
>
|
||||
{t("admin_users_deactivate") ?? "Deaktivovat"}
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user