Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2808: Add a filter by date option to events #2898

Open
wants to merge 65 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
5028027
2808: Creating a component called CustomDatePicker and filtering even…
bahaaTuffaha Aug 20, 2024
b6683da
2808: Creating a hook for useDateFilter and a toggle to hide and show…
bahaaTuffaha Aug 21, 2024
8dd13b4
2808: web changes and adding translation and direction for RTL plus c…
bahaaTuffaha Aug 21, 2024
3fb9deb
2828: added a library called react-native-ui-datepicker and create Ca…
bahaaTuffaha Aug 22, 2024
566da43
2808: Added DateFilterToggle to native and improvements to useDateFil…
bahaaTuffaha Aug 24, 2024
3c0dbe5
2808: Adding translations and using React-native modal
bahaaTuffaha Aug 25, 2024
63d158a
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Aug 25, 2024
4df2415
2808: Replacing (react-native-ui-datepicker) with (react-native-calen…
bahaaTuffaha Aug 27, 2024
c67fd25
Added some tests and release note
bahaaTuffaha Aug 27, 2024
60f9de7
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Aug 27, 2024
193909c
2808: Refactoring code + some improvements
bahaaTuffaha Aug 27, 2024
e701023
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Aug 27, 2024
5d18825
2808: prettier:check fixed for tsconfig
bahaaTuffaha Aug 27, 2024
c1cab6d
2808: Fixing Typescript issues
bahaaTuffaha Aug 27, 2024
25406e8
2808: Requested changes about DateTime
bahaaTuffaha Aug 29, 2024
3321eb4
2808: Fix translations
steffenkleinle Sep 10, 2024
115de27
2808: Requested changes part 2
bahaaTuffaha Sep 11, 2024
e652e78
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Sep 11, 2024
000a9a4
2808: Requested changes part 3
bahaaTuffaha Sep 12, 2024
d7ca0ff
2808: Replacing names fromDate and toDate to startDate and endDate
bahaaTuffaha Sep 12, 2024
a6176f5
2808: Replacing alt with placeholder at date-input (web) for tests ge…
bahaaTuffaha Sep 13, 2024
5b10e03
2808: Requested changes Part4
bahaaTuffaha Sep 19, 2024
52db677
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Sep 19, 2024
8929238
2808: Dealing with recurrences and adding requested changes
bahaaTuffaha Oct 3, 2024
915c099
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Oct 3, 2024
a371455
2808: Fixing recurrence to show beyond the limit and some refactoring…
bahaaTuffaha Oct 13, 2024
df9e206
Merge branch 'main' into 2808-Add-a-filter-by-date-option-to-events
bahaaTuffaha Oct 13, 2024
075d88a
2808: Importing DateFilterUtils module properly
bahaaTuffaha Oct 13, 2024
87f7daa
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Oct 14, 2024
8ea2492
2808: Requested changes: general improvements
bahaaTuffaha Oct 16, 2024
ab81a63
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Oct 16, 2024
d537677
2808: Requested changes about moving focus to next input and improvin…
bahaaTuffaha Nov 1, 2024
2af2efa
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Nov 1, 2024
2464cc5
2808: Adding missing spaces
bahaaTuffaha Nov 1, 2024
a19bb07
2808: Modified CalendarRangeModal to let you select from or to date i…
bahaaTuffaha Nov 3, 2024
4232588
2808: small Refactoring
bahaaTuffaha Nov 4, 2024
f62a0ca
2808: Jumping backward when backspacing and Adding width for views ju…
bahaaTuffaha Nov 4, 2024
dc2a79f
2808: Expanded on some more tests for DatePicker spec file
bahaaTuffaha Nov 4, 2024
aeceee3
2808: Requested changes for DatePickers and adding more tests
bahaaTuffaha Nov 7, 2024
1f1ca05
2808: Added Accordion Animation for EventsDateFilter
bahaaTuffaha Nov 8, 2024
ac24b22
2808: Accordion changes and added invalidDate to translation
bahaaTuffaha Nov 11, 2024
20fd593
2808: Added Accordion Animation for EventsDateFilter
bahaaTuffaha Nov 8, 2024
829c7b2
Merge branch '2808-Add-a-filter-by-date-option-to-events' of https://…
bahaaTuffaha Nov 11, 2024
b3ba08b
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Nov 11, 2024
4282d93
2808: EventListItem can show the right date from the recurrences depe…
bahaaTuffaha Nov 20, 2024
abb3d98
2808: Fixing EventListItem test file
bahaaTuffaha Nov 20, 2024
4990e93
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Nov 20, 2024
2085834
2808: Adding tests for DateModal filterStartDate and filterEndDate pa…
bahaaTuffaha Nov 21, 2024
ca5a9bf
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Nov 21, 2024
0346272
2808: Changing placeholder for filter input at native
bahaaTuffaha Dec 2, 2024
c63fd9f
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Dec 2, 2024
09ee0ef
2808: Requested changes and improvements part1
bahaaTuffaha Dec 4, 2024
7a2b69b
2808: changing date input with react datepicker package
bahaaTuffaha Dec 9, 2024
ba14fa3
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Dec 9, 2024
672df15
2808: prettier fix
bahaaTuffaha Dec 9, 2024
4917393
2808: Fixing small overflow jumping issue
bahaaTuffaha Dec 9, 2024
e075d72
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Dec 11, 2024
69f5ea5
2808: changing es2021 to es2022 for react-datepicker
bahaaTuffaha Dec 17, 2024
c197a85
Merge branch 'main' into 2808-Add-a-filter-by-date-option-to-events
bahaaTuffaha Jan 14, 2025
05c70da
2808: fixing JavaScript heap out of memory
bahaaTuffaha Jan 15, 2025
88b908d
Merge remote-tracking branch 'origin' into 2808-Add-a-filter-by-date-…
bahaaTuffaha Jan 15, 2025
4ed5847
Merge branch '2808-Add-a-filter-by-date-option-to-events' of https://…
bahaaTuffaha Jan 15, 2025
5427c03
2808: fixing JavaScript heap out of memory attempt number 2
bahaaTuffaha Jan 15, 2025
965329f
2808: fixing JavaScript heap out of memory attempt number 3
bahaaTuffaha Jan 15, 2025
61034fd
2808: prettier fix
bahaaTuffaha Jan 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions assets/icons/expand.svg
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/icons/shrink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"react-native": "0.74.5",
"react-native-blob-util": "^0.19.11",
"react-native-calendar-events": "^2.2.0",
"react-native-calendars": "^1.1306.0",
"react-native-gesture-handler": "^2.19.0",
"react-native-get-random-values": "^1.11.0",
"react-native-highlight-words": "^1.0.1",
Expand Down
4 changes: 4 additions & 0 deletions native/src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import CategoriesIcon from '../../../assets/icons/categories.svg'
import ClockIcon from '../../../assets/icons/clock.svg'
import CloseIcon from '../../../assets/icons/close.svg'
import EditLocationIcon from '../../../assets/icons/edit-location.svg'
import ExpandIcon from '../../../assets/icons/expand.svg'
import ExternalLinkIcon from '../../../assets/icons/external-link.svg'
import HappySmileyIcon from '../../../assets/icons/happy-smiley.svg'
import LanguageIcon from '../../../assets/icons/language.svg'
Expand All @@ -29,6 +30,7 @@ import RefreshIcon from '../../../assets/icons/refresh.svg'
import SadSmileyIcon from '../../../assets/icons/sad-smiley.svg'
import SearchIcon from '../../../assets/icons/search.svg'
import SecurityIcon from '../../../assets/icons/security.svg'
import ShrinkIcon from '../../../assets/icons/shrink.svg'
import SprungbrettIcon from '../../../assets/icons/sprungbrett.svg'
import SupportIcon from '../../../assets/icons/support.svg'
import TuNewsActiveIcon from '../../../assets/icons/tu-news-active.svg'
Expand All @@ -52,6 +54,8 @@ export {
EventThumbnailPlaceholder2,
EventThumbnailPlaceholder3,
ExternalLinkIcon,
ExpandIcon,
ShrinkIcon,
LocationFixedIcon,
LocationMarkerIcon,
LocationNotFixedIcon,
Expand Down
49 changes: 49 additions & 0 deletions native/src/components/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { ReactElement } from 'react'
import { StyleProp, ViewStyle } from 'react-native'
import Animated, { useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'
import { styled } from 'styled-components/native'

const StyledWrapper = styled.View`
width: 100%;
position: absolute;
display: flex;
align-items: center;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
const StyledAnimatedView = styled(Animated.View)`
width: 100%;
overflow: hidden;
`

type AccordionProps = {
isOpen: boolean
style?: StyleProp<ViewStyle>
children: React.ReactNode
duration?: number
viewKey: string
}

const defaultDuration = 500

const Accordion = ({ isOpen, style, duration = defaultDuration, children, viewKey }: AccordionProps): ReactElement => {
const height = useSharedValue(0)
const derivedHeight = useDerivedValue(() =>
withTiming(height.value * Number(isOpen), {
duration,
}),
)
const bodyStyle = useAnimatedStyle(() => ({
height: derivedHeight.value,
}))
return (
<StyledAnimatedView key={`accordionItem_${viewKey}`} style={[bodyStyle, style]}>
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
<StyledWrapper
onLayout={e => {
height.value = e.nativeEvent.layout.height
}}>
{children}
</StyledWrapper>
</StyledAnimatedView>
)
}

export default Accordion
151 changes: 151 additions & 0 deletions native/src/components/CalendarRangeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { DateTime } from 'luxon'
import React, { ReactElement, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Modal } from 'react-native'
import { Calendar } from 'react-native-calendars'
import styled, { useTheme } from 'styled-components/native'

import { getMarkedDates } from '../utils/calendarRangeUtils'
import Caption from './Caption'
import TextButton from './base/TextButton'

const DatePickerWrapper = styled.View`
background-color: ${props => props.theme.colors.textDecorationColor};
border-radius: 20px;
position: absolute;
width: 90%;
top: 25%;
align-self: center;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledView = styled.View`
gap: 8px;
justify-content: ${props => (props.theme.contentDirection === 'rtl' ? 'flex-start' : 'flex-end')};
flex-direction: row;
padding: 5px 14px;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const DISABLED_OPACITY = 0.5

const StyledTextButton = styled(TextButton)`
background-color: transparent;
opacity: ${props => (props.disabled ? DISABLED_OPACITY : 1)};
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledPressable = styled.Pressable`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
flex: 1;
`

export type CalendarViewerProps = {
modalVisible: boolean
closeModal: () => void
startDate: DateTime | null
endDate: DateTime | null
setStartDate: (startDate: DateTime) => void
setEndDate: (endDate: DateTime) => void
currentInput?: string
}

const CalendarRangeModal = ({
modalVisible,
closeModal,
startDate,
endDate,
setStartDate,
setEndDate,
currentInput,
}: CalendarViewerProps): ReactElement => {
const [tempStartDate, setTempStartDate] = useState<DateTime | null>(startDate)
const [tempEndDate, setTempEndDate] = useState<DateTime | null>(endDate)
const { t } = useTranslation('events')
const theme = useTheme()

const textButtonStyles = {
container: {
height: 40,
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
},
text: {
fontSize: 16,
},
}

useEffect(() => {
setTempStartDate(startDate)
LeandraH marked this conversation as resolved.
Show resolved Hide resolved
setTempEndDate(endDate)
}, [startDate, endDate])

const handleDayPress = (day: { dateString: string }) => {
const selectedDate = DateTime.fromISO(day.dateString)

if (!tempStartDate || tempEndDate) {
setTempStartDate(selectedDate)
setTempEndDate(null)
} else {
setTempEndDate(selectedDate)
}
}

const updateCalendarBasedOnInput = (
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
tempStartDate: DateTime<true> | null,
tempEndDate: DateTime<true> | null,
currentInput: string,
) => {
if (tempStartDate && tempEndDate) {
setStartDate(tempStartDate)
setEndDate(tempEndDate)
} else if (tempStartDate && tempEndDate == null) {
;(currentInput === 'from' ? setStartDate : setEndDate)(tempStartDate)
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
}
setTempStartDate(null)
setTempEndDate(null)
closeModal()
}

return (
<Modal style={{ margin: 0 }} animationType='slide' transparent visible={modalVisible} onRequestClose={closeModal}>
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
<StyledPressable onPress={closeModal} />
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved
<DatePickerWrapper>
<Caption title={t('selectRange')} />
<Calendar
markingType='period'
markedDates={getMarkedDates(tempStartDate, tempEndDate, theme, currentInput ?? '')}
onDayPress={handleDayPress}
theme={{
calendarBackground: theme.colors.textDecorationColor,
dayTextColor: theme.colors.textColor,
textDisabledColor: theme.colors.textSecondaryColor,
todayTextColor: theme.colors.backgroundColor,
textSectionTitleColor: theme.colors.textColor,
arrowColor: theme.colors.textColor,
}}
/>
<StyledView>
<StyledTextButton
style={textButtonStyles.container}
textStyle={textButtonStyles.text}
onPress={() => {
setTempStartDate(startDate)
setTempEndDate(endDate)
LeandraH marked this conversation as resolved.
Show resolved Hide resolved
closeModal()
}}
text={t('layout:cancel')}
type='clear'
/>
<StyledTextButton
style={textButtonStyles.container}
textStyle={textButtonStyles.text}
onPress={() => updateCalendarBasedOnInput(tempStartDate, tempEndDate, currentInput ?? '')}
text={t('common:ok')}
type='clear'
disabled={
(tempStartDate === null && tempEndDate === null) ||
!!(tempStartDate && tempEndDate && tempStartDate > tempEndDate)
}
/>
</StyledView>
</DatePickerWrapper>
</Modal>
)
}

export default CalendarRangeModal
153 changes: 153 additions & 0 deletions native/src/components/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { DateTime } from 'luxon'
import React, { ReactElement, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { TextInput, View } from 'react-native'
import styled from 'styled-components/native'

import { CalendarTodayIcon } from '../assets'
import DatePickerInput from './DatePickerInput'
import Icon from './base/Icon'
import IconButton from './base/IconButton'
import Text from './base/Text'

const DateContainer = styled.View`
width: auto;
position: relative;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledInputWrapper = styled.View`
min-width: 80%;
height: 56px;
padding: 0 16px;
border-radius: 8px;
border-color: ${props => props.theme.colors.themeColorLight};
border-width: 3px;
border-style: solid;
flex-direction: row;
justify-content: space-between;
align-items: center;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const Wrapper = styled.View`
flex-direction: row;
align-items: center;
width: 50%;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledIconButton = styled(IconButton)<{ $isModalOpen: boolean }>`
width: 40px;
height: 40px;
background-color: ${props =>
props.$isModalOpen ? props.theme.colors.themeColorLight : props.theme.colors.textDisabledColor};
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledTitle = styled.Text`
background-color: ${props => props.theme.colors.backgroundColor};
position: absolute;
top: -12px;
left: 12px;
padding: 2px 5px;
font-size: 12px;
z-index: 1;
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const StyledError = styled.Text`
font-size: 12px;
font-weight: bold;
color: ${props => props.theme.colors.invalidInput};
`
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

export type DatePickerProps = {
title: string
date: DateTime | null
setDate: (date: DateTime | null) => void
error?: string
modalOpen: boolean
setModalOpen: (open: boolean) => void
}
bahaaTuffaha marked this conversation as resolved.
Show resolved Hide resolved

const DatePicker = ({ title, date, setDate, error, modalOpen, setModalOpen }: DatePickerProps): ReactElement => {
const { t } = useTranslation('events')
const [inputDay, setInputDay] = useState(date?.toFormat('dd'))
const [inputMonth, setInputMonth] = useState(date?.toFormat('MM'))
const [inputYear, setInputYear] = useState(date?.toFormat('yyyy'))
ztefanie marked this conversation as resolved.
Show resolved Hide resolved
const [datePickerError, setDatePickerError] = useState('')
const dayRef = useRef<TextInput>(null)
const monthRef = useRef<TextInput>(null)
const yearRef = useRef<TextInput>(null)

useEffect(() => {
try {
setDatePickerError('')
setDate(DateTime.fromISO(`${inputYear}-${inputMonth}-${inputDay}`))
} catch (e) {
// This will detect out of range for days
if (!String(e).includes('ISO')) {
setDatePickerError(String(e).replace('Error: ', ''))
}
}
}, [inputDay, inputMonth, inputYear, setDate])

useEffect(() => {
if (date) {
setInputDay(date.toFormat('dd'))
setInputMonth(date.toFormat('MM'))
setInputYear(date.toFormat('yyyy'))
} else {
setInputDay('')
setInputMonth('')
setInputYear('')
}
}, [date])
LeandraH marked this conversation as resolved.
Show resolved Hide resolved

return (
<DateContainer>
<StyledTitle>{title}</StyledTitle>
<StyledInputWrapper>
<Wrapper>
<DatePickerInput
ref={dayRef}
placeholder={t('dd')}
nextTargetRef={monthRef}
inputValue={inputDay}
setInputValue={setInputDay}
type='day'
/>
<Text>.</Text>
<DatePickerInput
ref={monthRef}
placeholder={t('mm')}
nextTargetRef={yearRef}
prevTargetRef={dayRef}
inputValue={inputMonth}
setInputValue={setInputMonth}
type='month'
/>
<Text>.</Text>
<DatePickerInput
style={{ marginLeft: 6 }}
ref={yearRef}
prevTargetRef={monthRef}
placeholder={t('yyyy')}
inputValue={inputYear}
setInputValue={setInputYear}
type='year'
/>
</Wrapper>
<StyledIconButton
$isModalOpen={modalOpen}
icon={<Icon Icon={CalendarTodayIcon} />}
accessibilityLabel={t('common:openCalendar')}
onPress={() => {
setModalOpen(true)
}}
/>
</StyledInputWrapper>
<View style={{ width: '80%' }}>
{!!(error || datePickerError) && <StyledError>{error || datePickerError}</StyledError>}
</View>
</DateContainer>
)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ New issue: Complex Method
DatePicker has a cyclomatic complexity of 10, threshold = 10

Suppress


export default DatePicker
Loading
Loading