From c4e02585527038030ddcc94f84147d6a3e5afef6 Mon Sep 17 00:00:00 2001 From: MKuijpers Date: Wed, 18 Jan 2023 23:36:59 +0100 Subject: [PATCH 1/5] Add Toast error message for failing sticker uploads --- .../app/home/stickerpack/StickerPackScreen.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx b/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx index fe389c69..c417ff5a 100644 --- a/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx +++ b/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; -import { Alert, Platform, SafeAreaView, TouchableOpacity } from "react-native"; +import { Alert, Platform, SafeAreaView, ToastAndroid } from "react-native"; -import { Button, Icon, Layout, ModalService, Spinner, Text } from "@ui-kitten/components"; +import { Button, Icon, Layout, Spinner } from "@ui-kitten/components"; import { StackScreenProps } from "@react-navigation/stack"; import { HomeStackParamList } from "../../../../navigation/app/AppStackNavigator"; import tailwind from "tailwind-rn"; @@ -65,6 +65,11 @@ export const StickerPackScreen = ({ navigation, route }: Props): React.ReactElem const pickAndUploadSticker = async (stickerPackId: string) => { + const showErrorAlert = () => { + // TODO: Add alert for iOS as well + ToastAndroid.show("Something went wrong while uploading the sticker, please try again.", 10000); + }; + ImagePicker.openPicker({ width: STICKER_FULL_SIZE_PX, height: STICKER_FULL_SIZE_PX, @@ -82,11 +87,15 @@ export const StickerPackScreen = ({ navigation, route }: Props): React.ReactElem const dto = { stickerPackId, stickerName, file }; - uploadSticker(dto); + uploadSticker(dto, { + onError: showErrorAlert + }); }) .catch((error) => { if (error.code !== "E_PICKER_CANCELLED") { console.log(error); + } else { + showErrorAlert(); } }); }; From e9ed8d4849c3521d4206b1b8a682904142007c45 Mon Sep 17 00:00:00 2001 From: MKuijpers Date: Wed, 18 Jan 2023 23:37:45 +0100 Subject: [PATCH 2/5] Rewrite confirm modal as react component and use if for delete sticker confirm --- app/src/components/common/ConfirmModal.tsx | 79 ++++++++++++++----- .../app/home/stickerpack/StickerScreen.tsx | 51 +++++++----- 2 files changed, 89 insertions(+), 41 deletions(-) diff --git a/app/src/components/common/ConfirmModal.tsx b/app/src/components/common/ConfirmModal.tsx index 52179872..0c8b7055 100644 --- a/app/src/components/common/ConfirmModal.tsx +++ b/app/src/components/common/ConfirmModal.tsx @@ -1,7 +1,7 @@ -import React from "react"; +import React, { ReactNode } from "react"; import { TouchableOpacity } from "react-native"; -import { Button, Layout, ModalService, Text } from "@ui-kitten/components"; +import { Button, Layout, Modal, ModalService, Text } from "@ui-kitten/components"; import tailwind from "tailwind-rn"; interface ConfirmModalProps { @@ -11,6 +11,28 @@ interface ConfirmModalProps { onPressCancel?: () => void; status?: "basic" | "primary" | "success" | "info" | "warning" | "danger" | "control"; } +const ConfirmModalComponent = ({ message, buttonText, onPressConfirm, onPressCancel, status = "primary" }: ConfirmModalProps) => { + return ( + + + + {message} + + + + + + + + ) +} export const showConfirmModal = ({ message, buttonText, onPressConfirm, onPressCancel, status }: ConfirmModalProps): void => { let modalId = '' @@ -27,26 +49,43 @@ export const showConfirmModal = ({ message, buttonText, onPressConfirm, onPressC }; modalId = ModalService.show( - - - - {message} - - - - - - - , + , { onBackdropPress: pressCancel, } ); +} + +interface ConfirmModalComponentProps extends ConfirmModalProps { + visible: boolean; + hideModal: () => void; +} +export const ConfirmModal = ({ visible, hideModal, message, buttonText, onPressCancel, onPressConfirm, status }: ConfirmModalComponentProps): JSX.Element => { + const pressConfirm = () => { + onPressConfirm(); + hideModal(); + } + + const pressCancel = () => { + onPressCancel && onPressCancel(); + hideModal(); + }; + + return ( + + + + ) } \ No newline at end of file diff --git a/app/src/screens/app/home/stickerpack/StickerScreen.tsx b/app/src/screens/app/home/stickerpack/StickerScreen.tsx index 18ecc7a9..6c03cde1 100644 --- a/app/src/screens/app/home/stickerpack/StickerScreen.tsx +++ b/app/src/screens/app/home/stickerpack/StickerScreen.tsx @@ -1,38 +1,41 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { StackScreenProps } from "@react-navigation/stack"; import { Button, Icon } from "@ui-kitten/components"; -import { Image, SafeAreaView } from "react-native"; +import { Image, SafeAreaView, ToastAndroid } from "react-native"; import { HomeStackParamList } from "../../../../navigation/app/AppStackNavigator"; import tw from "tailwind-react-native-classnames"; import tailwind from "tailwind-rn"; import { useDeleteStickerMutation } from "../../../../api/hooks/mutations/stickerPack"; import { useQueryClient } from "react-query"; -import { showConfirmModal } from "../../../../components/common/ConfirmModal"; +import { ConfirmModal } from "../../../../components/common/ConfirmModal"; type Props = StackScreenProps; const StickerScreen = ({ route, navigation }: Props): JSX.Element => { const { stickerPack, sticker, allowDeleteSticker } = route.params; + const [confirmModalVisible, setConfirmModalVisible] = useState(false) + const queryClient = useQueryClient(); const { mutate: deleteSticker } = useDeleteStickerMutation(queryClient); - const onPressDeleteSticker = async () => { - const onPressConfirm = async () => { - await deleteSticker({ - stickerPackId: stickerPack.id, - stickerId: sticker.id, - }) - navigation.pop(); - } + const onPressConfirmDelete = async () => { + deleteSticker({ + stickerPackId: stickerPack.id, + stickerId: sticker.id, + }, { + onSuccess: () => { + navigation.pop(); + }, + onError: () => { + ToastAndroid.show("Something went wrong while deleting the sticker, please try again.", 10000); + } + }) + } - showConfirmModal({ - message: "Are you sure?", - buttonText: "Delete Sticker", - onPressConfirm, - status: "danger" - }); + const onPressDeleteButton = async () => { + setConfirmModalVisible(true); } const DeleteIcon = () => ( @@ -40,7 +43,7 @@ const StickerScreen = ({ route, navigation }: Props): JSX.Element => { appearance="ghost" status="danger" style={tailwind("mx-3 px-1")} - onPress={onPressDeleteSticker} + onPress={onPressDeleteButton} accessoryLeft={(props) => ()} /> ); @@ -54,11 +57,17 @@ const StickerScreen = ({ route, navigation }: Props): JSX.Element => { return ( + setConfirmModalVisible(false)} + message="Are you sure?" + buttonText="Delete Sticker" + onPressConfirm={onPressConfirmDelete} + status="danger" + /> ); } From 1d86623daab0af51d964930eaee0291fa2d7a3c2 Mon Sep 17 00:00:00 2001 From: MKuijpers Date: Wed, 18 Jan 2023 23:48:52 +0100 Subject: [PATCH 3/5] Add loading indicator and message to confirm modal and integrate with delete sticker --- app/src/components/common/ConfirmModal.tsx | 46 +++++++++++-------- .../app/home/stickerpack/StickerScreen.tsx | 5 +- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/app/src/components/common/ConfirmModal.tsx b/app/src/components/common/ConfirmModal.tsx index 0c8b7055..3b920023 100644 --- a/app/src/components/common/ConfirmModal.tsx +++ b/app/src/components/common/ConfirmModal.tsx @@ -1,17 +1,19 @@ -import React, { ReactNode } from "react"; +import React from "react"; import { TouchableOpacity } from "react-native"; -import { Button, Layout, Modal, ModalService, Text } from "@ui-kitten/components"; +import { Button, Layout, Modal, ModalService, Spinner, Text } from "@ui-kitten/components"; import tailwind from "tailwind-rn"; interface ConfirmModalProps { message: string; buttonText: string; + isLoading?: boolean; + loadingMessage?: string; onPressConfirm: () => void; onPressCancel?: () => void; status?: "basic" | "primary" | "success" | "info" | "warning" | "danger" | "control"; } -const ConfirmModalComponent = ({ message, buttonText, onPressConfirm, onPressCancel, status = "primary" }: ConfirmModalProps) => { +const ConfirmModalComponent = ({ message, buttonText, isLoading, loadingMessage, onPressConfirm, onPressCancel, status = "primary" }: ConfirmModalProps) => { return ( - {message} + {isLoading ? (loadingMessage ?? message) : message} - - - + + {isLoading + ? ( + + ) : ( + <> + + + + )} ) } -export const showConfirmModal = ({ message, buttonText, onPressConfirm, onPressCancel, status }: ConfirmModalProps): void => { + +type ConfirmModalMethodProps = Omit; +export const showConfirmModal = ({ message, buttonText, onPressConfirm, onPressCancel, status }: ConfirmModalMethodProps): void => { let modalId = '' const hideModal = () => ModalService.hide(modalId) @@ -66,12 +77,7 @@ interface ConfirmModalComponentProps extends ConfirmModalProps { visible: boolean; hideModal: () => void; } -export const ConfirmModal = ({ visible, hideModal, message, buttonText, onPressCancel, onPressConfirm, status }: ConfirmModalComponentProps): JSX.Element => { - const pressConfirm = () => { - onPressConfirm(); - hideModal(); - } - +export const ConfirmModal = ({ visible, hideModal, message, buttonText, isLoading, loadingMessage, onPressCancel, onPressConfirm, status }: ConfirmModalComponentProps): JSX.Element => { const pressCancel = () => { onPressCancel && onPressCancel(); hideModal(); @@ -82,7 +88,9 @@ export const ConfirmModal = ({ visible, hideModal, message, buttonText, onPressC diff --git a/app/src/screens/app/home/stickerpack/StickerScreen.tsx b/app/src/screens/app/home/stickerpack/StickerScreen.tsx index 6c03cde1..1974e16d 100644 --- a/app/src/screens/app/home/stickerpack/StickerScreen.tsx +++ b/app/src/screens/app/home/stickerpack/StickerScreen.tsx @@ -18,7 +18,7 @@ const StickerScreen = ({ route, navigation }: Props): JSX.Element => { const [confirmModalVisible, setConfirmModalVisible] = useState(false) const queryClient = useQueryClient(); - const { mutate: deleteSticker } = useDeleteStickerMutation(queryClient); + const { mutate: deleteSticker, isLoading } = useDeleteStickerMutation(queryClient); const onPressConfirmDelete = async () => { deleteSticker({ @@ -26,6 +26,7 @@ const StickerScreen = ({ route, navigation }: Props): JSX.Element => { stickerId: sticker.id, }, { onSuccess: () => { + setConfirmModalVisible(false); navigation.pop(); }, onError: () => { @@ -62,6 +63,8 @@ const StickerScreen = ({ route, navigation }: Props): JSX.Element => { /> setConfirmModalVisible(false)} message="Are you sure?" buttonText="Delete Sticker" From ad4b26319a7359e8fc1d8041af52be4f1416abb3 Mon Sep 17 00:00:00 2001 From: MKuijpers Date: Wed, 18 Jan 2023 23:53:15 +0100 Subject: [PATCH 4/5] Add error toast when create sticker pack fails --- .../screens/app/home/stickerpack/CreateStickerPackScreen.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/screens/app/home/stickerpack/CreateStickerPackScreen.tsx b/app/src/screens/app/home/stickerpack/CreateStickerPackScreen.tsx index adbdf540..14e4b643 100644 --- a/app/src/screens/app/home/stickerpack/CreateStickerPackScreen.tsx +++ b/app/src/screens/app/home/stickerpack/CreateStickerPackScreen.tsx @@ -1,7 +1,7 @@ import { StackScreenProps } from "@react-navigation/stack"; import { Button, CheckBox, Icon, IconProps, Input, Layout, Spinner, Text } from "@ui-kitten/components"; import React, { useState } from "react"; -import { Keyboard, SafeAreaView } from "react-native"; +import { Keyboard, SafeAreaView, ToastAndroid } from "react-native"; import { useQueryClient } from "react-query"; import tailwind from "tailwind-rn"; import validate from "validate.js"; @@ -51,6 +51,9 @@ export const CreateStickerPackScreen = ({ navigation }: Props): React.ReactEleme stickerPack: data, }); }, + onError: () => { + ToastAndroid.show("Failed to create stickerpack, please try again.", 10000); + } }); }; From b5ccdf29ff4c401c99de7672537bce0f6ef2e75e Mon Sep 17 00:00:00 2001 From: MKuijpers Date: Thu, 19 Jan 2023 17:23:55 +0100 Subject: [PATCH 5/5] Add different alert message for image picker errors --- .../home/stickerpack/StickerPackScreen.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx b/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx index c417ff5a..5badfafd 100644 --- a/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx +++ b/app/src/screens/app/home/stickerpack/StickerPackScreen.tsx @@ -65,11 +65,6 @@ export const StickerPackScreen = ({ navigation, route }: Props): React.ReactElem const pickAndUploadSticker = async (stickerPackId: string) => { - const showErrorAlert = () => { - // TODO: Add alert for iOS as well - ToastAndroid.show("Something went wrong while uploading the sticker, please try again.", 10000); - }; - ImagePicker.openPicker({ width: STICKER_FULL_SIZE_PX, height: STICKER_FULL_SIZE_PX, @@ -88,14 +83,24 @@ export const StickerPackScreen = ({ navigation, route }: Props): React.ReactElem const dto = { stickerPackId, stickerName, file }; uploadSticker(dto, { - onError: showErrorAlert + onError: () => { + // TODO: Add alert for iOS as well + ToastAndroid.show( + "Something went wrong while uploading the sticker, please try again.", + 10000 + ); + } }); }) .catch((error) => { if (error.code !== "E_PICKER_CANCELLED") { console.log(error); } else { - showErrorAlert(); + // TODO: Add alert for iOS as well + ToastAndroid.show( + "Something went wrong while selecting an image, please try again.", + 10000 + ); } }); };