Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

65 Update Status Form #72

Merged
merged 11 commits into from
Nov 18, 2024
4 changes: 2 additions & 2 deletions client-app/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ForgotPassword from './Components/ForgotPassword';
import ResetPasswordPage from './Components/ResetPasswordPage';
import DonatedItemsList from './Components/DonatedItemsList';
import DonorForm from './Components/DonorForm.tsx';
import StatusDisplayPage from './Components/StatusDisplayPage';
import StatusUpdate from './Components/AddNewStatus';
import Programs from './Components/Programs';
import AddProgramPage from './Components/AddProgramPage'; // Import AddProgramPage correctly
import NewItemForm from './Components/NewItemForm.tsx';
Expand All @@ -35,7 +35,7 @@ function App() {
<Route path="/about" element={<Home />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/resetpassword" element={<ResetPasswordPage />} />
<Route path="/item/:itemId" element={<StatusDisplayPage />} />
<Route path="/donatedItem/status/:id" element={<StatusUpdate />} />
<Route path="/donorform" element={<DonorForm />} />
<Route path="/donorlist" element={<DonorList />} />
<Route path="/donations" element={<DonatedItemsList />} />
Expand Down
205 changes: 205 additions & 0 deletions client-app/src/Components/AddNewStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import React, { useState, useEffect, ChangeEvent, FormEvent } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import ItemStatus from '../constants/Enums';
import '../css/DonorForm.css';

interface FormData {
statusType: string;
dateModified: string;
donatedItemId: string;
}

interface FormErrors {
[key: string]: string;
}

interface Option {
value: string;
label: string;
id?: number;
}

const AddNewStatus: React.FC = () => {
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const [formData, setFormData] = useState<FormData>({
statusType: ItemStatus.DONATED, // Initial status
dateModified: '',
donatedItemId: id || '',
});
const [errors, setErrors] = useState<FormErrors>({});
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);

useEffect(() => { // DOES NOT WORK. If time permits, this is trying to fetch the currentStatus of the item, then sets it to be the first thing displayed in the status box.
const fetchItemData = async () => {
try {
const response = await axios.get(
`${process.env.REACT_APP_BACKEND_API_BASE_URL}donatedItem/${id}`
);
const data: FormData = response.data;

setFormData({
statusType: data.statusType || ItemStatus.DONATED, // Supposed to set the initial display to be the currentStatus
dateModified: '',
donatedItemId: id || '',
});
} catch (error: any) {
setErrorMessage(
error.response?.data?.message || 'Error fetching item data'
);
}
};

if (id) {
fetchItemData();
}
}, [id]); // End of disfunctional code. Good luck if you are trying to get this working!

const handleChange = async (e: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prevState => ({
...prevState,
[name]: value,
}));
setErrors(prevState => ({ ...prevState, [name]: '' }));
setErrorMessage(null);
setSuccessMessage(null);
};

const validateField = (name: string, value: any) => {
if (!value || value.length === 0) {
return `${name.replace(/([A-Z])/g, ' $1')} is required`;
}
return '';
};

const validateForm = (): boolean => {
const newErrors: FormErrors = {};
Object.keys(formData).forEach(field => {
const error = validateField(field, (formData as any)[field]);
if (error) newErrors[field] = error;
});
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};

const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (validateForm()) {
try {
const formDataToSubmit = new FormData();
formDataToSubmit.append('statusType', formData.statusType);
formDataToSubmit.append('dateModified', formData.dateModified);
formDataToSubmit.append('donatedItemId', formData.donatedItemId);

const response = await axios.post(
`${process.env.REACT_APP_BACKEND_API_BASE_URL}donatedItem/status/${id}`,
formDataToSubmit,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}
);

if (response.status === 200) {
setSuccessMessage('Item updated successfully!');
handleRefresh();
navigate(`/donations/${id}`);
} else {
setErrorMessage('Failed to update item');
}
} catch (error: any) {
setErrorMessage(
error.response?.data?.message || 'Error updating item'
);
}
} else {
setErrorMessage('Form has validation errors');
}
};


const handleRefresh = () => {
setFormData({
statusType: 'Received',
dateModified: '',
donatedItemId: '',
});
setErrors({});
setErrorMessage(null);
setSuccessMessage(null);
};

const renderFormField = (
label: string,
name: keyof FormData,
type = 'text',
required = true,
options?: Option[]
) => (
<div className="form-field">
<label htmlFor={name} className="block text-sm font-semibold mb-1">
{label}
{required && <span className="text-red-500">&nbsp;*</span>}
</label>
{options ? (
<select
id={name}
name={name}
value={formData[name] as string}
onChange={handleChange}
className={`w-full px-3 py-2 rounded border ${
errors[name] ? 'border-red-500' : 'border-gray-300'
}`}
>
{options.map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
) : (
<input
type={type}
id={name}
name={name}
value={formData[name] as string}
onChange={handleChange}
className={`w-full px-3 py-2 rounded border ${
errors[name] ? 'border-red-500' : 'border-gray-300'
}`}
/>
)}
{errors[name] && <p className="text-red-500 text-sm mt-1">{errors[name]}</p>}
</div>
);

return (
<div className="donor-form outer-container mx-auto p-10">
<h1 className="text-2xl font-bold heading-centered">Add New Status</h1>
{errorMessage && <p className="error-message">{errorMessage}</p>}
{successMessage && <p className="success-message">{successMessage}</p>}
<form onSubmit={handleSubmit} className="form-grid">
{renderFormField('Current Status', 'statusType', 'text', true, [
{ value: ItemStatus.DONATED, label: 'Donated' },
{ value: ItemStatus.IN_STORAGE, label: 'In storage facility' },
{ value: ItemStatus.REFURBISHED, label: 'Refurbished' },
{ value: ItemStatus.SOLD, label: 'Item sold' },
{ value: ItemStatus.RECEIVED, label: 'Received' },
])}
{renderFormField('Date Updated', 'dateModified', 'date')}

<div className="form-field full-width button-container">
<button type="submit" className="submit-button">Update</button>
<button type="button" onClick={handleRefresh} className="refresh-button">Refresh</button>
</div>
</form>
</div>
);
};

export default AddNewStatus;
9 changes: 9 additions & 0 deletions client-app/src/Components/DonatedItemDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import PersonIcon from '@mui/icons-material/Person';
Expand All @@ -16,6 +17,11 @@ const DonatedItemDetails: React.FC = () => {
const [donatedItem, setDonatedItem] = useState<DonatedItem | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string>('');
const navigate = useNavigate();

const handleAddNewDonationClick = (): void => {
navigate(`/donatedItem/status/${id}`);
};

useEffect(() => {
const fetchDonatedItemDetails = async () => {
Expand Down Expand Up @@ -87,6 +93,9 @@ const DonatedItemDetails: React.FC = () => {
<div className="section-header">
<AssignmentTurnedInIcon className="icon" />
<h2>Donated Item Status</h2>
<button onClick={handleAddNewDonationClick}>
Add New Status
</button>
</div>
truffer11 marked this conversation as resolved.
Show resolved Hide resolved
{donatedItem.statuses.map(status => (
<div>
Expand Down
1 change: 1 addition & 0 deletions client-app/src/Components/DonatedItemsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ const DonatedItemsList: React.FC = () => {
const handleAddNewDonationClick = (): void => {
navigate('/adddonation');
};

const downloadBarcode = (id: number) => {
const barcodeElement = document.getElementById(`barcode-${id}`);
if (barcodeElement) {
Expand Down
Loading
Loading