diff --git a/inventory/src/components/dashboard/FinancialOverview.tsx b/inventory/src/components/dashboard/FinancialOverview.tsx index 00a1ef3..d1fa5af 100644 --- a/inventory/src/components/dashboard/FinancialOverview.tsx +++ b/inventory/src/components/dashboard/FinancialOverview.tsx @@ -7,7 +7,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; import { Select, SelectContent, @@ -45,17 +44,11 @@ import { import type { TooltipProps } from "recharts"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Skeleton } from "@/components/ui/skeleton"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { ArrowUpRight, ArrowDownRight, Minus, TrendingUp, AlertCircle, Calendar } from "lucide-react"; -import type { CustomPeriod } from "@/utils/naturalLanguagePeriod"; -import { - generateNaturalLanguagePreview, - parseNaturalLanguagePeriod, -} from "@/utils/naturalLanguagePeriod"; +import { ArrowUpRight, ArrowDownRight, Minus, TrendingUp, AlertCircle } from "lucide-react"; +import PeriodSelectionPopover, { + type QuickPreset, +} from "@/components/dashboard/PeriodSelectionPopover"; +import type { CustomPeriod, NaturalLanguagePeriodResult } from "@/utils/naturalLanguagePeriod"; type TrendDirection = "up" | "down" | "flat"; @@ -634,8 +627,6 @@ const FinancialOverview = () => { }); const [isLast30DaysMode, setIsLast30DaysMode] = useState(true); const [isPeriodPopoverOpen, setIsPeriodPopoverOpen] = useState(false); - const [naturalLanguageInput, setNaturalLanguageInput] = useState(""); - const [showSuggestions, setShowSuggestions] = useState(false); const [metrics, setMetrics] = useState>({ income: true, cogs: true, @@ -1040,62 +1031,19 @@ const FinancialOverview = () => { [series]: !prev[series], })); }; - - - const suggestions = [ - "last 30 days", - "this month", - "last month", - "this quarter", - "last quarter", - "this year", - "last year", - "last 3 months", - "last 6 months", - "last 2 quarters", - "Q1 2024", - "q1-q3 24", - "q1 24 - q2 25", - "January 2024", - "jan-24", - "jan-may 24", - "2023", - "2021-2023", - "21-23", - "January to March 2024", - "jan 2023 - may 2024" - ]; - - const filteredSuggestions = suggestions.filter(suggestion => - suggestion.toLowerCase().includes(naturalLanguageInput.toLowerCase()) && - suggestion.toLowerCase() !== naturalLanguageInput.toLowerCase() - ); - - const handleNaturalLanguageChange = (value: string) => { - setNaturalLanguageInput(value); - setShowSuggestions(value.length > 0); - }; - - const handleNaturalLanguageSubmit = (input: string) => { - const parsed = parseNaturalLanguagePeriod(input, currentDate); - if (parsed === "last30days") { + const handleNaturalLanguageResult = (result: NaturalLanguagePeriodResult) => { + if (result === "last30days") { setIsLast30DaysMode(true); - setIsPeriodPopoverOpen(false); - } else if (parsed) { - setIsLast30DaysMode(false); - setCustomPeriod(parsed); - setIsPeriodPopoverOpen(false); + return; + } + + if (result) { + setIsLast30DaysMode(false); + setCustomPeriod(result); } - setNaturalLanguageInput(""); - setShowSuggestions(false); }; - const handleSuggestionClick = (suggestion: string) => { - setNaturalLanguageInput(suggestion); - handleNaturalLanguageSubmit(suggestion); - }; - - const handleQuickPeriod = (preset: string) => { + const handleQuickPeriod = (preset: QuickPreset) => { const now = new Date(); const currentYear = now.getFullYear(); const currentMonth = now.getMonth(); @@ -1176,174 +1124,15 @@ const FinancialOverview = () => {
{!error && ( <> - - - - - -
-
Select Time Period
- - {/* Quick Presets - Compact Grid */} -
- - - - - - -
- - - - {/* Natural Language Input */} -
-
Or type a custom period
- -
- handleNaturalLanguageChange(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - handleNaturalLanguageSubmit(naturalLanguageInput); - } - if (e.key === 'Escape') { - setNaturalLanguageInput(""); - setShowSuggestions(false); - } - }} - className="h-8 text-sm" - /> - - {/* Live Preview */} - {naturalLanguageInput && ( -
- {(() => { - const parsed = parseNaturalLanguagePeriod(naturalLanguageInput, currentDate); - const preview = generateNaturalLanguagePreview(parsed); - - if (preview) { - return ( -
- Recognized as: - - {preview} - -
- ); - } else { - return ( -
- Not recognized - try a different format -
- ); - } - })()} -
- )} - - {/* Suggestions Dropdown */} - {showSuggestions && filteredSuggestions.length > 0 && ( -
- {filteredSuggestions.slice(0, 6).map((suggestion, index) => ( - - ))} -
- )} -
- - {/* Example suggestions when input is empty */} - {naturalLanguageInput === "" && ( -
-
Examples:
-
- {suggestions.slice(0, 6).map((suggestion, index) => ( - - ))} -
-
- )} -
-
-
-
+ @@ -1650,7 +1439,7 @@ function FinancialStatGrid({ }>; }) { return ( -
+
{cards.map((card) => ( ))} diff --git a/inventory/src/components/dashboard/PeriodSelectionPopover.tsx b/inventory/src/components/dashboard/PeriodSelectionPopover.tsx new file mode 100644 index 0000000..a77c30d --- /dev/null +++ b/inventory/src/components/dashboard/PeriodSelectionPopover.tsx @@ -0,0 +1,269 @@ +import { useMemo, useState, type KeyboardEventHandler } from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Calendar } from "lucide-react"; +import { + generateNaturalLanguagePreview, + parseNaturalLanguagePeriod, + type NaturalLanguagePeriodResult, +} from "@/utils/naturalLanguagePeriod"; + +export type QuickPreset = + | "last30days" + | "thisMonth" + | "lastMonth" + | "thisQuarter" + | "lastQuarter" + | "thisYear"; + +const SUGGESTIONS = [ + "last 30 days", + "this month", + "last month", + "this quarter", + "last quarter", + "this year", + "last year", + "last 3 months", + "last 6 months", + "last 2 quarters", + "Q1 2024", + "q1-q3 24", + "q1 24 - q2 25", + "January 2024", + "jan-24", + "jan-may 24", + "2023", + "2021-2023", + "21-23", + "January to March 2024", + "jan 2023 - may 2024", +]; + +interface PeriodSelectionPopoverProps { + open: boolean; + onOpenChange: (open: boolean) => void; + selectedLabel: string; + referenceDate: Date; + isLast30DaysActive: boolean; + onQuickSelect: (preset: QuickPreset) => void; + onApplyResult: (result: NaturalLanguagePeriodResult) => void; +} + +const PeriodSelectionPopover = ({ + open, + onOpenChange, + selectedLabel, + referenceDate, + isLast30DaysActive, + onQuickSelect, + onApplyResult, +}: PeriodSelectionPopoverProps) => { + const [inputValue, setInputValue] = useState(""); + const [showSuggestions, setShowSuggestions] = useState(false); + + const filteredSuggestions = useMemo(() => { + if (!inputValue) { + return SUGGESTIONS; + } + return SUGGESTIONS.filter((suggestion) => + suggestion.toLowerCase().includes(inputValue.toLowerCase()) && + suggestion.toLowerCase() !== inputValue.toLowerCase() + ); + }, [inputValue]); + + const preview = useMemo(() => { + if (!inputValue) { + return { label: null, parsed: null } as const; + } + const parsed = parseNaturalLanguagePeriod(inputValue, referenceDate); + return { + parsed, + label: generateNaturalLanguagePreview(parsed), + } as const; + }, [inputValue, referenceDate]); + + const closePopover = () => { + onOpenChange(false); + }; + + const resetInput = () => { + setInputValue(""); + setShowSuggestions(false); + }; + + const applyResult = (value: string) => { + const parsed = parseNaturalLanguagePeriod(value, referenceDate); + if (!parsed) { + return; + } + onApplyResult(parsed); + resetInput(); + closePopover(); + }; + + const handleInputChange = (value: string) => { + setInputValue(value); + setShowSuggestions(value.length > 0); + }; + + const handleKeyDown: KeyboardEventHandler = (event) => { + if (event.key === "Enter") { + event.preventDefault(); + applyResult(inputValue); + } + if (event.key === "Escape") { + resetInput(); + } + }; + + const handleSuggestionClick = (suggestion: string) => { + setInputValue(suggestion); + applyResult(suggestion); + }; + + const handleQuickSelect = (preset: QuickPreset) => { + onQuickSelect(preset); + resetInput(); + closePopover(); + }; + + return ( + + + + + +
+
Select Time Period
+ +
+ + + + + + +
+ + + +
+
Or type a custom period
+ +
+ handleInputChange(event.target.value)} + onKeyDown={handleKeyDown} + className="h-8 text-sm" + /> + + {inputValue && ( +
+ {preview.label ? ( +
+ Recognized as: + + {preview.label} + +
+ ) : ( +
+ Not recognized - try a different format +
+ )} +
+ )} + + {showSuggestions && filteredSuggestions.length > 0 && ( +
+ {filteredSuggestions.slice(0, 6).map((suggestion) => ( + + ))} +
+ )} + + {inputValue === "" && ( +
+
Examples:
+
+ {SUGGESTIONS.slice(0, 6).map((suggestion) => ( + + ))} +
+
+ )} +
+
+
+
+
+ ); +}; + +export default PeriodSelectionPopover;