From e821719facdb4616ddd3e4a5e89f98663ca059a1 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 14 Aug 2023 21:28:04 +0000 Subject: [PATCH] added faq steps --- App.js | 37 ++- locales/de.json | 36 ++- locales/en.json | 30 +- package-lock.json | 29 -- package.json | 5 +- src/Components/Accordion/index.js | 1 - src/Components/Button/index.js | 14 +- src/Screens/Help/index.js | 105 +++---- .../Help/modals/Feedback/finished/index.js | 49 ++++ src/Screens/Help/modals/Feedback/index.js | 30 +- .../Help/modals/Feedback/steps/index.js | 260 ++++++++++++++++++ src/Screens/Help/modals/HelpCenter/index.js | 153 ++++++----- .../Help/modals/ReportProblem/index.js | 5 - src/utils.js | 4 + 14 files changed, 574 insertions(+), 184 deletions(-) create mode 100644 src/Screens/Help/modals/Feedback/finished/index.js create mode 100644 src/Screens/Help/modals/Feedback/steps/index.js delete mode 100644 src/Screens/Help/modals/ReportProblem/index.js diff --git a/App.js b/App.js index 97625d8..e72194e 100644 --- a/App.js +++ b/App.js @@ -42,9 +42,9 @@ import WaitXSecondsEditActionModalContent from "./src/Screens/Device/modals/Edit import StopEditActionModalContent from "./src/Screens/Device/modals/EditActions/Stop"; import SearchForNewDevicesModalContent from "./src/Screens/SearchForNewDevices"; import HelpCenterModalContent from "./src/Screens/Help/modals/HelpCenter"; +import { FeedbackStepsModalContent } from "./src/Screens/Help/modals/Feedback/steps"; import GiveFeedbackModalContent from "./src/Screens/Help/modals/Feedback"; -import ReportProblemModalContent from "./src/Screens/Help/modals/ReportProblem"; -import * as MailComposer from "expo-mail-composer"; +import FeedbackFinishedModalContent from "./src/Screens/Help/modals/Feedback/finished"; const Drawer = createDrawerNavigator(); const Stack = createStackNavigator(); @@ -305,12 +305,23 @@ export function MyApp() { /> options({ navigation: navigation, - pageTitle: t("screens.help.modalReportProblem.pageTitle"), + pageTitle: t("screens.help.modalFeedbackSteps.pageTitle"), + }) + } + /> + + + options({ + navigation: navigation, + pageTitle: t("screens.help.modalFeedbackFinished.pageTitle"), }) } /> @@ -528,19 +539,3 @@ export default function App() { ); } - -export function OpenMailComposer(recipients, subject, body) { - return new Promise((resolve, reject) => { - MailComposer.composeAsync({ - recipients: recipients, - subject: subject, - body: body, - }) - .then((result) => { - resolve(result); - }) - .catch((error) => { - reject(error); - }); - }); -} diff --git a/locales/de.json b/locales/de.json index 69eaed5..bd26c04 100644 --- a/locales/de.json +++ b/locales/de.json @@ -187,14 +187,42 @@ }, "help": { "pageTitle": "Hilfe", + "pageInfoText": "Wie können wir Ihnen helfen?", + "textButtonContactUs": "Kontaktiere uns", + "items": { + "helpCenter": "Hilfezentrum", + "giveFeedback": "Feedback geben", + "reportProblem": "Problem melden" + }, "modalHelpCenter": { - "pageTitle": "Hilfezentrum" + "pageTitle": "Hilfezentrum", + "pageInfoText": "Fragen und Anworten" }, "modalGiveFeedback": { - "pageTitle": "Feedback geben" + "pageTitle": "Feedback geben", + "pageInfoText": "Teilen Sie uns mit, wie wir das Produkt verbessern können", + "buttonGiveFeedback": "Feedback geben" }, - "modalReportProblem": { - "pageTitle": "Problem melden" + "modalFeedbackSteps": { + "pageTitle": "Feedback", + "cardTopicText": "Bewerten Sie Ihr Erlebnis", + "backButton": "Zurück", + "cancelButton": "Abbrechen", + "sendFeedbackButton": "Feedback senden", + "continueButton": "Weiter", + "startTexts": [ + "Schlecht", + "Mangelhaft", + "In Ordnung", + "Gut", + "Ausgezeichnet" + ] + }, + "modalFeedbackFinished": { + "pageTitle": "Feedback gesendet", + "textThankYou": "Vielen Dank für Ihr Feedback!", + "description": "Wir werden Ihre Anregungen sorgfältig prüfen und bemühen uns, mögliche Verbesserungsvorschläge in unsere zukünftigen Entwicklungen einzubeziehen.", + "textButtonBackToOverview": "Zurück zur Übersicht" } }, "settings": { diff --git a/locales/en.json b/locales/en.json index ba49ec1..63865ef 100644 --- a/locales/en.json +++ b/locales/en.json @@ -185,14 +185,36 @@ }, "help": { "pageTitle": "Help", + "textButtonContactUs": "Contact us", + "pageInfoText": "How can we help you?", + "items": { + "helpCenter": "Help Center", + "giveFeedback": "Give feedback", + "reportProblem": "Report problem" + }, "modalHelpCenter": { - "pageTitle": "Help Center" + "pageTitle": "Help Center", + "pageInfoText": "Questions and answers" }, "modalGiveFeedback": { - "pageTitle": "Give feedback" + "pageTitle": "Give feedback", + "pageInfoText": "Tell us how we can improve the product", + "buttonGiveFeedback": "Give feedback" }, - "modalReportProblem": { - "pageTitle": "Report problem" + "modalFeedbackSteps": { + "pageTitle": "Feedback", + "cardTopicText": "Rate your experience", + "backButton": "Back", + "cancelButton": "Cancel", + "sendFeedbackButton": "Send feedback", + "continueButton": "Continue", + "startTexts": ["Poor", "Bad", "Ok", "Good", "Excellent"] + }, + "modalFeedbackFinished": { + "pageTitle": "Feedback sent", + "textThankYou": "Thank you for your feedback!", + "description": "We will carefully review your suggestions and strive to incorporate possible improvement ideas into our future developments.", + "textButtonBackToOverview": "Back to Overview" } }, "settings": { diff --git a/package-lock.json b/package-lock.json index 86ac1c8..572c0ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "expo": "~48.0.18", "expo-haptics": "~12.2.1", "expo-linear-gradient": "~12.1.2", - "expo-mail-composer": "~12.1.1", "expo-status-bar": "~1.4.4", "i18next": "^23.2.11", "i18next-browser-languagedetector": "^7.1.0", @@ -7202,34 +7201,6 @@ "expo": "*" } }, - "node_modules/expo-mail-composer": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/expo-mail-composer/-/expo-mail-composer-12.1.1.tgz", - "integrity": "sha512-DJZpxdc6huwg8M9STfzL415xHGEaEXOseK2VyPAKKllWYR6m2gE18sXND9Ak8rcynZGTwyuaHrqJLBXd3I/LcQ==", - "dependencies": { - "query-string": "^6.2.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-mail-composer/node_modules/query-string": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", - "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", - "dependencies": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/expo-modules-autolinking": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.2.0.tgz", diff --git a/package.json b/package.json index 47b77bb..be9b885 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@react-navigation/stack": "^6.3.17", "expo": "~48.0.18", "expo-haptics": "~12.2.1", + "expo-linear-gradient": "~12.1.2", "expo-status-bar": "~1.4.4", "i18next": "^23.2.11", "i18next-browser-languagedetector": "^7.1.0", @@ -31,9 +32,7 @@ "react-native-tab-view": "^3.5.2", "react-native-uuid": "^2.0.1", "react-native-zeroconf": "^0.13.8", - "reanimated-color-picker": "^2.3.1", - "expo-linear-gradient": "~12.1.2", - "expo-mail-composer": "~12.1.1" + "reanimated-color-picker": "^2.3.1" }, "devDependencies": { "@babel/core": "^7.20.0" diff --git a/src/Components/Accordion/index.js b/src/Components/Accordion/index.js index 4168932..84d4b81 100644 --- a/src/Components/Accordion/index.js +++ b/src/Components/Accordion/index.js @@ -66,7 +66,6 @@ export function AccordionItem({ style={[ { color: appContext.appTheme.text, - fontWeight: "bold", width: "90%", }, AppStyles.typography16, diff --git a/src/Components/Button/index.js b/src/Components/Button/index.js index a1c3b0c..f9e14e6 100644 --- a/src/Components/Button/index.js +++ b/src/Components/Button/index.js @@ -76,6 +76,7 @@ export function MyTextButton({ actionColor, iconName, disabled, + textSelectable, }) { const appContext = useContext(AppContext); @@ -106,7 +107,10 @@ export function MyTextButton({ color: color, }} /> - + {title} @@ -123,6 +127,7 @@ export function MyIconButton({ iconColor, usePrimaryColor, disabled, + activeOpacity, }) { const appContext = useContext(AppContext); @@ -134,7 +139,12 @@ export function MyIconButton({ : iconColor; return ( - + - - + + + + navigation.navigate("modalHelpCenter")} + /> + navigation.navigate("modalGiveFeedback")} + /> + + + + + {t("screens.help.textButtonContactUs")} + + + + Linking.openURL(`mailto:${Constants.globals.contact_us_email}`) + } + /> + + + ); +} + +export function InfoHeader({ appContext, iconName, text }) { + return ( + + + - Wie können wir Ihnen helfen? + {text} - - - navigation.navigate("modalHelpCenter")} - /> - navigation.navigate("modalGiveFeedback")} - /> - navigation.navigate("modalReportProblem")} - /> - ); } - -/* - - - {Array.from({ length: 20 }).map((item, index) => ( - - ))} - - -*/ diff --git a/src/Screens/Help/modals/Feedback/finished/index.js b/src/Screens/Help/modals/Feedback/finished/index.js new file mode 100644 index 0000000..5bdffad --- /dev/null +++ b/src/Screens/Help/modals/Feedback/finished/index.js @@ -0,0 +1,49 @@ +import { useContext } from "react"; +import { Text } from "react-native"; +import { AppContext, AppStyles, ModalContainer } from "../../../../../utils"; +import { useTranslation } from "react-i18next"; +import MyIcon from "../../../../../Components/Icon"; +import { MyTextButton } from "../../../../../Components/Button"; + +export default function FeedbackFinishedModalContent({ navigation }) { + const appContext = useContext(AppContext); + const { t } = useTranslation(); + + return ( + + + + {t("screens.help.modalFeedbackFinished.textThankYou")} + + + + {t("screens.help.modalFeedbackFinished.description")} + + + navigation.navigate("help")} + /> + + ); +} diff --git a/src/Screens/Help/modals/Feedback/index.js b/src/Screens/Help/modals/Feedback/index.js index 3c4fa08..56c3ffe 100644 --- a/src/Screens/Help/modals/Feedback/index.js +++ b/src/Screens/Help/modals/Feedback/index.js @@ -1,3 +1,29 @@ -export default function GiveFeedbackModalContent({ navigation, route }) { - return <>; +import { useContext } from "react"; +import { InfoHeader } from "../.."; +import { AppContext } from "../../../../utils"; +import { useTranslation } from "react-i18next"; +import { View } from "react-native"; +import MyButton from "../../../../Components/Button"; + +export default function GiveFeedbackModalContent({ navigation }) { + const appContext = useContext(AppContext); + const { t } = useTranslation(); + + return ( + + + + + navigation.navigate("modalFeedbackSteps")} + /> + + + ); } diff --git a/src/Screens/Help/modals/Feedback/steps/index.js b/src/Screens/Help/modals/Feedback/steps/index.js new file mode 100644 index 0000000..df38fd7 --- /dev/null +++ b/src/Screens/Help/modals/Feedback/steps/index.js @@ -0,0 +1,260 @@ +import { useContext, useState } from "react"; +import { + AppContext, + AppStyles, + Constants, + ModalContainer, +} from "../../../../../utils"; +import { useTranslation } from "react-i18next"; +import { ScrollView, Text, TextInput, View } from "react-native"; +import MyButton, { MyIconButton } from "../../../../../Components/Button"; +import Card from "../../../../../Components/Card"; + +const defaultRating = 0; + +const feedbackDataDe = [ + { + title: "Produktbewertung", + text: "Bewerten Sie Ihre Gesamtzufriedenheit mit dem Produkt.", + textPlaceholder: + "Besonders gut gefällt mir...\n\nNicht gut gefällt mir...\n\nVerbessern würde ich...", + }, + { + title: "Handhabung", + text: "Bewerten Sie, wie einfach und komfortabel das Produkt in der Handhabung ist.", + textPlaceholder: + "Besonders gut gefällt mir...\n\nNicht gut gefällt mir...\n\nVerbessern würde ich...", + }, + { + title: "Design", + text: "Bewerten Sie das Design des Produkts.", + textPlaceholder: + "Besonders gut gefällt mir...\n\nNicht gut gefällt mir...\n\nVerbessern würde ich...", + }, + { + title: "Sonstiges", + text: "Teilen Sie uns gerne weitere Gedanken und Anregungen mit, um uns bei der kontinuierlichen Verbesserung unserer Produkte zu unterstützen.", + textPlaceholder: "Ich würde mir wünschen...", + }, +]; + +const feedbackDataEn = [ + { + title: "Product Rating", + text: "Rate your overall satisfaction with the product.", + textPlaceholder: + "I particularly like...\n\nI don't like...\n\nI would suggest improving...", + }, + { + title: "Ease of Use", + text: "Rate how easy and comfortable the product is to use.", + textPlaceholder: + "I particularly like...\n\nI don't like...\n\nI would suggest improving...", + }, + { + title: "Design", + text: "Rate the design of the product.", + textPlaceholder: + "I particularly like...\n\nI don't like...\n\nI would suggest improving...", + }, + { + title: "Other", + text: "Feel free to share additional thoughts and suggestions to help us in continuously improving our products.", + textPlaceholder: "I would wish for...", + }, +]; + +const feedbackData = [ + { + rating: defaultRating, + textInput: "", + }, + { + rating: defaultRating, + textInput: "", + }, + { + rating: defaultRating, + textInput: "", + }, + { + ratingDisabled: true, + rating: defaultRating, + textInput: "", + }, +]; + +export function FeedbackStepsModalContent({ navigation }) { + const appContext = useContext(AppContext); + const { t } = useTranslation(); + + const [data, setData] = useState(feedbackData); + const [step, setStep] = useState(0); + + const feedbackDataLangauge = + appContext.appLanguage === Constants.defaultLanguage + ? feedbackDataDe + : feedbackDataEn; + + const handleBackPress = () => { + if (step === 0) { + navigation.goBack(); + } else { + setStep(step - 1); + } + }; + + const handleContinuePress = () => { + const nextStep = step + 1; + + if (nextStep >= feedbackData.length) { + navigation.navigate("help"); + navigation.navigate("modalFeedbackFinished", data); + } else { + setStep(nextStep); + } + }; + + const handleRating = (rating) => { + const newData = [...data]; + newData[step].rating = rating; + setData(newData); + }; + + const renderStars = () => { + if (data[step].ratingDisabled) return null; + + const stars = []; + + for (let i = 1; i <= 5; i++) { + stars.push( + handleRating(i)} + iconName={data[step].rating >= i ? "star" : "star"} + iconSize={36} + iconColor={ + data[step].rating >= i + ? appContext.appTheme.colors.primary + : appContext.appTheme.colors.gray + } + activeOpacity={0.7} + /> + ); + } + + return ( + + {stars} + + { + t("screens.help.modalFeedbackSteps.startTexts", { + returnObjects: true, + })[data[step].rating - 1] + } + + + ); + }; + + const isContinueButtonDisabled = () => { + if (data[step].ratingDisabled) return false; + + if (data[step].rating === 0) return true; + + return false; + }; + + return ( + + + + + {feedbackDataLangauge[step].title} + + + + {feedbackDataLangauge[step].text} + + + {renderStars()} + + + { + const newData = [...data]; + newData[step].textInput = text; + setData(newData); + }} + style={{ + textAlignVertical: "top", + height: 40 * 8, + borderWidth: 1, + borderColor: appContext.appTheme.divider, + borderRadius: 10, + padding: 12, + color: appContext.appTheme.text, + backgroundColor: appContext.appTheme.backgroundColor, + }} + /> + + + + handleBackPress()} + /> + handleContinuePress()} + disabled={isContinueButtonDisabled()} + /> + + + + + + + ); +} diff --git a/src/Screens/Help/modals/HelpCenter/index.js b/src/Screens/Help/modals/HelpCenter/index.js index bc4beb6..7b5b07f 100644 --- a/src/Screens/Help/modals/HelpCenter/index.js +++ b/src/Screens/Help/modals/HelpCenter/index.js @@ -1,12 +1,16 @@ -import { FlatList, Text, View } from "react-native"; +import { FlatList, View } from "react-native"; import { AccordionItem } from "../../../../Components/Accordion"; -import { AppContext, AppStyles, ModalContainer } from "../../../../utils"; +import { + AppContext, + AppStyles, + Constants, + ModalContainer, +} from "../../../../utils"; import { useContext } from "react"; -import MyIcon from "../../../../Components/Icon"; -import { MyTextButton } from "../../../../Components/Button"; -import { OpenMailComposer } from "../../../../../App"; +import { useTranslation } from "react-i18next"; +import { InfoHeader } from "../.."; -const helpData = [ +const helpDataDe = [ { topicText: "Allgemeine Fragen", question: @@ -73,72 +77,93 @@ const helpData = [ }, ]; -export default function HelpCenterModalContent({ navigation, route }) { +const helpDataEn = [ + { + topicText: "General Questions", + question: + "What is the basic functionality of the mobile app for device control?", + answer: + "The mobile app allows you to control compatible devices using your smartphone or tablet. You can activate various functions, change settings, and perform actions remotely.", + }, + { + question: "What types of devices can be controlled through the app?", + answer: + "Our app supports a variety of devices, including smart home devices, entertainment electronics, household appliances, and more.", + }, + { + question: "Is the app available for both Android and iOS devices?", + answer: + "Yes, the app is available for both Android and iOS devices. You can download it from the Google Play Store or the Apple App Store.", + }, + { + question: "Where can I download the app?", + answer: + "You can download and install the app directly from the Google Play Store (for Android) or the Apple App Store (for iOS).", + }, + { + question: + "Do I need an internet connection to control the device through the app?", + answer: + "Yes, an active internet connection (Wi-Fi or mobile data) is required to connect the app to the device and use the control functions.", + }, + { + question: "Does the app support multiple devices simultaneously?", + answer: + "Yes, the app allows you to control multiple compatible devices simultaneously and switch between them.", + }, + { + topicText: "Setup and Connection", + question: "How do I set up the connection between the app and my device?", + answer: + "The exact setup process may vary depending on the device, but typically, you need to open the app, select the device, and follow the on-screen instructions to establish the connection.", + }, + { + question: + "What steps are required to initially connect the device to the app?", + answer: + "Launch the app, create an account (if required), add the device by selecting it from the list of available devices, and follow the instructions for establishing the connection.", + }, + { + question: + "Do I need specific settings on the device to establish the connection?", + answer: + "Yes, in most cases, you need to ensure that the device is powered on and in pairing mode before attempting to connect it through the app.", + }, + { + question: + "What types of connection methods are supported by the app (e.g., Bluetooth, Wi-Fi, etc.)?", + answer: + "Our app typically supports Wi-Fi connections to enable stable and reliable control over longer distances.", + }, + { + question: + "What should I do if the connection between the app and the device is lost?", + answer: + "First, check your internet connection. If the issue persists, you can try removing and re-adding the device from the app. If necessary, restarting the device might help.", + }, +]; + +export default function HelpCenterModalContent() { const appContext = useContext(AppContext); + const { t } = useTranslation(); + + const helpData = + appContext.appLanguage === Constants.defaultLanguage + ? helpDataDe + : helpDataEn; return ( - - - - Hier findest du Antworten. - - - } - ListFooterComponent={ - - - Konnte deine Frage nicht beantwortet werden oder fehlt dir etwas? - - { - console.log("contact us"); - - OpenMailComposer(["support@roese.dev"], "FAQ Help", "") - .then((result) => { - console.log(result); - }) - .catch((error) => { - console.log(error); - }); - }} - /> - + } + ListFooterComponent={} renderItem={({ item, index }) => ( ; -} diff --git a/src/utils.js b/src/utils.js index 1b57414..a44ec6a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -38,8 +38,10 @@ export const Constants = { jumpToScene: 8, }, globals: { + contact_us_email: "support@shinnex.com", max_device_name_length: 20, max_scene_name_length: 20, + faq_max_input_length: 1500, }, defaultAnimationId: "00000000-0000-0000-0000-000000000000", // used id for -> No animation selected gradients: { @@ -93,6 +95,7 @@ const DarkAppTheme = { primary: "#e67e22", secondary: "#9b59b6", gray: "#b2bec3", + green: "#2ecc71", }, text: "#fff", textSecondary: "#ddd", @@ -149,6 +152,7 @@ const LightAppTheme = { primary: "#e67e22", secondary: "#9b59b6", gray: "#636e72", + green: "#2ecc71", }, text: "#000", textSecondary: "#555",