From bf9d3f1dae3a09001463edc0f0fc676f21eff88d Mon Sep 17 00:00:00 2001 From: Alex Ruzenhack Date: Mon, 1 Apr 2024 16:47:46 +0100 Subject: [PATCH 1/2] feat(nc): add components --- src/components/EditInfoContainer.component.js | 65 ++++++++++ src/components/HathorHeader.js | 10 +- src/components/ModalBase.component.js | 121 ++++++++++++++++++ src/components/NewHathorButton.js | 24 ++++ src/components/TextLabel.component.js | 28 ++++ src/components/TextValue.component.js | 28 ++++ src/utils.js | 3 + 7 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 src/components/EditInfoContainer.component.js create mode 100644 src/components/ModalBase.component.js create mode 100644 src/components/TextLabel.component.js create mode 100644 src/components/TextValue.component.js diff --git a/src/components/EditInfoContainer.component.js b/src/components/EditInfoContainer.component.js new file mode 100644 index 000000000..5ce731f23 --- /dev/null +++ b/src/components/EditInfoContainer.component.js @@ -0,0 +1,65 @@ +import React from 'react'; +import { + StyleSheet, + View, + TouchableOpacity +} from 'react-native'; +import { COLORS } from '../styles/themes'; + +import { PenIcon } from './Icon/Pen.icon'; + +export const EditInfoContainer = ({ center, onPress, children }) => ( + + + + {children} + + + + + + +); + +const styles = StyleSheet.create({ + editInfoWrapperCentered: { + alignSelf: 'center', + }, + editInfoContainer: { + paddingVertical: 8, + paddingLeft: 8, + paddingRight: 40, + borderRadius: 8, + backgroundColor: COLORS.white, + }, + editInfoContainerCentered: { + paddingLeft: 40, + }, + alignCenter: { + alignItems: 'center', + }, + editIcon: { + position: 'absolute', + display: 'flex', + justifyContent: 'center', + top: 0, + right: 0, + bottom: 0, + width: 24, + height: '100%', + marginVertical: 8, + marginRight: 8, + }, +}); diff --git a/src/components/HathorHeader.js b/src/components/HathorHeader.js index 493a9e404..f6a174b2a 100644 --- a/src/components/HathorHeader.js +++ b/src/components/HathorHeader.js @@ -30,6 +30,9 @@ const HathorHeader = ({ const left = React.Children.toArray(children).find( (child) => child.type.displayName === HathorHeaderLeft.displayName ); + const central = React.Children.toArray(children).find( + (child) => child.type.displayName === HathorHeaderCentral.displayName + ); const right = React.Children.toArray(children).find( (child) => child.type.displayName === HathorHeaderRight.displayName ); @@ -40,6 +43,7 @@ const HathorHeader = ({ && ( {left} + {central} {right} )} @@ -70,10 +74,14 @@ const InnerWrapper = ({ children }) => ( const HathorHeaderLeft = ({ children }) => ({children}); HathorHeaderLeft.displayName = 'HathorHeaderLeft'; +const HathorHeaderCentral = ({ style, children }) => {children}; +HathorHeaderCentral.displayName = 'HathorHeaderCentral'; + const HathorHeaderRight = ({ children }) => {children}; HathorHeaderRight.displayName = 'HathorHeaderRight'; HathorHeader.Left = HathorHeaderLeft; +HathorHeader.Central = HathorHeaderCentral; HathorHeader.Right = HathorHeaderRight; const CancelButton = ({ onCancel }) => ( @@ -118,7 +126,7 @@ const RightComponent = ({ rightElement, onCancel }) => { const styles = StyleSheet.create({ wrapper: { - height: STYLE.headerHeight, + minHeight: STYLE.headerHeight, flexDirection: 'row', alignItems: 'flex-end', borderColor: COLORS.borderColor, diff --git a/src/components/ModalBase.component.js b/src/components/ModalBase.component.js new file mode 100644 index 000000000..bb15769ea --- /dev/null +++ b/src/components/ModalBase.component.js @@ -0,0 +1,121 @@ +/** + * Copyright (c) Hathor Labs and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React, { ReactNode } from 'react'; +import { + StyleSheet, + View, + Text, + StyleProp, + ViewStyle +} from 'react-native'; +import Modal from 'react-native-modal'; + +import { COLORS } from '../styles/themes'; +import NewHathorButton from './NewHathorButton'; + +const ModalBase = ({ styleModal, styleWrapper, show, onDismiss, children }) => { + const hasChildren = children != null; + + const title = hasChildren && React.Children.toArray(children).find( + (child) => child.type.displayName === Title.displayName + ); + const body = hasChildren && React.Children.toArray(children).find( + (child) => child.type.displayName === Body.displayName + ); + const button = hasChildren && React.Children.toArray(children).find( + (child) => child.type.displayName === Button.displayName + ); + + const discreteButton = hasChildren && React.Children.toArray(children).find( + (child) => child.type.displayName === DiscreteButton.displayName + ); + + return ( + + + {title && title} + {body && body} + {button && button} + {discreteButton && discreteButton} + + + ); +}; + +const Title = ({ children }) => ( + + + {children} + + +); +Title.displayName = 'ModalBaseTitle'; + +/** + * @typedef {Object} Properties p + * @property {ReactNode} p.children + * @property {StyleProp} p.style + * + * @param {Properties} + */ +const Body = ({ style, children }) => ( + + {children} + +); +Body.displayName = 'ModalBaseBody'; + +const Button = ({ title, disabled, secondary, danger, onPress }) => ( + +); +Button.displayName = 'ModalBaseButton'; + +const DiscreteButton = ({ title, onPress }) => ( + +); +DiscreteButton.displayName = 'ModalBaseDiscreteButton'; + +ModalBase.Title = Title; +ModalBase.Body = Body; +ModalBase.Button = Button; +ModalBase.DiscreteButton = DiscreteButton; + +const styles = StyleSheet.create({ + wrapper: { + borderRadius: 8, + paddingVertical: 24, + paddingHorizontal: 16, + backgroundColor: COLORS.white, + }, + titleWrapper: { + paddingBottom: 20, + }, + title: { + color: 'black', + fontSize: 18, + lineHeight: 20, + }, + discreteButton: { + marginTop: 8, + }, +}); + +export { ModalBase } diff --git a/src/components/NewHathorButton.js b/src/components/NewHathorButton.js index a1603e949..1afe5e5d1 100644 --- a/src/components/NewHathorButton.js +++ b/src/components/NewHathorButton.js @@ -21,6 +21,11 @@ const NewHathorButton = (props) => { textStyle.push(style.textDisabled); } + if (props.discrete) { + wrapperViewStyle.push(style.wrapperDiscrete); + textStyle.push(style.textDiscrete); + } + if (props.secondary) { wrapperViewStyle.push(style.wrapperSecondary); textStyle.push(style.textSecondary); @@ -34,6 +39,11 @@ const NewHathorButton = (props) => { } } + if (props.danger) { + wrapperViewStyle.push(style.wrapperSecondaryDanger); + textStyle.push(style.textSecondaryDanger); + } + return ( @@ -79,6 +89,14 @@ const style = StyleSheet.create({ wrapperSecondaryDisabled: { borderColor: COLORS.textColorShadow, }, + wrapperDiscrete: { + backgroundColor: COLORS.backgroundColor, + borderColor: COLORS.backgroundColor, + borderWidth: 1.5, + }, + wrapperSecondaryDanger: { + borderColor: COLORS.errorBgColor, + }, touchable: { flex: 1, flexDirection: 'row', @@ -101,6 +119,12 @@ const style = StyleSheet.create({ textDisabled: { color: COLORS.textColorShadow, }, + textDiscrete: { + color: COLORS.freeze300, + }, + textSecondaryDanger: { + color: COLORS.errorBgColor, + }, }); export default NewHathorButton; diff --git a/src/components/TextLabel.component.js b/src/components/TextLabel.component.js new file mode 100644 index 000000000..cae53932e --- /dev/null +++ b/src/components/TextLabel.component.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { + StyleSheet, + Text, +} from 'react-native'; + +export const TextLabel = ({ pb8, bold, children }) => ( + {children} +); + +const styles = StyleSheet.create({ + textLabel: { + fontSize: 12, + lineHeight: 20, + color: 'hsla(0, 0%, 38%, 1)', + }, + pb8: { + paddingBottom: 8, + }, + bold: { + fontWeight: 'bold', + }, +}); diff --git a/src/components/TextValue.component.js b/src/components/TextValue.component.js new file mode 100644 index 000000000..f0e392f41 --- /dev/null +++ b/src/components/TextValue.component.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { + StyleSheet, + Text, +} from 'react-native'; + +export const TextValue = ({ bold, pb4, children }) => ( + {children} +); + +const styles = StyleSheet.create({ + textValue: { + fontSize: 14, + lineHeight: 20, + color: 'black', + }, + pb4: { + paddingBottom: 4, + }, + bold: { + fontWeight: 'bold', + }, +}); diff --git a/src/utils.js b/src/utils.js index e950f1354..3856c5c4d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -11,6 +11,7 @@ import React from 'react'; import { t } from 'ttag'; import { Linking, Platform, Text } from 'react-native'; import { getStatusBarHeight } from 'react-native-status-bar-height'; +import moment from 'moment'; import baseStyle from './styles/init'; import { KEYCHAIN_USER, NANO_CONTRACT_FEATURE_TOGGLE } from './constants'; import { STORE } from './store'; @@ -403,3 +404,5 @@ export const isPushNotificationAvailableForUser = (state) => ( export const getNanoContractFeatureToggle = (state) => ( state.featureToggles[NANO_CONTRACT_FEATURE_TOGGLE] ); + +export const getTimestampFormat = (timestamp) => moment.unix(timestamp).format('DD MMM YYYY [•] HH:mm') From e1d912d4a72488c1e5c41f25b76ef995937c6a59 Mon Sep 17 00:00:00 2001 From: Alex Ruzenhack Date: Tue, 14 May 2024 17:03:43 +0100 Subject: [PATCH 2/2] review: apply suggestions --- locale/da/texts.po | 2 +- locale/pt-br/texts.po | 2 +- locale/ru-ru/texts.po | 2 +- locale/texts.pot | 2 +- ...oContainer.component.js => EditInfoContainer.js} | 9 ++++++++- .../{ModalBase.component.js => ModalBase.js} | 13 ++++--------- .../{TextLabel.component.js => TextLabel.js} | 7 +++++++ .../{TextValue.component.js => TextValue.js} | 7 +++++++ src/utils.js | 9 ++++++++- 9 files changed, 38 insertions(+), 15 deletions(-) rename src/components/{EditInfoContainer.component.js => EditInfoContainer.js} (84%) rename src/components/{ModalBase.component.js => ModalBase.js} (92%) rename src/components/{TextLabel.component.js => TextLabel.js} (71%) rename src/components/{TextValue.component.js => TextValue.js} (70%) diff --git a/locale/da/texts.po b/locale/da/texts.po index d5cb9eac0..c42056faa 100644 --- a/locale/da/texts.po +++ b/locale/da/texts.po @@ -61,7 +61,7 @@ msgstr "[Sidste] dddd [•] HH:mm" msgid "DD MMM YYYY [•] HH:mm" msgstr "DD MMM YYYY [•] HH:mm" -#: src/utils.js:159 +#: src/utils.js:160 msgid "Invalid address" msgstr "Ugyldig adresse" diff --git a/locale/pt-br/texts.po b/locale/pt-br/texts.po index dae12e7e5..c502c4226 100644 --- a/locale/pt-br/texts.po +++ b/locale/pt-br/texts.po @@ -61,7 +61,7 @@ msgstr "[Última] dddd [•] HH:mm" msgid "DD MMM YYYY [•] HH:mm" msgstr "DD MMM YYYY [•] HH:mm" -#: src/utils.js:159 +#: src/utils.js:160 msgid "Invalid address" msgstr "Endereço inválido" diff --git a/locale/ru-ru/texts.po b/locale/ru-ru/texts.po index d06c178fe..ae00bf6ee 100644 --- a/locale/ru-ru/texts.po +++ b/locale/ru-ru/texts.po @@ -62,7 +62,7 @@ msgstr "[Последний] dddd [•] HH:mm" msgid "DD MMM YYYY [•] HH:mm" msgstr "DD MMM YYYY [•] HH:mm" -#: src/utils.js:159 +#: src/utils.js:160 msgid "Invalid address" msgstr "Неправильный адрес" diff --git a/locale/texts.pot b/locale/texts.pot index ffc40232d..2cb15ab4b 100644 --- a/locale/texts.pot +++ b/locale/texts.pot @@ -52,7 +52,7 @@ msgstr "" msgid "DD MMM YYYY [•] HH:mm" msgstr "" -#: src/utils.js:159 +#: src/utils.js:160 msgid "Invalid address" msgstr "" diff --git a/src/components/EditInfoContainer.component.js b/src/components/EditInfoContainer.js similarity index 84% rename from src/components/EditInfoContainer.component.js rename to src/components/EditInfoContainer.js index 5ce731f23..202e49ccc 100644 --- a/src/components/EditInfoContainer.component.js +++ b/src/components/EditInfoContainer.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Hathor Labs and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import React from 'react'; import { StyleSheet, @@ -6,7 +13,7 @@ import { } from 'react-native'; import { COLORS } from '../styles/themes'; -import { PenIcon } from './Icon/Pen.icon'; +import { PenIcon } from './Icons/Pen.icon'; export const EditInfoContainer = ({ center, onPress, children }) => ( { const button = hasChildren && React.Children.toArray(children).find( (child) => child.type.displayName === Button.displayName ); - const discreteButton = hasChildren && React.Children.toArray(children).find( (child) => child.type.displayName === DiscreteButton.displayName ); @@ -70,11 +67,9 @@ const Title = ({ children }) => ( Title.displayName = 'ModalBaseTitle'; /** - * @typedef {Object} Properties p - * @property {ReactNode} p.children - * @property {StyleProp} p.style - * - * @param {Properties} + * @param {Object} props + * @property {ReactNode} props.children + * @property {StyleProp} props.style */ const Body = ({ style, children }) => ( diff --git a/src/components/TextLabel.component.js b/src/components/TextLabel.js similarity index 71% rename from src/components/TextLabel.component.js rename to src/components/TextLabel.js index cae53932e..702e17d2d 100644 --- a/src/components/TextLabel.component.js +++ b/src/components/TextLabel.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Hathor Labs and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import React from 'react'; import { StyleSheet, diff --git a/src/components/TextValue.component.js b/src/components/TextValue.js similarity index 70% rename from src/components/TextValue.component.js rename to src/components/TextValue.js index f0e392f41..952616385 100644 --- a/src/components/TextValue.component.js +++ b/src/components/TextValue.js @@ -1,3 +1,10 @@ +/** + * Copyright (c) Hathor Labs and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import React from 'react'; import { StyleSheet, diff --git a/src/utils.js b/src/utils.js index 3856c5c4d..281c5d790 100644 --- a/src/utils.js +++ b/src/utils.js @@ -405,4 +405,11 @@ export const getNanoContractFeatureToggle = (state) => ( state.featureToggles[NANO_CONTRACT_FEATURE_TOGGLE] ); -export const getTimestampFormat = (timestamp) => moment.unix(timestamp).format('DD MMM YYYY [•] HH:mm') +/** + * Get timestamp in specific format. + * + * @param {number} timestamp + * + * @returns {string} formatted timestamp + */ +export const getTimestampFormat = (timestamp) => moment.unix(timestamp).format(t`DD MMM YYYY [•] HH:mm`)