From 1b7c53b810b90e1fe6921cc17209882c57bdcf28 Mon Sep 17 00:00:00 2001 From: Krao Hasanee Date: Wed, 13 May 2026 11:35:42 -0400 Subject: [PATCH] Add dedicated New Project page for clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route /new-project: name + company selector → creates project, redirects to project detail. My Projects buttons now link there instead of new-request. Co-Authored-By: Claude Sonnet 4.6 --- src/App.jsx | 70 ++++++++++++++------ src/pages/client/MyProjects.jsx | 6 +- src/pages/client/NewProject.jsx | 109 ++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 24 deletions(-) create mode 100644 src/pages/client/NewProject.jsx diff --git a/src/App.jsx b/src/App.jsx index 0857c7a..046c32d 100755 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,34 +1,48 @@ +import { lazy, Suspense } from 'react'; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; import { AuthProvider } from './context/AuthContext'; import ProtectedRoute from './components/ProtectedRoute'; +import PageLoader from './components/PageLoader'; import Login from './pages/Login'; +import PayInvoice from './pages/PayInvoice'; -import Dashboard from './pages/team/Dashboard'; -import Companies from './pages/team/Companies'; -import CompanyDetail from './pages/team/CompanyDetail'; -import ProjectDetail from './pages/team/ProjectDetail'; -import TaskDetail from './pages/team/TaskDetail'; -import Requests from './pages/team/Requests'; -import Invoices from './pages/team/Invoices'; -import CreateInvoice from './pages/team/CreateInvoice'; -import InvoiceDetail from './pages/team/InvoiceDetail'; -import BrandBook from './pages/team/BrandBook'; - -import Settings from './pages/Settings'; -import ClientDashboard from './pages/client/ClientDashboard'; -import MyCompany from './pages/client/MyCompany'; -import MyRequests from './pages/client/MyRequests'; -import MyProjects from './pages/client/MyProjects'; -import MyProjectDetail from './pages/client/MyProjectDetail'; -import MyInvoices from './pages/client/MyInvoices'; -import RequestDetail from './pages/client/RequestDetail'; -import NewRequest from './pages/client/NewRequest'; +const Settings = lazy(() => import('./pages/Settings')); +const Dashboard = lazy(() => import('./pages/team/Dashboard')); +const Companies = lazy(() => import('./pages/team/Companies')); +const CompanyDetail = lazy(() => import('./pages/team/CompanyDetail')); +const ProjectDetail = lazy(() => import('./pages/team/ProjectDetail')); +const Requests = lazy(() => import('./pages/team/Requests')); +const Invoices = lazy(() => import('./pages/team/Invoices')); +const MeetingNotes = lazy(() => import('./pages/team/MeetingNotes')); +const TaskDetail = lazy(() => import('./pages/team/TaskDetail')); +const CreateInvoice = lazy(() => import('./pages/team/CreateInvoice')); +const CreateSubcontractorPO = lazy(() => import('./pages/team/CreateSubcontractorPO')); +const InvoiceDetail = lazy(() => import('./pages/team/InvoiceDetail')); +const SubcontractorPODetail = lazy(() => import('./pages/team/SubcontractorPODetail')); +const SurveyMaker = lazy(() => import('./pages/team/SurveyMaker')); +const BrandBook = lazy(() => import('./pages/team/BrandBook')); +const Converters = lazy(() => import('./pages/team/Converters')); +const ServerStatus = lazy(() => import('./pages/team/ServerStatus')); +const FileSharing = lazy(() => import('./pages/team/FileSharing')); +const FourgePasswords = lazy(() => import('./pages/team/FourgePasswords')); +const ExternalMyRequests = lazy(() => import('./pages/external/MyRequests')); +const MyPurchaseOrders = lazy(() => import('./pages/external/MyPurchaseOrders')); +const ClientDashboard = lazy(() => import('./pages/client/ClientDashboard')); +const MyCompany = lazy(() => import('./pages/client/MyCompany')); +const MyRequests = lazy(() => import('./pages/client/MyRequests')); +const MyProjects = lazy(() => import('./pages/client/MyProjects')); +const MyProjectDetail = lazy(() => import('./pages/client/MyProjectDetail')); +const MyInvoices = lazy(() => import('./pages/client/MyInvoices')); +const RequestDetail = lazy(() => import('./pages/client/RequestDetail')); +const NewRequest = lazy(() => import('./pages/client/NewRequest')); +const NewProject = lazy(() => import('./pages/client/NewProject')); export default function App() { return ( + }> } /> @@ -38,10 +52,21 @@ export default function App() { } /> } /> } /> + } /> } /> } /> + } /> } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> @@ -53,9 +78,12 @@ export default function App() { } /> } /> } /> + } /> + } /> } /> + ); diff --git a/src/pages/client/MyProjects.jsx b/src/pages/client/MyProjects.jsx index 6a8549f..29b9bbe 100755 --- a/src/pages/client/MyProjects.jsx +++ b/src/pages/client/MyProjects.jsx @@ -104,7 +104,7 @@ function ProjectGroup({ project, tasks, submissions, currentUserId, filter }) { )}
0 ? '1px solid var(--border)' : 'none' }}> + Add Request to {project.name} @@ -169,7 +169,7 @@ export default function MyProjects() {
Projects
All work for your company.
- + New Project + + New Project
@@ -199,7 +199,7 @@ export default function MyProjects() {

No projects yet

Submit a request and a project will be created automatically.

- + New Project + + New Project
) : ( projects.map(project => ( diff --git a/src/pages/client/NewProject.jsx b/src/pages/client/NewProject.jsx new file mode 100644 index 0000000..1d622d2 --- /dev/null +++ b/src/pages/client/NewProject.jsx @@ -0,0 +1,109 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import Layout from '../../components/Layout'; +import { supabase } from '../../lib/supabase'; +import { useAuth } from '../../context/AuthContext'; + +export default function NewProject() { + const { currentUser } = useAuth(); + const navigate = useNavigate(); + const companyOptions = currentUser.companies?.length + ? currentUser.companies + : (currentUser.company ? [currentUser.company] : []); + + const [selectedCompanyId, setSelectedCompanyId] = useState(companyOptions[0]?.id || ''); + const [name, setName] = useState(''); + const [saving, setSaving] = useState(false); + const [error, setError] = useState(null); + + if (!companyOptions.length) { + return ( + +
+

Account Not Yet Active

+

+ Your account hasn't been linked to a company yet. Please contact the Fourge team to get set up. +

+
+
+ ); + } + + const handleSubmit = async (e) => { + e.preventDefault(); + if (saving) return; + const trimmedName = name.trim(); + if (!trimmedName) return; + setSaving(true); + setError(null); + + const { data, error: insertError } = await supabase + .from('projects') + .insert({ company_id: selectedCompanyId, name: trimmedName }) + .select('id') + .single(); + + if (insertError) { + setError(insertError.message); + setSaving(false); + return; + } + + navigate(`/my-projects/${data.id}`); + }; + + return ( + +
+
+
New Project
+
Create a project to organise your work.
+
+
+ +
+
+ {companyOptions.length > 1 && ( +
+ + +
+ )} + +
+ + setName(e.target.value)} + autoFocus + required + /> +
+ + {error && ( +
+ {error} +
+ )} + +
+ + +
+
+
+
+ ); +}