Skip to content

Commit

Permalink
2808: Added Accordion Animation for EventsDateFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
bahaaTuffaha committed Nov 8, 2024
1 parent aeceee3 commit 1f1ca05
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 22 deletions.
52 changes: 52 additions & 0 deletions native/src/components/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { ReactElement } from 'react'
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'
import Animated, { useAnimatedStyle, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'

// For some reason I couldn't replicate this styling in styled-components
const styles = StyleSheet.create({
wrapper: {
width: '100%',
position: 'absolute',
display: 'flex',
alignItems: 'center',
},
animatedView: {
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 (
<Animated.View key={`accordionItem_${viewKey}`} style={[styles.animatedView, bodyStyle, style]}>
<View
onLayout={e => {
height.value = e.nativeEvent.layout.height
}}
style={styles.wrapper}>
{children}
</View>
</Animated.View>
)
}

export default Accordion
13 changes: 7 additions & 6 deletions native/src/components/EventsDateFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
import styled from 'styled-components/native'

import { CloseIcon } from '../assets'
import Accordion from './Accordion'
import CalendarRangeModal from './CalendarRangeModal'
import DatePicker from './DatePicker'
import FilterToggle from './FilterToggle'
Expand All @@ -14,7 +15,7 @@ const DateSection = styled.View`
display: flex;
flex-direction: column;
gap: 12px;
margin: 0 5px 15px;
margin: 15px 5px;
align-items: center;
`

Expand Down Expand Up @@ -84,9 +85,9 @@ const EventsDateFilter = ({
setStartDate={setStartDate}
currentInput={currentInput.current}
/>
<DateSection>
<FilterToggle isDateFilterActive={showDateFilter} setToggleDateFilter={setShowDateFilter} />
{showDateFilter && (
<FilterToggle isDateFilterActive={showDateFilter} setToggleDateFilter={setShowDateFilter} />
<Accordion isOpen={showDateFilter} viewKey='Accordion'>
<DateSection>
<>
<DatePicker
modalOpen={modalOpen}
Expand All @@ -104,8 +105,8 @@ const EventsDateFilter = ({
date={endDate}
/>
</>
)}
</DateSection>
</DateSection>
</Accordion>
<>
{(startDate || endDate) && (
<StyledButton
Expand Down
33 changes: 33 additions & 0 deletions web/src/components/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useRef, useEffect, useState, ReactElement } from 'react'
import styled from 'styled-components'

const AccordionWrapper = styled.div<{ height: number }>`
overflow: hidden;
transition: height 0.3s ease;
height: ${props => props.height}px;
width: 100%;
`

type AccordionProps = {
isOpen: boolean
children: React.ReactNode
}

const Accordion = ({ isOpen, children }: AccordionProps): ReactElement => {
const [height, setHeight] = useState(0)
const contentRef = useRef<HTMLDivElement>(null)

useEffect(() => {
if (contentRef.current) {
setHeight(isOpen ? contentRef.current.scrollHeight : 0)
}
}, [isOpen, children])

return (
<AccordionWrapper ref={contentRef} height={height}>
{children}
</AccordionWrapper>
)
}

export default Accordion
11 changes: 2 additions & 9 deletions web/src/components/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ import { useTranslation } from 'react-i18next'
import styled from 'styled-components'

import { CalendarTodayIcon } from '../assets'
import dimensions from '../constants/dimensions'

const INPUT_MIN_WIDTH = '316px'
const INPUT_HEIGHT = '56px'
const INPUT_MIN_WIDTH_ON_MID_VIEWPORT = '240px'

const DateContainer = styled.div`
width: fit-content;
position: relative;
`

const StyledInput = styled.input`
min-width: ${INPUT_MIN_WIDTH};
width: 240px;
height: ${INPUT_HEIGHT};
padding: 0 16px;
border-radius: 8px;
Expand All @@ -43,10 +40,6 @@ const StyledInput = styled.input`
background-color: ${props => props.theme.colors.themeColorLight};
}
}
@media ${dimensions.mediumViewport} {
min-width: ${INPUT_MIN_WIDTH_ON_MID_VIEWPORT};
}
`

const StyledTitle = styled.span`
Expand Down Expand Up @@ -84,7 +77,7 @@ const isValidIsoDate = (date: string): boolean => {
const DatePicker = ({ title, date, setDate, error }: DatePickerProps): ReactElement => {
const { t } = useTranslation('events')
const [tempDate, setTempDate] = useState(date?.toISODate() ?? '')
const isInvalidDate = tempDate !== '' && isValidIsoDate(tempDate) === false
const isInvalidDate = !!tempDate && !isValidIsoDate(tempDate)
const shownError = error || (isInvalidDate ? t('invalidToDate') : undefined)
useEffect(() => {
setTempDate(date?.toISODate() ?? '')
Expand Down
13 changes: 7 additions & 6 deletions web/src/components/EventsDateFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import styled from 'styled-components'

import { CloseIcon } from '../assets'
import dimensions from '../constants/dimensions'
import Accordion from './Accordion'
import DatePicker from './DatePicker'
import FilterToggle from './FilterToggle'
import Button from './base/Button'
Expand All @@ -13,8 +14,8 @@ import Icon from './base/Icon'
const DateSection = styled.div`
display: flex;
gap: 10px;
margin: 0 5px 15px;
justify-content: center;
margin: 15px 5px;
justify-content: space-evenly;
@media ${dimensions.smallViewport} {
flex-direction: column;
Expand Down Expand Up @@ -63,8 +64,8 @@ const EventsDateFilter = ({
return (
<>
<FilterToggle isDateFilterActive={showDateFilter} setToggleDateFilter={setShowDateFilter} />
<DateSection>
{showDateFilter && (
<Accordion isOpen={showDateFilter}>
<DateSection>
<>
<DatePicker
title={t('from')}
Expand All @@ -74,8 +75,8 @@ const EventsDateFilter = ({
/>
<DatePicker title={t('to')} date={endDate} setDate={setEndDate} />
</>
)}
</DateSection>
</DateSection>
</Accordion>
{(startDate || endDate) && (
<StyledButton
label='resetDate'
Expand Down
1 change: 0 additions & 1 deletion web/src/components/FilterToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Icon from './base/Icon'

const StyledButton = styled(Button)`
display: flex;
flex-direction: row;
align-items: center;
gap: 5px;
white-space: nowrap;
Expand Down

0 comments on commit 1f1ca05

Please sign in to comment.