From 88ddc7e8725bc89ed0dfb07919dc796921eb1166 Mon Sep 17 00:00:00 2001 From: IvanHoncharenko Date: Wed, 14 Jun 2023 13:54:41 +0300 Subject: [PATCH 1/4] MonthPicker implemented --- src/components/IconButton/IconButton.tsx | 2 +- src/components/Icons/ArrowLeftIcon.tsx | 17 ++++ src/components/Icons/ArrowRightIcon.tsx | 17 ++++ src/components/Icons/interfaces/IIcons.ts | 3 + src/components/MonthPicker/MonthPicker.tsx | 70 +++++++++++++++ .../MonthPicker/interfaces/IMonthPicker.ts | 18 ++++ .../MonthPicker/sass/MonthPicker.module.scss | 86 +++++++++++++++++++ src/constants/common.ts | 13 +++ src/sass/colors.scss | 1 + src/sass/main.scss | 1 + src/stories/MonthPicker.stories.tsx | 15 ++++ src/utils/helpers.ts | 28 ++++++ 12 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 src/components/Icons/ArrowLeftIcon.tsx create mode 100644 src/components/Icons/ArrowRightIcon.tsx create mode 100644 src/components/Icons/interfaces/IIcons.ts create mode 100644 src/components/MonthPicker/MonthPicker.tsx create mode 100644 src/components/MonthPicker/interfaces/IMonthPicker.ts create mode 100644 src/components/MonthPicker/sass/MonthPicker.module.scss create mode 100644 src/constants/common.ts create mode 100644 src/stories/MonthPicker.stories.tsx create mode 100644 src/utils/helpers.ts diff --git a/src/components/IconButton/IconButton.tsx b/src/components/IconButton/IconButton.tsx index b2e332e..d8f9271 100644 --- a/src/components/IconButton/IconButton.tsx +++ b/src/components/IconButton/IconButton.tsx @@ -1,7 +1,7 @@ import React from 'react'; +import { IconButtonColors, IconButtonSizes } from '../../constants/general'; import styles from './sass/IconButton.module.scss'; import { IconButtonProps } from './interfaces/IIconButton'; -import { IconButtonColors, IconButtonSizes } from '../../constants/general'; const IconButton: React.FC = ({ size = IconButtonSizes.Medium, diff --git a/src/components/Icons/ArrowLeftIcon.tsx b/src/components/Icons/ArrowLeftIcon.tsx new file mode 100644 index 0000000..7506722 --- /dev/null +++ b/src/components/Icons/ArrowLeftIcon.tsx @@ -0,0 +1,17 @@ +import React, { FC } from 'react'; +import { IIconsProps } from './interfaces/IIcons'; + +const AttachmentIcon: FC = ({ fill = 'currentColor' }) => ( + + + + +); + +export default AttachmentIcon; diff --git a/src/components/Icons/ArrowRightIcon.tsx b/src/components/Icons/ArrowRightIcon.tsx new file mode 100644 index 0000000..7eea2cc --- /dev/null +++ b/src/components/Icons/ArrowRightIcon.tsx @@ -0,0 +1,17 @@ +import React, { FC } from 'react'; +import { IIconsProps } from './interfaces/IIcons'; + +const AttachmentIcon: FC = ({ fill = 'currentColor' }) => ( + + + + +); + +export default AttachmentIcon; diff --git a/src/components/Icons/interfaces/IIcons.ts b/src/components/Icons/interfaces/IIcons.ts new file mode 100644 index 0000000..00adcf0 --- /dev/null +++ b/src/components/Icons/interfaces/IIcons.ts @@ -0,0 +1,3 @@ +export interface IIconsProps { + fill?: string, +} diff --git a/src/components/MonthPicker/MonthPicker.tsx b/src/components/MonthPicker/MonthPicker.tsx new file mode 100644 index 0000000..f3b21e2 --- /dev/null +++ b/src/components/MonthPicker/MonthPicker.tsx @@ -0,0 +1,70 @@ +import React, { FC, useState } from 'react'; +import IconButton from '../IconButton/IconButton'; +import { parseToMonthInt, parseMonthIntToObj } from '../../utils/helpers'; +import { DEFAULT_MONTH_INT, DEFAULT_YEAR_RANGE, MONTHS } from '../../constants/common'; +import ArrowLeftIcon from '../Icons/ArrowLeftIcon'; +import ArrowRightIcon from '../Icons/ArrowRightIcon'; +import styles from './sass/MonthPicker.module.scss'; +import { IMonthPickerProps } from './interfaces/IMonthPicker'; + +const MonthPicker: FC = ({ + onChange, monthInt = DEFAULT_MONTH_INT, className = '', yearRange = DEFAULT_YEAR_RANGE, +}) => { + const { minYear, maxYear } = yearRange; + const { month, year } = parseMonthIntToObj(monthInt); + const [currentYear, setYear] = useState(year); + + return ( +
+
+ setYear(currentYear - 1)} + onKeyDown={() => {}} + aria-label="prevYear" + aria-disabled={currentYear <= minYear} + icon={} + /> +
+ + {currentYear} + +
+ setYear(currentYear + 1)} + onKeyDown={() => {}} + aria-label="nextYear" + aria-disabled={currentYear >= maxYear} + icon={} + /> +
+
+ {MONTHS.map((item, index) => ( +
{ + onChange({ + month: parseToMonthInt(currentYear, index + 1), + monthIndex: index, + year: currentYear, + monthName: item, + }); + }} + onKeyDown={() => {}} + > + {item} +
+ ))} +
+
+ ); +}; + +export default MonthPicker; diff --git a/src/components/MonthPicker/interfaces/IMonthPicker.ts b/src/components/MonthPicker/interfaces/IMonthPicker.ts new file mode 100644 index 0000000..3467572 --- /dev/null +++ b/src/components/MonthPicker/interfaces/IMonthPicker.ts @@ -0,0 +1,18 @@ +export interface IYearRange { + minYear: number + maxYear: number +} + +export interface IMonthPickerInfo { + month: number + monthIndex: number + year: number + monthName: string, +} + +export interface IMonthPickerProps { + onChange: (value: IMonthPickerInfo) => void + monthInt?: number + className?: string + yearRange?: IYearRange +} diff --git a/src/components/MonthPicker/sass/MonthPicker.module.scss b/src/components/MonthPicker/sass/MonthPicker.module.scss new file mode 100644 index 0000000..19b645c --- /dev/null +++ b/src/components/MonthPicker/sass/MonthPicker.module.scss @@ -0,0 +1,86 @@ +@import "../../../sass/colors"; + +.container { + width: 170px; + background-color: $white; + box-shadow: 0 4px 22px $shadow; + + .year { + height: 32px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 4px; + border-bottom: 1px solid $light-gray; + + .navBtnPrev, .navBtnNext { + position: relative; + width: 24px; + height: 24px; + border-radius: 4px; + transition: .3s; + cursor: pointer; + + &[aria-disabled="true"] { + pointer-events: none; + } + + &:before { + position: absolute; + content: ""; + width: 24px; + height: 24px; + + background: { + repeat: no-repeat; + position: center; + }; + } + + &:hover { + background-color: $outlined-hover; + } + } + + .selectedYear { + font-weight: bold; + font-size: 13px; + line-height: 16px; + color: #000000; + } + } + + .months { + display: flex; + flex-wrap: wrap; + + .month { + width: 50%; + text-align: center; + font-size: 13px; + line-height: 16px; + padding: 8px; + cursor: pointer; + transition: .3s; + border-bottom: 1px solid $light-gray; + + + &.selected { + color: $white; + background-color: $primary; + + &:hover { + color: $dark-gray; + } + } + + &:nth-child(even) { + border-left: 1px solid $light-gray; + } + + &:hover { + background-color: $light-blue; + } + } + } +} diff --git a/src/constants/common.ts b/src/constants/common.ts new file mode 100644 index 0000000..3a811cf --- /dev/null +++ b/src/constants/common.ts @@ -0,0 +1,13 @@ +import { getMonthIntFromDate } from '../utils/helpers'; + +export const MONTHS = [ + 'January', 'February', 'March', 'April', 'May', 'June', 'July', + 'August', 'September', 'October', 'November', 'December', +]; + +export const DEFAULT_YEAR_RANGE = { + minYear: 2000, + maxYear: 2100, +}; + +export const DEFAULT_MONTH_INT = getMonthIntFromDate().monthInt; diff --git a/src/sass/colors.scss b/src/sass/colors.scss index b929c6d..b73b649 100644 --- a/src/sass/colors.scss +++ b/src/sass/colors.scss @@ -17,3 +17,4 @@ $light-gray: #EBEEF2; $light-gray-2: #C4C4C4; $light-yellow: #FDFAEB; $transparent: #FFFFFF00; +$shadow: #2B2C3028; diff --git a/src/sass/main.scss b/src/sass/main.scss index 3686a00..b38d802 100644 --- a/src/sass/main.scss +++ b/src/sass/main.scss @@ -1,3 +1,4 @@ * { + box-sizing: border-box; font-family: -apple-system,Inter,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; } diff --git a/src/stories/MonthPicker.stories.tsx b/src/stories/MonthPicker.stories.tsx new file mode 100644 index 0000000..baf5520 --- /dev/null +++ b/src/stories/MonthPicker.stories.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import MonthPicker from '../components/MonthPicker/MonthPicker'; + +export default { + title: 'Example/MonthPicker', + component: MonthPicker, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + onChange: () => {}, +}; diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts new file mode 100644 index 0000000..acc6649 --- /dev/null +++ b/src/utils/helpers.ts @@ -0,0 +1,28 @@ +export const getMonthIntFromDate = (date = new Date()) => { + const month = date.getMonth(); + const year = date.getFullYear(); + const monthInt = +(`${year}${month < 9 ? `0${month + 1}` : month + 1}`); + + return { monthInt, month, year }; +}; + +export const parseToMonthInt = (year: number, month: number) => ( + parseInt(`${year}${month >= 10 ? month : `0${month}`}`) +); + +export const parseMonthIntToObj = (monthInt?: number) => { + let year; + let month; + + if (monthInt) { + const str = monthInt.toString(); + year = parseInt(str.slice(0, 4)); + month = +str.slice(4) - 1; + } else { + const date = new Date(); + year = date.getFullYear(); + month = date.getMonth(); + } + + return { month, year }; +}; From a10259f345d1def3db4f33ced612822a4c19209b Mon Sep 17 00:00:00 2001 From: IvanHoncharenko Date: Wed, 14 Jun 2023 16:01:19 +0300 Subject: [PATCH 2/4] Month picker removed unnecessary lines --- src/components/MonthPicker/MonthPicker.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/MonthPicker/MonthPicker.tsx b/src/components/MonthPicker/MonthPicker.tsx index f3b21e2..588af6a 100644 --- a/src/components/MonthPicker/MonthPicker.tsx +++ b/src/components/MonthPicker/MonthPicker.tsx @@ -35,7 +35,6 @@ const MonthPicker: FC = ({ setYear(currentYear + 1)} - onKeyDown={() => {}} aria-label="nextYear" aria-disabled={currentYear >= maxYear} icon={} From 2b98ebf6aa5ff40814c354affc3dad3287bdf839 Mon Sep 17 00:00:00 2001 From: IvanHoncharenko Date: Wed, 14 Jun 2023 16:01:34 +0300 Subject: [PATCH 3/4] Month picker removed unnecessary lines --- src/components/MonthPicker/MonthPicker.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/MonthPicker/MonthPicker.tsx b/src/components/MonthPicker/MonthPicker.tsx index 588af6a..240e972 100644 --- a/src/components/MonthPicker/MonthPicker.tsx +++ b/src/components/MonthPicker/MonthPicker.tsx @@ -20,7 +20,6 @@ const MonthPicker: FC = ({ setYear(currentYear - 1)} - onKeyDown={() => {}} aria-label="prevYear" aria-disabled={currentYear <= minYear} icon={} From d21b2ca3c3b8ffee8553302228768fab7e2b0f0b Mon Sep 17 00:00:00 2001 From: IvanHoncharenko Date: Wed, 14 Jun 2023 16:15:11 +0300 Subject: [PATCH 4/4] Month picker styles updated --- src/components/MonthPicker/MonthPicker.tsx | 5 ++++- src/components/MonthPicker/sass/MonthPicker.module.scss | 4 +--- src/stories/MonthPicker.stories.tsx | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/MonthPicker/MonthPicker.tsx b/src/components/MonthPicker/MonthPicker.tsx index 240e972..ddd9bd9 100644 --- a/src/components/MonthPicker/MonthPicker.tsx +++ b/src/components/MonthPicker/MonthPicker.tsx @@ -8,7 +8,10 @@ import styles from './sass/MonthPicker.module.scss'; import { IMonthPickerProps } from './interfaces/IMonthPicker'; const MonthPicker: FC = ({ - onChange, monthInt = DEFAULT_MONTH_INT, className = '', yearRange = DEFAULT_YEAR_RANGE, + onChange, + monthInt = DEFAULT_MONTH_INT, + yearRange = DEFAULT_YEAR_RANGE, + className = '', }) => { const { minYear, maxYear } = yearRange; const { month, year } = parseMonthIntToObj(monthInt); diff --git a/src/components/MonthPicker/sass/MonthPicker.module.scss b/src/components/MonthPicker/sass/MonthPicker.module.scss index 19b645c..af9482a 100644 --- a/src/components/MonthPicker/sass/MonthPicker.module.scss +++ b/src/components/MonthPicker/sass/MonthPicker.module.scss @@ -64,10 +64,8 @@ transition: .3s; border-bottom: 1px solid $light-gray; - &.selected { - color: $white; - background-color: $primary; + color: $primary; &:hover { color: $dark-gray; diff --git a/src/stories/MonthPicker.stories.tsx b/src/stories/MonthPicker.stories.tsx index baf5520..b5c21ee 100644 --- a/src/stories/MonthPicker.stories.tsx +++ b/src/stories/MonthPicker.stories.tsx @@ -12,4 +12,9 @@ const Template: ComponentStory = (args) => {}, + yearRange: { + minYear: 2020, + maxYear: 2025, + }, + monthInt: 202310, };