Skip to main content
Glama

Convex MCP server

Official
by get-convex
DateRangePicker.tsx6.9 kB
"use client"; import { CalendarIcon, CheckIcon } from "@radix-ui/react-icons"; import { endOfToday, parse, startOfDay, format } from "date-fns"; import { NextRouter } from "next/router"; import * as React from "react"; import { DateRange } from "react-day-picker"; import { Popover } from "@ui/Popover"; import { Button } from "@ui/Button"; import { Calendar } from "@common/elements/Calendar"; export type DateRangeShortcut = { value: string; label: string; from: Date; to: Date; disableFilters?: boolean; }; export function DateRangePicker({ minDate, maxDate, date, setDate, shortcuts, formatDate = (d: Date) => format(d, "LLL dd, y"), disabled = false, dateFilterEnabled = true, prefix, }: { minDate?: Date; maxDate?: Date; date: { from?: Date; to?: Date; }; setDate: (date: DateRange, shortcut?: DateRangeShortcut) => void; shortcuts?: DateRangeShortcut[]; formatDate?: (date: Date) => string; disabled?: boolean; dateFilterEnabled?: boolean; prefix?: string; }) { const { from, to } = date; // Track current selected shortcut const [activeShortcut, setActiveShortcut] = React.useState<string | null>( null, ); // Initialize activeShortcut based on dateFilterEnabled React.useEffect(() => { if (!dateFilterEnabled) { // Set to "anytime" when filters are disabled setActiveShortcut("anytime"); } else if (shortcuts && from && to) { // Check if current date range matches any shortcut const matchingShortcut = shortcuts.find( (s) => !s.disableFilters && s.from.toDateString() === from.toDateString() && s.to.toDateString() === to.toDateString(), ); setActiveShortcut(matchingShortcut?.value || null); } }, [dateFilterEnabled, from, to, shortcuts]); // When a calendar selection is made, we need to track it for rendering, // but defer to the parent component for state management const [selectedRange, setSelectedRange] = React.useState< DateRange | undefined >(from && to ? { from, to } : undefined); // Update selected range when date props change React.useEffect(() => { setSelectedRange(from && to ? { from, to } : undefined); }, [from, to]); return ( <Popover placement="bottom-start" button={ <Button variant="neutral" className="w-fit justify-start text-left font-normal" icon={<CalendarIcon className="size-4" />} disabled={disabled} > <div className="flex items-center gap-1"> {prefix && <span className="font-semibold">{prefix}</span>} {dateFilterEnabled ? ( from && to ? ( <> {formatDate(from)} – {formatDate(to)} </> ) : from ? ( formatDate(from) ) : ( <span>Pick a date</span> ) ) : ( <span>Any time</span> )} </div> </Button> } > {({ close }) => ( <div className="flex flex-col gap-4 md:flex-row"> {shortcuts && ( <div className="flex w-[13rem] flex-col gap-2 border-b pb-4 md:border-r md:border-b-0 md:pb-0"> {shortcuts.map((s) => ( <Button key={s.label} variant="unstyled" onClick={() => { setActiveShortcut(s.value); // Clear the internal selected range for "Any time" if (s.disableFilters) { setSelectedRange(undefined); } else { setSelectedRange({ from: s.from, to: s.to }); } close(); setDate(s, s); }} className="-ml-4 flex w-full items-start gap-1 rounded-sm p-1 text-xs hover:bg-background-tertiary" icon={ activeShortcut === s.value ? ( <CheckIcon className="mt-1" /> ) : ( <div className="size-4" /> ) } > <div className="flex flex-col items-start"> {s.label}{" "} {!s.disableFilters ? ( <span className="text-xs text-content-secondary"> {formatDate(s.from)} – {formatDate(s.to)} </span> ) : ( <span className="text-xs text-content-secondary"> Show all results </span> )} </div> </Button> ))} </div> )} <Calendar initialFocus mode="range" fromDate={minDate} toDate={maxDate} defaultMonth={from || new Date()} selected={selectedRange} onSelect={(d) => { if (!d) return; // Clear active shortcut when manually selecting dates setActiveShortcut(null); // Update internal selected range for immediate UI feedback setSelectedRange(d); // Pass the date range to parent component setDate(d); }} numberOfMonths={2} /> </div> )} </Popover> ); } export const DATE_FORMAT = "yyyy-MM-dd"; export function useDateFilters(router: NextRouter) { // Current day const maxEndDate = endOfToday(); // A week from current day const initStartDate = new Date(maxEndDate); initStartDate.setDate(initStartDate.getDate() - 7); const startDate = router.query.startDate ? parse(router.query.startDate as string, DATE_FORMAT, new Date()) : initStartDate; const endDate = router.query.endDate ? parse(router.query.endDate as string, DATE_FORMAT, new Date()) : maxEndDate; const checkAndSetStartDate = React.useCallback( async (date: Date) => { const start = startOfDay(date); // eslint-disable-next-line no-param-reassign router.query.startDate = format(start, DATE_FORMAT); await router.replace({ query: router.query, }); }, [router], ); const checkAndSetEndDate = React.useCallback( async (date: Date) => { const end = startOfDay(date); // eslint-disable-next-line no-param-reassign router.query.endDate = format(end, DATE_FORMAT); await router.replace({ query: router.query, }); }, [router], ); return { startDate, endDate, setDate: async (date: DateRange) => { date.from && (await checkAndSetStartDate(date.from)); date.to && (await checkAndSetEndDate(date.to)); }, }; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server