| import React from 'react'; | |
| import { WORKING_GROUPS } from '../constants'; | |
| import { Search, Loader2 } from 'lucide-react'; | |
| interface FilterBarProps { | |
| onFetch: (wg: string, meeting: string) => void; | |
| isFetching: boolean; | |
| } | |
| const FilterBar: React.FC<FilterBarProps> = ({ onFetch, isFetching }) => { | |
| const [selectedWg, setSelectedWg] = React.useState(WORKING_GROUPS[0]); | |
| const [meetings, setMeetings] = React.useState<Record<string, string>>({}); | |
| const [selectedMeeting, setSelectedMeeting] = React.useState(''); | |
| const [isLoadingMeetings, setIsLoadingMeetings] = React.useState(false); | |
| React.useEffect(() => { | |
| const fetchMeetings = async () => { | |
| setIsLoadingMeetings(true); | |
| try { | |
| const response = await fetch('https://organizedprogrammers-docxtract.hf.space/docs/get_meetings', | |
| { method: 'POST', body: JSON.stringify({ "working_group": selectedWg }), headers: { 'Content-Type': 'application/json' } }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| if (data.meetings) { | |
| setMeetings(data.meetings); | |
| const firstMeetingValue = Object.values(data.meetings)[0] as string; | |
| if (firstMeetingValue) { | |
| setSelectedMeeting(firstMeetingValue); | |
| } | |
| } | |
| } else { | |
| console.error("Failed to fetch meetings"); | |
| } | |
| } catch (error) { | |
| console.error("Error fetching meetings:", error); | |
| } finally { | |
| setIsLoadingMeetings(false); | |
| } | |
| }; | |
| fetchMeetings(); | |
| }, [selectedWg]); | |
| return ( | |
| <div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 mb-6"> | |
| <div className="grid grid-cols-1 md:grid-cols-12 gap-4 items-end"> | |
| <div className="md:col-span-3"> | |
| <label className="block text-sm font-medium text-slate-600 mb-1">Working Group</label> | |
| <div className="relative"> | |
| <select | |
| value={selectedWg} | |
| onChange={(e) => setSelectedWg(e.target.value)} | |
| className="w-full appearance-none bg-slate-50 border border-slate-300 text-slate-700 py-2.5 px-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" | |
| > | |
| {WORKING_GROUPS.map(wg => <option key={wg} value={wg}>{wg}</option>)} | |
| </select> | |
| <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-500"> | |
| <svg className="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="md:col-span-4"> | |
| <label className="block text-sm font-medium text-slate-600 mb-1">Meeting</label> | |
| <div className="relative"> | |
| <select | |
| value={selectedMeeting} | |
| onChange={(e) => setSelectedMeeting(e.target.value)} | |
| disabled={isLoadingMeetings} | |
| className="w-full appearance-none bg-slate-50 border border-slate-300 text-slate-700 py-2.5 px-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50" | |
| > | |
| {isLoadingMeetings ? ( | |
| <option>Loading meetings...</option> | |
| ) : ( | |
| Object.entries(meetings).map(([displayName, value]) => ( | |
| <option key={value} value={value}>{displayName}</option> | |
| )) | |
| )} | |
| </select> | |
| <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-500"> | |
| <svg className="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="md:col-span-3"> | |
| <label className="block text-sm font-medium text-slate-600 mb-2">Doc Types</label> | |
| <div className="flex space-x-4"> | |
| <label className="inline-flex items-center"> | |
| <input type="checkbox" className="form-checkbox text-blue-600 h-4 w-4 rounded border-slate-300" defaultChecked /> | |
| <span className="ml-2 text-slate-700">CR</span> | |
| </label> | |
| <label className="inline-flex items-center"> | |
| <input type="checkbox" className="form-checkbox text-blue-600 h-4 w-4 rounded border-slate-300" defaultChecked /> | |
| <span className="ml-2 text-slate-700">PCR</span> | |
| </label> | |
| </div> | |
| </div> | |
| <div className="md:col-span-2"> | |
| <button | |
| onClick={() => onFetch(selectedWg, selectedMeeting)} | |
| disabled={isFetching} | |
| className="w-full flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2.5 px-4 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| {isFetching ? ( | |
| <Loader2 className="w-4 h-4 mr-2 animate-spin" /> | |
| ) : ( | |
| <Search className="w-4 h-4 mr-2" /> | |
| )} | |
| Fetch Docs | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default FilterBar; |