-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(Messaggi a valore legale): [IAMVL-20] Display legal message met…
…adata (#3596) * wip * add legalmessageheader * simplify CtaBar and HeaderDueDateBar * fix * fix * rework CTABar * refactoring * add placeholders * fix tests * add comments * addd tests * align images to center * refactoring * fix mock due date * delete style * fix merge * add react-native-render-html and first MvlBody * refactoring * renaming * change mock text * graphical refinement * add tests * remove comment * add digital information representation * add comments * finalize mvlAttachments style * add comments * add confirmation bottomsheet * clean * fix test * add todo * add todo * refactoring * add tests * add rawaccordion * add Animation * Add metadata description * render links * change arrow rotation * refactoring * refactoring RawAccordion * add IOAccordion and showroom update * update snapshot * change message title to mvl subject * fix * update mock * add tests * add mvlmetadata test * fix * sender sender link only if there are others cc * add tests and refactoring * add missing data for MvlMetadata * Update ts/components/core/accordion/IOAccordion.tsx * remove unnecessary data * remove feedback * use isAndroid * add comment Co-authored-by: Matteo Boschi <[email protected]> Co-authored-by: pietro909 <[email protected]>
- Loading branch information
1 parent
e98e05f
commit 0dc8658
Showing
19 changed files
with
663 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default () => { | ||
process.env.TZ = "UTC"; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import * as React from "react"; | ||
import { StyleSheet } from "react-native"; | ||
import themeVariables from "../../../theme/variables"; | ||
import { H3 } from "../typography/H3"; | ||
import { IOStyles } from "../variables/IOStyles"; | ||
import { RawAccordion } from "./RawAccordion"; | ||
|
||
type Props = Omit<React.ComponentProps<typeof RawAccordion>, "header"> & { | ||
title: string; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
header: { | ||
marginVertical: themeVariables.contentPadding | ||
} | ||
}); | ||
|
||
/** | ||
* A simplified accordion that accepts a title and one child and uses {@link RawAccordion} | ||
* @param props | ||
* @constructor | ||
*/ | ||
export const IOAccordion = (props: Props): React.ReactElement => ( | ||
<RawAccordion | ||
animated={props.animated} | ||
headerStyle={styles.header} | ||
accessibilityLabel={props.title} | ||
header={ | ||
<H3 numberOfLines={1} style={IOStyles.flex}> | ||
{props.title} | ||
</H3> | ||
} | ||
> | ||
{props.children} | ||
</RawAccordion> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { View } from "native-base"; | ||
import * as React from "react"; | ||
import { useEffect, useRef, useState } from "react"; | ||
import { | ||
AccessibilityProps, | ||
Animated, | ||
Easing, | ||
LayoutAnimation, | ||
StyleSheet, | ||
TouchableWithoutFeedback, | ||
UIManager | ||
} from "react-native"; | ||
import I18n from "../../../i18n"; | ||
import themeVariables from "../../../theme/variables"; | ||
import customVariables from "../../../theme/variables"; | ||
import { isAndroid } from "../../../utils/platform"; | ||
import IconFont from "../../ui/IconFont"; | ||
import { IOStyles } from "../variables/IOStyles"; | ||
|
||
// TODO: handle external initial open/closed state | ||
type Props = { | ||
// The header component, an arrow indicating the open/closed state will be added on the right | ||
header: React.ReactElement; | ||
// The accordion component must accept one children | ||
children: React.ReactElement; | ||
// The component should be animated? default: true | ||
animated?: boolean; | ||
headerStyle?: React.ComponentProps<typeof View>["style"]; | ||
accessibilityLabel?: AccessibilityProps["accessibilityLabel"]; | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
headerIcon: { | ||
alignSelf: "center" | ||
}, | ||
row: { | ||
...IOStyles.row, | ||
justifyContent: "space-between" | ||
}, | ||
internalHeader: { | ||
flex: 1, | ||
paddingRight: themeVariables.contentPadding | ||
} | ||
}); | ||
|
||
/** | ||
* Obtains the degree starting from the open state | ||
* @param isOpen | ||
*/ | ||
const getDegree = (isOpen: boolean) => (isOpen ? "-90deg" : "-270deg"); | ||
|
||
/** | ||
* The base accordion component, implements the opening and closing logic for viewing the children | ||
* @param props | ||
* @constructor | ||
*/ | ||
export const RawAccordion: React.FunctionComponent<Props> = props => { | ||
const [isOpen, setOpen] = useState<boolean>(false); | ||
const animatedController = useRef(new Animated.Value(1)).current; | ||
const shouldAnimate = props.animated ?? true; | ||
const headerStyle = props.headerStyle ?? {}; | ||
const accessibilityLabel = props.accessibilityLabel | ||
? `${props.accessibilityLabel}, ` | ||
: ""; | ||
|
||
const arrowAngle = shouldAnimate | ||
? animatedController.interpolate({ | ||
inputRange: [0, 1], | ||
outputRange: ["-90deg", "-270deg"] | ||
}) | ||
: getDegree(isOpen); | ||
|
||
useEffect(() => { | ||
if (isAndroid) { | ||
UIManager.setLayoutAnimationEnabledExperimental(shouldAnimate); | ||
} | ||
}, [shouldAnimate]); | ||
|
||
const onPress = () => { | ||
if (shouldAnimate) { | ||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); | ||
Animated.timing(animatedController, { | ||
duration: 300, | ||
toValue: isOpen ? 1 : 0, | ||
useNativeDriver: true, | ||
easing: Easing.linear | ||
}).start(); | ||
} | ||
setOpen(!isOpen); | ||
}; | ||
|
||
return ( | ||
<View style={IOStyles.flex}> | ||
<TouchableWithoutFeedback | ||
onPress={onPress} | ||
accessible={true} | ||
accessibilityRole={"button"} | ||
accessibilityLabel={ | ||
accessibilityLabel + | ||
(isOpen | ||
? I18n.t("global.accessibility.expanded") | ||
: I18n.t("global.accessibility.collapsed")) | ||
} | ||
> | ||
<View style={[styles.row, headerStyle]}> | ||
<View style={styles.internalHeader}>{props.header}</View> | ||
<Animated.View | ||
testID={"ArrowAccordion"} | ||
style={{ | ||
...styles.headerIcon, | ||
transform: [{ rotateZ: arrowAngle }] | ||
}} | ||
> | ||
<IconFont | ||
name={"io-right"} | ||
color={customVariables.brandPrimary} | ||
size={24} | ||
/> | ||
</Animated.View> | ||
</View> | ||
</TouchableWithoutFeedback> | ||
{isOpen && props.children} | ||
</View> | ||
); | ||
}; |
131 changes: 131 additions & 0 deletions
131
ts/components/core/accordion/__test__/RawAccordion.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { fireEvent, render } from "@testing-library/react-native"; | ||
import { View } from "native-base"; | ||
import * as React from "react"; | ||
import Fingerprint from "../../../../../img/test/fingerprint.svg"; | ||
import I18n from "../../../../i18n"; | ||
import { Body } from "../../typography/Body"; | ||
import { H3 } from "../../typography/H3"; | ||
import { IOColors } from "../../variables/IOColors"; | ||
import { IOStyles } from "../../variables/IOStyles"; | ||
import { RawAccordion } from "../RawAccordion"; | ||
|
||
const bodyText = "This is a body text"; | ||
const headerText = "This is an header text"; | ||
|
||
describe("RawAccordion", () => { | ||
jest.useFakeTimers(); | ||
|
||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
describe("When a RawAccordion is rendered for the first time", () => { | ||
it("Should be in the closed state", () => { | ||
const res = renderRawAccordion(); | ||
expect(res.queryByText(headerText)).not.toBeNull(); | ||
expect(res.queryByText(bodyText)).toBeNull(); | ||
}); | ||
describe("And the header is tapped", () => { | ||
it("Should expand and display the content", () => { | ||
const res = renderRawAccordion(); | ||
const header = res.queryByText(headerText); | ||
if (header !== null) { | ||
fireEvent.press(header); | ||
expect(res.queryByText(headerText)).not.toBeNull(); | ||
expect(res.queryByText(bodyText)).not.toBeNull(); | ||
} else { | ||
fail("header not found"); | ||
} | ||
}); | ||
describe("And the header is tapped again", () => { | ||
it("Should close and hide the content", () => { | ||
const res = renderRawAccordion(); | ||
const header = res.queryByText(headerText); | ||
if (header !== null) { | ||
fireEvent.press(header); | ||
fireEvent.press(header); | ||
expect(res.queryByText(bodyText)).toBeNull(); | ||
} else { | ||
fail("header not found"); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe("And no accessibilityLabel is used", () => { | ||
it("Should use only global.accessibility.collapsed", () => { | ||
const res = renderRawAccordion(); | ||
expect( | ||
res.queryByA11yLabel(I18n.t("global.accessibility.collapsed")) | ||
).not.toBeNull(); | ||
}); | ||
describe("And the header is tapped", () => { | ||
it("Should use only global.accessibility.expanded", () => { | ||
const res = renderRawAccordion(); | ||
const header = res.queryByText(headerText); | ||
if (header !== null) { | ||
fireEvent.press(header); | ||
expect( | ||
res.queryByA11yLabel(I18n.t("global.accessibility.expanded")) | ||
).not.toBeNull(); | ||
} else { | ||
fail("header not found"); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe("Accessibility", () => { | ||
describe("And an accessibilityLabel is used", () => { | ||
it("Should use accessibilityLabel and global.accessibility.collapsed", () => { | ||
const res = renderRawAccordion({ | ||
accessibilityLabel: "CustomAccessibilityLabel" | ||
}); | ||
expect( | ||
res.queryByA11yLabel( | ||
`CustomAccessibilityLabel, ${I18n.t( | ||
"global.accessibility.collapsed" | ||
)}` | ||
) | ||
).not.toBeNull(); | ||
}); | ||
describe("And the header is tapped", () => { | ||
it("Should use accessibilityLabel and global.accessibility.expanded", () => { | ||
const res = renderRawAccordion({ | ||
accessibilityLabel: "CustomAccessibilityLabel" | ||
}); | ||
const header = res.queryByText(headerText); | ||
if (header !== null) { | ||
fireEvent.press(header); | ||
expect( | ||
res.queryByA11yLabel( | ||
`CustomAccessibilityLabel, ${I18n.t( | ||
"global.accessibility.expanded" | ||
)}` | ||
) | ||
).not.toBeNull(); | ||
} else { | ||
fail("header not found"); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
const renderRawAccordion = ( | ||
props?: Pick<React.ComponentProps<typeof RawAccordion>, "accessibilityLabel"> | ||
) => | ||
render( | ||
<RawAccordion | ||
accessibilityLabel={props?.accessibilityLabel} | ||
headerStyle={{ | ||
paddingVertical: 16, | ||
backgroundColor: IOColors.greyLight | ||
}} | ||
header={ | ||
<View style={IOStyles.row}> | ||
<Fingerprint width={32} height={32} /> | ||
<H3 style={{ alignSelf: "center" }}>{headerText}</H3> | ||
</View> | ||
} | ||
> | ||
<Body>{bodyText}</Body> | ||
</RawAccordion> | ||
); |
Oops, something went wrong.