Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@
"autoprefixer": "^10.4.22",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"lucide-react": "^0.553.0",
"next-themes": "^0.4.6",
"postcss": "^8.5.6",
"react": "^18.3.1",
"react-day-picker": "^9.11.3",
"react-dom": "^18.3.1",
"react-router-dom": "^7.9.6",
"react-router-dom": "^7.10.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
Expand Down
60 changes: 43 additions & 17 deletions client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./base";
export * from "./examples";
export * from "./library";
39 changes: 39 additions & 0 deletions client/src/components/library/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
AlertDialog,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";

export interface ConfirmationDialogProps {
open: boolean;
title: string;
text: string;
buttons: React.ReactNode;
}

/**
* Reusable confirmation dialog component
*
* @component
*/
export const ConfirmationDialog = ({
open,
title,
text,
buttons,
}: ConfirmationDialogProps) => {
return (
<AlertDialog open={open}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{title}</AlertDialogTitle>
<AlertDialogDescription>{text}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>{buttons}</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};
81 changes: 81 additions & 0 deletions client/src/components/library/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { format } from "date-fns";
import { Calendar as CalendarIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";

export interface DatePickerProps {
value: string | null; // YYYY-MM-DD
onChange: (value: string | null) => void;
label?: string;
placeholder?: string;
maxDate?: Date;
minDate?: Date;
disabled?: boolean;
}

/**
* Date picker component using shadcn calendar
*
* @component
*/
export const DatePicker = ({
value,
onChange,
placeholder = "Pick a date",
maxDate,
minDate,
disabled = false,
}: DatePickerProps) => {
const dateValue = value
? (() => {
const [year, month, day] = value.split("-").map(Number);
return new Date(year, month - 1, day);
})()
: undefined;

const handleSelect = (date: Date | undefined) => {
if (date) {
// Format as YYYY-MM-DD for consistency
const formattedDate = format(date, "yyyy-MM-dd");
onChange(formattedDate);
} else {
onChange(null);
}
};

return (
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className={`w-full justify-start text-left font-normal ${dateValue ? "text-muted-foreground" : ""}`}
disabled={disabled}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{dateValue ? (
format(dateValue, "PPP")
) : (
<span>{placeholder}</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={dateValue}
onSelect={handleSelect}
disabled={(date) => {
if (maxDate && date > maxDate) return true;
if (minDate && date < minDate) return true;
return false;
}}
/>
</PopoverContent>
</Popover>
);
};
2 changes: 2 additions & 0 deletions client/src/components/library/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./ConfirmationDialog";
export * from "./DatePicker";
Loading