- Added ResponsiveDialog component for handling responsive dialogs in the UI. - Created ExpensesProvider to manage state and API interactions for expenses. - Developed ExpensesTabContent to display expenses with filtering options and dialogs for new and pay expense actions. - Implemented ExpensesTable for rendering expense data in a tabular format with actions. - Added dialogs for creating new expenses and paying existing ones with form validation. - Introduced PeriodicExpenseForm for managing periodic expenses with month selection. - Created PeriodicExpensesTabContent to manage and display periodic expenses with create/edit functionality. - Added GenerateCurrentMonthDialog for confirming monthly expense generation. - Implemented PeriodicExpensesTable for displaying periodic expenses with edit and delete actions.
88 lines
3.9 KiB
TypeScript
88 lines
3.9 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import { DayPicker } from "react-day-picker"
|
|
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
|
|
|
function Calendar({
|
|
className,
|
|
classNames,
|
|
showOutsideDays = true,
|
|
...props
|
|
}: CalendarProps) {
|
|
return (
|
|
<DayPicker
|
|
showOutsideDays={showOutsideDays}
|
|
className={cn("w-full", className)}
|
|
classNames={{
|
|
root: "w-full",
|
|
months: "flex flex-col",
|
|
month: "flex flex-col gap-3",
|
|
month_caption: "flex items-center justify-center",
|
|
caption_label: "hidden",
|
|
nav: "flex items-center gap-1",
|
|
button_previous:
|
|
"inline-flex items-center justify-center rounded-md size-7 bg-transparent p-0 text-foreground opacity-50 hover:opacity-100 hover:bg-accent",
|
|
button_next:
|
|
"inline-flex items-center justify-center rounded-md size-7 bg-transparent p-0 text-foreground opacity-50 hover:opacity-100 hover:bg-accent",
|
|
dropdowns: "flex items-center gap-2",
|
|
dropdown_root: "relative inline-flex items-center",
|
|
dropdown:
|
|
"h-7 w-full appearance-none rounded-md border border-input bg-background pl-2 pr-6 text-xs font-medium text-foreground outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 cursor-pointer",
|
|
months_dropdown: "w-28",
|
|
years_dropdown: "w-22",
|
|
chevron: "size-3 text-muted-foreground",
|
|
month_grid: "w-full border-collapse",
|
|
weekdays: "flex",
|
|
weekday: "w-8 text-xs font-normal text-muted-foreground pt-2 pb-1 text-center",
|
|
week: "flex w-full",
|
|
day: "p-0 size-8 text-center text-sm",
|
|
day_button:
|
|
"inline-flex items-center justify-center rounded-md size-8 text-sm font-normal text-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 aria-selected:opacity-100",
|
|
today: "bg-accent text-accent-foreground rounded-md",
|
|
outside: "text-muted-foreground opacity-50",
|
|
disabled: "text-muted-foreground opacity-50",
|
|
range_middle:
|
|
"aria-selected:bg-accent aria-selected:text-accent-foreground rounded-none",
|
|
range_start:
|
|
"aria-selected:bg-primary aria-selected:text-primary-foreground rounded-l-md",
|
|
range_end:
|
|
"aria-selected:bg-primary aria-selected:text-primary-foreground rounded-r-md",
|
|
selected:
|
|
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground rounded-md",
|
|
...classNames,
|
|
}}
|
|
components={{
|
|
Chevron: (props) => {
|
|
const { orientation, ...rest } = props
|
|
if (orientation === "up" || orientation === "down") {
|
|
return <ChevronDownIcon className="size-3" {...rest} />
|
|
}
|
|
const Icon = orientation === "left" ? ChevronLeftIcon : ChevronRightIcon
|
|
return <Icon className="size-4" {...rest} />
|
|
},
|
|
Select: (props) => {
|
|
const { className, children, ...rest } = props
|
|
return (
|
|
<select
|
|
className={cn("h-7 appearance-none rounded-md border border-input bg-background px-2 text-xs font-medium text-foreground outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 cursor-pointer bg-[right_4px_center] bg-no-repeat", className)}
|
|
style={{ backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23666' stroke-width='1.5'%3e%3cpath d='M4 6l4 4 4-4'/%3e%3c/svg%3e")` }}
|
|
{...rest}
|
|
>
|
|
{children}
|
|
</select>
|
|
)
|
|
},
|
|
}}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
Calendar.displayName = "Calendar"
|
|
|
|
export { Calendar }
|