diff --git a/src/App.css b/src/App.css index d54ede8..b3eb87f 100644 --- a/src/App.css +++ b/src/App.css @@ -1,5 +1,5 @@ #root { - max-width: 1280px; + margin: 0 auto; padding: 2rem; text-align: center; diff --git a/src/api/userApi.js b/src/api/userApi.js index ba07e58..94f56c5 100644 --- a/src/api/userApi.js +++ b/src/api/userApi.js @@ -1,4 +1,3 @@ -// src/api/userApi.js export default class UserApi { constructor(token) { this.baseUrl = 'https://thalos-bff.dream-views.com/api/v1/User'; @@ -32,4 +31,40 @@ export default class UserApi { throw err; } } + + // === CREATE a user === + async createUser(userData) { + try { + const response = await fetch(`${this.baseUrl}/Create`, { + method: 'POST', + headers: this.getHeaders(), + body: JSON.stringify(userData), + }); + if (!response.ok) { + throw new Error(`Failed to create user: ${response.status}`); + } + return await response.json(); + } catch (err) { + console.error('Error creating user:', err); + throw err; + } + } + + // === UPDATE a user === + async updateUser(userData) { + try { + const response = await fetch(`${this.baseUrl}/Update`, { + method: 'PUT', + headers: this.getHeaders(), + body: JSON.stringify(userData), + }); + if (!response.ok) { + throw new Error(`Failed to update user: ${response.status}`); + } + return await response.json(); + } catch (err) { + console.error('Error updating user:', err); + throw err; + } + } } \ No newline at end of file diff --git a/src/private/users/AddOrEditUserForm.jsx b/src/private/users/AddOrEditUserForm.jsx index 4d79483..fbacc50 100644 --- a/src/private/users/AddOrEditUserForm.jsx +++ b/src/private/users/AddOrEditUserForm.jsx @@ -1,103 +1,192 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; import { Box, Button, TextField, MenuItem } from '@mui/material'; -import { createExternalData, updateExternalData } from '../../api/mongo/actions'; +import UserApi from '../../api/userApi'; +import { useAuth } from '../../context/AuthContext'; export default function AddOrEditUserForm({ onAdd, initialData, onCancel }) { - const [formData, setFormData] = useState({ - username: '', - fullName: '', + const { user } = useAuth(); + const thalosToken = user?.thalosToken || localStorage.getItem('thalosToken'); + const api = useMemo(() => (thalosToken ? new UserApi(thalosToken) : null), [thalosToken]); + + const [formData, setFormData] = useState({ + _Id: '', + email: '', + name: '', + middleName: '', + lastName: '', + tenantId: '', + roleId: '', + status: 'Active', + companies: [], + projects: [], + sendInvitation: true, + }); + + useEffect(() => { + if (initialData) { + setFormData({ + _Id: initialData._id || initialData._Id || '', + email: initialData.email ?? '', + name: initialData.name ?? '', + middleName: initialData.middleName ?? '', + lastName: initialData.lastName ?? '', + tenantId: initialData.tenantId ?? '', + roleId: initialData.roleId ?? '', + status: initialData.status ?? 'Active', + companies: Array.isArray(initialData.companies) ? initialData.companies : [], + projects: Array.isArray(initialData.projects) ? initialData.projects : [], + sendInvitation: true, + }); + } else { + setFormData({ + _Id: '', email: '', - role: 'User', - status: 'Active' - }); + name: '', + middleName: '', + lastName: '', + tenantId: '', + roleId: '', + status: 'Active', + companies: [], + projects: [], + sendInvitation: true, + }); + } + }, [initialData]); - useEffect(() => { - if (initialData) { - setFormData({ ...initialData }); - } else { - setFormData({ - username: '', - fullName: '', - email: '', - role: 'User', - status: 'Active' - }); - } - }, [initialData]); + const handleChange = (e) => { + const { name, value } = e.target; + if (name === 'companies' || name === 'projects') { + const arr = value.split(',').map(s => s.trim()).filter(s => s.length > 0); + setFormData(prev => ({ ...prev, [name]: arr })); + } else { + setFormData(prev => ({ ...prev, [name]: value })); + } + }; - const handleChange = (e) => { - const { name, value } = e.target; - setFormData(prev => ({ ...prev, [name]: value })); - }; + const handleSubmit = async () => { + try { + if (!api) throw new Error('Missing Thalos token'); - const handleSubmit = async () => { - try { - if (initialData) { - await updateExternalData(formData); - } else { - await createExternalData(formData); - } - if (onAdd) onAdd(); - } catch (error) { - console.error('Error submitting form:', error); - } - }; + if (initialData) { + // UPDATE (PUT /User/Update) — API requires _Id, remove Id, displayName, tenantId + const payload = { + _Id: formData._Id, + email: formData.email, + name: formData.name, + middleName: formData.middleName, + lastName: formData.lastName, + tenantId: formData.tenantId, + roleId: formData.roleId, + companies: formData.companies, + projects: formData.projects, + status: formData.status || 'Active', + }; + await api.updateUser(payload); + } else { + // CREATE (POST /User/Create) + const payload = { + email: formData.email, + name: formData.name, + middleName: formData.middleName, + lastName: formData.lastName, + roleId: formData.roleId, + sendInvitation: !!formData.sendInvitation, + }; + await api.createUser(payload); + } - return ( - - - - - - Admin - User - Manager - - - Active - Inactive - - - - - - - ); + onAdd?.(); + } catch (error) { + console.error('Error submitting form:', error); + } + }; + + return ( + + + + + + + + + + + Active + Inactive + + + + + + + + ); } \ No newline at end of file diff --git a/src/private/users/UserManagement.jsx b/src/private/users/UserManagement.jsx index 7e3a992..a1f6290 100644 --- a/src/private/users/UserManagement.jsx +++ b/src/private/users/UserManagement.jsx @@ -7,8 +7,8 @@ import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded'; import AddOrEditUserForm from './AddOrEditUserForm'; import UserApi from '../../api/userApi'; import { useAuth } from '../../context/AuthContext'; -import { deleteExternalData } from '../../api/mongo/actions'; import useApiToast from '../../hooks/useApiToast'; +import '../../App.css'; const columnsBase = [ { field: 'email', headerName: 'Email', width: 260 }, @@ -88,7 +88,22 @@ export default function UserManagement() { const handleEditClick = (params) => { if (!params || !params.row) return; - setEditingData(params.row); + const r = params.row; + const normalized = { + _id: r._id || r._Id || '', + id: r.id || r.Id || '', + email: r.email ?? '', + name: r.name ?? '', + middleName: r.middleName ?? '', + lastName: r.lastName ?? '', + displayName: r.displayName ?? '', + tenantId: r.tenantId ?? '', + roleId: r.roleId ?? '', + status: r.status ?? 'Active', + companies: Array.isArray(r.companies) ? r.companies : [], + projects: Array.isArray(r.projects) ? r.projects : [], + }; + setEditingData(normalized); setOpen(true); }; @@ -100,7 +115,22 @@ export default function UserManagement() { const handleConfirmDelete = async () => { try { - await deleteExternalData(rowToDelete?._id); + if (!apiRef.current || !rowToDelete?._id) throw new Error('Missing API or user id'); + + const payload = { + _Id: rowToDelete._id || rowToDelete._Id, + Id: rowToDelete.id || rowToDelete.Id, + email: rowToDelete.email ?? '', + name: rowToDelete.name ?? '', + middleName: rowToDelete.middleName ?? '', + lastName: rowToDelete.lastName ?? '', + roleId: rowToDelete.roleId ?? '', + companies: Array.isArray(rowToDelete.companies) ? rowToDelete.companies : [], + projects: Array.isArray(rowToDelete.projects) ? rowToDelete.projects : [], + status: 'Inactive', + }; + + await apiRef.current.updateUser(payload); await loadData(); } catch (error) { console.error('Delete failed:', error); @@ -164,12 +194,11 @@ export default function UserManagement() { return ( - User Management - { setOpen(false); setEditingData(null); }} maxWidth="md" fullWidth> {editingData ? 'Edit User' : 'Add User'} { await loadData(); setOpen(false); @@ -212,18 +241,18 @@ export default function UserManagement() { sx={{ '& .MuiDataGrid-cell': { display: 'flex', - alignItems: 'center', // vertical centering + alignItems: 'center', }, '& .MuiDataGrid-columnHeader': { display: 'flex', - alignItems: 'center', // vertical centering headers too + alignItems: 'center', } }} /> -