@@ -15,7 +15,7 @@ import {
1515 ChevronsLeft ,
1616 ChevronsRight ,
1717} from "lucide-react" ;
18- import React , { useState } from "react" ;
18+ import React , { useState , useEffect } from "react" ;
1919import { Button } from "./ui/button" ;
2020import {
2121 Table ,
@@ -27,7 +27,6 @@ import {
2727import { Input } from "@/components/ui/input" ;
2828import { Checkbox } from "@/components/ui/checkbox" ;
2929import { usePivotStore } from "@/stores/usePivotStore" ;
30- import { Table as Arrow } from "apache-arrow" ;
3130import {
3231 Collapsible ,
3332 CollapsibleContent ,
@@ -37,13 +36,17 @@ import { ChevronDown, ChevronUp } from "lucide-react";
3736import { Separator } from "./ui/separator" ;
3837import { useToast } from "@/hooks/use-toast" ;
3938
39+ type FilterDialogProps = {
40+ table : string ;
41+ field : string ;
42+ dateExtract ?: "YEAR" | "MONTH" | "QUARTER" ;
43+ } ;
44+
4045export default function FilterDialog ( {
4146 table,
4247 field,
43- } : {
44- table : string ;
45- field : string ;
46- } ) {
48+ dateExtract,
49+ } : FilterDialogProps ) {
4750 const { toast } = useToast ( ) ;
4851 const { db, runQuery } = useDuckDBStore ( ) ;
4952 const { filters, addFilter } = usePivotStore ( ) ;
@@ -60,36 +63,55 @@ export default function FilterDialog({
6063 const itemsPerPage = 10 ;
6164
6265 const fetchData = async ( ) => {
63- if ( db ) {
64- setLoading ( true ) ;
65- const result : Arrow = await runQuery (
66- db ,
67- `
68- SELECT DISTINCT " ${ field } "
69- FROM ' ${ table } '
70- ORDER BY " ${ field } " ASC`
71- ) ;
66+ if ( ! db ) return ;
67+ setLoading ( true ) ;
68+
69+ try {
70+ let query ;
71+ // Extract the original field name if it's already a date-extracted field
72+ const originalField = field . match ( / ^ ( Y E A R | M O N T H | Q U A R T E R ) \( ( . * ? ) \) $ / ) ;
73+ const actualField = originalField ? originalField [ 2 ] : field ;
74+ const actualExtract = originalField ? originalField [ 1 ] : dateExtract ;
7275
73- const cleanedData = result . toArray ( ) . map ( ( row ) => {
76+ if ( actualExtract ) {
77+ query = `SELECT DISTINCT REPLACE(CAST(EXTRACT(${ actualExtract } FROM CAST("${ actualField } " AS DATE)) AS VARCHAR), '"', '') as value FROM '${ table } ' WHERE "${ actualField } " IS NOT NULL ORDER BY value` ;
78+ } else {
79+ query = `SELECT DISTINCT REPLACE("${ actualField } ", '"', '') as value FROM '${ table } ' WHERE "${ actualField } " IS NOT NULL ORDER BY value` ;
80+ }
81+ const result = await runQuery ( db , query ) ;
82+
83+ const values = result
84+ . toArray ( )
7485 // eslint-disable-next-line @typescript-eslint/no-explicit-any
75- const cleanedRow : any = { } ;
76- for ( const [ key , value ] of Object . entries ( row ) ) {
77- cleanedRow [ key ] =
78- typeof value === "string" ? value . replace ( / " / g, "" ) : value ;
79- }
80- return cleanedRow ;
86+ . map ( ( row : { value : { toString : ( ) => any } } ) => row . value . toString ( ) ) ;
87+ setValues ( values ) ;
88+ } catch ( error ) {
89+ console . error ( "Error fetching filter options:" , error ) ;
90+ toast ( {
91+ title : "Error" ,
92+ description :
93+ "Failed to fetch filter values. Please make sure this is a proper date or text field." ,
94+ variant : "destructive" ,
8195 } ) ;
82-
83- setValues (
84- cleanedData . map (
85- // eslint-disable-next-line @typescript-eslint/no-explicit-any
86- ( obj : any ) => obj [ field ] ?. toString ( ) ?? "(Null)"
87- )
88- ) ;
96+ } finally {
8997 setLoading ( false ) ;
9098 }
9199 } ;
92100
101+ // Remove the automatic fetching from useEffect since we now have a manual fetch button
102+ useEffect ( ( ) => {
103+ // Reset selected values when dialog opens
104+ if ( open ) {
105+ // Find the filter checking both regular and date-extracted field names
106+ const existingFilter = filters . find (
107+ ( f ) =>
108+ f . table === table &&
109+ ( f . field === field || f . field === `${ dateExtract } (${ field } )` )
110+ ) ;
111+ setSelectedValues ( existingFilter ?. values || [ ] ) ;
112+ }
113+ } , [ open , table , field , dateExtract , filters ] ) ;
114+
93115 const filteredValues = values . filter ( ( value ) =>
94116 value . toString ( ) . toLowerCase ( ) . includes ( searchQuery . toLowerCase ( ) )
95117 ) ;
@@ -108,7 +130,7 @@ export default function FilterDialog({
108130 } ;
109131
110132 const handleSubmit = ( ) => {
111- addFilter ( table , field , selectedValues ) ;
133+ addFilter ( table , field , selectedValues , dateExtract ) ;
112134 toast ( {
113135 title : "Filter Applied" ,
114136 description : `Successfully applied filter for ${ field } ` ,
@@ -138,7 +160,9 @@ export default function FilterDialog({
138160 < DialogHeader >
139161 < DialogTitle > Add filter</ DialogTitle >
140162 < DialogDescription className = "text-white" >
141- Add filter for { field }
163+ { dateExtract
164+ ? `Filter by ${ dateExtract . toLowerCase ( ) } s from "${ field } " in "${ table } "`
165+ : `Add filter for "${ field } " from "${ table } "` }
142166 </ DialogDescription >
143167 </ DialogHeader >
144168 < div className = "flex flex-col space-y-4" >
0 commit comments