Spaces:
Configuration error
Configuration error
| import { useState, useEffect } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Input } from "@/components/ui/input"; | |
| import { Label } from "@/components/ui/label"; | |
| import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { User, Phone, Lock, Shield, Leaf, Users } from "lucide-react"; | |
| import { useToast } from "@/hooks/use-toast"; | |
| import { userStorage, type UserProfile } from "@/lib/userStorage"; | |
| import logoImage from "@assets/ChatGPT Image Jun 6, 2025, 02_19_36 PM.png"; | |
| interface AuthProps { | |
| onLogin: (user: UserProfile) => void; | |
| isOpen: boolean; | |
| } | |
| export default function UserAuth({ onLogin, isOpen }: AuthProps) { | |
| const [isLoginMode, setIsLoginMode] = useState(true); | |
| const [name, setName] = useState(""); | |
| const [phone, setPhone] = useState(""); | |
| const [organization, setOrganization] = useState(""); | |
| const [role, setRole] = useState<UserProfile['role']>('engineer'); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const [recentUsers, setRecentUsers] = useState<UserProfile[]>([]); | |
| const { toast } = useToast(); | |
| useEffect(() => { | |
| loadRecentUsers(); | |
| }, []); | |
| const loadRecentUsers = async () => { | |
| try { | |
| const users = await userStorage.getRecentUsers(); | |
| setRecentUsers(users.slice(0, 3)); // Show last 3 users | |
| } catch (error) { | |
| console.warn('Could not load recent users:', error); | |
| } | |
| }; | |
| const validatePhone = (phoneNumber: string): boolean => { | |
| return userStorage.validatePhoneNumber(phoneNumber); | |
| }; | |
| const handleLogin = async () => { | |
| if (!phone.trim()) { | |
| toast({ | |
| title: "फोन नंबर आवश्यक / Phone Required", | |
| description: "कृपया अपना फोन नंबर दर्ज करें / Please enter your phone number", | |
| variant: "destructive" | |
| }); | |
| return; | |
| } | |
| if (!validatePhone(phone)) { | |
| toast({ | |
| title: "अमान्य फोन नंबर / Invalid Phone", | |
| description: "कृपया 10 अंकों का वैध फोन नंबर दर्ज करें / Please enter a valid 10-digit phone number", | |
| variant: "destructive" | |
| }); | |
| return; | |
| } | |
| setIsLoading(true); | |
| try { | |
| // Check if user exists | |
| let user = await userStorage.getUserByPhone(phone); | |
| if (user && isLoginMode) { | |
| // Existing user login | |
| const session = userStorage.createSession(user); | |
| toast({ | |
| title: `स्वागत है ${user.name} / Welcome ${user.name}`, | |
| description: "सफलतापूर्वक लॉग इन हो गए / Successfully logged in" | |
| }); | |
| onLogin(session.user); | |
| } else if (!user && !isLoginMode) { | |
| // New user registration | |
| if (!name.trim()) { | |
| toast({ | |
| title: "नाम आवश्यक / Name Required", | |
| description: "कृपया अपना नाम दर्ज करें / Please enter your name", | |
| variant: "destructive" | |
| }); | |
| setIsLoading(false); | |
| return; | |
| } | |
| const newUser = await userStorage.createUser({ | |
| name: name.trim(), | |
| phone: phone.trim(), | |
| organization: organization.trim() || undefined, | |
| role, | |
| }); | |
| const session = userStorage.createSession(newUser); | |
| toast({ | |
| title: `खाता बनाया गया / Account Created`, | |
| description: `स्वागत है ${newUser.name} / Welcome ${newUser.name}` | |
| }); | |
| onLogin(session.user); | |
| } else if (user && !isLoginMode) { | |
| // User exists but trying to register | |
| toast({ | |
| title: "उपयोगकर्ता मौजूद है / User Exists", | |
| description: "यह फोन नंबर पहले से पंजीकृत है / This phone number is already registered", | |
| variant: "destructive" | |
| }); | |
| } else { | |
| // User doesn't exist but trying to login | |
| toast({ | |
| title: "उपयोगकर्ता नहीं मिला / User Not Found", | |
| description: "कृपया पहले खाता बनाएं / Please create an account first", | |
| variant: "destructive" | |
| }); | |
| } | |
| } catch (error) { | |
| toast({ | |
| title: "त्रुटि / Error", | |
| description: error instanceof Error ? error.message : "कृपया पुनः प्रयास करें / Please try again", | |
| variant: "destructive" | |
| }); | |
| } | |
| setIsLoading(false); | |
| }; | |
| const handleQuickLogin = (user: UserProfile) => { | |
| const session = userStorage.createSession(user); | |
| onLogin(session.user); | |
| }; | |
| const getRoleDisplay = (role: UserProfile['role']) => { | |
| const roleMap = { | |
| engineer: "इंजीनियर / Engineer", | |
| student: "छात्र / Student", | |
| researcher: "शोधकर्ता / Researcher", | |
| government: "सरकारी / Government", | |
| farmer: "किसान / Farmer", | |
| consultant: "सलाहकार / Consultant" | |
| }; | |
| return roleMap[role]; | |
| }; | |
| const getRoleIcon = (role: UserProfile['role']) => { | |
| const icons = { | |
| engineer: <Shield className="w-4 h-4" />, | |
| student: <User className="w-4 h-4" />, | |
| researcher: <Leaf className="w-4 h-4" />, | |
| government: <Shield className="w-4 h-4" />, | |
| farmer: <Leaf className="w-4 h-4" />, | |
| consultant: <Users className="w-4 h-4" /> | |
| }; | |
| return icons[role]; | |
| }; | |
| return ( | |
| <Dialog open={isOpen}> | |
| <DialogContent className="max-w-md"> | |
| <DialogHeader> | |
| <div className="text-center"> | |
| <img | |
| src={logoImage} | |
| alt="Prithvi Guardian AI Logo" | |
| className="w-20 h-20 mx-auto mb-3 rounded-full shadow-md" | |
| /> | |
| <DialogTitle className="text-xl font-bold text-green-800 mb-2"> | |
| Prithvi Guardian Ai | |
| </DialogTitle> | |
| </div> | |
| <DialogDescription className="text-center"> | |
| पर्यावरण और सिविल इंजीनियरिंग के लिए ऑफलाइन ऐप | |
| <br /> | |
| Offline Environmental & Civil Engineering App | |
| </DialogDescription> | |
| </DialogHeader> | |
| <CardContent className="space-y-4"> | |
| {/* Recent Users Quick Login */} | |
| {recentUsers.length > 0 && ( | |
| <div className="space-y-2"> | |
| <Label className="text-sm font-medium">त्वरित लॉगिन / Quick Login</Label> | |
| <div className="space-y-2"> | |
| {recentUsers.map((user) => ( | |
| <Card | |
| key={user.id} | |
| className="p-3 cursor-pointer hover:bg-gray-50 transition-colors" | |
| onClick={() => handleQuickLogin(user)} | |
| > | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center space-x-2"> | |
| {getRoleIcon(user.role)} | |
| <div> | |
| <p className="font-medium text-sm">{user.name}</p> | |
| <p className="text-xs text-gray-500">{user.phone}</p> | |
| </div> | |
| </div> | |
| <Badge variant="secondary" className="text-xs"> | |
| {getRoleDisplay(user.role).split(' / ')[0]} | |
| </Badge> | |
| </div> | |
| </Card> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| {/* Login/Register Toggle */} | |
| <div className="flex space-x-2"> | |
| <Button | |
| variant={isLoginMode ? "default" : "outline"} | |
| onClick={() => setIsLoginMode(true)} | |
| className="flex-1" | |
| > | |
| लॉग इन / Login | |
| </Button> | |
| <Button | |
| variant={!isLoginMode ? "default" : "outline"} | |
| onClick={() => setIsLoginMode(false)} | |
| className="flex-1" | |
| > | |
| नया खाता / Register | |
| </Button> | |
| </div> | |
| {/* Phone Number Input */} | |
| <div className="space-y-2"> | |
| <Label htmlFor="phone"> | |
| <Phone className="w-4 h-4 inline mr-2" /> | |
| फोन नंबर / Phone Number * | |
| </Label> | |
| <Input | |
| id="phone" | |
| type="tel" | |
| placeholder="9876543210" | |
| value={phone} | |
| onChange={(e) => setPhone(e.target.value)} | |
| maxLength={10} | |
| /> | |
| </div> | |
| {/* Name Input (Registration only) */} | |
| {!isLoginMode && ( | |
| <div className="space-y-2"> | |
| <Label htmlFor="name"> | |
| <User className="w-4 h-4 inline mr-2" /> | |
| नाम / Name * | |
| </Label> | |
| <Input | |
| id="name" | |
| type="text" | |
| placeholder="आपका नाम / Your Name" | |
| value={name} | |
| onChange={(e) => setName(e.target.value)} | |
| /> | |
| </div> | |
| )} | |
| {/* Organization Input (Registration only) */} | |
| {!isLoginMode && ( | |
| <div className="space-y-2"> | |
| <Label htmlFor="organization"> | |
| संस्था / Organization (Optional) | |
| </Label> | |
| <Input | |
| id="organization" | |
| type="text" | |
| placeholder="कंपनी/कॉलेज का नाम / Company/College Name" | |
| value={organization} | |
| onChange={(e) => setOrganization(e.target.value)} | |
| /> | |
| </div> | |
| )} | |
| {/* Role Selection (Registration only) */} | |
| {!isLoginMode && ( | |
| <div className="space-y-2"> | |
| <Label>भूमिका / Role</Label> | |
| <div className="grid grid-cols-2 gap-2"> | |
| {[ | |
| { key: 'engineer' as const, label: 'इंजीनियर' }, | |
| { key: 'student' as const, label: 'छात्र' }, | |
| { key: 'researcher' as const, label: 'शोधकर्ता' }, | |
| { key: 'government' as const, label: 'सरकारी' }, | |
| { key: 'farmer' as const, label: 'किसान' }, | |
| { key: 'consultant' as const, label: 'सलाहकार' } | |
| ].map(({ key, label }) => ( | |
| <Button | |
| key={key} | |
| variant={role === key ? "default" : "outline"} | |
| onClick={() => setRole(key)} | |
| className="text-xs py-1" | |
| > | |
| {label} | |
| </Button> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| {/* Submit Button */} | |
| <Button | |
| onClick={handleLogin} | |
| disabled={isLoading} | |
| className="w-full bg-green-600 hover:bg-green-700" | |
| > | |
| {isLoading ? ( | |
| "प्रसंस्करण... / Processing..." | |
| ) : isLoginMode ? ( | |
| "लॉग इन करें / Login" | |
| ) : ( | |
| "खाता बनाएं / Create Account" | |
| )} | |
| </Button> | |
| {/* Offline Notice */} | |
| <div className="text-xs text-center text-gray-500 mt-4"> | |
| <Lock className="w-3 h-3 inline mr-1" /> | |
| पूर्ण ऑफलाइन - कोई डेटा साझा नहीं | |
| <br /> | |
| Completely Offline - No Data Shared | |
| </div> | |
| </CardContent> | |
| </DialogContent> | |
| </Dialog> | |
| ); | |
| } |