Skip to content

Commit

Permalink
feat: update components and add comments (back) to make Martin happy
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbrusegard committed Oct 28, 2024
1 parent 433de7d commit 2fee9e2
Show file tree
Hide file tree
Showing 14 changed files with 494 additions and 100 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"previousMonth": "Previous month",
"selectMonth": "Select month",
"selectYear": "Select year",
"pickDate": "Pick a date"
"pickDate": "Pick a date",
"dateFormat": "dd/MM/yyyy"
},
"error": {
"notFound": "404 - Page not found",
Expand Down
3 changes: 2 additions & 1 deletion messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"previousMonth": "Forrige måned",
"selectMonth": "Velg måned",
"selectYear": "Velg år",
"pickDate": "Velg en dato"
"pickDate": "Velg en dato",
"dateFormat": "dd.MM.yyyy"
},
"error": {
"notFound": "404 - Siden ble ikke funnet",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"reading-time": "^1.5.0",
"superjson": "^2.2.1",
"tailwind-merge": "^2.5.2",
"vaul": "^1.1.0",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
5 changes: 2 additions & 3 deletions postcss.config.ts → postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Config } from 'postcss-load-config';

const config: Config = {
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
Expand Down
50 changes: 26 additions & 24 deletions src/components/composites/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
'use client';

import { Button, type buttonVariants } from '@/components/ui/Button';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/Dialog';
ResponsiveDialog,
ResponsiveDialogClose,
ResponsiveDialogContent,
ResponsiveDialogDescription,
ResponsiveDialogFooter,
ResponsiveDialogHeader,
ResponsiveDialogTitle,
ResponsiveDialogTrigger,
} from '@/components/composites/ResponsiveDialog';
import { Button, type buttonVariants } from '@/components/ui/Button';
import type { VariantProps } from '@/lib/utils';
import { useState } from 'react';

Expand All @@ -30,21 +30,23 @@ function ConfirmDialog({ confirmAction, t, ...props }: ConfirmDialogProps) {
const [open, setOpen] = useState(false);

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<ResponsiveDialog open={open} onOpenChange={setOpen}>
<ResponsiveDialogTrigger asChild>
<Button variant='destructive' {...props} />
</DialogTrigger>
<DialogContent className='sm:max-w-md'>
<DialogHeader>
<DialogTitle>{t.title}</DialogTitle>
<DialogDescription>{t.description}</DialogDescription>
</DialogHeader>
<DialogFooter className='flex w-full gap-2 sm:justify-between'>
<DialogClose asChild>
</ResponsiveDialogTrigger>
<ResponsiveDialogContent className='sm:max-w-md'>
<ResponsiveDialogHeader>
<ResponsiveDialogTitle>{t.title}</ResponsiveDialogTitle>
<ResponsiveDialogDescription>
{t.description}
</ResponsiveDialogDescription>
</ResponsiveDialogHeader>
<ResponsiveDialogFooter className='flex w-full gap-2 sm:justify-between'>
<ResponsiveDialogClose asChild>
<Button type='button' variant='secondary'>
{t.cancel}
</Button>
</DialogClose>
</ResponsiveDialogClose>
<Button
variant='destructive'
onClick={() => {
Expand All @@ -54,9 +56,9 @@ function ConfirmDialog({ confirmAction, t, ...props }: ConfirmDialogProps) {
>
{t.confirm}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</ResponsiveDialogFooter>
</ResponsiveDialogContent>
</ResponsiveDialog>
);
}

Expand Down
121 changes: 121 additions & 0 deletions src/components/composites/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use client';

import { isValid, parse } from 'date-fns';
import { CalendarIcon } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useFormatter } from 'next-intl';
import * as React from 'react';
import type { DayPickerProps } from 'react-day-picker';

import { cx } from '@/lib/utils';

import { Button } from '@/components/ui/Button';
import { Calendar } from '@/components/ui/Calendar';
import { Input } from '@/components/ui/Input';
import {
Popover,
PopoverContent,
PopoverTrigger,
} from '@/components/ui/Popover';

type DatePickerProps = {
className?: string;
side?: 'top' | 'bottom' | 'left' | 'right';
avoidCollisions?: boolean;
date: Date | undefined;
setDate: (date: Date | undefined) => void;
id: string;
} & Omit<DayPickerProps, 'selected' | 'onSelect' | 'autoFocus' | 'mode'>;

/**
* This is a sligtly modified version of shadcn's Date Picker built on top of Calendar.
* The component has a state, but also allows adding an additional date callback function which
* provides a way to have side effects and/or state updates on the parent component whenever a new date is selected.
* UPDATE: Now supports an input field so it actually works as a date picker in a form. State is passed to it via props
* so it works in a form. Also included i18n support.
*/
function DatePicker({
className,
side,
avoidCollisions = true,
date,
setDate,
id,
...props
}: DatePickerProps) {
const t = useTranslations('ui');
const format = useFormatter();
const [open, setOpen] = React.useState(false);
const [month, setMonth] = React.useState(date);
const [inputValue, setInputValue] = React.useState('');

function handleSelectDate(date: Date | undefined) {
if (!date) {
setInputValue('');
setDate(undefined);
} else {
setDate(date);
setMonth(date);
setInputValue(
format.dateTime(date, {
day: 'numeric',
month: 'numeric',
year: 'numeric',
}),
);
}
}

function handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
setInputValue(e.target.value);
const parsedDate = parse(e.target.value, t('dateFormat'), new Date());

if (isValid(parsedDate)) {
setMonth(parsedDate);
}
setDate(parsedDate);
}

return (
<Popover open={open} onOpenChange={setOpen}>
<div className='relative'>
<Input
className={className}
id={id}
placeholder={t('dateFormat')}
value={inputValue}
onChange={handleInputChange}
/>
<PopoverTrigger asChild>
<Button
aria-label={t('pickDate')}
variant={'secondary'}
className={cx(
'-translate-y-1/2 absolute top-1/2 right-1.5 h-7 rounded-sm border px-2 font-normal',
!date && 'text-muted-foreground',
)}
>
<CalendarIcon className='h-4 w-4' />
</Button>
</PopoverTrigger>
</div>
<PopoverContent
className='w-auto p-0'
side={side}
avoidCollisions={avoidCollisions}
>
<Calendar
mode='single'
month={month}
onMonthChange={setMonth}
selected={date}
onSelect={handleSelectDate}
autoFocus
{...props}
/>
</PopoverContent>
</Popover>
);
}

export { DatePicker };
Loading

0 comments on commit 2fee9e2

Please sign in to comment.