Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
APP_VERSION=2.5.2
APP_VERSION=2.5.3

APP_BUILD_NUMBER=428
APP_BUILD_NUMBER=429
1 change: 1 addition & 0 deletions fastlane/metadata/android/en-US/changelogs/429.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added QR to download the receipt after payment
1 change: 1 addition & 0 deletions fastlane/metadata/android/fr-FR/changelogs/429.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Ajouté un QR code de téléchargement du reçu après paiement
4 changes: 3 additions & 1 deletion src/assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@
"scanToVerify": "Scan to verify your identity",
"or": "or",
"scanToWithdraw": "Scan to receive bitcoin via",
"printReceipt": "Print receipt"
"printReceipt": "Print receipt",
"receipt": "Receipt",
"downloadReceipt": "Download receipt"
},
"history": {
"title": "Transaction history",
Expand Down
4 changes: 3 additions & 1 deletion src/assets/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@
"scanToVerify": "Scanner pour vérifier votre identité",
"or": "ou",
"scanToWithdraw": "Scanner pour recevoir des bitcoins via",
"printReceipt": "Imprimer reçu"
"printReceipt": "Imprimer reçu",
"receipt": "Reçu",
"downloadReceipt": "Télécharger le reçu"
},
"history": {
"title": "Historique des transactions",
Expand Down
20 changes: 16 additions & 4 deletions src/components/QR/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ type QRProps = Omit<QRCodeProps, "ref"> & {
{ icon?: IconProp }
>;

export const QR = ({ style, image, icon, size = 0, ...props }: QRProps) => {
export const QR = ({
style,
image,
icon,
size = 0,
logoBackgroundColor,
logoColor,
...props
}: QRProps) => {
const theme = useTheme();
const { padding, borderRadius } = useMemo(
() => extractPaddingFromStyle(style as React.CSSProperties),
Expand All @@ -79,9 +87,13 @@ export const QR = ({ style, image, icon, size = 0, ...props }: QRProps) => {
style={{ transform: [{ scale: image.scale || 1 }] }}
/>
) : icon ? (
<S.QRIconContinaer>
<Icon icon={icon} size={50} color={theme.colors.primary} />
</S.QRIconContinaer>
<S.QRIconContainer style={{ backgroundColor: logoBackgroundColor }}>
<Icon
icon={icon}
size={size / 5}
color={logoColor || theme.colors.primary}
/>
</S.QRIconContainer>
) : null}
</S.QRContainer>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/QR/styled.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from "styled-components";
import { Icon, Image, View } from "@components";
import { Image, View } from "@components";

export const QRContainer = styled(View)`
background: ${({ theme }) => theme.colors.white};
Expand All @@ -19,10 +19,10 @@ export const QRImage = styled(Image)`
height: 70px;
`;

export const QRIconContinaer = styled(View)`
export const QRIconContainer = styled(View)`
position: absolute;
background-color: ${({ theme }) => theme.colors.white};
padding: 8px;
padding: 2%;
border-radius: 100px;
align-items: center;
justify-content: center;
Expand Down
64 changes: 58 additions & 6 deletions src/screens/Invoice/Invoice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ import {
QR,
CountdownCircleTimer,
Pressable,
Modal
Modal,
View
} from "@components";
import {
faArrowLeft,
faArrowUpRightFromSquare,
faBolt,
faCheck,
faCircleDown,
faClock,
faFileDownload,
faGlobe,
faHandPointer,
faIdCard,
Expand All @@ -55,6 +58,7 @@ import { FooterLine } from "./components/FooterLine";
import {
DEFAULT_DECIMALS,
apiRootDomain,
apiRootUrl,
appRootUrl,
currencies,
rateUpdateDelay
Expand Down Expand Up @@ -162,13 +166,15 @@ const STATUS_ICON_SIZE = 120;
const MAX_QR_SIZE = 320;
const FOOTER_VALUE_ITEMS_SIZE = 18;

const REDIRECT_DELAY = 60 * 1000;

export const Invoice = () => {
const navigate = useNavigate();
const { colors, gridSize } = useTheme();
const toast = useToast();
const versionTag = useVersionTag();
const printInvoiceTicket = usePrintInvoiceTicket();
const { t } = useTranslation(undefined, {
const { t, i18n } = useTranslation(undefined, {
keyPrefix: "screens.invoice"
});
const { t: tRoot } = useTranslation();
Expand Down Expand Up @@ -396,8 +402,6 @@ export const Invoice = () => {
delay: springAnimationDelay
});

const REDIRECT_DELAY = 7000;

redirectProgressApi.start({
to: { left: "0%" },
config: { duration: REDIRECT_DELAY }
Expand Down Expand Up @@ -539,7 +543,10 @@ export const Invoice = () => {
);
}

setDescription(getInvoiceData.description);
if (getInvoiceData.description) {
// don't remove description if it already stored
setDescription(getInvoiceData.description);
}
setAmount(getInvoiceData.amount * 1000);
setPaidAt(getInvoiceData.paidAt);
setInvoiceCurrency(getInvoiceData.input.unit || "CHF");
Expand Down Expand Up @@ -736,6 +743,12 @@ export const Invoice = () => {
printInvoiceTicket
]);

const downloadPdfLink = useMemo(
() =>
`${apiRootUrl}/pdf/${invoiceId}?lng=${i18n.language}&tz=${Intl.DateTimeFormat().resolvedOptions().timeZone}`,
[i18n.language, invoiceId]
);

const getPageContainerProps = useCallback(
(isSuccessScreen = false) => {
return {
Expand Down Expand Up @@ -788,6 +801,13 @@ export const Invoice = () => {
[qrCodeSize, gridSize]
);

const redirectDuration = useMemo(() => {
if (!isExternalInvoice) {
return REDIRECT_DELAY / 1000;
}
return 7;
}, [isExternalInvoice]);

return (
<>
<Modal
Expand All @@ -811,6 +831,23 @@ export const Invoice = () => {
>
<S.InvoicePageContainer {...getPageContainerProps(true)}>
<S.SectionsContainer gapSize={2}>
{!isWithdraw && (
<S.InvoiceDownloadContainer isLarge={isLarge}>
<QR
value={downloadPdfLink}
size={S.INVOICE_DOWNLOAD_QR}
icon={faCircleDown}
ecl="M"
backgroundColor={colors.white}
logoBackgroundColor={colors.white}
color={colors.success}
logoColor={colors.success}
/>
<Text centered weight={600} color={colors.success} h4>
{t("receipt")}
</Text>
</S.InvoiceDownloadContainer>
)}
<S.Section grow>
<>
<S.TypeText color="transparent">_</S.TypeText>
Expand Down Expand Up @@ -1025,7 +1062,7 @@ export const Invoice = () => {
<CountdownCircleTimer
isGrowing
isPlaying
duration={7}
duration={redirectDuration}
strokeWidth={5}
size={STATUS_ICON_SIZE / 4}
colors={colors.white}
Expand Down Expand Up @@ -1143,6 +1180,21 @@ export const Invoice = () => {
</ComponentStack>
</ComponentStack>
)}
{status === "settled" && !isWithdraw && (
<View
style={{
flex: 1,
justifyContent: "flex-end",
width: "100%"
}}
>
<Button
icon={faFileDownload}
title={t("downloadReceipt")}
onPress={downloadPdfLink}
/>
</View>
)}
{createdAt && delay && isAlive && !isExternalInvoice && (
<S.ProgressBar
progress={progress}
Expand Down
28 changes: 28 additions & 0 deletions src/screens/Invoice/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { platform } from "@config";
import { Circle } from "react-native-progress";
import { animated } from "@react-spring/native";
import { ColorValue } from "react-native";
import { getShadow } from "@utils";

const { isNative, maxContentWidth } = platform;

Expand Down Expand Up @@ -63,6 +64,33 @@ export const SectionsContainer = styled(ComponentStack)`
flex-grow: 1;
`;

export const INVOICE_DOWNLOAD_QR = 115;
const INVOICE_DOWNLOAD_PADDING = 12;

export const InvoiceDownloadContainer = styled(ComponentStack).attrs(() => ({
direction: "vertical",
gapSize: 6
}))<{ isLarge: boolean }>`
position: absolute;
top: -22px;
right: 0px;
padding: ${INVOICE_DOWNLOAD_PADDING}px;
width: ${INVOICE_DOWNLOAD_QR + 2 * INVOICE_DOWNLOAD_PADDING}px;
border-radius: ${({ theme }) => theme.borderRadius}px;
align-items: center;
text-align: center;
background-color: ${({ theme }) => theme.colors.white};
${getShadow({ level: 16 })}
${({ theme, isLarge }) =>
!isLarge
? `
right: -${theme.gridSize}px;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
`
: ``}
`;

export const Section = styled(ComponentStack)<{ grow?: boolean }>`
align-items: center;
overflow: hidden;
Expand Down