# All files / src/components CreateNoteDialog.tsx

92% Statements 23/25
88.23% Branches 15/17
90% Functions 9/10
95.23% Lines 20/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120

    1x

    25x
    25x
    25x

    25x
    11x

    10x
    10x

    25x
    5x
    5x
    5x
    4x
    4x

    25x

    6x

    200x

    1x

    6x

    1x

     import { useState, useRef, useEffect } from 'react'
    import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
    import { Button } from '@/components/ui/button'
    import { Input } from '@/components/ui/input'
    import { cn } from '@/lib/utils'

    const BUILT_IN_TYPES = [
      'Note',
      'Project',
      'Experiment',
      'Responsibility',
      'Procedure',
      'Person',
      'Event',
      'Topic',
    ] as const

    export type NoteType = (typeof BUILT_IN_TYPES)[number]

    interface CreateNoteDialogProps {
      open: boolean
      onClose: () => void
      onCreate: (title: string, type: string) => void
      defaultType?: string
      /** Custom types from the vault (Type documents not in built-in list) */
      customTypes?: string[]
    }

    export function CreateNoteDialog({ open, onClose, onCreate, defaultType, customTypes = [] }: CreateNoteDialogProps) {
      const [title, setTitle] = useState('')
      const [type, setType] = useState<string>('Note')
      const inputRef = useRef<HTMLInputElement>(null)

      useEffect(() => {
        if (open) {
          // eslint-disable-next-line react-hooks/set-state-in-effect -- reset on dialog open
          setTitle(''); setType(defaultType ?? 'Note')
          setTimeout(() => inputRef.current?.focus(), 50)
        }
      }, [open, defaultType])

      const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault()
        const trimmed = title.trim()
        if (!trimmed) return
        onCreate(trimmed, type)
        onClose()
      }

      return (
        <Dialog open={open} onOpenChange={(isOpen) => { if (!isOpen) onClose() }}>
          <DialogContent showCloseButton={false} className="sm:max-w-[420px]">
            <DialogHeader>
              <DialogTitle>Create New Note</DialogTitle>
            </DialogHeader>
            <form onSubmit={handleSubmit} className="space-y-4">
              <div className="space-y-1.5">
                <label className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                  Title
                </label>
                <Input
                  ref={inputRef}
                  placeholder="Enter note title..."
                  value={title}
                  onChange={(e) => setTitle(e.target.value)}
                />
              </div>
              <div className="space-y-1.5">
                <label className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                  Type
                </label>
                <div className="flex flex-wrap gap-1.5">
                  {BUILT_IN_TYPES.map((t) => (
                    <Button
                      key={t}
                      type="button"
                      variant={type === t ? 'default' : 'outline'}
                      size="sm"
                      className={cn(
                        "rounded-full text-xs",
                        type === t && "bg-primary text-primary-foreground"
                      )}
                      onClick={() => setType(t)}
                    >
                      {t}
                    </Button>
                  ))}
                  {customTypes.map((t) => (
                    <Button
                      key={t}
                      type="button"
                      variant={type === t ? 'default' : 'outline'}
                      size="sm"
                      className={cn(
                        "rounded-full text-xs",
                        type === t
                          ? "bg-[var(--accent-blue)] text-white"
                          : "border-[var(--accent-blue)] text-[var(--accent-blue)]"
                      )}
                      onClick={() => setType(t)}
                    >
                      {t}
                    </Button>
                  ))}
                </div>
              </div>
              <DialogFooter>
                <Button type="button" variant="outline" onClick={onClose}>
                  Cancel
                </Button>
                <Button type="submit" disabled={!title.trim()}>
                  Create
                </Button>
              </DialogFooter>
            </form>
          </DialogContent>
        </Dialog>
      )
    }