import React, { useEffect, useMemo, useState } from "react"; import Table from "../../components/Table"; import Sidebar from "../../components/Sidebar"; import { Container, Row, Col, Button as BootstrapButton, Modal, Form, Alert, } from "react-bootstrap"; import { ActionIcon, Group, TextInput, Text, Stack, Button, Switch, Badge, Tooltip, } from "@mantine/core"; import { IconSearch, IconX, IconEye, IconEdit, IconTrash, IconPlus, IconReceipt2 } from "@tabler/icons-react"; import userAPI from "../../api/model/user"; import { fetchEnumFromSchemaJson } from "../../api/get_chocies"; function Users() { // State const [users, setUsers] = useState([]); const [fetching, setFetching] = useState(true); // Separate filter states for each field const [filterUsername, setFilterUsername] = useState(""); const [filterEmail, setFilterEmail] = useState(""); const [filterFirstName, setFilterFirstName] = useState(""); const [filterLastName, setFilterLastName] = useState(""); const [selectedRoles, setSelectedRoles] = useState([]); const [selectedAccountTypes, setSelectedAccountTypes] = useState([]); const [selectedActive, setSelectedActive] = useState([]); const [selectedEmailVerified, setSelectedEmailVerified] = useState([]); // new filter state const [filterCity, setFilterCity] = useState(""); const [filterPSC, setFilterPSC] = useState(""); const [showModal, setShowModal] = useState(false); const [modalType, setModalType] = useState('view'); // 'view', 'edit' const [selectedUser, setSelectedUser] = useState(null); // Add more fields to formData for editing const [formData, setFormData] = useState({ username: "", email: "", first_name: "", last_name: "", role: "", account_type: "", email_verified: false, phone_number: "", city: "", street: "", PSC: "", bank_account: "", ICO: "", RC: "", GDPR: false, is_active: true, var_symbol: "", // <-- add this line }); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); const [roleDropdownOptions, setRoleDropdownOptions] = useState([]); const [accountTypeDropdownOptions, setAccountTypeDropdownOptions] = useState([]); // Fetch users useEffect(() => { const fetchData = async () => { try { console.log("Fetching users..."); const data = await userAPI.getUsers(); // Defensive: check if response is array, otherwise log error and set empty array if (Array.isArray(data)) { console.log("Fetched users:", data); setUsers(data); } else if (data && Array.isArray(data.results)) { // DRF pagination: { count, next, previous, results } console.log("Fetched users (paginated):", data.results); setUsers(data.results); } else { console.error("Fetched users is not an array:", data); setUsers([]); } } catch (err) { console.error("Error fetching users:", err); setUsers([]); } finally { setFetching(false); } }; fetchData(); }, []); useEffect(() => { // Načti možnosti pro role fetchEnumFromSchemaJson("/api/account/users/", "post", "role") .then((choices) => setRoleDropdownOptions(choices)) .catch(() => setRoleDropdownOptions([ { value: "admin", label: "Administrátor" }, { value: "seller", label: "Prodejce" }, { value: "squareManager", label: "Správce tržiště" }, { value: "cityClerk", label: "Úředník" }, { value: "checker", label: "Kontrolor" }, ])); // Načti možnosti pro typ účtu fetchEnumFromSchemaJson("/api/account/users/", "post", "account_type") .then((choices) => setAccountTypeDropdownOptions(choices)) .catch(() => setAccountTypeDropdownOptions([ { value: "company", label: "Firma" }, { value: "individual", label: "Fyzická osoba" }, ])); }, []); // Role/group options const roleOptions = useMemo(() => { if (!Array.isArray(users)) return []; const allRoles = users.map(u => u.role).filter(Boolean); return [...new Set(allRoles)]; }, [users]); const accountTypeOptions = useMemo(() => { if (!Array.isArray(users)) return []; const allTypes = users.map(u => u.account_type).filter(Boolean); return [...new Set(allTypes)]; }, [users]); // Filtering const filteredUsers = useMemo(() => { let data = Array.isArray(users) ? users : []; if (filterUsername) { const q = filterUsername.toLowerCase(); data = data.filter(u => u.username?.toLowerCase().includes(q)); } if (filterEmail) { const q = filterEmail.toLowerCase(); data = data.filter(u => u.email?.toLowerCase().includes(q)); } if (filterFirstName) { const q = filterFirstName.toLowerCase(); data = data.filter(u => u.first_name?.toLowerCase().includes(q)); } if (filterLastName) { const q = filterLastName.toLowerCase(); data = data.filter(u => u.last_name?.toLowerCase().includes(q)); } if (selectedRoles.length > 0) { data = data.filter(u => selectedRoles.includes(u.role)); } if (selectedAccountTypes.length > 0) { data = data.filter(u => selectedAccountTypes.includes(u.account_type)); } if (selectedActive.length > 0) { data = data.filter(u => selectedActive.includes(u.is_active ? "true" : "false") ); } if (selectedEmailVerified.length > 0) { data = data.filter(u => selectedEmailVerified.includes(u.email_verified ? "true" : "false") ); } if (filterCity) { const q = filterCity.toLowerCase(); data = data.filter(u => u.city?.toLowerCase().includes(q)); } if (filterPSC) { const q = filterPSC.toLowerCase(); data = data.filter(u => u.PSC?.toLowerCase().includes(q)); } return data; }, [users, filterUsername, filterEmail, filterFirstName, filterLastName, selectedRoles, selectedAccountTypes, selectedActive, selectedEmailVerified, filterCity, filterPSC]); // Handlers const handleShowUser = (user) => { console.log("Show user:", user); setSelectedUser(user); setModalType('view'); setShowModal(true); }; const handleEditUser = (user) => { console.log("Edit user:", user); setSelectedUser(user); setFormData({ username: user.username || "", email: user.email || "", first_name: user.first_name || "", last_name: user.last_name || "", role: user.role || "", account_type: user.account_type || "", email_verified: user.email_verified || false, phone_number: user.phone_number || "", city: user.city || "", street: user.street || "", PSC: user.PSC || "", bank_account: user.bank_account || "", ICO: user.ICO || "", RC: user.RC || "", GDPR: user.GDPR || false, is_active: user.is_active ?? true, var_symbol: user.var_symbol || "", }); setModalType('edit'); setShowModal(true); setError(null); }; const handleDeleteUser = async (user) => { console.log("Delete user:", user); if (window.confirm(`Opravdu smazat uživatele: ${user.username}?`)) { await userAPI.deleteUser(user.id); const data = await userAPI.getUsers(); setUsers(data); } }; const handleChange = (e) => { const { name, value, type, checked } = e.target; console.log("Form change:", name, type === "checkbox" ? checked : value); setFormData((old) => ({ ...old, [name]: type === "checkbox" ? checked : value, })); }; const handleGroupsChange = (groups) => { console.log("Groups changed:", groups); setFormData((old) => ({ ...old, groups })); }; const handleEditModalSubmit = async (e) => { e.preventDefault(); setError(null); setSubmitting(true); console.log("Submitting edit:", formData); try { await userAPI.updateUser(selectedUser.id, { ...formData, account_type: formData.account_type, var_symbol: formData.var_symbol, // <-- ensure this is sent }); setShowModal(false); const data = await userAPI.getUsers(); setUsers(data); } catch (err) { const apiErrors = err.response?.data; if (typeof apiErrors === "object") { const messages = Object.entries(apiErrors) .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(", ") : value}`) .join("\n"); setError("Chyba při ukládání:\n" + messages); console.log("API error:", apiErrors); } else { setError("Chyba při ukládání: " + (err.message || "Neznámá chyba")); console.log("Unknown error:", err); } } finally { setSubmitting(false); } }; // Table columns const columns = [ { accessor: "id", title: "#", sortable: true, width: "2%" }, { accessor: "username", title: "Uživatelské jméno", sortable: true, width: "7%", filter: ( } rightSection={ setFilterUsername("")}> } value={filterUsername} onChange={(e) => setFilterUsername(e.currentTarget.value)} /> ), filtering: !!filterUsername, }, { accessor: "email", title: "Email", sortable: true, width: "7%", filter: ( } rightSection={ setFilterEmail("")}> } value={filterEmail} onChange={(e) => setFilterEmail(e.currentTarget.value)} /> ), filtering: !!filterEmail, }, { accessor: "first_name", title: "Jméno", sortable: true, width: "5%", filter: ( } rightSection={ setFilterFirstName("")}> } value={filterFirstName} onChange={(e) => setFilterFirstName(e.currentTarget.value)} /> ), filtering: !!filterFirstName, }, { accessor: "last_name", title: "Příjmení", sortable: true, width: "5%", filter: ( } rightSection={ setFilterLastName("")}> } value={filterLastName} onChange={(e) => setFilterLastName(e.currentTarget.value)} /> ), filtering: !!filterLastName, }, { accessor: "role", title: "Role", width: "7%", render: (row) => row.role ? ( { { "admin": "Administrátor", "seller": "Prodejce", "squareManager": "Správce tržiště", "cityClerk": "Úředník", "checker": "Kontrolor", }[row.role] || row.role } ) : ( Žádná ), filter: (() => { const toggle = (val) => { setSelectedRoles(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val]); }; const roleBadges = roleOptions.map(role => { const label = { "admin": "Administrátor", "seller": "Prodejce", "squareManager": "Správce tržiště", "cityClerk": "Úředník", "checker": "Kontrolor", }[role] || role; const active = selectedRoles.includes(role); return ( toggle(role)} aria-pressed={active} role="button" > {label} ); }); return ( Filtrovat role {roleBadges} {selectedRoles.length > 0 && ( )} ); })(), filtering: selectedRoles.length > 0, }, { accessor: "account_type", title: "Typ účtu", width: "7%", render: (row) => row.account_type ? ( { accountTypeDropdownOptions.find(opt => opt.value === row.account_type)?.label || row.account_type } ) : ( ), sortable: true, filter: (() => { const toggle = (val) => { setSelectedAccountTypes(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val]); }; return ( Filtrovat typ účtu {accountTypeDropdownOptions.map(opt => { const active = selectedAccountTypes.includes(opt.value); return ( toggle(opt.value)} aria-pressed={active} role='button' > {opt.label} ); })} {selectedAccountTypes.length > 0 && ( )} ); })(), filtering: selectedAccountTypes.length > 0, }, { accessor: "email_verified", title: "E-mail ověřen", width: "4%", render: (row) => row.email_verified ? ( Ano ) : ( Ne ), sortable: true, filter: (() => { const toggle = (val) => { setSelectedEmailVerified(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val]); }; const options = [ { value: 'true', label: 'Ano', color: 'green' }, { value: 'false', label: 'Ne', color: 'red' } ]; return ( Ověření {options.map(opt => { const active = selectedEmailVerified.includes(opt.value); return ( toggle(opt.value)} aria-pressed={active} role='button' > {opt.label} ); })} {selectedEmailVerified.length > 0 && ( )} ); })(), filtering: selectedEmailVerified.length > 0, }, { accessor: "is_active", title: "Aktivní", width: "4%", render: (row) => row.is_active ? ( Ano ) : ( Ne ), sortable: true, filter: (() => { const toggle = (val) => { setSelectedActive(prev => prev.includes(val) ? prev.filter(v => v !== val) : [...prev, val]); }; const options = [ { value: 'true', label: 'Ano', color: 'green' }, { value: 'false', label: 'Ne', color: 'red' } ]; return ( Aktivita {options.map(opt => { const active = selectedActive.includes(opt.value); return ( toggle(opt.value)} aria-pressed={active} role='button' > {opt.label} ); })} {selectedActive.length > 0 && ( )} ); })(), filtering: selectedActive.length > 0, }, { accessor: "city", title: "Město", width: "5%", filter: ( } rightSection={ setFilterCity("")}> } value={filterCity} onChange={(e) => setFilterCity(e.currentTarget.value)} /> ), filtering: !!filterCity, }, { accessor: "PSC", title: "PSČ", width: "3%", filter: ( } rightSection={ setFilterPSC("")}> } value={filterPSC} onChange={(e) => setFilterPSC(e.currentTarget.value)} /> ), filtering: !!filterPSC, }, { accessor: "actions", title: "Akce", width: "3.5%", render: (user) => ( handleShowUser(user)}> handleEditUser(user)}> handleDeleteUser(user)}> ), }, ]; return (

Uživatelé

{/* Bootstrap Modal for view */} setShowModal(false)} centered> Detail uživatele {selectedUser && ( <>

ID: {selectedUser.id}

Uživatelské jméno: {selectedUser.username}

Email: {selectedUser.email || "—"}

Jméno: {selectedUser.first_name || "—"}

Příjmení: {selectedUser.last_name || "—"}

Role: {(selectedUser.groups && selectedUser.groups.length > 0) ? selectedUser.groups.join(", ") : "—"}

Aktivní: {selectedUser.is_active ? "Ano" : "Ne"}

)}
setShowModal(false)}>Zavřít { setShowModal(false); handleEditUser(selectedUser); }}>Upravit
{/* Bootstrap Modal for edit */} setShowModal(false)} centered> Upravit uživatele
Uživatelské jméno Email Jméno Příjmení Role {roleDropdownOptions.map(opt => ( ))} Typ účtu {accountTypeDropdownOptions.map(opt => ( ))} Telefon Město Ulice PSČ Bankovní účet IČO Rodné číslo Variabilní symbol setFormData(old => ({ ...old, is_active: e.target.checked }))} /> {error && {error}} setShowModal(false)}>Zrušit Uložit změny
); } export default Users;