| 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; |