Instructions to use CaseLoop/rights-navigator with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use CaseLoop/rights-navigator with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSeq2SeqLM tokenizer = AutoTokenizer.from_pretrained("CaseLoop/rights-navigator") model = AutoModelForSeq2SeqLM.from_pretrained("CaseLoop/rights-navigator", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download Frontend/src/components/Header.tsx from CaseLoop/rights-navigator: direct link, hf CLI and curl.
- Browser
- Download file 17.4 kB
-
https://huggingface.co/CaseLoop/rights-navigator/resolve/main/Frontend/src/components/Header.tsx
- Command line
-
hf download hf://CaseLoop/rights-navigator/Frontend/src/components/Header.tsx
-
curl -L -o Header.tsx https://huggingface.co/CaseLoop/rights-navigator/resolve/main/Frontend/src/components/Header.tsx
17.4 kB
| import React, { useState, useEffect, useRef } from 'react'; | |
| import { useAuth } from '../context/AuthContext'; | |
| import { AuthModal } from './AuthModal'; | |
| interface HeaderProps { | |
| currentView: 'home' | 'workspace' | 'my-filings'; | |
| onNavigate: (view: 'home' | 'workspace' | 'my-filings') => void; | |
| selectedCity: string; | |
| onSelectCity: (city: string) => void; | |
| unreadNotifications?: number; | |
| filingsCount?: number; | |
| } | |
| export const CITIES = [ | |
| 'Delhi (NCR)', | |
| 'Bengaluru', | |
| 'Mumbai', | |
| 'Chennai', | |
| 'Hyderabad', | |
| 'Kolkata', | |
| 'Pune', | |
| 'Ahmedabad', | |
| 'Jaipur', | |
| 'Chandigarh', | |
| ]; | |
| export const Header: React.FC<HeaderProps> = ({ | |
| currentView, | |
| onNavigate, | |
| selectedCity, | |
| onSelectCity, | |
| unreadNotifications = 2, | |
| filingsCount = 0, | |
| }) => { | |
| const { user, loading, signOut, sendVerificationEmail, reloadUser } = useAuth(); | |
| const [showCityMenu, setShowCityMenu] = useState(false); | |
| const [showNotificationMenu, setShowNotificationMenu] = useState(false); | |
| const [showProfileMenu, setShowProfileMenu] = useState(false); | |
| const [showAuthModal, setShowAuthModal] = useState(false); | |
| const [authWorking, setAuthWorking] = useState(false); | |
| const [verifSent, setVerifSent] = useState(false); | |
| const [verifError, setVerifError] = useState<string | null>(null); | |
| const cityMenuRef = useRef<HTMLDivElement>(null); | |
| const notificationMenuRef = useRef<HTMLDivElement>(null); | |
| const profileMenuRef = useRef<HTMLDivElement>(null); | |
| const handleSendVerification = async () => { | |
| setVerifError(null); | |
| setVerifSent(false); | |
| try { | |
| await sendVerificationEmail(); | |
| setVerifSent(true); | |
| setTimeout(() => setVerifSent(false), 5000); | |
| } catch (err: any) { | |
| setVerifError(err?.message || 'Could not send verification email.'); | |
| } | |
| }; | |
| const handleCheckVerification = async () => { | |
| try { | |
| await reloadUser(); | |
| } catch (err) { | |
| console.warn('Could not reload user status:', err); | |
| } | |
| }; | |
| useEffect(() => { | |
| const handleClickOutside = (event: MouseEvent) => { | |
| const target = event.target as Node; | |
| if (cityMenuRef.current && !cityMenuRef.current.contains(target)) { | |
| setShowCityMenu(false); | |
| } | |
| if (notificationMenuRef.current && !notificationMenuRef.current.contains(target)) { | |
| setShowNotificationMenu(false); | |
| } | |
| if (profileMenuRef.current && !profileMenuRef.current.contains(target)) { | |
| setShowProfileMenu(false); | |
| } | |
| }; | |
| const handleKeyDown = (event: KeyboardEvent) => { | |
| if (event.key === 'Escape') { | |
| setShowCityMenu(false); | |
| setShowNotificationMenu(false); | |
| setShowProfileMenu(false); | |
| } | |
| }; | |
| document.addEventListener('mousedown', handleClickOutside); | |
| window.addEventListener('keydown', handleKeyDown); | |
| return () => { | |
| document.removeEventListener('mousedown', handleClickOutside); | |
| window.removeEventListener('keydown', handleKeyDown); | |
| }; | |
| }, []); | |
| const handleSignOut = async () => { | |
| setAuthWorking(true); | |
| try { | |
| await signOut(); | |
| setShowProfileMenu(false); | |
| } catch (err) { | |
| console.error('Sign-out error:', err); | |
| } finally { | |
| setAuthWorking(false); | |
| } | |
| }; | |
| return ( | |
| <> | |
| <header className="bg-white/95 backdrop-blur-md border-b border-[#E2E8F0] sticky top-0 z-50 transition-all duration-200"> | |
| <div className="flex justify-between items-center w-full px-4 sm:px-8 md:px-10 max-w-[1280px] mx-auto h-16"> | |
| {/* Brand & City Selector */} | |
| <div className="flex items-center gap-4"> | |
| <button | |
| onClick={() => onNavigate('home')} | |
| className="font-headline text-[22px] font-bold text-[#0F172A] flex items-center gap-2 tracking-tight group text-left cursor-pointer" | |
| > | |
| <span className="material-symbols-outlined fill text-[#006c4a] text-[26px] group-hover:rotate-[-6deg] transition-transform duration-200"> | |
| gavel | |
| </span> | |
| <span>CaseLoop</span> | |
| </button> | |
| <div className="hidden md:flex items-center gap-2"> | |
| <div ref={cityMenuRef} className="relative"> | |
| <button | |
| onClick={() => setShowCityMenu(!showCityMenu)} | |
| className="flex items-center gap-1.5 px-2.5 py-1 bg-[#F1F5F9] hover:bg-[#E2E8F0] text-[#475569] hover:text-[#0F172A] rounded-full border border-[#CBD5E1] text-[12px] font-medium transition-colors cursor-pointer" | |
| title="Change jurisdiction location" | |
| > | |
| <span className="material-symbols-outlined text-[15px] text-[#64748B]">location_on</span> | |
| <span>{selectedCity}</span> | |
| <span className="material-symbols-outlined text-[14px] text-[#94A3B8]">arrow_drop_down</span> | |
| </button> | |
| {showCityMenu && ( | |
| <div className="absolute left-0 mt-1.5 w-44 bg-white rounded-lg shadow-lg border border-[#E2E8F0] py-1 z-50 animate-in fade-in zoom-in-95 duration-150"> | |
| <div className="px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[#94A3B8] border-b border-[#F1F5F9]"> | |
| Select Jurisdiction | |
| </div> | |
| {CITIES.map((city) => ( | |
| <button | |
| key={city} | |
| onClick={() => { | |
| onSelectCity(city); | |
| setShowCityMenu(false); | |
| }} | |
| className={`w-full text-left px-3 py-1.5 text-[13px] flex items-center justify-between hover:bg-[#F8FAFC] transition-colors ${ | |
| selectedCity === city ? 'font-semibold text-[#006c4a] bg-[#F0FDF4]' : 'text-[#334155]' | |
| }`} | |
| > | |
| {city} | |
| {selectedCity === city && ( | |
| <span className="material-symbols-outlined text-[16px] text-[#006c4a]">check</span> | |
| )} | |
| </button> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| {/* Clean Single Navigation Link */} | |
| <nav className="flex items-center gap-3 sm:gap-6"> | |
| <button | |
| onClick={() => onNavigate('my-filings')} | |
| className={`text-[13.5px] font-medium transition-colors cursor-pointer flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg relative ${ | |
| currentView === 'my-filings' | |
| ? 'text-[#006c4a] font-bold bg-[#F0FDF4]' | |
| : 'text-[#64748B] hover:text-[#0F172A] hover:bg-[#F8FAFC]' | |
| }`} | |
| > | |
| <span className="material-symbols-outlined text-[18px]">folder</span> | |
| <span>My Filings</span> | |
| {filingsCount > 0 && ( | |
| <span className="text-[10px] font-bold px-1.5 py-0.2 bg-[#006c4a] text-white rounded-full"> | |
| {filingsCount} | |
| </span> | |
| )} | |
| </button> | |
| </nav> | |
| {/* Notifications & Profile */} | |
| <div className="flex items-center gap-3"> | |
| <div ref={notificationMenuRef} className="relative"> | |
| <button | |
| onClick={() => setShowNotificationMenu(!showNotificationMenu)} | |
| className="text-[#64748B] hover:text-[#0F172A] flex items-center justify-center w-9 h-9 rounded-full bg-[#F1F5F9] hover:bg-[#E2E8F0] border border-[#CBD5E1] transition-colors relative cursor-pointer" | |
| title="Notifications" | |
| > | |
| <span className="material-symbols-outlined text-[18px]">notifications</span> | |
| {unreadNotifications > 0 && ( | |
| <span className="absolute top-1 right-1 w-2 h-2 bg-[#D97706] rounded-full ring-2 ring-white"></span> | |
| )} | |
| </button> | |
| {showNotificationMenu && ( | |
| <div className="absolute right-0 mt-2 w-80 bg-white rounded-xl shadow-xl border border-[#E2E8F0] p-3 z-50 animate-in fade-in duration-150"> | |
| <div className="flex justify-between items-center pb-2 border-b border-[#F1F5F9] mb-2"> | |
| <span className="font-headline font-semibold text-[14px] text-[#0F172A]">Filing Alerts</span> | |
| <span className="text-[11px] text-[#059669] font-medium bg-[#059669]/10 px-2 py-0.5 rounded">2 Active</span> | |
| </div> | |
| <div className="flex flex-col gap-2"> | |
| <div className="p-2.5 bg-[#FEF3C7]/60 border border-[#FDE68A] rounded-lg text-[12px]"> | |
| <div className="font-semibold text-[#92400E] flex items-center gap-1"> | |
| <span className="material-symbols-outlined text-[14px]">timer</span> | |
| Statutory Clock Notice | |
| </div> | |
| <p className="text-[#78350F] mt-0.5">Agency response required within 18 statutory calendar days.</p> | |
| </div> | |
| <div className="p-2.5 bg-[#F0FDF4] border border-[#DCFCE7] rounded-lg text-[12px]"> | |
| <div className="font-semibold text-[#166534] flex items-center gap-1"> | |
| <span className="material-symbols-outlined text-[14px]">cloud_done</span> | |
| Firebase Real-time Storage | |
| </div> | |
| <p className="text-[#14532D] mt-0.5">Your filings are synced automatically with zero data loss.</p> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| {loading ? ( | |
| <div className="w-8 h-8 rounded-full bg-slate-200 animate-pulse"></div> | |
| ) : user ? ( | |
| <div ref={profileMenuRef} className="relative"> | |
| <button | |
| onClick={() => setShowProfileMenu(!showProfileMenu)} | |
| className="flex items-center gap-2 px-2 py-1 rounded-full border border-[#CBD5E1] hover:border-[#94A3B8] bg-white transition-all cursor-pointer shadow-xs" | |
| title="Account Settings" | |
| > | |
| <img | |
| alt={user.displayName || 'User'} | |
| className="w-7 h-7 rounded-full object-cover border border-[#E2E8F0]" | |
| src={ | |
| user.photoURL || | |
| 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&auto=format&fit=crop&q=80' | |
| } | |
| /> | |
| <span className="hidden sm:inline text-[12px] font-semibold text-[#1E293B] max-w-[90px] truncate"> | |
| {user.displayName?.split(' ')[0] || 'Citizen'} | |
| </span> | |
| <span className="material-symbols-outlined text-[14px] text-[#94A3B8]">expand_more</span> | |
| </button> | |
| {showProfileMenu && ( | |
| <div className="absolute right-0 mt-2 w-64 bg-white rounded-xl shadow-xl border border-[#E2E8F0] p-3 z-50 animate-in fade-in duration-150"> | |
| <div className="flex items-center gap-2.5 pb-2.5 border-b border-[#F1F5F9]"> | |
| <img | |
| src={ | |
| user.photoURL || | |
| 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&auto=format&fit=crop&q=80' | |
| } | |
| alt="User" | |
| className="w-9 h-9 rounded-full object-cover border border-[#E2E8F0]" | |
| /> | |
| <div className="overflow-hidden"> | |
| <div className="font-semibold text-[13px] text-[#0F172A] truncate"> | |
| {user.displayName || 'Citizen User'} | |
| </div> | |
| <div className="text-[11px] text-[#64748B] truncate">{user.email || 'citizen@caseloop.app'}</div> | |
| </div> | |
| </div> | |
| {user.email && ( | |
| <div className="mt-2 p-2 rounded-lg bg-[#F8FAFC] border border-[#E2E8F0] text-[11.5px]"> | |
| <div className="flex items-center justify-between"> | |
| <span className="font-medium text-[#475569]">Email Status</span> | |
| {user.emailVerified ? ( | |
| <span className="inline-flex items-center gap-1 text-[#059669] font-semibold bg-[#DCFCE7] px-2 py-0.5 rounded-full text-[10.5px]"> | |
| <span className="material-symbols-outlined text-[13px]">verified</span> | |
| Verified | |
| </span> | |
| ) : ( | |
| <span className="inline-flex items-center gap-1 text-[#D97706] font-semibold bg-[#FEF3C7] px-2 py-0.5 rounded-full text-[10.5px]"> | |
| <span className="material-symbols-outlined text-[13px]">pending</span> | |
| Unverified | |
| </span> | |
| )} | |
| </div> | |
| {!user.emailVerified && ( | |
| <div className="mt-2 pt-2 border-t border-[#E2E8F0] flex flex-col gap-1"> | |
| <button | |
| onClick={handleSendVerification} | |
| className="text-left text-[#006c4a] hover:underline font-semibold flex items-center gap-1 cursor-pointer" | |
| > | |
| <span className="material-symbols-outlined text-[14px]">forward_to_inbox</span> | |
| {verifSent ? 'Verification link sent!' : 'Send Verification Email'} | |
| </button> | |
| <button | |
| onClick={handleCheckVerification} | |
| className="text-left text-[#64748B] hover:text-[#0F172A] flex items-center gap-1 cursor-pointer text-[11px]" | |
| > | |
| <span className="material-symbols-outlined text-[13px]">refresh</span> | |
| Check status after verifying | |
| </button> | |
| {verifError && ( | |
| <p className="text-[11px] text-[#DC2626] mt-1 leading-snug">{verifError}</p> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| <div className="mt-2 flex flex-col gap-1 text-[13px]"> | |
| <button | |
| onClick={() => { | |
| onNavigate('my-filings'); | |
| setShowProfileMenu(false); | |
| }} | |
| className="w-full text-left px-2 py-1.5 hover:bg-[#F8FAFC] rounded text-[#334155] flex items-center gap-2 cursor-pointer mt-1" | |
| > | |
| <span className="material-symbols-outlined text-[16px]">folder</span> | |
| <span>My Cloud Filings ({filingsCount})</span> | |
| </button> | |
| <div className="border-t border-[#F1F5F9] my-1"></div> | |
| <button | |
| onClick={handleSignOut} | |
| disabled={authWorking} | |
| className="w-full text-left px-2 py-1.5 hover:bg-[#FEF2F2] rounded text-[#DC2626] font-medium flex items-center gap-2 cursor-pointer transition-colors" | |
| > | |
| <span className="material-symbols-outlined text-[16px]">logout</span> | |
| <span>{authWorking ? 'Signing Out...' : 'Sign Out'}</span> | |
| </button> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ) : ( | |
| <button | |
| onClick={() => setShowAuthModal(true)} | |
| className="group relative inline-flex items-center gap-2 px-4 py-2 rounded-xl text-[13px] font-semibold text-white bg-[#0F172A] hover:bg-[#1E293B] active:scale-[0.98] border border-slate-700/60 shadow-sm hover:shadow transition-all duration-200 cursor-pointer overflow-hidden" | |
| > | |
| <div className="w-1.5 h-1.5 rounded-full bg-[#10B981] group-hover:scale-125 transition-transform duration-200"></div> | |
| <span>Sign In</span> | |
| <span className="material-symbols-outlined text-[16px] text-slate-400 group-hover:translate-x-0.5 group-hover:text-white transition-all duration-200"> | |
| arrow_forward | |
| </span> | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| </header> | |
| <AuthModal | |
| isOpen={showAuthModal} | |
| onClose={() => setShowAuthModal(false)} | |
| /> | |
| </> | |
| ); | |
| }; | |