feat: Implement user tracking in projects

- Added user tracking features to the projects module, including:
  - Database schema updates to track project creator and assignee.
  - API enhancements for user management and project filtering by user.
  - UI components for user assignment in project forms and listings.
  - New query functions for retrieving users and filtering projects.
  - Security integration with role-based access and authentication requirements.

chore: Create utility scripts for database checks and project testing

- Added scripts to check the structure of the projects table.
- Created tests for project creation and user tracking functionality.
- Implemented API tests to verify project retrieval and user assignment.

fix: Update project creation and update functions to include user tracking

- Modified createProject and updateProject functions to handle user IDs for creator and assignee.
- Ensured that project updates reflect the correct user assignments and timestamps.
This commit is contained in:
Chop
2025-06-25 23:08:15 +02:00
parent 81afa09f3a
commit 294d8343d3
19 changed files with 790 additions and 35 deletions

View File

@@ -22,22 +22,59 @@ export default function ProjectForm({ initialData = null }) {
contact: "",
notes: "",
coordinates: "",
project_type: initialData?.project_type || "design",
// project_status is not included in the form for creation or editing
...initialData,
project_type: "design",
assigned_to: "",
});
const [contracts, setContracts] = useState([]);
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const router = useRouter();
const isEdit = !!initialData;
useEffect(() => {
// Fetch contracts
fetch("/api/contracts")
.then((res) => res.json())
.then(setContracts);
// Fetch users for assignment
fetch("/api/projects/users")
.then((res) => res.json())
.then(setUsers);
}, []);
// Update form state when initialData changes (for edit mode)
useEffect(() => {
if (initialData) {
setForm({
contract_id: "",
project_name: "",
address: "",
plot: "",
district: "",
unit: "",
city: "",
investment_number: "",
finish_date: "",
wp: "",
contact: "",
notes: "",
coordinates: "",
project_type: "design",
assigned_to: "",
...initialData,
// Ensure these defaults are preserved if not in initialData
project_type: initialData.project_type || "design",
assigned_to: initialData.assigned_to || "",
// Format finish_date for input if it exists
finish_date: initialData.finish_date
? formatDateForInput(initialData.finish_date)
: "",
});
}
}, [initialData]);
function handleChange(e) {
setForm({ ...form, [e.target.name]: e.target.value });
}
@@ -83,7 +120,7 @@ export default function ProjectForm({ initialData = null }) {
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
{/* Contract and Project Type Section */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Contract <span className="text-red-500">*</span>
@@ -125,6 +162,25 @@ export default function ProjectForm({ initialData = null }) {
</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Assigned To
</label>
<select
name="assigned_to"
value={form.assigned_to || ""}
onChange={handleChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
>
<option value="">Unassigned</option>
{users.map((user) => (
<option key={user.id} value={user.id}>
{user.name} ({user.email})
</option>
))}
</select>
</div>
</div>
{/* Basic Information Section */}