commit b0cd20ced5827a6db85fdeb1b11b6d7d17fb679f Author: Aditya Pulipaka Date: Wed Mar 18 17:10:16 2026 -0500 initial diff --git a/App.tsx b/App.tsx new file mode 100644 index 0000000..f79e46c --- /dev/null +++ b/App.tsx @@ -0,0 +1,60 @@ +import { useState } from "react"; +import { Dashboard } from "./components/Dashboard"; +import { Inventory } from "./components/Inventory"; +import { ProtocolChecker } from "./components/ProtocolChecker"; +import { + LayoutDashboard, + Package, + FileCheck +} from "lucide-react"; +import logo from "figma:asset/e1cc93b8a3ca5c34482c2d8ace21b3610ba98443.png"; + +type Tab = "dashboard" | "inventory" | "protocol"; + +export default function App() { + const [activeTab, setActiveTab] = useState("dashboard"); + + const navItems = [ + { id: "dashboard" as Tab, label: "Dashboard", icon: LayoutDashboard }, + { id: "inventory" as Tab, label: "Inventory", icon: Package }, + { id: "protocol" as Tab, label: "Protocol Checker", icon: FileCheck }, + ]; + + return ( +
+ {/* Sidebar */} + + + {/* Main Content */} +
+ {activeTab === "dashboard" && } + {activeTab === "inventory" && } + {activeTab === "protocol" && } +
+
+ ); +} \ No newline at end of file diff --git a/Attributions.md b/Attributions.md new file mode 100644 index 0000000..9b7cd4e --- /dev/null +++ b/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/components/AIChat.tsx b/components/AIChat.tsx new file mode 100644 index 0000000..8f4710f --- /dev/null +++ b/components/AIChat.tsx @@ -0,0 +1,206 @@ +import { useState, useRef, useEffect } from "react"; +import { Card } from "./ui/card"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { Badge } from "./ui/badge"; +import { Send, Bot, User, Sparkles, FileText } from "lucide-react"; + +interface Message { + id: string; + role: "user" | "assistant"; + content: string; + timestamp: Date; +} + +export function AIChat() { + const [messages, setMessages] = useState([ + { + id: "1", + role: "assistant", + content: "Hello! I'm your Labwise AI assistant. I can help you with:\n\n• Chemical safety information\n• Protocol guidance\n• SDS lookups\n• EHS documentation questions\n• Emergency procedures\n\nWhat would you like to know?", + timestamp: new Date() + } + ]); + const [inputValue, setInputValue] = useState(""); + const [isTyping, setIsTyping] = useState(false); + const messagesEndRef = useRef(null); + + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + + useEffect(() => { + scrollToBottom(); + }, [messages, isTyping]); + + const mockResponses: { [key: string]: string } = { + "acetone": "Acetone (CAS 67-64-1) is a flammable liquid. Key safety considerations:\n\n• Store in flammables cabinet away from ignition sources\n• Use in well-ventilated areas or fume hood\n• Wear nitrile gloves and safety goggles\n• Keep away from oxidizing agents\n• Flash point: -20°C\n\nWould you like me to pull up the full SDS?", + "disposal": "For chemical waste disposal:\n\n1. Segregate waste by compatibility class\n2. Label all waste containers with contents and hazards\n3. Use proper waste containers (no food/beverage containers)\n4. Contact EHS for pickup when containers are 80% full\n5. Never pour chemicals down the drain unless specifically approved\n\nWhat type of waste are you disposing of?", + "ppe": "Personal Protective Equipment (PPE) requirements depend on the chemicals and procedures:\n\n**Minimum PPE:**\n• Safety glasses or goggles\n• Lab coat\n• Closed-toe shoes\n• Long pants\n\n**Additional PPE may include:**\n• Chemical-resistant gloves (nitrile, neoprene, etc.)\n• Face shield for splash hazards\n• Respirator for specific vapors\n\nWhat chemicals are you working with?", + "default": "I can help you with that! Based on your question, here are some key points:\n\n• Always refer to the Safety Data Sheet (SDS) for specific chemical hazards\n• Ensure proper PPE is worn at all times\n• Work in well-ventilated areas or fume hoods when handling volatile chemicals\n• Follow your lab's standard operating procedures\n\nWould you like more specific information about a particular chemical or procedure?" + }; + + const handleSend = () => { + if (!inputValue.trim()) return; + + const userMessage: Message = { + id: Date.now().toString(), + role: "user", + content: inputValue, + timestamp: new Date() + }; + + setMessages(prev => [...prev, userMessage]); + setInputValue(""); + setIsTyping(true); + + setTimeout(() => { + const lowercaseInput = inputValue.toLowerCase(); + let response = mockResponses.default; + + if (lowercaseInput.includes("acetone")) { + response = mockResponses.acetone; + } else if (lowercaseInput.includes("disposal") || lowercaseInput.includes("waste")) { + response = mockResponses.disposal; + } else if (lowercaseInput.includes("ppe") || lowercaseInput.includes("protective equipment")) { + response = mockResponses.ppe; + } + + const assistantMessage: Message = { + id: (Date.now() + 1).toString(), + role: "assistant", + content: response, + timestamp: new Date() + }; + + setMessages(prev => [...prev, assistantMessage]); + setIsTyping(false); + }, 1500); + }; + + const quickQuestions = [ + "What PPE do I need for handling acids?", + "How do I dispose of organic solvents?", + "What are the hazards of acetone?", + "Where can I find the SDS for benzene?" + ]; + + return ( +
+
+
+
+
+ +
+

AI Safety Assistant

+
+

Ask questions about chemical safety, protocols, and lab procedures

+
+ +
+ {/* Messages */} + +
+ {messages.map((message) => ( +
+
+ {message.role === "user" ? ( + + ) : ( + + )} +
+
+
+

{message.content}

+
+

+ {message.timestamp.toLocaleTimeString()} +

+
+
+ ))} + + {isTyping && ( +
+
+ +
+
+
+
+
+
+
+
+
+ )} +
+
+ + + {/* Quick Questions */} + {messages.length === 1 && ( +
+

Quick questions:

+
+ {quickQuestions.map((question, idx) => ( + + ))} +
+
+ )} + + {/* Input */} + +
+ setInputValue(e.target.value)} + onKeyPress={(e) => e.key === "Enter" && handleSend()} + className="flex-1" + /> + +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx new file mode 100644 index 0000000..21f9bb8 --- /dev/null +++ b/components/Dashboard.tsx @@ -0,0 +1,275 @@ +import { Card } from "./ui/card"; +import { Button } from "./ui/button"; +import { Badge } from "./ui/badge"; +import { + AlertTriangle, + CheckCircle2, + Clock, + TrendingUp, + Package, + FileCheck, + MessageSquare, + ArrowRight, + Bell, + Camera, + Activity +} from "lucide-react"; + +type Tab = "dashboard" | "inventory" | "protocol"; + +interface DashboardProps { + setActiveTab: (tab: Tab) => void; +} + +export function Dashboard({ setActiveTab }: DashboardProps) { + const stats = [ + { label: "Chemicals Tracked", value: "252", icon: Package, color: "text-[#5a9584]" }, + { label: "Low Stock (<20%)", value: "2", icon: AlertTriangle, color: "text-amber-600" }, + { label: "Expiring Soon", value: "3", icon: Clock, color: "text-red-600" }, + { label: "Protocols Reviewed", value: "12", icon: FileCheck, color: "text-[#2d5a4a]" }, + ]; + + const lowStockAlerts = [ + { chemical: "Sodium Hydroxide", location: "Cabinet B-1", percentFull: 15, lab: "Lab 305" }, + { chemical: "Ethanol", location: "Cabinet A-5", percentFull: 18, lab: "Lab 201" }, + ]; + + const expirationAlerts = [ + { chemical: "Hydrochloric Acid", location: "Acid Cabinet", daysLeft: -2, status: "expired", lab: "Lab 201" }, + { chemical: "Benzene", location: "Flammables Cabinet", daysLeft: 15, status: "expiring-soon", lab: "Lab 305" }, + { chemical: "Acetone", location: "Cabinet A-3", daysLeft: 28, status: "expiring-soon", lab: "Lab 201" }, + ]; + + const recentActivity = [ + { action: "Scanned and added Methanol via photo", time: "30 mins ago", type: "inventory" }, + { action: "Protocol safety review completed", time: "2 hours ago", type: "protocol" }, + { action: "Low stock alert: Sodium Hydroxide", time: "4 hours ago", type: "alert" }, + { action: "Expiration reminder sent for 3 chemicals", time: "1 day ago", type: "reminder" }, + ]; + + const alerts = [ + { message: "Hydrochloric Acid expired 2 days ago - requires disposal", severity: "critical" }, + { message: "Sodium Hydroxide below 20% full - reorder needed", severity: "warning" }, + { message: "3 chemicals expiring in next 30 days", severity: "warning" }, + ]; + + return ( +
+
+
+

Welcome to Labwise

+

Your AI-powered lab safety and compliance assistant

+
+ + {/* Stats Grid */} +
+ {stats.map((stat) => { + const Icon = stat.icon; + return ( + +
+
+

{stat.label}

+

{stat.value}

+
+ +
+
+ ); + })} +
+ + {/* Quick Actions */} +
+ +
+
+ +
+
+

AI Safety Assistant

+

Ask questions with sourced answers

+
+
+ +
+ + +
+
+ +
+
+

Check Protocol

+

Get AI safety feedback

+
+
+ +
+ + +
+
+ +
+
+

Scan Chemical

+

Photo capture with auto-fill

+
+
+ +
+
+ +
+ {/* Low Stock Alerts */} + +
+
+ +

Low Stock Alerts

+
+ +
+
+ {lowStockAlerts.map((alert, idx) => ( +
setActiveTab("inventory")} + > +
+

{alert.chemical}

+

{alert.lab} • {alert.location}

+
+ + {alert.percentFull}% full + +
+ ))} +
+
+ + {/* Expiration Alerts */} + +
+
+ +

Expiration Alerts

+
+ +
+
+ {expirationAlerts.map((alert, idx) => ( +
setActiveTab("inventory")} + > +
+
+
+

{alert.chemical}

+

{alert.lab} • {alert.location}

+
+
+ + + {alert.status === 'expired' + ? `Expired ${Math.abs(alert.daysLeft)}d ago` + : `${alert.daysLeft}d left`} + +
+ ))} +
+ +
+ +
+ {/* Recent Activity */} + +

Recent Activity

+
+ {recentActivity.map((activity, idx) => ( +
+ +
+

{activity.action}

+

{activity.time}

+
+
+ ))} +
+
+ + {/* Safety Alerts */} + +

Safety Alerts

+
+ {alerts.map((alert, idx) => ( +
+ +

{alert.message}

+
+ ))} +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/EHSDocumentation.tsx b/components/EHSDocumentation.tsx new file mode 100644 index 0000000..07c268c --- /dev/null +++ b/components/EHSDocumentation.tsx @@ -0,0 +1,287 @@ +import { useState } from "react"; +import { Card } from "./ui/card"; +import { Button } from "./ui/button"; +import { Input } from "./ui/input"; +import { Label } from "./ui/label"; +import { Textarea } from "./ui/textarea"; +import { Badge } from "./ui/badge"; +import { + FileText, + CheckCircle2, + Clock, + AlertCircle, + Plus, + Calendar +} from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "./ui/dialog"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "./ui/select"; + +interface Document { + id: string; + title: string; + type: string; + status: "complete" | "pending" | "overdue"; + dueDate: string; + lastModified: string; +} + +export function EHSDocumentation() { + const [selectedDoc, setSelectedDoc] = useState(null); + + const documents: Document[] = [ + { + id: "1", + title: "Quarterly Chemical Inventory Report", + type: "Inventory Report", + status: "complete", + dueDate: "2024-12-01", + lastModified: "2024-11-20" + }, + { + id: "2", + title: "Hazardous Waste Disposal Form", + type: "Waste Disposal", + status: "pending", + dueDate: "2024-11-30", + lastModified: "2024-11-22" + }, + { + id: "3", + title: "Lab Safety Inspection Checklist", + type: "Inspection", + status: "overdue", + dueDate: "2024-11-15", + lastModified: "2024-10-30" + }, + { + id: "4", + title: "Annual Training Documentation", + type: "Training", + status: "complete", + dueDate: "2024-09-30", + lastModified: "2024-09-28" + } + ]; + + const getStatusBadge = (status: string) => { + switch (status) { + case "complete": + return ( + + + Complete + + ); + case "pending": + return ( + + + Pending + + ); + case "overdue": + return ( + + + Overdue + + ); + default: + return null; + } + }; + + return ( +
+
+
+
+

EHS Documentation

+

Manage and track your Environmental Health & Safety documentation

+
+ + + + + + + Create EHS Document + + AI-assisted form filling using your inventory history + + +
+
+ + +
+ +
+ + +
+ +
+
+ +
+

AI Assistant Ready

+

+ I can auto-fill this form using data from your inventory history, recent chemical usage, and previous documentation. +

+
+
+
+ +
+ +