Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • shreyp2305/dbms-inventory-manager
1 result
Show changes
Commits on Source (5)
Showing
with 331 additions and 737 deletions
......@@ -54,7 +54,7 @@ function App() {
<Route path="/createorganization" element={<CreateOrganization />} />
</Route>
<Route element={<PrivateRoutes token={token} />}>
<Route path="/createrequest" element={<CreateRequest />} />
<Route path="/createrequest/:orgId" element={<CreateRequest token={token}/>} />
</Route>
<Route element={<PrivateRoutes token={token} />}>
<Route path="/myorganizations" element={<MyOrganizations token={token}/>} />
......
......@@ -43,9 +43,6 @@ export const Navbar = ({ token }) => {
<li>
<NavLink to="/myrequests">My Requests</NavLink>
</li>
<li>
<NavLink to="/createrequest">Create Request</NavLink>
</li>
<li>
<NavLink to="/listallorganizations">
List All Organizations
......
......@@ -60,4 +60,48 @@
width: 100%;
margin-bottom: 10px;
}
.request-form {
display: flex;
flex-direction: column;
align-items: center;
}
.request-form h3 {
margin-bottom: 10px;
}
.request-form label {
margin-bottom: 10px;
}
.request-form input {
padding: 8px;
width: 100%;
margin-bottom: 10px;
}
.send-request-button {
display: block;
margin-top: 20px;
padding: 10px 20px;
color: #fff;
background-color: #5cb85c; /* Green color for send request button */
border: 1px solid #5cb85c;
border-radius: 5px;
cursor: pointer;
}
.send-request-button:hover {
background-color: #4cae4c; /* Darker green color on hover */
}
.borrow-item-button {
/* Add your styles for the borrow item button */
color: #fff;
background-color: #5bc0de; /* Blue color for modify button */
border: 1px solid #5bc0de;
display: block;
margin-top: 20px;
padding: 10px 20px;
}
......@@ -18,6 +18,14 @@ const OrganizationItemDetails = ({ token }) => {
quantity: 0,
});
const navigate = useNavigate();
const [showRequestForm, setShowRequestForm] = useState(false);
const [requestDescription, setRequestDescription] = useState('');
const [requestQuantity, setRequestQuantity] = useState(1);
const [requestSent, setRequestSent] = useState(false);
const handleBorrowItem = () => {
setShowRequestForm(true);
};
const [error, setError] = useState(null); // New state for error handling
const handleDeleteItem = async () => {
// Logic to handle item deletion
......@@ -44,6 +52,32 @@ const OrganizationItemDetails = ({ token }) => {
}
};
const handleSendRequest = async () => {
// Logic to send the request
// You can customize this based on your backend API
console.log('Sending request...');
// Assuming you have an API endpoint to handle request creation
try {
// You need to replace this with your actual API endpoint
const response = await Axios.post('http://localhost:8080/requests/create', {
orgId: parseInt(orgId),
itemId: parseInt(itemId),
description: requestDescription,
quantity: requestQuantity,
jwt: token.jwt,
});
if (response.data.result === 'success') {
setRequestSent(true);
setError(null);
} else {
console.error('Error sending request');
setError('Something went wrong creating the send request!');
}
} catch (error) {
console.error('Some unexpected error occurred:', error);
}
};
const handleDropdownChange = (field, value) => {
setModifiedFields((prevFields) => ({
...prevFields,
......@@ -93,8 +127,10 @@ const OrganizationItemDetails = ({ token }) => {
if (response.data.result === 'success') {
setItemInfo(response.data);
setError(null);
} else {
console.error('Error fetching item information');
setError('Something went wrong modifying the item');
}
} catch (error) {
console.error('Error fetching item information:', error);
......@@ -158,6 +194,7 @@ const OrganizationItemDetails = ({ token }) => {
return (
<div className="organization-item-details">
<h2>Item Details</h2>
{error && <p> {error}</p>}
<div className="item-details">
<span>Name: {itemInfo.data[1]}</span>
<span>Description: {itemInfo.data[2]}</span>
......@@ -244,6 +281,36 @@ const OrganizationItemDetails = ({ token }) => {
Delete Item
</button>
)}
<div className="request-form">
{showRequestForm && !requestSent && (
<div>
<h3>Borrow Item</h3>
<label>
Description:
<input
type="text"
value={requestDescription}
onChange={(e) => setRequestDescription(e.target.value)}
/>
</label>
<label>
Quantity:
<input
type="number"
value={requestQuantity}
onChange={(e) => setRequestQuantity(e.target.value)}
/>
</label>
<button onClick={handleSendRequest} className="send-request-button">
Send Request
</button>
</div>
)}
{requestSent && <p>Request sent!</p>}
</div>
<button onClick={handleBorrowItem} className="borrow-item-button">
Borrow Item
</button>
</div>
);
};
......
......@@ -15,6 +15,7 @@ const OrganizationItems = ({ token }) => {
const [locationFilter, setLocationFilter] = useState('');
const [quantityFilter, setQuantityFilter] = useState('');
const [searchFilter, setSearchFilter] = useState('');
const [statusFilter, setStatusFilter] = useState('');
const navigate = useNavigate();
const handleItemClick = (item) => {
navigate(`/organizations/${orgId}/items/${item}`);
......@@ -71,6 +72,9 @@ const OrganizationItems = ({ token }) => {
item[1].toLowerCase().includes(searchFilter.toLowerCase())
);
}
if (statusFilter) {
filteredItemsCopy = filteredItemsCopy.filter(item => item[6] === statusFilter);
}
setFilteredItems(filteredItemsCopy);
};
......@@ -119,6 +123,14 @@ const OrganizationItems = ({ token }) => {
onChange={(e) => setSearchFilter(e.target.value)}
/>
</label>
<label>
Status:
<select onChange={(e) => setStatusFilter(e.target.value)}>
<option value="">All</option>
<option value="AVAILABLE">Available</option>
<option value="BORROWED">Borrowed</option>
</select>
</label>
<button onClick={handleFilter}>Apply Filters</button>
</div>
<div className="items-list">
......
import React, { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import Axios from 'axios';
import '../../user/Login.css'
const OrganizationItemCreate = ({ token }) => {
const { orgId } = useParams();
const navigate = useNavigate();
const [locations, setLocations] = useState([]);
const [formData, setFormData] = useState({
status: 'AVAILABLE',
category: 'TOOLS',
description: '',
name: '',
quantity: 0,
locationId: '',
});
const [error, setError] = useState(null); // New state for error handling
useEffect(() => {
const fetchLocations = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/location', {
orgId: parseInt(orgId),
jwt: token.jwt,
});
if (response.data.result === 'success') {
setLocations(response.data.data);
if (response.data.type === 'MEMBER')
{
//members are not supposed to create items, redirect them to 404 page
navigate('/404');
}
} else {
console.error('Error fetching locations');
}
} catch (error) {
console.error('Error fetching locations:', error);
}
};
fetchLocations();
}, [orgId, token]);
const handleDropdownChange = (field, value) => {
setFormData((prevData) => ({
...prevData,
[field]: value,
}));
};
const handleCreateItem = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/oneitem/create', {
orgId: parseInt(orgId),
jwt: token.jwt,
...formData,
});
if (response.data.result === 'success') {
navigate(`/organizations/${orgId}/items`);
} else {
console.error('Error creating item');
setError('Error, incomplete fields'); // Set error message
}
} catch (error) {
console.error('Some unexpected error occurred:', error);
setError('Error, incomplete fields'); // Set error message
}
};
return (
<div className="organization-item-create">
<h2>Create Item</h2>
<div className="create-item-fields">
<div>
<span>Status:</span>
<select value={formData.status} onChange={(e) => handleDropdownChange('status', e.target.value)}>
<option value="AVAILABLE">Available</option>
<option value="BORROWED">Borrowed</option>
</select>
</div>
<div>
<span>Category:</span>
<select value={formData.category} onChange={(e) => handleDropdownChange('category', e.target.value)}>
<option value="STATIONERY">Stationery</option>
<option value="MARKETING">Marketing</option>
<option value="ELECTRONICS">Electronics</option>
<option value="SUPPLIES">Supplies</option>
<option value="PERISHABLES">Perishables</option>
<option value="MERCHANDISE">Merchandise</option>
<option value="TOOLS">Tools</option>
<option value="CHEMICALS">Chemicals</option>
<option value="FLAMMABLE">Flammable</option>
<option value="OTHER">Other</option>
<option value="UNIQUE">Unique</option>
<option value="BOOKS">Books</option>
{/* Add other category options */}
</select>
</div>
<label>
Description:
<input
type="text"
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
/>
</label>
<label>
Name:
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
</label>
<label>
Quantity:
<input
type="number"
value={formData.quantity}
onChange={(e) => setFormData({ ...formData, quantity: e.target.value })}
/>
</label>
<label>
Location:
<select
value={formData.locationId}
onChange={(e) => handleDropdownChange('locationId', e.target.value)}
>
<option value="">Select a location</option>
{locations.map(([locationName, locationId]) => (
<option key={locationId} value={locationId}>
{locationName}
</option>
))}
</select>
</label>
{error && <p className="error-message">{error}</p>}
</div>
<button onClick={handleCreateItem} className="create-item-button">
Create Item
</button>
</div>
);
};
export default OrganizationItemCreate;
/* OrganizationItemDetails.css */
.organization-item-details {
max-width: 600px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
align-items: center;
}
.item-details {
margin-top: 20px;
display: flex;
flex-direction: column;
align-items: center; /* Center the entire content */
text-align: center;
}
.item-details span {
display: block;
margin-bottom: 10px;
text-align: left;
width: 100%;
}
.modify-item-button {
display: block;
margin-top: 20px;
padding: 10px 20px;
color: #fff;
background-color: #5bc0de; /* Blue color for modify button */
border: 1px solid #5bc0de;
border-radius: 5px;
cursor: pointer;
}
.modify-item-button:hover {
background-color: #46b8da; /* Darker blue color on hover */
}
.delete-item-button {
background-color: #8b0000; /* Dark red color */
color: #fff;
border: 1px solid #6b0000; /* Dark red border color */
padding: 10px 20px;
font-size: 14px;
cursor: pointer;
border-radius: 5px;
margin-top: 20px;
}
.delete-item-button:hover
{
background-color: #6b0000; /* Dark red color on hover */
}
/* Style for dropdowns */
.item-details select {
padding: 8px;
width: 100%;
margin-bottom: 10px;
}
// OrganizationItemDetails.jsx
import React, { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import Axios from 'axios';
import './OrganizationItemDetails.css';
import '../OrganizationDetails.css'
const OrganizationItemDetails = ({ token }) => {
const { orgId, itemId } = useParams();
const [itemInfo, setItemInfo] = useState(null);
const [locations, setLocations] = useState([]);
const [modifiedLocation, setModifiedLocation] = useState('');
const [modifiedFields, setModifiedFields] = useState({
status: '',
category: '',
description: '',
name: '',
quantity: 0,
});
const navigate = useNavigate();
const [error, setError] = useState(null); // New state for error handling
const handleDeleteItem = async () => {
// Logic to handle item deletion
if (
window.confirm(
`Are you sure you want to permanently delete all quantities of ${itemInfo.data[1]}? This will delete the entire item.`
)
) {
console.log('Deleting item...');
try {
const response = await Axios.post('http://localhost:8080/item/user/oneitem/delete', {
orgId: parseInt(orgId), // Convert orgId to integer
jwt: token.jwt,
itemId: parseInt(itemId), // Convert itemId to integer
});
if (response.data.result === 'success') {
navigate(`/organizations/${orgId}/items`);
} else {
console.error('Error deleting item');
}
} catch (error) {
console.error('Some unexpected error occurred:', error);
}
}
};
const handleDropdownChange = (field, value) => {
setModifiedFields((prevFields) => ({
...prevFields,
[field]: value,
}));
};
const handleModifyItem = async () => {
// Logic to handle item modification
try {
const modifiedFieldsToSend = {
orgId: parseInt(orgId),
jwt: token.jwt,
itemId: parseInt(itemId),
...modifiedFields,
};
// Check if a modified field is left blank and use the current value from itemInfo
Object.keys(modifiedFields).forEach((key) => {
if (modifiedFields[key] === '') {
console.log(key);
if (key === 'status')
modifiedFieldsToSend[key] = itemInfo.data[6];
else if (key === 'quantity')
modifiedFieldsToSend[key] = itemInfo.data[4];
else if (key === 'category')
modifiedFieldsToSend[key] = itemInfo.data[5];
else if (key === 'name')
modifiedFieldsToSend[key] = itemInfo.data[1];
else if (key === 'description')
modifiedFieldsToSend[key] = itemInfo.data[2];
else if (key === 'location')
modifiedFieldsToSend[key] = itemInfo.data[9];
}
});
const response = await Axios.put('http://localhost:8080/item/user/oneitem', modifiedFieldsToSend);
if (response.data.result === 'success') {
// Reload the item details after modification
const fetchItemDetails = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/oneitem', {
orgId: parseInt(orgId), // Convert orgId to integer
jwt: token.jwt,
itemId: parseInt(itemId), // Convert itemId to integer
});
if (response.data.result === 'success') {
setItemInfo(response.data);
} else {
console.error('Error fetching item information');
}
} catch (error) {
console.error('Error fetching item information:', error);
}
};
fetchItemDetails();
} else {
console.error('Error modifying item');
}
} catch (error) {
console.error('Some unexpected error occurred:', error);
}
};
// Fetch item details on component mount
useEffect(() => {
const fetchLocations = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/location', {
orgId: parseInt(orgId),
jwt: token.jwt,
});
if (response.data.result === 'success') {
setLocations(response.data.data);
} else {
console.error('Error fetching locations');
}
} catch (error) {
console.error('Error fetching locations:', error);
}
};
fetchLocations();
const fetchItemDetails = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/oneitem', {
orgId: parseInt(orgId),
jwt: token.jwt,
itemId: parseInt(itemId),
});
if (response.data.result === 'success') {
setItemInfo(response.data);
} else {
console.error('Error fetching item information');
}
} catch (error) {
console.error('Error fetching item information:', error);
}
};
fetchItemDetails();
}, [orgId, itemId, token]);
if (!itemInfo) {
return <div>Loading...</div>;
}
return (
<div className="organization-item-details">
<h2>Item Details</h2>
<div className="item-details">
<span>Name: {itemInfo.data[1]}</span>
<span>Description: {itemInfo.data[2]}</span>
<span>Owner Email: {itemInfo.data[3]}</span>
<span>Quantity: {itemInfo.data[4]}</span>
<span>Category: {itemInfo.data[5]}</span>
<span>Status: {itemInfo.data[6]}</span>
<span>Location: {itemInfo.data[9]}</span>
</div>
{(itemInfo.type === 'OWNER' || itemInfo.type === 'MANAGER') && (
<div>
<h3>Modify Item</h3>
<div className="modify-item-fields">
<div>
<span>Status:</span>
<select value={modifiedFields.status} defaultValue={itemInfo.data[6]} onChange={(e) => handleDropdownChange('status', e.target.value)}>
<option value="AVAILABLE">Available</option>
<option value="BORROWED">Borrowed</option>
</select>
</div>
<div>
<span>Category:</span>
<select value={modifiedFields.category} defaultValue={itemInfo.data[5]} onChange={(e) => handleDropdownChange('category', e.target.value)}>
<option value="STATIONERY">Stationery</option>
<option value="MARKETING">Marketing</option>
<option value="ELECTRONICS">Electronics</option>
<option value="SUPPLIES">Supplies</option>
<option value="PERISHABLES">Perishables</option>
<option value="MERCHANDISE">Merchandise</option>
<option value="TOOLS">Tools</option>
<option value="CHEMICALS">Chemicals</option>
<option value="FLAMMABLE">Flammable</option>
<option value="OTHER">Other</option>
<option value="UNIQUE">Unique</option>
<option value="BOOKS">Books</option>
</select>
</div>
<label>
Description:
<input
type="text"
value={modifiedFields.description}
onChange={(e) => setModifiedFields({ ...modifiedFields, description: e.target.value })}
/>
</label>
<label>
Name:
<input
type="text"
value={modifiedFields.name}
onChange={(e) => setModifiedFields({ ...modifiedFields, name: e.target.value })}
/>
</label>
<label>
Quantity:
<input
type="number"
value={modifiedFields.quantity}
onChange={(e) => setModifiedFields({ ...modifiedFields, quantity: e.target.value })}
/>
</label>
</div>
<label>
Location:
<select
value={modifiedFields.locationId}
onChange={(e) => setModifiedFields( { ...modifiedFields, locationId:e.target.value})}
>
<option value="">Select a location</option>
{locations.map(([locationName, locationId], index) => (
<option key={locationId} value={locationId}>
{locationName}
</option>
))}
</select>
</label>
<button onClick={handleModifyItem} className="modify-item-button">
Modify Item
</button>
</div>
)}
{(itemInfo.type === 'OWNER' || itemInfo.type === 'MANAGER') && (
<button onClick={handleDeleteItem} className="delete-item-button">
Delete Item
</button>
)}
</div>
);
};
export default OrganizationItemDetails;
.organization-items {
max-width: 800px;
margin: 0 auto;
}
h2 {
color: #333;
}
.filters {
margin-bottom: 20px;
}
label {
margin-right: 10px;
}
select,
input {
margin-right: 10px;
padding: 5px;
}
button {
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
}
.items-list {
display: grid;
gap: 20px;
}
.item-item {
border: 1px solid #ddd;
padding: 15px;
border-radius: 8px;
background-color: #f9f9f9;
text-align: left;
}
.item-details {
display: flex;
flex-direction: column;
gap: 8px;
}
.item-details span {
display: block;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #f0f0f0; /* Optional background color for the header */
}
.create-item-button {
display: block;
margin-top: 20px;
padding: 10px 20px;
color: #fff;
background-color: #5bc0de; /* Blue color for modify button */
border: 1px solid #5bc0de;
border-radius: 5px;
cursor: pointer;
width: 300px;
}
/* Add more styles as needed */
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import './OrganizationItems.css'
import './OrganizationItemDetails.css'
import {useNavigate, useParams} from "react-router-dom";
const OrganizationItems = ({ token }) => {
// const [orgId, setOrgId] = useState(null);
const [items, setItems] = useState([]);
const { orgId } = useParams();
const [filteredItems, setFilteredItems] = useState([]);
const [categories, setCategories] = useState([]);
const [locations, setLocations] = useState([]);
const [categoryFilter, setCategoryFilter] = useState('');
const [locationFilter, setLocationFilter] = useState('');
const [quantityFilter, setQuantityFilter] = useState('');
const [searchFilter, setSearchFilter] = useState('');
const navigate = useNavigate();
const handleItemClick = (item) => {
navigate(`/organizations/${orgId}/items/${item}`);
};
const [type, setType] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await Axios.post('http://localhost:8080/item/user/all', {
orgId: orgId,
jwt: token.jwt,
});
if (response.data.result === 'success') {
setItems(response.data.data);
setType(response.data.type);
setFilteredItems(response.data.data);
// Extract categories and locations for filtering
const uniqueCategories = [...new Set(response.data.data.map(item => item[5]))];
const uniqueLocations = [...new Set(response.data.data.map(item => item[9]))];
setCategories(['', ...uniqueCategories]);
setLocations(['', ...uniqueLocations]);
} else {
console.error('Error fetching organization items');
navigate('/404');
}
} catch (error) {
console.error('Error fetching organization items:', error);
navigate('/404');
}
};
// Set orgId based on your logic (e.g., from token or passed as a prop)
// setOrgId(2);
fetchData();
}, [orgId, token]);
const handleFilter = () => {
let filteredItemsCopy = [...items];
// Apply filters
if (categoryFilter) {
filteredItemsCopy = filteredItemsCopy.filter(item => item[5] === categoryFilter);
}
if (locationFilter) {
filteredItemsCopy = filteredItemsCopy.filter(item => item[9] === locationFilter);
}
if (quantityFilter) {
filteredItemsCopy = filteredItemsCopy.filter(item => item[4] >= parseInt(quantityFilter, 10));
}
if (searchFilter) {
filteredItemsCopy = filteredItemsCopy.filter(item =>
item[1].toLowerCase().includes(searchFilter.toLowerCase())
);
}
setFilteredItems(filteredItemsCopy);
};
const handleCreateButton = () => {
navigate(`/organizations/${orgId}/items/create`);
}
return (
<div className="organization-items">
<div className="header">
<h2>Organization Items</h2>
{(type === 'MANAGER' || type === 'OWNER') && <button className="create-item-button" onClick={() => handleCreateButton()}>
Create Item
</button>}
</div>
<div className="filters">
<label>
Category:
<select onChange={(e) => setCategoryFilter(e.target.value)}>
{categories.map((category, index) => (
<option key={index} value={category}>{category}</option>
))}
</select>
</label>
<label>
Location:
<select onChange={(e) => setLocationFilter(e.target.value)}>
{locations.map((location, index) => (
<option key={index} value={location}>{location}</option>
))}
</select>
</label>
<label>
Minimum Quantity:
<input
type="number"
value={quantityFilter}
onChange={(e) => setQuantityFilter(e.target.value)}
/>
</label>
<label>
Search by Name:
<input
type="text"
value={searchFilter}
onChange={(e) => setSearchFilter(e.target.value)}
/>
</label>
<button onClick={handleFilter}>Apply Filters</button>
</div>
<div className="items-list">
{filteredItems.length > 0 ? (
filteredItems.map((item, index) => (
<div key={index} className="item-item" onClick={() => handleItemClick(item[0])}>
<div className="item-details" >
<span><strong>Name:</strong> {item[1]}</span>
<span><strong>Description:</strong> {item[2]}</span>
<span><strong>Owner Email:</strong> {item[3]}</span>
<span><strong>Quantity:</strong> {item[4]}</span>
<span><strong>Category:</strong> {item[5]}</span>
<span><strong>Status:</strong> {item[6]}</span>
<span><strong>Location:</strong> {item[9]}</span>
</div>
</div>
))
) : (
<p>No items found.</p>
)}
</div>
</div>
);
};
export default OrganizationItems;
......@@ -40,13 +40,16 @@ const MyRequests = ({ token }) => {
<h2>Your Requests</h2>
<ul>
{requests.map((request) => (
<li key={request.requestId} className="request-item">
<li key={request[4]} className="request-item">
{/* <Link to={`/organizations/${org.orgId}`}>
<h3>{org.name}</h3>
</Link> */}
<p>Organization Name: {request.organizationName}</p>
<p>Status: {request.status}</p>
<p>Description: {request.description}</p>
<p>Organization Name: {request[2]}</p>
<p>Status: {request[0]}</p>
<p>Description: {request[1]}</p>
<p>Type: {request[3]}</p>
{request[6] && <p> Item Name: {request[6]}</p>}
{request[5] && <p> Item Quantity: {request[5]}</p>}
{/* Add more information as needed */}
</li>
))}
......
import React, { useState, useEffect } from "react";
import Axios from "axios";
import { useLocation } from 'react-router-dom';
import {useLocation, useParams, useNavigate} from 'react-router-dom';
export const CreateRequest = (props) => {
export const CreateRequest = ({token}) => {
// const [reqId, setReqId] = useState("");
const [userEmail, setUserEmail] = useState("");
const [desc, setDesc] = useState("");
......@@ -11,7 +11,8 @@ export const CreateRequest = (props) => {
const [status, setStatus] = useState("");
const [type, setType] = useState("");
const [organizationName, setOrganizationName] = useState(""); // name of org to join/add item to
const orgId = useParams();
const navigate = useNavigate();
const location = useLocation();
const rowData = location.state?.data;
......@@ -30,18 +31,18 @@ export const CreateRequest = (props) => {
const handleSubmit = (e) => {
e.preventDefault();
console.log(orgId);
Axios.post("http://localhost:8080/request/add", {
userEmail: userEmail,
// reqId: reqId,
desc: desc,
organizationId: 2,
status: "PENDING",
type: type,
organizationName: organizationName,
itemId: null,
quantity: null
jwt: token.jwt,
description: desc,
orgId: orgId
}).then((response) => {
console.log(response);
if (response.data.result === 'success')
{
navigate('/myrequests');
}
});
};
......@@ -58,7 +59,7 @@ export const CreateRequest = (props) => {
placeholder="Request ID"
/> */}
<label htmlFor="name">Organization/Item Name</label>
<label htmlFor="name">Organization Name</label>
<input
value={organizationName}
onChange={(e) => setOrganizationName(e.target.value)}
......@@ -67,15 +68,6 @@ export const CreateRequest = (props) => {
placeholder="name"
/>
<label htmlFor="userEmail">User Email</label>
<input
value={userEmail}
onChange={(e) => setUserEmail(e.target.value)}
name="userEmail"
id="userEmail"
placeholder="user_pid@vt.edu"
type="email"
/>
{/* <label htmlFor="status">Status</label>
<input
......@@ -87,14 +79,6 @@ export const CreateRequest = (props) => {
placeholder="STATUS"
/> */}
<label htmlFor="type">Type</label>
<input
value={type}
onChange={(e) => setType(e.target.value)}
name="type"
id="type"
placeholder="JOIN/ITEM"
/>
<label htmlFor="desc">Description</label>
<input
......
......@@ -24,6 +24,8 @@ import FilterListIcon from '@mui/icons-material/FilterList';
import { visuallyHidden } from '@mui/utils';
import Axios from "axios";
import { useNavigate } from 'react-router-dom';
import {FormControl, InputLabel, MenuItem, Select} from "@mui/material";
import TextField from "@mui/material/TextField";
function descendingComparator(a, b, orderBy) {
......@@ -213,14 +215,20 @@ EnhancedTableToolbar.propTypes = {
//export default function EnhancedTable() {
export const ListAllOrganizations = (props) => {
const navigate = useNavigate();
const [searchInput, setSearchInput] = useState('');
const [selectedCategory, setSelectedCategory] = useState('');
const [order, setOrder] = React.useState('asc');
const [orderBy, setOrderBy] = React.useState('');
const [orderBy, setOrderBy] = React.useState('category');
const [selected, setSelected] = React.useState([]);
const [page, setPage] = React.useState(0);
const [dense, setDense] = React.useState(false);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
const getFilteredRows = () => {
return rows
.filter(row => row.name.toLowerCase().includes(searchInput.toLowerCase()))
.filter(row => selectedCategory ? row.category === selectedCategory : true);
};
//export const ListAllOrganizations = (props) => {
const [rows, setRows] = useState([]); // State to store the rows
......@@ -229,6 +237,7 @@ export const ListAllOrganizations = (props) => {
try {
const response = await Axios.get("http://localhost:8080/organization/all");
setRows(response.data); // Update state with fetched data
setOrderBy('name');
} catch (error) {
console.error('Error fetching data: ', error);
}
......@@ -243,6 +252,13 @@ export const ListAllOrganizations = (props) => {
setOrderBy(property);
};
const handleSearchClicked = () => {
if (orderBy === 'name')
setOrderBy('category');
else
setOrderBy('name');
setOrder('asc');
}
const handleSelectAllClick = (event) => {
if (event.target.checked) {
const newSelected = rows.map((n) => n.id);
......@@ -276,7 +292,7 @@ export const ListAllOrganizations = (props) => {
// }
const toRequest = (event, row) => {
navigate('/createrequest', { state: { data: row } });
navigate(`/createrequest/${row.orgId}`, { state: { data: row } });
};
const handleChangePage = (event, newPage) => {
......@@ -300,7 +316,7 @@ export const ListAllOrganizations = (props) => {
const visibleRows = React.useMemo(
() =>
stableSort(rows, getComparator(order, orderBy)).slice(
stableSort(getFilteredRows(), getComparator(order, orderBy)).slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage,
),
......@@ -310,6 +326,33 @@ export const ListAllOrganizations = (props) => {
return (
<Box sx={{ width: '100%' }}>
<Paper sx={{ width: '100%', mb: 2 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<TextField
label="Search by Name"
variant="outlined"
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
sx={{ mr: 2 }}
/>
<button onClick={handleSearchClicked}> Search</button>
<FormControl sx={{ minWidth: 120 }}>
<InputLabel id="category-select-label">Category</InputLabel>
<Select
labelId="category-select-label"
id="category-select"
value={selectedCategory}
label="Category"
onChange={(e) => setSelectedCategory(e.target.value)}
>
<MenuItem value="">All</MenuItem>
<MenuItem value="ACADEMIC">Academic</MenuItem>
<MenuItem value="RECREATION">Recreation</MenuItem>
<MenuItem value="TECHNOLOGY">Technology</MenuItem>
<MenuItem value="POLITICS">Politics</MenuItem>
<MenuItem value="GREEKLIFE">Greek Life</MenuItem>
</Select>
</FormControl>
</Box>
<EnhancedTableToolbar numSelected={selected.length} />
<TableContainer>
<Table
......@@ -334,7 +377,7 @@ export const ListAllOrganizations = (props) => {
<TableRow
hover
// onClick={(event) => handleClick(event, row.id)}
onClick={(event) => toRequest(event, row)}
onClick={(event) => toRequest(event, row, row.id)}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
......
......@@ -70,10 +70,12 @@ public class AuthController {
if (claim != null)
{
res.put("user", claim.getSubject());
res.put("result", "success");
}
else
{
res.put("login", "failed - expired/bad token");
res.put("result", "failure");
}
}
else
......
......@@ -29,14 +29,88 @@ public class CustomRequestRepository {
return query.getResultList();
}
@Transactional
public List<Object> findUserRequests(String userEmail)
public List<Object[]> findUserRequests(String userEmail)
{
String nativeQuery = "SELECT r.status, r.description, r.type, r.quantity, i.name, o.name FROM REQUEST r JOIN ORGANIZATION o ON o.organization_id = r.organization_id JOIN ITEM i ON r.item_id = i.item_id WHERE r.user_email = :userEmail";
List<Object> requests = entityManager
.createNativeQuery(nativeQuery)
.setParameter("userEmail", userEmail)
.getResultList();
return requests;
String nativeQuery = "SELECT r.status, r.description, o.name, " +
"r.type, r.request_id, r.quantity, i.name " +
"FROM REQUEST r " +
"JOIN ORGANIZATION o ON r.organization_id = o.organization_id " +
"LEFT JOIN ITEM i ON r.item_id = i.item_id " +
"WHERE r.user_email = :userEmail";
Query query = entityManager.createNativeQuery(nativeQuery);
query.setParameter("userEmail", userEmail);
@SuppressWarnings("unchecked")
List<Object[]> resultRows = query.getResultList();
return resultRows;
}
@Transactional
public Object createItemRequest(@RequestBody Map<String, Object> json)
{
// Extract parameters from the JSON map
Integer orgId;
if (json.get("orgId") instanceof Integer)
orgId = (Integer) json.get("orgId");
else {
orgId = Integer.parseInt((String)json.get("orgId"));
}
Integer quantity;
if (json.get("quantity") instanceof Integer)
quantity = (Integer) json.get("quantity");
else {
quantity = Integer.parseInt((String)json.get("quantity"));
}
Integer itemId;
if (json.get("itemId") instanceof Integer)
itemId = (Integer) json.get("itemId");
else {
itemId = Integer.parseInt((String)json.get("itemId"));
}
String description = (String) json.get("description");
String userEmail = (String) json.get("userEmail");
// Use native SQL query with EntityManager to create a new request
String nativeQuery = "INSERT INTO REQUEST (user_email, organization_id, status, quantity, type, description, item_id) " +
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)";
Query query = entityManager.createNativeQuery(nativeQuery)
.setParameter(1, userEmail)
.setParameter(2, orgId)
.setParameter(3, "PENDING")
.setParameter(4, quantity)
.setParameter(5, "ITEM")
.setParameter(6, description)
.setParameter(7, itemId);
int updatedRows = query.executeUpdate();
return updatedRows > 0;
}
@Transactional
public Object createJoinRequest(@RequestBody Map<String, Object> json)
{
// Extract parameters from the JSON map
Integer orgId;
if (json.get("orgId") instanceof Integer)
orgId = (Integer) json.get("orgId");
else if (json.get("orgId") instanceof HashMap<?,?>)
orgId = Integer.parseInt((String)((HashMap)json.get("orgId")).get("orgId"));
else {
orgId = Integer.parseInt((String)json.get("orgId"));
}
String description = (String) json.get("description");
String userEmail = (String) json.get("userEmail");
// Use native SQL query with EntityManager to create a new request
String nativeQuery = "INSERT INTO REQUEST (user_email, organization_id, status, type, description) " +
"VALUES (?1, ?2, ?3, ?4, ?5)";
Query query = entityManager.createNativeQuery(nativeQuery)
.setParameter(1, userEmail)
.setParameter(2, orgId)
.setParameter(3, "PENDING")
.setParameter(4, "JOIN")
.setParameter(5, description);
int updatedRows = query.executeUpdate();
return updatedRows > 0;
}
@Transactional
public Object updateRequest(@RequestBody Map<String, Object> json)
......
......@@ -67,11 +67,61 @@ public class RequestController {
}
@PostMapping(path = "/add") // Map ONLY POST Requests
@ResponseBody
public Request addJsonOrg(@RequestBody Request req) {
public Map<String, Object> createJoinRequest(@RequestBody Map <String, Object> json) {
// @ResponseBody means the returned String is the response, not a view name
// @RequestParam means it is a parameter from the GET or POST request
requestRepository.save(req);
return req;
Map<String, Object> response = new HashMap<>();
if (!json.containsKey("orgId") || !json.containsKey("jwt") || !json.containsKey("description"))
{
response.put("result", "failure - bad request");
return response;
}
AuthController au = new AuthController();
Map<String, String> map = au.verify(json); // if the jwt token could not be verified
if (map.get("result").equals("success"))
{
json.put("userEmail", map.get("user"));
// System.out.println(json.get("orgId"));
response.put("data", customRequestRepository.createJoinRequest(json));
response.put("result", "success");
}
else
{
response.put("result", "failure - not authorized");
}
return response;
}
@PostMapping(path = "/user/create") // Map ONLY POST Requests
@ResponseBody
public Map<String, Object> createRequest(@RequestBody Map<String, Object> json) {
// @ResponseBody means the returned String is the response, not a view name
// @RequestParam means it is a parameter from the GET or POST request
Map<String, Object> response = new HashMap<>();
if (!json.containsKey("orgId") || !json.containsKey("jwt") || !json.containsKey("description")
|| !json.containsKey("quantity") || !json.containsKey("itemId"))
{
response.put("result", "failure - bad request");
return response;
}
Map<String, Object> map = getUserOrg(json);
if (map.get("result").equals("success"))
{
if (map.get("type") != OrganizationRoster.Type.MANAGER && map.get("type") != OrganizationRoster.Type.OWNER
&& map.get("type") != OrganizationRoster.Type.MEMBER)
{
response.put("result", "failure - not a member of the org");
return response;
}
json.put("userEmail", map.get("userEmail"));
response.put("data", customRequestRepository.createItemRequest(json));
response.put("result", "success");
}
else
{
response.put("result", "failure - not authorized");
}
return response;
}
@PostMapping(path = "/user/requests")
public @ResponseBody Map<String, Object> getOrgRequest(@RequestBody Map<String, Object> json)
......@@ -116,6 +166,7 @@ public class RequestController {
response.put("result", "failure - bad request");
return response;
}
System.out.println(json.get("orgId"));
Map<String, Object> map = getUserOrg(json);
if (map.get("result").equals("success"))
{
......@@ -166,6 +217,8 @@ public class RequestController {
response.put("result", "failed = user not found");
return response;
}
if (json.get("orgId") instanceof HashMap<?,?>)
return myOrgRosterRepository.findUserOrg(usr.get().getEmail(), Integer.parseInt((String)((HashMap)json.get("orgId")).get("orgId")));
if (json.get("orgId") instanceof Integer)
return myOrgRosterRepository.findUserOrg(usr.get().getEmail(), (Integer) json.get("orgId"));
return myOrgRosterRepository.findUserOrg(usr.get().getEmail(), Integer.parseInt((String) json.get("orgId")));
......