From 9ee5b41921e726b661295c57310018724ad06e43 Mon Sep 17 00:00:00 2001 From: deepakglobant <123438709+deepakglobant@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:59:29 +0530 Subject: [PATCH] feat: setup feedback package (MN-295) (#601) --- .babelrc.json | 3 +- .github/workflows/camera-analyze.yml | 2 +- .github/workflows/corejs-analyze.yml | 2 +- .github/workflows/feedback-analyze.yml | 30 ++++ .github/workflows/sights-analyze.yml | 2 +- .github/workflows/toolkit-analyze.yml | 2 +- .github/workflows/ui-analyze.yml | 2 +- .github/workflows/visualization-analyze.yml | 2 +- .github/workflows/website-deploy.yml | 4 +- metro.config.js | 1 + package.json | 8 +- packages/feedback/.editorconfig | 8 + packages/feedback/.eslintignore | 3 + packages/feedback/.eslintrc.json | 3 + packages/feedback/.gitignore | 29 ++++ packages/feedback/.release-it.json | 5 + packages/feedback/LICENSE | 32 ++++ packages/feedback/README.md | 13 ++ packages/feedback/babel.config.js | 6 + packages/feedback/bob.config.js | 8 + packages/feedback/jsconfig.json | 6 + packages/feedback/package.json | 62 +++++++ .../src/components/BuildQuestion/index.js | 86 ++++++++++ .../src/components/Feedback/Feedback.js | 42 +++++ .../feedback/src/components/Feedback/index.js | 15 ++ .../src/components/common/FreeTextInput.js | 48 ++++++ .../src/components/common/RadioInput.js | 79 +++++++++ .../src/components/common/SelectInput.js | 123 ++++++++++++++ .../src/components/common/TextButton.js | 40 +++++ .../feedback/src/components/common/index.js | 11 ++ packages/feedback/src/components/index.js | 2 + packages/feedback/src/hooks/index.js | 0 packages/feedback/src/i18n/index.js | 16 ++ packages/feedback/src/i18n/resources/en.js | 5 + packages/feedback/src/i18n/resources/fr.js | 5 + packages/feedback/src/i18n/resources/index.js | 6 + packages/feedback/src/index.js | 2 + src/config/Navigation.js | 5 + src/screens/InspectionFeedback/index.js | 104 ++++++++++++ src/screens/InspectionFeedback/styles.js | 3 + src/screens/index.js | 1 + src/screens/names.js | 1 + webpack.config.js | 1 + website/docs.sidebars.js | 1 + website/docs/feedback.md | 159 ++++++++++++++++++ yarn.lock | 7 + 46 files changed, 984 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/feedback-analyze.yml create mode 100644 packages/feedback/.editorconfig create mode 100644 packages/feedback/.eslintignore create mode 100644 packages/feedback/.eslintrc.json create mode 100644 packages/feedback/.gitignore create mode 100644 packages/feedback/.release-it.json create mode 100644 packages/feedback/LICENSE create mode 100644 packages/feedback/README.md create mode 100644 packages/feedback/babel.config.js create mode 100644 packages/feedback/bob.config.js create mode 100644 packages/feedback/jsconfig.json create mode 100644 packages/feedback/package.json create mode 100644 packages/feedback/src/components/BuildQuestion/index.js create mode 100644 packages/feedback/src/components/Feedback/Feedback.js create mode 100644 packages/feedback/src/components/Feedback/index.js create mode 100644 packages/feedback/src/components/common/FreeTextInput.js create mode 100644 packages/feedback/src/components/common/RadioInput.js create mode 100644 packages/feedback/src/components/common/SelectInput.js create mode 100644 packages/feedback/src/components/common/TextButton.js create mode 100644 packages/feedback/src/components/common/index.js create mode 100644 packages/feedback/src/components/index.js create mode 100644 packages/feedback/src/hooks/index.js create mode 100644 packages/feedback/src/i18n/index.js create mode 100644 packages/feedback/src/i18n/resources/en.js create mode 100644 packages/feedback/src/i18n/resources/fr.js create mode 100644 packages/feedback/src/i18n/resources/index.js create mode 100644 packages/feedback/src/index.js create mode 100644 src/screens/InspectionFeedback/index.js create mode 100644 src/screens/InspectionFeedback/styles.js create mode 100644 website/docs/feedback.md diff --git a/.babelrc.json b/.babelrc.json index 78f204fb8..99517340a 100644 --- a/.babelrc.json +++ b/.babelrc.json @@ -19,7 +19,8 @@ "@monkvision/sights": "./packages/sights", "@monkvision/toolkit": "./packages/toolkit", "@monkvision/visualization": "./packages/visualization", - "@monkvision/inspection-report": "./packages/inspection-report" + "@monkvision/inspection-report": "./packages/inspection-report", + "@monkvision/feedback": "./packages/feedback" } }], ["babel-plugin-inline-import", { "extensions": [".svg"] }] diff --git a/.github/workflows/camera-analyze.yml b/.github/workflows/camera-analyze.yml index d4f3bbad2..176e132cb 100644 --- a/.github/workflows/camera-analyze.yml +++ b/.github/workflows/camera-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/camera && yarn install - run: cd packages/camera && yarn lint diff --git a/.github/workflows/corejs-analyze.yml b/.github/workflows/corejs-analyze.yml index 462797576..833b8ae7f 100644 --- a/.github/workflows/corejs-analyze.yml +++ b/.github/workflows/corejs-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/corejs && yarn install - run: cd packages/corejs && yarn lint diff --git a/.github/workflows/feedback-analyze.yml b/.github/workflows/feedback-analyze.yml new file mode 100644 index 000000000..f39e1a9ef --- /dev/null +++ b/.github/workflows/feedback-analyze.yml @@ -0,0 +1,30 @@ +name: Check Feedback package + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + analyze: + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '16' + cache: 'yarn' + - run: cd packages/feedback && yarn install + - run: cd packages/feedback && yarn lint + - run: cd packages/feedback && yarn run build diff --git a/.github/workflows/sights-analyze.yml b/.github/workflows/sights-analyze.yml index 26b4dcf20..e350324b6 100644 --- a/.github/workflows/sights-analyze.yml +++ b/.github/workflows/sights-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/sights && yarn install - run: cd packages/sights && yarn lint diff --git a/.github/workflows/toolkit-analyze.yml b/.github/workflows/toolkit-analyze.yml index 00c196b3f..6678aab86 100644 --- a/.github/workflows/toolkit-analyze.yml +++ b/.github/workflows/toolkit-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/toolkit && yarn install - run: cd packages/toolkit && yarn lint diff --git a/.github/workflows/ui-analyze.yml b/.github/workflows/ui-analyze.yml index 60eefc6a5..2feedc616 100644 --- a/.github/workflows/ui-analyze.yml +++ b/.github/workflows/ui-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/ui && yarn install - run: cd packages/ui && yarn lint diff --git a/.github/workflows/visualization-analyze.yml b/.github/workflows/visualization-analyze.yml index 2031f1d2d..f5e96c698 100644 --- a/.github/workflows/visualization-analyze.yml +++ b/.github/workflows/visualization-analyze.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '16' cache: 'yarn' - run: cd packages/visualization && yarn install - run: cd packages/visualization && yarn lint diff --git a/.github/workflows/website-deploy.yml b/.github/workflows/website-deploy.yml index cd34594c0..fc85359aa 100644 --- a/.github/workflows/website-deploy.yml +++ b/.github/workflows/website-deploy.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: "16.x" - name: Build Packages run: | yarn @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: "16.x" - uses: webfactory/ssh-agent@v0.5.0 with: ssh-private-key: ${{ secrets.FUTURA_SECRET }} diff --git a/metro.config.js b/metro.config.js index d62bb8feb..8f2da1d2f 100644 --- a/metro.config.js +++ b/metro.config.js @@ -13,6 +13,7 @@ config.resolver = { '@monkvision/toolkit', '@monkvision/visualization', '@monkvision/inspection-report', + '@monkvision/feedback', ], }; diff --git a/package.json b/package.json index a67706be3..0c2dd0b45 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "start": "expo start --https", "start:documentation": "cd website && yarn run docs:start", "start:report": "cd services/inspection-report && yarn run start", + "start:feedback": "cd services/feedback && yarn run start", "watch:ui": "cd ./packages/ui && yarn watch", "watch:camera": "cd ./packages/camera && yarn watch", "watch:visualization": "cd ./packages/visualization && yarn watch", @@ -24,7 +25,8 @@ "watch:corejs": "cd ./packages/corejs && yarn watch", "watch:sights": "cd ./packages/sights && yarn watch", "watch:inspection-report": "cd ./packages/inspection-report && yarn watch", - "watch:all": "concurrently \"yarn run watch:ui\" \"yarn run watch:toolkit\" \"yarn run watch:visualization\" \"yarn run watch:camera\" \"yarn run watch:corejs\" \"yarn run watch:sights\" \"yarn run watch:inspection-report\"", + "watch:feedback": "cd ./packages/feedback && yarn watch", + "watch:all": "concurrently \"yarn run watch:ui\" \"yarn run watch:toolkit\" \"yarn run watch:visualization\" \"yarn run watch:camera\" \"yarn run watch:corejs\" \"yarn run watch:sights\" \"yarn run watch:inspection-report\" \"yarn run watch:feedback\"", "build:ui": "cd ./packages/ui && yarn run build", "build:camera": "cd ./packages/camera && yarn run build", "build:visualization": "cd ./packages/visualization && yarn run build", @@ -32,7 +34,8 @@ "build:corejs": "cd ./packages/corejs && yarn run build", "build:sights": "cd ./packages/sights && yarn run build", "build:inspection-report": "cd ./packages/inspection-report && yarn run build", - "build:all": "concurrently \"yarn run build:ui\" \"yarn run build:toolkit\" \"yarn run build:visualization\" \"yarn run build:camera\" \"yarn run build:corejs\" \"yarn run build:sights\" \"yarn run build:inspection-report\"", + "build:all": "concurrently \"yarn run build:ui\" \"yarn run build:toolkit\" \"yarn run build:visualization\" \"yarn run build:camera\" \"yarn run build:corejs\" \"yarn run build:sights\" \"yarn run build:inspection-report\" \"yarn run build:feedback\"", + "build:feedback": "cd ./packages/feedback && yarn run build", "build:android": "expo build:android", "build:ios": "expo build:ios", "eject": "expo eject", @@ -153,6 +156,7 @@ "@monkvision/ui": "*", "@monkvision/visualization": "*", "@monkvision/inspection-report": "*", + "@monkvision/feedback": "*", "react-native-svg": "*" }, "resolutions": { diff --git a/packages/feedback/.editorconfig b/packages/feedback/.editorconfig new file mode 100644 index 000000000..73db316c0 --- /dev/null +++ b/packages/feedback/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/packages/feedback/.eslintignore b/packages/feedback/.eslintignore new file mode 100644 index 000000000..375c30fe5 --- /dev/null +++ b/packages/feedback/.eslintignore @@ -0,0 +1,3 @@ +node_modules/ +commonjs/ +module/ diff --git a/packages/feedback/.eslintrc.json b/packages/feedback/.eslintrc.json new file mode 100644 index 000000000..afd435d3a --- /dev/null +++ b/packages/feedback/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "root": false +} diff --git a/packages/feedback/.gitignore b/packages/feedback/.gitignore new file mode 100644 index 000000000..1b8564d22 --- /dev/null +++ b/packages/feedback/.gitignore @@ -0,0 +1,29 @@ +# builds +build/ +lib/ +dist/ +module/ +commonjs/ +typescript/ +web-build/ + +# deploy +.env* + +# modules +node_modules/ +coverage/ +.expo/ +.docusaurus/ + +# logs +npm-debug.* +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# cache +.eslintcache + +# misc +.DS_Store diff --git a/packages/feedback/.release-it.json b/packages/feedback/.release-it.json new file mode 100644 index 000000000..5854004b4 --- /dev/null +++ b/packages/feedback/.release-it.json @@ -0,0 +1,5 @@ +{ + "hooks": { "after:bump": ["npm run build"] }, + "git": { "commit": false }, + "github": { "release": false } +} diff --git a/packages/feedback/LICENSE b/packages/feedback/LICENSE new file mode 100644 index 000000000..a3592ab9e --- /dev/null +++ b/packages/feedback/LICENSE @@ -0,0 +1,32 @@ +The Clear BSD License + +Copyright (c) [2022] [Monk](http://monk.ai) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted (subject to the limitations in the disclaimer +below) provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/feedback/README.md b/packages/feedback/README.md new file mode 100644 index 000000000..5606d3a1c --- /dev/null +++ b/packages/feedback/README.md @@ -0,0 +1,13 @@ +# 👁️‍🗨️ @monkvision/feedback + +[![npm latest package](https://img.shields.io/npm/v/@monkvision/feedback/latest.svg)](https://www.npmjs.com/package/@monkvision/feedback) + +```yarn +yarn add @monkvision/feedback +``` + +This project is licensed under the BSD-3-Clause-Clear license. See the [LICENSE](LICENSE) file for more info. + +--- + +![Monk banner](https://raw.githubusercontent.com/monkvision/monkjs/main/assets/banner.png) diff --git a/packages/feedback/babel.config.js b/packages/feedback/babel.config.js new file mode 100644 index 000000000..f6d217d38 --- /dev/null +++ b/packages/feedback/babel.config.js @@ -0,0 +1,6 @@ +module.exports = (api) => { + api.cache(true); + return { + presets: ['babel-preset-expo'], + }; +}; diff --git a/packages/feedback/bob.config.js b/packages/feedback/bob.config.js new file mode 100644 index 000000000..ac0924a8e --- /dev/null +++ b/packages/feedback/bob.config.js @@ -0,0 +1,8 @@ +module.exports = { + source: 'src', + output: '.', + targets: [ + ['commonjs', { copyFlow: true }], + ['module', { copyFlow: true }], + ], +}; diff --git a/packages/feedback/jsconfig.json b/packages/feedback/jsconfig.json new file mode 100644 index 000000000..51679b31c --- /dev/null +++ b/packages/feedback/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "baseUrl": "src/", + "target": "es2020" + } +} diff --git a/packages/feedback/package.json b/packages/feedback/package.json new file mode 100644 index 000000000..8c979f79d --- /dev/null +++ b/packages/feedback/package.json @@ -0,0 +1,62 @@ +{ + "name": "@monkvision/feedback", + "author": "monkvision", + "license": "BSD-3-Clause-Clear", + "version": "3.8.4", + "private": false, + "description": "AI-powered vehicle damage detection for React Native", + "homepage": "https://github.com/monkvision/monkjs/packages/feedback/#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/monkvision/monkjs.git", + "directory": "packages/feedback" + }, + "bugs": { + "url": "https://github.com/monkvision/monkjs/issues" + }, + "keywords": [ + "react native", + "inspection report", + "native components", + "vehicle damage detection" + ], + "main": "commonjs/index.js", + "module": "module/index.js", + "react-native": "src/index.js", + "files": [ + "commonjs", + "module", + "src", + ".editorconfig", + "LICENSE", + "package.json", + "README.md" + ], + "scripts": { + "watch": "watch 'yarn run build' src", + "lint": "eslint src --cache", + "lint-fix": "eslint src --fix", + "build": "bob build", + "release": "release-it" + }, + "dependencies": { + "@expo/vector-icons": "^12.0.5", + "@react-native-community/slider": "^4.4.2", + "i18next": "^21.8.13", + "react-i18next": "^11.18.0", + "react-native-element-dropdown": "^2.10.0" + }, + "devDependencies": { + "prop-types": "^15.8.1", + "react-native-builder-bob": "^0.18.2", + "release-it": "*" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-svg": "*" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/feedback/src/components/BuildQuestion/index.js b/packages/feedback/src/components/BuildQuestion/index.js new file mode 100644 index 000000000..99eb6825a --- /dev/null +++ b/packages/feedback/src/components/BuildQuestion/index.js @@ -0,0 +1,86 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { + FreeTextInput, + RadioInput, + SelectInput, + TextButton, +} from '../common'; + +export default function BuildQuestion({ + type, + question, + answer, + options, + onChange, + config, + inputProps, +}) { + return ( + <> + { + type === 'text' && ( + + ) + } + { + type === 'radio' && ( + + ) + } + { + type === 'select' && ( + + ) + } + { + type === 'button' && ( + + ) + } + + ); +} + +BuildQuestion.propTypes = { + answer: PropTypes.any, + config: PropTypes.shape({ + isMulti: PropTypes.bool, + }), + inputProps: PropTypes.object, + onChange: PropTypes.func, + options: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.any, + })), + question: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, +}; + +BuildQuestion.defaultProps = { + answer: '', + onChange: () => { }, + config: { + isMulti: false, + }, + inputProps: {}, + options: [], +}; diff --git a/packages/feedback/src/components/Feedback/Feedback.js b/packages/feedback/src/components/Feedback/Feedback.js new file mode 100644 index 000000000..4b0d1d3dd --- /dev/null +++ b/packages/feedback/src/components/Feedback/Feedback.js @@ -0,0 +1,42 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { View } from 'react-native'; +import BuildQuestion from '../BuildQuestion'; + +export default function Feedback({ questions }) { + return ( + questions.map((question, index) => ( + // eslint-disable-next-line react/no-array-index-key + + + + )) + ); +} + +Feedback.propTypes = { + questions: PropTypes.arrayOf(PropTypes.shape({ + answer: PropTypes.any, + config: PropTypes.object, + inputProps: PropTypes.object, + onChange: PropTypes.func, + options: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.any, + })), + question: PropTypes.string.isRequired, + type: PropTypes.string.isRequired, + })), +}; + +Feedback.defaultProps = { + questions: [], +}; diff --git a/packages/feedback/src/components/Feedback/index.js b/packages/feedback/src/components/Feedback/index.js new file mode 100644 index 000000000..caa95ab99 --- /dev/null +++ b/packages/feedback/src/components/Feedback/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { I18nextProvider } from 'react-i18next'; + +import i18n from '../../i18n'; +import Feedback from './Feedback'; + +function FeedbackHOC(props) { + return ( + + + + ); +} + +export default FeedbackHOC; diff --git a/packages/feedback/src/components/common/FreeTextInput.js b/packages/feedback/src/components/common/FreeTextInput.js new file mode 100644 index 000000000..cbbce6e8a --- /dev/null +++ b/packages/feedback/src/components/common/FreeTextInput.js @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { StyleSheet, Text, TextInput, View } from 'react-native'; + +const styles = StyleSheet.create({ + textLabel: { + color: '#fff', + fontSize: 16, + marginBottom: 10, + }, + textInput: { + borderColor: '#fff', + borderRadius: 4, + borderWidth: 1, + color: '#fff', + padding: 10, + }, +}); + +function FreeTextInput({ label, value, inputProps, onChange }) { + return ( + + {label} + + + ); +} + +FreeTextInput.propTypes = { + inputProps: PropTypes.object, + label: PropTypes.string, + onChange: PropTypes.func, + value: PropTypes.string, +}; + +FreeTextInput.defaultProps = { + inputProps: {}, + label: '', + onChange: () => { }, + value: '', +}; + +export default FreeTextInput; diff --git a/packages/feedback/src/components/common/RadioInput.js b/packages/feedback/src/components/common/RadioInput.js new file mode 100644 index 000000000..df0613e4e --- /dev/null +++ b/packages/feedback/src/components/common/RadioInput.js @@ -0,0 +1,79 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; + +const styles = StyleSheet.create({ + textLabel: { + color: '#fff', + fontSize: 16, + marginBottom: 10, + }, + radioButtonContainer: { + alignItems: 'center', + flexDirection: 'row', + marginBottom: 10, + marginRight: 10, + }, + radioButton: { + alignItems: 'center', + borderColor: '#fff', + borderRadius: 10, + borderWidth: 1, + height: 18, + justifyContent: 'center', + width: 18, + }, + radioButtonIcon: { + backgroundColor: '#fff', + borderRadius: 7, + height: 12, + width: 12, + }, + radioButtonText: { + color: '#fff', + fontSize: 16, + marginLeft: 10, + }, +}); + +function RadioInput({ label, options, value, onChange }) { + return ( + <> + {label} + 3 ? { flexDirection: 'column' } : { flexDirection: 'row' }}> + { + options.map((item, index) => ( + // eslint-disable-next-line react/no-array-index-key + + onChange(item)} style={styles.radioButton}> + {value === item.value ? : null} + + onChange(item)}> + {item.label} + + + )) + } + + + ); +} + +RadioInput.propTypes = { + label: PropTypes.string, + onChange: PropTypes.func, + options: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.any, + })), + value: PropTypes.any, +}; + +RadioInput.defaultProps = { + label: '', + value: '', + options: [], + onChange: () => { }, +}; + +export default RadioInput; diff --git a/packages/feedback/src/components/common/SelectInput.js b/packages/feedback/src/components/common/SelectInput.js new file mode 100644 index 000000000..e78050522 --- /dev/null +++ b/packages/feedback/src/components/common/SelectInput.js @@ -0,0 +1,123 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { StyleSheet, Text } from 'react-native'; +import { Dropdown, MultiSelect } from 'react-native-element-dropdown'; + +const styles = StyleSheet.create({ + textLabel: { + color: '#fff', + fontSize: 16, + marginBottom: 10, + }, + containerStyle: { + backgroundColor: '#121212', + }, + dropdown: { + borderColor: '#fff', + borderRadius: 4, + borderWidth: 1, + height: 39, + padding: 12, + }, + placeholderStyle: { + color: '#fff', + fontSize: 16, + }, + selectedTextStyle: { + fontSize: 14, + color: '#fff', + }, + iconStyle: { + height: 20, + width: 20, + }, + itemTextStyle: { + color: '#fff', + }, + inputSearchStyle: { + color: '#fff', + fontSize: 16, + outlineWidth: 0, + }, + icon: { + marginRight: 5, + }, +}); + +function SelectInput({ label, options, value, onChange, config, inputProps }) { + return ( + <> + {label} + { + config.isMulti ? ( + onChange(item)} + placeholderStyle={styles.placeholderStyle} + search + selectedTextStyle={styles.selectedTextStyle} + style={styles.dropdown} + value={value} + valueField="value" + /> + ) : ( + onChange(item)} + placeholderStyle={styles.placeholderStyle} + search + selectedTextStyle={styles.selectedTextStyle} + style={styles.dropdown} + value={value} + valueField="value" + /> + ) + } + + ); +} + +SelectInput.propTypes = { + config: PropTypes.shape({ + isMulti: PropTypes.bool, + }), + inputProps: PropTypes.object, + label: PropTypes.string, + onChange: PropTypes.func, + options: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string, + value: PropTypes.any, + })), + value: PropTypes.any, +}; + +SelectInput.defaultProps = { + label: '', + value: '', + options: [], + onChange: () => { }, + config: { + isMulti: false, + }, + inputProps: {}, +}; + +export default SelectInput; diff --git a/packages/feedback/src/components/common/TextButton.js b/packages/feedback/src/components/common/TextButton.js new file mode 100644 index 000000000..f4d5f0f69 --- /dev/null +++ b/packages/feedback/src/components/common/TextButton.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { StyleSheet, TouchableOpacity, Text } from 'react-native'; + +const styles = StyleSheet.create({ + container: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + borderWidth: 2, + borderStyle: 'solid', + borderColor: '#5D5E67', + borderRadius: 28, + paddingHorizontal: 10, + paddingVertical: 10, + }, + text: { + color: '#ffffff', + fontSize: 14, + }, +}); + +function TextButton({ label, onPress }) { + return ( + + {label} + + ); +} + +TextButton.propTypes = { + label: PropTypes.string, + onPress: PropTypes.func, +}; +TextButton.defaultProps = { + label: '', + onPress: () => {}, +}; + +export default TextButton; diff --git a/packages/feedback/src/components/common/index.js b/packages/feedback/src/components/common/index.js new file mode 100644 index 000000000..7909813e3 --- /dev/null +++ b/packages/feedback/src/components/common/index.js @@ -0,0 +1,11 @@ +import FreeTextInput from './FreeTextInput'; +import RadioInput from './RadioInput'; +import TextButton from './TextButton'; +import SelectInput from './SelectInput'; + +export { + FreeTextInput, + RadioInput, + TextButton, + SelectInput, +}; diff --git a/packages/feedback/src/components/index.js b/packages/feedback/src/components/index.js new file mode 100644 index 000000000..202986754 --- /dev/null +++ b/packages/feedback/src/components/index.js @@ -0,0 +1,2 @@ +export { default as Feedback } from './Feedback'; +export { default as BuildQuestion } from './BuildQuestion'; diff --git a/packages/feedback/src/hooks/index.js b/packages/feedback/src/hooks/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/packages/feedback/src/i18n/index.js b/packages/feedback/src/i18n/index.js new file mode 100644 index 000000000..21f5c3d62 --- /dev/null +++ b/packages/feedback/src/i18n/index.js @@ -0,0 +1,16 @@ +import { createInstance } from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import resources from './resources'; + +const i18n = createInstance({ + compatibilityJSON: 'v3', + fallbackLng: 'en', + interpolation: { + escapeValue: false, + }, + resources, +}); + +i18n.use(initReactI18next).init(); + +export default i18n; diff --git a/packages/feedback/src/i18n/resources/en.js b/packages/feedback/src/i18n/resources/en.js new file mode 100644 index 000000000..a268e27f9 --- /dev/null +++ b/packages/feedback/src/i18n/resources/en.js @@ -0,0 +1,5 @@ +const en = { + translation: {}, +}; + +export default en; diff --git a/packages/feedback/src/i18n/resources/fr.js b/packages/feedback/src/i18n/resources/fr.js new file mode 100644 index 000000000..6539a22ba --- /dev/null +++ b/packages/feedback/src/i18n/resources/fr.js @@ -0,0 +1,5 @@ +const fr = { + translation: {}, +}; + +export default fr; diff --git a/packages/feedback/src/i18n/resources/index.js b/packages/feedback/src/i18n/resources/index.js new file mode 100644 index 000000000..db9aa5ec3 --- /dev/null +++ b/packages/feedback/src/i18n/resources/index.js @@ -0,0 +1,6 @@ +import en from './en'; +import fr from './fr'; + +const resources = { en, fr }; + +export default resources; diff --git a/packages/feedback/src/index.js b/packages/feedback/src/index.js new file mode 100644 index 000000000..a5457872b --- /dev/null +++ b/packages/feedback/src/index.js @@ -0,0 +1,2 @@ +export * from './components'; +export { default as i18nDamageReport } from './i18n'; diff --git a/src/config/Navigation.js b/src/config/Navigation.js index 7eb1e1d2c..7db47e3d9 100644 --- a/src/config/Navigation.js +++ b/src/config/Navigation.js @@ -51,6 +51,11 @@ export default function Navigation() { component={Screens.InspectionReport} title="Monk - Inspection Report" /> + ); diff --git a/src/screens/InspectionFeedback/index.js b/src/screens/InspectionFeedback/index.js new file mode 100644 index 000000000..08989082e --- /dev/null +++ b/src/screens/InspectionFeedback/index.js @@ -0,0 +1,104 @@ +import React, { useCallback, useState } from 'react'; +import { Feedback } from '@monkvision/feedback'; +import { View } from 'react-native'; + +export default function InspectionFeedback() { + const [interior, setInterior] = useState(''); + const [windShieldCondition, setWindShieldCondition] = useState(''); + const [tireCondition, setTireCondition] = useState(''); + const [tireConditionSingleSelect, setTireConditionSingleSelect] = useState(''); + const [tireConditionMultiSelect, setTireConditionMultiSelect] = useState([]); + const [vehicleInterior, setVehicleInterior] = useState(''); + + const handleSubmit = useCallback(() => { + console.log('🚀 interior : ', interior); + console.log('🚀 windShieldCondition : ', windShieldCondition); + console.log('🚀 tireCondition : ', tireCondition); + console.log('🚀 tireConditionSingleSelect : ', tireConditionSingleSelect); + console.log('🚀 tireConditionMultiSelect : ', tireConditionMultiSelect); + console.log('🚀 vehicleInterior : ', vehicleInterior); + }, [ + interior, + windShieldCondition, + tireCondition, + tireConditionSingleSelect, + tireConditionMultiSelect, + vehicleInterior + ]); + + return ( + + setInterior(value) + }, { + type: 'radio', + question: 'Is the windshield in good condition?', + answer: windShieldCondition, + onChange: (data) => setWindShieldCondition(data.value), + options: [ + { label: 'Y', value: true }, + { label: 'N', value: false }, + ], + }, { + type: 'select', + question: 'Is the tire condition normal (Single Select)?', + answer: tireConditionSingleSelect, + onChange: (data) => setTireConditionSingleSelect(data), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'select', + question: 'Is the tire condition normal (Multi Select)?', + answer: tireConditionMultiSelect, + config: { + isMulti: true, + }, + onChange: (data) => setTireConditionMultiSelect(data), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'radio', + question: 'Is the tire condition normal?', + answer: tireCondition, + onChange: (data) => setTireCondition(data.value), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'radio', + question: 'How is the interior of the vehicle?', + answer: vehicleInterior, + onChange: (data) => setVehicleInterior(data.value), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + ], + }, { + type: 'button', + question: 'Submit', + onChange: () => handleSubmit() + }]} + /> + + ); +} + +InspectionFeedback.propTypes = {}; + +InspectionFeedback.defaultProps = {}; diff --git a/src/screens/InspectionFeedback/styles.js b/src/screens/InspectionFeedback/styles.js new file mode 100644 index 000000000..78c2ab86e --- /dev/null +++ b/src/screens/InspectionFeedback/styles.js @@ -0,0 +1,3 @@ +import { StyleSheet } from 'react-native'; + +export default StyleSheet.create({}); diff --git a/src/screens/index.js b/src/screens/index.js index 9bdcf24e9..274746503 100644 --- a/src/screens/index.js +++ b/src/screens/index.js @@ -4,5 +4,6 @@ export { default as InspectionVehicleUpdate } from './InspectionVehicleUpdate'; export { default as InspectionList } from './InspectionList'; export { default as InspectionPrompt } from './InspectionPrompt'; export { default as InspectionReport } from './InspectionReport'; +export { default as InspectionFeedback } from './InspectionFeedback'; export { default as Landing } from './Landing'; export { default as SignIn } from './Authentication/SignIn'; diff --git a/src/screens/names.js b/src/screens/names.js index e543ccdbb..3fd7e075a 100644 --- a/src/screens/names.js +++ b/src/screens/names.js @@ -3,6 +3,7 @@ export const INSPECTION_CREATE = 'inspectionCreate'; export const INSPECTION_VEHICLE_UPDATE = 'InspectionVehicleUpdate'; export const INSPECTION_LIST = 'inspectionList'; export const INSPECTION_PROMPT = 'inspectionPrompt'; +export const INSPECTION_FEEDBACK = 'inspectionFeedback'; export const INSPECTION_REPORT = 'inspectionReport'; export const LANDING = 'landing'; export const SIGN_IN = 'signIn'; diff --git a/webpack.config.js b/webpack.config.js index 603eadfa0..99acb3369 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -22,6 +22,7 @@ module.exports = async function (env, argv) { config.resolve.alias['@monkvision/toolkit'] = path.resolve(__dirname, './packages/toolkit'); config.resolve.alias['@monkvision/visualization'] = path.resolve(__dirname, './packages/visualization'); config.resolve.alias['@monkvision/inspection-report'] = path.resolve(__dirname, './packages/inspection-report'); + config.resolve.alias['@monkvision/feedback'] = path.resolve(__dirname, './packages/feedback'); if (config.mode === 'development') { config.devServer.compress = false; diff --git a/website/docs.sidebars.js b/website/docs.sidebars.js index 86769b545..d76aa371a 100644 --- a/website/docs.sidebars.js +++ b/website/docs.sidebars.js @@ -41,5 +41,6 @@ module.exports = { 'troubleshooting', 'monitoring', 'inspection-report', + 'feedback', ], }; diff --git a/website/docs/feedback.md b/website/docs/feedback.md new file mode 100644 index 000000000..04a291277 --- /dev/null +++ b/website/docs/feedback.md @@ -0,0 +1,159 @@ +--- +id: feedback +title: "🧿 Feedback" +slug: /feedback +--- + +![npm latest package](https://img.shields.io/npm/v/@monkvision/inspection-report/latest.svg) + +# Package Overview + +The Feedback package allows users to create a feedback page with different input controls such as free text, radio buttons, single / multi selection and button components. + +# Implementation Guide +## Installation + +To install the package simply run the following command in your project : + +```bash +yarn add @monkvision/feedback +``` + +## Basic Usage +The `Feedback` component exported by the package is a single page component that will automatically display the entire form with all the questions assigned to the component. It takes only one parameter which is `questions` which will be an array of all the questions. The component will create an form using an `BuildQuestion` component. + +Here is a minimal working example : + +```javascript +import React, { useState } from 'react'; +import { Feedback } from '@monkvision/feedback'; + +export default function InspectionFeedback() { + const [interior, setInterior] = useState(''); + const [windShieldCondition, setWindShieldCondition] = useState(''); + const [tireCondition, setTireCondition] = useState(''); + const [tireConditionSingleSelect, setTireConditionSingleSelect] = useState(''); + const [tireConditionMultiSelect, setTireConditionMultiSelect] = useState([]); + const [vehicleInterior, setVehicleInterior] = useState(''); + + const handleSubmit = useCallback(() => { + // Further logic will be implemented here + }, [ + interior, + windShieldCondition, + tireCondition, + tireConditionSingleSelect, + tireConditionMultiSelect, + vehicleInterior + ]); + + return ( + setInterior(value) + }, { + type: 'radio', + question: 'Is the windshield in good condition?', + answer: windShieldCondition, + onChange: (data) => setWindShieldCondition(data.value), + options: [ + { label: 'Y', value: true }, + { label: 'N', value: false }, + ], + }, { + type: 'select', + question: 'Is the tire condition normal (Single Select)?', + answer: tireConditionSingleSelect, + onChange: (data) => setTireConditionSingleSelect(data), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'select', + question: 'Is the tire condition normal (Multi Select)?', + answer: tireConditionMultiSelect, + config: { + isMulti: true, + }, + onChange: (data) => setTireConditionMultiSelect(data), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'radio', + question: 'Is the tire condition normal?', + answer: tireCondition, + onChange: (data) => setTireCondition(data.value), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + { label: 'Great', value: 'Great' }, + ], + }, { + type: 'radio', + question: 'How is the interior of the vehicle?', + answer: vehicleInterior, + onChange: (data) => setVehicleInterior(data.value), + options: [ + { label: 'Poor', value: 'Poor' }, + { label: 'Medium', value: 'Medium' }, + { label: 'Good', value: 'Good' }, + ], + }, { + type: 'button', + question: 'Submit', + onChange: () => handleSubmit() + }]} + /> + ); +} +``` + +# API +## Components +### Feedback +#### Description +```javascript +import { Feedback } from '@monkvision/feedback'; +``` + +This component is a single page component that uses `BuildQuestion` component to create an form. + +#### Props +| Prop | Type | Description | Required | Default Value | +|---------------------------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------| +| `questions.answer` | `any` | The answer for the question. Which can be string, number, boolean, object. | ✔ | | +| `questions.config` | `object` | The configuration for inputs such as `isMulti`. | ✔ | | +| `questions.inputProps` | `any` | Any other configuration which can be supported by an input as it's going to override the default behaviour. | ✔ | | +| `questions.onChange` | `Function` | A callback of change input data. | ✔ | () => {} | +| `questions.question` | `string` | The label for the question. | ✔ | | +| `questions.type` | `string` | The type of inputs which can be one of `radio`, `text`, `select`, `button`. | ✔ | | +| `questions.options` | `object` | The list of options available for radio and select inputs. | ✔ | | + +### Feedback +#### BuildQuestion +```javascript +import BuildQuestion from '../BuildQuestion'; + + +``` + +This component is a question builder which helps to create / build input components. All the props are same as passed in feedback component. diff --git a/yarn.lock b/yarn.lock index 38300b31c..d062eb7a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14121,6 +14121,13 @@ react-native-codegen@^0.0.6: jscodeshift "^0.11.0" nullthrows "^1.1.1" +react-native-element-dropdown@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/react-native-element-dropdown/-/react-native-element-dropdown-2.10.0.tgz#f4ec2310b37ff3ba64927286ab775c0ed28b681e" + integrity sha512-aFjw0JbUIKGkqklHxDm8aDCZW6Q1GICP7pIHc0sllvpWpEamItzOwAMV4G1mBIKxED77Mp+nkq9p0Dhsr/faVw== + dependencies: + lodash "^4.17.21" + react-native-gesture-handler@~1.10.2: version "1.10.3" resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz#942bbf2963bbf49fa79593600ee9d7b5dab3cfc0"