From 6742202ac5c61a29ccdc0bb968b9b394651283ad Mon Sep 17 00:00:00 2001 From: cordycepsers Date: Sun, 24 Aug 2025 21:42:38 +0200 Subject: [PATCH 01/10] feat(frontend): Implement frontend changes for proposal_master --- Frontend/README.md | 11 + Frontend/index.html | 15 + Frontend/package.json | 59 + Frontend/src/App.tsx | 78 + Frontend/src/Attributions.md | 3 + Frontend/src/components/DashboardChatbot.tsx | 156 + Frontend/src/components/DashboardSidebar.tsx | 66 + Frontend/src/components/LeadsSection.tsx | 209 + Frontend/src/components/MetricCard.tsx | 35 + Frontend/src/components/OverviewSection.tsx | 171 + Frontend/src/components/ProjectsSection.tsx | 154 + Frontend/src/components/RecentActivity.tsx | 84 + Frontend/src/components/ResearchSection.tsx | 177 + .../components/figma/ImageWithFallback.tsx | 27 + Frontend/src/components/ui/accordion.tsx | 66 + Frontend/src/components/ui/alert-dialog.tsx | 157 + Frontend/src/components/ui/alert.tsx | 66 + Frontend/src/components/ui/aspect-ratio.tsx | 11 + Frontend/src/components/ui/avatar.tsx | 53 + Frontend/src/components/ui/badge.tsx | 46 + Frontend/src/components/ui/breadcrumb.tsx | 109 + Frontend/src/components/ui/button.tsx | 58 + Frontend/src/components/ui/calendar.tsx | 75 + Frontend/src/components/ui/card.tsx | 92 + Frontend/src/components/ui/carousel.tsx | 241 + Frontend/src/components/ui/chart.tsx | 353 ++ Frontend/src/components/ui/checkbox.tsx | 32 + Frontend/src/components/ui/collapsible.tsx | 33 + Frontend/src/components/ui/command.tsx | 177 + Frontend/src/components/ui/context-menu.tsx | 252 + Frontend/src/components/ui/dialog.tsx | 135 + Frontend/src/components/ui/drawer.tsx | 132 + Frontend/src/components/ui/dropdown-menu.tsx | 257 + Frontend/src/components/ui/form.tsx | 168 + Frontend/src/components/ui/hover-card.tsx | 44 + Frontend/src/components/ui/input-otp.tsx | 77 + Frontend/src/components/ui/input.tsx | 21 + Frontend/src/components/ui/label.tsx | 24 + Frontend/src/components/ui/menubar.tsx | 276 + .../src/components/ui/navigation-menu.tsx | 168 + Frontend/src/components/ui/pagination.tsx | 127 + Frontend/src/components/ui/popover.tsx | 48 + Frontend/src/components/ui/progress.tsx | 31 + Frontend/src/components/ui/radio-group.tsx | 45 + Frontend/src/components/ui/resizable.tsx | 56 + Frontend/src/components/ui/scroll-area.tsx | 58 + Frontend/src/components/ui/select.tsx | 189 + Frontend/src/components/ui/separator.tsx | 28 + Frontend/src/components/ui/sheet.tsx | 139 + Frontend/src/components/ui/sidebar.tsx | 726 +++ Frontend/src/components/ui/skeleton.tsx | 13 + Frontend/src/components/ui/slider.tsx | 63 + Frontend/src/components/ui/sonner.tsx | 25 + Frontend/src/components/ui/switch.tsx | 31 + Frontend/src/components/ui/table.tsx | 116 + Frontend/src/components/ui/tabs.tsx | 66 + Frontend/src/components/ui/textarea.tsx | 18 + Frontend/src/components/ui/toggle-group.tsx | 73 + Frontend/src/components/ui/toggle.tsx | 47 + Frontend/src/components/ui/tooltip.tsx | 61 + Frontend/src/components/ui/use-mobile.ts | 21 + Frontend/src/components/ui/utils.ts | 6 + Frontend/src/guidelines/Guidelines.md | 61 + Frontend/src/index.css | 4872 +++++++++++++++++ Frontend/src/main.tsx | 7 + Frontend/src/styles/globals.css | 191 + Frontend/vite.config.ts | 60 + 67 files changed, 11546 insertions(+) create mode 100644 Frontend/README.md create mode 100644 Frontend/index.html create mode 100644 Frontend/package.json create mode 100644 Frontend/src/App.tsx create mode 100644 Frontend/src/Attributions.md create mode 100644 Frontend/src/components/DashboardChatbot.tsx create mode 100644 Frontend/src/components/DashboardSidebar.tsx create mode 100644 Frontend/src/components/LeadsSection.tsx create mode 100644 Frontend/src/components/MetricCard.tsx create mode 100644 Frontend/src/components/OverviewSection.tsx create mode 100644 Frontend/src/components/ProjectsSection.tsx create mode 100644 Frontend/src/components/RecentActivity.tsx create mode 100644 Frontend/src/components/ResearchSection.tsx create mode 100644 Frontend/src/components/figma/ImageWithFallback.tsx create mode 100644 Frontend/src/components/ui/accordion.tsx create mode 100644 Frontend/src/components/ui/alert-dialog.tsx create mode 100644 Frontend/src/components/ui/alert.tsx create mode 100644 Frontend/src/components/ui/aspect-ratio.tsx create mode 100644 Frontend/src/components/ui/avatar.tsx create mode 100644 Frontend/src/components/ui/badge.tsx create mode 100644 Frontend/src/components/ui/breadcrumb.tsx create mode 100644 Frontend/src/components/ui/button.tsx create mode 100644 Frontend/src/components/ui/calendar.tsx create mode 100644 Frontend/src/components/ui/card.tsx create mode 100644 Frontend/src/components/ui/carousel.tsx create mode 100644 Frontend/src/components/ui/chart.tsx create mode 100644 Frontend/src/components/ui/checkbox.tsx create mode 100644 Frontend/src/components/ui/collapsible.tsx create mode 100644 Frontend/src/components/ui/command.tsx create mode 100644 Frontend/src/components/ui/context-menu.tsx create mode 100644 Frontend/src/components/ui/dialog.tsx create mode 100644 Frontend/src/components/ui/drawer.tsx create mode 100644 Frontend/src/components/ui/dropdown-menu.tsx create mode 100644 Frontend/src/components/ui/form.tsx create mode 100644 Frontend/src/components/ui/hover-card.tsx create mode 100644 Frontend/src/components/ui/input-otp.tsx create mode 100644 Frontend/src/components/ui/input.tsx create mode 100644 Frontend/src/components/ui/label.tsx create mode 100644 Frontend/src/components/ui/menubar.tsx create mode 100644 Frontend/src/components/ui/navigation-menu.tsx create mode 100644 Frontend/src/components/ui/pagination.tsx create mode 100644 Frontend/src/components/ui/popover.tsx create mode 100644 Frontend/src/components/ui/progress.tsx create mode 100644 Frontend/src/components/ui/radio-group.tsx create mode 100644 Frontend/src/components/ui/resizable.tsx create mode 100644 Frontend/src/components/ui/scroll-area.tsx create mode 100644 Frontend/src/components/ui/select.tsx create mode 100644 Frontend/src/components/ui/separator.tsx create mode 100644 Frontend/src/components/ui/sheet.tsx create mode 100644 Frontend/src/components/ui/sidebar.tsx create mode 100644 Frontend/src/components/ui/skeleton.tsx create mode 100644 Frontend/src/components/ui/slider.tsx create mode 100644 Frontend/src/components/ui/sonner.tsx create mode 100644 Frontend/src/components/ui/switch.tsx create mode 100644 Frontend/src/components/ui/table.tsx create mode 100644 Frontend/src/components/ui/tabs.tsx create mode 100644 Frontend/src/components/ui/textarea.tsx create mode 100644 Frontend/src/components/ui/toggle-group.tsx create mode 100644 Frontend/src/components/ui/toggle.tsx create mode 100644 Frontend/src/components/ui/tooltip.tsx create mode 100644 Frontend/src/components/ui/use-mobile.ts create mode 100644 Frontend/src/components/ui/utils.ts create mode 100644 Frontend/src/guidelines/Guidelines.md create mode 100644 Frontend/src/index.css create mode 100644 Frontend/src/main.tsx create mode 100644 Frontend/src/styles/globals.css create mode 100644 Frontend/vite.config.ts diff --git a/Frontend/README.md b/Frontend/README.md new file mode 100644 index 0000000..1c8c9b0 --- /dev/null +++ b/Frontend/README.md @@ -0,0 +1,11 @@ + + # Data Dashboard Application + + This is a code bundle for Data Dashboard Application. The original project is available at https://www.figma.com/design/WM7vJl1EE8XVXMm7oAz0uk/Data-Dashboard-Application. + + ## Running the code + + Run `npm i` to install the dependencies. + + Run `npm run dev` to start the development server. + \ No newline at end of file diff --git a/Frontend/index.html b/Frontend/index.html new file mode 100644 index 0000000..c228cb5 --- /dev/null +++ b/Frontend/index.html @@ -0,0 +1,15 @@ + + + + + + + Data Dashboard Application + + + +
+ + + + \ No newline at end of file diff --git a/Frontend/package.json b/Frontend/package.json new file mode 100644 index 0000000..d29e600 --- /dev/null +++ b/Frontend/package.json @@ -0,0 +1,59 @@ + + { + "name": "Data Dashboard Application", + "version": "0.1.0", + "private": true, + "dependencies": { + "@radix-ui/react-accordion": "^1.2.3", + "@radix-ui/react-alert-dialog": "^1.1.6", + "@radix-ui/react-aspect-ratio": "^1.1.2", + "@radix-ui/react-avatar": "^1.1.3", + "@radix-ui/react-checkbox": "^1.1.4", + "@radix-ui/react-collapsible": "^1.1.3", + "@radix-ui/react-context-menu": "^2.2.6", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-hover-card": "^1.1.6", + "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-menubar": "^1.1.6", + "@radix-ui/react-navigation-menu": "^1.2.5", + "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-radio-group": "^1.2.3", + "@radix-ui/react-scroll-area": "^1.2.3", + "@radix-ui/react-select": "^2.1.6", + "@radix-ui/react-separator": "^1.1.2", + "@radix-ui/react-slider": "^1.2.3", + "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-switch": "^1.1.3", + "@radix-ui/react-tabs": "^1.1.3", + "@radix-ui/react-toggle": "^1.1.2", + "@radix-ui/react-toggle-group": "^1.1.2", + "@radix-ui/react-tooltip": "^1.1.8", + "class-variance-authority": "^0.7.1", + "clsx": "*", + "cmdk": "^1.1.1", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", + "lucide-react": "^0.487.0", + "next-themes": "^0.4.6", + "react": "^18.3.1", + "react-day-picker": "^8.10.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.55.0", + "react-resizable-panels": "^2.1.7", + "recharts": "^2.15.2", + "sonner": "^2.0.3", + "tailwind-merge": "*", + "vaul": "^1.1.2" + }, + "devDependencies": { + "@types/node": "^20.10.0", + "@vitejs/plugin-react-swc": "^3.10.2", + "vite": "^5.4.19" + }, + "scripts": { + "dev": "vite", + "build": "vite build" + } + } \ No newline at end of file diff --git a/Frontend/src/App.tsx b/Frontend/src/App.tsx new file mode 100644 index 0000000..476765e --- /dev/null +++ b/Frontend/src/App.tsx @@ -0,0 +1,78 @@ +import { useState } from 'react' +import { DashboardSidebar } from './components/DashboardSidebar' +import { OverviewSection } from './components/OverviewSection' +import { ProjectsSection } from './components/ProjectsSection' +import { LeadsSection } from './components/LeadsSection' +import { ResearchSection } from './components/ResearchSection' + +export default function App() { + const [activeSection, setActiveSection] = useState('overview') + + const renderSection = () => { + switch (activeSection) { + case 'overview': + return + case 'projects': + return + case 'leads': + return + case 'research': + return + default: + return + } + } + + const getSectionTitle = () => { + switch (activeSection) { + case 'overview': + return 'Dashboard Overview' + case 'projects': + return 'Project Management' + case 'leads': + return 'Lead Management' + case 'research': + return 'Market Research' + default: + return 'Dashboard Overview' + } + } + + const getSectionDescription = () => { + switch (activeSection) { + case 'overview': + return 'Get a comprehensive view of your business performance and key metrics' + case 'projects': + return 'Track and manage all your active projects in one place' + case 'leads': + return 'Monitor your sales pipeline and lead conversion rates' + case 'research': + return 'Analyze market trends and identify growth opportunities' + default: + return 'Get a comprehensive view of your business performance and key metrics' + } + } + + return ( +
+ + +
+
+
+

+ {getSectionTitle()} +

+

+ {getSectionDescription()} +

+
+
+ +
+ {renderSection()} +
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/Attributions.md b/Frontend/src/Attributions.md new file mode 100644 index 0000000..9b7cd4e --- /dev/null +++ b/Frontend/src/Attributions.md @@ -0,0 +1,3 @@ +This Figma Make file includes components from [shadcn/ui](https://ui.shadcn.com/) used under [MIT license](https://github.com/shadcn-ui/ui/blob/main/LICENSE.md). + +This Figma Make file includes photos from [Unsplash](https://unsplash.com) used under [license](https://unsplash.com/license). \ No newline at end of file diff --git a/Frontend/src/components/DashboardChatbot.tsx b/Frontend/src/components/DashboardChatbot.tsx new file mode 100644 index 0000000..f05463b --- /dev/null +++ b/Frontend/src/components/DashboardChatbot.tsx @@ -0,0 +1,156 @@ +import { useState } from 'react' +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { Button } from "./ui/button" +import { Input } from "./ui/input" +import { ScrollArea } from "./ui/scroll-area" +import { Badge } from "./ui/badge" +import { Send, Bot, User, Sparkles } from "lucide-react" + +interface Message { + id: number + type: 'user' | 'bot' + content: string + timestamp: Date +} + +const suggestedQuestions = [ + "Best performing project?", + "Lead conversion trends?", + "Top marketing channel?", + "Growth opportunities?" +] + +const botResponses: { [key: string]: string } = { + "best performing project": "The E-commerce Platform project for Retail Co is performing excellently with 95% completion and a $65,000 budget. It's on track for early delivery.", + "lead conversion trends": "Your conversion rate is 24.8% this month, down 2% from last month. However, lead quality has improved with more qualified prospects in the pipeline.", + "top marketing channel": "Website leads are your top performer at 35% of total leads, followed by referrals at 25%. Consider investing more in SEO and content marketing.", + "growth opportunities": "AI Integration Services show the highest opportunity score (85/100). The market demand for AI-powered solutions is growing rapidly across industries." +} + +export function DashboardChatbot() { + const [messages, setMessages] = useState([ + { + id: 1, + type: 'bot', + content: "Hello! I'm your AI business assistant. I can help analyze your dashboard data and provide actionable insights. What would you like to know?", + timestamp: new Date() + } + ]) + const [inputValue, setInputValue] = useState('') + + const handleSendMessage = (content: string) => { + if (!content.trim()) return + + const userMessage: Message = { + id: Date.now(), + type: 'user', + content, + timestamp: new Date() + } + + setMessages(prev => [...prev, userMessage]) + + setTimeout(() => { + const normalizedInput = content.toLowerCase() + let response = "I'm analyzing your dashboard data to provide the best insights. Based on your current metrics, I can help you understand performance trends and identify opportunities for growth." + + for (const [key, value] of Object.entries(botResponses)) { + if (normalizedInput.includes(key.toLowerCase())) { + response = value + break + } + } + + const botMessage: Message = { + id: Date.now() + 1, + type: 'bot', + content: response, + timestamp: new Date() + } + + setMessages(prev => [...prev, botMessage]) + }, 1000) + + setInputValue('') + } + + const handleSuggestedQuestion = (question: string) => { + handleSendMessage(question) + } + + return ( + + + +
+ +
+
+
AI Assistant
+
Ask about your business data
+
+
+
+ + +
+ {messages.map((message) => ( +
+
+
+ {message.type === 'bot' ? : } +
+
+

{message.content}

+
+
+
+ ))} +
+
+ +
+
+ {suggestedQuestions.map((question, index) => ( + handleSuggestedQuestion(question)} + > + {question} + + ))} +
+ +
+ setInputValue(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && handleSendMessage(inputValue)} + className="flex-1 bg-input-background border-border/50 focus:border-primary/50" + /> + +
+
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/DashboardSidebar.tsx b/Frontend/src/components/DashboardSidebar.tsx new file mode 100644 index 0000000..bf6d4bb --- /dev/null +++ b/Frontend/src/components/DashboardSidebar.tsx @@ -0,0 +1,66 @@ +import { BarChart3, Users, TrendingUp, Home } from "lucide-react" +import { Button } from "./ui/button" + +interface DashboardSidebarProps { + activeSection: string + onSectionChange: (section: string) => void +} + +export function DashboardSidebar({ activeSection, onSectionChange }: DashboardSidebarProps) { + const navItems = [ + { id: 'overview', label: 'Overview', icon: Home }, + { id: 'projects', label: 'Projects', icon: BarChart3 }, + { id: 'leads', label: 'Leads', icon: Users }, + { id: 'research', label: 'Research', icon: TrendingUp }, + ] + + return ( +
+
+
+

+ Business Intelligence +

+

+ Get real-time insights, seamless transactions, and advanced tools to manage your business effectively +

+
+ + + +
+

Need Help?

+

+ Our support team is here to assist you with any questions. +

+ +
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/LeadsSection.tsx b/Frontend/src/components/LeadsSection.tsx new file mode 100644 index 0000000..a6b12a0 --- /dev/null +++ b/Frontend/src/components/LeadsSection.tsx @@ -0,0 +1,209 @@ +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table" +import { Badge } from "./ui/badge" +import { MetricCard } from "./MetricCard" +import { Users, UserPlus, UserCheck, UserX } from "lucide-react" +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts' + +const leads = [ + { + id: 1, + name: "Sarah Johnson", + company: "TechStart Inc", + email: "sarah@techstart.com", + phone: "+1 (555) 123-4567", + status: "Hot", + source: "Website", + value: "$50,000", + lastContact: "2024-01-05" + }, + { + id: 2, + name: "Mike Chen", + company: "Growth Co", + email: "mike@growthco.com", + phone: "+1 (555) 987-6543", + status: "Warm", + source: "Referral", + value: "$25,000", + lastContact: "2024-01-03" + }, + { + id: 3, + name: "Emily Davis", + company: "Creative Agency", + email: "emily@creative.com", + phone: "+1 (555) 456-7890", + status: "Cold", + source: "Social Media", + value: "$15,000", + lastContact: "2023-12-28" + }, + { + id: 4, + name: "David Wilson", + company: "Enterprise Ltd", + email: "david@enterprise.com", + phone: "+1 (555) 321-0987", + status: "Hot", + source: "Email", + value: "$75,000", + lastContact: "2024-01-06" + }, + { + id: 5, + name: "Lisa Thompson", + company: "Startup Hub", + email: "lisa@startuphub.com", + phone: "+1 (555) 654-3210", + status: "Qualified", + source: "Website", + value: "$30,000", + lastContact: "2024-01-04" + } +] + +const leadsByMonth = [ + { month: 'Aug', new: 23, qualified: 12, converted: 5 }, + { month: 'Sep', new: 31, qualified: 18, converted: 8 }, + { month: 'Oct', new: 28, qualified: 15, converted: 6 }, + { month: 'Nov', new: 35, qualified: 21, converted: 9 }, + { month: 'Dec', new: 42, qualified: 25, converted: 11 }, + { month: 'Jan', new: 38, qualified: 23, converted: 10 }, +] + +const getStatusBadge = (status: string) => { + const variants = { + 'Hot': 'bg-red-100 text-red-800', + 'Warm': 'bg-orange-100 text-orange-800', + 'Cold': 'bg-blue-100 text-blue-800', + 'Qualified': 'bg-green-100 text-green-800' + } + + return {status} +} + +export function LeadsSection() { + const totalLeads = leads.length + const hotLeads = leads.filter(l => l.status === 'Hot').length + const qualifiedLeads = leads.filter(l => l.status === 'Qualified').length + const totalValue = leads.reduce((sum, lead) => sum + parseInt(lead.value.replace(/[$,]/g, '')), 0) + + return ( +
+
+ + + + +
+ +
+ + + Lead Pipeline + + + + + + + + + + + + + + + + + + + Recent Leads + + + + + + Name + Status + Value + + + + {leads.slice(0, 5).map((lead) => ( + + +
+
{lead.name}
+
{lead.company}
+
+
+ {getStatusBadge(lead.status)} + {lead.value} +
+ ))} +
+
+
+
+
+ + + + All Leads + + + + + + Name + Company + Contact + Status + Source + Value + Last Contact + + + + {leads.map((lead) => ( + + {lead.name} + {lead.company} + +
+
{lead.email}
+
{lead.phone}
+
+
+ {getStatusBadge(lead.status)} + {lead.source} + {lead.value} + {lead.lastContact} +
+ ))} +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/MetricCard.tsx b/Frontend/src/components/MetricCard.tsx new file mode 100644 index 0000000..7688abf --- /dev/null +++ b/Frontend/src/components/MetricCard.tsx @@ -0,0 +1,35 @@ +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { LucideIcon } from "lucide-react" + +interface MetricCardProps { + title: string + value: string + change?: string + changeType?: 'positive' | 'negative' | 'neutral' + icon: LucideIcon +} + +export function MetricCard({ title, value, change, changeType = 'neutral', icon: Icon }: MetricCardProps) { + const changeColor = { + positive: 'text-green-600', + negative: 'text-red-600', + neutral: 'text-muted-foreground' + }[changeType] + + return ( + + + {title} + + + +
{value}
+ {change && ( +

+ {change} +

+ )} +
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/OverviewSection.tsx b/Frontend/src/components/OverviewSection.tsx new file mode 100644 index 0000000..00d584a --- /dev/null +++ b/Frontend/src/components/OverviewSection.tsx @@ -0,0 +1,171 @@ +import { MetricCard } from "./MetricCard" +import { DashboardChatbot } from "./DashboardChatbot" +import { RecentActivity } from "./RecentActivity" +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line, PieChart, Pie, Cell } from 'recharts' +import { FolderOpen, Users, TrendingUp, DollarSign } from "lucide-react" + +const monthlyData = [ + { month: 'Jan', projects: 12, leads: 45, revenue: 85000 }, + { month: 'Feb', projects: 15, leads: 52, revenue: 92000 }, + { month: 'Mar', projects: 18, leads: 38, revenue: 78000 }, + { month: 'Apr', projects: 22, leads: 61, revenue: 105000 }, + { month: 'May', projects: 25, leads: 73, revenue: 118000 }, + { month: 'Jun', projects: 28, leads: 69, revenue: 112000 }, +] + +const leadsBySource = [ + { name: 'Website', value: 35, color: '#7a8f63' }, + { name: 'Referrals', value: 25, color: '#9bb380' }, + { name: 'Social Media', value: 20, color: '#5a6b47' }, + { name: 'Email', value: 15, color: '#b8c9a3' }, + { name: 'Other', value: 5, color: '#6d7f5a' }, +] + +export function OverviewSection() { + return ( +
+
+ + + + +
+ +
+ + + Monthly Trends +

Projects and leads performance over time

+
+ + + + + + + + + + + + +
+ + + + Lead Sources +

Distribution of incoming leads by channel

+
+ + + + `${name} ${(percent * 100).toFixed(0)}%`} + outerRadius={100} + fill="#8884d8" + dataKey="value" + stroke="var(--color-background)" + strokeWidth={2} + > + {leadsBySource.map((entry, index) => ( + + ))} + + + + + +
+
+ +
+ + + Revenue Trend +

Last 4 months performance

+
+ + + + + + + [`$${value.toLocaleString()}`, 'Revenue']} + contentStyle={{ + backgroundColor: 'var(--color-card)', + border: '1px solid var(--color-border)', + borderRadius: '8px', + boxShadow: '0 4px 12px rgba(0,0,0,0.1)' + }} + /> + + + + +
+ + + + +
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/ProjectsSection.tsx b/Frontend/src/components/ProjectsSection.tsx new file mode 100644 index 0000000..afb6d62 --- /dev/null +++ b/Frontend/src/components/ProjectsSection.tsx @@ -0,0 +1,154 @@ +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table" +import { Badge } from "./ui/badge" +import { Progress } from "./ui/progress" +import { MetricCard } from "./MetricCard" +import { FolderOpen, Clock, CheckCircle, AlertCircle } from "lucide-react" + +const projects = [ + { + id: 1, + name: "Website Redesign", + client: "Tech Corp", + status: "In Progress", + priority: "High", + progress: 75, + dueDate: "2024-02-15", + budget: "$25,000" + }, + { + id: 2, + name: "Mobile App Development", + client: "StartupXYZ", + status: "Planning", + priority: "Medium", + progress: 25, + dueDate: "2024-03-30", + budget: "$45,000" + }, + { + id: 3, + name: "Brand Identity", + client: "Fashion Brand", + status: "In Progress", + priority: "Low", + progress: 90, + dueDate: "2024-01-20", + budget: "$8,000" + }, + { + id: 4, + name: "E-commerce Platform", + client: "Retail Co", + status: "Review", + priority: "High", + progress: 95, + dueDate: "2024-01-10", + budget: "$65,000" + }, + { + id: 5, + name: "Marketing Campaign", + client: "Local Business", + status: "In Progress", + priority: "Medium", + progress: 60, + dueDate: "2024-02-28", + budget: "$12,000" + } +] + +const getStatusBadge = (status: string) => { + const variants = { + 'In Progress': 'default', + 'Planning': 'secondary', + 'Review': 'outline', + 'Completed': 'default' + } as const + + return {status} +} + +const getPriorityBadge = (priority: string) => { + const colors = { + 'High': 'bg-red-100 text-red-800', + 'Medium': 'bg-yellow-100 text-yellow-800', + 'Low': 'bg-green-100 text-green-800' + } + + return {priority} +} + +export function ProjectsSection() { + const totalProjects = projects.length + const inProgressProjects = projects.filter(p => p.status === 'In Progress').length + const completedProjects = projects.filter(p => p.progress === 100).length + const overdueProjects = projects.filter(p => new Date(p.dueDate) < new Date()).length + + return ( +
+
+ + + + +
+ + + + Open Projects + + + + + + Project Name + Client + Status + Priority + Progress + Due Date + Budget + + + + {projects.map((project) => ( + + {project.name} + {project.client} + {getStatusBadge(project.status)} + {getPriorityBadge(project.priority)} + +
+ + {project.progress}% +
+
+ {project.dueDate} + {project.budget} +
+ ))} +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/RecentActivity.tsx b/Frontend/src/components/RecentActivity.tsx new file mode 100644 index 0000000..e1e424d --- /dev/null +++ b/Frontend/src/components/RecentActivity.tsx @@ -0,0 +1,84 @@ +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { Badge } from "./ui/badge" +import { Avatar, AvatarFallback } from "./ui/avatar" +import { Clock, CheckCircle, AlertCircle, UserPlus } from "lucide-react" + +const activities = [ + { + id: 1, + type: 'project_update', + message: 'Brand Identity project completed', + user: 'Sarah Johnson', + time: '2 hours ago', + icon: CheckCircle, + iconColor: 'text-green-600' + }, + { + id: 2, + type: 'new_lead', + message: 'New hot lead from TechStart Inc', + user: 'Mike Chen', + time: '4 hours ago', + icon: UserPlus, + iconColor: 'text-blue-600' + }, + { + id: 3, + type: 'deadline', + message: 'E-commerce Platform due in 2 days', + user: 'System', + time: '6 hours ago', + icon: AlertCircle, + iconColor: 'text-orange-600' + }, + { + id: 4, + type: 'project_start', + message: 'Website Redesign entered review phase', + user: 'Emily Davis', + time: '1 day ago', + icon: Clock, + iconColor: 'text-gray-600' + }, + { + id: 5, + type: 'lead_converted', + message: 'Lead converted to project - $30,000', + user: 'David Wilson', + time: '1 day ago', + icon: CheckCircle, + iconColor: 'text-green-600' + } +] + +export function RecentActivity() { + return ( + + + Recent Activity + + +
+ {activities.map((activity) => { + const Icon = activity.icon + return ( +
+
+ +
+
+

{activity.message}

+
+ {activity.user} + + {activity.time} +
+
+
+ ) + })} +
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/ResearchSection.tsx b/Frontend/src/components/ResearchSection.tsx new file mode 100644 index 0000000..6554037 --- /dev/null +++ b/Frontend/src/components/ResearchSection.tsx @@ -0,0 +1,177 @@ +import { Card, CardContent, CardHeader, CardTitle } from "./ui/card" +import { MetricCard } from "./MetricCard" +import { TrendingUp, TrendingDown, Target, Globe } from "lucide-react" +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area, BarChart, Bar } from 'recharts' + +const marketTrends = [ + { month: 'Jul', webDev: 85, mobileApp: 92, branding: 78, ecommerce: 88 }, + { month: 'Aug', webDev: 88, mobileApp: 89, branding: 82, ecommerce: 91 }, + { month: 'Sep', webDev: 92, mobileApp: 95, branding: 85, ecommerce: 89 }, + { month: 'Oct', webDev: 89, mobileApp: 98, branding: 88, ecommerce: 93 }, + { month: 'Nov', webDev: 95, mobileApp: 94, branding: 91, ecommerce: 96 }, + { month: 'Dec', webDev: 98, mobileApp: 97, branding: 94, ecommerce: 99 }, +] + +const competitorData = [ + { name: 'Our Company', marketShare: 15, growth: 12 }, + { name: 'Competitor A', marketShare: 22, growth: 8 }, + { name: 'Competitor B', marketShare: 18, growth: 15 }, + { name: 'Competitor C', marketShare: 12, growth: -3 }, + { name: 'Others', marketShare: 33, growth: 5 }, +] + +const industryInsights = [ + { + title: "Web Development Demand", + trend: "up", + value: "+18%", + description: "Increased demand for responsive web applications" + }, + { + title: "Mobile App Projects", + trend: "up", + value: "+25%", + description: "Growing mobile-first approach across industries" + }, + { + title: "Traditional Marketing", + trend: "down", + value: "-12%", + description: "Shift towards digital marketing strategies" + }, + { + title: "E-commerce Solutions", + trend: "up", + value: "+30%", + description: "Surge in online retail platform development" + } +] + +export function ResearchSection() { + return ( +
+
+ + + + +
+ +
+ + + Service Demand Trends + + + + + + + + + + + + + + + + + + + + Competitive Landscape + + + + + + + + + + + + + +
+ +
+ + + Industry Insights + + +
+ {industryInsights.map((insight, index) => ( +
+
+ {insight.trend === 'up' ? ( + + ) : ( + + )} +
+

{insight.title}

+

{insight.description}

+
+
+
+ {insight.value} +
+
+ ))} +
+
+
+ + + + Growth Opportunities + + +
+
+

AI Integration Services

+

High demand for AI-powered solutions across industries

+
Opportunity Score: 85/100
+
+
+

Sustainable Tech Solutions

+

Growing focus on environmentally conscious technology

+
Opportunity Score: 78/100
+
+
+

Remote Work Tools

+

Continued demand for remote collaboration platforms

+
Opportunity Score: 72/100
+
+
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/Frontend/src/components/figma/ImageWithFallback.tsx b/Frontend/src/components/figma/ImageWithFallback.tsx new file mode 100644 index 0000000..0e26139 --- /dev/null +++ b/Frontend/src/components/figma/ImageWithFallback.tsx @@ -0,0 +1,27 @@ +import React, { useState } from 'react' + +const ERROR_IMG_SRC = + 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg==' + +export function ImageWithFallback(props: React.ImgHTMLAttributes) { + const [didError, setDidError] = useState(false) + + const handleError = () => { + setDidError(true) + } + + const { src, alt, style, className, ...rest } = props + + return didError ? ( +
+
+ Error loading image +
+
+ ) : ( + {alt} + ) +} diff --git a/Frontend/src/components/ui/accordion.tsx b/Frontend/src/components/ui/accordion.tsx new file mode 100644 index 0000000..aa2c37b --- /dev/null +++ b/Frontend/src/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +"use client"; + +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion@1.2.3"; +import { ChevronDownIcon } from "lucide-react@0.487.0"; + +import { cn } from "./utils"; + +function Accordion({ + ...props +}: React.ComponentProps) { + return ; +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className, + )} + {...props} + > + {children} + + + + ); +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ); +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/Frontend/src/components/ui/alert-dialog.tsx b/Frontend/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..68f3605 --- /dev/null +++ b/Frontend/src/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +"use client"; + +import * as React from "react"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog@1.1.6"; + +import { cn } from "./utils"; +import { buttonVariants } from "./button"; + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return ; +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ); +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/Frontend/src/components/ui/alert.tsx b/Frontend/src/components/ui/alert.tsx new file mode 100644 index 0000000..856b94d --- /dev/null +++ b/Frontend/src/components/ui/alert.tsx @@ -0,0 +1,66 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority@0.7.1"; + +import { cn } from "./utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Alert, AlertTitle, AlertDescription }; diff --git a/Frontend/src/components/ui/aspect-ratio.tsx b/Frontend/src/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..2a2f462 --- /dev/null +++ b/Frontend/src/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +"use client"; + +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio@1.1.2"; + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return ; +} + +export { AspectRatio }; diff --git a/Frontend/src/components/ui/avatar.tsx b/Frontend/src/components/ui/avatar.tsx new file mode 100644 index 0000000..589b166 --- /dev/null +++ b/Frontend/src/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client"; + +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar@1.1.3"; + +import { cn } from "./utils"; + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/Frontend/src/components/ui/badge.tsx b/Frontend/src/components/ui/badge.tsx new file mode 100644 index 0000000..3f8eff8 --- /dev/null +++ b/Frontend/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot@1.1.2"; +import { cva, type VariantProps } from "class-variance-authority@0.7.1"; + +import { cn } from "./utils"; + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/Frontend/src/components/ui/breadcrumb.tsx b/Frontend/src/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..d2adf98 --- /dev/null +++ b/Frontend/src/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot@1.1.2"; +import { ChevronRight, MoreHorizontal } from "lucide-react@0.487.0"; + +import { cn } from "./utils"; + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return