Skip to content

Commit

Permalink
Terms Stack (#70)
Browse files Browse the repository at this point in the history
* Terms Stack

Signed-off-by: Jean-Christophe <[email protected]>

* Adding accordion to terms and translation.

* Removed bottom text.

* Removed unused import.

* Fixed margins and got closer to the design from Figma.

* Adding TestId accordion

Signed-off-by: agueye84 <[email protected]>

* Update index.ts

Signed-off-by: agueye84 <[email protected]>

* Terms Stack

Signed-off-by: agueye84 <[email protected]>

* Terms Stack

Signed-off-by: agueye84 <[email protected]>

---------

Signed-off-by: Jean-Christophe <[email protected]>
Signed-off-by: agueye84 <[email protected]>
Signed-off-by: agueye84 <[email protected]>
Co-authored-by: Nicolas Dumais <[email protected]>
Co-authored-by: agueye84 <[email protected]>
Co-authored-by: agueye84 <[email protected]>
  • Loading branch information
4 people authored Apr 12, 2023
1 parent dcd4ba5 commit 692fff9
Show file tree
Hide file tree
Showing 13 changed files with 488 additions and 377 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { LayoutAnimation, LayoutAnimationConfig } from 'react-native'

/**
* Toggle animation config
* @param animationDuration
* @return LayoutAnimationConfig
*/
export const toggleAnimation = (animationDuration = 300): LayoutAnimationConfig => {
return {
duration: animationDuration,
update: {
duration: animationDuration,
property: LayoutAnimation.Properties.scaleXY,
type: LayoutAnimation.Types.easeInEaseOut,
},
delete: {
duration: animationDuration,
property: LayoutAnimation.Properties.opacity,
type: LayoutAnimation.Types.easeInEaseOut,
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useEffect, useRef, useState } from 'react'
import { View, Animated, LayoutAnimation, I18nManager, Pressable } from 'react-native'
import MaterialIcons from 'react-native-vector-icons/MaterialIcons'

import { toggleAnimation } from '../../animations/toggleAnimation'
import { AccordionItemProps } from '../../models/AccordionItem'

import { styles } from './styles'

const AccordionItem = ({
customBody,
customTitle,
customIcon = undefined,
containerStyle = {},
animationDuration = 300,
isRTL = false,
isOpen = false,
onPress = undefined,
testID,
}: AccordionItemProps) => {
const [showContent, setShowContent] = useState(isOpen)
const animationController = useRef(new Animated.Value(isOpen ? 1 : 0)).current

const toggleListItem = () => {
const config = {
duration: animationDuration,
toValue: showContent ? 0 : 1,
useNativeDriver: true,
}
Animated.timing(animationController, config).start()
LayoutAnimation.configureNext(toggleAnimation(animationDuration))
if (onPress) onPress(!showContent)
setShowContent(!showContent)
}

useEffect(() => {
if (showContent && !isOpen) {
toggleListItem()
}
}, [isOpen])

const arrowTransform = animationController.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', isRTL ? '-90deg' : '90deg'],
})
return (
<View style={[styles.container, containerStyle]}>
<Pressable onPress={() => toggleListItem()} testID={testID}>
<View style={styles.titleContainer}>
{(!isRTL || I18nManager.isRTL) && customTitle()}
<Animated.View style={{ transform: [{ rotateZ: arrowTransform }] }}>
{!customIcon ? (
<MaterialIcons name={isRTL ? 'keyboard-arrow-left' : 'keyboard-arrow-right'} size={30} />
) : (
customIcon()
)}
</Animated.View>
{isRTL && !I18nManager.isRTL && customTitle()}
</View>
</Pressable>
{showContent && customBody()}
</View>
)
}
export default AccordionItem
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useTheme } from 'aries-bifold'
import { StyleSheet } from 'react-native'

const { ColorPallet } = useTheme()
export const styles = StyleSheet.create({
container: {
width: '100%',
borderRadius: 2,
marginBottom: '2%',
overflow: 'hidden',

borderStyle: 'solid',
borderWidth: 1,
borderColor: ColorPallet.grayscale.lightGrey,
},
title: {
fontSize: 16,
color: '#2d2d2d',
fontWeight: 'bold',
},
body: {
padding: '4%',
paddingHorizontal: '2%',
paddingVertical: '3%',
},
titleContainer: {
padding: '4%',
backgroundColor: ColorPallet.grayscale.lightGrey,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { testIdWithKey } from 'aries-bifold'
import React, { useState } from 'react'
import { FlatList } from 'react-native'

import { AccordionListProps } from '../../models/AccordionList'
import AccordionItem from '../AccordionItem'

const AccordionList = ({
data,
customTitle,
customBody,
customIcon = undefined,
containerItemStyle = {},
animationDuration = 300,
isRTL = false,
expandMultiple = false,
...props
}: AccordionListProps) => {
const [currentlyOpen, setCurrentlyOpen] = useState<any>(null)
const renderItem = ({ item, index }: { item: any, index: number }) => (
<AccordionItem
containerStyle={containerItemStyle}
customTitle={() => customTitle(item)}
customBody={() => customBody(item)}
customIcon={customIcon}
animationDuration={animationDuration}
isRTL={isRTL}
isOpen={JSON.stringify(currentlyOpen) === JSON.stringify(item)}
onPress={(status) => {
if (status && !expandMultiple) {
setCurrentlyOpen(item)
}
}}
testID={testIdWithKey('AccordionItem'+index)}
/>
)
return <FlatList data={data} renderItem={renderItem} keyExtractor={(item, index) => index.toString()} {...props} />
}

export default AccordionList
5 changes: 5 additions & 0 deletions app/src/components/react-native-accordion-list-view/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AccordionItem from './components/AccordionItem'
import AccordionList from './components/AccordionList'

// default export
export { AccordionItem, AccordionList }
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ViewStyle } from 'react-native'

export interface AccordionItemProps {
/**
* Function that returns a React element to display as Accordion title
*/
customTitle: () => JSX.Element
/**
* Function that returns a React element to display as Accordion body
*/
customBody: () => JSX.Element
/**
* An optional Function that returns a React element to display as Accordion icon
* default icon keyboard-arrow-left
*/
customIcon?: () => JSX.Element
/**
* An optional param to add custom container style
*/
containerStyle?: ViewStyle
/**
* An optional param to control Accordion animation duration
* default value is 300
*/
animationDuration?: number
/**
* An optional param to support RTL layout
* default value is false
*/
isRTL?: boolean
/**
* An optional param to make accordion item already open
* default value is false
*/
isOpen?: boolean
/**
* An optional param to call a function when a click happen to accordion item
* default value is undefined
* @param {boolean} isOpen the current state of the accordion item
*/
onPress?: (isOpen: boolean) => void
/**
* An optional param to support test ID
* default value is ''
*/
testID?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { FlatListProps, ViewStyle } from 'react-native'

export interface AccordionListProps extends Omit<FlatListProps<any>, 'data' | 'renderItem'> {
/**
* For simplicity, data is a plain array.
* If you want to use something else, like an immutable list
*/
data: any[]
/**
* Function that returns a React element to display as Accordion title
*/
customTitle: (item: any) => JSX.Element
/**
* Function that returns a React element to display as Accordion body
*/
customBody: (item: any) => JSX.Element
/**
* An optional Function that returns a React element to display as Accordion icon
* default icon keyboard-arrow-left
*/
customIcon?: () => JSX.Element
/**
* An optional param to add custom container item style
*/
containerItemStyle?: ViewStyle
/**
* An optional param to control Accordion animation duration
* default value is 300
*/
animationDuration?: number
/**
* An optional param to support RTL layout
* default value is false
*/
isRTL?: boolean

/**
* Allow more than one section to be expanded.
* default value is false
*/
expandMultiple?: boolean
}
4 changes: 2 additions & 2 deletions app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import { PINValidationRules } from './constants'
import { useNotifications } from './hooks/notifications'
import en from './localization/en'
import fr from './localization/fr'
import TermsStack from './navigators/TermsStack'
import Developer from './screens/Developer'
import { pages } from './screens/OnboardingPages'
import PersonCredentialScreen from './screens/PersonCredential'
import Splash from './screens/Splash'
import Terms from './screens/Terms'
import { BCDispatchAction } from './store'
import { defaultTheme as theme } from './theme'

Expand All @@ -38,7 +38,7 @@ const configuration: ConfigurationContext = {
...defaultConfiguration,
pages,
splash: Splash,
terms: Terms,
terms: TermsStack,
useBiometry: UseBiometry,
credentialListHeaderRight: AddCredentialButton,
credentialListOptions: AddCredentialSlider,
Expand Down
84 changes: 78 additions & 6 deletions app/src/localization/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,84 @@ const translation = {
StatusMessages: {
InitAgent: 'Initializing agent ..',
},
Terms: {
TermsOfService: 'Terms of Service',
TermsOfServiceText:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vel consectetur diam. Nunc sit amet elit est. Praesent libero elit, consectetur dapibus diam non, facilisis euismod velit. Etiam a ligula eget leo elementum tincidunt. Fusce et lorem turpis. Nunc tempus nisl consectetur eros vehicula venenatis. Suspendisse potenti. Aenean vitae aliquet augue. Maecenas lacinia nunc vitae blandit hendrerit. Sed congue risus quis magna convallis sollicitudin. Integer in ante vel orci ornare porta quis id libero. Proin mollis urna nec lectus fringilla, sit amet aliquam urna fringilla. Praesent pellentesque non augue et gravida. Donec congue urna ac massa consequat, lacinia condimentum dolor blandit. Nam ultrices tellus at risus dignissim, quis cursus mauris pellentesque. Donec at scelerisque ipsum. Praesent eu massa at tellus cursus ornare. Fusce vel faucibus dolor. Etiam blandit velit sed velit tempus feugiat. Donec condimentum pretium suscipit. Sed suscipit, leo molestie tempus maximus, turpis enim hendrerit nibh, semper sagittis turpis velit sed nisl. Aliquam eu ultrices velit. Aenean tristique mauris justo, eu commodo quam semper non. Curabitur ultricies auctor mi eu tempus. Sed bibendum eros sed neque semper fermentum. Nullam porta tortor ut ante congue molestie. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur sit amet aliquam nunc, malesuada auctor quam. Pellentesque vel lobortis risus, volutpat suscipit velit. Aenean ut erat sed metus interdum mattis. Nam consectetur ante eu felis rhoncus, et volutpat dolor tincidunt. Vivamus sit amet feugiat mi. Proin in dui ac metus vehicula fringilla eget id mauris. Maecenas et elit venenatis dolor pulvinar pulvinar in et leo. Aliquam scelerisque viverra sapien at bibendum. Curabitur et libero nec enim convallis porttitor sed a libero. In hac habitasse platea dictumst. Integer dignissim velit eu pharetra ultricies. Vestibulum at velit hendrerit, pretium purus eget, lobortis tellus. Maecenas non erat ut lacus scelerisque luctus et et tellus.',
IAgree: 'I Agree',
Attestation: 'I have read, understand and accept the terms of this EULA.',
TermsV2: {
Consent: {
title: 'Consent',
body: 'Please read the general conditions for the use of the digital portfolio of the Government of Quebec.',
PersonalUse: {
title: 'Exclusive Personal Use',
body:
'You are responsible for the confidentiality of your digital portfolio. You must use it exclusively for your own purposes. Do not divulge your access code to anyone and protect your mobile phone adequately.\n' +
'You will find recommendations in the Security section.',
subsection: {
title: 'Acceptable Use',
body:
'In connection with your use of the Licensed Application, you shall not take any action that may jeopardise the security, integrity and/or availability of the Licensed Application, including, without limitation: \n' +
'\n' +
'Using the Licensed Application for illegal or improper purposes; \n' +
'\n' +
'Tampering with any part of the Licensed Application; \n' +
'\n' +
'Using the Licensed Application to transmit any virus or other harmful or destructive computer code, files or programs, or to conduct hacking and/or intrusive activities; \n' +
'\n' +
'Attempt to circumvent or subvert any security measures associated with the Licensed Application; \n' +
'\n' +
'Take any action that could reasonably be construed to adversely affect other users of the Licensed Application; \n' +
'\n' +
'Where \n' +
'\n' +
'Remove or alter any proprietary symbols or notices, including any copyright, trademark or logo notices, displayed in connection with the Licensed Application. ',
},
},
IdentityTheft: {
title: 'In case of identity theft',
body: 'If you suspect that the security of your wallet and its contents has been compromised, you must contact *the Identity Quebec Customer Relations Centre* immediately. You will not be held responsible for identity theft as long as you comply with these terms and conditions',
subsection: {
title: 'Indemnification',
body:
'You agree to indemnify, defend and hold harmless the Province and all of its respective officers, employees and agents from and against any and all claims, demands, obligations, losses, liabilities, costs or debts and expenses (including, without limitation, reasonable legal fees).\n' +
'\n' +
' Arising out of:\n' +
'\n' +
' (a) your use of the Licensed Application;\n' +
'\n' +
' Where\n' +
'\n' +
' (b) your breach of any provision of this EULA',
},
},
Privacy: {
title: 'Protection and privacy',
body: "The Government of Quebec is concerned about the protection of your privacy and the personal and confidential information contained in this application. You are responsible for consulting the 'Privacy Policy' to learn about the Government of Quebec's practices in this regard",
subsection: {
title: 'Personal Information Protection',
body:
'If you visit the website of the application licensed to\n' +
'\n' +
'https://www.quebec.ca/gouvernement/ministere/cybersecurite-numerique,\n' +
'\n' +
'including accessing the Help Function for the licensed application or related content at https://www.quebec.ca/gouvernement/ministere/cybersecurite-numerique, certain information will be provided to you in accordance with the Province\'s Privacy Statement for Government Websites. Certain information is also collected as part of the licence application as set out in the Quebec Wallet App Privacy Policy (the "Privacy Policy"), which is incorporated by reference into and forms part of this EULA. You consent to the collection by the Licensed App of such information which, together with your Content, is stored locally on your device and is not accessible to the Province, except in cases where you choose to provide information to the Province as set forth in the Privacy Policy. Any information you provide to the Province that is "personal information", as defined in the Quebec Freedom of Information and Protection of Privacy Act ("the Act"), is collected by the Province pursuant to section 26c of the Act, for the purposes set out in the Privacy Policy. Any questions regarding the collection of this information may be directed to the contact person identified in Section 11. The consents you have provided pursuant to this section will continue until you revoke them in writing to the contact person identified in section 11, at which time this EULA will terminate immediately in accordance with section 9.',
},
},
AppAccess: {
title: 'Right of access to the application',
body: 'The Government of Quebec may suspend access to this application if you fail to comply with these terms of use. It may also do so for these terms of use. It may also do so for security or administrative purposes',
subsection: {
title: 'Limitation of liability',
body:
'To the extent permitted by applicable law, in no event shall the Province be liable to any person or entity for any direct, indirect, special, incidental or consequential loss, claim, injury or damage, or for any other loss, claim, injury or damage. \n' +
'\n' +
'If foreseeable or unforeseeable (including claims for limitation of damages for loss of profits or business opportunities, use or misuse of, or inability to use, the Licensed Application, interruptions, deletion or corruption of files, loss of programs or information, errors, defects or delays) arising out of or in any way connected with your use of the Licensed Application, whether based on contract, tort, strict liability or any other legal theory. The preceding sentence shall apply even if the Province has been expressly advised of the possibility of such loss, claim, injury or damage. The parties acknowledge that Apple is not responsible for: \n' +
'\n' +
'(a) dealing with any claim you or any third party may have in connection with the Authorized Application; \n' +
'\n' +
'b) your possession and/or use of the Permitted Application.',
},
},
More: {
body: 'Learn more about *these terms and conditions(*)*',
},
},
},
PinCreate: {
UserAuthenticationPin: 'User authentication pin',
Expand Down
Loading

0 comments on commit 692fff9

Please sign in to comment.