Sonar Pipeline tw mosip (#768)

* fix(INJI-223): show the camera in scan screen while sharing the VC and click on scan icon

Issue Link https://mosip.atlassian.net/browse/INJI-223

* chore: update pod deps' to match development team of 1st project

* feat[#211]:[Pooja] fix turncated passcode and confirm password button

* feat[#211]:[Pooja] fix truncated histroy title text in iOS

* feat[#211]:[Pooja] fix multiple error being displayed when the vc binding fails

* fix(INJI-223): disconnect the device while sharing the VC and click on tab icons except scan icon

Issue Link https://mosip.atlassian.net/browse/INJI-223

* feat[#211]:[Pooja] fix download card button styles

* version code for beta build in pipeline

* feat[#211]:[Pooja] add error message when VC activation fails in kebab pop up

* chore(INJI-216): bump up tuvali version to v0.4.3

* feat[#225]:[Pooja] fix about inji url in about page

* refactor(INJI-223): get the scan string from route config to keep it consistent

Issue Link https://mosip.atlassian.net/browse/INJI-223

* feat[mosip#211]:[Pooja] refactor onCancel

Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>

* feat(INJI-222): add popup for error in decryption

* feat(INJI-222): wrap app init component & popups

* feat(INJI-222): propagate event from _store to app state machine

Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>

* chore(INJI-222): move error msg text to errors obj

* Implemented Receive Card & Received Cards options in Settings

* Fixed all the locals

* [Pooja] add quality gate check for critical open bugs in sonar

---------

Co-authored-by: PuBHARGAVI <46226958+PuBHARGAVI@users.noreply.github.com>
Co-authored-by: vijay151096 <94220135+vijay151096@users.noreply.github.com>
Co-authored-by: Harsh Vardhan <harsh59v@gmail.com>
Co-authored-by: Pooja Babusingh <68894211+PoojaBabusingh@users.noreply.github.com>
Co-authored-by: adityankannan-tw <adityan.kannan@thoughtworks.com>
Co-authored-by: Alka <prasadalka1998@gmail.com>
Co-authored-by: anil_majji <majjianilkumar050@gmail.com>
Co-authored-by: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com>
This commit is contained in:
PoojaBabusing
2023-08-09 11:55:50 +05:30
committed by GitHub
parent c14327095f
commit 0af87909c9
35 changed files with 460 additions and 84 deletions

View File

@@ -22,6 +22,31 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: https://sonarcloud.io
SONAR_ORGANIZATION: ${{ secrets.ORG_KEY }}
- name: Install jq
run: sudo apt-get -y install jq
- name: Check for critical bugs
run: |
# Fetch SonarQube issues using the API
SONAR_HOST_URL=https://sonarcloud.io
SONAR_PROJECT_KEY=mosip_inji
# Fetch issues using the SonarQube API
response=$(curl -s "${SONAR_HOST_URL}/api/issues/search?componentKeys=${SONAR_PROJECT_KEY}&severities=CRITICAL&statuses=OPEN")
echo "The response is $response"
# Extract the value of "issues" field
issues_count=$(echo "$response" | jq '.issues | length')
echo "The number of issues $issues_count"
if [ "$issues_count" -eq 0 ]; then
echo "No critical issues found."
else
echo "Critical issues found. Failing the pipeline"
exit 1
fi
# If you wish to fail your job when the Quality Gate is red, uncomment the
# following lines. This would typically be used to fail a deployment.
# - uses: sonarsource/sonarqube-quality-gate-action@master

75
App.tsx
View File

@@ -6,29 +6,72 @@ import { GlobalContextProvider } from './components/GlobalContextProvider';
import { GlobalContext } from './shared/GlobalContext';
import { useSelector } from '@xstate/react';
import { useTranslation } from 'react-i18next';
import { selectIsReadError, selectIsReady } from './machines/app';
import {
selectIsDecryptError,
selectIsReadError,
selectIsReady,
} from './machines/app';
import { DualMessageOverlay } from './components/DualMessageOverlay';
import { useApp } from './screens/AppController';
import { Alert } from 'react-native';
const AppInitialization: React.FC = () => {
// kludge: this is a bad practice but has been done temporarily to surface
// an occurance of a bug with minimal residual code changes, this should
// be removed once the bug cause is determined & fixed, ref: INJI-222
const DecryptErrorAlert = (controller, t) => {
const heading = t('errors.decryptionFailed');
const desc = t('errors.decryptionFailed');
const ignoreBtnTxt = t('ignore');
Alert.alert(heading, desc, [
{
text: ignoreBtnTxt,
onPress: () => controller.ignoreDecrypt(),
style: 'cancel',
},
]);
};
const AppLayoutWrapper: React.FC = () => {
const { appService } = useContext(GlobalContext);
const isDecryptError = useSelector(appService, selectIsDecryptError);
const controller = useApp();
const { t } = useTranslation('WelcomeScreen');
if (isDecryptError) {
DecryptErrorAlert(controller, t);
}
return <AppLayout />;
};
const AppLoadingWrapper: React.FC = () => {
const { appService } = useContext(GlobalContext);
const hasFontsLoaded = useFont();
const isReady = useSelector(appService, selectIsReady);
const isReadError = useSelector(appService, selectIsReadError);
const controller = useApp();
const { t } = useTranslation('WelcomeScreen');
if (isReadError) {
return (
<DualMessageOverlay
isVisible={isReadError}
title={t('failedToReadKeys')}
message={t('retryRead')}
onTryAgain={controller.TRY_AGAIN}
onIgnore={controller.IGNORE}
/>
);
}
return isReady && hasFontsLoaded ? <AppLayout /> : <AppLoading />;
return (
<>
<AppLoading />
{isReadError ? (
<DualMessageOverlay
isVisible={isReadError}
title={t('failedToReadKeys')}
message={t('retryRead')}
onTryAgain={controller.TRY_AGAIN}
onIgnore={controller.IGNORE}
/>
) : null}
</>
);
};
const AppInitialization: React.FC = () => {
const { appService } = useContext(GlobalContext);
const isReady = useSelector(appService, selectIsReady);
const hasFontsLoaded = useFont();
return isReady && hasFontsLoaded ? (
<AppLayoutWrapper />
) : (
<AppLoadingWrapper />
);
};
export default function App() {

View File

@@ -55,6 +55,19 @@ lane :android_build_beta do
git_tag = sh('git describe --abbrev=0 --tags --exact-match HEAD').strip
def convert_tag_to_code(version)
parts = version.split('.')
version_code = parts[0].to_i * 1000000 + parts[1].to_i * 1000 + parts[2].to_i
return version_code
end
versionCode = convert_tag_to_code(git_tag)
increment_version_code(
gradle_file_path: "app/build.gradle",
version_code: versionCode
)
versionName = "Inji #{git_tag}"
gradle(task: "clean bundleBetaRelease")

View File

@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next';
import { Image, ImageBackground, View } from 'react-native';
import { getLocalizedField } from '../i18n';
import { VerifiableCredential } from '../types/vc';
import { RotatingIcon } from './RotatingIcon';
import { VcItemTags } from './VcItemTags';
import VerifiedIcon from './VerifiedIcon';
import { Column, Row, Text } from './ui';
@@ -135,7 +134,7 @@ export const VcItemContent: React.FC<VcItemContentProps> = (props) => {
{t('idType')}
</Text>
<Text
weight="regular"
weight="semibold"
color={Theme.Colors.Details}
size="smaller"
style={

View File

@@ -466,7 +466,7 @@ export const DefaultTheme = {
flex: 1,
fontSize: 33,
fontFamily: 'Inter_600SemiBold',
height: 40,
height: 60,
lineHeight: 28,
margin: 8,
textAlign: 'center',

View File

@@ -480,7 +480,7 @@ export const PurpleTheme = {
flex: 1,
fontFamily: 'Inter_700Bold',
fontSize: 29,
height: 40,
height: 60,
margin: 8,
textAlign: 'center',
},

View File

@@ -58,6 +58,25 @@ target 'Inji' do
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
# get team-id from project's first target
dev_team = ""
project = installer.aggregate_targets[0].user_project
project.targets.each do |target|
target.build_configurations.each do |config|
if dev_team.empty? and !config.build_settings['DEVELOPMENT_TEAM'].nil?
dev_team = config.build_settings['DEVELOPMENT_TEAM']
break
end
end
end
# Apply team-id
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings["DEVELOPMENT_TEAM"] = dev_team
end
end
end
permissions_path = '../node_modules/react-native-permissions/ios'

View File

@@ -718,6 +718,6 @@ SPEC CHECKSUMS:
Yoga: d1fc3575b8b68891ff5ef3c276daa855e841eb32
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: c9f0fe8dbf7e1bc17ab0a1e74d2edd0a76cd4b7f
PODFILE CHECKSUM: 81400285e73643c9d2ca00905667d0014ac840fc
COCOAPODS: 1.12.1

View File

@@ -129,6 +129,7 @@
"SettingScreen": {
"header": "إعدادات",
"injiAsVerifierApp": " كتطبيق للتحقق إنجي",
"receiveCard": "البطاقة المستلمة",
"basicSettings": "الإعدادات الأساسية",
"bioUnlock": "افتح مع القياسات الحيوية",
"language": "لغة",
@@ -512,7 +513,11 @@
"getStarted": "البدء",
"unlockApp": "فتح التطبيق",
"failedToReadKeys": "فشلت قراءة المفاتيح",
"retryRead": "هل تريد إعادة المحاولة؟"
"retryRead": "هل تريد إعادة المحاولة؟",
"errors": {
"decryptionFailed": "فشل في فك تشفير البيانات"
},
"ignore": "يتجاهل"
},
"SetupLanguage": {
"header": "حدد اللغة",
@@ -541,4 +546,4 @@
"copied": "نسخ"
}
}
}
}

View File

@@ -129,6 +129,7 @@
"SettingScreen": {
"header": "Settings",
"injiAsVerifierApp": "Inji as verifier app",
"receiveCard": "Receive Card",
"basicSettings": "Basic settings",
"bioUnlock": "Unlock with Biometric",
"language": "Language",
@@ -354,7 +355,7 @@
}
},
"RequestScreen": {
"receiveCard": "REceive Card",
"receiveCard": "Receive Card",
"bluetoothDenied": "Please enable Bluetooth to be able to request card",
"bluetoothStateIos": "Bluetooth is turned OFF, please turn it ON from Control center",
"bluetoothStateAndroid": "Bluetooth is turned OFF, please turn it ON from Quick settings menu",
@@ -512,7 +513,11 @@
"getStarted": "Get started",
"unlockApp": "Unlock application",
"failedToReadKeys": "Failed to read keys",
"retryRead": "Want to retry?"
"retryRead": "Want to retry?",
"ignore": "Ignore",
"errors": {
"decryptionFailed": "Failed to decrypt data"
}
},
"SetupLanguage": {
"header": "Choose Language",

View File

@@ -129,6 +129,7 @@
"SettingScreen": {
"header": "Mga setting",
"injiAsVerifierApp": "Inji bilang Verifier App",
"receiveCard": "Tumanggap ng Card",
"basicSettings": "Mga Pangunahing Setting",
"bioUnlock": "I-unlock gamit ang Biometrics",
"language": "Wika",
@@ -516,7 +517,11 @@
"getStarted": "Magsimula",
"unlockApp": "Buksan ang aplikasyon",
"failedToReadKeys": "Nabigong basahin ang mga susi",
"retryRead": "Gustong subukang muli?"
"retryRead": "Gustong subukang muli?",
"error": {
"decryptionFailed": "Nabigong i-decrypt ang data"
},
"ignore": "Huwag pansinin"
},
"SetupLanguage": {
"header": "Piliin ang Wika",
@@ -545,4 +550,4 @@
"copied": "Kinopya"
}
}
}
}

View File

@@ -126,6 +126,7 @@
"SettingScreen": {
"header": "समायोजन",
"injiAsVerifierApp": "सत्यापनकर्ता ऐप के रूप में इंजी",
"receiveCard": "कार्ड प्राप्त करें",
"basicSettings": "मूल सेटिंग्स",
"bioUnlock": "बायोमेट्रिक्स से अनलॉक करें",
"language": "भाषा",
@@ -509,7 +510,13 @@
"WelcomeScreen": {
"title": "ओपन सोर्स आइडेंटिटी सॉल्यूशन",
"getStarted": "आरंभ करें",
"unlockApp": "एप्लिकेशन अनलॉक करें"
"unlockApp": "एप्लिकेशन अनलॉक करें",
"failedToReadKeys": "कुंजियाँ पढ़ने में विफल",
"retryRead": "पुनः प्रयास करना चाहते हैं?",
"errors": {
"decryptionFailed": "डेटा डिक्रिप्ट करने में विफल"
},
"ignore": "अनदेखा करना"
},
"SetupLanguage": {
"header": "भाषा चुनें",
@@ -536,4 +543,4 @@
"copied": "कॉपी किया गया"
}
}
}
}

View File

@@ -125,6 +125,7 @@
"SettingScreen": {
"header": "ಸಂಯೋಜನೆಗಳು",
"injiAsVerifierApp": "ವೆರಿಫೈಯರ್ ಆಪ್ ಆಗಿ ಇಂಜಿ",
"receiveCard": "ಕಾರ್ಡ್ ಸ್ವೀಕರಿಸಿ",
"basicSettings": "ಮೂಲ ಸೆಟ್ಟಿಂಗ್‌ಗಳು",
"bioUnlock": "ಬಯೋಮೆಟ್ರಿಕ್ಸ್‌ನೊಂದಿಗೆ ಅನ್‌ಲಾಕ್ ಮಾಡಿ",
"language": "ಭಾಷೆ",
@@ -509,7 +510,11 @@
"getStarted": "ಪ್ರಾರಂಭಿಸಿ",
"unlockApp": "ಅಪ್ಲಿಕೇಶನ್ ಅನ್ಲಾಕ್ ಮಾಡಿ",
"failedToReadKeys": "ಕೀಗಳನ್ನು ಓದಲು ವಿಫಲವಾಗಿದೆ",
"retryRead": "ಮರುಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ?"
"retryRead": "ಮರುಪ್ರಯತ್ನಿಸಲು ಬಯಸುವಿರಾ?",
"errors": {
"decryptionFailed": "ಡೇಟಾವನ್ನು ಡೀಕ್ರಿಪ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"
},
"ignore": "ನಿರ್ಲಕ್ಷಿಸಿ"
},
"SetupLanguage": {
"header": "ಭಾಷೆಯನ್ನು ಆರಿಸಿ",

View File

@@ -125,6 +125,7 @@
"SettingScreen": {
"header": "அமைப்புகள்",
"injiAsVerifierApp": "சரிபார்ப்பு பயன்பாடாக இன்ஜி",
"receiveCard": "பெற்ற அட்டை",
"basicSettings": "அடிப்படை அமைப்புகள்",
"bioUnlock": "பயோமெட்ரிக்ஸ் மூலம் திறக்கவும்",
"language": "மொழி",
@@ -509,7 +510,11 @@
"getStarted": "தொடங்கு",
"unlockApp": "பயன்பாட்டைத் திற",
"failedToReadKeys": "விசைகளைப் படிக்க முடியவில்லை",
"retryRead": "மீண்டும் முயற்சிக்க வேண்டுமா?"
"retryRead": "மீண்டும் முயற்சிக்க வேண்டுமா?",
"errors": {
"decryptionFailed": "தரவை மறைகுறியாக்க முடியவில்லை"
},
"ignore": "புறக்கணிக்க"
},
"SetupLanguage": {
"header": "மொழியைத் தேர்ந்தெடுக்கவும்",

View File

@@ -32,13 +32,16 @@ const model = createModel(
info: {} as AppInfo,
backendInfo: {} as BackendInfo,
serviceRefs: {} as AppServices,
isReadError: false,
isReadError: true,
isDecryptError: false,
},
{
events: {
ACTIVE: () => ({}),
INACTIVE: () => ({}),
ERROR: () => ({}),
DECRYPT_ERROR: () => ({}),
DECRYPT_ERROR_DISMISS: () => ({}),
OFFLINE: () => ({}),
ONLINE: (networkType: NetInfoStateType) => ({ networkType }),
REQUEST_DEVICE_INFO: () => ({}),
@@ -52,6 +55,7 @@ const model = createModel(
export const appMachine = model.createMachine(
{
/** @xstate-layout N4IgpgJg5mDOIC5QEMAOqB0BLAdlgLhrPgPYBOYAxAEoCiAggCICaA2gAwC6ioqJsBLCRw8QAD0QBmdgE4MMgIwAmSaoDsADmkb2agDQgAnoiUAWJRnNqZayVvYKArDdMBfVwbSZcBIqQqUtNTUAPLUHNxIIHwC+EIiURIICpJypgBsaqaOSjmOqfmmBsbJjuzyaimaMpJq7BqOOe6e6Nh4hLBgZABuWADGcDQMLBGiMYLCokmZ6RiSSro5NQrsjcUm5pZK1rb2Ti7NIF5tvn0UEGA4ccgANtRgUFjEZIaUAMoAKmG0APp0bwAFEIAOTetFGUXGcUmiUQCgU6VMFW0tVkOXY6XWCCUCjkakqBNMMl0ZjcHiOrR8hFwADMSJR6ACAT8AJLAgBiIT+tAAwrQWQA1WiMCG8fgTBKgJIIjJzdRqRGmDQEjRYnF4gkKLLEtSkw7HKkYC69HB0ygAIXoPIA0rRgYxWRyuXQ+YLhaLouLoZLxCZlI55DjTJJ0jV0vlJGrcRh8VqtUSSaYyS1MBRkBBXnQAIoAVVonx+jFoApZfMdnI9UPiUxM9Rj6URGmJMh0Zg0mKMiEc6Q0GA0GmyPd180kyYpqbA6cMGDpfQArrAGTyPm7K17q7Dkroscre+l2KknAoB8qbPrWmmMzOSPPF2yrSuhWvYhupXDt52EDIbBhGnVJN27CyA2SjnhOU4YDgYD4AA7uQADWlAggAMmy4JcGM64wm+W76J+yhEpYaiOKYGL4jI+4hmBGCXtOUGwQhSHsuyqHAuhkRii+2G+rhWIpD2WwNNsuLdjI7jkjgJAXPAUReJhXE+kkAC0tRYkpZgYEBWnaTpajUVS8kSjW2IyFi6SSJYDS2FqjgaPCMi2fp7R+OQYCGd6xn4mqGKWKimimMoTaOLqTm+J0PT9HA7mvjx5gWeYChJmYEbth2JQLLMwZ1P5gUOSF5IGs5ZyQJc1x3A8Tz4C80XcUk1R9koLbpAiDghgoUZpNImgkSsGhmLUoXUqaJA1YpcJJrM4aVCkShaDI5hFJ+6q+bouz4tIqgaINRpgCadKjcZx7pBYDakZoo6OCkjgdSt1ihkmF1UQVF6ThmB2bvCZmqBgIGaPU5FONRtHXre704c4WK6goGCJQOs2rD2Ohic94FXrOC4YH0AAWYB9PBuBQGDPHwtDWoLDUtn1LN35YjUcgYhRiUNhiTbIymNGvdO6OwBgyB9HE3RuZCWFjdipE-YopE1O2f12DujQ-WR0jNUBl2OEDnMgxjuB8wLQucUZm5mOUoaJbIdiZDocufi4v7OA0KxKM1tRbSjHMQfRcFkPBRNJBD+GyBYDjfri4YtRkGse9BXvwZjON4wTvvvnhJQpLI8gBSsx2NAFdiR1ensIRgwg3Lg+uegpxkqBYo66ko9e5MoZh8fXmWaA3CymPiTRu8Dhfe8XNI0qXUFJ9i8xzF3HeN-Xi2pxdvkpOYx31M16Tia4QA */
predictableActionArguments: true,
preserveActionOrder: true,
tsTypes: {} as import('./app.typegen').Typegen0,
@@ -61,6 +65,14 @@ export const appMachine = model.createMachine(
},
id: 'app',
initial: 'init',
on: {
DECRYPT_ERROR: {
actions: ['setIsDecryptError'],
},
DECRYPT_ERROR_DISMISS: {
actions: ['unsetIsDecryptError'],
},
},
states: {
init: {
initial: 'store',
@@ -69,7 +81,7 @@ export const appMachine = model.createMachine(
entry: ['spawnStoreActor', 'logStoreEvents'],
on: {
READY: {
actions: 'unsetIsReadError',
actions: ['unsetIsReadError', 'unsetIsDecryptError'],
target: 'services',
},
ERROR: {
@@ -177,6 +189,12 @@ export const appMachine = model.createMachine(
setIsReadError: assign({
isReadError: true,
}),
setIsDecryptError: assign({
isDecryptError: true,
}),
unsetIsDecryptError: assign({
isDecryptError: false,
}),
unsetIsReadError: assign({
isReadError: false,
}),
@@ -423,3 +441,7 @@ export function logState(state: AnyState) {
export function selectIsReadError(state: State) {
return state.context.isReadError;
}
export function selectIsDecryptError(state: State) {
return state.context.isDecryptError;
}

View File

@@ -26,9 +26,11 @@ export interface Typegen0 {
requestDeviceInfo: 'REQUEST_DEVICE_INFO';
setAppInfo: 'APP_INFO_RECEIVED';
setBackendInfo: 'BACKEND_INFO_RECEIVED';
setIsDecryptError: 'DECRYPT_ERROR';
setIsReadError: 'ERROR';
spawnServiceActors: 'READY';
spawnStoreActor: 'xstate.init';
unsetIsDecryptError: 'DECRYPT_ERROR_DISMISS' | 'READY';
unsetIsReadError: 'READY';
};
'eventsCausingDelays': {};

View File

@@ -96,6 +96,7 @@ const model = createModel(
RETRY_VERIFICATION: () => ({}),
VP_CREATED: (vp: VerifiablePresentation) => ({ vp }),
TOGGLE_USER_CONSENT: () => ({}),
RESET: () => ({}),
},
}
);
@@ -125,7 +126,7 @@ export const scanMachine =
initial: 'inactive',
on: {
SCREEN_BLUR: {
target: '.inactive',
target: '#scan.disconnectDevice',
},
SCREEN_FOCUS: {
target: '.checkStorage',
@@ -134,11 +135,24 @@ export const scanMachine =
target: '.handlingBleError',
actions: 'setBleError',
},
RESET: {
target: '.checkStorage',
},
},
states: {
inactive: {
entry: 'removeLoggers',
},
disconnectDevice: {
invoke: {
src: 'disconnect',
},
on: {
DISCONNECT: {
target: '#scan.inactive',
},
},
},
checkStorage: {
invoke: {
src: 'checkStorageAvailability',

View File

@@ -30,6 +30,7 @@ const model = createModel(
TRY_AGAIN: () => ({}),
IGNORE: () => ({}),
GET: (key: string) => ({ key }),
DECRYPT_ERROR: () => ({}),
SET: (key: string, value: unknown) => ({ key, value }),
APPEND: (key: string, value: unknown) => ({ key, value }),
PREPEND: (key: string, value: unknown) => ({ key, value }),
@@ -76,7 +77,7 @@ export const storeMachine =
},
on: {
KEY_RECEIVED: {
actions: 'setEncryptionKey',
actions: ['setEncryptionKey', 'logKey'],
target: 'ready',
},
ERROR: {
@@ -190,6 +191,9 @@ export const storeMachine =
sendUpdate(),
],
},
DECRYPT_ERROR: {
actions: sendParent('DECRYPT_ERROR'),
},
TAMPERED_VC: {
actions: ['setIsTamperedVc'],
},
@@ -230,10 +234,15 @@ export const storeMachine =
checkStorageInitialisedOrNot: () => async (callback) => {
const isDirectoryExist = await Storage.isVCStorageInitialised();
if (!isDirectoryExist) {
// clear the storage
callback(model.events.READY());
} else {
callback(model.events.ERROR(new Error('show the popup for retry')));
callback(
model.events.ERROR(
new Error(
'vc directory exists and decryption key is not available'
)
)
);
}
},
@@ -322,6 +331,12 @@ export const storeMachine =
} catch (e) {
if (e.message === 'Data is tampered') {
callback(model.events.TAMPERED_VC());
} else if (
e.message.includes('JSON') ||
e.message.includes('decrypt')
) {
callback(model.events.DECRYPT_ERROR());
sendUpdate();
} else {
console.error(e);
callback(model.events.STORE_ERROR(e, event.requester));

View File

@@ -0,0 +1,49 @@
// This file was automatically generated. Edits will be overwritten
export interface Typegen0 {
'@@xstate/typegen': true;
internalEvents: {
"done.invoke._store": { type: "done.invoke._store"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"done.invoke.store.resettingStorage:invocation[0]": { type: "done.invoke.store.resettingStorage:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." };
"error.platform._store": { type: "error.platform._store"; data: unknown };
"xstate.init": { type: "xstate.init" };
};
invokeSrcNameMap: {
"checkStorageInitialisedOrNot": "done.invoke.store.checkStorageInitialisation:invocation[0]";
"clear": "done.invoke.store.resettingStorage:invocation[0]";
"generateEncryptionKey": "done.invoke.store.generatingEncryptionKey:invocation[0]";
"getEncryptionKey": "done.invoke.store.gettingEncryptionKey:invocation[0]";
"store": "done.invoke._store";
};
missingImplementations: {
actions: "logKey";
delays: never;
guards: never;
services: never;
};
eventsCausingActions: {
"forwardStoreRequest": "APPEND" | "CLEAR" | "GET" | "PREPEND" | "REMOVE" | "REMOVE_ITEMS" | "REMOVE_VC_METADATA" | "SET" | "UPDATE";
"logKey": "KEY_RECEIVED";
"notifyParent": "KEY_RECEIVED" | "done.invoke.store.resettingStorage:invocation[0]";
"resetIsTamperedVc": "RESET_IS_TAMPERED";
"setEncryptionKey": "KEY_RECEIVED";
"setIsTamperedVc": "TAMPERED_VC";
};
eventsCausingDelays: {
};
eventsCausingGuards: {
};
eventsCausingServices: {
"checkStorageInitialisedOrNot": "ERROR";
"clear": "KEY_RECEIVED";
"generateEncryptionKey": "IGNORE" | "READY";
"getEncryptionKey": "TRY_AGAIN" | "xstate.init";
"store": "KEY_RECEIVED" | "done.invoke.store.resettingStorage:invocation[0]";
};
matchesStates: "checkStorageInitialisation" | "failedReadingKey" | "generatingEncryptionKey" | "gettingEncryptionKey" | "ready" | "resettingStorage";
tags: never;
}

View File

@@ -360,7 +360,10 @@ export const vcItemMachine =
],
onError: [
{
actions: 'setWalletBindingError',
actions: [
'setWalletBindingError',
'logWalletBindingFailure',
],
target: '#vc-item.kebabPopUp.showingWalletBindingError',
},
],
@@ -1354,7 +1357,10 @@ export function selectAcceptingBindingOtp(state: State) {
}
export function selectShowWalletBindingError(state: State) {
return state.matches('showingWalletBindingError');
return (
state.matches('showingWalletBindingError') ||
state.matches('kebabPopUp.showingWalletBindingError')
);
}
export function selectWalletBindingInProgress(state: State) {

View File

@@ -193,6 +193,7 @@ export interface Typegen0 {
logWalletBindingFailure:
| 'error.platform.vc-item.addKeyPair:invocation[0]'
| 'error.platform.vc-item.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item.kebabPopUp.addingWalletBindingId:invocation[0]'
| 'error.platform.vc-item.requestingBindingOtp:invocation[0]'
| 'error.platform.vc-item.updatingPrivateKey:invocation[0]';
logWalletBindingSuccess:

View File

@@ -11,6 +11,8 @@ import { MainLayout } from '../screens/MainLayout';
import { NotificationsScreen } from '../screens/NotificationsScreen';
import { SetupLanguageScreen } from '../screens/SetupLanguageScreen';
import { IntroSlidersScreen } from '../screens/Home/IntroSlidersScreen';
import { RequestLayout } from '../screens/Request/RequestLayout';
import { RequestStackParamList } from '../screens/Request/RequestLayoutController';
export const baseRoutes: Screen[] = [
{
@@ -40,6 +42,13 @@ export const baseRoutes: Screen[] = [
name: 'Biometric',
component: BiometricScreen,
},
{
name: 'Request',
component: RequestLayout,
options: {
headerShown: false,
},
},
];
export const authRoutes: Screen[] = [
@@ -89,3 +98,8 @@ export type BiometricRouteProps = NativeStackScreenProps<
RootStackParamList,
'Biometric'
>;
export type RequestRouteProps = NativeStackScreenProps<
RequestStackParamList,
'Request'
>;

View File

@@ -6,11 +6,9 @@ import {
import { Image } from 'react-native';
import { HomeScreen } from '../screens/Home/HomeScreen';
import { RootStackParamList } from './index';
import { RequestLayout } from '../screens/Request/RequestLayout';
import { ScanLayout } from '../screens/Scan/ScanLayout';
import { HistoryScreen } from '../screens/History/HistoryScreen';
import i18n from '../i18n';
import { Platform } from 'react-native';
const home: TabScreen = {
name: 'Home',
@@ -25,7 +23,7 @@ const home: TabScreen = {
}),
},
};
const scan: TabScreen = {
export const scan: TabScreen = {
name: 'Scan',
component: ScanLayout,
icon: 'qr-code-scanner',
@@ -34,15 +32,6 @@ const scan: TabScreen = {
headerShown: false,
},
};
const request: TabScreen = {
name: 'Request',
component: RequestLayout,
icon: 'file-download',
options: {
title: i18n.t('MainLayout:request'),
headerShown: false,
},
};
const history: TabScreen = {
name: 'History',
component: HistoryScreen,
@@ -56,11 +45,6 @@ const history: TabScreen = {
export const mainRoutes: TabScreen[] = [];
mainRoutes.push(home);
mainRoutes.push(scan);
if (Platform.OS !== 'ios') {
mainRoutes.push(request);
}
mainRoutes.push(history);
export type MainBottomTabParamList = {
@@ -68,7 +52,6 @@ export type MainBottomTabParamList = {
activeTab: number;
};
Scan: undefined;
Request: undefined;
History: undefined;
};

View File

@@ -5,8 +5,8 @@ import { StoreEvents } from '../machines/store';
export function useApp() {
const { appService } = useContext(GlobalContext);
const storeService = appService.children.get('store');
return {
ignoreDecrypt: () => appService.send('DECRYPT_ERROR_DISMISS'),
IGNORE: () => storeService.send(StoreEvents.IGNORE()),
TRY_AGAIN: () => storeService.send(StoreEvents.TRY_AGAIN()),
};

View File

@@ -9,7 +9,10 @@ import { GetVcModal } from './MyVcs/GetVcModal';
import { useTranslation } from 'react-i18next';
import { VcItem } from '../../components/VcItem';
import { GET_INDIVIDUAL_ID } from '../../shared/constants';
import { ErrorMessageOverlay } from '../../components/MessageOverlay';
import {
ErrorMessageOverlay,
MessageOverlay,
} from '../../components/MessageOverlay';
import { Icon } from 'react-native-elements';
export const MyVcsTab: React.FC<HomeScreenTabProps> = (props) => {
@@ -102,7 +105,6 @@ export const MyVcsTab: React.FC<HomeScreenTabProps> = (props) => {
</Column>
<Button
type="gradient"
isVcThere
disabled={controller.isRefreshingVcs}
title={t('downloadCard')}
onPress={controller.DOWNLOAD_ID}
@@ -152,6 +154,11 @@ export const MyVcsTab: React.FC<HomeScreenTabProps> = (props) => {
error={storeErrorTranslationPath}
onDismiss={controller.DISMISS}
/>
<MessageOverlay
isVisible={controller.isBindingError}
title={controller.walletBindingError}
onCancel={controller.DISMISS}
/>
<ErrorMessageOverlay
translationPath={'MyVcsTab'}
isVisible={controller.isMinimumStorageLimitReached}

View File

@@ -7,6 +7,10 @@ import {
selectMyVcs,
VcEvents,
} from '../../machines/vc';
import {
selectWalletBindingError,
selectShowWalletBindingError,
} from '../../machines/vcItem';
import { vcItemMachine } from '../../machines/vcItem';
import { GlobalContext } from '../../shared/GlobalContext';
import { HomeScreenTabProps } from './HomeScreen';
@@ -39,6 +43,8 @@ export function useMyVcsTab(props: HomeScreenTabProps) {
isRequestSuccessful: useSelector(service, selectIsRequestSuccessful),
isOnboarding: useSelector(service, selectIsOnboarding),
isSavingFailedInIdle: useSelector(service, selectIsSavingFailedInIdle),
walletBindingError: useSelector(service, selectWalletBindingError),
isBindingError: useSelector(service, selectShowWalletBindingError),
isMinimumStorageLimitReached: useSelector(
service,
selectIsMinimumStorageLimitReached

View File

@@ -45,12 +45,6 @@ export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
isBindingPending={controller.isWalletBindingPending}
activeTab={props.activeTab}
/>
{controller.walletBindingError !== '' && (
<Text style={{ color: 'red', fontSize: 20 }}>
Error Occured : {controller.walletBindingError}
</Text>
)}
</Column>
</Column>
{controller.isEditingTag && (

View File

@@ -1,11 +1,11 @@
import React from 'react';
import React, { useContext } from 'react';
import {
BottomTabNavigationOptions,
createBottomTabNavigator,
} from '@react-navigation/bottom-tabs';
import { Icon } from 'react-native-elements';
import { mainRoutes } from '../routes/main';
import { RootRouteProps } from '../routes';
import { RequestRouteProps, RootRouteProps } from '../routes';
import { mainRoutes, scan } from '../routes/main';
import { Theme } from '../components/ui/styleUtils';
import { useTranslation } from 'react-i18next';
import { Row } from '../components/ui';
@@ -13,10 +13,16 @@ import { Image } from 'react-native';
import { SettingScreen } from './Settings/SettingScreen';
import { HelpScreen } from '../components/HelpScreen';
import { GlobalContext } from '../shared/GlobalContext';
import { ScanEvents } from '../machines/bleShare/scan/scanMachine';
const { Navigator, Screen } = createBottomTabNavigator();
export const MainLayout: React.FC<RootRouteProps> = (props) => {
export const MainLayout: React.FC<RootRouteProps & RequestRouteProps> = (
props
) => {
const { t } = useTranslation('MainLayout');
const { appService } = useContext(GlobalContext);
const scanService = appService.children.get('scan');
const options: BottomTabNavigationOptions = {
headerRight: () => (
@@ -50,7 +56,7 @@ export const MainLayout: React.FC<RootRouteProps> = (props) => {
headerTitleStyle: {
fontFamily: 'Inter_600SemiBold',
fontSize: 30,
margin: 8,
margin: 4,
},
headerRightContainerStyle: { paddingEnd: 13 },
headerLeftContainerStyle: { paddingEnd: 13 },
@@ -77,6 +83,13 @@ export const MainLayout: React.FC<RootRouteProps> = (props) => {
key={route.name}
name={route.name}
component={route.component}
listeners={{
tabPress: (e) => {
if (route.name == scan.name) {
scanService.send(ScanEvents.RESET());
}
},
}}
options={{
...route.options,
title: t(route.name),

View File

@@ -49,7 +49,7 @@ export const RequestLayout: React.FC = () => {
name="RequestScreen"
component={RequestScreen}
options={{
title: t('request').toUpperCase(),
title: t('receiveCard').toUpperCase(),
}}
/>
</RequestStack.Navigator>

View File

@@ -20,7 +20,8 @@ import {
} from '../../machines/bleShare/commonSelectors';
import { RequestEvents } from '../../machines/bleShare/request/requestMachine';
type RequestStackParamList = {
export type RequestStackParamList = {
Request: undefined;
RequestScreen: undefined;
ReceiveVcScreen: undefined;
};

View File

@@ -86,7 +86,9 @@ export const AboutInji: React.FC<AboutInjiProps> = ({ appId }) => {
</Text>
<TouchableOpacity
activeOpacity={1}
onPress={() => Linking.openURL(aboutInjiUrl)}>
onPress={() => {
aboutInjiUrl && Linking.openURL(aboutInjiUrl);
}}>
<Text color={Theme.Colors.AddIdBtnBg} weight="bold">
{t('clickHere')}
</Text>

View File

@@ -0,0 +1,77 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { RefreshControl } from 'react-native';
import { Pressable, TouchableOpacity } from 'react-native';
import { Centered, Column, Row, Text } from '../../components/ui';
import { Icon } from 'react-native-elements';
import { Theme } from '../../components/ui/styleUtils';
import { Image } from 'react-native';
import { Modal } from '../../components/ui/Modal';
import { HomeScreenTabProps } from '../Home/HomeScreen';
import { useReceivedVcsTab } from '../Home/ReceivedVcsTabController';
import { VcItem } from '../../components/VcItem';
export const ReceivedCards: React.FC<HomeScreenTabProps> = (props) => {
const { t } = useTranslation('ReceivedVcsTab');
const controller = useReceivedVcsTab(props);
return (
<React.Fragment>
<Pressable onPress={controller.TOGGLE_RECEIVED_CARDS}>
<Column style={Theme.Styles.receiveCardsContainer}>
<Image
source={Theme.ReceivedCardsIcon}
style={{ marginLeft: 10, marginRight: 9 }}
/>
<Text margin="6" weight="semibold">
{t('receivedCards')}
</Text>
</Column>
</Pressable>
<Modal
isVisible={controller.isVisible}
arrowLeft={<Icon name={''} />}
headerTitle={t('header')}
headerElevation={2}
onDismiss={controller.TOGGLE_RECEIVED_CARDS}>
<Column
scroll
pX={15}
refreshControl={
<RefreshControl
refreshing={controller.isRefreshingVcs}
onRefresh={controller.REFRESH}
/>
}>
{controller.vcKeys.map((vcKey) => (
<VcItem
key={vcKey}
vcKey={vcKey}
margin="0 2 8 2"
isSharingVc
onPress={controller.VIEW_VC}
/>
))}
{controller.vcKeys.length === 0 && (
<React.Fragment>
<Centered fill>
<Icon
style={{ marginBottom: 20 }}
size={40}
name="sentiment-dissatisfied"
/>
<Text align="center" weight="semibold" margin="0 0 4 0">
{t('noReceivedVcsTitle')}
</Text>
<Text align="center" color={Theme.Colors.textLabel}>
{t('noReceivedVcsText')}
</Text>
</Centered>
</React.Fragment>
)}
</Column>
</Modal>
</React.Fragment>
);
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Platform, Pressable, View } from 'react-native';
import { Platform, Pressable, View, Image } from 'react-native';
import { Icon, ListItem, Switch } from 'react-native-elements';
import { Column, Text } from '../../components/ui';
import { Column, Row, Text } from '../../components/ui';
import { Theme } from '../../components/ui/styleUtils';
import { MessageOverlay } from '../../components/MessageOverlay';
@@ -13,7 +13,8 @@ import { Modal } from '../../components/ui/Modal';
import { CREDENTIAL_REGISTRY_EDIT } from 'react-native-dotenv';
import { AboutInji } from './AboutInji';
import { EditableListItem } from '../../components/EditableListItem';
import { RootRouteProps } from '../../routes';
import { RequestRouteProps } from '../../routes';
import { ReceivedCards } from './ReceivedCards';
const LanguageSetting: React.FC = () => {
const { t } = useTranslation('SettingScreen');
@@ -46,7 +47,7 @@ const LanguageSetting: React.FC = () => {
);
};
export const SettingScreen: React.FC<SettingProps & RootRouteProps> = (
export const SettingScreen: React.FC<SettingProps & RequestRouteProps> = (
props
) => {
const { t } = useTranslation('SettingScreen');
@@ -63,8 +64,43 @@ export const SettingScreen: React.FC<SettingProps & RootRouteProps> = (
headerTitle={t('header')}
headerElevation={2}
onDismiss={controller.TOGGLE_SETTINGS}>
<ScrollView>
<Column fill backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
<ScrollView backgroundColor={Theme.Colors.lightGreyBackgroundColor}>
<Column style={{ display: Platform.OS !== 'ios' ? 'flex' : 'none' }}>
<Text
weight="semibold"
margin="10"
color={Theme.Colors.aboutVersion}>
{t('injiAsVerifierApp')}
</Text>
<Row
align="space-evenly"
backgroundColor={Theme.Colors.whiteBackgroundColor}>
<Pressable onPress={controller.RECEIVE_CARD}>
<Column style={Theme.Styles.receiveCardsContainer}>
<Image
source={Theme.ReceiveCardIcon}
style={{ alignSelf: 'center' }}
/>
<Text margin="6" weight="semibold">
{t('receiveCard')}
</Text>
</Column>
</Pressable>
<ReceivedCards
isVisible={false}
service={undefined}
vcItemActor={undefined}
/>
</Row>
<Text
weight="semibold"
margin="10"
color={Theme.Colors.aboutVersion}>
{t('basicSettings')}
</Text>
</Column>
<Column fill>
<MessageOverlay
isVisible={controller.alertMsg != ''}
onBackdropPress={controller.hideAlert}

View File

@@ -26,10 +26,10 @@ import {
} from '../../machines/biometrics';
import { GlobalContext } from '../../shared/GlobalContext';
import { useTranslation } from 'react-i18next';
import { RootRouteProps } from '../../routes';
import { Platform } from 'react-native';
import { RequestRouteProps } from '../../routes';
export function useSettingsScreen(props: RootRouteProps) {
export function useSettingsScreen(props: RequestRouteProps) {
const { appService } = useContext(GlobalContext);
const authService = appService.children.get('auth');
const settingsService = appService.children.get('settings');
@@ -138,6 +138,11 @@ export function useSettingsScreen(props: RootRouteProps) {
)
),
RECEIVE_CARD: () => {
props.navigation.navigate('Request');
setIsVisible(false);
},
TOGGLE_BIOMETRIC: (enable: boolean) =>
settingsService.send(SettingsEvents.TOGGLE_BIOMETRIC_UNLOCK(enable)),
@@ -145,7 +150,6 @@ export function useSettingsScreen(props: RootRouteProps) {
setIsVisible(false);
const navigate = () => {
authService.send(AuthEvents.LOGOUT());
props.navigation.navigate('Welcome');
};
if (Platform.OS === 'ios') {

View File

@@ -9,7 +9,6 @@ import { useWelcomeScreen } from './WelcomeScreenController';
export const WelcomeScreen: React.FC<RootRouteProps> = (props) => {
const { t } = useTranslation('WelcomeScreen');
const controller = useWelcomeScreen(props);
return (
<Column
fill