Skip to content
Snippets Groups Projects
Commit 81da0608 authored by Sarthak Shrivastava's avatar Sarthak Shrivastava
Browse files

Working Roster view, endpoints developed for updating members. Roster view looks nice too.

parent 4eaf78b0
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@ import PrivateRoutes from "./routes/PrivateRoutes";
import MyOrganizations from "./components/myorg/MyOrganizations";
import OrganizationDetails from "./components/myorg/OrganizationDetails";
import NotFound from "./components/error/NotFound";
import OrganizationRoster from "./components/myorg/roster/OrganizationRoster";
function App() {
// const [token, setToken] = useState();
......@@ -54,6 +55,9 @@ function App() {
<Route element={<PrivateRoutes token={token} />}>
<Route path="/organizations/:orgId" element={<OrganizationDetails token={token}/> } />
</Route>
<Route element={<PrivateRoutes token={token} />}>
<Route path="/organizations/:orgId/members" element={<OrganizationRoster token={token}/> } />
</Route>
<Route path='*' element={<NotFound />}/>
<Route path='/404' element={<NotFound />}/>
{/*<Route path="/organizations/:orgId" element={<OrganizationDetails token={token}/>}>*/}
......
......@@ -30,6 +30,10 @@ const OrganizationDetails = ({token}) => {
fetchOrganizationDetails();
}, [orgId]);
const handleRosterButtonClick = () => {
// Redirect to the OrganizationMembers page
navigate(`/organizations/${orgId}/members`);
};
if (!organization) {
return <div>Loading...</div>;
}
......@@ -45,7 +49,7 @@ const OrganizationDetails = ({token}) => {
</div>
{/* Buttons at the bottom */}
<div className="button-container">
<button className="blue-button">Roster</button>
<button className="blue-button" onClick={handleRosterButtonClick}>Roster</button>
<button className="blue-button">Requests</button>
<button className="blue-button">Items</button>
<button className="blue-button">Listings</button>
......
.organization-members {
text-align: center;
margin-top: 50px;
padding: 20px; /* Add padding for more space */
}
h2 {
font-size: 24px;
}
.members-list {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
}
.member-item {
display: flex;
flex-direction: column; /* Display columns instead of rows */
width: 300px;
margin-bottom: 20px; /* Increase margin for better spacing */
padding: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
.member-item span {
margin-bottom: 10px; /* Add space between each span */
}
.member-type {
padding: 8px 16px;
border-radius: 4px;
color: #fff;
}
.owner {
background-color: #3498db;
}
.member {
background-color: #2ecc71;
}
.manager {
background-color: #e74c3c;
}
import React, { useState, useEffect} from 'react';
import {useNavigate, useParams} from "react-router-dom";
import Axios from 'axios';
import './OrganizationRoster.css'; // Import the CSS file for styling
const OrganizationMembers = ({ token }) => {
const { orgId } = useParams();
const [roster, setRoster] = useState([]);
const [type, setType] = useState('');
const [loading, setLoading] = useState(true);
const navigate = useNavigate();
useEffect(() => {
const fetchOrganizationMembers = async () => {
try {
const response = await Axios.post('http://localhost:8080/myorg/user/roster', {
orgId: orgId,
jwt: token.jwt,
});
if (response.data.result === 'success') {
setRoster(response.data.roster);
setType(response.data.type);
} else {
console.error('Error fetching organization members');
navigate('/404');
}
} catch (error) {
console.error('Error fetching organization members:', error);
navigate('/404');
} finally {
setLoading(false);
}
};
fetchOrganizationMembers();
}, [orgId, token]);
if (loading) {
return <div>Loading...</div>;
}
return (
<div className="organization-members">
<h2>Organization Members</h2>
<div className="members-list">
{roster.map((member, index) => (
<div key={index} className="member-item">
<span>{member[1]}, {member[0]}</span>
<span>Email: {member[2]}</span>
<span className={`member-type ${member[3].toLowerCase()}`}>{member[3]}</span>
</div>
))}
</div>
<p>Your role in the organization: {type}</p>
</div>
);
};
export default OrganizationMembers;
......@@ -60,14 +60,17 @@ VALUES
('alicedoe@example.com', 5, 'MEMBER'),
('emilyjohnson@example.com', 2, 'MEMBER');
INSERT INTO ORGANIZATION_ROSTER(user_email, organization_id, type)
VALUES
('johnsmith@example.com', 2, 'MEMBER');
UPDATE ORGANIZATION o
SET member_count = (
SELECT COUNT(DISTINCT user_email)
FROM ORGANIZATION_ROSTER
WHERE organization_id = o.organization_id
)
WHERE member_count != o.member_count
;
WHERE member_count != o.member_count;
......
......@@ -5,6 +5,7 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
......@@ -69,7 +70,7 @@ public class MyOrgRosterRepository implements OrgRosterRepository{
@Transactional
public List<Object> getRoster(Integer orgId)
{
String nativeQuery = "SELECT u.fname, u.lname, r.type" +
String nativeQuery = "SELECT u.fname, u.lname, u.email, r.type" +
" FROM ORGANIZATION_ROSTER r" +
" JOIN USER u ON r.user_email=u.email" +
" WHERE r.organization_id = :orgId";
......@@ -79,6 +80,64 @@ public class MyOrgRosterRepository implements OrgRosterRepository{
}
@Transactional
public Map<String, Object> updateMember(Integer orgId, String memberEmail, OrganizationRoster.Type type)
{
Map<String, Object> result = new HashMap<>();
try {
String query = "UPDATE organization_roster SET type = :type " +
"WHERE organization_id = :orgId AND user_email = :memberEmail";
Query nativeQuery = entityManager.createNativeQuery(query);
nativeQuery.setParameter("type", type.name());
nativeQuery.setParameter("orgId", orgId);
nativeQuery.setParameter("memberEmail", memberEmail);
int updatedRows = nativeQuery.executeUpdate();
result.put("result", "success");
result.put("updatedRows", updatedRows);
} catch (Exception e) {
result.put("result", "failure");
result.put("error", e.getMessage());
}
return result;
}
@Transactional
public Map<String, Object> deleteMember(Integer orgId, String memberEmail)
{
Map<String, Object> result = new HashMap<>();
try {
// Delete the member from ORGANIZATION_ROSTER
String deleteQuery = "DELETE FROM organization_roster WHERE organization_id = :orgId AND user_email = :memberEmail";
Query deleteNativeQuery = entityManager.createNativeQuery(deleteQuery);
deleteNativeQuery.setParameter("orgId", orgId);
deleteNativeQuery.setParameter("memberEmail", memberEmail);
int deletedRows = deleteNativeQuery.executeUpdate();
if (deletedRows > 0) {
// Decrement the member count in ORGANIZATION
String updateCountQuery = "UPDATE organization SET member_count = member_count - 1 WHERE organization_id = :orgId";
Query updateCountNativeQuery = entityManager.createNativeQuery(updateCountQuery);
updateCountNativeQuery.setParameter("orgId", orgId);
int updatedCountRows = updateCountNativeQuery.executeUpdate();
result.put("result", "success");
result.put("deletedRows", deletedRows);
result.put("updatedCountRows", updatedCountRows);
} else {
result.put("result", "failure");
result.put("error", "Member not found in the organization roster");
}
} catch (Exception e) {
result.put("result", "failure");
result.put("error", e.getMessage());
}
return result;
}
@Override
public <S extends OrganizationRoster> S save(S entity) {
return null;
......
......@@ -98,11 +98,82 @@ public class OrgRosterController {
result.put("result", "success");
result.put("type", map.get("type")); //tell the client what type this user is so they can render buttons for the roster
System.out.println(map.get("orgId"));
result.put("roster", myOrgRosterRepository.getRoster((Integer) json.get("orgId")));
if (json.get("orgId") instanceof Integer)
result.put("roster", myOrgRosterRepository.getRoster((Integer) json.get("orgId")));
else
result.put("roster", myOrgRosterRepository.getRoster(Integer.parseInt((String) json.get("orgId"))));
return result;
}
result.put("result", "failure");
return result;
}
@PutMapping(path="/user/update")
public @ResponseBody Map<String, Object> updateUser(@RequestBody Map<String, Object> json)
{
Map<String, Object> result = new HashMap<>();
if (!json.containsKey("orgId") || !json.containsKey("newtype") || !json.containsKey("jwt") || !json.containsKey("memberEmail"))
{
result.put("result", "failure bad request");
return result;
}
Map<String, Object> map = getUserOrg(json);
//above, verify that this user is even supposed to see this information
if (map.get("result").equals("success"))
{
Integer orgId;
if (json.get("orgId") instanceof Integer)
{
orgId = (Integer) json.get("orgId");
}
else
{
orgId = Integer.parseInt((String)json.get("orgId"));
}
System.out.println(map.get("type"));
System.out.println(map.get("type").getClass());
if (map.get("type") == OrganizationRoster.Type.OWNER)
{
if (json.get("newtype").equals("MANAGER") || json.get("newtype").equals("MEMBER"))
{
//simple promotion/demotion case
result.put("result", "success");
result.put("data", myOrgRosterRepository.updateMember(orgId, (String) json.get("memberEmail"), OrganizationRoster.Type.valueOf((String)json.get("newtype"))));
}
else if (json.get("newtype").equals("DELETE"))
{
result.put("data", myOrgRosterRepository.deleteMember(orgId, (String) json.get("memberEmail")));
return result;
}
else
{
result.put("result", "failure - bad type");
return result;
}
}
else if (map.get("type") == OrganizationRoster.Type.MANAGER)
{
if (json.get("newtype").equals("DELETE"))
{
//delete this user, update the membercount for the org
result.put("data", myOrgRosterRepository.deleteMember(orgId, (String) json.get("memberEmail")));
return result;
}
else
{
result.put("result", "failure - permission denied or bad type");
return result;
}
}
else
{
//members cannot promote or change anyone's type
result.put("result", "failure - permission denied");
return result;
}
}
result.put("result", "failure");
return result;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment