zaman-backoffice 1.0.0 → 1.0.2

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.
Files changed (115) hide show
  1. package/.eslintrc.cjs +26 -0
  2. package/.husky/commit-msg +4 -0
  3. package/.husky/pre-commit +4 -0
  4. package/.idea/git_toolbox_blame.xml +6 -0
  5. package/.idea/git_toolbox_prj.xml +15 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/material_theme_project_new.xml +12 -0
  8. package/.idea/modules.xml +8 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/.idea/zaman-backoffice2.iml +12 -0
  11. package/.prettierrc +9 -0
  12. package/.travis.yml +10 -0
  13. package/client/index.html +12 -0
  14. package/client/main.tsx +84 -0
  15. package/client/style.css +62 -0
  16. package/cypress/fixtures/example.json +5 -0
  17. package/cypress/support/commands.ts +38 -0
  18. package/cypress/support/component-index.html +12 -0
  19. package/cypress/support/component.ts +39 -0
  20. package/cypress/videos/Calendar/CalendarComponent.cy.tsx.mp4 +0 -0
  21. package/cypress/videos/DatePicker/DatePicker.cy.tsx.mp4 +0 -0
  22. package/cypress.config.ts +10 -0
  23. package/desktop.ini +2 -0
  24. package/help/banner.png +0 -0
  25. package/jest.config.ts +47 -0
  26. package/package.json +1 -1
  27. package/src/components/CalendarItem/CalendarItem.styled.tsx +96 -0
  28. package/src/components/CalendarItem/CalendarItem.types.ts +7 -0
  29. package/src/components/CalendarItem/index.ts +1 -0
  30. package/src/components/CalendarWrapper/CalendarWrapper.styled.tsx +19 -0
  31. package/src/components/CalendarWrapper/index.ts +1 -0
  32. package/src/components/FloatingElement/FloatingElement.styled.tsx +8 -0
  33. package/src/components/FloatingElement/FloatingElement.tsx +83 -0
  34. package/src/components/FloatingElement/FloatingElement.types.ts +8 -0
  35. package/src/components/FloatingElement/index.tsx +1 -0
  36. package/src/components/Header/Header.styled.tsx +40 -0
  37. package/src/components/Header/Header.tsx +46 -0
  38. package/src/components/Header/Header.types.ts +6 -0
  39. package/src/components/Header/index.ts +1 -0
  40. package/src/components/IconButton/IconButton.styled.tsx +22 -0
  41. package/src/components/IconButton/IconButton.tsx +3 -0
  42. package/src/components/IconButton/index.tsx +1 -0
  43. package/src/components/Icons/ChevronLeft/index.tsx +22 -0
  44. package/src/components/Icons/ChevronRight/index.tsx +22 -0
  45. package/src/components/Modal/Modal.styled.tsx +23 -0
  46. package/src/components/Modal/Modal.tsx +29 -0
  47. package/src/components/Modal/index.tsx +1 -0
  48. package/src/components/Modal/types.ts +7 -0
  49. package/src/components/MonthPicker/Month.styled.tsx +11 -0
  50. package/src/components/MonthPicker/MonthPicker.tsx +35 -0
  51. package/src/components/MonthPicker/MonthPicker.types.ts +4 -0
  52. package/src/components/MonthPicker/index.ts +1 -0
  53. package/src/components/RenderCalendar/RenderCalendar.tsx +31 -0
  54. package/src/components/RenderCalendar/RenderCalendar.types.ts +10 -0
  55. package/src/components/RenderCalendar/index.ts +1 -0
  56. package/src/components/YearPicker/YearPicker.styled.tsx +14 -0
  57. package/src/components/YearPicker/YearPicker.tsx +49 -0
  58. package/src/components/YearPicker/YearPicker.types.ts +4 -0
  59. package/src/components/YearPicker/index.ts +1 -0
  60. package/src/constants.ts +6 -0
  61. package/src/hooks/__tests__/useClickOutside.test.tsx +32 -0
  62. package/src/hooks/useCalendarHandlers.tsx +113 -0
  63. package/src/hooks/useClickOutside.tsx +23 -0
  64. package/src/hooks/useSlideCalendar.tsx +95 -0
  65. package/src/hooks/useTimePicker.tsx +95 -0
  66. package/src/index.tsx +4 -0
  67. package/src/packages/Calendar/Calendar.styled.tsx +42 -0
  68. package/src/packages/Calendar/Calendar.tsx +159 -0
  69. package/src/packages/Calendar/Calendar.types.ts +31 -0
  70. package/src/packages/Calendar/CalendarComponent.cy.tsx +69 -0
  71. package/src/packages/Calendar/index.ts +2 -0
  72. package/src/packages/CalendarProvider/CalendarProvider.tsx +30 -0
  73. package/src/packages/CalendarProvider/CalendarProvider.types.ts +6 -0
  74. package/src/packages/CalendarProvider/index.ts +2 -0
  75. package/src/packages/DatePicker/DatePicker.cy.tsx +54 -0
  76. package/src/packages/DatePicker/DatePicker.tsx +127 -0
  77. package/src/packages/DatePicker/DatePicker.types.ts +26 -0
  78. package/src/packages/DatePicker/index.ts +2 -0
  79. package/src/packages/TimePicker/TimePicker.styled.tsx +77 -0
  80. package/src/packages/TimePicker/TimePicker.tsx +121 -0
  81. package/src/packages/TimePicker/TimePicker.types.ts +16 -0
  82. package/src/packages/TimePicker/components/Numbers/Numbers.styled.tsx +36 -0
  83. package/src/packages/TimePicker/components/Numbers/Numbers.tsx +58 -0
  84. package/src/packages/TimePicker/components/Numbers/Numbers.types.ts +14 -0
  85. package/src/packages/TimePicker/components/Numbers/index.ts +1 -0
  86. package/src/packages/TimePicker/index.ts +2 -0
  87. package/src/style/animation.ts +23 -0
  88. package/src/style/classNames.ts +8 -0
  89. package/src/style/colorPallete.ts +16 -0
  90. package/src/style/colors.ts +15 -0
  91. package/src/style/hexToHSL.ts +52 -0
  92. package/src/style/radius.ts +28 -0
  93. package/src/types.ts +75 -0
  94. package/src/utils/dateHelper/dateHelper.ts +67 -0
  95. package/src/utils/dateHelper/index.ts +1 -0
  96. package/src/utils/dateTimeFormat/dateTimeFormat.ts +43 -0
  97. package/src/utils/dateTimeFormat/index.ts +1 -0
  98. package/src/utils/format/format.test.ts +37 -0
  99. package/src/utils/format/format.ts +56 -0
  100. package/src/utils/format/format.types.ts +11 -0
  101. package/src/utils/format/index.ts +1 -0
  102. package/src/utils/index.ts +21 -0
  103. package/src/utils/locale.ts +13 -0
  104. package/src/utils/locales/en.ts +89 -0
  105. package/src/utils/locales/fa.ts +89 -0
  106. package/src/utils/locales/index.ts +10 -0
  107. package/src/utils/locales/locales.types.ts +11 -0
  108. package/src/utils/month/index.ts +1 -0
  109. package/src/utils/month/month.ts +54 -0
  110. package/src/utils/month/month.types.ts +11 -0
  111. package/src/utils/timePicker.ts +107 -0
  112. package/src/utils/type.ts +0 -0
  113. package/tsconfig.json +22 -0
  114. package/tsconfig.test.json +7 -0
  115. package/vite.config.ts +7 -0
@@ -0,0 +1,23 @@
1
+ import type React from 'react'
2
+ import { useEffect } from 'react'
3
+
4
+ function useClickOutside(
5
+ ref: React.RefObject<HTMLElement>,
6
+ handler: () => void
7
+ ) {
8
+ useEffect(() => {
9
+ function handleClickOutside({ target }: MouseEvent) {
10
+ if (ref.current != null && !ref.current.contains(target as Node)) {
11
+ handler()
12
+ }
13
+ }
14
+ // Bind the event listener
15
+ document.addEventListener('mousedown', handleClickOutside)
16
+ return () => {
17
+ // Unbind the event listener on clean up
18
+ document.removeEventListener('mousedown', handleClickOutside)
19
+ }
20
+ }, [ref, handler])
21
+ }
22
+
23
+ export default useClickOutside
@@ -0,0 +1,95 @@
1
+ import dayjs from 'dayjs'
2
+ import { useRef } from 'react'
3
+ import type { Dispatch, RefObject, SetStateAction } from 'react'
4
+ import { isRtl } from '../utils'
5
+ import { CALENDAR_WIDTH, TIME, ANIMATE_FUNC } from '../constants'
6
+ import getDays from '../utils/month'
7
+ import type { DaysInMonth } from '../utils/month/month.types'
8
+
9
+ const toRight = () => {
10
+ if (isRtl()) {
11
+ return CALENDAR_WIDTH
12
+ }
13
+ return CALENDAR_WIDTH * -1
14
+ }
15
+
16
+ interface UseSliderTypes {
17
+ daysElementRefs: RefObject<HTMLDivElement[]>
18
+ days: DaysInMonth[]
19
+ setDays: Dispatch<SetStateAction<DaysInMonth[]>>
20
+ }
21
+ export const useSlideCalendar = ({
22
+ daysElementRefs,
23
+ days,
24
+ setDays
25
+ }: UseSliderTypes) => {
26
+ const isAnimating = useRef(false)
27
+ const currentMonth = days[0].middleOfMonth
28
+
29
+ const slideToTheNextMonth = () => {
30
+ if (isAnimating.current) {
31
+ return
32
+ }
33
+ const nextMonth = dayjs(currentMonth).add(1, 'month')
34
+ const newValue = getDays(nextMonth.toDate())
35
+
36
+ setDays([...days, newValue])
37
+
38
+ requestAnimationFrame(() => {
39
+ isAnimating.current = true
40
+ // @ts-expect-error I will check this out later
41
+ const [firstItemRef, lastItemRef] = daysElementRefs.current
42
+ firstItemRef.style.transition = `transform ${TIME}ms ${ANIMATE_FUNC}`
43
+ firstItemRef.style.transform = `translateX(${toRight()}px)`
44
+
45
+ lastItemRef.style.transition = `transform ${TIME}ms ${ANIMATE_FUNC}`
46
+ lastItemRef.style.transform = `translateX(${toRight()}px)`
47
+
48
+ setTimeout(() => {
49
+ setDays((oldItems) => {
50
+ return oldItems.filter((items) => items.id === newValue.id)
51
+ })
52
+ lastItemRef.style.transition = null
53
+ lastItemRef.style.transform = null
54
+ isAnimating.current = false
55
+ }, TIME + 50)
56
+ })
57
+ }
58
+ const slideToPrevMonth = () => {
59
+ if (isAnimating.current) {
60
+ return
61
+ }
62
+ const prevMonth = dayjs(currentMonth).subtract(1, 'month')
63
+ const newValue = getDays(prevMonth.toDate())
64
+
65
+ setDays([newValue, ...days])
66
+
67
+ requestAnimationFrame(() => {
68
+ isAnimating.current = true
69
+ const [firstItemRef, lastItemRef] = daysElementRefs.current
70
+ firstItemRef.style.transform = `translateX(${toRight()}px)`
71
+ lastItemRef.style.transform = `translateX(${toRight()}px)`
72
+
73
+ requestAnimationFrame(() => {
74
+ lastItemRef.style.transition = `transform ${TIME}ms ${ANIMATE_FUNC}`
75
+ lastItemRef.style.transform = `translateX(${0}px)`
76
+
77
+ firstItemRef.style.transition = `transform ${TIME}ms ${ANIMATE_FUNC}`
78
+ firstItemRef.style.transform = `translateX(${0}px)`
79
+
80
+ setTimeout(() => {
81
+ setDays((oldItems) => {
82
+ return oldItems.filter((items) => items.id === newValue.id)
83
+ })
84
+ firstItemRef.style.transition = null
85
+ firstItemRef.style.transform = null
86
+ isAnimating.current = false
87
+ }, TIME + 50)
88
+ })
89
+ })
90
+ }
91
+ return {
92
+ slideToTheNextMonth,
93
+ slideToPrevMonth
94
+ }
95
+ }
@@ -0,0 +1,95 @@
1
+ import type React from 'react'
2
+ import { useState } from 'react'
3
+ import dayjs from 'dayjs'
4
+ import { getAngelValues } from '../utils/timePicker'
5
+ import { type DatePickerValue } from '../types'
6
+ import { type onChangePayload } from '../packages/TimePicker/TimePicker.types'
7
+
8
+ interface useTimePickerType {
9
+ timeConvention?: 'am' | 'pm'
10
+ clockTime?: 24 | 12
11
+ defaultValue?: DatePickerValue
12
+ onChange?: (payload: onChangePayload) => void
13
+ }
14
+ export const useTimePicker = ({
15
+ defaultValue,
16
+ clockTime,
17
+ timeConvention,
18
+ onChange
19
+ }: useTimePickerType) => {
20
+ const time =
21
+ defaultValue !== undefined ? dayjs(defaultValue) : dayjs().startOf('date')
22
+ const [selecting, setSelecting] = useState<boolean>(false)
23
+ const [selectingHour, setSelectingHour] = useState<boolean>(false)
24
+ const [isInsideHour, setInsideHour] = useState<boolean>(false)
25
+ const hourFormat = clockTime === 24 ? 'HH' : 'h'
26
+ const [hour, setHour] = useState<number>(
27
+ parseInt(time.format(hourFormat), 10)
28
+ )
29
+ const [minute, setMinute] = useState<number>(parseInt(time.format('mm'), 10))
30
+
31
+ const handleChangeMinute = (e: React.MouseEvent | React.TouchEvent) => {
32
+ const { value } = getAngelValues(e, 6)
33
+ setMinute(value)
34
+ }
35
+ const handleChangeHour = (e: React.MouseEvent | React.TouchEvent) => {
36
+ const { value, delta } = getAngelValues(e)
37
+ if (clockTime === 24) {
38
+ if (Math.round(delta) < 85) {
39
+ setHour(value)
40
+ setInsideHour(true)
41
+ } else {
42
+ setHour(value + 12)
43
+ setInsideHour(false)
44
+ }
45
+ return
46
+ }
47
+ setHour(value)
48
+ }
49
+ const handleMouseMove = (e: React.MouseEvent) => {
50
+ e.preventDefault()
51
+ if (!selecting) {
52
+ return
53
+ }
54
+ if (selectingHour) {
55
+ return handleChangeHour(e)
56
+ }
57
+ return handleChangeMinute(e)
58
+ }
59
+ const handleSelecting = (e: React.MouseEvent | React.TouchEvent) => {
60
+ setSelecting(true)
61
+ if (selectingHour) {
62
+ return handleChangeHour(e)
63
+ } else {
64
+ return handleChangeMinute(e)
65
+ }
66
+ }
67
+
68
+ const handleMouseUp = () => {
69
+ if (selectingHour) {
70
+ if (typeof onChange === 'function') {
71
+ onChange({
72
+ hour,
73
+ minute,
74
+ ...(clockTime === 12 && { timeConvention })
75
+ })
76
+ }
77
+ setSelecting(false)
78
+ setSelectingHour(false)
79
+ setInsideHour(false)
80
+ return
81
+ }
82
+ setSelecting(false)
83
+ setSelectingHour(true)
84
+ }
85
+
86
+ return {
87
+ hour,
88
+ minute,
89
+ isInsideHour,
90
+ selectingHour,
91
+ handleMouseMove,
92
+ handleMouseUp,
93
+ handleSelecting
94
+ }
95
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,4 @@
1
+ export { default as DatePicker } from './packages/DatePicker'
2
+ export { default as CalendarProvider } from './packages/CalendarProvider'
3
+ export { default as Calendar } from './packages/Calendar'
4
+ export { default as TimePicker } from './packages/TimePicker'
@@ -0,0 +1,42 @@
1
+ import styled from '@emotion/styled'
2
+ import { CALENDAR_HEIGHT, CALENDAR_WIDTH } from '../../constants'
3
+ import { radius } from '../../style/radius'
4
+
5
+ export const Wrapper = styled.div`
6
+ overflow: hidden;
7
+ position: relative;
8
+ width: ${CALENDAR_WIDTH}px;
9
+ height: ${CALENDAR_HEIGHT}px;
10
+ border: 1px solid ${(props) => props.theme.colors.gray[40]};
11
+ background-color: #fff;
12
+ border-radius: ${(props) => radius[props.theme.round].wrapper}px;
13
+ `
14
+
15
+ export const WrapperDays = styled.div`
16
+ display: flex;
17
+ position: absolute;
18
+ overflow: hidden;
19
+ right: ${(props) => (props.theme.direction === 'rtl' ? '8px' : 'unset')};
20
+ left: ${(props) => (props.theme.direction !== 'rtl' ? '8px' : 'unset')};
21
+ `
22
+
23
+ export const SlideDays = styled.div`
24
+ will-change: transform;
25
+ display: flex;
26
+ flex-direction: column;
27
+ width: ${CALENDAR_WIDTH}px;
28
+ gap: 4px;
29
+ `
30
+ export const Days = styled.div`
31
+ display: flex;
32
+ gap: 4px;
33
+ `
34
+ export const SubHeader = styled.div`
35
+ display: flex;
36
+ justify-content: center;
37
+ align-items: center;
38
+ margin-top: 12px;
39
+ margin-bottom: 8px;
40
+ height: 24px;
41
+ gap: 4px;
42
+ `
@@ -0,0 +1,159 @@
1
+ import React, {
2
+ type ForwardedRef,
3
+ forwardRef,
4
+ useMemo,
5
+ useRef,
6
+ useState
7
+ } from 'react'
8
+ import {
9
+ Days,
10
+ SlideDays,
11
+ SubHeader,
12
+ Wrapper,
13
+ WrapperDays
14
+ } from './Calendar.styled'
15
+ import Header from '../../components/Header'
16
+ import { useSlideCalendar } from '../../hooks/useSlideCalendar'
17
+ import CalendarItem from '../../components/CalendarItem'
18
+ import {
19
+ isInBetween,
20
+ sameDay,
21
+ selectMonth,
22
+ selectYear
23
+ } from '../../utils/dateHelper/dateHelper'
24
+ import formatDate from '../../utils/format'
25
+ import getDays from '../../utils/month'
26
+ import MonthPicker from '../../components/MonthPicker'
27
+ import YearPicker from '../../components/YearPicker'
28
+ import { DayName } from '../../components/Header/Header.styled'
29
+ import locales from '../../utils/locales'
30
+ import localeCache from '../../utils/locale'
31
+ import type { DaysInMonth } from '../../utils/month/month.types'
32
+ import type { CalendarProps } from './Calendar.types'
33
+ import type { Pickers } from '../../types'
34
+ import useCalendarHandlers from '../../hooks/useCalendarHandlers'
35
+ import { CalendarText } from '../../components/CalendarItem/CalendarItem.styled'
36
+ import { DaysButton } from '../../style/classNames'
37
+
38
+ const Calendar = (props: CalendarProps, ref: ForwardedRef<HTMLDivElement>) => {
39
+ const { locale } = localeCache
40
+ const { defaultValue, weekends, range = false } = props
41
+ const startDate = defaultValue === undefined ? new Date() : defaultValue
42
+ // memo
43
+ const getAllDays = useMemo(() => getDays(defaultValue), [])
44
+ // states
45
+ const [days, setDays] = useState<DaysInMonth[]>([getAllDays])
46
+ const [picker, setPicker] = useState<Pickers>('days')
47
+ // refs
48
+ const daysElementRefs = useRef<HTMLDivElement[]>([])
49
+ // handlers
50
+ const slideHandlers = useSlideCalendar({
51
+ daysElementRefs,
52
+ days,
53
+ setDays
54
+ })
55
+ const { from, to, handlers } = useCalendarHandlers(props)
56
+
57
+ const togglePickers = () => {
58
+ if (picker === 'month' || picker === 'year') {
59
+ setPicker('days')
60
+ return
61
+ }
62
+ setPicker('year')
63
+ }
64
+ const handleNextMonth = () => {
65
+ if (picker === 'days') {
66
+ return slideHandlers.slideToTheNextMonth()
67
+ }
68
+ }
69
+ const handlePrevMonth = () => {
70
+ if (picker === 'days') {
71
+ return slideHandlers.slideToPrevMonth()
72
+ }
73
+ }
74
+ const handleMonthSelect = (month: number) => {
75
+ const date = selectMonth(days[0].middleOfMonth, month)
76
+ setDays([getDays(date)])
77
+ setPicker('days')
78
+ }
79
+ const handleYearSelect = (year: number) => {
80
+ const date = selectYear(startDate, year)
81
+ setDays([getDays(date)])
82
+ setPicker('month')
83
+ }
84
+ return (
85
+ <Wrapper
86
+ ref={ref}
87
+ className={props.className !== null ? props.className : ''}
88
+ >
89
+ <Header
90
+ monthName={days[0].monthName}
91
+ onNextClick={handleNextMonth}
92
+ onPrevClick={handlePrevMonth}
93
+ onClickOnTitle={togglePickers}
94
+ />
95
+ {picker === 'year' ? (
96
+ <YearPicker value={startDate} onYearSelect={handleYearSelect} />
97
+ ) : null}
98
+ {picker === 'month' ? (
99
+ <MonthPicker value={startDate} onMonthSelect={handleMonthSelect} />
100
+ ) : null}
101
+ {picker === 'days' ? (
102
+ <>
103
+ <SubHeader>
104
+ {locales[locale].shortWeekDays.map((day) => (
105
+ <DayName key={day.key}>{day.name}</DayName>
106
+ ))}
107
+ </SubHeader>
108
+ <WrapperDays>
109
+ {days.map((weeks, idx) => (
110
+ <SlideDays
111
+ key={weeks.id}
112
+ className="item"
113
+ ref={(el: HTMLDivElement) => {
114
+ daysElementRefs.current[idx] = el
115
+ }}
116
+ role="rowgroup"
117
+ >
118
+ {weeks.weeks.map((week, id) => (
119
+ <Days key={id} role="row" aria-rowindex={id + 1}>
120
+ {week.map((day, idx) => (
121
+ <CalendarItem
122
+ key={day.date.getTime()}
123
+ className={DaysButton}
124
+ data-value={day.date}
125
+ data-disabled={day.disabled}
126
+ data-range={props.range}
127
+ data-selected={!range && sameDay(startDate, day.date)}
128
+ data-start-range={
129
+ from != null && sameDay(from, day.date)
130
+ }
131
+ data-in-range={isInBetween(day.date, from, to)}
132
+ data-end-range={to != null && sameDay(to, day.date)}
133
+ data-weekend={weekends?.some((wDay) => wDay === idx)}
134
+ type="button"
135
+ role="gridcell"
136
+ aria-colindex={idx + 1}
137
+ tabIndex={0}
138
+ aria-selected={!range && sameDay(startDate, day.date)}
139
+ {...handlers}
140
+ >
141
+ <CalendarText className="cl-text">
142
+ {formatDate(day.date, 'DD')}
143
+ </CalendarText>
144
+ </CalendarItem>
145
+ ))}
146
+ </Days>
147
+ ))}
148
+ </SlideDays>
149
+ ))}
150
+ </WrapperDays>
151
+ </>
152
+ ) : null}
153
+ </Wrapper>
154
+ )
155
+ }
156
+
157
+ Calendar.displayName = 'Calendar'
158
+
159
+ export default forwardRef(Calendar)
@@ -0,0 +1,31 @@
1
+ import type {
2
+ DaysRange,
3
+ DatePickerValue,
4
+ onRangeDatePickerChangePayload,
5
+ onDatePickerChangePayload
6
+ } from '../../types'
7
+
8
+ export interface CalendarBaseProps {
9
+ defaultValue?: Date
10
+ weekends?: DaysRange[]
11
+ className?: string
12
+ }
13
+ export interface CalendarRangeProps {
14
+ range: true
15
+ from?: DatePickerValue
16
+ to?: DatePickerValue
17
+ rangeValue?: Date[]
18
+ onChange?: (args: onRangeDatePickerChangePayload) => void
19
+ }
20
+
21
+ export interface CalendarDefaultProps {
22
+ range?: false | undefined
23
+ onChange?: (args: onDatePickerChangePayload) => void
24
+ }
25
+
26
+ export type OnChangePayload =
27
+ | onRangeDatePickerChangePayload
28
+ | onDatePickerChangePayload
29
+
30
+ export type CalendarProps = CalendarBaseProps &
31
+ (CalendarRangeProps | CalendarDefaultProps)
@@ -0,0 +1,69 @@
1
+ import React from 'react'
2
+ import Calendar from './Calendar'
3
+ import { CalendarProvider } from '../../index'
4
+ import {
5
+ DaysButton,
6
+ HeaderClass,
7
+ IconNextButton,
8
+ IconPrevButton,
9
+ YearPickerButton
10
+ } from '../../style/classNames'
11
+
12
+ describe('Calendar Component', () => {
13
+ it('renders', () => {
14
+ const initialDate = '1994 08 09'
15
+ cy.mount(
16
+ <CalendarProvider locale={'fa'}>
17
+ <Calendar defaultValue={new Date(initialDate)} onChange={() => {}} />
18
+ </CalendarProvider>
19
+ )
20
+ .get(`.${HeaderClass}`)
21
+ .findByText('مرداد ۱۳۷۳')
22
+ .get(`.${DaysButton}[aria-selected=true]`)
23
+ .should('have.text', '۱۸')
24
+ })
25
+ it('renders en locale', () => {
26
+ const initialDate = '1994 08 09'
27
+ cy.mount(
28
+ <CalendarProvider locale={'en'}>
29
+ <Calendar defaultValue={new Date(initialDate)} onChange={() => {}} />
30
+ </CalendarProvider>
31
+ )
32
+ .get(`.${HeaderClass}`)
33
+ .findByText('Aug 1994')
34
+ .get(`.${DaysButton}[aria-selected=true]`)
35
+ .should('have.text', '9')
36
+ })
37
+ it('scenario 1 choose the year and the month', () => {
38
+ const initialDate = '1994 08 09'
39
+ // going to Year and Month Picker state
40
+ cy.mount(
41
+ <CalendarProvider locale={'fa'}>
42
+ <Calendar defaultValue={new Date(initialDate)} onChange={() => {}} />
43
+ </CalendarProvider>
44
+ )
45
+ .get(`.${HeaderClass}`)
46
+ .click()
47
+ .get(`.${YearPickerButton}[aria-selected=true]`)
48
+ .should('have.text', '۱۳۷۳')
49
+ // change the year
50
+ cy.findByText('۱۴۰۲').click()
51
+ // click on the current month
52
+ cy.findByText('مرداد').click()
53
+ // now year should be changed
54
+ cy.get(`.${HeaderClass}`).should('have.text', 'مرداد ۱۴۰۲')
55
+ // go to previous month
56
+ cy.get(`.${IconPrevButton}`).click()
57
+ // now month should be changed
58
+ cy.get(`.${HeaderClass}`).should('have.text', 'تیر ۱۴۰۲')
59
+ cy.wait(300)
60
+ // go to previous month
61
+ cy.get(`.${IconNextButton}`).click()
62
+ // now month should be changed
63
+ cy.get(`.${HeaderClass}`).should('have.text', 'مرداد ۱۴۰۲')
64
+ // go to previous month
65
+ cy.get(`.${IconNextButton}`).click()
66
+ // now month should be changed
67
+ cy.get(`.${HeaderClass}`).should('have.text', 'شهریور ۱۴۰۲')
68
+ })
69
+ })
@@ -0,0 +1,2 @@
1
+ export { default } from './Calendar'
2
+ export type { CalendarProps } from './Calendar.types'
@@ -0,0 +1,30 @@
1
+ import React, { useMemo } from 'react'
2
+ import { ThemeProvider } from '@emotion/react'
3
+ import { makeColorPallet } from '../../style/colorPallete'
4
+ import { ACCENT_COLOR } from '../../constants'
5
+ import localeCache from '../../utils/locale'
6
+ import { gray } from '../../style/colors'
7
+ import type { CalendarProviderProps } from './CalendarProvider.types'
8
+
9
+ export const CalendarProvider = (props: CalendarProviderProps) => {
10
+ const {
11
+ accentColor = ACCENT_COLOR,
12
+ locale,
13
+ round = 'thin',
14
+ direction = 'rtl'
15
+ } = props
16
+ useMemo(() => localeCache.setLocale(locale), [locale])
17
+ const primaryColors = useMemo(() => makeColorPallet(accentColor), [])
18
+
19
+ const theme = {
20
+ colors: {
21
+ primary: primaryColors,
22
+ gray
23
+ },
24
+ round,
25
+ direction
26
+ }
27
+ return <ThemeProvider theme={theme}>{props.children}</ThemeProvider>
28
+ }
29
+
30
+ export default CalendarProvider
@@ -0,0 +1,6 @@
1
+ import type React from 'react'
2
+ import type { BaseProps } from '../../types'
3
+
4
+ export interface CalendarProviderProps extends BaseProps {
5
+ children: React.ReactNode
6
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './CalendarProvider'
2
+ export type { CalendarProviderProps } from './CalendarProvider.types'
@@ -0,0 +1,54 @@
1
+ import React from 'react'
2
+ import DatePicker from './DatePicker'
3
+ import { HeaderClass } from '../../style/classNames'
4
+
5
+ describe('<DatePicker />', () => {
6
+ const initialDate = '2023 04 25'
7
+ it('renders', () => {
8
+ const onChangeSpy = cy.spy().as('onChangeSpy')
9
+ cy.mount(<DatePicker defaultValue={initialDate} onChange={onChangeSpy} />)
10
+ .get('input')
11
+ .click()
12
+
13
+ // change the year
14
+ cy.get(`.${HeaderClass}`).click()
15
+ // click on the current month
16
+ cy.findByText('۱۴۰۲').click()
17
+ // click on the mordad month
18
+ cy.findByText('مرداد').click()
19
+ // click on the mordad month
20
+ cy.findByText('۱۸').click()
21
+ cy.get('@onChangeSpy').should('have.callCount', 1)
22
+ cy.get('@onChangeSpy').should('be.calledWith', { value: new Date('Tue, 08 Aug 2023 20:30:00 GMT') })
23
+ // now input's value should be changed
24
+ cy.get('input').should('have.value', '۱۴۰۲/۰۵/۱۸')
25
+ })
26
+ it('check range renders', () => {
27
+ const onChangeSpy = cy.spy().as('onChangeSpy')
28
+ cy.mount(<DatePicker defaultValue={initialDate} onChange={onChangeSpy} range />)
29
+ .get('input')
30
+ .click()
31
+
32
+ // change the year
33
+ cy.get(`.${HeaderClass}`).click()
34
+ // click on the current month
35
+ cy.findByText('۱۴۰۲').click()
36
+ // click on the mordad month
37
+ cy.findByText('مرداد').click()
38
+ // click on the mordad month
39
+ cy.findByText('۱۸').click()
40
+ // click on the mordad month
41
+ cy.findByText('۱۹').click()
42
+ cy.get('@onChangeSpy').should('have.callCount', 1)
43
+ cy.get('@onChangeSpy').should('be.calledWith', { from: new Date('Tue, 08 Aug 2023 20:30:00 GMT'), to: new Date('Tue, 09 Aug 2023 20:30:00 GMT') })
44
+ })
45
+ it('close the DatePicker ', () => {
46
+ const onChangeSpy = cy.spy().as('onChangeSpy')
47
+ cy.mount(<DatePicker defaultValue={initialDate} onChange={onChangeSpy} />)
48
+ .get('input')
49
+ .click()
50
+
51
+ cy.get('body').click()
52
+ cy.get(`.${HeaderClass}`).should('not.exist')
53
+ })
54
+ })