ihub-pti / boldo-mobile Goto Github PK
View Code? Open in Web Editor NEWFlutter based mobile application (iOS and Android) for Boldo (Patients).
License: GNU General Public License v3.0
Flutter based mobile application (iOS and Android) for Boldo (Patients).
License: GNU General Public License v3.0
When the profile screen is opened we need to:
This includes setting the data for the "Location" screen too, since this is a part of the flow.
Additionally we need to add a loading spinner while we fetch the data and show an error if fetching the data failed.
Show error (snackbar) when login fails and the appauth throws an error
We need to control the user setting state from a provider because we have multiple screens that need to share the same data.
This includes sending the data to the server from the "Location" and "Profile" screen. The main action button (submit) should do the same for both pages.
Problem:
Core did not accept timezones. Now it does. We should now add timezones everywhere 😊
There is no message once the user is logged out. The app simply changes it state.
There should be some notification that the user has been logged out and that he/she has to login again.
Make sure the app runs on iOS - additional setup is required for deep links and eventually other libraries
In the past, appointments would only have the status upcoming
open
and closed
.
Now we have added "locked". This status will be added around 8 hours after the appointment has taken place and should be handled in the app UI exactly as the closed
state.
During the call-end (doctor ends the call) we update the status of the appointment in the database.
It seems like there is a glitch possibility where the app has processed the call-end and switched to the home screen, before the appointment has been fully updated.
Therefore we should make sure to reload the home screen AFTER the patient has confirmed the pop-up. This should give enough time for the new status to fully settle in the database.
We need to think about the error messages we are going to display under every screen and translate them to spanish
We also need to create the requirements for the validation on the client side (password length, firstname maxlength etc...)
There is a new way to pass parameters to the GET /doctors endpoint:
Before: /doctors?text=text%20from%20search&languages=1,2,3&specialties=4,5,2
Now: /doctors?content=text%20from%20search&content=LanguageName,LanguageName2&content=SpecializationName
Note: it is actually important to send several content
, as each content in the query will result in an AND while each item within a content (content=language1,language2
) will count as an OR.
Also check https://ihub-docs.netlify.app/docs/ihub-docs/doctor which will hopefully reflect the new way already.
We now have pagination available. The next page of doctors should start loading as soon as the user scrolls close to the end of the existing search results.
To pass pagination parameters: /doctors?count=20&offset=40
The return value is now of format: {total: int, items: []}
where total contains information about the total amount of doctors.
We need to change the datetime format from YYYY-MM-DD to DD.MM.YYYY on the mobile (but still send YYY-MM-DD) to the server.
Add loading spinner to the button when it is loading. (next to the text)
Currently we only change the profile screen locally. We need to send the picture to the server,get the signed url, send the image to the url we get from the first response and finally send the profile picture url to the server together with all of the other data.
We also need to configure the picture component to work with URL links instead of local images.
Use the more secure universal deepling for authentication with https:// in the app
We need to implement the UI for the upcoming and past appointments.
For this we need to:
Users can use the app to explore doctors even without being logged in.
If a user is not logged in, they can go until the screen where they can select a date.
On this screen, clicking on "Reservar ahora" or "Acceptar" should show a message that you have to login or register to proceed. This could be a pop up with the following content:
Design: https://www.figma.com/file/s5QFKXhMS3Lcmpg5ZFb7Xo/CMR?node-id=2581%3A0
Here a screenshot of the screen containing the buttons that should trigger the pop-up.
We need to implement a filter screen that will help us selected specializations we need.
Problem: In the Home Screen page in the past and future appointments lists You can't scroll to the bottom of the list of appointments. The user is not able to access all appointments. It's hard to spot because its roughly one viewport height of appointments but for user 1 there are actually many more appointments. You can see an example in the picture below where at the bottom you can see a part of the card is clipped and you cant scroll further down.
The list view has the physics property set to NeverScrollablePhysics. This was meant to only have the scroll controller on the parent custom scroll view. However this is not allowing for scrolling the full list.
To mitigate Man-in-the-middle attacks, we could add SSL Pinning.
Every request might fail with a 500 (Server f*** up) or 400. 400 errors include a {message:string}
answer describing the problem. Every request needs to handle 500 and 400 errors and informing the user about the error + ensuring there is a way for them to recover (back button or automatically moving them back or another button to e.g. retry).
500 errors should show a generic error message, 400 errors should show a generic error message + the specific message.
Sidenote : The server can also return other error codes that are handed through from the core - e.g. 404. These should be handled as 500 or how it makes sense given the context.
Currently, after logging in in Boldo using a chrome tab, the session with KC is persisted in the main browser.
Logging out in the app and logging in again, will immediately log the person into the app as the previously logged in user.
How can we allow a user to logout and login as a different user - using the app?
Example use case: One smartphone, two users.
Currently we have a unrestricted phone number field. Means everyone can input a too-long or too-short phone number. Currently it is a Spanish phone number only.
We need to discuss if we keep it Spanish only and how to validate the phone number correctly.
We need to be able to change the password in the reset password screen. This includes sending the data to the keycloak server.
The docs for password changing can be found here:
https://github.com/iHub-PTI/ihub-keycloak#keycloak-api-call-for-changing-user-password
The server will send a 400, if the authToken is not valid anymore (every 5 to 15 minutes in production). The client should then use the refresh token to receive a new set of tokens (access AND refresh) and store those. Afterwards, the request should be triggered again.
The app is crashing the first time a user books an appointment.
It happens exactly after the appointment was booked. On the confirmation page there is a button that leads back to the home screen (expected behaviour). Clicking this button leaves the app with a black screen.
It's important to delete all the app data beforehand!
After wiping the app data:
Problem:
Breaking change in doctors.
languages
and specializations
will now be arrays of objets (instead of arrays of strings).
The objects will have the shape:
{
id: string,
description: string
}
Task:
specializations
is a list, not a single value. All items from the list should be shown with a comma separated.The time has come to secure the socket connection.
Everything is prepared to make it as comfortable as possible.
feature/token
from boldo-server, boldo-sockets, boldo-mobile..env
of server and sockets. Make sure to double check those and also do npm i
."
and "\n" after the first line (header) and before the last line (footer).The app is passing token: "superPenguinMagic"
in all socket.emit() calls currently.
superPenguinMagic` is a magic value that will always validate successfully. But of course, this is not good. We need to pass the real token.
To get your hands on a real token, use the /profile/patient/appointments/:id
endpoint exposed by the server. It returns the appointment object, including patient details and also a token:string
property 😱.
Some notes about this token:
It will only be defined, if the status is "open" (15 minutes before the meeting and until the doctor leaves the room open). Otherwise the token is an empty string. The token is valid for 1 day, this should be more than enough as open appointments are locked the latest 8 hours after the meeting was scheduled to take place.
If the token is not defined, it means the user should also not be able to be in the waiting room.
It seems like a good idea (but maybe it just seems like it) to download the token once the waiting room is opened. Important is to show some loading animation in this case as it can take a second or three until the data arrives. If there is no token, send the user back to the previous screen and show some snack bar 🍫 that the user should try shortly again. In this erroneous situation, it might also be good to reload the data on the home screen.
When logging in after logging out, the old user is shown data of the previously logged in user.
To try this out, use these credentials:
2, password
10, password
After logging in with one user, logging out, logging in with the other user, you will still see that the whole app shows data from the first logged-in user.
Expected would be that we remove tokens and all other user related data during logout.
Currently in the profile screen profile_screen.dart
page we have a form. From this form we are able to navigate to address_screen.dart
.
Inside the address_screen.dart
we also have a form. It is actually extending the form we have from profile_screen.dart
. Clicking on "submit" in any of the forms will trigger the same function updateProfile
. This function takes the data from the provider (from both forms) and sends it to the server. We save the data from the inputs not onChange but onSubmit. So the data will go inside the provider when we try to submit the form. Then we get this data from provider and pass it to the server. We need a provider because we shared the data of the same form between 2 screens.
Because of the functionality above if we try to remove some text from profile_screen.dart
and then navigate to address_screen.dart
we will successfully submit the form. This should not happen(or at least not as it happens right now). The changes we made in profile_screen.dart
will not be reflected because we save the data onSave. We don't submit the form in profile_screen.dart
so we don't save the new data. We submit the form in address_screen.dart
so we save the data only there.
Save the data onChange and not on onSave in the text controller.
The errors are not shared between the forms. We should share them.
Store the error inside the provider
flutter curently throws the following error:
I/flutter (20126): unhandled element filter; Picture key: AssetBundlePictureKey(bundle: PlatformAssetBundle#69fba(), name: "assets/images/DoctorImage.svg", colorFilter: null)
The problem is that the svg library does not support the dropshadow on the svg.
For more details, see: dnfield/flutter_svg#98
Solution:
Use the original images and add drop-shadow where needed via flutter.
https://www.figma.com/file/s5QFKXhMS3Lcmpg5ZFb7Xo/CMR?node-id=1242%3A19999
We need to improve the dropdown so we can show a default value like "select your gender". This value should not be selectable but it should be the value that the user sees if nothing is selected.
While on a video call with a doctor, iphone's screen turns off and the cellphone locks up preventing the call to continue; it shuts down the connection.
We need to dynamically show the waiting room notification in the dashboard.
It should open 15 minutes before a call starts and close after the appointment has actually happened.
We receive appointments from the server.
Start of an appointment:
We can use the start
property of an appointment and check every second (or n seconds) if there is an appointment that is about to start. And then render a card for it.
End of an appointment:
We can NOT use the end
property of an appointment as the doctor might be delayed longer than the appointment actually was scheduled so it would not be possible for a patient to join the call anymore.
INSTEAD, we check for a prop from the server waitingRoomStatus
('upcoming' | 'open' | 'closed'). If an appointment has the status closed, we never show a waitingRoom card for it.
The implementation includes two tasks:
waitingRoomStatus == 'open'
.waitingRoomStatus == 'upcoming'
and open them once it's LATER than 15 minutes before the appointment.Problem:
If the doctor reloads currently, the patient immediately sees the "call ended" screen.
This should not happen, instead the call should try to reestablish connection OR go into the waiting room. Whatever is best to connect the call immediately back once the doctor's browser did load.
Potential Issues:
Problem:
Right now clicking on video and audio mute buttons does not do anything.
Solution:
Implement them in both waiting room and call to be functional. Make sure that the configuration from waiting room stays this way once entering the call.
Expect that this value can be set on the local media stream which would automatically take care to also mute it in the RTC connection.
Logout will now have to be handeled directly via calling the KC endpoint.
Neither the node server, nor appAuth will help with that.
There is a revoke endpoint that KC offers. It's documented here:
https://www.keycloak.org/docs/latest/securing_apps/#_token_revocation_endpoint
This is the official OIDC Description of such an endpiont:
This document proposes an additional endpoint for OAuth authorization
servers, which allows clients to notify the authorization server that
a previously obtained refresh or access token is no longer needed.
This allows the authorization server to clean up security
credentials. A revocation request will invalidate the actual token
and, if applicable, other tokens based on the same authorization
grant.
We need to add the functionality "pull to refresh" on the dashboard so we refresh the appointments data on the dashboard.
In encountered the following error when leaving the home screen while it was still sending the request (I had clicked the button to reload after an error occured).
The solution seems to be given in the screenshots and it probably involves to check for mounted before setting the state in the callback (or after the await of the request).
Exception has occurred.
FlutterError (setState() called after dispose(): _HomeTabState#7d1a0(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.