mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 21:48:04 -05:00
* 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>
448 lines
13 KiB
TypeScript
448 lines
13 KiB
TypeScript
import NetInfo, { NetInfoStateType } from '@react-native-community/netinfo';
|
|
import { AppState, AppStateStatus, Platform } from 'react-native';
|
|
import {
|
|
getDeviceId,
|
|
getDeviceName,
|
|
getDeviceNameSync,
|
|
} from 'react-native-device-info';
|
|
import { EventFrom, spawn, StateFrom, send, assign, AnyState } from 'xstate';
|
|
import { createModel } from 'xstate/lib/model';
|
|
import { authMachine, createAuthMachine } from './auth';
|
|
import { createSettingsMachine, settingsMachine } from './settings';
|
|
import { StoreEvents, storeMachine } from './store';
|
|
import { createVcMachine, vcMachine } from './vc';
|
|
import { createActivityLogMachine, activityLogMachine } from './activityLog';
|
|
import {
|
|
createRequestMachine,
|
|
requestMachine,
|
|
} from './bleShare/request/requestMachine';
|
|
import { createScanMachine, scanMachine } from './bleShare/scan/scanMachine';
|
|
import { createRevokeMachine, revokeVidsMachine } from './revoke';
|
|
import { pure, respond } from 'xstate/lib/actions';
|
|
import { AppServices } from '../shared/GlobalContext';
|
|
import { request } from '../shared/request';
|
|
import {
|
|
changeCrendetialRegistry,
|
|
SETTINGS_STORE_KEY,
|
|
} from '../shared/constants';
|
|
import { MIMOTO_HOST } from 'react-native-dotenv';
|
|
|
|
const model = createModel(
|
|
{
|
|
info: {} as AppInfo,
|
|
backendInfo: {} as BackendInfo,
|
|
serviceRefs: {} as AppServices,
|
|
isReadError: true,
|
|
isDecryptError: false,
|
|
},
|
|
{
|
|
events: {
|
|
ACTIVE: () => ({}),
|
|
INACTIVE: () => ({}),
|
|
ERROR: () => ({}),
|
|
DECRYPT_ERROR: () => ({}),
|
|
DECRYPT_ERROR_DISMISS: () => ({}),
|
|
OFFLINE: () => ({}),
|
|
ONLINE: (networkType: NetInfoStateType) => ({ networkType }),
|
|
REQUEST_DEVICE_INFO: () => ({}),
|
|
READY: (data?: unknown) => ({ data }),
|
|
APP_INFO_RECEIVED: (info: AppInfo) => ({ info }),
|
|
BACKEND_INFO_RECEIVED: (info: BackendInfo) => ({ info }),
|
|
STORE_RESPONSE: (response: unknown) => ({ response }),
|
|
},
|
|
}
|
|
);
|
|
|
|
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,
|
|
schema: {
|
|
context: model.initialContext,
|
|
events: {} as EventFrom<typeof model>,
|
|
},
|
|
id: 'app',
|
|
initial: 'init',
|
|
on: {
|
|
DECRYPT_ERROR: {
|
|
actions: ['setIsDecryptError'],
|
|
},
|
|
DECRYPT_ERROR_DISMISS: {
|
|
actions: ['unsetIsDecryptError'],
|
|
},
|
|
},
|
|
states: {
|
|
init: {
|
|
initial: 'store',
|
|
states: {
|
|
store: {
|
|
entry: ['spawnStoreActor', 'logStoreEvents'],
|
|
on: {
|
|
READY: {
|
|
actions: ['unsetIsReadError', 'unsetIsDecryptError'],
|
|
target: 'services',
|
|
},
|
|
ERROR: {
|
|
actions: 'setIsReadError',
|
|
},
|
|
},
|
|
},
|
|
services: {
|
|
entry: ['spawnServiceActors', 'logServiceEvents'],
|
|
on: {
|
|
READY: 'credentialRegistry',
|
|
},
|
|
},
|
|
credentialRegistry: {
|
|
entry: ['loadCredentialRegistryHostFromStorage'],
|
|
on: {
|
|
STORE_RESPONSE: {
|
|
actions: ['loadCredentialRegistryInConstants'],
|
|
target: 'info',
|
|
},
|
|
},
|
|
},
|
|
info: {
|
|
invoke: {
|
|
src: 'getAppInfo',
|
|
},
|
|
on: {
|
|
APP_INFO_RECEIVED: {
|
|
target: 'devinfo',
|
|
actions: ['setAppInfo'],
|
|
},
|
|
},
|
|
},
|
|
devinfo: {
|
|
invoke: {
|
|
src: 'getBackendInfo',
|
|
},
|
|
on: {
|
|
BACKEND_INFO_RECEIVED: {
|
|
target: '#ready',
|
|
actions: ['setBackendInfo'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ready: {
|
|
id: 'ready',
|
|
type: 'parallel',
|
|
on: {
|
|
REQUEST_DEVICE_INFO: {
|
|
actions: ['requestDeviceInfo'],
|
|
},
|
|
},
|
|
states: {
|
|
focus: {
|
|
invoke: {
|
|
src: 'checkFocusState',
|
|
},
|
|
on: {
|
|
ACTIVE: '.active',
|
|
INACTIVE: '.inactive',
|
|
},
|
|
initial: 'checking',
|
|
states: {
|
|
checking: {},
|
|
active: {
|
|
entry: ['forwardToServices'],
|
|
},
|
|
inactive: {
|
|
entry: ['forwardToServices'],
|
|
},
|
|
},
|
|
},
|
|
network: {
|
|
invoke: {
|
|
src: 'checkNetworkState',
|
|
},
|
|
on: {
|
|
ONLINE: '.online',
|
|
OFFLINE: '.offline',
|
|
},
|
|
initial: 'checking',
|
|
states: {
|
|
checking: {},
|
|
online: {
|
|
entry: ['forwardToServices'],
|
|
},
|
|
offline: {
|
|
entry: ['forwardToServices'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
actions: {
|
|
forwardToServices: pure((context, event) =>
|
|
Object.values(context.serviceRefs).map((serviceRef) =>
|
|
send({ ...event, type: `APP_${event.type}` }, { to: serviceRef })
|
|
)
|
|
),
|
|
setIsReadError: assign({
|
|
isReadError: true,
|
|
}),
|
|
setIsDecryptError: assign({
|
|
isDecryptError: true,
|
|
}),
|
|
unsetIsDecryptError: assign({
|
|
isDecryptError: false,
|
|
}),
|
|
unsetIsReadError: assign({
|
|
isReadError: false,
|
|
}),
|
|
requestDeviceInfo: respond((context) => ({
|
|
type: 'RECEIVE_DEVICE_INFO',
|
|
info: {
|
|
...context.info,
|
|
name: context.serviceRefs.settings.getSnapshot().context.name,
|
|
},
|
|
})),
|
|
|
|
spawnStoreActor: assign({
|
|
serviceRefs: (context) => ({
|
|
...context.serviceRefs,
|
|
store: spawn(storeMachine, storeMachine.id),
|
|
}),
|
|
}),
|
|
|
|
logStoreEvents: (context) => {
|
|
if (__DEV__) {
|
|
context.serviceRefs.store.subscribe(logState);
|
|
}
|
|
},
|
|
|
|
spawnServiceActors: model.assign({
|
|
serviceRefs: (context) => {
|
|
const serviceRefs = {
|
|
...context.serviceRefs,
|
|
};
|
|
|
|
serviceRefs.auth = spawn(
|
|
createAuthMachine(serviceRefs),
|
|
authMachine.id
|
|
);
|
|
|
|
serviceRefs.vc = spawn(createVcMachine(serviceRefs), vcMachine.id);
|
|
|
|
serviceRefs.settings = spawn(
|
|
createSettingsMachine(serviceRefs),
|
|
settingsMachine.id
|
|
);
|
|
|
|
serviceRefs.activityLog = spawn(
|
|
createActivityLogMachine(serviceRefs),
|
|
activityLogMachine.id
|
|
);
|
|
|
|
serviceRefs.scan = spawn(
|
|
createScanMachine(serviceRefs),
|
|
scanMachine.id
|
|
);
|
|
|
|
if (Platform.OS === 'android') {
|
|
serviceRefs.request = spawn(
|
|
createRequestMachine(serviceRefs),
|
|
requestMachine.id
|
|
);
|
|
}
|
|
|
|
serviceRefs.revoke = spawn(
|
|
createRevokeMachine(serviceRefs),
|
|
revokeVidsMachine.id
|
|
);
|
|
|
|
return serviceRefs;
|
|
},
|
|
}),
|
|
|
|
logServiceEvents: (context) => {
|
|
if (__DEV__) {
|
|
context.serviceRefs.auth.subscribe(logState);
|
|
context.serviceRefs.vc.subscribe(logState);
|
|
context.serviceRefs.settings.subscribe(logState);
|
|
context.serviceRefs.activityLog.subscribe(logState);
|
|
context.serviceRefs.scan.subscribe(logState);
|
|
|
|
if (Platform.OS === 'android') {
|
|
context.serviceRefs.request.subscribe(logState);
|
|
}
|
|
|
|
context.serviceRefs.revoke.subscribe(logState);
|
|
}
|
|
},
|
|
|
|
setAppInfo: model.assign({
|
|
info: (_, event) => event.info,
|
|
}),
|
|
|
|
setBackendInfo: model.assign({
|
|
backendInfo: (_, event) => event.info,
|
|
}),
|
|
|
|
loadCredentialRegistryHostFromStorage: send(
|
|
StoreEvents.GET(SETTINGS_STORE_KEY),
|
|
{
|
|
to: (context) => context.serviceRefs.store,
|
|
}
|
|
),
|
|
|
|
loadCredentialRegistryInConstants: (_context, event) => {
|
|
changeCrendetialRegistry(
|
|
!event.response?.credentialRegistry
|
|
? MIMOTO_HOST
|
|
: event.response?.credentialRegistry
|
|
);
|
|
},
|
|
},
|
|
|
|
services: {
|
|
getAppInfo: () => async (callback) => {
|
|
const appInfo = {
|
|
deviceId: getDeviceId(),
|
|
deviceName: await getDeviceName(),
|
|
};
|
|
callback(model.events.APP_INFO_RECEIVED(appInfo));
|
|
},
|
|
|
|
getBackendInfo: () => async (callback) => {
|
|
let backendInfo = {
|
|
application: {
|
|
name: '',
|
|
version: '',
|
|
},
|
|
build: {},
|
|
config: {},
|
|
};
|
|
try {
|
|
backendInfo = await request('GET', '/residentmobileapp/info');
|
|
callback(model.events.BACKEND_INFO_RECEIVED(backendInfo));
|
|
} catch {
|
|
callback(model.events.BACKEND_INFO_RECEIVED(backendInfo));
|
|
}
|
|
},
|
|
|
|
checkFocusState: () => (callback) => {
|
|
const changeHandler = (newState: AppStateStatus) => {
|
|
switch (newState) {
|
|
case 'background':
|
|
case 'inactive':
|
|
callback({ type: 'INACTIVE' });
|
|
break;
|
|
case 'active':
|
|
callback({ type: 'ACTIVE' });
|
|
break;
|
|
}
|
|
};
|
|
|
|
const blurHandler = () => callback({ type: 'INACTIVE' });
|
|
const focusHandler = () => callback({ type: 'ACTIVE' });
|
|
|
|
AppState.addEventListener('change', changeHandler);
|
|
|
|
// android only
|
|
if (Platform.OS === 'android') {
|
|
AppState.addEventListener('blur', blurHandler);
|
|
AppState.addEventListener('focus', focusHandler);
|
|
}
|
|
|
|
return () => {
|
|
AppState.removeEventListener('change', changeHandler);
|
|
|
|
if (Platform.OS === 'android') {
|
|
AppState.removeEventListener('blur', blurHandler);
|
|
AppState.removeEventListener('focus', focusHandler);
|
|
}
|
|
};
|
|
},
|
|
|
|
checkNetworkState: () => (callback) => {
|
|
return NetInfo.addEventListener((state) => {
|
|
if (state.isConnected) {
|
|
callback({ type: 'ONLINE', networkType: state.type });
|
|
} else {
|
|
callback({ type: 'OFFLINE' });
|
|
}
|
|
});
|
|
},
|
|
},
|
|
}
|
|
);
|
|
|
|
interface AppInfo {
|
|
deviceId: string;
|
|
deviceName: string;
|
|
}
|
|
|
|
interface BackendInfo {
|
|
application: {
|
|
name: string;
|
|
version: string;
|
|
};
|
|
build: object;
|
|
config: object;
|
|
}
|
|
|
|
type State = StateFrom<typeof appMachine>;
|
|
|
|
export function selectAppInfo(state: State) {
|
|
return state.context.info;
|
|
}
|
|
|
|
export function selectBackendInfo(state: State) {
|
|
return state.context.backendInfo;
|
|
}
|
|
|
|
export function selectIsReady(state: State) {
|
|
return state.matches('ready');
|
|
}
|
|
|
|
export function selectIsOnline(state: State) {
|
|
return state.matches('ready.network.online');
|
|
}
|
|
|
|
export function selectIsActive(state: State) {
|
|
return state.matches('ready.focus.active');
|
|
}
|
|
|
|
export function selectIsFocused(state: State) {
|
|
return state.matches('ready.focus');
|
|
}
|
|
|
|
export function logState(state: AnyState) {
|
|
const data = JSON.stringify(
|
|
state.event,
|
|
(key, value) => {
|
|
if (key === 'type') return undefined;
|
|
if (typeof value === 'string' && value.length >= 100) {
|
|
return value.slice(0, 100) + '...';
|
|
}
|
|
return value;
|
|
},
|
|
2
|
|
);
|
|
console.log(
|
|
`[${getDeviceNameSync()}] ${state.machine.id}: ${
|
|
state.event.type
|
|
} -> ${state.toStrings().pop()}\n${
|
|
data.length > 300 ? data.slice(0, 300) + '...' : data
|
|
}
|
|
`
|
|
);
|
|
}
|
|
|
|
export function selectIsReadError(state: State) {
|
|
return state.context.isReadError;
|
|
}
|
|
|
|
export function selectIsDecryptError(state: State) {
|
|
return state.context.isDecryptError;
|
|
}
|