mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 05:27:57 -05:00
updated
This commit is contained in:
@@ -5,7 +5,7 @@ import { VC, CredentialSubject } from '../types/vc';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Colors } from './ui/styleUtils';
|
||||
|
||||
export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
export const VcDetails: React.FC<VcDetailsProps> = (props) => {
|
||||
return (
|
||||
<Column>
|
||||
<Row padding="16 24">
|
||||
@@ -14,7 +14,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
Generated
|
||||
</Text>
|
||||
<Text weight="bold" size="smaller">
|
||||
{new Date(props.vid?.generatedOn).toLocaleDateString()}
|
||||
{new Date(props.vc?.generatedOn).toLocaleDateString()}
|
||||
</Text>
|
||||
</Column>
|
||||
<Column fill elevation={1} padding="12 16" margin="0 16 0 0">
|
||||
@@ -22,7 +22,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
{props.vid?.idType}
|
||||
</Text>
|
||||
<Text weight="bold" size="smaller">
|
||||
{props.vid?.id}
|
||||
{props.vc?.id}
|
||||
</Text>
|
||||
</Column>
|
||||
<Column fill elevation={1} padding="12 16" margin="">
|
||||
@@ -40,8 +40,8 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<Image
|
||||
source={
|
||||
props.vid?.credential.biometrics?.face
|
||||
? { uri: props.vid?.credential.biometrics.face }
|
||||
props.vc?.credential.biometrics?.face
|
||||
? { uri: props.vc?.credential.biometrics.face }
|
||||
: require('../assets/placeholder-photo.png')
|
||||
}
|
||||
style={{
|
||||
@@ -58,7 +58,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Full name</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{props.vid?.verifiableCredential.credentialSubject.fullName}
|
||||
{props.vc?.verifiableCredential.credentialSubject.fullName}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
@@ -67,7 +67,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Subtitle>Gender</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{getLocalizedField(
|
||||
props.vid?.verifiableCredential.credentialSubject.gender
|
||||
props.vc?.verifiableCredential.credentialSubject.gender
|
||||
)}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
@@ -76,7 +76,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Date of birth</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{props.vid?.verifiableCredential.credentialSubject.dateOfBirth}
|
||||
{props.vc?.verifiableCredential.credentialSubject.dateOfBirth}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
@@ -84,7 +84,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Phone number</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{props.vid?.verifiableCredential.credentialSubject.phone}
|
||||
{props.vc?.verifiableCredential.credentialSubject.phone}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
@@ -92,7 +92,7 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Email</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{props.vid?.verifiableCredential.credentialSubject.email}
|
||||
{props.vc?.verifiableCredential.credentialSubject.email}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
@@ -100,15 +100,15 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Address</ListItem.Subtitle>
|
||||
<ListItem.Title>
|
||||
{getFullAddress(props.vid?.verifiableCredential.credentialSubject)}
|
||||
{getFullAddress(props.vc?.verifiableCredential.credentialSubject)}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
{Boolean(props.vid?.reason) && (
|
||||
{Boolean(props.vc?.reason) && (
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
<ListItem.Subtitle>Reason for sharing</ListItem.Subtitle>
|
||||
<ListItem.Title>{props.vid?.reason}</ListItem.Title>
|
||||
<ListItem.Title>{props.vc?.reason}</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
)}
|
||||
@@ -116,8 +116,8 @@ export const VidDetails: React.FC<VidDetailsProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface VidDetailsProps {
|
||||
vid: VC;
|
||||
interface VcDetailsProps {
|
||||
vc: VC;
|
||||
}
|
||||
|
||||
interface LocalizedField {
|
||||
@@ -4,13 +4,13 @@ import { Pressable, StyleSheet } from 'react-native';
|
||||
import { CheckBox, Icon } from 'react-native-elements';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
createVidItemMachine,
|
||||
createVcItemMachine,
|
||||
selectVerifiableCredential,
|
||||
selectGeneratedOn,
|
||||
selectTag,
|
||||
selectId,
|
||||
vidItemMachine,
|
||||
} from '../machines/vidItem';
|
||||
vcItemMachine,
|
||||
} from '../machines/vcItem';
|
||||
import { Column, Row, Text } from './ui';
|
||||
import { Colors } from './ui/styleUtils';
|
||||
import { RotatingIcon } from './RotatingIcon';
|
||||
@@ -42,12 +42,12 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
export const VidItem: React.FC<VidItemProps> = (props) => {
|
||||
export const VcItem: React.FC<VcItemProps> = (props) => {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const machine = useRef(
|
||||
createVidItemMachine(
|
||||
createVcItemMachine(
|
||||
appService.getSnapshot().context.serviceRefs,
|
||||
props.vidKey
|
||||
props.vcKey
|
||||
)
|
||||
);
|
||||
const service = useInterpret(machine.current);
|
||||
@@ -103,10 +103,10 @@ export const VidItem: React.FC<VidItemProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface VidItemProps {
|
||||
vidKey: string;
|
||||
interface VcItemProps {
|
||||
vcKey: string;
|
||||
margin?: string;
|
||||
selectable?: boolean;
|
||||
selected?: boolean;
|
||||
onPress?: (vidRef?: ActorRefFrom<typeof vidItemMachine>) => void;
|
||||
onPress?: (vcRef?: ActorRefFrom<typeof vcItemMachine>) => void;
|
||||
}
|
||||
@@ -103,10 +103,10 @@ export function createActivityLogMachine(serviceRefs: AppServices) {
|
||||
}
|
||||
|
||||
export interface ActivityLog {
|
||||
_vidKey: string;
|
||||
_vcKey: string;
|
||||
timestamp: number;
|
||||
deviceName: string;
|
||||
vidLabel: string;
|
||||
VCLabel: string;
|
||||
action: ActivityLogAction;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createModel } from 'xstate/lib/model';
|
||||
import { authMachine, createAuthMachine } from './auth';
|
||||
import { createSettingsMachine, settingsMachine } from './settings';
|
||||
import { storeMachine } from './store';
|
||||
import { createVidMachine, vidMachine } from './vid';
|
||||
import { createVcMachine, vcMachine } from './vc';
|
||||
import { createActivityLogMachine, activityLogMachine } from './activityLog';
|
||||
import { createRequestMachine, requestMachine } from './request';
|
||||
import { createScanMachine, scanMachine } from './scan';
|
||||
@@ -166,7 +166,7 @@ export const appMachine = model.createMachine(
|
||||
createAuthMachine(serviceRefs),
|
||||
authMachine.id
|
||||
);
|
||||
serviceRefs.vid = spawn(createVidMachine(serviceRefs), vidMachine.id);
|
||||
serviceRefs.vc = spawn(createVcMachine(serviceRefs), vcMachine.id);
|
||||
serviceRefs.settings = spawn(
|
||||
createSettingsMachine(serviceRefs),
|
||||
settingsMachine.id
|
||||
@@ -190,7 +190,7 @@ export const appMachine = model.createMachine(
|
||||
logServiceEvents: (context) => {
|
||||
if (__DEV__) {
|
||||
context.serviceRefs.auth.subscribe(logState);
|
||||
context.serviceRefs.vid.subscribe(logState);
|
||||
context.serviceRefs.vc.subscribe(logState);
|
||||
context.serviceRefs.settings.subscribe(logState);
|
||||
context.serviceRefs.activityLog.subscribe(logState);
|
||||
context.serviceRefs.scan.subscribe(logState);
|
||||
|
||||
@@ -10,18 +10,18 @@ import { StoreEvents } from './store';
|
||||
import { VC } from '../types/vc';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import {
|
||||
RECEIVED_VIDS_STORE_KEY,
|
||||
VID_ITEM_STORE_KEY,
|
||||
RECEIVED_VCS_STORE_KEY,
|
||||
VC_ITEM_STORE_KEY,
|
||||
} from '../shared/constants';
|
||||
import { ActivityLogEvents } from './activityLog';
|
||||
import { VidEvents } from './vid';
|
||||
import { VcEvents } from './vc';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
senderInfo: {} as DeviceInfo,
|
||||
receiverInfo: {} as DeviceInfo,
|
||||
incomingVid: {} as VC,
|
||||
incomingVc: {} as VC,
|
||||
connectionParams: '',
|
||||
loggers: [] as EmitterSubscription[],
|
||||
},
|
||||
@@ -31,7 +31,7 @@ const model = createModel(
|
||||
REJECT: () => ({}),
|
||||
CANCEL: () => ({}),
|
||||
DISMISS: () => ({}),
|
||||
VID_RECEIVED: (vid: VC) => ({ vid }),
|
||||
VC_RECEIVED: (vc: VC) => ({ vc }),
|
||||
RESPONSE_SENT: () => ({}),
|
||||
CONNECTED: () => ({}),
|
||||
DISCONNECT: () => ({}),
|
||||
@@ -43,8 +43,8 @@ const model = createModel(
|
||||
STORE_READY: () => ({}),
|
||||
STORE_RESPONSE: (response: any) => ({ response }),
|
||||
RECEIVE_DEVICE_INFO: (info: DeviceInfo) => ({ info }),
|
||||
RECEIVED_VIDS_UPDATED: () => ({}),
|
||||
VID_RESPONSE: (response: any) => ({ response }),
|
||||
RECEIVED_VCS_UPDATED: () => ({}),
|
||||
VC_RESPONSE: (response: any) => ({ response }),
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -52,10 +52,10 @@ const model = createModel(
|
||||
export const RequestEvents = model.events;
|
||||
|
||||
type ExchangeDoneEvent = EventFrom<typeof model, 'EXCHANGE_DONE'>;
|
||||
type VidReceivedEvent = EventFrom<typeof model, 'VID_RECEIVED'>;
|
||||
type VcReceivedEvent = EventFrom<typeof model, 'VC_RECEIVED'>;
|
||||
type ReceiveDeviceInfoEvent = EventFrom<typeof model, 'RECEIVE_DEVICE_INFO'>;
|
||||
type StoreResponseEvent = EventFrom<typeof model, 'STORE_RESPONSE'>;
|
||||
type VidResponseEvent = EventFrom<typeof model, 'VID_RESPONSE'>;
|
||||
type VcResponseEvent = EventFrom<typeof model, 'VC_RESPONSE'>;
|
||||
|
||||
export const requestMachine = model.createMachine(
|
||||
{
|
||||
@@ -132,20 +132,20 @@ export const requestMachine = model.createMachine(
|
||||
},
|
||||
on: {
|
||||
EXCHANGE_DONE: {
|
||||
target: 'waitingForVid',
|
||||
target: 'waitingForVc',
|
||||
actions: ['setSenderInfo'],
|
||||
},
|
||||
},
|
||||
},
|
||||
waitingForVid: {
|
||||
waitingForVc: {
|
||||
invoke: {
|
||||
src: 'receiveVid',
|
||||
src: 'receiveVc',
|
||||
},
|
||||
on: {
|
||||
DISCONNECT: 'disconnected',
|
||||
VID_RECEIVED: {
|
||||
VC_RECEIVED: {
|
||||
target: 'reviewing',
|
||||
actions: ['setIncomingVid'],
|
||||
actions: ['setIncomingVc'],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -159,34 +159,34 @@ export const requestMachine = model.createMachine(
|
||||
states: {
|
||||
idle: {},
|
||||
accepting: {
|
||||
initial: 'requestingReceivedVids',
|
||||
initial: 'requestingReceivedVcs',
|
||||
states: {
|
||||
requestingReceivedVids: {
|
||||
entry: ['requestReceivedVids'],
|
||||
requestingReceivedVcs: {
|
||||
entry: ['requestReceivedVcs'],
|
||||
on: {
|
||||
VID_RESPONSE: [
|
||||
VC_RESPONSE: [
|
||||
{
|
||||
cond: 'hasExistingVid',
|
||||
cond: 'hasExistingVc',
|
||||
target: '#accepted',
|
||||
},
|
||||
{
|
||||
target: 'prependingReceivedVid',
|
||||
target: 'prependingReceivedVc',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
prependingReceivedVid: {
|
||||
entry: ['prependReceivedVid'],
|
||||
prependingReceivedVc: {
|
||||
entry: ['prependReceivedVc'],
|
||||
on: {
|
||||
STORE_RESPONSE: 'storingVid',
|
||||
STORE_RESPONSE: 'storingVc',
|
||||
},
|
||||
},
|
||||
storingVid: {
|
||||
entry: ['storeVid'],
|
||||
storingVc: {
|
||||
entry: ['storeVc'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: '#accepted',
|
||||
actions: ['sendVidReceived'],
|
||||
actions: ['sendVcReceived'],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -197,7 +197,7 @@ export const requestMachine = model.createMachine(
|
||||
id: 'accepted',
|
||||
invoke: {
|
||||
src: {
|
||||
type: 'sendVidResponse',
|
||||
type: 'sendVcResponse',
|
||||
status: 'accepted',
|
||||
},
|
||||
},
|
||||
@@ -208,7 +208,7 @@ export const requestMachine = model.createMachine(
|
||||
rejected: {
|
||||
invoke: {
|
||||
src: {
|
||||
type: 'sendVidResponse',
|
||||
type: 'sendVcResponse',
|
||||
status: 'rejected',
|
||||
},
|
||||
},
|
||||
@@ -229,8 +229,8 @@ export const requestMachine = model.createMachine(
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
requestReceivedVids: send(VidEvents.GET_RECEIVED_VIDS(), {
|
||||
to: (context) => context.serviceRefs.vid,
|
||||
requestReceivedVcs: send(VcEvents.GET_RECEIVED_VCS(), {
|
||||
to: (context) => context.serviceRefs.vc,
|
||||
}),
|
||||
|
||||
requestReceiverInfo: sendParent('REQUEST_DEVICE_INFO'),
|
||||
@@ -255,8 +255,8 @@ export const requestMachine = model.createMachine(
|
||||
senderInfo: (_, event: ExchangeDoneEvent) => event.senderInfo,
|
||||
}),
|
||||
|
||||
setIncomingVid: model.assign({
|
||||
incomingVid: (_, event: VidReceivedEvent) => event.vid,
|
||||
setIncomingVc: model.assign({
|
||||
incomingVc: (_, event: VcReceivedEvent) => event.vc,
|
||||
}),
|
||||
|
||||
registerLoggers: model.assign({
|
||||
@@ -291,20 +291,20 @@ export const requestMachine = model.createMachine(
|
||||
},
|
||||
}),
|
||||
|
||||
prependReceivedVid: send(
|
||||
prependReceivedVc: send(
|
||||
(context) =>
|
||||
StoreEvents.PREPEND(
|
||||
RECEIVED_VIDS_STORE_KEY,
|
||||
VID_ITEM_STORE_KEY(context.incomingVid)
|
||||
RECEIVED_VCS_STORE_KEY,
|
||||
VC_ITEM_STORE_KEY(context.incomingVc)
|
||||
),
|
||||
{ to: (context) => context.serviceRefs.store }
|
||||
),
|
||||
|
||||
storeVid: send(
|
||||
storeVc: send(
|
||||
(context) =>
|
||||
StoreEvents.SET(
|
||||
VID_ITEM_STORE_KEY(context.incomingVid),
|
||||
context.incomingVid
|
||||
VC_ITEM_STORE_KEY(context.incomingVc),
|
||||
context.incomingVc
|
||||
),
|
||||
{ to: (context) => context.serviceRefs.store }
|
||||
),
|
||||
@@ -312,23 +312,23 @@ export const requestMachine = model.createMachine(
|
||||
logReceived: send(
|
||||
(context) =>
|
||||
ActivityLogEvents.LOG_ACTIVITY({
|
||||
_vidKey: VID_ITEM_STORE_KEY(context.incomingVid),
|
||||
_vcKey: VC_ITEM_STORE_KEY(context.incomingVc),
|
||||
action: 'received',
|
||||
timestamp: Date.now(),
|
||||
deviceName:
|
||||
context.senderInfo.name || context.senderInfo.deviceName,
|
||||
vidLabel: context.incomingVid.tag || context.incomingVid.id,
|
||||
VCLabel: context.incomingVc.tag || context.incomingVc.id,
|
||||
}),
|
||||
{ to: (context) => context.serviceRefs.activityLog }
|
||||
),
|
||||
|
||||
sendVidReceived: send(
|
||||
sendVcReceived: send(
|
||||
(context) => {
|
||||
return VidEvents.VID_RECEIVED(
|
||||
VID_ITEM_STORE_KEY(context.incomingVid)
|
||||
return VcEvents.VC_RECEIVED(
|
||||
VC_ITEM_STORE_KEY(context.incomingVc)
|
||||
);
|
||||
},
|
||||
{ to: (context) => context.serviceRefs.vid }
|
||||
{ to: (context) => context.serviceRefs.vc }
|
||||
),
|
||||
},
|
||||
|
||||
@@ -380,7 +380,7 @@ export const requestMachine = model.createMachine(
|
||||
return () => subscription.remove();
|
||||
},
|
||||
|
||||
receiveVid: () => (callback) => {
|
||||
receiveVc: () => (callback) => {
|
||||
const subscription = SmartShare.handleNearbyEvents((event) => {
|
||||
if (event.type === 'onDisconnected') {
|
||||
callback({ type: 'DISCONNECT' });
|
||||
@@ -389,8 +389,8 @@ export const requestMachine = model.createMachine(
|
||||
if (event.type !== 'msg') return;
|
||||
|
||||
const message = Message.fromString<VC>(event.data);
|
||||
if (message.type === 'send:vid') {
|
||||
callback({ type: 'VID_RECEIVED', vid: message.data });
|
||||
if (message.type === 'send:vc') {
|
||||
callback({ type: 'VC_RECEIVED', vc: message.data });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -398,8 +398,8 @@ export const requestMachine = model.createMachine(
|
||||
},
|
||||
|
||||
// tslint:disable-next-line
|
||||
sendVidResponse: (context, event, meta) => (callback) => {
|
||||
const response = new Message('send:vid:response', {
|
||||
sendVcResponse: (context, event, meta) => (callback) => {
|
||||
const response = new Message('send:vc:response', {
|
||||
status: meta.src.status,
|
||||
});
|
||||
|
||||
@@ -410,10 +410,10 @@ export const requestMachine = model.createMachine(
|
||||
},
|
||||
|
||||
guards: {
|
||||
hasExistingVid: (context, event: VidResponseEvent) => {
|
||||
const receivedVids: string[] = event.response;
|
||||
const vidKey = VID_ITEM_STORE_KEY(context.incomingVid);
|
||||
return receivedVids.includes(vidKey);
|
||||
hasExistingVc: (context, event: VcResponseEvent) => {
|
||||
const receivedVcs: string[] = event.response;
|
||||
const vcKey = VC_ITEM_STORE_KEY(context.incomingVc);
|
||||
return receivedVcs.includes(vcKey);
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -436,8 +436,8 @@ export function selectConnectionParams(state: State) {
|
||||
return state.context.connectionParams;
|
||||
}
|
||||
|
||||
export function selectIncomingVid(state: State) {
|
||||
return state.context.incomingVid;
|
||||
export function selectIncomingVc(state: State) {
|
||||
return state.context.incomingVc;
|
||||
}
|
||||
|
||||
export function selectIsReviewing(state: State) {
|
||||
@@ -468,6 +468,6 @@ export function selectIsExchangingDeviceInfo(state: State) {
|
||||
return state.matches('exchangingDeviceInfo');
|
||||
}
|
||||
|
||||
export function selectIsWaitingForVid(state: State) {
|
||||
return state.matches('waitingForVid');
|
||||
export function selectIsWaitingForVc(state: State) {
|
||||
return state.matches('waitingForVc');
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@ import { getDeviceNameSync } from 'react-native-device-info';
|
||||
import { VC } from '../types/vc';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { ActivityLogEvents } from './activityLog';
|
||||
import { VID_ITEM_STORE_KEY } from '../shared/constants';
|
||||
import { VC_ITEM_STORE_KEY } from '../shared/constants';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
senderInfo: {} as DeviceInfo,
|
||||
receiverInfo: {} as DeviceInfo,
|
||||
selectedVid: {} as VC,
|
||||
selectedVc: {} as VC,
|
||||
reason: '',
|
||||
loggers: [] as EmitterSubscription[],
|
||||
locationConfig: {
|
||||
@@ -25,17 +25,17 @@ const model = createModel(
|
||||
alwaysShow: false,
|
||||
needBle: true,
|
||||
},
|
||||
vidName: '',
|
||||
vcName: '',
|
||||
},
|
||||
{
|
||||
events: {
|
||||
EXCHANGE_DONE: (receiverInfo: DeviceInfo) => ({ receiverInfo }),
|
||||
RECEIVE_DEVICE_INFO: (info: DeviceInfo) => ({ info }),
|
||||
SELECT_VID: (vid: VC) => ({ vid }),
|
||||
SELECT_VC: (vc: VC) => ({ vc }),
|
||||
SCAN: (params: string) => ({ params }),
|
||||
ACCEPT_REQUEST: () => ({}),
|
||||
VID_ACCEPTED: () => ({}),
|
||||
VID_REJECTED: () => ({}),
|
||||
VC_ACCEPTED: () => ({}),
|
||||
VC_REJECTED: () => ({}),
|
||||
CANCEL: () => ({}),
|
||||
DISMISS: () => ({}),
|
||||
CONNECTED: () => ({}),
|
||||
@@ -49,7 +49,7 @@ const model = createModel(
|
||||
FLIGHT_DISABLED: () => ({}),
|
||||
FLIGHT_REQUEST: () => ({}),
|
||||
LOCATION_REQUEST: () => ({}),
|
||||
UPDATE_VID_NAME: (vidName: string) => ({ vidName }),
|
||||
UPDATE_VC_NAME: (vcName: string) => ({ vcName }),
|
||||
STORE_RESPONSE: (response: any) => ({ response }),
|
||||
APP_ACTIVE: () => ({}),
|
||||
},
|
||||
@@ -60,7 +60,7 @@ export const ScanEvents = model.events;
|
||||
|
||||
type ExchangeDoneEvent = EventFrom<typeof model, 'EXCHANGE_DONE'>;
|
||||
type ScanEvent = EventFrom<typeof model, 'SCAN'>;
|
||||
type SelectVidEvent = EventFrom<typeof model, 'SELECT_VID'>;
|
||||
type selectVcEvent = EventFrom<typeof model, 'SELECT_VC'>;
|
||||
type UpdateReasonEvent = EventFrom<typeof model, 'UPDATE_REASON'>;
|
||||
type ReceiveDeviceInfoEvent = EventFrom<typeof model, 'RECEIVE_DEVICE_INFO'>;
|
||||
|
||||
@@ -206,7 +206,7 @@ export const scanMachine = model.createMachine(
|
||||
on: {
|
||||
CANCEL: 'findingConnection',
|
||||
DISMISS: 'findingConnection',
|
||||
ACCEPT_REQUEST: '.selectingVid',
|
||||
ACCEPT_REQUEST: '.selectingVc',
|
||||
UPDATE_REASON: {
|
||||
actions: ['setReason'],
|
||||
},
|
||||
@@ -215,26 +215,26 @@ export const scanMachine = model.createMachine(
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
ACCEPT_REQUEST: 'selectingVid',
|
||||
ACCEPT_REQUEST: 'selectingVc',
|
||||
},
|
||||
},
|
||||
selectingVid: {
|
||||
selectingVc: {
|
||||
on: {
|
||||
SELECT_VID: {
|
||||
target: 'sendingVid',
|
||||
actions: ['setSelectedVid'],
|
||||
SELECT_VC: {
|
||||
target: 'sendingVc',
|
||||
actions: ['setSelectedVc'],
|
||||
},
|
||||
CANCEL: 'idle',
|
||||
},
|
||||
},
|
||||
sendingVid: {
|
||||
sendingVc: {
|
||||
invoke: {
|
||||
src: 'sendVid',
|
||||
src: 'sendVc',
|
||||
},
|
||||
on: {
|
||||
DISCONNECT: '#scan.disconnected',
|
||||
VID_ACCEPTED: 'accepted',
|
||||
VID_REJECTED: 'rejected',
|
||||
VC_ACCEPTED: 'accepted',
|
||||
VC_REJECTED: 'rejected',
|
||||
},
|
||||
},
|
||||
accepted: {
|
||||
@@ -302,10 +302,10 @@ export const scanMachine = model.createMachine(
|
||||
|
||||
clearReason: model.assign({ reason: '' }),
|
||||
|
||||
setSelectedVid: model.assign({
|
||||
selectedVid: (context, event: SelectVidEvent) => {
|
||||
setSelectedVc: model.assign({
|
||||
selectedVc: (context, event: selectVcEvent) => {
|
||||
return {
|
||||
...event.vid,
|
||||
...event.vc,
|
||||
reason: context.reason,
|
||||
};
|
||||
},
|
||||
@@ -346,12 +346,12 @@ export const scanMachine = model.createMachine(
|
||||
logShared: send(
|
||||
(context) =>
|
||||
ActivityLogEvents.LOG_ACTIVITY({
|
||||
_vidKey: VID_ITEM_STORE_KEY(context.selectedVid),
|
||||
_vcKey: VC_ITEM_STORE_KEY(context.selectedVc),
|
||||
action: 'shared',
|
||||
timestamp: Date.now(),
|
||||
deviceName:
|
||||
context.receiverInfo.name || context.receiverInfo.deviceName,
|
||||
vidLabel: context.selectedVid.tag || context.selectedVid.id,
|
||||
VCLabel: context.selectedVc.tag || context.selectedVc.id,
|
||||
}),
|
||||
{ to: (context) => context.serviceRefs.activityLog }
|
||||
),
|
||||
@@ -442,15 +442,15 @@ export const scanMachine = model.createMachine(
|
||||
return () => subscription?.remove();
|
||||
},
|
||||
|
||||
sendVid: (context) => (callback) => {
|
||||
sendVc: (context) => (callback) => {
|
||||
let subscription: EmitterSubscription;
|
||||
|
||||
const vid = {
|
||||
...context.selectedVid,
|
||||
const vc = {
|
||||
...context.selectedVc,
|
||||
tag: '',
|
||||
};
|
||||
|
||||
const message = new Message<VC>('send:vid', vid);
|
||||
const message = new Message<VC>('send:vc', vc);
|
||||
|
||||
SmartShare.send(message.toString(), () => {
|
||||
subscription = SmartShare.handleNearbyEvents((event) => {
|
||||
@@ -460,13 +460,13 @@ export const scanMachine = model.createMachine(
|
||||
|
||||
if (event.type !== 'msg') return;
|
||||
|
||||
const response = Message.fromString<SendVidStatus>(event.data);
|
||||
if (response.type === 'send:vid:response') {
|
||||
const response = Message.fromString<SendVcStatus>(event.data);
|
||||
if (response.type === 'send:vc:response') {
|
||||
callback({
|
||||
type:
|
||||
response.data.status === 'accepted'
|
||||
? 'VID_ACCEPTED'
|
||||
: 'VID_REJECTED',
|
||||
? 'VC_ACCEPTED'
|
||||
: 'VC_REJECTED',
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -499,7 +499,7 @@ export function createScanMachine(serviceRefs: AppServices) {
|
||||
});
|
||||
}
|
||||
|
||||
interface SendVidStatus {
|
||||
interface SendVcStatus {
|
||||
status: 'accepted' | 'rejected';
|
||||
}
|
||||
|
||||
@@ -513,8 +513,8 @@ export function selectReason(state: State) {
|
||||
return state.context.reason;
|
||||
}
|
||||
|
||||
export function selectVidName(state: State) {
|
||||
return state.context.vidName;
|
||||
export function selectVcName(state: State) {
|
||||
return state.context.vcName;
|
||||
}
|
||||
|
||||
export function selectStatusMessage(state: State) {
|
||||
@@ -533,12 +533,12 @@ export function selectReviewing(state: State) {
|
||||
return state.matches('reviewing');
|
||||
}
|
||||
|
||||
export function selectSelectingVid(state: State) {
|
||||
return state.matches('reviewing.selectingVid');
|
||||
export function selectSelectingVc(state: State) {
|
||||
return state.matches('reviewing.selectingVc');
|
||||
}
|
||||
|
||||
export function selectSendingVid(state: State) {
|
||||
return state.matches('reviewing.sendingVid');
|
||||
export function selectSendingVc(state: State) {
|
||||
return state.matches('reviewing.sendingVc');
|
||||
}
|
||||
|
||||
export function selectAccepted(state: State) {
|
||||
|
||||
@@ -2,23 +2,23 @@ import { ContextFrom, EventFrom, send, StateFrom } from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { SETTINGS_STORE_KEY } from '../shared/constants';
|
||||
import { VIDLabel } from '../types/vc';
|
||||
import { VCLabel } from '../types/vc';
|
||||
import { StoreEvents } from './store';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
name: '',
|
||||
vidLabel: {
|
||||
VCLabel: {
|
||||
singular: 'ID',
|
||||
plural: 'IDs',
|
||||
} as VIDLabel,
|
||||
} as VCLabel,
|
||||
isBiometricUnlockEnabled: false,
|
||||
},
|
||||
{
|
||||
events: {
|
||||
UPDATE_NAME: (name: string) => ({ name }),
|
||||
UPDATE_VID_LABEL: (label: string) => ({ label }),
|
||||
UPDATE_VC_LABEL: (label: string) => ({ label }),
|
||||
TOGGLE_BIOMETRIC_UNLOCK: () => ({}),
|
||||
STORE_RESPONSE: (response: any) => ({ response }),
|
||||
},
|
||||
@@ -30,7 +30,7 @@ export const SettingsEvents = model.events;
|
||||
type Context = ContextFrom<typeof model>;
|
||||
|
||||
type UpdateNameEvent = EventFrom<typeof model, 'UPDATE_NAME'>;
|
||||
type UpdateVidLabelEvent = EventFrom<typeof model, 'UPDATE_VID_LABEL'>;
|
||||
type UpdateVCLabelEvent = EventFrom<typeof model, 'UPDATE_VC_LABEL'>;
|
||||
type StoreResponseEvent = EventFrom<typeof model, 'STORE_RESPONSE'>;
|
||||
|
||||
export const settingsMachine = model.createMachine(
|
||||
@@ -62,8 +62,8 @@ export const settingsMachine = model.createMachine(
|
||||
UPDATE_NAME: {
|
||||
actions: ['updateName', 'storeContext'],
|
||||
},
|
||||
UPDATE_VID_LABEL: {
|
||||
actions: ['updateVidLabel', 'storeContext'],
|
||||
UPDATE_VC_LABEL: {
|
||||
actions: ['updateVCLabel', 'storeContext'],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -95,8 +95,8 @@ export const settingsMachine = model.createMachine(
|
||||
name: (_, event: UpdateNameEvent) => event.name,
|
||||
}),
|
||||
|
||||
updateVidLabel: model.assign({
|
||||
vidLabel: (_, event: UpdateVidLabelEvent) => ({
|
||||
updateVCLabel: model.assign({
|
||||
VCLabel: (_, event: UpdateVCLabelEvent) => ({
|
||||
singular: event.label,
|
||||
plural: event.label + 's',
|
||||
}),
|
||||
@@ -124,8 +124,8 @@ export function selectName(state: State) {
|
||||
return state.context.name;
|
||||
}
|
||||
|
||||
export function selectVidLabel(state: State) {
|
||||
return state.context.vidLabel;
|
||||
export function selectVCLabel(state: State) {
|
||||
return state.context.VCLabel;
|
||||
}
|
||||
|
||||
export function selectBiometricUnlockEnabled(state: State) {
|
||||
|
||||
217
machines/vc.ts
Normal file
217
machines/vc.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { EventFrom, StateFrom } from 'xstate';
|
||||
import { send, sendParent } from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { StoreEvents } from './store';
|
||||
import { VC } from '../types/vc';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { log, respond } from 'xstate/lib/actions';
|
||||
import { VcItemEvents } from './vcItem';
|
||||
import {
|
||||
MY_VCS_STORE_KEY,
|
||||
RECEIVED_VCS_STORE_KEY,
|
||||
VC_ITEM_STORE_KEY,
|
||||
} from '../shared/constants';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
myVcs: [] as string[],
|
||||
receivedVcs: [] as string[],
|
||||
vcs: {} as Record<string, VC>,
|
||||
},
|
||||
{
|
||||
events: {
|
||||
VIEW_VC: (vc: VC) => ({ vc }),
|
||||
GET_VC_ITEM: (vcKey: string) => ({ vcKey }),
|
||||
STORE_RESPONSE: (response: any) => ({ response }),
|
||||
STORE_ERROR: (error: Error) => ({ error }),
|
||||
VC_ADDED: (vcKey: string) => ({ vcKey }),
|
||||
VC_RECEIVED: (vcKey: string) => ({ vcKey }),
|
||||
VC_DOWNLOADED: (vc: VC) => ({ vc }),
|
||||
REFRESH_MY_VCS: () => ({}),
|
||||
REFRESH_RECEIVED_VCS: () => ({}),
|
||||
GET_RECEIVED_VCS: () => ({}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const VcEvents = model.events;
|
||||
|
||||
type GetVcItemEvent = EventFrom<typeof model, 'GET_VC_ITEM'>;
|
||||
type StoreResponseEvent = EventFrom<typeof model, 'STORE_RESPONSE'>;
|
||||
type VcDownloadedEvent = EventFrom<typeof model, 'VC_DOWNLOADED'>;
|
||||
type VcAddedEvent = EventFrom<typeof model, 'VC_ADDED'>;
|
||||
type VcReceivedEvent = EventFrom<typeof model, 'VC_RECEIVED'>;
|
||||
|
||||
export const vcMachine = model.createMachine(
|
||||
{
|
||||
id: 'vc',
|
||||
context: model.initialContext,
|
||||
initial: 'init',
|
||||
states: {
|
||||
init: {
|
||||
initial: 'myVcs',
|
||||
states: {
|
||||
myVcs: {
|
||||
entry: ['loadMyVcs'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: 'receivedVcs',
|
||||
actions: ['setMyVcs'],
|
||||
},
|
||||
},
|
||||
},
|
||||
receivedVcs: {
|
||||
entry: ['loadReceivedVcs'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: '#ready',
|
||||
actions: ['setReceivedVcs'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ready: {
|
||||
id: 'ready',
|
||||
entry: [sendParent('READY')],
|
||||
on: {
|
||||
GET_RECEIVED_VCS: {
|
||||
actions: ['getReceivedVcsResponse'],
|
||||
},
|
||||
GET_VC_ITEM: {
|
||||
actions: ['getVcItemResponse'],
|
||||
},
|
||||
VC_ADDED: {
|
||||
actions: ['prependToMyVcs'],
|
||||
},
|
||||
VC_DOWNLOADED: {
|
||||
actions: ['setDownloadedVc'],
|
||||
},
|
||||
VC_RECEIVED: {
|
||||
actions: ['prependToReceivedVcs'],
|
||||
},
|
||||
},
|
||||
type: 'parallel',
|
||||
states: {
|
||||
myVcs: {
|
||||
initial: 'idle',
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
REFRESH_MY_VCS: 'refreshing',
|
||||
},
|
||||
},
|
||||
refreshing: {
|
||||
entry: ['loadMyVcs'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: 'idle',
|
||||
actions: ['setMyVcs'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
receivedVcs: {
|
||||
initial: 'idle',
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
REFRESH_RECEIVED_VCS: 'refreshing',
|
||||
},
|
||||
},
|
||||
refreshing: {
|
||||
entry: ['loadReceivedVcs'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: 'idle',
|
||||
actions: ['setReceivedVcs'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
getReceivedVcsResponse: respond((context) => ({
|
||||
type: 'VC_RESPONSE',
|
||||
response: context.receivedVcs,
|
||||
})),
|
||||
|
||||
getVcItemResponse: respond((context, event: GetVcItemEvent) => {
|
||||
const vc = context.vcs[event.vcKey];
|
||||
return VcItemEvents.GET_VC_RESPONSE(vc);
|
||||
}),
|
||||
|
||||
loadMyVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), {
|
||||
to: (context) => context.serviceRefs.store,
|
||||
}),
|
||||
|
||||
loadReceivedVcs: send(StoreEvents.GET(RECEIVED_VCS_STORE_KEY), {
|
||||
to: (context) => context.serviceRefs.store,
|
||||
}),
|
||||
|
||||
setMyVcs: model.assign({
|
||||
myVcs: (_, event: StoreResponseEvent) => event.response || [],
|
||||
}),
|
||||
|
||||
setReceivedVcs: model.assign({
|
||||
receivedVcs: (_, event: StoreResponseEvent) => event.response || [],
|
||||
}),
|
||||
|
||||
setDownloadedVc: (context, event: VcDownloadedEvent) => {
|
||||
context.vcs[VC_ITEM_STORE_KEY(event.vc)] = event.vc;
|
||||
},
|
||||
|
||||
prependToMyVcs: model.assign({
|
||||
myVcs: (context, event: VcAddedEvent) => [
|
||||
event.vcKey,
|
||||
...context.myVcs,
|
||||
],
|
||||
}),
|
||||
|
||||
prependToReceivedVcs: model.assign({
|
||||
receivedVcs: (context, event: VcReceivedEvent) => [
|
||||
event.vcKey,
|
||||
...context.receivedVcs,
|
||||
],
|
||||
}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export function createVcMachine(serviceRefs: AppServices) {
|
||||
return vcMachine.withContext({
|
||||
...vcMachine.context,
|
||||
serviceRefs,
|
||||
});
|
||||
}
|
||||
|
||||
type State = StateFrom<typeof vcMachine>;
|
||||
|
||||
export function selectMyVcs(state: State) {
|
||||
return state.context.myVcs;
|
||||
}
|
||||
|
||||
export function selectShareableVcs(state: State) {
|
||||
return state.context.myVcs.filter(
|
||||
(vcKey) => state.context.vcs[vcKey]?.credential != null
|
||||
);
|
||||
}
|
||||
|
||||
export function selectReceivedVcs(state: State) {
|
||||
return state.context.receivedVcs;
|
||||
}
|
||||
|
||||
export function selectIsRefreshingMyVcs(state: State) {
|
||||
return state.matches('ready.myVcs.refreshing');
|
||||
}
|
||||
|
||||
export function selectIsRefreshingReceivedVcs(state: State) {
|
||||
return state.matches('ready.receivedVcs.refreshing');
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EventFrom, send, StateFrom } from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { VID_ITEM_STORE_KEY } from '../shared/constants';
|
||||
import { VC_ITEM_STORE_KEY } from '../shared/constants';
|
||||
import { AppServices } from '../shared/GlobalContext';
|
||||
import { CredentialDownloadResponse, request } from '../shared/request';
|
||||
import {
|
||||
@@ -29,40 +29,40 @@ const model = createModel(
|
||||
SAVE_TAG: (tag: string) => ({ tag }),
|
||||
STORE_READY: () => ({}),
|
||||
DISMISS: () => ({}),
|
||||
CREDENTIAL_DOWNLOADED: (vid: VC) => ({ vid }),
|
||||
CREDENTIAL_DOWNLOADED: (vc: VC) => ({ vc }),
|
||||
STORE_RESPONSE: (response: VC) => ({ response }),
|
||||
POLL: () => ({}),
|
||||
DOWNLOAD_READY: () => ({}),
|
||||
GET_VID_RESPONSE: (vid: VC) => ({ vid }),
|
||||
GET_VC_RESPONSE: (vc: VC) => ({ vc }),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const VidItemEvents = model.events;
|
||||
export const VcItemEvents = model.events;
|
||||
|
||||
type SaveTagEvent = EventFrom<typeof model, 'SAVE_TAG'>;
|
||||
type GetVidResponseEvent = EventFrom<typeof model, 'GET_VID_RESPONSE'>;
|
||||
type GetVcResponseEvent = EventFrom<typeof model, 'GET_VC_RESPONSE'>;
|
||||
type StoreResponseEvent = EventFrom<typeof model, 'STORE_RESPONSE'>;
|
||||
type CredentialDownloadedEvent = EventFrom<
|
||||
typeof model,
|
||||
'CREDENTIAL_DOWNLOADED'
|
||||
>;
|
||||
|
||||
type RequestVidDataEvent =
|
||||
type RequestVcDataEvent =
|
||||
| StoreResponseEvent
|
||||
| CredentialDownloadedEvent
|
||||
| GetVidResponseEvent;
|
||||
| GetVcResponseEvent;
|
||||
|
||||
export const vidItemMachine = model.createMachine(
|
||||
export const vcItemMachine = model.createMachine(
|
||||
{
|
||||
id: 'vid-item',
|
||||
id: 'vc-item',
|
||||
context: model.initialContext,
|
||||
initial: 'checkingVid',
|
||||
initial: 'checkingVc',
|
||||
states: {
|
||||
checkingVid: {
|
||||
entry: ['requestVidContext'],
|
||||
checkingVc: {
|
||||
entry: ['requestVcContext'],
|
||||
on: {
|
||||
GET_VID_RESPONSE: [
|
||||
GET_VC_RESPONSE: [
|
||||
{
|
||||
cond: 'hasCredential',
|
||||
target: 'idle',
|
||||
@@ -81,7 +81,7 @@ export const vidItemMachine = model.createMachine(
|
||||
{
|
||||
cond: 'hasCredential',
|
||||
target: 'idle',
|
||||
actions: ['setCredential', 'updateVid'],
|
||||
actions: ['setCredential', 'updateVc'],
|
||||
},
|
||||
{
|
||||
target: 'checkingServerData',
|
||||
@@ -118,7 +118,7 @@ export const vidItemMachine = model.createMachine(
|
||||
actions: [
|
||||
'setCredential',
|
||||
'storeContext',
|
||||
'updateVid',
|
||||
'updateVc',
|
||||
'logDownloaded',
|
||||
],
|
||||
},
|
||||
@@ -151,26 +151,26 @@ export const vidItemMachine = model.createMachine(
|
||||
},
|
||||
{
|
||||
actions: {
|
||||
updateVid: send(
|
||||
updateVc: send(
|
||||
(context) => {
|
||||
const { serviceRefs, ...vid } = context;
|
||||
return { type: 'VID_DOWNLOADED', vid };
|
||||
const { serviceRefs, ...vc } = context;
|
||||
return { type: 'VC_DOWNLOADED', vc };
|
||||
},
|
||||
{ to: (context) => context.serviceRefs.vid }
|
||||
{ to: (context) => context.serviceRefs.vc }
|
||||
),
|
||||
|
||||
requestVidContext: send(
|
||||
requestVcContext: send(
|
||||
(context) => ({
|
||||
type: 'GET_VID_ITEM',
|
||||
vidKey: VID_ITEM_STORE_KEY(context),
|
||||
type: 'GET_VC_ITEM',
|
||||
vcKey: VC_ITEM_STORE_KEY(context),
|
||||
}),
|
||||
{
|
||||
to: (context) => context.serviceRefs.vid,
|
||||
to: (context) => context.serviceRefs.vc,
|
||||
}
|
||||
),
|
||||
|
||||
requestStoredContext: send(
|
||||
(context) => StoreEvents.GET(VID_ITEM_STORE_KEY(context)),
|
||||
(context) => StoreEvents.GET(VC_ITEM_STORE_KEY(context)),
|
||||
{
|
||||
to: (context) => context.serviceRefs.store,
|
||||
}
|
||||
@@ -179,7 +179,7 @@ export const vidItemMachine = model.createMachine(
|
||||
storeContext: send(
|
||||
(context) => {
|
||||
const { serviceRefs, ...data } = context;
|
||||
return StoreEvents.SET(VID_ITEM_STORE_KEY(context), data);
|
||||
return StoreEvents.SET(VC_ITEM_STORE_KEY(context), data);
|
||||
},
|
||||
{
|
||||
to: (context) => context.serviceRefs.store,
|
||||
@@ -193,29 +193,29 @@ export const vidItemMachine = model.createMachine(
|
||||
storeTag: send(
|
||||
(context) => {
|
||||
const { serviceRefs, ...data } = context;
|
||||
return StoreEvents.SET(VID_ITEM_STORE_KEY(context), data);
|
||||
return StoreEvents.SET(VC_ITEM_STORE_KEY(context), data);
|
||||
},
|
||||
{ to: (context) => context.serviceRefs.store }
|
||||
),
|
||||
|
||||
setCredential: model.assign((_, event: RequestVidDataEvent) => {
|
||||
setCredential: model.assign((_, event: RequestVcDataEvent) => {
|
||||
switch (event.type) {
|
||||
case 'STORE_RESPONSE':
|
||||
return event.response;
|
||||
case 'GET_VID_RESPONSE':
|
||||
case 'GET_VC_RESPONSE':
|
||||
case 'CREDENTIAL_DOWNLOADED':
|
||||
return event.vid;
|
||||
return event.vc;
|
||||
}
|
||||
}),
|
||||
|
||||
logDownloaded: send(
|
||||
(_, event: CredentialDownloadedEvent) =>
|
||||
ActivityLogEvents.LOG_ACTIVITY({
|
||||
_vidKey: VID_ITEM_STORE_KEY(event.vid),
|
||||
_vcKey: VC_ITEM_STORE_KEY(event.vc),
|
||||
action: 'downloaded',
|
||||
timestamp: Date.now(),
|
||||
deviceName: '',
|
||||
vidLabel: event.vid.tag || event.vid.id,
|
||||
VCLabel: event.vc.tag || event.vc.id,
|
||||
}),
|
||||
{ to: (context) => context.serviceRefs.activityLog }
|
||||
),
|
||||
@@ -294,13 +294,13 @@ export const vidItemMachine = model.createMachine(
|
||||
}
|
||||
);
|
||||
|
||||
export const createVidItemMachine = (
|
||||
export const createVcItemMachine = (
|
||||
serviceRefs: AppServices,
|
||||
vidKey: string
|
||||
vcKey: string
|
||||
) => {
|
||||
const [_, idType, id, requestId] = vidKey.split(':');
|
||||
return vidItemMachine.withContext({
|
||||
...vidItemMachine.context,
|
||||
const [_, idType, id, requestId] = vcKey.split(':');
|
||||
return vcItemMachine.withContext({
|
||||
...vcItemMachine.context,
|
||||
serviceRefs,
|
||||
id,
|
||||
idType: idType as VcIdType,
|
||||
@@ -308,9 +308,9 @@ export const createVidItemMachine = (
|
||||
});
|
||||
};
|
||||
|
||||
type State = StateFrom<typeof vidItemMachine>;
|
||||
type State = StateFrom<typeof vcItemMachine>;
|
||||
|
||||
export function selectVid(state: State) {
|
||||
export function selectVc(state: State) {
|
||||
const { serviceRefs, ...data } = state.context;
|
||||
return data;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export const HistoryTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
<TextItem
|
||||
key={activity.timestamp}
|
||||
label={createLabel(activity)}
|
||||
text={`${activity.vidLabel} ${activity.action}`}
|
||||
text={`${activity.VCLabel} ${activity.action}`}
|
||||
/>
|
||||
))}
|
||||
{controller.activities.length === 0 && (
|
||||
|
||||
@@ -5,9 +5,9 @@ import { Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { HomeRouteProps } from '../../routes/main';
|
||||
import { HistoryTab } from './HistoryTab';
|
||||
import { MyVidsTab } from './MyVidsTab';
|
||||
import { ReceivedVidsTab } from './ReceivedVidsTab';
|
||||
import { ViewVidModal } from './ViewVidModal';
|
||||
import { MyVcsTab } from './MyVcsTab';
|
||||
import { ReceivedVcsTab } from './ReceivedVcsTab';
|
||||
import { ViewVcModal } from './ViewVcModal';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { useHomeScreen } from './HomeScreenController';
|
||||
|
||||
@@ -34,19 +34,19 @@ export const HomeScreen: React.FC<HomeRouteProps> = (props) => {
|
||||
value={controller.activeTab}
|
||||
onChange={controller.SELECT_TAB}
|
||||
indicatorStyle={styles.tabIndicator}>
|
||||
{TabItem(`My\n${controller.vidLabel.plural}`)}
|
||||
{TabItem(`Received\n${controller.vidLabel.plural}`)}
|
||||
{TabItem(`My\n${controller.VCLabel.plural}`)}
|
||||
{TabItem(`Received\n${controller.VCLabel.plural}`)}
|
||||
{TabItem('History')}
|
||||
</Tab>
|
||||
{controller.haveTabsLoaded && (
|
||||
<Column fill>
|
||||
<MyVidsTab
|
||||
<MyVcsTab
|
||||
isVisible={controller.activeTab === 0}
|
||||
service={controller.service.children.get('myVidsTab')}
|
||||
service={controller.service.children.get('MyVcsTab')}
|
||||
/>
|
||||
<ReceivedVidsTab
|
||||
<ReceivedVcsTab
|
||||
isVisible={controller.activeTab === 1}
|
||||
service={controller.service.children.get('receivedVidsTab')}
|
||||
service={controller.service.children.get('receivedVcsTab')}
|
||||
/>
|
||||
<HistoryTab
|
||||
isVisible={controller.activeTab === 2}
|
||||
@@ -55,11 +55,11 @@ export const HomeScreen: React.FC<HomeRouteProps> = (props) => {
|
||||
</Column>
|
||||
)}
|
||||
</Column>
|
||||
{controller.selectedVid && (
|
||||
<ViewVidModal
|
||||
isVisible={controller.isViewingVid}
|
||||
{controller.selectedVc && (
|
||||
<ViewVcModal
|
||||
isVisible={controller.isViewingVc}
|
||||
onDismiss={controller.DISMISS_MODAL}
|
||||
vidItemActor={controller.selectedVid}
|
||||
vcItemActor={controller.selectedVc}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useInterpret, useSelector } from '@xstate/react';
|
||||
import { useContext, useEffect, useRef } from 'react';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import { HomeRouteProps } from '../../routes/main';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import {
|
||||
HomeScreenEvents,
|
||||
HomeScreenMachine,
|
||||
selectActiveTab,
|
||||
selectSelectedVid,
|
||||
selectSelectedVc,
|
||||
selectTabsLoaded,
|
||||
selectViewingVid,
|
||||
selectViewingVc,
|
||||
} from './HomeScreenMachine';
|
||||
|
||||
export function useHomeScreen(props: HomeRouteProps) {
|
||||
@@ -33,10 +33,10 @@ export function useHomeScreen(props: HomeRouteProps) {
|
||||
service,
|
||||
|
||||
activeTab: useSelector(service, selectActiveTab),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
selectedVid: useSelector(service, selectSelectedVid),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
selectedVc: useSelector(service, selectSelectedVc),
|
||||
|
||||
isViewingVid: useSelector(service, selectViewingVid),
|
||||
isViewingVc: useSelector(service, selectViewingVc),
|
||||
haveTabsLoaded: useSelector(service, selectTabsLoaded),
|
||||
|
||||
SELECT_TAB,
|
||||
@@ -45,8 +45,8 @@ export function useHomeScreen(props: HomeRouteProps) {
|
||||
|
||||
function SELECT_TAB(index: number) {
|
||||
const tabs = [
|
||||
HomeScreenEvents.SELECT_MY_VIDS,
|
||||
HomeScreenEvents.SELECT_RECEIVED_VIDS,
|
||||
HomeScreenEvents.SELECT_MY_VCS,
|
||||
HomeScreenEvents.SELECT_RECEIVED_VCS,
|
||||
HomeScreenEvents.SELECT_HISTORY,
|
||||
];
|
||||
service.send(tabs[index]());
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { ActorRefFrom, EventFrom, send, spawn, StateFrom } from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { AppServices } from '../../shared/GlobalContext';
|
||||
import {
|
||||
createHistoryTabMachine,
|
||||
HistoryTabMachine,
|
||||
} from './HistoryTabMachine';
|
||||
import { createMyVidsTabMachine, MyVidsTabMachine } from './MyVidsTabMachine';
|
||||
import { createMyVcsTabMachine, MyVcsTabMachine } from './MyVcsTabMachine';
|
||||
import {
|
||||
createReceivedVidsTabMachine,
|
||||
ReceivedVidsTabMachine,
|
||||
} from './ReceivedVidsTabMachine';
|
||||
createReceivedVcsTabMachine,
|
||||
ReceivedVcsTabMachine,
|
||||
} from './ReceivedVcsTabMachine';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
serviceRefs: {} as AppServices,
|
||||
tabRefs: {
|
||||
myVids: {} as ActorRefFrom<typeof MyVidsTabMachine>,
|
||||
receivedVids: {} as ActorRefFrom<typeof ReceivedVidsTabMachine>,
|
||||
myVcs: {} as ActorRefFrom<typeof MyVcsTabMachine>,
|
||||
receivedVcs: {} as ActorRefFrom<typeof ReceivedVcsTabMachine>,
|
||||
history: {} as ActorRefFrom<typeof HistoryTabMachine>,
|
||||
},
|
||||
selectedVid: null as ActorRefFrom<typeof vidItemMachine>,
|
||||
selectedVc: null as ActorRefFrom<typeof vcItemMachine>,
|
||||
activeTab: 0,
|
||||
},
|
||||
{
|
||||
events: {
|
||||
SELECT_MY_VIDS: () => ({}),
|
||||
SELECT_RECEIVED_VIDS: () => ({}),
|
||||
SELECT_MY_VCS: () => ({}),
|
||||
SELECT_RECEIVED_VCS: () => ({}),
|
||||
SELECT_HISTORY: () => ({}),
|
||||
VIEW_VID: (vidItemActor: ActorRefFrom<typeof vidItemMachine>) => ({
|
||||
vidItemActor,
|
||||
VIEW_VC: (vcItemActor: ActorRefFrom<typeof vcItemMachine>) => ({
|
||||
vcItemActor,
|
||||
}),
|
||||
DISMISS_MODAL: () => ({}),
|
||||
},
|
||||
@@ -38,7 +38,7 @@ const model = createModel(
|
||||
|
||||
export const HomeScreenEvents = model.events;
|
||||
|
||||
type ViewVidEvent = EventFrom<typeof model, 'VIEW_VID'>;
|
||||
type ViewVcEvent = EventFrom<typeof model, 'VIEW_VC'>;
|
||||
|
||||
export const HomeScreenMachine = model.createMachine(
|
||||
{
|
||||
@@ -50,36 +50,36 @@ export const HomeScreenMachine = model.createMachine(
|
||||
id: 'tabs',
|
||||
initial: 'init',
|
||||
on: {
|
||||
SELECT_MY_VIDS: '.myVids',
|
||||
SELECT_RECEIVED_VIDS: '.receivedVids',
|
||||
SELECT_MY_VCS: '.myVcs',
|
||||
SELECT_RECEIVED_VCS: '.receivedVcs',
|
||||
SELECT_HISTORY: '.history',
|
||||
},
|
||||
states: {
|
||||
init: {
|
||||
entry: ['spawnTabActors'],
|
||||
after: {
|
||||
100: 'myVids',
|
||||
100: 'myVcs',
|
||||
},
|
||||
},
|
||||
myVids: {
|
||||
myVcs: {
|
||||
entry: [setActiveTab(0)],
|
||||
on: {
|
||||
DISMISS_MODAL: {
|
||||
actions: [
|
||||
send('DISMISS', {
|
||||
to: (context) => context.tabRefs.myVids,
|
||||
to: (context) => context.tabRefs.myVcs,
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
receivedVids: {
|
||||
receivedVcs: {
|
||||
entry: [setActiveTab(1)],
|
||||
on: {
|
||||
DISMISS_MODAL: {
|
||||
actions: [
|
||||
send('DISMISS', {
|
||||
to: (context) => context.tabRefs.receivedVids,
|
||||
to: (context) => context.tabRefs.receivedVcs,
|
||||
}),
|
||||
],
|
||||
},
|
||||
@@ -94,15 +94,15 @@ export const HomeScreenMachine = model.createMachine(
|
||||
initial: 'none',
|
||||
states: {
|
||||
none: {
|
||||
entry: ['resetSelectedVid'],
|
||||
entry: ['resetSelectedVc'],
|
||||
on: {
|
||||
VIEW_VID: {
|
||||
target: 'viewingVid',
|
||||
actions: ['setSelectedVid'],
|
||||
VIEW_VC: {
|
||||
target: 'viewingVc',
|
||||
actions: ['setSelectedVc'],
|
||||
},
|
||||
},
|
||||
},
|
||||
viewingVid: {
|
||||
viewingVc: {
|
||||
on: {
|
||||
DISMISS_MODAL: 'none',
|
||||
},
|
||||
@@ -115,13 +115,13 @@ export const HomeScreenMachine = model.createMachine(
|
||||
actions: {
|
||||
spawnTabActors: model.assign({
|
||||
tabRefs: (context) => ({
|
||||
myVids: spawn(
|
||||
createMyVidsTabMachine(context.serviceRefs),
|
||||
'myVidsTab'
|
||||
myVcs: spawn(
|
||||
createMyVcsTabMachine(context.serviceRefs),
|
||||
'MyVcsTab'
|
||||
),
|
||||
receivedVids: spawn(
|
||||
createReceivedVidsTabMachine(context.serviceRefs),
|
||||
'receivedVidsTab'
|
||||
receivedVcs: spawn(
|
||||
createReceivedVcsTabMachine(context.serviceRefs),
|
||||
'receivedVcsTab'
|
||||
),
|
||||
history: spawn(
|
||||
createHistoryTabMachine(context.serviceRefs),
|
||||
@@ -130,12 +130,12 @@ export const HomeScreenMachine = model.createMachine(
|
||||
}),
|
||||
}),
|
||||
|
||||
setSelectedVid: model.assign({
|
||||
selectedVid: (_, event: ViewVidEvent) => event.vidItemActor,
|
||||
setSelectedVc: model.assign({
|
||||
selectedVc: (_, event: ViewVcEvent) => event.vcItemActor,
|
||||
}),
|
||||
|
||||
resetSelectedVid: model.assign({
|
||||
selectedVid: null,
|
||||
resetSelectedVc: model.assign({
|
||||
selectedVc: null,
|
||||
}),
|
||||
},
|
||||
}
|
||||
@@ -151,12 +151,12 @@ export function selectActiveTab(state: State) {
|
||||
return state.context.activeTab;
|
||||
}
|
||||
|
||||
export function selectSelectedVid(state: State) {
|
||||
return state.context.selectedVid;
|
||||
export function selectSelectedVc(state: State) {
|
||||
return state.context.selectedVc;
|
||||
}
|
||||
|
||||
export function selectViewingVid(state: State) {
|
||||
return state.matches('modals.viewingVid');
|
||||
export function selectViewingVc(state: State) {
|
||||
return state.matches('modals.viewingVc');
|
||||
}
|
||||
|
||||
export function selectTabsLoaded(state: State) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import { MessageOverlay } from '../../../components/MessageOverlay';
|
||||
import { AddVidModalProps, useAddVidModal } from './AddVidModalController';
|
||||
import { AddVcModalProps, useAddVcModal } from './AddVcModalController';
|
||||
import { OtpVerificationModal } from './OtpVerificationModal';
|
||||
import { IdInputModal } from './IdInputModal';
|
||||
|
||||
export const AddVidModal: React.FC<AddVidModalProps> = (props) => {
|
||||
const controller = useAddVidModal(props);
|
||||
export const AddVcModal: React.FC<AddVcModalProps> = (props) => {
|
||||
const controller = useAddVcModal(props);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import {
|
||||
AddVidModalEvents,
|
||||
AddVidModalMachine,
|
||||
AddVcModalEvents,
|
||||
AddVcModalMachine,
|
||||
selectIsAcceptingOtpInput,
|
||||
selectIsRequestingCredential,
|
||||
selectOtpError,
|
||||
selectIsAcceptingIdInput,
|
||||
} from './AddVidModalMachine';
|
||||
} from './AddVcModalMachine';
|
||||
|
||||
export function useAddVidModal({ service }: AddVidModalProps) {
|
||||
export function useAddVcModal({ service }: AddVcModalProps) {
|
||||
return {
|
||||
isRequestingCredential: useSelector(service, selectIsRequestingCredential),
|
||||
|
||||
@@ -18,12 +18,12 @@ export function useAddVidModal({ service }: AddVidModalProps) {
|
||||
isAcceptingUinInput: useSelector(service, selectIsAcceptingIdInput),
|
||||
isAcceptingOtpInput: useSelector(service, selectIsAcceptingOtpInput),
|
||||
|
||||
INPUT_OTP: (otp: string) => service.send(AddVidModalEvents.INPUT_OTP(otp)),
|
||||
INPUT_OTP: (otp: string) => service.send(AddVcModalEvents.INPUT_OTP(otp)),
|
||||
|
||||
DISMISS: () => service.send(AddVidModalEvents.DISMISS()),
|
||||
DISMISS: () => service.send(AddVcModalEvents.DISMISS()),
|
||||
};
|
||||
}
|
||||
|
||||
export interface AddVidModalProps {
|
||||
service: ActorRefFrom<typeof AddVidModalMachine>;
|
||||
export interface AddVcModalProps {
|
||||
service: ActorRefFrom<typeof AddVcModalMachine>;
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { BackendResponseError, request } from '../../../shared/request';
|
||||
import { VID_ITEM_STORE_KEY } from '../../../shared/constants';
|
||||
import { VC_ITEM_STORE_KEY } from '../../../shared/constants';
|
||||
import { VcIdType } from '../../../types/vc';
|
||||
|
||||
const model = createModel(
|
||||
@@ -35,16 +35,16 @@ const model = createModel(
|
||||
}
|
||||
);
|
||||
|
||||
export const AddVidModalEvents = model.events;
|
||||
export const AddVcModalEvents = model.events;
|
||||
|
||||
type ReadyEvent = EventFrom<typeof model, 'READY'>;
|
||||
type InputIdEvent = EventFrom<typeof model, 'INPUT_ID'>;
|
||||
type InputOtpEvent = EventFrom<typeof model, 'INPUT_OTP'>;
|
||||
type SelectIdTypeEvent = EventFrom<typeof model, 'SELECT_ID_TYPE'>;
|
||||
|
||||
export const AddVidModalMachine = model.createMachine(
|
||||
export const AddVcModalMachine = model.createMachine(
|
||||
{
|
||||
id: 'AddVidModal',
|
||||
id: 'AddVcModal',
|
||||
context: model.initialContext,
|
||||
initial: 'acceptingIdInput',
|
||||
states: {
|
||||
@@ -162,7 +162,7 @@ export const AddVidModalMachine = model.createMachine(
|
||||
},
|
||||
done: {
|
||||
type: 'final',
|
||||
data: (context) => VID_ITEM_STORE_KEY(context),
|
||||
data: (context) => VC_ITEM_STORE_KEY(context),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -254,7 +254,7 @@ export const AddVidModalMachine = model.createMachine(
|
||||
}
|
||||
);
|
||||
|
||||
type State = StateFrom<typeof AddVidModalMachine>;
|
||||
type State = StateFrom<typeof AddVcModalMachine>;
|
||||
|
||||
export function selectId(state: State) {
|
||||
return state.context.id;
|
||||
@@ -1,21 +1,21 @@
|
||||
import React from 'react';
|
||||
import { Button, Column, Text } from '../../../components/ui';
|
||||
import { Modal, ModalProps } from '../../../components/ui/Modal';
|
||||
import { useDownloadingvidModal } from './DownloadingVidModalController';
|
||||
import { useDownloadingvcModal } from './DownloadingVcModalController';
|
||||
|
||||
export const DownloadingVidModal: React.FC<ModalProps> = (props) => {
|
||||
const controller = useDownloadingvidModal();
|
||||
export const DownloadingVcModal: React.FC<ModalProps> = (props) => {
|
||||
const controller = useDownloadingvcModal();
|
||||
|
||||
return (
|
||||
<Modal isVisible={props.isVisible} onDismiss={props.onDismiss}>
|
||||
<Column fill padding="32 24" align="space-between">
|
||||
<Column fill>
|
||||
<Text weight="semibold" align="center">
|
||||
Downloading your {controller.vidLabel.singular}
|
||||
Downloading your {controller.VCLabel.singular}
|
||||
</Text>
|
||||
<Text align="center">
|
||||
This may take some time, we will{'\n'}notify you when your{' '}
|
||||
{controller.vidLabel.singular} has been{'\n'}downloaded and is
|
||||
{controller.VCLabel.singular} has been{'\n'}downloaded and is
|
||||
available
|
||||
</Text>
|
||||
</Column>
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { selectVidLabel } from '../../../machines/settings';
|
||||
import { selectVCLabel } from '../../../machines/settings';
|
||||
import { GlobalContext } from '../../../shared/GlobalContext';
|
||||
|
||||
export function useDownloadingvidModal() {
|
||||
export function useDownloadingvcModal() {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
|
||||
return {
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
};
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export const IdInputModal: React.FC<IdInputModalProps> = (props) => {
|
||||
<Column fill align="space-between" padding="32 24">
|
||||
<Text align="center">
|
||||
Enter the MOSIP-provided UIN or VID{'\n'}of the{' '}
|
||||
{controller.vidLabel.singular} you wish to retrieve
|
||||
{controller.VCLabel.singular} you wish to retrieve
|
||||
</Text>
|
||||
<Column>
|
||||
<Row crossAlign="flex-end">
|
||||
@@ -55,7 +55,7 @@ export const IdInputModal: React.FC<IdInputModalProps> = (props) => {
|
||||
</Column>
|
||||
</Row>
|
||||
<Button
|
||||
title={`Generate ${controller.vidLabel.singular}`}
|
||||
title={`Generate ${controller.VCLabel.singular}`}
|
||||
margin="24 0 0 0"
|
||||
onPress={controller.VALIDATE_INPUT}
|
||||
loading={controller.isRequestingOtp}
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useContext } from 'react';
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { selectVidLabel } from '../../../machines/settings';
|
||||
import { selectVCLabel } from '../../../machines/settings';
|
||||
import { GlobalContext } from '../../../shared/GlobalContext';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { TextInput } from 'react-native';
|
||||
import { ModalProps } from '../../../components/ui/Modal';
|
||||
import {
|
||||
AddVidModalEvents,
|
||||
AddVidModalMachine,
|
||||
AddVcModalEvents,
|
||||
AddVcModalMachine,
|
||||
selectIsAcceptingOtpInput,
|
||||
selectIsInvalid,
|
||||
selectIsRequestingOtp,
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
selectIdError,
|
||||
selectIdInputRef,
|
||||
selectIdType,
|
||||
} from './AddVidModalMachine';
|
||||
} from './AddVcModalMachine';
|
||||
import { VcIdType } from '../../../types/vc';
|
||||
|
||||
export function useIdInputModal({ service }: IdInputModalProps) {
|
||||
@@ -27,7 +27,7 @@ export function useIdInputModal({ service }: IdInputModalProps) {
|
||||
id: useSelector(service, selectId),
|
||||
idType: useSelector(service, selectIdType),
|
||||
idInputRef: useSelector(service, selectIdInputRef),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
idError: useSelector(service, selectIdError),
|
||||
otpError: useSelector(service, selectOtpError),
|
||||
|
||||
@@ -35,16 +35,16 @@ export function useIdInputModal({ service }: IdInputModalProps) {
|
||||
isAcceptingOtpInput: useSelector(service, selectIsAcceptingOtpInput),
|
||||
isRequestingOtp: useSelector(service, selectIsRequestingOtp),
|
||||
|
||||
INPUT_ID: (id: string) => service.send(AddVidModalEvents.INPUT_ID(id)),
|
||||
INPUT_ID: (id: string) => service.send(AddVcModalEvents.INPUT_ID(id)),
|
||||
SELECT_ID_TYPE: (selectedValue: VcIdType) =>
|
||||
service.send(AddVidModalEvents.SELECT_ID_TYPE(selectedValue)),
|
||||
VALIDATE_INPUT: () => service.send(AddVidModalEvents.VALIDATE_INPUT()),
|
||||
INPUT_OTP: (otp: string) => service.send(AddVidModalEvents.INPUT_OTP(otp)),
|
||||
READY: (input: TextInput) => service.send(AddVidModalEvents.READY(input)),
|
||||
DISMISS: () => service.send(AddVidModalEvents.DISMISS()),
|
||||
service.send(AddVcModalEvents.SELECT_ID_TYPE(selectedValue)),
|
||||
VALIDATE_INPUT: () => service.send(AddVcModalEvents.VALIDATE_INPUT()),
|
||||
INPUT_OTP: (otp: string) => service.send(AddVcModalEvents.INPUT_OTP(otp)),
|
||||
READY: (input: TextInput) => service.send(AddVcModalEvents.READY(input)),
|
||||
DISMISS: () => service.send(AddVcModalEvents.DISMISS()),
|
||||
};
|
||||
}
|
||||
|
||||
export interface IdInputModalProps extends ModalProps {
|
||||
service: ActorRefFrom<typeof AddVidModalMachine>;
|
||||
service: ActorRefFrom<typeof AddVcModalMachine>;
|
||||
}
|
||||
@@ -1,60 +1,60 @@
|
||||
import React from 'react';
|
||||
import { Button, Column, Text, Centered } from '../../components/ui';
|
||||
import { VidItem } from '../../components/VidItem';
|
||||
import { VcItem } from '../../components/VcItem';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { RefreshControl } from 'react-native';
|
||||
import { useMyVidsTab } from './MyVidsTabController';
|
||||
import { useMyVcsTab } from './MyVcsTabController';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import { AddVidModal } from './MyVids/AddVidModal';
|
||||
import { DownloadingVidModal } from './MyVids/DownloadingVidModal';
|
||||
import { AddVcModal } from './MyVcs/AddVcModal';
|
||||
import { DownloadingVcModal } from './MyVcs/DownloadingVcModal';
|
||||
import { OnboardingOverlay } from './OnboardingOverlay';
|
||||
|
||||
export const MyVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
const controller = useMyVidsTab(props);
|
||||
export const MyVcsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
const controller = useMyVcsTab(props);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Column fill style={{ display: props.isVisible ? 'flex' : 'none' }}>
|
||||
<Column fill padding="32 24">
|
||||
{controller.vidKeys.length > 0 && (
|
||||
{controller.vcKeys.length > 0 && (
|
||||
<React.Fragment>
|
||||
<Column
|
||||
scroll
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={controller.isRefreshingVids}
|
||||
refreshing={controller.isRefreshingVcs}
|
||||
onRefresh={controller.REFRESH}
|
||||
/>
|
||||
}>
|
||||
{controller.vidKeys.map((vidKey) => (
|
||||
<VidItem
|
||||
key={vidKey}
|
||||
vidKey={vidKey}
|
||||
{controller.vcKeys.map((vcKey) => (
|
||||
<VcItem
|
||||
key={vcKey}
|
||||
vcKey={vcKey}
|
||||
margin="0 2 8 2"
|
||||
onPress={controller.VIEW_VID}
|
||||
onPress={controller.VIEW_VC}
|
||||
/>
|
||||
))}
|
||||
</Column>
|
||||
<Column elevation={2} margin="0 2">
|
||||
<Button
|
||||
type="clear"
|
||||
disabled={controller.isRefreshingVids}
|
||||
title={`Add ${controller.vidLabel.singular}`}
|
||||
onPress={controller.ADD_VID}
|
||||
disabled={controller.isRefreshingVcs}
|
||||
title={`Add ${controller.VCLabel.singular}`}
|
||||
onPress={controller.ADD_VC}
|
||||
/>
|
||||
</Column>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{controller.vidKeys.length === 0 && (
|
||||
{controller.vcKeys.length === 0 && (
|
||||
<React.Fragment>
|
||||
<Centered fill>
|
||||
<Text weight="semibold" margin="0 0 8 0">
|
||||
Generate your {controller.vidLabel.plural}
|
||||
Generate your {controller.VCLabel.plural}
|
||||
</Text>
|
||||
<Text color={Colors.Grey} align="center">
|
||||
Tap on "Add {controller.vidLabel.singular}" below to{'\n'}
|
||||
download your {controller.vidLabel.singular}
|
||||
Tap on "Add {controller.VCLabel.singular}" below to{'\n'}
|
||||
download your {controller.VCLabel.singular}
|
||||
</Text>
|
||||
<Icon
|
||||
name="arrow-downward"
|
||||
@@ -63,20 +63,20 @@ export const MyVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
/>
|
||||
</Centered>
|
||||
<Button
|
||||
disabled={controller.isRefreshingVids}
|
||||
title={`Add ${controller.vidLabel.singular}`}
|
||||
onPress={controller.ADD_VID}
|
||||
disabled={controller.isRefreshingVcs}
|
||||
title={`Add ${controller.VCLabel.singular}`}
|
||||
onPress={controller.ADD_VC}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Column>
|
||||
</Column>
|
||||
|
||||
{controller.AddVidModalService && (
|
||||
<AddVidModal service={controller.AddVidModalService} />
|
||||
{controller.AddVcModalService && (
|
||||
<AddVcModal service={controller.AddVcModalService} />
|
||||
)}
|
||||
{controller.isRequestSuccessful && (
|
||||
<DownloadingVidModal
|
||||
<DownloadingVcModal
|
||||
isVisible={controller.isRequestSuccessful}
|
||||
onDismiss={controller.DISMISS}
|
||||
/>
|
||||
@@ -85,7 +85,7 @@ export const MyVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
<OnboardingOverlay
|
||||
isVisible={controller.isOnboarding}
|
||||
onDone={controller.ONBOARDING_DONE}
|
||||
onAddVid={controller.ADD_VID}
|
||||
onAddVc={controller.ADD_VC}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
50
screens/Home/MyVcsTabController.ts
Normal file
50
screens/Home/MyVcsTabController.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import {
|
||||
selectIsRefreshingMyVcs,
|
||||
selectMyVcs,
|
||||
VcEvents,
|
||||
} from '../../machines/vc';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import {
|
||||
MyVcsTabEvents,
|
||||
MyVcsTabMachine,
|
||||
selectAddVcModal,
|
||||
selectIsOnboarding,
|
||||
selectIsRequestSuccessful,
|
||||
} from './MyVcsTabMachine';
|
||||
|
||||
export function useMyVcsTab(props: HomeScreenTabProps) {
|
||||
const service = props.service as ActorRefFrom<typeof MyVcsTabMachine>;
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
return {
|
||||
service,
|
||||
AddVcModalService: useSelector(service, selectAddVcModal),
|
||||
|
||||
vcKeys: useSelector(vcService, selectMyVcs),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
|
||||
isRefreshingVcs: useSelector(vcService, selectIsRefreshingMyVcs),
|
||||
isRequestSuccessful: useSelector(service, selectIsRequestSuccessful),
|
||||
isOnboarding: useSelector(service, selectIsOnboarding),
|
||||
|
||||
DISMISS: () => service.send(MyVcsTabEvents.DISMISS()),
|
||||
|
||||
ADD_VC: () => service.send(MyVcsTabEvents.ADD_VC()),
|
||||
|
||||
REFRESH: () => vcService.send(VcEvents.REFRESH_MY_VCS()),
|
||||
|
||||
VIEW_VC: (vcRef: ActorRefFrom<typeof vcItemMachine>) => {
|
||||
return service.send(MyVcsTabEvents.VIEW_VC(vcRef));
|
||||
},
|
||||
|
||||
ONBOARDING_DONE: () => service.send(MyVcsTabEvents.ONBOARDING_DONE()),
|
||||
};
|
||||
}
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
} from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { StoreEvents, StoreResponseEvent } from '../../machines/store';
|
||||
import { VidEvents } from '../../machines/vid';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { VcEvents } from '../../machines/vc';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { AppServices } from '../../shared/GlobalContext';
|
||||
import {
|
||||
MY_VIDS_STORE_KEY,
|
||||
MY_VCS_STORE_KEY,
|
||||
ONBOARDING_STATUS_STORE_KEY,
|
||||
} from '../../shared/constants';
|
||||
import { AddVidModalMachine } from './MyVids/AddVidModalMachine';
|
||||
import { AddVcModalMachine } from './MyVcs/AddVcModalMachine';
|
||||
|
||||
const model = createModel(
|
||||
{
|
||||
@@ -24,24 +24,24 @@ const model = createModel(
|
||||
{
|
||||
events: {
|
||||
REFRESH: () => ({}),
|
||||
VIEW_VID: (vidItemActor: ActorRefFrom<typeof vidItemMachine>) => ({
|
||||
vidItemActor,
|
||||
VIEW_VC: (vcItemActor: ActorRefFrom<typeof vcItemMachine>) => ({
|
||||
vcItemActor,
|
||||
}),
|
||||
DISMISS: () => ({}),
|
||||
STORE_RESPONSE: (response?: any) => ({ response }),
|
||||
ADD_VID: () => ({}),
|
||||
ADD_VC: () => ({}),
|
||||
ONBOARDING_DONE: () => ({}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const MyVidsTabEvents = model.events;
|
||||
export const MyVcsTabEvents = model.events;
|
||||
|
||||
type ViewVidEvent = EventFrom<typeof model, 'VIEW_VID'>;
|
||||
type ViewVcEvent = EventFrom<typeof model, 'VIEW_VC'>;
|
||||
|
||||
export const MyVidsTabMachine = model.createMachine(
|
||||
export const MyVcsTabMachine = model.createMachine(
|
||||
{
|
||||
id: 'MyVidsTab',
|
||||
id: 'MyVcsTab',
|
||||
context: model.initialContext,
|
||||
initial: 'checkingOnboardingStatus',
|
||||
states: {
|
||||
@@ -56,8 +56,8 @@ export const MyVidsTabMachine = model.createMachine(
|
||||
},
|
||||
onboarding: {
|
||||
on: {
|
||||
ADD_VID: {
|
||||
target: 'addingVid',
|
||||
ADD_VC: {
|
||||
target: 'addingVc',
|
||||
actions: ['completeOnboarding'],
|
||||
},
|
||||
ONBOARDING_DONE: {
|
||||
@@ -69,42 +69,42 @@ export const MyVidsTabMachine = model.createMachine(
|
||||
idle: {
|
||||
id: 'idle',
|
||||
on: {
|
||||
ADD_VID: 'addingVid',
|
||||
VIEW_VID: 'viewingVid',
|
||||
ADD_VC: 'addingVc',
|
||||
VIEW_VC: 'viewingVc',
|
||||
},
|
||||
},
|
||||
viewingVid: {
|
||||
viewingVc: {
|
||||
entry: [
|
||||
sendParent((_, event: ViewVidEvent) =>
|
||||
model.events.VIEW_VID(event.vidItemActor)
|
||||
sendParent((_, event: ViewVcEvent) =>
|
||||
model.events.VIEW_VC(event.vcItemActor)
|
||||
),
|
||||
],
|
||||
on: {
|
||||
DISMISS: 'idle',
|
||||
},
|
||||
},
|
||||
addingVid: {
|
||||
addingVc: {
|
||||
invoke: {
|
||||
id: 'AddVidModal',
|
||||
src: AddVidModalMachine,
|
||||
id: 'AddVcModal',
|
||||
src: AddVcModalMachine,
|
||||
onDone: '.storing',
|
||||
},
|
||||
on: {
|
||||
DISMISS: 'idle',
|
||||
},
|
||||
initial: 'waitingForVidKey',
|
||||
initial: 'waitingForvcKey',
|
||||
states: {
|
||||
waitingForVidKey: {},
|
||||
waitingForvcKey: {},
|
||||
storing: {
|
||||
entry: ['storeVidItem'],
|
||||
entry: ['storeVcItem'],
|
||||
on: {
|
||||
STORE_RESPONSE: {
|
||||
target: 'addVidSuccessful',
|
||||
actions: ['sendVidAdded'],
|
||||
target: 'addVcSuccessful',
|
||||
actions: ['sendVcAdded'],
|
||||
},
|
||||
},
|
||||
},
|
||||
addVidSuccessful: {
|
||||
addVcSuccessful: {
|
||||
on: {
|
||||
DISMISS: '#idle',
|
||||
},
|
||||
@@ -125,17 +125,17 @@ export const MyVidsTabMachine = model.createMachine(
|
||||
{ to: (context) => context.serviceRefs.store }
|
||||
),
|
||||
|
||||
storeVidItem: send(
|
||||
storeVcItem: send(
|
||||
(_, _event: any) => {
|
||||
const event: DoneInvokeEvent<string> = _event;
|
||||
return StoreEvents.PREPEND(MY_VIDS_STORE_KEY, event.data);
|
||||
return StoreEvents.PREPEND(MY_VCS_STORE_KEY, event.data);
|
||||
},
|
||||
{ to: (context) => context.serviceRefs.store }
|
||||
),
|
||||
|
||||
sendVidAdded: send(
|
||||
(_, event: StoreResponseEvent) => VidEvents.VID_ADDED(event.response),
|
||||
{ to: (context) => context.serviceRefs.vid }
|
||||
sendVcAdded: send(
|
||||
(_, event: StoreResponseEvent) => VcEvents.VC_ADDED(event.response),
|
||||
{ to: (context) => context.serviceRefs.vc }
|
||||
),
|
||||
},
|
||||
|
||||
@@ -147,17 +147,17 @@ export const MyVidsTabMachine = model.createMachine(
|
||||
}
|
||||
);
|
||||
|
||||
export function createMyVidsTabMachine(serviceRefs: AppServices) {
|
||||
return MyVidsTabMachine.withContext({
|
||||
...MyVidsTabMachine.context,
|
||||
export function createMyVcsTabMachine(serviceRefs: AppServices) {
|
||||
return MyVcsTabMachine.withContext({
|
||||
...MyVcsTabMachine.context,
|
||||
serviceRefs,
|
||||
});
|
||||
}
|
||||
|
||||
type State = StateFrom<typeof MyVidsTabMachine>;
|
||||
type State = StateFrom<typeof MyVcsTabMachine>;
|
||||
|
||||
export function selectAddVidModal(state: State) {
|
||||
return state.children.AddVidModal as ActorRefFrom<typeof AddVidModalMachine>;
|
||||
export function selectAddVcModal(state: State) {
|
||||
return state.children.AddVcModal as ActorRefFrom<typeof AddVcModalMachine>;
|
||||
}
|
||||
|
||||
export function selectIsOnboarding(state: State) {
|
||||
@@ -165,5 +165,5 @@ export function selectIsOnboarding(state: State) {
|
||||
}
|
||||
|
||||
export function selectIsRequestSuccessful(state: State) {
|
||||
return state.matches('addingVid.addVidSuccessful');
|
||||
return state.matches('addingVc.addVcSuccessful');
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import {
|
||||
selectIsRefreshingMyVids,
|
||||
selectMyVids,
|
||||
VidEvents,
|
||||
} from '../../machines/vid';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import {
|
||||
MyVidsTabEvents,
|
||||
MyVidsTabMachine,
|
||||
selectAddVidModal,
|
||||
selectIsOnboarding,
|
||||
selectIsRequestSuccessful,
|
||||
} from './MyVidsTabMachine';
|
||||
|
||||
export function useMyVidsTab(props: HomeScreenTabProps) {
|
||||
const service = props.service as ActorRefFrom<typeof MyVidsTabMachine>;
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidService = appService.children.get('vid');
|
||||
|
||||
return {
|
||||
service,
|
||||
AddVidModalService: useSelector(service, selectAddVidModal),
|
||||
|
||||
vidKeys: useSelector(vidService, selectMyVids),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
|
||||
isRefreshingVids: useSelector(vidService, selectIsRefreshingMyVids),
|
||||
isRequestSuccessful: useSelector(service, selectIsRequestSuccessful),
|
||||
isOnboarding: useSelector(service, selectIsOnboarding),
|
||||
|
||||
DISMISS: () => service.send(MyVidsTabEvents.DISMISS()),
|
||||
|
||||
ADD_VID: () => service.send(MyVidsTabEvents.ADD_VID()),
|
||||
|
||||
REFRESH: () => vidService.send(VidEvents.REFRESH_MY_VIDS()),
|
||||
|
||||
VIEW_VID: (vidRef: ActorRefFrom<typeof vidItemMachine>) => {
|
||||
return service.send(MyVidsTabEvents.VIEW_VID(vidRef));
|
||||
},
|
||||
|
||||
ONBOARDING_DONE: () => service.send(MyVidsTabEvents.ONBOARDING_DONE()),
|
||||
};
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { Button, Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
@@ -57,30 +57,30 @@ export const OnboardingOverlay: React.FC<OnboardingProps> = (props) => {
|
||||
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidLabel = useSelector(settingsService, selectVidLabel);
|
||||
const VCLabel = useSelector(settingsService, selectVCLabel);
|
||||
|
||||
const slides = [
|
||||
{
|
||||
key: 'one',
|
||||
title: 'Welcome!',
|
||||
text: `Keep your digital credential with you at all times. To get started, add ${vidLabel.plural} to your profile.`,
|
||||
text: `Keep your digital credential with you at all times. To get started, add ${VCLabel.plural} to your profile.`,
|
||||
},
|
||||
{
|
||||
key: 'two',
|
||||
title: `${vidLabel.singular} management`,
|
||||
text: `Once generated, ${vidLabel.plural} are safely stored on your mobile and can be renamed or shared at any time.`,
|
||||
title: `${VCLabel.singular} management`,
|
||||
text: `Once generated, ${VCLabel.plural} are safely stored on your mobile and can be renamed or shared at any time.`,
|
||||
},
|
||||
{
|
||||
key: 'three',
|
||||
title: 'Easy sharing',
|
||||
text: `Share and receive ${vidLabel.plural} switfly using your phone camera to scan QR codes.`,
|
||||
text: `Share and receive ${VCLabel.plural} switfly using your phone camera to scan QR codes.`,
|
||||
footer: (
|
||||
<Button
|
||||
margin="24 0 0 0"
|
||||
raised
|
||||
type="outline"
|
||||
title={`Get started and add ${vidLabel.singular}`}
|
||||
onPress={props.onAddVid}
|
||||
title={`Get started and add ${VCLabel.singular}`}
|
||||
onPress={props.onAddVc}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -147,5 +147,5 @@ export const OnboardingOverlay: React.FC<OnboardingProps> = (props) => {
|
||||
interface OnboardingProps {
|
||||
isVisible: boolean;
|
||||
onDone: () => void;
|
||||
onAddVid: () => void;
|
||||
onAddVc: () => void;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { RefreshControl } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { Centered, Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { VidItem } from '../../components/VidItem';
|
||||
import { VcItem } from '../../components/VcItem';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import { useReceivedVidsTab } from './ReceivedVidsTabController';
|
||||
import { useReceivedVcsTab } from './ReceivedVcsTabController';
|
||||
|
||||
export const ReceivedVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
const controller = useReceivedVidsTab(props);
|
||||
export const ReceivedVcsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
const controller = useReceivedVcsTab(props);
|
||||
|
||||
return (
|
||||
<Column fill style={{ display: props.isVisible ? 'flex' : 'none' }}>
|
||||
@@ -17,19 +17,19 @@ export const ReceivedVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
padding="32 24"
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={controller.isRefreshingVids}
|
||||
refreshing={controller.isRefreshingVcs}
|
||||
onRefresh={controller.REFRESH}
|
||||
/>
|
||||
}>
|
||||
{controller.vidKeys.map((vidKey) => (
|
||||
<VidItem
|
||||
key={vidKey}
|
||||
vidKey={vidKey}
|
||||
{controller.vcKeys.map((vcKey) => (
|
||||
<VcItem
|
||||
key={vcKey}
|
||||
vcKey={vcKey}
|
||||
margin="0 2 8 2"
|
||||
onPress={controller.VIEW_VID}
|
||||
onPress={controller.VIEW_VC}
|
||||
/>
|
||||
))}
|
||||
{controller.vidKeys.length === 0 && (
|
||||
{controller.vcKeys.length === 0 && (
|
||||
<React.Fragment>
|
||||
<Centered fill>
|
||||
<Icon
|
||||
@@ -38,10 +38,10 @@ export const ReceivedVidsTab: React.FC<HomeScreenTabProps> = (props) => {
|
||||
name="sentiment-dissatisfied"
|
||||
/>
|
||||
<Text align="center" weight="semibold" margin="0 0 4 0">
|
||||
No {controller.vidLabel.plural} available yet
|
||||
No {controller.VCLabel.plural} available yet
|
||||
</Text>
|
||||
<Text align="center" color={Colors.Grey}>
|
||||
Tap on Request below to receive {controller.vidLabel.singular}
|
||||
Tap on Request below to receive {controller.VCLabel.singular}
|
||||
</Text>
|
||||
</Centered>
|
||||
</React.Fragment>
|
||||
33
screens/Home/ReceivedVcsTabController.ts
Normal file
33
screens/Home/ReceivedVcsTabController.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import {
|
||||
selectIsRefreshingReceivedVcs,
|
||||
selectReceivedVcs,
|
||||
} from '../../machines/vc';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import {
|
||||
ReceivedVcsTabEvents,
|
||||
ReceivedVcsTabMachine,
|
||||
} from './ReceivedVcsTabMachine';
|
||||
|
||||
export function useReceivedVcsTab(props: HomeScreenTabProps) {
|
||||
const service = props.service as ActorRefFrom<typeof ReceivedVcsTabMachine>;
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
return {
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
vcKeys: useSelector(vcService, selectReceivedVcs),
|
||||
|
||||
isRefreshingVcs: useSelector(vcService, selectIsRefreshingReceivedVcs),
|
||||
|
||||
VIEW_VC: (vcItemActor: ActorRefFrom<typeof vcItemMachine>) =>
|
||||
service.send(ReceivedVcsTabEvents.VIEW_VC(vcItemActor)),
|
||||
REFRESH: () => service.send(ReceivedVcsTabEvents.REFRESH()),
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
sendParent
|
||||
} from 'xstate';
|
||||
import { createModel } from 'xstate/lib/model';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { createVcItemMachine, vcItemMachine } from '../../machines/vcItem';
|
||||
import { AppServices } from '../../shared/GlobalContext';
|
||||
|
||||
const model = createModel(
|
||||
@@ -14,43 +14,43 @@ const model = createModel(
|
||||
},
|
||||
{
|
||||
events: {
|
||||
VIEW_VID: (vidItemActor: ActorRefFrom<typeof vidItemMachine>) => ({
|
||||
vidItemActor,
|
||||
VIEW_VC: (vcItemActor: ActorRefFrom<typeof vcItemMachine>) => ({
|
||||
vcItemActor,
|
||||
}),
|
||||
REFRESH: () => ({}),
|
||||
DISMISS: () => ({}),
|
||||
STORE_RESPONSE: (response?: any) => ({ response }),
|
||||
STORE_ERROR: (error: Error) => ({ error }),
|
||||
ERROR: (error: Error) => ({ error }),
|
||||
GET_RECEIVED_VIDS_RESPONSE: (vidKeys: string[]) => ({ vidKeys }),
|
||||
GET_RECEIVED_VCS_RESPONSE: (vcKeys: string[]) => ({ vcKeys }),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const ReceivedVidsTabEvents = model.events;
|
||||
export const ReceivedVcsTabEvents = model.events;
|
||||
|
||||
type ErrorEvent = EventFrom<typeof model, 'ERROR'>;
|
||||
type ViewVidEvent = EventFrom<typeof model, 'VIEW_VID'>;
|
||||
type GetReceivedVidListResponseEvent = EventFrom<
|
||||
type ViewVcEvent = EventFrom<typeof model, 'VIEW_VC'>;
|
||||
type GetReceivedVcListResponseEvent = EventFrom<
|
||||
typeof model,
|
||||
'GET_RECEIVED_VIDS_RESPONSE'
|
||||
'GET_RECEIVED_VCS_RESPONSE'
|
||||
>;
|
||||
|
||||
export const ReceivedVidsTabMachine = model.createMachine(
|
||||
export const ReceivedVcsTabMachine = model.createMachine(
|
||||
{
|
||||
id: 'ReceivedVidsTab',
|
||||
id: 'ReceivedVcsTab',
|
||||
context: model.initialContext,
|
||||
initial: 'idle',
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
VIEW_VID: 'viewingVid',
|
||||
VIEW_VC: 'viewingVc',
|
||||
},
|
||||
},
|
||||
viewingVid: {
|
||||
viewingVc: {
|
||||
entry: [
|
||||
sendParent((_, event: ViewVidEvent) =>
|
||||
model.events.VIEW_VID(event.vidItemActor)
|
||||
sendParent((_, event: ViewVcEvent) =>
|
||||
model.events.VIEW_VC(event.vcItemActor)
|
||||
),
|
||||
],
|
||||
on: {
|
||||
@@ -64,9 +64,9 @@ export const ReceivedVidsTabMachine = model.createMachine(
|
||||
}
|
||||
);
|
||||
|
||||
export function createReceivedVidsTabMachine(serviceRefs: AppServices) {
|
||||
return ReceivedVidsTabMachine.withContext({
|
||||
...ReceivedVidsTabMachine.context,
|
||||
export function createReceivedVcsTabMachine(serviceRefs: AppServices) {
|
||||
return ReceivedVcsTabMachine.withContext({
|
||||
...ReceivedVcsTabMachine.context,
|
||||
serviceRefs,
|
||||
});
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import {
|
||||
selectIsRefreshingReceivedVids,
|
||||
selectReceivedVids,
|
||||
} from '../../machines/vid';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { HomeScreenTabProps } from './HomeScreen';
|
||||
import {
|
||||
ReceivedVidsTabEvents,
|
||||
ReceivedVidsTabMachine,
|
||||
} from './ReceivedVidsTabMachine';
|
||||
|
||||
export function useReceivedVidsTab(props: HomeScreenTabProps) {
|
||||
const service = props.service as ActorRefFrom<typeof ReceivedVidsTabMachine>;
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidService = appService.children.get('vid');
|
||||
|
||||
return {
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
vidKeys: useSelector(vidService, selectReceivedVids),
|
||||
|
||||
isRefreshingVids: useSelector(vidService, selectIsRefreshingReceivedVids),
|
||||
|
||||
VIEW_VID: (vidItemActor: ActorRefFrom<typeof vidItemMachine>) =>
|
||||
service.send(ReceivedVidsTabEvents.VIEW_VID(vidItemActor)),
|
||||
REFRESH: () => service.send(ReceivedVidsTabEvents.REFRESH()),
|
||||
};
|
||||
}
|
||||
@@ -4,31 +4,31 @@ import { TextEditOverlay } from '../../components/TextEditOverlay';
|
||||
import { Column } from '../../components/ui';
|
||||
import { Modal } from '../../components/ui/Modal';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { VidDetails } from '../../components/VidDetails';
|
||||
import { useViewVidModal, ViewVidModalProps } from './ViewVidModalController';
|
||||
import { VcDetails } from '../../components/VcDetails';
|
||||
import { useViewVcModal, ViewVcModalProps } from './ViewVcModalController';
|
||||
|
||||
export const ViewVidModal: React.FC<ViewVidModalProps> = (props) => {
|
||||
const controller = useViewVidModal(props);
|
||||
export const ViewVcModal: React.FC<ViewVcModalProps> = (props) => {
|
||||
const controller = useViewVcModal(props);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={props.isVisible}
|
||||
onDismiss={props.onDismiss}
|
||||
headerTitle={controller.vid.tag || controller.vid.id}
|
||||
headerTitle={controller.vc.tag || controller.vc.id}
|
||||
headerElevation={2}
|
||||
headerRight={
|
||||
<Icon name="edit" onPress={controller.EDIT_TAG} color={Colors.Orange} />
|
||||
}>
|
||||
<Column scroll backgroundColor={Colors.LightGrey}>
|
||||
<Column>
|
||||
<VidDetails vid={controller.vid} />
|
||||
<VcDetails vc={controller.vc} />
|
||||
</Column>
|
||||
</Column>
|
||||
|
||||
<TextEditOverlay
|
||||
isVisible={controller.isEditingTag}
|
||||
label="Edit Tag"
|
||||
value={controller.vid.tag}
|
||||
value={controller.vc.tag}
|
||||
onDismiss={controller.DISMISS}
|
||||
onSave={controller.SAVE_TAG}
|
||||
/>
|
||||
25
screens/Home/ViewVcModalController.ts
Normal file
25
screens/Home/ViewVcModalController.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { ModalProps } from '../../components/ui/Modal';
|
||||
import {
|
||||
selectIsEditingTag,
|
||||
selectVc,
|
||||
VcItemEvents,
|
||||
vcItemMachine,
|
||||
} from '../../machines/vcItem';
|
||||
|
||||
export function useViewVcModal({ vcItemActor }: ViewVcModalProps) {
|
||||
return {
|
||||
vc: useSelector(vcItemActor, selectVc),
|
||||
|
||||
isEditingTag: useSelector(vcItemActor, selectIsEditingTag),
|
||||
|
||||
EDIT_TAG: () => vcItemActor.send(VcItemEvents.EDIT_TAG()),
|
||||
SAVE_TAG: (tag: string) => vcItemActor.send(VcItemEvents.SAVE_TAG(tag)),
|
||||
DISMISS: () => vcItemActor.send(VcItemEvents.DISMISS()),
|
||||
};
|
||||
}
|
||||
|
||||
export interface ViewVcModalProps extends ModalProps {
|
||||
vcItemActor: ActorRefFrom<typeof vcItemMachine>;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { ModalProps } from '../../components/ui/Modal';
|
||||
import {
|
||||
selectIsEditingTag,
|
||||
selectVid,
|
||||
VidItemEvents,
|
||||
vidItemMachine,
|
||||
} from '../../machines/vidItem';
|
||||
|
||||
export function useViewVidModal({ vidItemActor }: ViewVidModalProps) {
|
||||
return {
|
||||
vid: useSelector(vidItemActor, selectVid),
|
||||
|
||||
isEditingTag: useSelector(vidItemActor, selectIsEditingTag),
|
||||
|
||||
EDIT_TAG: () => vidItemActor.send(VidItemEvents.EDIT_TAG()),
|
||||
SAVE_TAG: (tag: string) => vidItemActor.send(VidItemEvents.SAVE_TAG(tag)),
|
||||
DISMISS: () => vidItemActor.send(VidItemEvents.DISMISS()),
|
||||
};
|
||||
}
|
||||
|
||||
export interface ViewVidModalProps extends ModalProps {
|
||||
vidItemActor: ActorRefFrom<typeof vidItemMachine>;
|
||||
}
|
||||
@@ -20,8 +20,8 @@ export const ProfileScreen: React.FC<MainRouteProps> = (props) => {
|
||||
/>
|
||||
<EditableListItem
|
||||
label="VC Label"
|
||||
value={controller.vidLabel.singular}
|
||||
onEdit={controller.UPDATE_VID_LABEL}
|
||||
value={controller.VCLabel.singular}
|
||||
onEdit={controller.UPDATE_VC_LABEL}
|
||||
/>
|
||||
<ListItem bottomDivider>
|
||||
<ListItem.Content>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AuthEvents, selectCanUseBiometrics } from '../../machines/auth';
|
||||
import {
|
||||
selectBiometricUnlockEnabled,
|
||||
selectName,
|
||||
selectVidLabel,
|
||||
selectVCLabel,
|
||||
SettingsEvents,
|
||||
} from '../../machines/settings';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
@@ -17,7 +17,7 @@ export function useProfileScreen({ navigation }: MainRouteProps) {
|
||||
|
||||
return {
|
||||
name: useSelector(settingsService, selectName),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
isBiometricUnlockEnabled: useSelector(
|
||||
settingsService,
|
||||
selectBiometricUnlockEnabled
|
||||
@@ -27,8 +27,8 @@ export function useProfileScreen({ navigation }: MainRouteProps) {
|
||||
UPDATE_NAME: (name: string) =>
|
||||
settingsService.send(SettingsEvents.UPDATE_NAME(name)),
|
||||
|
||||
UPDATE_VID_LABEL: (label: string) =>
|
||||
settingsService.send(SettingsEvents.UPDATE_VID_LABEL(label)),
|
||||
UPDATE_VC_LABEL: (label: string) =>
|
||||
settingsService.send(SettingsEvents.UPDATE_VC_LABEL(label)),
|
||||
|
||||
LOGOUT: () => {
|
||||
authService.send(AuthEvents.LOGOUT());
|
||||
|
||||
@@ -2,12 +2,12 @@ import React from 'react';
|
||||
import { DeviceInfoList } from '../../components/DeviceInfoList';
|
||||
import { Button, Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { VidDetails } from '../../components/VidDetails';
|
||||
import { VcDetails } from '../../components/VcDetails';
|
||||
import { Modal, ModalProps } from '../../components/ui/Modal';
|
||||
import { useReceiveVidModal } from './ReceiveVidModalController';
|
||||
import { useReceiveVcModal } from './ReceiveVcModalController';
|
||||
|
||||
export const ReceiveVidModal: React.FC<ReceveVidModalProps> = (props) => {
|
||||
const controller = useReceiveVidModal();
|
||||
export const ReceiveVcModal: React.FC<ReceveVcModalProps> = (props) => {
|
||||
const controller = useReceiveVcModal();
|
||||
|
||||
return (
|
||||
<Modal {...props}>
|
||||
@@ -15,13 +15,13 @@ export const ReceiveVidModal: React.FC<ReceveVidModalProps> = (props) => {
|
||||
<Column>
|
||||
<DeviceInfoList of="sender" deviceInfo={controller.senderInfo} />
|
||||
<Text weight="semibold" margin="24 24 0 24">
|
||||
{controller.vidLabel.singular} details
|
||||
{controller.VCLabel.singular} details
|
||||
</Text>
|
||||
<VidDetails vid={controller.incomingVid} />
|
||||
<VcDetails vc={controller.incomingVc} />
|
||||
</Column>
|
||||
<Column padding="0 24" margin="32 0 0 0">
|
||||
<Button
|
||||
title={`Accept request and receive ${controller.vidLabel.singular}`}
|
||||
title={`Accept request and receive ${controller.VCLabel.singular}`}
|
||||
margin="12 0 12 0"
|
||||
onPress={props.onAccept}
|
||||
/>
|
||||
@@ -37,7 +37,7 @@ export const ReceiveVidModal: React.FC<ReceveVidModalProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface ReceveVidModalProps extends ModalProps {
|
||||
interface ReceveVcModalProps extends ModalProps {
|
||||
onAccept: () => void;
|
||||
onReject: () => void;
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext } from 'react';
|
||||
import { selectIncomingVid, selectSenderInfo } from '../../machines/request';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectIncomingVc, selectSenderInfo } from '../../machines/request';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
|
||||
export function useReceiveVidModal() {
|
||||
export function useReceiveVcModal() {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const requestService = appService.children.get('request');
|
||||
const settingsService = appService.children.get('settings');
|
||||
|
||||
return {
|
||||
senderInfo: useSelector(requestService, selectSenderInfo),
|
||||
incomingVid: useSelector(requestService, selectIncomingVid),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
incomingVc: useSelector(requestService, selectIncomingVc),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import QRCode from 'react-native-qrcode-svg';
|
||||
import { Centered, Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
import { ReceiveVidModal } from './ReceiveVidModal';
|
||||
import { ReceiveVcModal } from './ReceiveVcModal';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { useRequestScreen } from './RequestScreenController';
|
||||
|
||||
@@ -16,12 +16,12 @@ export const RequestScreen: React.FC<MainRouteProps> = (props) => {
|
||||
{controller.isBluetoothDenied ? (
|
||||
<Text color={Colors.Red} align="center">
|
||||
Please enable Bluetooth to be able to request{' '}
|
||||
{controller.vidLabel.singular}
|
||||
{controller.VCLabel.singular}
|
||||
</Text>
|
||||
) : (
|
||||
controller.isWaitingForConnection && (
|
||||
<Text align="center">
|
||||
Show this QR code to request {controller.vidLabel.singular}
|
||||
Show this QR code to request {controller.vcLabel.singular}
|
||||
</Text>
|
||||
)
|
||||
)}
|
||||
@@ -44,25 +44,25 @@ export const RequestScreen: React.FC<MainRouteProps> = (props) => {
|
||||
</Column>
|
||||
)}
|
||||
|
||||
<ReceiveVidModal
|
||||
<ReceiveVcModal
|
||||
isVisible={controller.isReviewing}
|
||||
onDismiss={controller.REJECT}
|
||||
onAccept={controller.ACCEPT}
|
||||
onReject={controller.REJECT}
|
||||
headerTitle={`Incoming ${controller.vidLabel.singular}`}
|
||||
headerTitle={`Incoming ${controller.VCLabel.singular}`}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isAccepted}
|
||||
title="Success!"
|
||||
message={`${controller.vidLabel.singular} has been successfully received from ${controller.senderInfo.deviceName}`}
|
||||
message={`${controller.vcLabel.singular} has been successfully received from ${controller.senderInfo.deviceName}`}
|
||||
onBackdropPress={controller.DISMISS}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isRejected}
|
||||
title="Notice"
|
||||
message={`You rejected ${controller.senderInfo.deviceName}'s ${controller.vidLabel.singular}`}
|
||||
message={`You rejected ${controller.senderInfo.deviceName}'s ${controller.vcLabel.singular}`}
|
||||
onBackdropPress={controller.DISMISS}
|
||||
/>
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
selectSenderInfo,
|
||||
selectIsWaitingForConnection,
|
||||
selectIsExchangingDeviceInfo,
|
||||
selectIsWaitingForVid,
|
||||
selectIsWaitingForVc,
|
||||
} from '../../machines/request';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectVcLabel } from '../../machines/settings';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import BluetoothStateManager from 'react-native-bluetooth-state-manager';
|
||||
@@ -22,7 +22,7 @@ import BluetoothStateManager from 'react-native-bluetooth-state-manager';
|
||||
export function useRequestScreen({ navigation }: MainRouteProps) {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidLabel = useSelector(settingsService, selectVidLabel);
|
||||
const vcLabel = useSelector(settingsService, selectVcLabel);
|
||||
|
||||
const requestService = appService.children.get('request');
|
||||
const isActive = useSelector(appService, selectIsActive);
|
||||
@@ -39,15 +39,15 @@ export function useRequestScreen({ navigation }: MainRouteProps) {
|
||||
requestService,
|
||||
selectIsExchangingDeviceInfo
|
||||
);
|
||||
const isWaitingForVid = useSelector(requestService, selectIsWaitingForVid);
|
||||
const isWaitingForVc = useSelector(requestService, selectIsWaitingForVc);
|
||||
|
||||
let statusMessage = '';
|
||||
if (isWaitingForConnection) {
|
||||
statusMessage = 'Waiting for connection...';
|
||||
} else if (isExchangingDeviceInfo) {
|
||||
statusMessage = 'Exchanging device info...';
|
||||
} else if (isWaitingForVid) {
|
||||
statusMessage = `Connected to device. Waiting for ${vidLabel.singular}...`;
|
||||
} else if (isWaitingForVc) {
|
||||
statusMessage = `Connected to device. Waiting for ${vcLabel.singular}...`;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -81,13 +81,13 @@ export function useRequestScreen({ navigation }: MainRouteProps) {
|
||||
}, [isFocused, isActive]);
|
||||
|
||||
return {
|
||||
vidLabel,
|
||||
vcLabel,
|
||||
statusMessage,
|
||||
|
||||
isWaitingForConnection,
|
||||
isExchangingDeviceInfo,
|
||||
|
||||
isWaitingForVid,
|
||||
isWaitingForVc,
|
||||
isBluetoothDenied,
|
||||
connectionParams: useSelector(requestService, selectConnectionParams),
|
||||
senderInfo: useSelector(requestService, selectSenderInfo),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Button, Column, Text } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { SendVidModal } from './SendVidModal';
|
||||
import { SendVcModal } from './SendVcModal';
|
||||
import { useScanScreen } from './ScanScreenController';
|
||||
|
||||
export const ScanScreen: React.FC<MainRouteProps> = (props) => {
|
||||
@@ -36,7 +36,7 @@ export const ScanScreen: React.FC<MainRouteProps> = (props) => {
|
||||
)
|
||||
) : (
|
||||
<Text align="center" margin="16 0" color={Colors.Red}>
|
||||
No sharable {controller.vidLabel.plural} are available.
|
||||
No sharable {controller.VCLabel.plural} are available.
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -47,11 +47,11 @@ export const ScanScreen: React.FC<MainRouteProps> = (props) => {
|
||||
onBackdropPress={controller.DISMISS_INVALID}
|
||||
/>
|
||||
|
||||
<SendVidModal
|
||||
<SendVcModal
|
||||
isVisible={controller.isReviewing}
|
||||
onDismiss={controller.DISMISS}
|
||||
headerElevation={2}
|
||||
headerTitle={`Sharing ${controller.vidLabel.singular}`}
|
||||
headerTitle={`Sharing ${controller.VCLabel.singular}`}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
selectScanning,
|
||||
selectStatusMessage,
|
||||
} from '../../machines/scan';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectShareableVids } from '../../machines/vid';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import { selectShareableVcs } from '../../machines/vc';
|
||||
import { MainRouteProps } from '../../routes/main';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
|
||||
@@ -19,9 +19,9 @@ export function useScanScreen({ navigation }: MainRouteProps) {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const scanService = appService.children.get('scan');
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidService = appService.children.get('vid');
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
const shareableVids = useSelector(vidService, selectShareableVids);
|
||||
const shareableVcs = useSelector(vcService, selectShareableVcs);
|
||||
const isInvalid = useSelector(scanService, selectInvalid);
|
||||
|
||||
const isLocationDisabled = useSelector(scanService, selectIsLocationDisabled);
|
||||
@@ -70,10 +70,10 @@ export function useScanScreen({ navigation }: MainRouteProps) {
|
||||
return {
|
||||
locationError,
|
||||
statusMessage: useSelector(scanService, selectStatusMessage),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
|
||||
isInvalid,
|
||||
isEmpty: !shareableVids.length,
|
||||
isEmpty: !shareableVcs.length,
|
||||
isLocationDisabled,
|
||||
isLocationDenied,
|
||||
isScanning: useSelector(scanService, selectScanning),
|
||||
|
||||
@@ -3,11 +3,11 @@ import { Dimensions, StyleSheet } from 'react-native';
|
||||
import { Overlay } from 'react-native-elements/dist/overlay/Overlay';
|
||||
import { Button, Column, Row, Text } from '../../components/ui';
|
||||
import { Colors, elevation } from '../../components/ui/styleUtils';
|
||||
import { VidItem } from '../../components/VidItem';
|
||||
import { VcItem } from '../../components/VcItem';
|
||||
import {
|
||||
SelectVidOverlayProps,
|
||||
useSelectVidOverlay,
|
||||
} from './SelectVidOverlayController';
|
||||
SelectVcOverlayProps,
|
||||
useSelectVcOverlay,
|
||||
} from './SelectVcOverlayController';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
@@ -17,8 +17,8 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
});
|
||||
|
||||
export const SelectVidOverlay: React.FC<SelectVidOverlayProps> = (props) => {
|
||||
const controller = useSelectVidOverlay(props);
|
||||
export const SelectVcOverlay: React.FC<SelectVcOverlayProps> = (props) => {
|
||||
const controller = useSelectVcOverlay(props);
|
||||
|
||||
return (
|
||||
<Overlay isVisible={props.isVisible} overlayStyle={styles.overlay}>
|
||||
@@ -27,19 +27,19 @@ export const SelectVidOverlay: React.FC<SelectVidOverlayProps> = (props) => {
|
||||
width={Dimensions.get('screen').width * 0.9}
|
||||
style={{ maxHeight: Dimensions.get('screen').height * 0.9 }}>
|
||||
<Text weight="semibold" margin="0 0 16 0">
|
||||
Share {controller.vidLabel.singular}
|
||||
Share {controller.VCLabel.singular}
|
||||
</Text>
|
||||
<Text margin="0 0 16 0">
|
||||
Choose the {controller.vidLabel.singular} you'd like to share with{' '}
|
||||
Choose the {controller.VCLabel.singular} you'd like to share with{' '}
|
||||
<Text weight="semibold">{props.receiverName}</Text>
|
||||
</Text>
|
||||
<Column margin="0 0 32 0" scroll>
|
||||
{props.vidKeys.map((vidKey, index) => (
|
||||
<VidItem
|
||||
key={vidKey}
|
||||
vidKey={vidKey}
|
||||
{props.vcKeys.map((vcKey, index) => (
|
||||
<VcItem
|
||||
key={vcKey}
|
||||
vcKey={vcKey}
|
||||
margin="0 2 8 2"
|
||||
onPress={controller.selectVidItem(index)}
|
||||
onPress={controller.selectVcItem(index)}
|
||||
selectable
|
||||
selected={index === controller.selectedIndex}
|
||||
/>
|
||||
42
screens/Scan/SelectVcOverlayController.ts
Normal file
42
screens/Scan/SelectVcOverlayController.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext, useState } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import { vcItemMachine } from '../../machines/vcItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { VC } from '../../types/vc';
|
||||
|
||||
export function useSelectVcOverlay(props: SelectVcOverlayProps) {
|
||||
const [selectedIndex, setSelectedIndex] = useState<number>(null);
|
||||
const [selectedVcRef, setSelectedVcRef] =
|
||||
useState<ActorRefFrom<typeof vcItemMachine>>(null);
|
||||
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
|
||||
return {
|
||||
selectVcItem,
|
||||
selectedIndex,
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
|
||||
onSelect: () => {
|
||||
const { serviceRefs, ...vc } = selectedVcRef.getSnapshot().context;
|
||||
props.onSelect(vc);
|
||||
},
|
||||
};
|
||||
|
||||
function selectVcItem(index: number) {
|
||||
return (vcRef: ActorRefFrom<typeof vcItemMachine>) => {
|
||||
setSelectedIndex(index);
|
||||
setSelectedVcRef(vcRef);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface SelectVcOverlayProps {
|
||||
isVisible: boolean;
|
||||
receiverName: string;
|
||||
vcKeys: string[];
|
||||
onSelect: (vc: VC) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { useSelector } from '@xstate/react';
|
||||
import { useContext, useState } from 'react';
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { vidItemMachine } from '../../machines/vidItem';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { VC } from '../../types/vc';
|
||||
|
||||
export function useSelectVidOverlay(props: SelectVidOverlayProps) {
|
||||
const [selectedIndex, setSelectedIndex] = useState<number>(null);
|
||||
const [selectedVidRef, setSelectedVidRef] =
|
||||
useState<ActorRefFrom<typeof vidItemMachine>>(null);
|
||||
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const settingsService = appService.children.get('settings');
|
||||
|
||||
return {
|
||||
selectVidItem,
|
||||
selectedIndex,
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
|
||||
onSelect: () => {
|
||||
const { serviceRefs, ...vid } = selectedVidRef.getSnapshot().context;
|
||||
props.onSelect(vid);
|
||||
},
|
||||
};
|
||||
|
||||
function selectVidItem(index: number) {
|
||||
return (vidRef: ActorRefFrom<typeof vidItemMachine>) => {
|
||||
setSelectedIndex(index);
|
||||
setSelectedVidRef(vidRef);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface SelectVidOverlayProps {
|
||||
isVisible: boolean;
|
||||
receiverName: string;
|
||||
vidKeys: string[];
|
||||
onSelect: (vid: VC) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
@@ -3,13 +3,13 @@ import { Input } from 'react-native-elements';
|
||||
import { DeviceInfoList } from '../../components/DeviceInfoList';
|
||||
import { Button, Column } from '../../components/ui';
|
||||
import { Colors } from '../../components/ui/styleUtils';
|
||||
import { SelectVidOverlay } from './SelectVidOverlay';
|
||||
import { SelectVcOverlay } from './SelectVcOverlay';
|
||||
import { MessageOverlay } from '../../components/MessageOverlay';
|
||||
import { Modal, ModalProps } from '../../components/ui/Modal';
|
||||
import { useSendVidModal } from './SendVidModalController';
|
||||
import { useSendVcModal } from './SendVcModalController';
|
||||
|
||||
export const SendVidModal: React.FC<SendVidModalProps> = (props) => {
|
||||
const controller = useSendVidModal();
|
||||
export const SendVcModal: React.FC<SendVcModalProps> = (props) => {
|
||||
const controller = useSendVcModal();
|
||||
|
||||
const reasonLabel = 'Reason for sharing (optional)';
|
||||
|
||||
@@ -33,24 +33,24 @@ export const SendVidModal: React.FC<SendVidModalProps> = (props) => {
|
||||
margin="2 0 0 0"
|
||||
elevation={2}>
|
||||
<Button
|
||||
title={`Accept request and choose ${controller.vidLabel.singular}`}
|
||||
title={`Accept request and choose ${controller.VCLabel.singular}`}
|
||||
margin="12 0 12 0"
|
||||
onPress={controller.ACCEPT_REQUEST}
|
||||
/>
|
||||
<Button type="clear" title="Reject" onPress={controller.CANCEL} />
|
||||
</Column>
|
||||
</Column>
|
||||
|
||||
<SelectVidOverlay
|
||||
isVisible={controller.isSelectingVid}
|
||||
|
||||
<SelectVcOverlay
|
||||
isVisible={controller.isSelectingVc}
|
||||
receiverName={controller.receiverInfo.deviceName}
|
||||
onSelect={controller.SELECT_VID}
|
||||
onSelect={controller.SELECT_VC}
|
||||
onCancel={controller.CANCEL}
|
||||
vidKeys={controller.vidKeys}
|
||||
vcKeys={controller.vcKeys}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isSendingVid}
|
||||
isVisible={controller.isSendingVc}
|
||||
title="Sharing..."
|
||||
hasProgress
|
||||
/>
|
||||
@@ -58,18 +58,18 @@ export const SendVidModal: React.FC<SendVidModalProps> = (props) => {
|
||||
<MessageOverlay
|
||||
isVisible={controller.isAccepted}
|
||||
title="Success!"
|
||||
message={`Your ${controller.vidLabel.singular} has been successfully shared with ${controller.receiverInfo.deviceName}`}
|
||||
message={`Your ${controller.VCLabel.singular} has been successfully shared with ${controller.receiverInfo.deviceName}`}
|
||||
onBackdropPress={props.onDismiss}
|
||||
/>
|
||||
|
||||
<MessageOverlay
|
||||
isVisible={controller.isRejected}
|
||||
title="Notice"
|
||||
message={`Your ${controller.vidLabel.singular} was rejected by ${controller.receiverInfo.deviceName}`}
|
||||
message={`Your ${controller.VCLabel.singular} was rejected by ${controller.receiverInfo.deviceName}`}
|
||||
onBackdropPress={props.onDismiss}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
interface SendVidModalProps extends ModalProps {}
|
||||
interface SendVcModalProps extends ModalProps {}
|
||||
@@ -6,40 +6,40 @@ import {
|
||||
selectReason,
|
||||
selectReceiverInfo,
|
||||
selectRejected,
|
||||
selectSelectingVid,
|
||||
selectSendingVid,
|
||||
selectVidName,
|
||||
selectSelectingVc,
|
||||
selectSendingVc,
|
||||
selectVcName,
|
||||
} from '../../machines/scan';
|
||||
import { selectVidLabel } from '../../machines/settings';
|
||||
import { selectShareableVids } from '../../machines/vid';
|
||||
import { selectVCLabel } from '../../machines/settings';
|
||||
import { selectShareableVcs } from '../../machines/vc';
|
||||
import { GlobalContext } from '../../shared/GlobalContext';
|
||||
import { VC } from '../../types/vc';
|
||||
|
||||
export function useSendVidModal() {
|
||||
export function useSendVcModal() {
|
||||
const { appService } = useContext(GlobalContext);
|
||||
const scanService = appService.children.get('scan');
|
||||
const settingsService = appService.children.get('settings');
|
||||
const vidService = appService.children.get('vid');
|
||||
const vcService = appService.children.get('vc');
|
||||
|
||||
return {
|
||||
receiverInfo: useSelector(scanService, selectReceiverInfo),
|
||||
reason: useSelector(scanService, selectReason),
|
||||
vidName: useSelector(scanService, selectVidName),
|
||||
vidLabel: useSelector(settingsService, selectVidLabel),
|
||||
vidKeys: useSelector(vidService, selectShareableVids),
|
||||
vcName: useSelector(scanService, selectVcName),
|
||||
VCLabel: useSelector(settingsService, selectVCLabel),
|
||||
vcKeys: useSelector(vcService, selectShareableVcs),
|
||||
|
||||
isSelectingVid: useSelector(scanService, selectSelectingVid),
|
||||
isSendingVid: useSelector(scanService, selectSendingVid),
|
||||
isSelectingVc: useSelector(scanService, selectSelectingVc),
|
||||
isSendingVc: useSelector(scanService, selectSendingVc),
|
||||
isAccepted: useSelector(scanService, selectAccepted),
|
||||
isRejected: useSelector(scanService, selectRejected),
|
||||
|
||||
ACCEPT_REQUEST: () => scanService.send(ScanEvents.ACCEPT_REQUEST()),
|
||||
CANCEL: () => scanService.send(ScanEvents.CANCEL()),
|
||||
SELECT_VID: (vid: VC) => scanService.send(ScanEvents.SELECT_VID(vid)),
|
||||
SELECT_VC: (vc: VC) => scanService.send(ScanEvents.SELECT_VC(vc)),
|
||||
DISMISS: () => scanService.send(ScanEvents.DISMISS()),
|
||||
UPDATE_REASON: (reason: string) =>
|
||||
scanService.send(ScanEvents.UPDATE_REASON(reason)),
|
||||
UPDATE_VID_NAME: (vidName: string) =>
|
||||
scanService.send(ScanEvents.UPDATE_VID_NAME(vidName)),
|
||||
UPDATE_VC_NAME: (vcName: string) =>
|
||||
scanService.send(ScanEvents.UPDATE_VC_NAME(vcName)),
|
||||
};
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { requestMachine } from '../machines/request';
|
||||
import { scanMachine } from '../machines/scan';
|
||||
import { settingsMachine } from '../machines/settings';
|
||||
import { storeMachine } from '../machines/store';
|
||||
import { vidMachine } from '../machines/vid';
|
||||
import { vcMachine } from '../machines/vc';
|
||||
|
||||
export const GlobalContext = createContext({} as GlobalServices);
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface GlobalServices {
|
||||
export interface AppServices {
|
||||
store: ActorRefFrom<typeof storeMachine>;
|
||||
auth: ActorRefFrom<typeof authMachine>;
|
||||
vid: ActorRefFrom<typeof vidMachine>;
|
||||
vc: ActorRefFrom<typeof vcMachine>;
|
||||
settings: ActorRefFrom<typeof settingsMachine>;
|
||||
activityLog: ActorRefFrom<typeof activityLogMachine>;
|
||||
request: ActorRefFrom<typeof requestMachine>;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ActorRefFrom } from 'xstate';
|
||||
import { vidItemMachine } from '../machines/vidItem';
|
||||
import { vcItemMachine } from '../machines/vcItem';
|
||||
|
||||
export const VidTabEvents = {
|
||||
VIEW_VID: (vidItemActor: ActorRefFrom<typeof vidItemMachine>) => ({
|
||||
vidItemActor,
|
||||
export const VcTabEvents = {
|
||||
VIEW_VC: (vcItemActor: ActorRefFrom<typeof vcItemMachine>) => ({
|
||||
vcItemActor,
|
||||
}),
|
||||
REFRESH: () => ({}),
|
||||
};
|
||||
|
||||
@@ -5,11 +5,11 @@ export const HOST =
|
||||
Constants.manifest.extra.backendServiceUrl ||
|
||||
'https://resident-app.newlogic.dev';
|
||||
|
||||
export const MY_VIDS_STORE_KEY = 'myVCs';
|
||||
export const MY_VCS_STORE_KEY = 'myVCs';
|
||||
|
||||
export const RECEIVED_VIDS_STORE_KEY = 'receivedVCs';
|
||||
export const RECEIVED_VCS_STORE_KEY = 'receivedVCs';
|
||||
|
||||
export const VID_ITEM_STORE_KEY = (vc: Partial<VC>) =>
|
||||
export const VC_ITEM_STORE_KEY = (vc: Partial<VC>) =>
|
||||
`vc:${vc.idType}:${vc.id}:${vc.requestId}`;
|
||||
|
||||
export const ACTIVITY_LOG_STORE_KEY = 'activityLog';
|
||||
|
||||
@@ -54,8 +54,8 @@ export type OtpRequestResponse = BackendResponse<{
|
||||
maskedEmail?: string;
|
||||
}>;
|
||||
|
||||
export type VidGenerateResponse = BackendResponse<{
|
||||
vid: string;
|
||||
export type VcGenerateResponse = BackendResponse<{
|
||||
vc: string;
|
||||
message: string;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export type VerifiableCredentialType =
|
||||
| 'MOSIPVerfiableCredential'
|
||||
| string;
|
||||
|
||||
export interface VIDLabel {
|
||||
export interface VCLabel {
|
||||
singular: string;
|
||||
plural: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user