File size: 17,751 Bytes
73c513c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
import streamlit as st
import requests
import json

# Global variables
total_number_pages = 24
placeholder_buttons = None

st.set_page_config(page_title="Example Survey",)

# Radio Options
q1_radio_options         = ["Weekly", "Monthly", "Semi-annually", "Annually", "Less than Annually", "Never"]
yes_no_NotSure_radio_options = ["Yes", "No", "Not sure"]
yes_no_radio_options         = ["Yes", "No"]
frequency_radio_options      = ["Always", "Most of the time", "About half the time", "Sometimes", "Never"]


# Function that records radio element changes 
def radio_change(element, state, key):
    st.session_state[state] = element.index(st.session_state[key]) # Setting previously selected option

# Function that disables the last button while data is uploaded to IPFS 
def button_disable():
    st.session_state["disabled"] = True

# Changing the App title

# Page title
st.title('Patient Consent for HIE')

# The following code centralizes all the buttons
st.markdown("<style>.row-widget.stButton {text-align: center;}</style>", unsafe_allow_html=True)

# The following code helps with the font size of text labels
st.markdown("<style>.big-font {font-size:24px;}</style>", unsafe_allow_html=True)   

# Initialize state
if "current_page" not in st.session_state:
    st.session_state["current_page"] = 1
    st.session_state["Q1"]  = None
    st.session_state["Q2"]  = None
    st.session_state["Q3"]  = None
    st.session_state["Q4"]  = None
    st.session_state["Q5"]  = None
    st.session_state["disabled"] = False


# Page 1; Video
if st.session_state["current_page"]  == 1:

    st.markdown("""<p class="big-font">

                This survey asks questions about your views and preferences regarding how your healthcare providers have access to your medical information and to what extent you are in control of that access.  <br><br>

                Health information exchange or HIE is the process of either transferring patient health information electronically (e.g., from a primary care physician to a specialist) or granting access to patient health information maintained digitally by a specific person or organization. The information could reside in an electronic medical record system or other digital repository maintained by a health provider (e.g., hospital, doctor’s office) or in a personal health record maintained by the patient on a personal computer or online. <br><br>

                Health information exchange has the goal of making all relevant medical information about you available to your healthcare providers when they are making decisions about your care. The expected value of having access to all relevant medical information includes more timely and accurate treatment, fewer redundant tests, and better-quality outcomes. However, the concern with health information exchange is that as information is made more accessible, the potential for misuse of that information increases. <br><br>

                Some states have an opt-in requirement where patients must give consent before HIE is allowed, while other states have an opt-out requirement where HIE is allowed unless the patient specifically withdraws consent. Some states have not established specific HIE consent requirements leaving that decision to individual health providers. The process of documenting patient consent for HIE is almost always a paper-based process where the patient fills out and signs a paper consent form at their provider’s office and the provider stores the signed document. Because consent requirements vary from state to state, consent for HIE must be managed separately in each state where a patient receives care or where existing medical information resides. <br><br> 

                The video below provides additional information about HIE in the context of Arizona.                

                </p>""", unsafe_allow_html=True)
    st.video("https://www.youtube.com/watch?v=aJb6Dov0jlM")
   
    if  st.button('Next'):
       st.session_state["current_page"] += 1
       st.rerun()

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 2; Q1
elif st.session_state["current_page"]  == 2:

    st.radio(label     = "How frequently do you visit a healthcare provider to receive care for a medical problem?", 
             options   = q1_radio_options, 
             index     = None if st.session_state["Q1"] == None else st.session_state["Q1"],
             key       = 'Q1_radio', 
             on_change = radio_change, 
             args      = (q1_radio_options, "Q1", "Q1_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q1"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 3; Q2
elif st.session_state["current_page"]  == 3:

    st.radio(label     = "When receiving care for a medical problem, was there EVER a time when an important part of your health information was NOT available to your care provider to make a decision about your care at the time of your scheduled appointment?",
             options   = yes_no_NotSure_radio_options, 
             index     = None if st.session_state["Q2"] == None else st.session_state["Q2"],
             key       = 'Q2_radio', 
             on_change = radio_change, 
             args      = (yes_no_NotSure_radio_options, "Q2", "Q2_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q2"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 4; Q3
elif st.session_state["current_page"]  == 4:

    st.radio(label     = "When receiving care for a medical problem, was there EVER a time when you received conflicting information from different doctors or health care professionals?",
             options   = yes_no_NotSure_radio_options, 
             index     = None if st.session_state["Q3"] == None else st.session_state["Q3"],
             key       = 'Q3_radio', 
             on_change = radio_change, 
             args      = (yes_no_NotSure_radio_options, "Q3", "Q3_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q3"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 5; Q4
elif st.session_state["current_page"]  == 5:

    st.radio(label     = "When receiving care for a medical problem, was there EVER a time when a doctor ordered a medical test that you felt was unnecessary because the test had already been done?",
             options   = yes_no_NotSure_radio_options, 
             index     = None if st.session_state["Q4"] == None else st.session_state["Q4"],
             key       = 'Q4_radio', 
             on_change = radio_change, 
             args      = (yes_no_NotSure_radio_options, "Q4", "Q4_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q4"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 6; Q5
elif st.session_state["current_page"]  == 6:

    st.radio(label     = "When you need care or treatment, how often does your healthcare provider know important information about your medical history?",
             options   = frequency_radio_options, 
             index     = None if st.session_state["Q5"] == None else st.session_state["Q5"],
             key       = 'Q5_radio', 
             on_change = radio_change, 
             args      = (frequency_radio_options, "Q5", "Q5_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q5"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")

# Page 7; Q6
elif st.session_state["current_page"]  == 7:

    st.radio(label     = "How important is it that your healthcare providers have access to ALL of your medical information to make care decisions?",
             options   = importance_radio_options, 
             index     = None if st.session_state["Q6"] == None else st.session_state["Q6"],
             key       = 'Q6_radio', 
             on_change = radio_change, 
             args      = (importance_radio_options, "Q6", "Q6_radio",))
    
    # The code below changes the font size of the above radio's label. The last two <br> tags create extra space before the buttons
    st.markdown("""<style> div[class*="stRadio"] > label > div[data-testid="stMarkdownContainer"] > p {font-size: 24px;}</style> <br><br>""", unsafe_allow_html=True)

    # Placeholder for a potential warning message    
    placeholder = st.empty()

    # Back/Next buttons
    col1, col2 = st.columns(2)
    with col1:
        if st.button('Back'):
            st.session_state["current_page"] -= 1
            st.rerun()

    with col2:
        if st.button('Next'):
            if st.session_state["Q6"] != None:
                st.session_state["current_page"] += 1
                st.rerun()
            else: # Adding warning message to the placeholder
                with placeholder.container():
                    st.warning(f"Please answer all the questions on this page.", icon="⚠️")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")


# Page 24
elif st.session_state["current_page"]  == 24:
   
    st.markdown('<p class="big-font">Thank you for participating! <br> Click on the button below to submit your answers. </p>', unsafe_allow_html=True)

    st.button('Submit Responses', disabled = st.session_state["disabled"], on_click = button_disable)

    if st.session_state["disabled"]:    
        with st.spinner(r"$\textsf{\normalsize Storing data on IPFS and Ethereum. This operation might take a few minutes. Please wait to receive your confirmation code!}$"):
            try:
                response = {'file': json.dumps({"Q1":q1_radio_options[st.session_state["Q1"]],
                                                "Q2":yes_no_NotSure_radio_options[st.session_state["Q2"]],
                                                "Q3":yes_no_NotSure_radio_options[st.session_state["Q3"]],
                                                "Q4":yes_no_NotSure_radio_options[st.session_state["Q4"]],
                                                "Q5":frequency_radio_options[st.session_state["Q5"]]
                                            })
                            }   


                response = requests.post('https://ipfs.infura.io:5001/api/v0/add', 
                                        files=response, 
                                        auth=(st.secrets["username"], st.secrets["password"]))
                
                IPFS_hash = response.json()["Hash"]
                print(IPFS_hash)
            
                # Connect to the Ethereum blockchain
                w3 = web3.Web3(web3.HTTPProvider(st.secrets["infura"]))
            
                # Create a contract instance. Address is equal to the address of the smart contract
                contract = w3.eth.contract(address= "0x42b76d8c32f914630627Bf924BD1e06055673cF8", abi = '[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "string", "name": "data", "type": "string" } ], "name": "Store", "type": "event" }, { "inputs": [ { "internalType": "string", "name": "_IPFSHash", "type": "string" } ], "name": "storeHash", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ]')

                # Call your function: 11155111 is Sepolia's id
                call_function = contract.functions.storeHash(IPFS_hash).build_transaction({"chainId": 11155111, 
                                                                                        "from": "0x3Eb5abC0c5FeDCe75854A61163b7ee63baE71567",
                                                                                        "nonce": w3.eth.get_transaction_count("0x3Eb5abC0c5FeDCe75854A61163b7ee63baE71567")}) # Initialize address nonce

                # Sign transaction
                signed_tx = w3.eth.account.sign_transaction(call_function, private_key=st.secrets["pk"])

                # Send transaction
                send_tx = w3.eth.send_raw_transaction(signed_tx.rawTransaction)

                # Wait for transaction receipt
                tx_receipt = w3.eth.wait_for_transaction_receipt(send_tx)

                print(tx_receipt)

                st.success('Data successfully stored. Thank you for taking the survey!', icon="✅")
                st.info(f'The IPFS hash is: {IPFS_hash}', icon="ℹ️")
                st.info(f'The Ethereum hash is: {tx_receipt.logs[0].transactionHash.hex()}', icon="ℹ️")

                st.markdown('<p class="big-font">Please report your IPFS and Ethereum Hash to receive your payment.</p>', unsafe_allow_html=True)

            except Exception as e:
                print(e)
                st.error(f'An error ocurred. Here is the error message: {e}', icon="🚨")

    # Progress bar
    st.progress(st.session_state["current_page"]/total_number_pages, text="Progress")