From e0dfb55c5457aec489fc084c4567e791b4c65eb1 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Wed, 26 Mar 2025 00:37:41 +0000
Subject: 3/25 까지의 대표님 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/date-range-picker.tsx | 146 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 components/date-range-picker.tsx

(limited to 'components/date-range-picker.tsx')

diff --git a/components/date-range-picker.tsx b/components/date-range-picker.tsx
new file mode 100644
index 00000000..295160a5
--- /dev/null
+++ b/components/date-range-picker.tsx
@@ -0,0 +1,146 @@
+"use client"
+
+import * as React from "react"
+import { format } from "date-fns"
+import { CalendarIcon } from "lucide-react"
+import { parseAsString, useQueryStates } from "nuqs"
+import { type DateRange } from "react-day-picker"
+
+import { cn } from "@/lib/utils"
+import { Button, type ButtonProps } from "@/components/ui/button"
+import { Calendar } from "@/components/ui/calendar"
+import {
+  Popover,
+  PopoverContent,
+  PopoverTrigger,
+} from "@/components/ui/popover"
+
+interface DateRangePickerProps
+  extends React.ComponentPropsWithoutRef<typeof PopoverContent> {
+  /**
+   * The selected date range.
+   * @default undefined
+   * @type DateRange
+   * @example { from: new Date(), to: new Date() }
+   */
+  defaultDateRange?: DateRange
+
+  /**
+   * The placeholder text of the calendar trigger button.
+   * @default "Pick a date"
+   * @type string | undefined
+   */
+  placeholder?: string
+
+  /**
+   * The variant of the calendar trigger button.
+   * @default "outline"
+   * @type "default" | "outline" | "secondary" | "ghost"
+   */
+  triggerVariant?: Exclude<ButtonProps["variant"], "destructive" | "link">
+
+  /**
+   * The size of the calendar trigger button.
+   * @default "default"
+   * @type "default" | "sm" | "lg"
+   */
+  triggerSize?: Exclude<ButtonProps["size"], "icon">
+
+  /**
+   * The class name of the calendar trigger button.
+   * @default undefined
+   * @type string
+   */
+  triggerClassName?: string
+
+  /**
+   * Controls whether query states are updated client-side only (default: true).
+   * Setting to `false` triggers a network request to update the querystring.
+   * @default true
+   */
+  shallow?: boolean
+}
+
+export function DateRangePicker({
+  defaultDateRange,
+  placeholder = "Pick a date",
+  triggerVariant = "outline",
+  triggerSize = "default",
+  triggerClassName,
+  shallow = true,
+  className,
+  ...props
+}: DateRangePickerProps) {
+  const [dateParams, setDateParams] = useQueryStates(
+    {
+      from: parseAsString.withDefault(
+        defaultDateRange?.from?.toISOString() ?? ""
+      ),
+      to: parseAsString.withDefault(defaultDateRange?.to?.toISOString() ?? ""),
+    },
+    {
+      clearOnDefault: true,
+      shallow,
+    }
+  )
+
+  const date = React.useMemo(() => {
+    function parseDate(dateString: string | null) {
+      if (!dateString) return undefined
+      const parsedDate = new Date(dateString)
+      return isNaN(parsedDate.getTime()) ? undefined : parsedDate
+    }
+
+    return {
+      from: parseDate(dateParams.from) ?? defaultDateRange?.from,
+      to: parseDate(dateParams.to) ?? defaultDateRange?.to,
+    }
+  }, [dateParams, defaultDateRange])
+
+  return (
+    <div className="grid gap-2">
+      <Popover>
+        <PopoverTrigger asChild>
+          <Button
+            variant={triggerVariant}
+            size={triggerSize}
+            className={cn(
+              "w-full justify-start gap-2 truncate text-left font-normal",
+              !date && "text-muted-foreground",
+              triggerClassName
+            )}
+          >
+            <CalendarIcon className="size-4" />
+            {date?.from ? (
+              date.to ? (
+                <>
+                  {format(date.from, "LLL dd, y")} -{" "}
+                  {format(date.to, "LLL dd, y")}
+                </>
+              ) : (
+                format(date.from, "LLL dd, y")
+              )
+            ) : (
+              <span>{placeholder}</span>
+            )}
+          </Button>
+        </PopoverTrigger>
+        <PopoverContent className={cn("w-auto p-0", className)} {...props}>
+          <Calendar
+            initialFocus
+            mode="range"
+            defaultMonth={date?.from}
+            selected={date}
+            onSelect={(newDateRange) => {
+              void setDateParams({
+                from: newDateRange?.from?.toISOString() ?? "",
+                to: newDateRange?.to?.toISOString() ?? "",
+              })
+            }}
+            numberOfMonths={2}
+          />
+        </PopoverContent>
+      </Popover>
+    </div>
+  )
+}
-- 
cgit v1.2.3

