agroptima-design-system 0.30.3 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agroptima-design-system",
3
- "version": "0.30.3",
3
+ "version": "0.31.0",
4
4
  "scripts": {
5
5
  "dev": "npm run storybook",
6
6
  "storybook": "storybook dev -p 6006 --ci",
@@ -0,0 +1,58 @@
1
+ import 'react-day-picker/style.css'
2
+ import './DatePicker.scss'
3
+ import { type DateRange, type Locale } from 'react-day-picker'
4
+ import { classNames } from '../../utils/classNames'
5
+ import { DateRangePicker } from './DateRangePicker'
6
+ import { DateSinglePicker } from './DateSinglePicker'
7
+
8
+ export type Variant = 'primary'
9
+ export type DatePickerType = 'single' | 'range'
10
+
11
+ type DivPropsWithoutOnSelect = Omit<
12
+ React.ComponentPropsWithoutRef<'div'>,
13
+ 'onSelect'
14
+ >
15
+
16
+ export interface AvailableLocale {
17
+ [index: string]: Locale
18
+ }
19
+
20
+ export interface DatePickerBaseProps extends DivPropsWithoutOnSelect {
21
+ variant?: Variant
22
+ lng: keyof AvailableLocale
23
+ type: DatePickerType
24
+ }
25
+
26
+ export interface DateSinglePickerProps {
27
+ type: 'single'
28
+ selected?: Date | undefined
29
+ onSelect: (date: Date | undefined) => void
30
+ }
31
+
32
+ export interface DateRangePickerProps {
33
+ type: 'range'
34
+ selected?: DateRange | undefined
35
+ onSelect: (date: DateRange | undefined) => void
36
+ }
37
+
38
+ type DatePickerProps = (DateSinglePickerProps | DateRangePickerProps) &
39
+ DatePickerBaseProps
40
+
41
+ export function DatePicker(props: DatePickerProps): React.JSX.Element {
42
+ const { variant, className, type, lng, onSelect, selected } = props
43
+
44
+ const cssClasses = classNames('date-picker', variant, className)
45
+
46
+ if (type === 'single') {
47
+ return (
48
+ <div className={cssClasses}>
49
+ <DateSinglePicker lng={lng} selected={selected} onSelect={onSelect} />
50
+ </div>
51
+ )
52
+ }
53
+ return (
54
+ <div className={cssClasses}>
55
+ <DateRangePicker lng={lng} selected={selected} onSelect={onSelect} />
56
+ </div>
57
+ )
58
+ }
@@ -1,60 +1,32 @@
1
1
  import 'react-day-picker/style.css'
2
- import './DateRangePicker.scss'
3
2
  import { useEffect, useState } from 'react'
4
3
  import { type DateRange, DayPicker, type Locale } from 'react-day-picker'
5
4
  import { enGB, es } from 'react-day-picker/locale'
6
- import { classNames } from '../../utils/classNames'
7
- import {
8
- formatDatePickerFooterDate,
9
- formatDatePickerParamsDate,
10
- } from '../../utils/dateHelpers'
5
+ import { formatDatePickerFooterDate } from '../../utils/dateHelpers'
6
+ import type { AvailableLocale } from './DatePicker'
11
7
  import { translations } from './translations'
12
8
 
13
- export type Variant = 'primary'
14
-
15
- type DivPropsWithoutOnSelect = Omit<
16
- React.ComponentPropsWithoutRef<'div'>,
17
- 'onSelect'
18
- >
19
-
20
- interface AvailableLocale {
21
- [index: string]: Locale
22
- }
23
-
24
9
  const availableLocales: AvailableLocale = {
25
10
  es: es,
26
11
  en: enGB,
27
12
  }
28
13
 
29
- export interface DateRangePickerProps extends DivPropsWithoutOnSelect {
30
- variant?: Variant
14
+ export interface DateRangePickerProps {
31
15
  onSelect: (dateRange: DateRange | undefined) => void
32
16
  selected?: DateRange
33
17
  lng: keyof typeof availableLocales
34
18
  }
35
19
 
36
20
  export function DateRangePicker({
37
- className,
38
- variant = 'primary',
39
21
  onSelect = () => {},
40
22
  selected: preselected,
41
23
  lng,
42
24
  }: DateRangePickerProps): React.JSX.Element {
43
25
  const manageFooterText = (): string => {
44
26
  const hasDatesFilter = selected && selected.from && selected.to
45
- const isExactDate =
46
- formatDatePickerParamsDate(selected?.from) ===
47
- formatDatePickerParamsDate(selected?.to)
48
27
 
49
28
  if (!hasDatesFilter) return translations[lng].pickDate
50
29
 
51
- if (isExactDate) {
52
- return translations[lng].selectedDate.replace(
53
- '${date}',
54
- formatDatePickerFooterDate(selected.from, lng as string),
55
- )
56
- }
57
-
58
30
  return translations[lng].selectedRangeOfDates
59
31
  .replace(
60
32
  '${from}',
@@ -67,7 +39,6 @@ export function DateRangePicker({
67
39
  const [footer, setFooter] = useState<string>(() => {
68
40
  return manageFooterText()
69
41
  })
70
- const cssClasses = classNames('date-picker', variant, className)
71
42
 
72
43
  useEffect(() => {
73
44
  setSelected(preselected)
@@ -76,18 +47,12 @@ export function DateRangePicker({
76
47
  }, [preselected])
77
48
 
78
49
  function selectDate(dateRange: DateRange | undefined) {
79
- const isSingleDaySelection = dateRange && !dateRange.to
80
-
81
- if (isSingleDaySelection) {
82
- dateRange.to = dateRange.from
83
- }
84
-
85
50
  setSelected(dateRange)
86
51
  onSelect(dateRange)
87
52
  }
88
53
 
89
54
  return (
90
- <div className={cssClasses}>
55
+ <>
91
56
  <DayPicker
92
57
  locale={availableLocales[lng]}
93
58
  mode="range"
@@ -97,6 +62,6 @@ export function DateRangePicker({
97
62
  footer={footer}
98
63
  defaultMonth={selected?.from}
99
64
  />
100
- </div>
65
+ </>
101
66
  )
102
67
  }
@@ -0,0 +1,67 @@
1
+ import 'react-day-picker/style.css'
2
+ import { useEffect, useState } from 'react'
3
+ import { DayPicker } from 'react-day-picker'
4
+ import { enGB, es } from 'react-day-picker/locale'
5
+ import { formatDatePickerFooterDate } from '../../utils/dateHelpers'
6
+ import type { AvailableLocale } from './DatePicker'
7
+ import { translations } from './translations'
8
+
9
+ const availableLocales: AvailableLocale = {
10
+ es: es,
11
+ en: enGB,
12
+ }
13
+
14
+ export interface DateSinglePickerProps {
15
+ onSelect: (date: Date | undefined) => void
16
+ selected?: Date
17
+ lng: keyof typeof availableLocales
18
+ }
19
+
20
+ export function DateSinglePicker({
21
+ onSelect = () => {},
22
+ selected: preselected,
23
+ lng,
24
+ }: DateSinglePickerProps): React.JSX.Element {
25
+ const manageFooterText = (): string => {
26
+ if (!selected) return translations[lng].pickSingleDate
27
+
28
+ return translations[lng].selectedDate.replace(
29
+ '${date}',
30
+ formatDatePickerFooterDate(selected, lng as string),
31
+ )
32
+ }
33
+
34
+ const [selected, setSelected] = useState<Date | undefined>(preselected)
35
+ const [month, setMonth] = useState<Date | undefined>(preselected)
36
+ const [footer, setFooter] = useState<string>(() => {
37
+ return manageFooterText()
38
+ })
39
+
40
+ useEffect(() => {
41
+ setSelected(preselected)
42
+ setMonth(preselected)
43
+ setFooter(manageFooterText())
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [preselected])
46
+
47
+ function selectDate(date: Date | undefined) {
48
+ setSelected(date)
49
+ if (date) setMonth(new Date(date.getFullYear(), date.getMonth()))
50
+ onSelect(date)
51
+ }
52
+
53
+ return (
54
+ <>
55
+ <DayPicker
56
+ locale={availableLocales[lng]}
57
+ mode="single"
58
+ selected={selected}
59
+ onSelect={(date) => selectDate(date)}
60
+ footer={footer}
61
+ required
62
+ month={month}
63
+ onMonthChange={(date) => setMonth(date)}
64
+ />
65
+ </>
66
+ )
67
+ }
@@ -5,11 +5,13 @@ interface Translation {
5
5
  export const translations: Translation = {
6
6
  en: {
7
7
  pickDate: 'Pick a day or a range of dates',
8
+ pickSingleDate: 'Pick a date',
8
9
  selectedDate: 'Selected date: ${date}',
9
10
  selectedRangeOfDates: 'Selected dates range: from ${from} to ${to}',
10
11
  },
11
12
  es: {
12
13
  pickDate: 'Selecciona un día o un rango de fechas',
14
+ pickSingleDate: 'Selecciona una fecha',
13
15
  selectedDate: 'Fecha seleccionada: ${date}',
14
16
  selectedRangeOfDates: 'Rango de fechas seleccionado: desde ${from} a ${to}',
15
17
  },
@@ -4,6 +4,13 @@ import { Meta } from "@storybook/blocks";
4
4
 
5
5
  # Changelog
6
6
 
7
+ ## 0.31.0
8
+
9
+ * DatePicker option for a single day created.
10
+ * Updated the footer message for a single day date picker, and add month selection.
11
+ * DatePicker component now is a wrapper for the single and range options to select.
12
+ * DateRangePicker component refactored to DatePicker.
13
+
7
14
  ## 0.30.3
8
15
 
9
16
  * Autofocus on search input in the Select and MultiSelect components.
@@ -1,9 +1,9 @@
1
1
  import type { StoryObj } from '@storybook/react'
2
- import { DateRangePicker } from '../atoms/DatePicker/DateRangePicker'
2
+ import { DatePicker } from '../atoms/DatePicker/DatePicker'
3
3
 
4
4
  const meta = {
5
- title: 'Design System/Atoms/DateRangePicker',
6
- component: DateRangePicker,
5
+ title: 'Design System/Atoms/DatePicker',
6
+ component: DatePicker,
7
7
  parameters: {
8
8
  docs: {
9
9
  description: {
@@ -14,9 +14,6 @@ const meta = {
14
14
  },
15
15
  tags: ['autodocs'],
16
16
  argTypes: {
17
- footer: {
18
- description: 'Text for the footer',
19
- },
20
17
  variant: {
21
18
  description: 'Component variant used',
22
19
  },
@@ -29,6 +26,9 @@ const meta = {
29
26
  lng: {
30
27
  description: 'String with the locale to be used on the translations',
31
28
  },
29
+ type: {
30
+ description: 'Type of date that could be range or single',
31
+ },
32
32
  },
33
33
  }
34
34
 
@@ -42,21 +42,21 @@ const figmaPrimaryDesign = {
42
42
  export default meta
43
43
  type Story = StoryObj<typeof meta>
44
44
 
45
- export const Primary: Story = {
45
+ export const SingleDatePicker: Story = {
46
46
  args: {
47
47
  variant: 'primary',
48
48
  onSelect: (date) => console.log('onSelect date:', date),
49
49
  lng: 'en',
50
+ type: 'single',
50
51
  },
51
- parameters: figmaPrimaryDesign,
52
52
  }
53
53
 
54
- export const WithDateRangeSelected: Story = {
54
+ export const RangeDatePicker: Story = {
55
55
  args: {
56
56
  variant: 'primary',
57
57
  onSelect: (date) => console.log('onSelect date:', date),
58
- selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 15) },
59
58
  lng: 'en',
59
+ type: 'range',
60
60
  },
61
61
  parameters: figmaPrimaryDesign,
62
62
  }
@@ -65,8 +65,20 @@ export const WithSingleDaySelected: Story = {
65
65
  args: {
66
66
  variant: 'primary',
67
67
  onSelect: (date) => console.log('onSelect date:', date),
68
- selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 2) },
68
+ selected: new Date(2024, 1, 2),
69
+ lng: 'en',
70
+ type: 'single',
71
+ },
72
+ parameters: figmaPrimaryDesign,
73
+ }
74
+
75
+ export const WithRangeDateSelected: Story = {
76
+ args: {
77
+ variant: 'primary',
78
+ onSelect: (date) => console.log('onSelect date:', date),
79
+ selected: { from: new Date(2024, 1, 2), to: new Date(2024, 1, 12) },
69
80
  lng: 'en',
81
+ type: 'range',
70
82
  },
71
83
  parameters: figmaPrimaryDesign,
72
84
  }
@@ -0,0 +1,48 @@
1
+ import { render } from '@testing-library/react'
2
+ import React from 'react'
3
+ import { DatePicker } from '../src/atoms/DatePicker/DatePicker'
4
+
5
+ describe('DatePicker', () => {
6
+ it('renders with expected footer, language and month for a range type', () => {
7
+ const { getByText } = render(
8
+ <DatePicker
9
+ selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
10
+ onSelect={() => jest.fn()}
11
+ lng={'es'}
12
+ type="range"
13
+ />,
14
+ )
15
+
16
+ expect(getByText('enero 2025')).toBeInTheDocument()
17
+ expect(getByText('lu')).toBeInTheDocument()
18
+ expect(getByText('ma')).toBeInTheDocument()
19
+ expect(getByText('mi')).toBeInTheDocument()
20
+ expect(getByText('ju')).toBeInTheDocument()
21
+ expect(getByText('vi')).toBeInTheDocument()
22
+ expect(getByText('sá')).toBeInTheDocument()
23
+ expect(getByText('do')).toBeInTheDocument()
24
+ expect(
25
+ getByText('Rango de fechas seleccionado: desde 1/1/2025 a 15/1/2025'),
26
+ ).toBeInTheDocument()
27
+ })
28
+ it('renders with expected footer, language and month for a single type', () => {
29
+ const { getByText } = render(
30
+ <DatePicker
31
+ selected={new Date(2025, 1, 15)}
32
+ onSelect={() => jest.fn()}
33
+ lng={'es'}
34
+ type="single"
35
+ />,
36
+ )
37
+
38
+ expect(getByText('febrero 2025')).toBeInTheDocument()
39
+ expect(getByText('lu')).toBeInTheDocument()
40
+ expect(getByText('ma')).toBeInTheDocument()
41
+ expect(getByText('mi')).toBeInTheDocument()
42
+ expect(getByText('ju')).toBeInTheDocument()
43
+ expect(getByText('vi')).toBeInTheDocument()
44
+ expect(getByText('sá')).toBeInTheDocument()
45
+ expect(getByText('do')).toBeInTheDocument()
46
+ expect(getByText('Fecha seleccionada: 15/2/2025')).toBeInTheDocument()
47
+ })
48
+ })
@@ -1,26 +0,0 @@
1
- import { getAllByRole, render } from '@testing-library/react'
2
- import React from 'react'
3
- import { DateRangePicker } from '../src/atoms/DatePicker/DateRangePicker'
4
-
5
- describe('DateRangePicker', () => {
6
- it('renders with expected footer, language and month', () => {
7
- const { getByText } = render(
8
- <DateRangePicker
9
- selected={{ from: new Date(2025, 0, 1), to: new Date(2025, 0, 15) }}
10
- onSelect={() => jest.fn()}
11
- lng={'es'}
12
- />,
13
- )
14
- expect(getByText('enero 2025')).toBeInTheDocument()
15
- expect(getByText('lu')).toBeInTheDocument()
16
- expect(getByText('ma')).toBeInTheDocument()
17
- expect(getByText('mi')).toBeInTheDocument()
18
- expect(getByText('ju')).toBeInTheDocument()
19
- expect(getByText('vi')).toBeInTheDocument()
20
- expect(getByText('sá')).toBeInTheDocument()
21
- expect(getByText('do')).toBeInTheDocument()
22
- expect(
23
- getByText('Rango de fechas seleccionado: desde 1/1/2025 a 15/1/2025'),
24
- ).toBeInTheDocument()
25
- })
26
- })