From 3a58474996af9e98c58a291913894751c317170e Mon Sep 17 00:00:00 2001 From: Njeriiii Date: Mon, 3 Feb 2025 13:40:23 -0800 Subject: [PATCH 01/13] proposal builder initial setup --- Frontend/src/App.js | 2 + Frontend/src/components/Header.js | 1 + .../ProjectNarrativeSection.js | 331 ++++++++++++++++++ Frontend/src/pages/ProposalBuilderPage.js | 102 ++++++ 4 files changed, 436 insertions(+) create mode 100644 Frontend/src/components/ProposalBuilderComponents/ProjectNarrativeSection.js create mode 100644 Frontend/src/pages/ProposalBuilderPage.js diff --git a/Frontend/src/App.js b/Frontend/src/App.js index f22c474..f7b9fac 100644 --- a/Frontend/src/App.js +++ b/Frontend/src/App.js @@ -17,6 +17,7 @@ import VolunteerPage from './pages/VolunteerPage'; import SelectUserTypePage from './pages/SelectUserTypePage'; import EstablishmentGuide from './pages/EstablishmentGuide'; import EditProfile from './pages/EditProfilePage'; +import ProposalBuilderPage from './pages/ProposalBuilderPage'; function App() { @@ -43,6 +44,7 @@ function App() { } /> } /> + } /> diff --git a/Frontend/src/components/Header.js b/Frontend/src/components/Header.js index ce1be62..d36b6fc 100644 --- a/Frontend/src/components/Header.js +++ b/Frontend/src/components/Header.js @@ -15,6 +15,7 @@ const navigation = [ { name: "Home", href: "/" }, { name: "Find GOs", href: "/find-gos" }, { name: "Establishment Guide", href: "/establishment-guide" }, + { name: "Proposal Builder", href: "/proposal-builder" }, { name: "Volunteer", href: "/volunteer" }, { name: "About", href: "/about" }, ]; diff --git a/Frontend/src/components/ProposalBuilderComponents/ProjectNarrativeSection.js b/Frontend/src/components/ProposalBuilderComponents/ProjectNarrativeSection.js new file mode 100644 index 0000000..f490967 --- /dev/null +++ b/Frontend/src/components/ProposalBuilderComponents/ProjectNarrativeSection.js @@ -0,0 +1,331 @@ +import React, { useState, useEffect } from 'react'; +import { + DocumentTextIcon, + ArrowPathIcon, +} from '@heroicons/react/24/outline'; +import { useApi } from '../../contexts/ApiProvider'; + +/** + * ProjectNarrativeSection + * + * Collects project details and generates a comprehensive narrative section + * using AI assistance. Uses organization context to maintain consistency. + * + * Features: + * - Problem statement inputs + * - Solution/approach details + * - Goals and outcomes + * - Timeline information + * - Considers org context for cohesive narrative + */ +export default function ProjectNarrativeSection({ }) { + + const [generatedContent, setGeneratedContent] = useState(''); + const [isGenerating, setIsGenerating] = useState(false); + const [error, setError] = useState(null); + const { apiClient } = useApi(); + + const [inputs, setInputs] = useState({ + problem: { + statement: '', + affectedPopulation: '', + currentSituation: '', + relevance: '' + }, + solution: { + approach: '', + methodology: '', + innovation: '' + }, + impact: { + shortTerm: '', + longTerm: '', + beneficiaries: '', + measurement: '' + }, + timeline: { + duration: '', + majorPhases: '', + keyMilestones: '' + } + }); + + const sections = [ + { + title: 'Problem Statement', + stateKey: 'problem', + fields: [ + { + id: 'statement', + label: 'What specific problem are you addressing?', + placeholder: 'Describe the core issue your project tackles...', + type: 'textarea' + }, + { + id: 'affectedPopulation', + label: 'Who is affected by this problem?', + placeholder: 'Detail the communities or groups impacted...', + type: 'textarea' + }, + { + id: 'currentSituation', + label: 'What is the current situation?', + placeholder: 'Explain the existing conditions and challenges...', + type: 'textarea' + }, + { + id: 'relevance', + label: 'Why is addressing this important now?', + placeholder: 'Describe the urgency and significance...', + type: 'textarea' + } + ] + }, + { + title: 'Proposed Solution', + stateKey: 'solution', + fields: [ + { + id: 'approach', + label: 'What is your approach to solving this problem?', + placeholder: 'Outline your solution strategy...', + type: 'textarea' + }, + { + id: 'methodology', + label: 'How will you implement this solution?', + placeholder: 'Detail your implementation methods...', + type: 'textarea' + }, + { + id: 'innovation', + label: 'What makes your approach innovative or effective?', + placeholder: 'Highlight unique aspects of your solution...', + type: 'textarea' + } + ] + }, + { + title: 'Expected Impact', + stateKey: 'impact', + fields: [ + { + id: 'shortTerm', + label: 'What are the immediate outcomes?', + placeholder: 'List expected results in first year...', + type: 'textarea' + }, + { + id: 'longTerm', + label: 'What are the long-term impacts?', + placeholder: 'Describe lasting changes...', + type: 'textarea' + }, + { + id: 'beneficiaries', + label: 'Who will benefit and how?', + placeholder: 'Detail direct and indirect beneficiaries...', + type: 'textarea' + }, + { + id: 'measurement', + label: 'How will you measure success?', + placeholder: 'Outline key metrics and evaluation methods...', + type: 'textarea' + } + ] + }, + { + title: 'Timeline', + stateKey: 'timeline', + fields: [ + { + id: 'duration', + label: 'What is the project duration?', + placeholder: 'e.g., 18 months, 2 years...', + type: 'text' + }, + { + id: 'majorPhases', + label: 'What are the major project phases?', + placeholder: 'List main implementation phases...', + type: 'textarea' + }, + { + id: 'keyMilestones', + label: 'What are the key milestones?', + placeholder: 'List important project milestones...', + type: 'textarea' + } + ] + } + ]; + + const handleInputChange = (section, field, value) => { + setInputs(prev => ({ + ...prev, + [section]: { + ...prev[section], + [field]: value + } + })); + }; + + const handleGenerate = async () => { + setIsGenerating(true); + setError(null); + + console.log('inputs:', inputs); + + try { + // Get previous content for context + const orgContent = localStorage.getItem('organizationContent'); + + const prompt = `You are an expert grant writer. Using the provided information, create a compelling project narrative section for a grant proposal. + Make it professional, clear, and persuasive. + + Organization Context: + ${orgContent} + + Problem Information: + ${inputs.problem.statement} + Affected Population: ${inputs.problem.affectedPopulation} + Current Situation: ${inputs.problem.currentSituation} + Relevance: ${inputs.problem.relevance} + + Proposed Solution: + Approach: ${inputs.solution.approach} + Methodology: ${inputs.solution.methodology} + Innovation: ${inputs.solution.innovation} + + Expected Impact: + Short-term Outcomes: ${inputs.impact.shortTerm} + Long-term Impact: ${inputs.impact.longTerm} + Beneficiaries: ${inputs.impact.beneficiaries} + Success Metrics: ${inputs.impact.measurement} + + Timeline: + Duration: ${inputs.timeline.duration} + Major Phases: ${inputs.timeline.majorPhases} + Key Milestones: ${inputs.timeline.keyMilestones} + + Generate a cohesive project narrative that: + 1. Clearly states the problem and its significance + 2. Presents a compelling solution + 3. Details expected outcomes and impact + 4. Outlines a clear implementation timeline + 5. Maintains consistency with the organization's context + 6. Uses professional grant writing language and structure`; + + const response = await apiClient.post('/claude/generate', { + prompt, + section: 'narrative' + }); + + setGeneratedContent(response.content); + localStorage.setItem('projectNarrativeContent', response.content); + + } catch (error) { + console.error('Generation failed:', error); + setError('Failed to generate content. Please try again.'); + } finally { + setIsGenerating(false); + } + }; + + + return ( +
+

Project Narrative

+ + {/* Input Form */} +
+ {!generatedContent && sections.map((section) => ( +
+

+ {section.title} +

+
+ {section.fields.map((field) => ( +
+ + {field.type === 'textarea' ? ( +