Skip to content
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

feat(Carta Giovani Nazionale): [#177058904] Introduces the Bottom Sheet that shows all the informations about an available discount for CGN #2888

Merged
merged 38 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
fdd0129
[#177059013] Implements Discount item for Merchant detail screen
CrisTofani Mar 9, 2021
c400fc7
[#177059013] minor fixes on discountItem
CrisTofani Mar 10, 2021
c39be47
Merge branch 'master' into 177059013-merchants-discount-item
CrisTofani Mar 10, 2021
2d80498
[#176959185] Adds the CGN MErchant detail screen component
CrisTofani Mar 10, 2021
8ccc8a4
Merge branch 'master' into 176959185-merchant-detail-screen
CrisTofani Mar 10, 2021
6a8fe5e
Merge branch 'master' into 177059013-merchants-discount-item
CrisTofani Mar 10, 2021
1f9f5f1
Merge branch 'master' into 176959185-merchant-detail-screen
CrisTofani Mar 10, 2021
0b7a6c7
Merge branch 'master' into 177059013-merchants-discount-item
CrisTofani Mar 10, 2021
7035d0f
[#177058904] Implements Discount bottom sheet component
CrisTofani Mar 10, 2021
ee118a8
Merge branch 'master' into 177058904-discount-detail-bottom-sheet
CrisTofani Mar 10, 2021
0320927
Merge branch 'master' into 177059013-merchants-discount-item
CrisTofani Mar 10, 2021
f8b615e
Merge branch 'master' into 176959185-merchant-detail-screen
CrisTofani Mar 10, 2021
8951e62
[#177058904] UI fixes
CrisTofani Mar 11, 2021
119cef5
[#177058904] Merge
CrisTofani Mar 11, 2021
837eeec
[#177058904] UI Fixes and minor improvements on Copy handler
CrisTofani Mar 11, 2021
191fa24
[#177058904] UI Fixes
CrisTofani Mar 11, 2021
018e776
[#177059013] refactoring
Undermaken Mar 11, 2021
e6143d0
Merge branch 'master' into 177059013-merchants-discount-item
Undermaken Mar 11, 2021
cc0c660
[#177059013] improve
Undermaken Mar 11, 2021
02dc153
[#177058904] refactoring
CrisTofani Mar 11, 2021
8ce0fdb
[#177059013] fix UI styles and composition
Undermaken Mar 11, 2021
f46b855
[#177058904] refactoring
CrisTofani Mar 11, 2021
54be9ec
[#177059013] Merge branch 'master' of github.com:pagopa/io-app into 1…
Undermaken Mar 11, 2021
b553dcb
[#176959185] review
Undermaken Mar 11, 2021
47262e5
[#177058904] revert refactoring and fixes
CrisTofani Mar 11, 2021
c5a783f
[#176959185] from string to number
Undermaken Mar 11, 2021
a93a458
[#176959185] Merge from master branch
CrisTofani Mar 11, 2021
ca2330a
[#177058904] Merge and fixes
CrisTofani Mar 11, 2021
7e412eb
Merge branch 'master' into 177058904-discount-detail-bottom-sheet
CrisTofani Mar 12, 2021
21877cd
[#176959185] Merge branch 'master' of github.com:pagopa/io-app into 1…
Undermaken Mar 12, 2021
0f5ff25
[#177058904] Merge branch '176959185-merchant-detail-screen' of githu…
Undermaken Mar 12, 2021
79340bd
Apply suggestions from code review
CrisTofani Mar 12, 2021
fb2889e
[#177058904] Refactoring to value box
CrisTofani Mar 12, 2021
54064e3
[#177058904] refactoring
CrisTofani Mar 12, 2021
72cdf8c
[#177058904] refactoring
Undermaken Mar 12, 2021
f40633b
Merge branch 'master' into 177058904-discount-detail-bottom-sheet
Undermaken Mar 12, 2021
79d5d41
[#177058904] fix
Undermaken Mar 12, 2021
bee6233
[#177058904] Merge remote-tracking branch 'origin/177058904-discount-…
Undermaken Mar 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,21 @@ PODS:
- OpenSSL-Universal (1.0.2.19):
- OpenSSL-Universal/Static (= 1.0.2.19)
- OpenSSL-Universal/Static (1.0.2.19)
- Permission-Calendars (2.1.5):
- Permission-Calendars (2.2.2):
- RNPermissions
- Permission-Camera (2.1.5):
- Permission-Camera (2.2.2):
- RNPermissions
- Permission-Contacts (2.1.5):
- Permission-Contacts (2.2.2):
- RNPermissions
- Permission-FaceID (2.1.5):
- Permission-FaceID (2.2.2):
- RNPermissions
- Permission-MediaLibrary (2.1.5):
- Permission-MediaLibrary (2.2.2):
- RNPermissions
- Permission-Notifications (2.1.5):
- Permission-Notifications (2.2.2):
- RNPermissions
- Permission-PhotoLibrary (2.1.5):
- Permission-PhotoLibrary (2.2.2):
- RNPermissions
- Permission-Reminders (2.1.5):
- Permission-Reminders (2.2.2):
- RNPermissions
- QrCode (1.1.0):
- React
Expand Down Expand Up @@ -374,8 +374,8 @@ PODS:
- React
- RNKeychain (3.1.3):
- React
- RNPermissions (2.1.5):
- React
- RNPermissions (2.2.2):
- React-Core
- RNReanimated (1.13.1):
- React
- RNScreens (2.10.1):
Expand Down Expand Up @@ -663,14 +663,14 @@ SPEC CHECKSUMS:
jail-monkey: d7c5048b2336f22ee9c9e0efa145f1f917338ea9
Mixpanel: 61e6d8c0717c8e94ccc6d3a1ae8677b9a78f64c5
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
Permission-Calendars: dc345e3388149514603309c621151ff3cfd5816a
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
Permission-Contacts: edde2d433382b3118f0d4c9ebc7708d5d87c4f17
Permission-FaceID: fbdeb41087f35887f0cade55396007fadee3a234
Permission-MediaLibrary: dd1c48888cd95961fbfebdaebf8d4127c6e92e7d
Permission-Notifications: 231d0e1db2300b686548587d384ba414e6a93332
Permission-PhotoLibrary: 4d2eff62c8f4b8a27bcf045c0e36f5047efbbf20
Permission-Reminders: 330cfafecc259594cfd7845a035580b623f771ae
Permission-Calendars: 17bb6a871acc7580754be7b56cfb25537e1b57de
Permission-Camera: 5d2aaf95592660b6dcb5e8d1d90ed5d0156cad02
Permission-Contacts: 295b2f26e7607801e73b0fd35a56ec63cfd52dc4
Permission-FaceID: 8f034a57c60ed8c602d184f485a9bd524c0f98b7
Permission-MediaLibrary: e94e0a30ec5edc18b14e9df10fc78d5bb592a8ca
Permission-Notifications: 9c6b5cc4f0e6599e9fc3395b77cebddc48f1be41
Permission-PhotoLibrary: 8227a6ed9f6a971537afe63742d54f5f23a38fe2
Permission-Reminders: f1bddb60953645830289f9b00977b11e2b62fbf8
QrCode: 1212ff8b8fae1a0e2c698d1c42560abcc0c9019b
RCTRequired: f13f25e7b12f925f1f6a6a8c69d929a03c0129fe
RCTTypeSafety: 44982c5c8e43ff4141eb519a8ddc88059acd1f3a
Expand Down Expand Up @@ -715,7 +715,7 @@ SPEC CHECKSUMS:
RNGestureHandler: b6b359bb800ae399a9c8b27032bdbf7c18f08a08
RNI18n: e2f7e76389fcc6e84f2c8733ea89b92502351fd8
RNKeychain: c658833a9cb2cbcba6423bdd6e16cce59e27da0e
RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467
RNPermissions: 5df468064df661a4c8c017e2791ce90d7695eea5
RNReanimated: dd8c286ab5dd4ba36d3a7fef8bff7e08711b5476
RNScreens: b748efec66e095134c7166ca333b628cd7e6f3e2
RNSha256: ab608b2185fb806185a2cc112e0474065842e085
Expand Down
3 changes: 3 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2225,6 +2225,9 @@ bonus:
description: Description
services: Services
hours: Working Hours
validity: Validity
discountCode: Discount code
conditions: Conditions
cta:
label: Navigate to merchant website
cta:
Expand Down
3 changes: 3 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2255,6 +2255,9 @@ bonus:
description: Descrizione
services: Servizi
hours: Orari
validity: Validità
discountCode: Codice Sconto
conditions: Condizioni
cta:
label: Vai al sito dell'esercente
cta:
Expand Down
138 changes: 138 additions & 0 deletions ts/features/bonus/cgn/components/merchants/CgnDiscountDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import * as React from "react";
import { View } from "native-base";
import { StyleSheet } from "react-native";
import { TouchableWithoutFeedback } from "@gorhom/bottom-sheet";
import { TmpDiscountType } from "../../__mock__/availableMerchantDetail";
import { useIOBottomSheet } from "../../../../../utils/bottomSheet";
import I18n from "../../../../../i18n";
import { IOStyles } from "../../../../../components/core/variables/IOStyles";
import { H3 } from "../../../../../components/core/typography/H3";
import { H5 } from "../../../../../components/core/typography/H5";
import { H4 } from "../../../../../components/core/typography/H4";
import IconFont from "../../../../../components/ui/IconFont";
import { IOColors } from "../../../../../components/core/variables/IOColors";
import { clipboardSetStringWithFeedback } from "../../../../../utils/clipboard";
import { BaseTypography } from "../../../../../components/core/typography/BaseTypography";
import { CgnDiscountValueBox } from "./CgnMerchantsDiscountItem";

type Props = {
discount: TmpDiscountType;
};

const styles = StyleSheet.create({
row: {
flexDirection: "row"
},
verticalPadding: {
paddingBottom: 16
},
discountValueBox: {
borderRadius: 6.5,
paddingVertical: 5,
width: 40,
textAlign: "center",
backgroundColor: "#EB9505"
},
container: {
paddingTop: 16
},
codeContainer: { alignItems: "center", justifyContent: "space-between" },
codeText: {
fontSize: 20
},
flexEnd: { alignSelf: "flex-end" },
discountValue: { textAlign: "center", lineHeight: 30 }
});

const FEEDBACK_MS = 3000;
Undermaken marked this conversation as resolved.
Show resolved Hide resolved

const CATEGORY_ICON_SIZE = 22;
const COPY_ICON_SIZE = 24;

const CgnDiscountDetail: React.FunctionComponent<Props> = ({
discount
}: Props) => {
const [isTap, setIsTap] = React.useState(false);
const timerRetry = React.useRef<number | undefined>(undefined);

React.useEffect(
() => () => {
clearTimeout(timerRetry.current);
},
[]
);

const handleCopyPress = () => {
if (discount.discountCode) {
setIsTap(true);
clipboardSetStringWithFeedback(discount.discountCode);
// eslint-disable-next-line functional/immutable-data
timerRetry.current = setTimeout(() => setIsTap(false), FEEDBACK_MS);
}
};

return (
<View style={styles.container}>
<View style={IOStyles.row}>
{/* TODO when available and defined the icon name should be defined through a map of category codes */}
<IconFont
name={"io-theater"}
size={CATEGORY_ICON_SIZE}
color={IOColors.bluegrey}
/>
<View hspacer small />
<H5 weight={"SemiBold"} color={"bluegrey"}>
{discount.category.toLocaleUpperCase()}
</H5>
</View>
<View spacer />
<H3>{I18n.t("bonus.cgn.merchantDetail.title.description")}</H3>
<H4 weight={"Regular"}>{discount.description}</H4>
<View spacer />
<H3>{I18n.t("bonus.cgn.merchantDetail.title.validity")}</H3>
<H4 weight={"Regular"}>{discount.validityDescription}</H4>
{discount.discountCode && (
<>
<View spacer small />
<H3>{I18n.t("bonus.cgn.merchantDetail.title.discountCode")}</H3>
<TouchableWithoutFeedback onPress={handleCopyPress}>
<View style={[IOStyles.row, styles.codeContainer]}>
<BaseTypography
weight={"Bold"}
color={"bluegreyDark"}
font={"RobotoMono"}
style={styles.codeText}
>
{discount.discountCode}
</BaseTypography>
<IconFont
name={isTap ? "io-complete" : "io-copy"}
size={COPY_ICON_SIZE}
color={IOColors.blue}
style={styles.flexEnd}
/>
</View>
</TouchableWithoutFeedback>
</>
)}
<View spacer />
<H3>{I18n.t("bonus.cgn.merchantDetail.title.conditions")}</H3>
<H4 weight={"Regular"}>{discount.conditions}</H4>
</View>
);
};

const CgnDiscountDetailHeader = ({ discount }: Props) => (
<View style={[IOStyles.row, { alignItems: "center" }]}>
<CgnDiscountValueBox value={discount.value} small />
<View hspacer />
<H3>{discount.title}</H3>
</View>
);

export const useCgnDiscountDetailBottomSheet = (discount: TmpDiscountType) =>
useIOBottomSheet(
<CgnDiscountDetail {...{ discount }} />,
<CgnDiscountDetailHeader {...{ discount }} />,
520
);
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { H4 } from "../../../../../components/core/typography/H4";
import { ShadowBox } from "../../../bpd/screens/details/components/summary/base/ShadowBox";
import { H3 } from "../../../../../components/core/typography/H3";
import { IOStyles } from "../../../../../components/core/variables/IOStyles";
import { TmpDiscountType } from "../../__mock__/availableMerchantDetail";
import TouchableDefaultOpacity from "../../../../../components/TouchableDefaultOpacity";
import { useCgnDiscountDetailBottomSheet } from "./CgnDiscountDetail";

type Props = {
category: string;
description: string;
value: number;
discount: TmpDiscountType;
};

const PERCENTAGE_SYMBOL = "%";
Expand All @@ -35,46 +36,94 @@ const styles = StyleSheet.create({
height: 48,
backgroundColor: "#EB9505"
},
percentage: { textAlign: "center", lineHeight: 30 }
percentage: { textAlign: "center", lineHeight: 30 },
smallValueBox: {
borderRadius: 6.5,
paddingVertical: 5,
width: 40,
textAlign: "center",
backgroundColor: "#EB9505"
}
});

const CgnMerchantDiscountItem: React.FunctionComponent<Props> = (
props: Props
) => (
<View style={styles.verticalPadding}>
<ShadowBox>
<View style={[styles.row, styles.container]}>
<View style={IOStyles.flex}>
<View style={styles.row}>
{/* TODO when available and defined the icon name should be defined through a map of category codes */}
<IconFont name={"io-theater"} size={22} color={IOColors.bluegrey} />
<View hspacer small />
type ValueBoxProps = {
value: number;
small?: boolean;
};

export const CgnDiscountValueBox = ({ value, small }: ValueBoxProps) => {
const normalizedValue = WithinRangeInteger(0, 100)
.decode(value)
.map(v => v.toString())
.getOrElse("-");

return (
<View style={small ? styles.smallValueBox : styles.discountValueBox}>
{small ? (
<H4 weight={"Bold"} color={"white"} style={styles.percentage}>
{normalizedValue}
<H5 weight={"SemiBold"} color={"white"}>
{PERCENTAGE_SYMBOL}
</H5>
</H4>
) : (
<H3 weight={"Bold"} color={"white"} style={styles.percentage}>
{/* avoid overflow */}
{normalizedValue}
<H5 weight={"SemiBold"} color={"white"}>
{PERCENTAGE_SYMBOL}
</H5>
</H3>
)}
</View>
);
};

export const CgnMerchantDiscountItem: React.FunctionComponent<Props> = ({
discount
}: Props) => {
const { present } = useCgnDiscountDetailBottomSheet(discount);
return (
<TouchableDefaultOpacity style={styles.verticalPadding} onPress={present}>
<ShadowBox>
<View style={[styles.row, styles.container]}>
<View style={IOStyles.flex}>
<View style={[styles.row, styles.container]}>
{/* TODO when available and defined the icon name should be defined through a map of category codes */}
<IconFont
name={"io-theater"}
size={22}
color={IOColors.bluegrey}
/>
<View hspacer small />
<View style={IOStyles.flex}>
<H5 weight={"SemiBold"} color={"bluegrey"}>
{discount.category.toLocaleUpperCase()}
</H5>
</View>
</View>
<View spacer xsmall />
<View style={IOStyles.flex}>
<H5 weight={"SemiBold"} color={"bluegrey"}>
{props.category.toLocaleUpperCase()}
</H5>
<View spacer xsmall />
<H4 weight={"SemiBold"} color={"bluegreyDark"}>
{props.description}
{discount.title}
</H4>
</View>
<View style={styles.discountValueBox}>
<H3 weight={"Bold"} color={"white"} style={styles.percentage}>
{/* avoid overflow */}
{WithinRangeInteger(0, 100)
.decode(props.value)
.map(v => v.toString())
.getOrElse("-")}
<H5 weight={"SemiBold"} color={"white"}>
{PERCENTAGE_SYMBOL}
</H5>
</H3>
</View>
</View>
<CgnDiscountValueBox value={discount.value} small={true} />
<View style={styles.discountValueBox}>
<H3 weight={"Bold"} color={"white"} style={styles.percentage}>
{/* avoid overflow */}
{WithinRangeInteger(0, 100)
.decode(discount.value)
.map(v => v.toString())
.getOrElse("-")}
<H5 weight={"SemiBold"} color={"white"}>
{PERCENTAGE_SYMBOL}
</H5>
</H3>
</View>
</View>
</View>
</ShadowBox>
</View>
);

export default CgnMerchantDiscountItem;
</ShadowBox>
</TouchableDefaultOpacity>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { H1 } from "../../../../../components/core/typography/H1";
import { H4 } from "../../../../../components/core/typography/H4";
import { H2 } from "../../../../../components/core/typography/H2";
import I18n from "../../../../../i18n";
import CgnMerchantDiscountItem from "../../components/merchants/CgnMerchantsDiscountItem";
import { CgnMerchantDiscountItem } from "../../components/merchants/CgnMerchantsDiscountItem";

type Props = ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps>;
Expand All @@ -35,11 +35,7 @@ const CgnMerchantDetailScreen: React.FunctionComponent<Props> = ({
const renderDiscountListItem = ({
item
}: ListRenderItemInfo<TmpDiscountType>) => (
<CgnMerchantDiscountItem
category={item.category}
description={item.title}
value={item.value}
/>
<CgnMerchantDiscountItem discount={item} />
);

return (
Expand Down