Merge pull request #1 from abhay-raizada/add_inputs

Add Inputs to main screen
This commit is contained in:
Abhay Raizada
2024-08-26 08:44:49 +05:30
committed by GitHub
23 changed files with 724813 additions and 2314 deletions

32
App.tsx
View File

@@ -5,37 +5,35 @@
* @format
*/
import React, { useEffect, useState } from 'react';
import { SafeAreaView, ScrollView, StatusBar, StyleSheet } from 'react-native';
import React, {useEffect, useState} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
} from 'react-native';
import { getFormTemplate } from './formstr/formstr';
import { Colors } from 'react-native/Libraries/NewAppScreen';
import { PrescriptionCreator } from './components/PrescriptionCreator';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {PrescriptionCreator} from './components/PrescriptionCreator';
import 'react-native-url-polyfill/auto';
import PolyfillCrypto from 'react-native-webview-crypto';
function App(): React.JSX.Element {
const backgroundStyle = {
backgroundColor: Colors.darker,
backgroundColor: 'black',
color: 'white',
};
const [form, setForm] = useState<{} | null>(null);
useEffect(() => {
console.log('inside useeffect');
const fetchForm = async () => {
if (!form) {
console.log('fetchiiiing forrmmm!!!');
let form = await getFormTemplate(
'eb3df1f89653475f0bcbd22da35f8d2f126db8a68a88a7abedc53535c76c39b4',
)
setForm(form);
}
};
fetchForm();
}, [form]);
}, []);
return (
<SafeAreaView style={backgroundStyle}>
<PolyfillCrypto />
<StatusBar
barStyle={'light-content'}
backgroundColor={backgroundStyle.backgroundColor}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

View File

@@ -0,0 +1,129 @@
import {useState} from 'react';
import {Alert, Button, Modal, Text, TextInput, View} from 'react-native';
import {Section} from '../common/Section';
import {getData, storeData} from '../../utils/localStorage';
export const AddPharmacy = ({
isVisible,
onClose,
onAdd,
}: {
isVisible: boolean;
onClose: () => void;
onAdd: (npub: string, relay: string, name: string) => void;
}) => {
const [npub, setNpub] = useState('');
const [relay, setRelay] = useState('');
const [name, setName] = useState('');
const handleNpub = (value: string) => {
setNpub(value);
};
const handleRelay = (value: string) => {
setRelay(value);
};
const handleName = (value: string) => {
setName(value);
};
async function handleAddClick() {
if (!npub || !relay || !name) {
Alert.alert(
'Missing Inputs',
'Please enter name, npub and relay of the Pharmacy',
);
return;
}
if (npub.length !== 63 || !npub.startsWith('npub1')) {
Alert.alert('Invalid Npub');
return;
}
let pharmacyListString = (await getData('pharmacyList')) || '[]';
let pharmacyList = JSON.parse(pharmacyListString) as Array<{
label: string;
npub: string;
relay: string;
}>;
pharmacyList = [...pharmacyList, {label: name, relay: relay, npub: npub}];
await storeData('pharmacyList', JSON.stringify(pharmacyList));
onAdd(npub, relay, name);
}
return (
<Modal
visible={isVisible}
onRequestClose={() => {
console.log('closing....');
onClose();
return true;
}}
onDismiss={() => {
onClose();
}}
transparent={true}
style={{backgroundColor: 'black', margin: 0, padding: 0, height: '80%'}}
animationType="slide">
<View
style={{
backgroundColor: 'black',
justifyContent: 'center',
minHeight: '80%',
display: 'flex',
margin: 30,
alignItems: 'center',
}}>
<Section title="Add A Pharmacy">
<View style={{margin: 5}}>
<Text style={{color: 'white', margin: 5}}>Add Pharmacy Name</Text>
<TextInput
style={{
borderColor: '#000000',
borderWidth: 1,
borderRadius: 5,
color: 'white',
}}
placeholderTextColor="grey"
placeholder="Pharmacy X"
onChangeText={handleName}
/>
<Text style={{color: 'white', margin: 5}}>Add Pharmacy Npub</Text>
<TextInput
style={{
borderColor: '#000000',
borderWidth: 1,
borderRadius: 5,
color: 'white',
}}
placeholderTextColor="grey"
placeholder="npub1...."
onChangeText={handleNpub}
/>
<Text style={{color: 'white', margin: 5}}>Add Pharmacy Relay</Text>
<TextInput
style={{
borderColor: '#000000',
borderWidth: 1,
borderRadius: 5,
color: 'white',
}}
placeholderTextColor="grey"
placeholder="wss://<relay-url>"
onChangeText={handleRelay}
/>
</View>
<View style={{flexDirection: 'row'}}>
<View style={{margin: 10}}>
<Button title="Cancel" onPress={() => onClose()}></Button>
</View>
<View style={{margin: 10}}>
<Button title="Add" onPress={handleAddClick}></Button>
</View>
</View>
</Section>
</View>
</Modal>
);
};

View File

@@ -0,0 +1,109 @@
import {Dropdown} from 'react-native-element-dropdown';
import {Section} from '../common/Section';
import {Button, Dimensions, Text, View} from 'react-native';
import React, {useEffect, useState} from 'react';
import {AddPharmacy} from './AddPharmacy';
import {getData} from '../../utils/localStorage';
export const pharmacyData = [
{
label: 'Default pharmacy',
value: 'default',
npub: 'npub1tea09rtjeuzgk4gjajzry37wuyv7h02d4zw38cpadcrkg5yt0qhqncr7km',
relay: 'wss://relay.damus.io',
},
{
label: ' + Add Pharmacy',
value: 'custom',
},
];
let width = Dimensions.get('window').width;
interface PharmacyPickerProps {
handleLocationChange: (item: any) => void;
}
export const PharmacyPicker: React.FC<PharmacyPickerProps> = ({
handleLocationChange,
}) => {
const [showAddPharmacyModal, setShowAddPharmacyModal] = useState(false);
const [pharmacyList, setPharmacyList] = useState(pharmacyData);
const [initialized, setInitialized] = useState(false);
const initialize = async () => {
let pharmacyListString = (await getData('pharmacyList')) || '[]';
let newPharmacyList = JSON.parse(pharmacyListString);
let storePharmacyList = [...newPharmacyList, ...pharmacyList];
setPharmacyList(storePharmacyList);
setInitialized(true);
handleLocationChange(storePharmacyList[0]);
};
useEffect(() => {
if (!initialized) initialize();
}, []);
const renderItem = (item: any) => {
if (item.value === 'custom') {
return (
<View>
<Button
title="Add Pharmacy"
onPress={() => {
setShowAddPharmacyModal(true);
}}
/>
</View>
);
}
return (
<View
style={{
width: width,
display: 'flex',
flexDirection: 'column',
padding: 10,
flexWrap: 'wrap',
}}>
<Text style={{color: 'black', fontSize: 24}}>{item.label}</Text>
<View style={{width: width - 100}}>
<Text style={{color: 'grey', paddingBottom: 5}}>
Npub: {item.npub}
</Text>
<Text style={{color: 'grey'}}>Relay: {item.relay}</Text>
</View>
</View>
);
};
return (
<View>
<Section title="Choose a Pharmacy">
<View style={{width: width - 40}}>
<Dropdown
data={pharmacyList}
labelField={'label'}
valueField={'label'}
onChange={handleLocationChange}
value={pharmacyList[0]}
renderItem={renderItem}
style={{width: '100%'}}
placeholderStyle={{color: 'white'}}
selectedTextStyle={{color: 'white'}}
/>
</View>
</Section>
<AddPharmacy
isVisible={showAddPharmacyModal}
onClose={() => {
setShowAddPharmacyModal(false);
}}
onAdd={() => {
initialize();
setShowAddPharmacyModal(false);
}}
/>
</View>
);
};

View File

@@ -0,0 +1,90 @@
import {Text, TextInput, View} from 'react-native';
import {styles, TextTheme} from '../common/styles';
import {useState} from 'react';
import {Section} from '../common/Section';
interface AddressForm {
address_line_1?: string;
city?: string;
state_province?: string;
postal_code?: string;
country_code?: string;
}
interface AddressFormProps {
nestedFormCallback: (tag: string, form: Object) => void;
}
export const AddressForm: React.FC<AddressFormProps> = ({
nestedFormCallback,
}) => {
const [form, setForm] = useState<AddressForm>({});
const handleTextChange = (tag: keyof AddressForm, text: string) => {
let newForm = {...form};
newForm[tag] = text;
setForm(newForm);
nestedFormCallback('Address', newForm);
};
return (
<View>
<View>
<Text style={TextTheme}>Address Line 1</Text>
<TextInput
style={styles.input}
placeholder="Enter street"
value={form.address_line_1}
placeholderTextColor="white"
onChangeText={(text: string) =>
handleTextChange('address_line_1', text)
}
/>
</View>
<View>
<Text style={TextTheme}>City</Text>
<TextInput
style={styles.input}
placeholder="Enter city"
value={form.city}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('city', text)}
/>
</View>
<View>
<Text style={TextTheme}>State Provice</Text>
<TextInput
style={styles.input}
placeholder="enter state..."
value={form.state_province}
placeholderTextColor="white"
onChangeText={(text: string) =>
handleTextChange('state_province', text)
}
/>
</View>
<View>
<Text style={TextTheme}>Postal Code</Text>
<TextInput
style={styles.input}
placeholder="Enter postal code..."
value={form.postal_code}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('postal_code', text)}
/>
</View>
<View>
<Text style={TextTheme}>Country Code</Text>
<TextInput
style={styles.input}
placeholder="Enter Country Code..."
value={form.country_code}
placeholderTextColor="white"
onChangeText={(text: string) =>
handleTextChange('country_code', text)
}
/>
</View>
</View>
);
};

View File

@@ -0,0 +1,95 @@
import {Text, TextInput, View} from 'react-native';
import {Section} from '../common/Section';
import {styles, TextTheme} from '../common/styles';
import {useState} from 'react';
interface MedicineForm {
name?: string;
dosage_form?: string;
strength?: string;
quantity?: string;
refills?: string;
directions?: string;
}
interface MedicineFormProps {
nestedFormCallback: (tag: string, form: Object) => void;
}
export const MedicineForm: React.FC<MedicineFormProps> = ({
nestedFormCallback,
}) => {
const [form, setForm] = useState<MedicineForm>({});
const handleTextChange = (tag: keyof MedicineForm, text: string) => {
let newForm = {...form};
newForm[tag] = text;
setForm(newForm);
nestedFormCallback('MedicationPrescribed', newForm);
};
return (
<View>
<View>
<Text style={TextTheme}>Name of Medicine</Text>
<TextInput
style={styles.input}
placeholder="Enter name of medicine"
value={form.name}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('name', text)}
/>
</View>
<View>
<Text style={TextTheme}> Form of Dosage</Text>
<TextInput
style={styles.input}
placeholder="what is the dosage form"
value={form.dosage_form}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('dosage_form', text)}
/>
</View>
<View>
<Text style={TextTheme}>Strength</Text>
<TextInput
style={styles.input}
placeholder="enter strength..."
value={form.strength}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('strength', text)}
/>
</View>
<View>
<Text style={TextTheme}>Quantity</Text>
<TextInput
style={styles.input}
placeholder="Enter quantity..."
value={form.quantity}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('quantity', text)}
/>
</View>
<View>
<Text style={TextTheme}>Refills</Text>
<TextInput
style={styles.input}
placeholder="Refills"
value={form.refills}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('refills', text)}
/>
</View>
<View>
<Text style={TextTheme}>Directions</Text>
<TextInput
style={styles.input}
placeholder="Enter directions"
value={form.refills}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('directions', text)}
/>
</View>
</View>
);
};

View File

@@ -0,0 +1,75 @@
import {Text, TextInput, View, Button} from 'react-native';
import {Section} from '../common/Section';
import {styles, TextTheme} from '../common/styles';
import {useState} from 'react';
import DatePicker from 'react-native-date-picker';
interface PatientForm {
name?: string;
date_of_birth?: string;
}
interface PatientFormProps {
nestedFormCallback: (tag: string, form: Object) => void;
}
export const PatientForm: React.FC<PatientFormProps> = ({
nestedFormCallback,
}) => {
const [form, setForm] = useState<PatientForm>({});
const [openDate, setOpenDate] = useState<boolean>(false);
const handleTextChange = (tag: 'name' | 'date_of_birth', text: string) => {
let newForm = {...form};
newForm[tag] = text;
setForm(newForm);
nestedFormCallback('patient', {human_patient: newForm});
};
return (
<View>
<View>
<Text style={TextTheme}>Name</Text>
<TextInput
style={styles.input}
placeholder="Enter Patients Name"
value={form.name}
placeholderTextColor="white"
onChangeText={(text: string) => handleTextChange('name', text)}
/>
</View>
<View>
<Text style={TextTheme}>Date of Birth</Text>
{form.date_of_birth ? (
<View>
<Text style={TextTheme}>{form.date_of_birth}</Text>
<Button
onPress={() => {
setOpenDate(true);
}}
title="Edit"
/>
</View>
) : (
<Button
onPress={() => {
setOpenDate(true);
}}
title="Pick a date"
/>
)}
<DatePicker
modal
mode={'date'}
open={openDate}
date={new Date(form.date_of_birth || '01-01-1999')}
onCancel={() => setOpenDate(false)}
onConfirm={(date: Date) => {
handleTextChange('date_of_birth', date.toDateString());
setOpenDate(false);
}}
/>
</View>
</View>
);
};

View File

@@ -1,67 +1,150 @@
import {Dimensions, Image, StyleSheet, Text, View} from 'react-native';
import SampleJSON from '../../formstr/sample.json';
import {Alert, Dimensions, Image, View, Button} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
import {PropsWithChildren} from 'react';
import {Card} from '@ant-design/react-native';
import {useEffect, useState} from 'react';
import {
SimplePool,
UnsignedEvent,
finalizeEvent,
getPublicKey,
nip04,
nip19,
} from 'nostr-tools';
import EncryptedStorage from 'react-native-encrypted-storage';
import {ImportNsec} from '../common/ImportNsec';
import {Section} from '../common/Section';
import {PatientForm} from './PatientForm';
import {AddressForm} from './AddressForm';
import {MedicineForm} from './MedicineForm';
import {PharmacyPicker, pharmacyData} from '../PharmacyPicker';
type SectionProps = PropsWithChildren<{
title: string;
}>;
function OBJtoXML(obj: any) {
var xml = '';
for (var prop in obj) {
xml += '<' + prop + '>';
if (Array.isArray(obj[prop])) {
for (var array of obj[prop]) {
// A real botch fix here
xml += '</' + prop + '>';
xml += '<' + prop + '>';
const backgroundStyle = {
backgroundColor: Colors.darker,
};
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
width: Dimensions.get('window').width - 80,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '500',
},
});
function Section({children, title}: SectionProps): React.JSX.Element {
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: Colors.white,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: Colors.light,
},
]}>
{children}
</Text>
</View>
);
xml += OBJtoXML(new Object(array));
}
} else if (typeof obj[prop] == 'object') {
xml += OBJtoXML(new Object(obj[prop]));
} else {
xml += obj[prop];
}
xml += '</' + prop + '>';
}
var xml = xml.replace(/<\/?[0-9]{1,}>/g, '');
return xml;
}
export const PrescriptionCreator = () => {
const [showImportNsec, setShowImportNsec] = useState(false);
const [loggedInNpub, setLoggedInNpub] = useState('');
const [finalJSON, setFinalJson] = useState({});
const [selectedPharmacyId, setSelectedPharmacyId] = useState(
pharmacyData[0].npub,
);
const [selectedPharmacyRelays, setSelectedPharmacyRelays] = useState<
Array<string>
>([pharmacyData[0].relay!]);
const handleLocationChange = (item: {
name: string;
npub: string;
relay: string;
}) => {
setSelectedPharmacyId(item.npub);
setSelectedPharmacyRelays([item.relay]);
};
useEffect(() => {
async function initialize() {
let doctorCredentials = null;
try {
doctorCredentials = await EncryptedStorage.getItem('user_credentials');
if (!doctorCredentials) {
setShowImportNsec(true);
} else {
setLoggedInNpub(
nip19.npubEncode(
getPublicKey(nip19.decode(doctorCredentials).data as Uint8Array),
),
);
}
} catch (e) {
console.log('Error getting credentials', e);
}
}
initialize();
}, []);
const nestedFormCallback = (
xmlTag: string,
value: Object | Array<any> | string,
) => {
console.log('Filling', xmlTag, value);
setFinalJson({...finalJSON, [xmlTag]: value});
};
const handleImportNsec = (nsec: string) => {
EncryptedStorage.setItem('user_credentials', nsec);
if (nsec.startsWith('nsec1') && nsec.length !== 63) {
Alert.alert('not a valid nsec!');
return;
}
setLoggedInNpub(
nip19.npubEncode(getPublicKey(nip19.decode(nsec).data as Uint8Array)),
);
setShowImportNsec(false);
};
const handleButtonPress = () => {
console.log('Final JSON is', finalJSON);
const xml = OBJtoXML({prescription: finalJSON});
console.log('XML is...', xml, typeof xml);
sendPrescription(xml);
};
const sendPrescription = async (xml: string) => {
console.log('Will generate IDs');
const sk = nip19.decode(
(await EncryptedStorage.getItem('user_credentials')) as `nsec1${string}`,
).data as Uint8Array;
const pk = getPublicKey(sk);
const pharmacyId = nip19.decode(selectedPharmacyId!).data as string;
console.log('Got ids');
console.log('content is ', xml);
const baseKind4Event: UnsignedEvent = {
kind: 4,
tags: [['p', pharmacyId]],
content: await nip04.encrypt(sk, pharmacyId, `${xml}`),
created_at: Math.floor(Date.now() / 1000),
pubkey: pk,
};
const finalEvent = finalizeEvent(baseKind4Event, sk);
console.log(
'FINAL EVENT IS ',
finalEvent,
'relays are',
selectedPharmacyRelays,
);
const pool = new SimplePool();
console.log('publishing event');
let messages = await Promise.allSettled(
pool.publish(selectedPharmacyRelays, finalEvent),
);
console.log('Messages from relays', messages);
Alert.alert('Prescription Sent to the pharmacy!');
};
return (
<View
style={{
backgroundColor: Colors.black,
minHeight: Dimensions.get('window').height,
}}>
<Image
style={{
@@ -69,45 +152,45 @@ export const PrescriptionCreator = () => {
width: Dimensions.get('window').width,
}}
source={{
uri: SampleJSON.settings.titleImageUrl,
uri: 'https://www.studentdoctor.net/wp-content/uploads/2018/08/20180815_prescription.png',
}}
/>
<Section title="PeerScribe">
From the practice of {SampleJSON.name}
From the practice of {loggedInNpub}
<Button
onPress={() => {
setShowImportNsec(true);
}}
title="edit"
/>
</Section>
<Section title="Prescription">
<View style={{display: 'flex', flexDirection: 'column'}}>
{SampleJSON.fields.map(field => {
return (
<Card
key={field.questionId}
style={{
display: 'flex',
flexDirection: 'column',
padding: 10,
backgroundColor: Colors.white,
margin: 10,
width: 500,
height: 'auto',
}}>
<Text
style={{
color: Colors.green,
}}>
{field.question}
</Text>
<Text
style={{
color: Colors.light,
}}>
{field.answerType}
</Text>
</Card>
);
})}
<PharmacyPicker handleLocationChange={handleLocationChange} />
<Section title="Create Prescription">
<View style={{display: 'flex', flexDirection: 'column', width: '100%'}}>
<Section title="Patient" collapsible={true}>
{' '}
<PatientForm nestedFormCallback={nestedFormCallback} />
</Section>
<Section title="Address" collapsible={true}>
<AddressForm nestedFormCallback={nestedFormCallback} />
</Section>
<Section title="Medicine" collapsible={true}>
<MedicineForm nestedFormCallback={nestedFormCallback} />
</Section>
<View style={{margin: 15}}>
<Button onPress={handleButtonPress} title="Create Rx" />
</View>
</View>
</Section>
<ImportNsec
isVisible={showImportNsec}
onClose={() => {
setShowImportNsec(false);
}}
onPress={handleImportNsec}
/>
</View>
);
};

View File

@@ -0,0 +1,68 @@
import {useState} from 'react';
import {
Button,
Modal,
NativeSyntheticEvent,
Text,
TextInput,
TextInputChangeEventData,
View,
} from 'react-native';
export const ImportNsec = ({
isVisible,
onClose,
onPress,
}: {
isVisible: boolean;
onClose: () => void;
onPress: (nsec: `nsec1${string}`) => void;
}) => {
const [nsec, setNsec] = useState('');
const handleNsec = (value: string) => {
setNsec(value);
};
return (
<Modal
visible={isVisible}
onRequestClose={() => {
console.log('closing....');
onClose();
return true;
}}
onDismiss={() => {
onClose();
}}
presentationStyle="pageSheet">
<View
style={{
backgroundColor: '#ffffff',
height: 500,
justifyContent: 'center',
display: 'flex',
margin: 30,
borderColor: 'red',
alignItems: 'center',
}}>
<View style={{margin: 5}}>
<Text style={{color: '#000000', margin: 5}}>Import Your Nsec</Text>
<TextInput
style={{
borderColor: '#000000',
borderWidth: 1,
borderRadius: 5,
color: '#000000',
}}
onChangeText={handleNsec}
/>
</View>
<View>
<Button
title="Import"
onPress={() => onPress(nsec as `nsec1${string}`)}></Button>
</View>
</View>
</Modal>
);
};

View File

@@ -0,0 +1,43 @@
import {PropsWithChildren, useState} from 'react';
import {
Dimensions,
StyleSheet,
Text,
Touchable,
TouchableOpacity,
View,
} from 'react-native';
import {styles} from './styles';
type SectionProps = PropsWithChildren<{
title: string;
collapsible?: boolean;
}>;
export function Section({
children,
title,
collapsible,
}: SectionProps): React.JSX.Element {
const [collapsed, setCollapsed] = useState(true);
return (
<View style={styles.sectionContainer}>
{collapsible ? (
<TouchableOpacity
onPress={() => {
setCollapsed(!collapsed);
}}>
<Text style={styles.sectionTitle}>
{title} {collapsed ? '→' : '↓'}
</Text>
</TouchableOpacity>
) : (
<Text style={styles.sectionTitle}>{title}</Text>
)}
{!collapsible || !collapsed ? (
<Text style={[styles.sectionDescription]}>{children}</Text>
) : null}
</View>
);
}

View File

@@ -0,0 +1,39 @@
import {Dimensions, StyleSheet} from 'react-native';
import {Colors} from 'react-native/Libraries/NewAppScreen';
export const styles = StyleSheet.create({
input: {
height: 40,
margin: 12,
borderWidth: 1,
borderBottomColor: 'white',
padding: 10,
color: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
width: Dimensions.get('window').width - 80,
color: Colors.white,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.white,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.white,
},
highlight: {
fontWeight: '500',
},
});
export const TextTheme = [
{
color: Colors.white,
},
];

View File

@@ -1,33 +0,0 @@
import {SimplePool} from 'nostr-tools';
import {V1FormSpec} from '@formstr/sdk/dist/interfaces';
const relayList = ['wss://relay.primal.net/', 'wss://relay.hllo.live/'];
export const getFormTemplate = async (formId: string): Promise<{}> => {
console.log('inside getFormTemplate');
const pool = new SimplePool();
let formIdPubkey = formId;
console.log('everything initialised');
const filter = {
kinds: [0],
authors: [formIdPubkey], //formId is the npub of the form
};
let kind0 = null
try {
console.log('inside trydasdsad');
kind0 = await pool.get(relayList, filter)
console.log('Main thread is working, got event', kind0);
} catch (e) {
console.log('inside catch');
console.log('error is', e);
}
pool.close(relayList);
let formTemplate;
if (kind0) {
formTemplate = JSON.parse(kind0.content);
} else {
throw Error('Form template not found');
}
return formTemplate;
};

View File

@@ -1,121 +0,0 @@
{
"name": "X Pharmacy ",
"schemaVersion": "v1",
"settings": {
"titleImageUrl": "https://www.studentdoctor.net/wp-content/uploads/2018/08/20180815_prescription.png",
"description": "Testing formstr for getting prescriptions",
"thankYouPage": true
},
"fields": [
{
"question": "Location",
"answerType": "dropdown",
"answerSettings": {
"choices": [
{
"label": "Narnia",
"choiceId": "ae9DZi"
},
{
"label": "Hogwarts",
"choiceId": "Dx4gyn"
},
{
"label": "Mordor",
"choiceId": "oWygzo"
},
{
"label": "Tattooine",
"choiceId": "dLgxns"
}
],
"required": true
},
"questionId": "V7yEc2"
},
{
"question": "Patient",
"answerType": "label",
"answerSettings": {},
"questionId": "BPfwxq"
},
{
"question": "Name",
"answerType": "shortText",
"answerSettings": {},
"questionId": "HLydbI"
},
{
"question": "Date Of Birth ",
"answerType": "date",
"answerSettings": {},
"questionId": "lzpBhA"
},
{
"question": "Address",
"answerType": "paragraph",
"answerSettings": {},
"questionId": "Mvajrv"
},
{
"question": "Phone",
"answerType": "shortText",
"answerSettings": {},
"questionId": "PjTnfM"
},
{
"question": "Allergies",
"answerType": "shortText",
"answerSettings": {},
"questionId": "UMfscG"
},
{
"question": "Current Meds ",
"answerType": "shortText",
"answerSettings": {},
"questionId": "Cc8lih"
},
{
"question": "Medications",
"answerType": "label",
"answerSettings": {},
"questionId": "0R7uhf"
},
{
"question": "Name",
"answerType": "shortText",
"answerSettings": {},
"questionId": "WXJScB"
},
{
"question": "Dosage Form",
"answerType": "shortText",
"answerSettings": {},
"questionId": "BxEwHQ"
},
{
"question": "Strength",
"answerType": "shortText",
"answerSettings": {},
"questionId": "q2nC6e"
},
{
"question": "Quantiy ",
"answerType": "number",
"answerSettings": {},
"questionId": "fz68UV"
},
{
"question": "Re-fills",
"answerType": "shortText",
"answerSettings": {},
"questionId": "9SdbyN"
},
{
"question": "Directions",
"answerType": "paragraph",
"answerSettings": {},
"questionId": "6FrcPv"
}
]
}

View File

@@ -4,6 +4,7 @@
import {AppRegistry} from 'react-native';
import 'text-encoding-polyfill';
import 'react-native-get-random-values';
import App from './App';
import {name as appName} from './app.json';

View File

@@ -10,15 +10,33 @@
"test": "jest"
},
"dependencies": {
"@ant-design/react-native": "^5.1.0",
"@formstr/sdk": "^0.0.4-alpha",
"@react-native-async-storage/async-storage": "^1.24.0",
"@react-native-community/datetimepicker": "^8.0.1",
"@react-native-community/segmented-control": "^2.2.2",
"@react-native-community/slider": "^4.5.0",
"@react-native-picker/picker": "^2.6.1",
"@rneui/base": "^4.0.0-rc.8",
"@rneui/themed": "^4.0.0-rc.8",
"buffer": "^6.0.3",
"events": "^3.3.0",
"nostr-tools": "^2.3.1",
"react": "18.2.0",
"react-native": "0.73.4",
"react-native-crypto": "^2.2.0",
"react-native-date-picker": "^5.0.3",
"react-native-element-dropdown": "^2.10.4",
"react-native-encrypted-storage": "^4.0.3",
"react-native-get-random-values": "^1.11.0",
"react-native-picker-select": "^9.0.1",
"react-native-randombytes": "^3.6.1",
"react-native-safe-area-context": "^4.5.0",
"react-native-url-polyfill": "^2.0.0",
"text-encoding-polyfill": "^0.6.7"
"react-native-vector-icons": "^10.1.0",
"react-native-webview": "^13.8.4",
"react-native-webview-crypto": "^0.0.25",
"stream": "^0.0.2",
"text-encoding-polyfill": "^0.6.7",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@@ -29,6 +47,7 @@
"@react-native/metro-config": "0.73.5",
"@react-native/typescript-config": "0.73.1",
"@types/react": "^18.2.6",
"@types/react-native-vector-icons": "^6.4.18",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",

721109
static/medicine_names.json Normal file

File diff suppressed because it is too large Load Diff

29
utils/localStorage.ts Normal file
View File

@@ -0,0 +1,29 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
export const storeData = async (key: string, value: string): Promise<void> => {
try {
await AsyncStorage.setItem(key, value);
console.log('Data stored successfully');
} catch (error) {
console.error('Failed to store data:', error);
}
};
export const getData = async (key: string): Promise<string | null> => {
try {
const value = await AsyncStorage.getItem(key);
return value;
} catch (error) {
console.error('Failed to retrieve data:', error);
return null;
}
};
export const removeData = async (key: string): Promise<void> => {
try {
await AsyncStorage.removeItem(key);
console.log('Data removed successfully');
} catch (error) {
console.error('Failed to remove data:', error);
}
};

3905
yarn.lock

File diff suppressed because it is too large Load Diff