diff --git a/package.json b/package.json index af44072..2c460eb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "my-app", "version": "0.1.0", - "homepage": "/react/", + "homepage": "/", "private": true, "dependencies": { "@ckeditor/ckeditor5-build-classic": "^41.2.0", diff --git a/src/feature-module/projects/createproject.jsx b/src/feature-module/projects/createproject.jsx index fa00dcf..c79c4b1 100644 --- a/src/feature-module/projects/createproject.jsx +++ b/src/feature-module/projects/createproject.jsx @@ -1,14 +1,15 @@ -import React, { useState } from 'react'; -import { Link } from 'react-router-dom'; -import { DatePicker, Select, Input } from 'antd'; +import React, { useState, useEffect } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { DatePicker, Select, Input, message } from 'antd'; import { ArrowLeft, Calendar, Users, DollarSign, Target, - Clock, - FileText + FileText, + CheckCircle, + TrendingUp } from 'feather-icons-react'; import { LoadingButton } from '../../components/Loading'; import dayjs from 'dayjs'; @@ -17,24 +18,114 @@ const { Option } = Select; const { TextArea } = Input; const CreateProject = () => { + const navigate = useNavigate(); const [loading, setLoading] = useState(false); + const [categoriesLoading, setCategoriesLoading] = useState(true); + const [usersLoading, setUsersLoading] = useState(true); + const [formData, setFormData] = useState({ projectName: '', description: '', - category: '', + clientName: '', + categoryId: '', priority: 'medium', status: 'planning', startDate: dayjs(), endDate: dayjs().add(1, 'month'), budget: '', - client: '', - manager: [], + progressPercentage: 0, + managers: [], teamMembers: [], - tags: [], - attachments: [] + tags: [] }); const [errors, setErrors] = useState({}); + const [categories, setCategories] = useState([]); + const [users, setUsers] = useState([]); + + // Load categories from API + const loadCategories = async () => { + try { + const apiBaseUrl = process.env.REACT_APP_API_BASE_URL || ''; + const response = await fetch(`${apiBaseUrl}ProjectCategories`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + }); + + if (response.ok) { + const result = await response.json(); + setCategories(result.data || []); + } else { + console.error('Failed to load categories'); + // Fallback to sample data + setCategories([ + { id: 1, name: 'Web Development', color: 'blue' }, + { id: 2, name: 'Mobile App', color: 'green' }, + { id: 3, name: 'Design', color: 'purple' }, + { id: 4, name: 'Marketing', color: 'orange' } + ]); + } + } catch (error) { + console.error('Error loading categories:', error); + // Fallback to sample data + setCategories([ + { id: 1, name: 'Web Development', color: 'blue' }, + { id: 2, name: 'Mobile App', color: 'green' }, + { id: 3, name: 'Design', color: 'purple' }, + { id: 4, name: 'Marketing', color: 'orange' } + ]); + } finally { + setCategoriesLoading(false); + } + }; + + // Load users from API + const loadUsers = async () => { + try { + const apiBaseUrl = process.env.REACT_APP_API_BASE_URL || ''; + const response = await fetch(`${apiBaseUrl}Users`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + } + }); + + if (response.ok) { + const result = await response.json(); + setUsers(result.data || []); + } else { + console.error('Failed to load users'); + // Fallback to sample data + setUsers([ + { id: 1, fullName: 'John Smith', email: 'john@example.com' }, + { id: 2, fullName: 'Sarah Johnson', email: 'sarah@example.com' }, + { id: 3, fullName: 'Mike Wilson', email: 'mike@example.com' }, + { id: 4, fullName: 'Lisa Chen', email: 'lisa@example.com' } + ]); + } + } catch (error) { + console.error('Error loading users:', error); + // Fallback to sample data + setUsers([ + { id: 1, fullName: 'John Smith', email: 'john@example.com' }, + { id: 2, fullName: 'Sarah Johnson', email: 'sarah@example.com' }, + { id: 3, fullName: 'Mike Wilson', email: 'mike@example.com' }, + { id: 4, fullName: 'Lisa Chen', email: 'lisa@example.com' } + ]); + } finally { + setUsersLoading(false); + } + }; + + // Load data on component mount + useEffect(() => { + loadCategories(); + loadUsers(); + }, []); // Avatar component with initials fallback const UserAvatar = ({ initials, name }) => ( @@ -59,30 +150,17 @@ const CreateProject = () => { ); - // Sample data - const categories = [ - { value: 'web-development', label: 'Web Development', color: 'blue' }, - { value: 'mobile-app', label: 'Mobile App', color: 'green' }, - { value: 'design', label: 'Design', color: 'purple' }, - { value: 'marketing', label: 'Marketing', color: 'orange' }, - { value: 'devops', label: 'DevOps', color: 'cyan' }, - { value: 'data-science', label: 'Data Science', color: 'red' } - ]; + // Generate initials from name + const getInitials = (name) => { + return name + .split(' ') + .map(word => word.charAt(0)) + .join('') + .toUpperCase() + .substring(0, 2); + }; - const managers = [ - { value: 'john-smith', label: 'John Smith', initials: 'JS' }, - { value: 'sarah-johnson', label: 'Sarah Johnson', initials: 'SJ' }, - { value: 'mike-wilson', label: 'Mike Wilson', initials: 'MW' }, - { value: 'lisa-chen', label: 'Lisa Chen', initials: 'LC' } - ]; - const teamMembers = [ - { value: 'alex-rodriguez', label: 'Alex Rodriguez', initials: 'AR' }, - { value: 'maria-garcia', label: 'Maria Garcia', initials: 'MG' }, - { value: 'david-brown', label: 'David Brown', initials: 'DB' }, - { value: 'emma-davis', label: 'Emma Davis', initials: 'ED' }, - { value: 'james-miller', label: 'James Miller', initials: 'JM' } - ]; const handleInputChange = (field, value) => { setFormData(prev => ({ @@ -110,20 +188,22 @@ const CreateProject = () => { newErrors.description = 'Project description is required'; } - if (!formData.category) { - newErrors.category = 'Please select a category'; + if (!formData.categoryId) { + newErrors.categoryId = 'Please select a category'; } - if (!formData.client.trim()) { - newErrors.client = 'Client name is required'; + if (!formData.clientName.trim()) { + newErrors.clientName = 'Client name is required'; } if (!formData.budget.trim()) { newErrors.budget = 'Budget is required'; + } else if (isNaN(parseFloat(formData.budget))) { + newErrors.budget = 'Budget must be a valid number'; } - if (formData.manager.length === 0) { - newErrors.manager = 'Please assign at least one manager'; + if (formData.progressPercentage < 0 || formData.progressPercentage > 100) { + newErrors.progressPercentage = 'Progress must be between 0 and 100'; } if (dayjs(formData.endDate).isBefore(dayjs(formData.startDate))) { @@ -136,25 +216,61 @@ const CreateProject = () => { const handleSubmit = async (e) => { e.preventDefault(); - + if (!validateForm()) { return; } setLoading(true); - + try { - // Simulate API call - await new Promise(resolve => setTimeout(resolve, 2000)); - - console.log('Project created:', formData); - - // Reset form or redirect - alert('Project created successfully!'); - + const apiBaseUrl = process.env.REACT_APP_API_BASE_URL || ''; + + // Prepare data for API - Simple format + const projectData = { + projectName: formData.projectName, + description: formData.description, + clientName: formData.clientName, + categoryId: parseInt(formData.categoryId), + priority: formData.priority, + status: formData.status, + startDate: formData.startDate.format('YYYY-MM-DD'), + endDate: formData.endDate.format('YYYY-MM-DD'), + budget: parseFloat(formData.budget), + progressPercentage: parseInt(formData.progressPercentage) + }; + + console.log('Sending project data:', projectData); + + const response = await fetch(`${apiBaseUrl}Projects`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(projectData) + }); + + if (response.ok) { + const result = await response.json(); + console.log('Project created successfully:', result); + + message.success('Project created successfully!'); + + // Redirect to project list + setTimeout(() => { + navigate('/project-tracker'); + }, 1500); + + } else { + const errorData = await response.json(); + console.error('API Error:', errorData); + message.error(errorData.message || 'Failed to create project. Please try again.'); + } + } catch (error) { console.error('Error creating project:', error); - alert('Error creating project. Please try again.'); + message.error('Network error. Please check your connection and try again.'); } finally { setLoading(false); } @@ -215,12 +331,12 @@ const CreateProject = () => { handleInputChange('client', e.target.value)} + className={`form-control ${errors.clientName ? 'is-invalid' : ''}`} + value={formData.clientName} + onChange={(e) => handleInputChange('clientName', e.target.value)} placeholder="Enter client name" /> - {errors.client &&