2026-04-03 16:52:33 +02:00
import { useState , useRef , useEffect , useCallback } from 'react'
2026-04-02 20:54:06 +02:00
import { Dialog , DialogContent , DialogHeader , DialogTitle , DialogFooter } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { FilterBuilder } from './FilterBuilder'
2026-04-03 16:52:33 +02:00
import { EmojiPicker } from './EmojiPicker'
import type { FilterGroup , ViewDefinition } from '../types'
2026-04-02 20:54:06 +02:00
interface CreateViewDialogProps {
open : boolean
onClose : ( ) = > void
onCreate : ( definition : ViewDefinition ) = > void
availableFields : string [ ]
2026-04-03 16:52:33 +02:00
/** Returns known values for a given field (for autocomplete). */
valueSuggestions ? : ( field : string ) = > string [ ]
2026-04-02 20:54:06 +02:00
}
2026-04-03 16:52:33 +02:00
export function CreateViewDialog ( { open , onClose , onCreate , availableFields , valueSuggestions } : CreateViewDialogProps ) {
2026-04-02 20:54:06 +02:00
const [ name , setName ] = useState ( '' )
const [ icon , setIcon ] = useState ( '' )
2026-04-03 16:52:33 +02:00
const [ showEmojiPicker , setShowEmojiPicker ] = useState ( false )
const [ filters , setFilters ] = useState < FilterGroup > ( {
all : [ { field : 'type' , op : 'equals' , value : '' } ] ,
} )
2026-04-02 20:54:06 +02:00
const inputRef = useRef < HTMLInputElement > ( null )
useEffect ( ( ) = > {
if ( open ) {
setName ( '' ) // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open
setIcon ( '' ) // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open
2026-04-03 16:52:33 +02:00
setShowEmojiPicker ( false ) // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open
setFilters ( { all : [ { field : availableFields [ 0 ] ? ? 'type' , op : 'equals' , value : '' } ] } ) // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open
2026-04-02 20:54:06 +02:00
setTimeout ( ( ) = > inputRef . current ? . focus ( ) , 50 )
}
} , [ open , availableFields ] )
const handleSubmit = ( e : React.FormEvent ) = > {
e . preventDefault ( )
const trimmed = name . trim ( )
if ( ! trimmed ) return
const definition : ViewDefinition = {
name : trimmed ,
icon : icon || null ,
color : null ,
sort : null ,
2026-04-03 16:52:33 +02:00
filters ,
2026-04-02 20:54:06 +02:00
}
onCreate ( definition )
onClose ( )
}
2026-04-03 16:52:33 +02:00
const handleSelectEmoji = useCallback ( ( emoji : string ) = > {
setIcon ( emoji )
setShowEmojiPicker ( false )
} , [ ] )
const handleCloseEmojiPicker = useCallback ( ( ) = > {
setShowEmojiPicker ( false )
} , [ ] )
2026-04-02 20:54:06 +02:00
return (
< Dialog open = { open } onOpenChange = { ( isOpen ) = > { if ( ! isOpen ) onClose ( ) } } >
2026-04-04 01:56:03 +02:00
< DialogContent showCloseButton = { false } className = "flex max-h-[80vh] flex-col sm:max-w-[600px]" >
2026-04-02 20:54:06 +02:00
< DialogHeader >
< DialogTitle > Create View < / DialogTitle >
< / DialogHeader >
2026-04-04 01:56:03 +02:00
< form onSubmit = { handleSubmit } className = "flex min-h-0 flex-1 flex-col gap-4" >
2026-04-02 20:54:06 +02:00
< div className = "flex gap-2" >
2026-04-03 16:52:33 +02:00
< div className = "w-16 space-y-1.5 relative" >
2026-04-02 20:54:06 +02:00
< label className = "text-xs font-medium text-muted-foreground" > Icon < / label >
2026-04-03 16:52:33 +02:00
< button
type = "button"
className = "flex h-9 w-full items-center justify-center rounded-md border border-input bg-background text-xl cursor-pointer hover:bg-accent transition-colors"
onClick = { ( ) = > setShowEmojiPicker ( ! showEmojiPicker ) }
title = "Pick icon"
>
{ icon || < span className = "text-sm text-muted-foreground" > 📋 < / span > }
< / button >
{ showEmojiPicker && (
< EmojiPicker onSelect = { handleSelectEmoji } onClose = { handleCloseEmojiPicker } / >
) }
2026-04-02 20:54:06 +02:00
< / div >
< div className = "flex-1 space-y-1.5" >
< label className = "text-xs font-medium text-muted-foreground" > Name < / label >
< Input
ref = { inputRef }
placeholder = "e.g. Active Projects, Reading List..."
value = { name }
onChange = { ( e ) = > setName ( e . target . value ) }
/ >
< / div >
< / div >
2026-04-04 01:56:03 +02:00
< div className = "min-h-0 flex-1 space-y-1.5 overflow-y-auto" >
2026-04-02 20:54:06 +02:00
< label className = "text-xs font-medium text-muted-foreground" > Filters < / label >
< FilterBuilder
2026-04-03 16:52:33 +02:00
group = { filters }
onChange = { setFilters }
2026-04-02 20:54:06 +02:00
availableFields = { availableFields }
2026-04-03 16:52:33 +02:00
valueSuggestions = { valueSuggestions }
2026-04-02 20:54:06 +02:00
/ >
< / div >
< DialogFooter >
< Button type = "button" variant = "outline" onClick = { onClose } > Cancel < / Button >
< Button type = "submit" disabled = { ! name . trim ( ) } > Create < / Button >
< / DialogFooter >
< / form >
< / DialogContent >
< / Dialog >
)
}