-
Notifications
You must be signed in to change notification settings - Fork 21
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
Reset all filters button on Events page #435
Changes from 8 commits
e5e0181
4ab0a28
162fbe8
02c688f
d8d6b99
08999f9
740f9d9
e6a28c7
ce17274
06d1e28
4f79e3c
1a9bd19
f1176bc
43da313
11c94b6
923aff7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -187,5 +187,6 @@ export default { | |
stageImage: "community" | ||
} | ||
] | ||
} | ||
}, | ||
resetAllFilters: "Reset all filters" | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,38 +13,59 @@ import { | |
} from "../../constants/colors"; | ||
import text from "../../constants/text"; | ||
import { formatDateRange } from "../../data/formatters"; | ||
import ResetAllFiltersButton from "./ResetAllFiltersButton"; | ||
|
||
export type Props = { | ||
onFilterCategoriesPress: Function, | ||
dateFilter: ?DateRange, | ||
onFilterButtonPress: () => void, | ||
onDateFilterButtonPress: () => void, | ||
selectedCategories: Set<EventCategoryName>, | ||
numTagFiltersSelected: number | ||
numTagFiltersSelected: number, | ||
resetAllFiltersPress: () => void, | ||
scrollEventListToTop: () => void | ||
}; | ||
|
||
class FilterHeader extends React.PureComponent<Props> { | ||
static defaultProps = { | ||
resetAllFiltersPress: () => {} | ||
}; | ||
|
||
render() { | ||
const { | ||
dateFilter, | ||
onFilterCategoriesPress, | ||
selectedCategories, | ||
onFilterButtonPress, | ||
onDateFilterButtonPress, | ||
numTagFiltersSelected | ||
numTagFiltersSelected, | ||
resetAllFiltersPress, | ||
scrollEventListToTop | ||
} = this.props; | ||
const formattedDateFilter = dateFilter | ||
? formatDateRange(dateFilter) | ||
: text.selectDates; | ||
|
||
const anyAppliedFilters: boolean = | ||
!!dateFilter || numTagFiltersSelected > 0 || selectedCategories.size > 0; | ||
|
||
return ( | ||
<View accessibilityTraits={["header"]} style={styles.container}> | ||
<ContentPadding> | ||
<View testID="event-filter-header" style={styles.content}> | ||
<FilterHeaderCategories | ||
onFilterPress={onFilterCategoriesPress} | ||
selectedCategories={selectedCategories} | ||
<View> | ||
<ResetAllFiltersButton | ||
visible={anyAppliedFilters} | ||
onPress={() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you elaborate a bit? Not sure I follow this point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As fas as I know, this will generate a new function every time in We could solve this by adding the function to the resetAllFilters = () => {
this.props.resetAllFiltersPress();
this.props.scrollEventListToTop();
}; Then use |
||
resetAllFiltersPress(); | ||
scrollEventListToTop(); | ||
}} | ||
/> | ||
<View testID="event-filter-header" style={styles.content}> | ||
<FilterHeaderCategories | ||
onFilterPress={onFilterCategoriesPress} | ||
selectedCategories={selectedCategories} | ||
/> | ||
</View> | ||
</View> | ||
</ContentPadding> | ||
<View style={styles.contentFilters}> | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,113 @@ | ||||||||
// @flow | ||||||||
import React from "react"; | ||||||||
import { Animated, StyleSheet, Easing } from "react-native"; | ||||||||
import type { ViewLayoutEvent } from "react-native/Libraries/Components/View/ViewPropTypes"; | ||||||||
import FilterHeaderButton from "./FilterHeaderButton"; | ||||||||
import text from "../../constants/text"; | ||||||||
|
||||||||
type Props = { | ||||||||
visible: boolean, | ||||||||
onPress: () => void, | ||||||||
animationTime: number, | ||||||||
animationDelay: number | ||||||||
}; | ||||||||
|
||||||||
type State = { | ||||||||
isAnimating: boolean | ||||||||
}; | ||||||||
|
||||||||
const DEFAULT_HEIGHT = 120; | ||||||||
const DEFAULT_FADE_VALUE = 1; | ||||||||
const DEFAULT_TOP_OFFSET_VALUE = 0; | ||||||||
|
||||||||
class ResetAllFiltersButton extends React.Component<Props, State> { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to make this a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Certainly! |
||||||||
static defaultProps = { | ||||||||
animationTime: 200, | ||||||||
animationDelay: 50 | ||||||||
}; | ||||||||
|
||||||||
constructor(props: Props) { | ||||||||
super(props); | ||||||||
this.state = { | ||||||||
isAnimating: false | ||||||||
}; | ||||||||
} | ||||||||
|
||||||||
setButtonHeight = (e: ViewLayoutEvent): void => { | ||||||||
const { height } = e.nativeEvent.layout; | ||||||||
this.height = height; | ||||||||
}; | ||||||||
|
||||||||
fadeOut = (): void => { | ||||||||
const { animationTime, animationDelay } = this.props; | ||||||||
|
||||||||
Animated.parallel([ | ||||||||
Animated.timing(this.fadeValue, { | ||||||||
toValue: 0, | ||||||||
duration: animationTime / 2 | ||||||||
}), | ||||||||
Animated.timing(this.topOffset, { | ||||||||
toValue: -this.height, | ||||||||
duration: animationTime, | ||||||||
easing: Easing.out(Easing.quad), | ||||||||
delay: animationDelay | ||||||||
}) | ||||||||
]).start(this.animationFinished); | ||||||||
}; | ||||||||
|
||||||||
resetAllFilters = (): void => { | ||||||||
this.props.onPress(); | ||||||||
this.setState({ isAnimating: true }); | ||||||||
this.fadeOut(); | ||||||||
}; | ||||||||
|
||||||||
resetAnimation = (): void => { | ||||||||
this.topOffset = new Animated.Value(DEFAULT_TOP_OFFSET_VALUE); | ||||||||
this.fadeValue = new Animated.Value(DEFAULT_FADE_VALUE); | ||||||||
}; | ||||||||
|
||||||||
animationFinished = (): void => { | ||||||||
this.setState({ isAnimating: false }); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be called when the button has already been unmounted, in which case There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yeah, good catch. I notice that isMounted() is now deprecated. Do you have a pattern in mind to catch this? Maybe a try catch (might be a bit crude). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looked into this a bit more and there is a post from Dan Abramov on this issue:
It is now only a warning and not an error so inclined to leave this as is due do it being a edgy edge case unless you think it will be a major issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, interesting. We tested this we @RGBboy for the heart animation. I'm pretty sure we could make this crash. 🤔 As far as I can see the recommendation is to set a field, which is basically what we ended up doing here: pride-london-app/src/components/SaveEventButton.js Lines 52 to 54 in 3a94242
Maybe our crash was unrelated though and we can just leave this at it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I created a unit test for |
||||||||
this.resetAnimation(); | ||||||||
}; | ||||||||
|
||||||||
topOffset: Animated.Value = new Animated.Value(DEFAULT_TOP_OFFSET_VALUE); | ||||||||
fadeValue: Animated.Value = new Animated.Value(DEFAULT_FADE_VALUE); | ||||||||
height: number = DEFAULT_HEIGHT; | ||||||||
|
||||||||
render() { | ||||||||
const isVisible: boolean = this.state.isAnimating || this.props.visible; | ||||||||
return ( | ||||||||
isVisible && ( | ||||||||
<Animated.View | ||||||||
onLayout={this.setButtonHeight} | ||||||||
style={[ | ||||||||
styles.clearAllWrapper, | ||||||||
{ opacity: this.fadeValue, marginTop: this.topOffset } | ||||||||
]} | ||||||||
> | ||||||||
<FilterHeaderButton | ||||||||
active={false} | ||||||||
text={text.resetAllFilters} | ||||||||
label={text.resetAllFilters} | ||||||||
style={styles.clearAll} | ||||||||
onPress={this.resetAllFilters} | ||||||||
/> | ||||||||
</Animated.View> | ||||||||
) | ||||||||
); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
const styles = StyleSheet.create({ | ||||||||
clearAll: { | ||||||||
minHeight: 0, | ||||||||
paddingTop: 16 | ||||||||
}, | ||||||||
clearAllWrapper: { | ||||||||
flexDirection: "row", | ||||||||
justifyContent: "flex-end" | ||||||||
} | ||||||||
}); | ||||||||
|
||||||||
export default ResetAllFiltersButton; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎺