Skip to content

Instantly share code, notes, and snippets.

@mdsohelmia
Forked from tanishqsh/DOBPicker.tsx
Created September 22, 2024 15:39
Show Gist options
  • Save mdsohelmia/bf90dd11abf10a12655211ee20b94e0f to your computer and use it in GitHub Desktop.
Save mdsohelmia/bf90dd11abf10a12655211ee20b94e0f to your computer and use it in GitHub Desktop.

Revisions

  1. @tanishqsh tanishqsh created this gist Jul 3, 2023.
    141 changes: 141 additions & 0 deletions DOBPicker.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,141 @@
    /**
    /DOBPicker.tsx
    **/

    'use client';

    import * as React from 'react';
    import { format, subYears } from 'date-fns';
    import { cn } from '@/lib/utils';
    import { Button } from '@/components/ui/button';
    import { Calendar } from '@/components/ui/calendar';
    import { buttonVariants } from '@/components/ui/button';

    import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';

    export function DOBPicker({ dob, setDOB }: { dob: Date | undefined; setDOB: React.Dispatch<React.SetStateAction<Date | undefined>> }) {
    /**
    * The maximum date that can be selected is 18 years ago
    */
    const maxDate = subYears(new Date(), 18);

    return (
    <div className="w-full">
    <Popover>
    <PopoverTrigger asChild>
    <Button
    variant={'default'}
    className={cn('w-full justify-start font-mono text-left font-normal bg-white/5', !dob && 'text-muted-foreground')}
    >
    <svg className="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24">
    <path
    stroke="currentColor"
    stroke-linecap="round"
    stroke-linejoin="round"
    stroke-width="1.5"
    d="M4.75 8.75C4.75 7.64543 5.64543 6.75 6.75 6.75H17.25C18.3546 6.75 19.25 7.64543 19.25 8.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H6.75C5.64543 19.25 4.75 18.3546 4.75 17.25V8.75Z"
    ></path>
    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M8 4.75V8.25"></path>
    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M16 4.75V8.25"></path>
    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M7.75 10.75H16.25"></path>
    </svg>

    {dob ? format(dob, 'PPP') : <span>Date of Birth</span>}
    </Button>
    </PopoverTrigger>
    <PopoverContent className="w-full p-0 font-mono text-white bg-black border border-white/10">
    <Calendar
    classNames={{
    cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-white/5 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
    day: cn(
    buttonVariants({ variant: 'ghost' }),
    'h-9 w-9 p-0 font-normal aria-selected:opacity-100 hover:bg-languid-lavendar/10 hover:text-white/40'
    ),
    day_selected: 'rounded-full bg-languid-lavendar hover:bg-white/10 text-primary-foreground',
    caption_label: 'hidden',
    caption_dropdowns: 'flex w-full items-center justify-center space-x-2',
    }}
    mode="single"
    selected={dob}
    fromDate={subYears(new Date(), 100)}
    toDate={maxDate}
    captionLayout="dropdown"
    onSelect={setDOB}
    defaultMonth={new Date(dob?.getFullYear() ?? maxDate.getFullYear(), dob?.getMonth() ?? maxDate.getMonth(), 1)}
    required
    initialFocus
    className="border rounded-md border-white/10"
    />
    </PopoverContent>
    </Popover>
    </div>
    );
    }

    export default DOBPicker;

    /**
    /ui/calendar.tsx
    **/

    'use client';

    import * as React from 'react';
    import { ChevronLeft, ChevronRight } from 'lucide-react';
    import { DayPicker } from 'react-day-picker';

    import { cn } from '@/lib/utils';
    import { buttonVariants } from '@/components/ui/button';

    export type CalendarProps = React.ComponentProps<typeof DayPicker>;

    function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
    return (
    <DayPicker
    showOutsideDays={showOutsideDays}
    className={cn('p-3', className)}
    classNames={{
    months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
    month: 'space-y-4',
    caption: 'flex justify-center pt-1 relative items-center',
    caption_label: 'text-sm font-medium hidden',
    nav: 'space-x-1 flex items-center',
    nav_button: cn(buttonVariants({ variant: 'outline' }), 'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100'),
    nav_button_previous: 'absolute left-1 border border-white/20',
    nav_button_next: 'absolute right-1 border border-white/20',
    table: 'w-full border-collapse space-y-1',
    head_row: 'flex',
    head_cell: 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
    row: 'flex w-full mt-2',
    cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
    day: cn(buttonVariants({ variant: 'ghost' }), 'h-9 w-9 p-0 font-normal aria-selected:opacity-100'),
    day_selected:
    'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
    day_today: 'bg-accent text-accent-foreground',
    day_outside: 'text-muted-foreground opacity-50',
    day_disabled: 'text-muted-foreground opacity-50',
    day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
    day_hidden: 'invisible',
    ...classNames,
    }}
    components={{
    Dropdown: ({ ...props }) => (
    <div className="w-full">
    <select
    autoFocus
    {...props}
    className="w-full px-1 py-2 space-x-4 text-sm text-white transition-all duration-300 rounded-md outline-none bg-white/5 hover:bg-white/10 focus-outline:none"
    />
    </div>
    ),
    IconLeft: ({ ...props }) => <ChevronLeft className="w-4 h-4" />,
    IconRight: ({ ...props }) => <ChevronRight className="w-4 h-4" />,
    }}
    {...props}
    />
    );
    }
    Calendar.displayName = 'Calendar';

    export { Calendar };