Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🏷️ Migration of Label Screen Components #993

Conversation

JGreenlee
Copy link
Collaborator

This PR begins the work of rewriting the label screen components as React components.

Specifically, TimestampBadge.jsx and MultilabelButtonGroup.jsx are new. (The popup menus that MultilabelButtonGroup creates need to be reworked.)

(once framework_migration_prep is merged into master_for_platform, I will change the target of this PR to master_for_platform)

In the label screen, the timestamps for each trip/place/untracked are shown at the top and bottom of the card. Since this is used in many places, it has been refactored into a reusable React component.
It uses the Badge component from react-native-paper, and applies the appropriate colors from the theme.
This will allow the use of the `useTranslation()` hook in our React components. This is how we will accomplish internationalization in the new React components we are writing.
https://react.i18next.com/latest/usetranslation-hook
MultiLabelButtonGroup.jsx will be the React component that handles the multilabel buttons. This is a React rewrite of multi-label-ui.
The popup menu is a work in progress; it uses a `Menu` from React Native Paper, but it does not render correctly because of the existing DOM structure that is from AngularJS. We need a way for this to appear on top of all other content.
www/js/app.js Outdated Show resolved Hide resolved
@shankari
Copy link
Contributor

shankari commented Jun 15, 2023

I have now merged #990
I am not going to merge anything to master_for_platform until we have tested on staging and are ready to push to production since other teams are pulling from it for their own custom instances of the platform - e.g. UNSW and FabMob QC

I finally got icons working with React Native Paper components by following the guide from here:
https://callstack.github.io/react-native-paper/docs/guides/react-native-web/

The webpack configuration was more complicated than it needed to be. There was unnecessary config left over from when I tried to get the icons working before, and this can be removed.
As a pleasant side effect, I think bundling is now happening much faster.
At this point, the multilabel buttons are now behaving almost exactly the same as they used to - except rendered in React instead of AngularJS.

The popups are going to stay as ionic for now. For that to work, we use the $ionicPopover service from within React. This works fine for now.
Later, I'd prefer to make these into Menus or Dialogs. But I can't do this until we have some of the upper-level parts of the UI rewritten in React.
The functionality from the multilabel directive has been replaced by the MultilabelButtonGroup component, and the multilabel directive is no longer being used.
Inside `multi-label-ui.js`, the MultiLabelService is still being used, so that file has to stick around for a while longer.
This is not being used. Although this would be the ideal, I abandoned this idea because the Menus will not display correctly until we have migrated upper-level UI components.
The 'secondary' colors are being used for 'inferred' labels. For text readability, I'm using more of an orange than a yellow.
I'm also tweaking the primary colors in accordance so that we overall have a slightly more pleasant palette.
This popup is now triggered from MultilabelButtonGroup and this function is never used anywhere.
@JGreenlee
Copy link
Collaborator Author

JGreenlee commented Jun 15, 2023

The multilabel buttons, and the logic necessary for their behavior, have been consolidated into MultilabelButtonGroup.jsx.
I also made the decision to include the checkmark icon into that component, rather than rendering it separately.

I did not create a separate component for the checkmark, since it's just a one-liner IconButton.

As you can see, I opted to make the checkmark button show with an outline (this way it actually looks like something you can press); and I also shifted the color palette with the goal of having a better contrast ratio for readability

@JGreenlee
Copy link
Collaborator Author

Much of the hardest work is out of the way. MultilabelButtonGroup is most likely the most complex component we will have inside the label screen, other than perhaps the list component itself.

I think that creating components for the diary cards will not be difficult, as the only non-React elements left are just text. Similarly with the details page.

Migrating the label screen may not take as long as I had anticipated. But first, I want to stop and write unit tests for what's here.

Adding TypeScript to the project required a bit of webpack reconfiguration.
It also made bundling extremely slow (~60s). So, I sifted through the webpack.config.js and optimized it as much as possible. Now, bundling is taking about ~12s.
This allows VSCode's IntelliSense to not have so many files to watch
VSCode wanted me to explicitly add 'children' before on these elements, but I think it was due to a bug.
Once I got TypeScript fully configured, and the TypeScript extensions were reloaded, this was deemed unnecessary, and it gave me a warning to remove 'children' from the definition.
This allows us to 'import React from "react"', instead of having to 'import * as React from "react"'.
In this project we want to be consistent about using ES import syntax, preferably treating everything as either a default or named export. esModuleInterop allows us to do this even if the libraries differ.
@JGreenlee
Copy link
Collaborator Author

I have not been able to set up component testing.

I burned the better part of yesterday trying to find the right configuration. I exhausted all the help I can find on StackOverflow + GitHub, and I'm not sure that me continuing to wrangle with it is going to be beneficial anymore.

It seems darn near impossible to get Jest to work in our project at this time - there are too many complications: TypeScript, Ionic/Angular legacy packages, the fact that we are using React Native Web in a nonstandard way..

It's not going to be easy to implement quality testing until we are free of Cordova and are working in an Expo ecosystem.

That said, I think we can still test simple, individual functions easily; i.e we can make sure functions give the correct output when given a fake input. But I'm not sure how valuable that kind of testing is going to be in this codebase, because at that point we have to mock almost everything.
I was hoping to test components as a whole, using tools that virtually render a component in the React DOM - but I have not been able to get that part working.

I know that testing is really important because of the large-scale nature of the project, but unless someone else can get component testing working, we may have to settle for the more primitive kind of unit tests.

Since we are going to keep using the ionic popovers until the rest of the label screen is rewritten, we might as well make them look nicer.
This has been replaced by the new checkmark icon in MultilabelButtonGroup.
This component replaces enketo-add-note-button.
Most of the logic is kept the same.
The new AddNoteButton.tsx has a plus sign icon next to the text.
This style tweak is necessary for buttons with icons to show correctly; otherwise the button label overlaps the icon.
MultilabelButtonGroup should show if elementTag is 'multilabel', and the trip button should show if elementTag is 'enketo-trip-button'
This directive has been replaced by AddNoteButton.jsx.
This file also contains EnketoNotesButtonService, which is still being used, so I cannot remove the entire file as of yet.
This new component replaces enketo-trip-button. It has been made more generic; verbage has been changed to 'timelineEntry' in a few places that it still said 'trip'.
The enketoTripButton directive has been removed.
As was the case with the other buttons, EnketoTripButtonService is still in use and the enketo-trip-button.js file must be kept for now.
In the Content Security Policy, img-src was set to accept 'self' and 'ionic: data: https://*.tile.openstreetmap.org'. I believe this was necessary for the purpose of using ui-leaflet.

Now, we have LeafletView, which is independent of Ionic and AngularJS. It retrieves tiles directly from https://tile.openstreetmap.org.
Updating the policy as such resolves the issue.
The `detachPreviousScreen` option is true by default and means that when you navigate to a new screen, the old one is detached so it can be removed from memory.
In the case of the label details screen, we are going to go right back to the main label screen from the details page. So we shouldn't detach it.

This also fixes the issue of the scroll position resetting when going back from the details page.
Copy link
Contributor

@shankari shankari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This includes everything EXCEPT LabelTab and TimelineScrollList. Those are large and complex, so I will defer them until tomorrow morning. Note that I have also not reviewed the CSS/SCSS in any level of detail since the proof of their correctness is in the visual representation.

package.cordovabuild.json Show resolved Hide resolved
package.cordovabuild.json Show resolved Hide resolved
package.cordovabuild.json Outdated Show resolved Hide resolved
package.cordovabuild.json Outdated Show resolved Hide resolved
package.serve.json Show resolved Hide resolved
www/js/survey/enketo/enketo-add-note-button.js Outdated Show resolved Hide resolved
www/js/useAppConfig.ts Show resolved Hide resolved
www/templates/diary/infinite_scroll_detail.html Outdated Show resolved Hide resolved
<View style={{width: 'calc(100% - 20px)'}}>
{inputKeys.map((key, i) => {
const input = trip.inputDetails[key];
const inputIsConfirmed = trip.userInput[input.name];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still have the distinction between trip.userInput and trip.user_input? I have frequently felt that we should rename one or the other just to avoid confusion among future maintainers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't rename them. I've also thought it would be a good idea; for additions as well.

Currently, the server gives us user_input and additions, and the phone organizes these into userInput and additionsList

Maybe the phone can do userInputList and additionsList -- or a better descriptive name if we can think of one

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO later

Copy link
Collaborator Author

@JGreenlee JGreenlee Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aggUserInput and aggAdditions ?
I'm thinking it's basically an aggregate of processed input(s) from server and unprocessed input(s) on phone

package.cordovabuild.json Outdated Show resolved Hide resolved
There were changes upstream while I was working on the PR this is a part of.
When I pulled them back in and resolved merge conflicts, I overlooked some important changes that had happened with cordova plugins and versioning

https://github.com/e-mission/e-mission-phone/pull/993/files#r1244031155
https://github.com/e-mission/e-mission-phone/pull/993/files#r1244628495
https://github.com/e-mission/e-mission-phone/pull/993/files#r1245346066
Copy link
Contributor

@shankari shankari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I think this looks great! Once you have addressed the "TODO before merge" comments, I am ready to merge and push out.

I think we should leave the "TODO later" comments open so we can remember what to fix in the polishing stage.

www/js/diary/LabelTab.tsx Show resolved Hide resolved
www/js/diary/LabelTab.tsx Show resolved Hide resolved
www/js/diary/LabelTab.tsx Show resolved Hide resolved
Copy link
Contributor

@shankari shankari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Everything else seems fixable in a future polishing round

@shankari
Copy link
Contributor

I'm merging, building, and pushing to staging.
ETA ~ noon assuming no surprises when I build on native

@shankari shankari merged commit c724ac1 into e-mission:framework_migration_prep Jun 28, 2023
Abby-Wheelis pushed a commit to Abby-Wheelis/e-mission-phone that referenced this pull request Jun 28, 2023
Abby-Wheelis pushed a commit to Abby-Wheelis/e-mission-phone that referenced this pull request Jun 28, 2023
as a feature of e-mission#993 the calls to angularize need the name parameter, up to date and running smoothly!
@shankari
Copy link
Contributor

@JGreenlee while building the native app, I have the following error

angular.js:14794 Error: transition superseded
    at $StateProvider.$get (angular-ui-router.js:2827:44)
    at Object.invoke (angular.js:5097:1)
    at angular.js:4884:1
    at getService (angular.js:5038:1)
    at injectionArgs (angular.js:5063:1)
    at Object.invoke (angular.js:5089:1)
    at angular.js:4894:37
    at forEach (angular.js:408:1)
    at createInjector (angular.js:4894:1)
    at doBootstrap (angular.js:1955:1) 'Possibly unhandled rejection: {}'
(anonymous) @ angular.js:14794

angular.js:14794 Error: transition prevented
    at $StateProvider.$get (angular-ui-router.js:2828:43)
    at Object.invoke (angular.js:5097:1)
    at angular.js:4884:1
    at getService (angular.js:5038:1)
    at injectionArgs (angular.js:5063:1)
    at Object.invoke (angular.js:5089:1)
    at angular.js:4894:37
    at forEach (angular.js:408:1)
    at createInjector (angular.js:4894:1)
    at doBootstrap (angular.js:1955:1) 'Possibly unhandled rejection: {}'
(anonymous) @ angular.js:14794
angular.js:14794 Error: transition aborted
    at $StateProvider.$get (angular-ui-router.js:2829:41)
    at Object.invoke (angular.js:5097:1)
    at angular.js:4884:1
    at getService (angular.js:5038:1)
    at injectionArgs (angular.js:5063:1)
    at Object.invoke (angular.js:5089:1)
    at angular.js:4894:37
    at forEach (angular.js:408:1)
    at createInjector (angular.js:4894:1)
    at doBootstrap (angular.js:1955:1) 'Possibly unhandled rejection: {}'
(anonymous) @ angular.js:14794
angular.js:14794 Error: transition failed
    at $StateProvider.$get (angular-ui-router.js:2830:40)
    at Object.invoke (angular.js:5097:1)
    at angular.js:4884:1
    at getService (angular.js:5038:1)
    at injectionArgs (angular.js:5063:1)
    at Object.invoke (angular.js:5089:1)
    at angular.js:4894:37
    at forEach (angular.js:408:1)
    at createInjector (angular.js:4894:1)
    at doBootstrap (angular.js:1955:1) 'Possibly unhandled rejection: {}'

and the app hangs at the splash screen

@shankari
Copy link
Contributor

Upgrading to ui-router to 0.3.1
per https://stackoverflow.com/a/41515812/4040267

$ npm list | grep ui
├── [email protected]
├── [email protected]

did not fix the issue

@JGreenlee
Copy link
Collaborator Author

Does it hang on splash immediately on launch, or after onboarding?

@shankari
Copy link
Contributor

shankari commented Jun 28, 2023

on splash immediately after launch

EDIT: Stuck on this screen

Screenshot 2023-06-28 at 2 51 22 PM

You should be able to reproduce if you remove and reinstall the devapp

@JGreenlee
Copy link
Collaborator Author

The instance of ui-router we are using is in manual_lib, so upgrading it from npm probably won't do anything.

When I added Webpack, I did try using other versions of ui-router from npm and it didn't work. I think ionic wants this specific version - I believe it was part of the ionic bundle

@JGreenlee
Copy link
Collaborator Author

I'll try building later

@shankari
Copy link
Contributor

For the record, I also tried

diff --git a/www/js/app.js b/www/js/app.js
index eeb65a0e..5c95bfcc 100644
--- a/www/js/app.js
+++ b/www/js/app.js
@@ -106,9 +106,10 @@ angular.module('emission', ['ionic', 'jm.i18next',
   console.log("Ending run");
 })

-.config(function($stateProvider, $urlRouterProvider, $compileProvider) {
+.config(function($stateProvider, $qProvider, $urlRouterProvider, $compileProvider) {
   console.log("Starting config");
   // alert("config");
+  $qProvider.errorOnUnhandledRejections(false)

   // Ionic uses AngularUI Router which uses the concept of states
   // Learn more here: https://github.com/angular-ui/ui-router

from https://stackoverflow.com/a/43777868/4040267
but got the same error

I'll try building later

I don't think you need to build, just uninstall + reinstall the devapp

@shankari
Copy link
Contributor

For the record, this also happens on iOS (as would be expected)

@JGreenlee
Copy link
Collaborator Author

JGreenlee commented Jun 29, 2023

@shankari
I was unable to reproduce the issue. I see the same error messages, but it's not hanging on the splash screen.
I don't think the error messages are the problem.

Using framework_migration_prep:
First, I tried just uninstalling + reinstalling the devapp in the Simulator (Devapp version 3.2.5)
After reinstalling and connecting, the join page still appeared correctly. I was able to log in and everything seemed fine.

Next, I tried reproducing the issue on a build.
I setup and activated the native configuration, preparing for an android build

Then npm run build, which bundled JS with webpack and then built the app with cordova.
I installed the generated apk on a test phone with adb install

Result:

image

@JGreenlee
Copy link
Collaborator Author

Could the issue somehow be specific to the 'NREL OpenPATH' deployment?

I only built the 'emission' deployment (because that's all I know how to do)

@shankari
Copy link
Contributor

wait, so you are still getting the error, but the join page still launches?!
Reading carefully through your message, I think that the problem was that I wasn't running npm run build
I was running npx webpack manually before, but might have forgotten to run it before this build. Oops!
Stay tuned...

@shankari
Copy link
Contributor

I think we will also need to change bin/sign_and_align_keys.sh to match - let me do that as well

@JGreenlee
Copy link
Collaborator Author

JGreenlee commented Jun 29, 2023

FYI npm run build uses the prod Webpack configuration (--config webpack.prod.js)

image

Which minifies JS and fixes the Angular annotations with the babel plugin

I haven't tested dev Webpack + Cordova build

shankari pushed a commit that referenced this pull request Jul 6, 2023
* switched collect and sync lists over to react

* inserted a placeholding div control-list-item

This is not yet complete, but is an idea of where the schedule table might eventually be

* patch from Jack

incorporating a patch from Jack with a solution to some of the issues with scheduled notifications, as well as cleaning up some of the style around the control-data-table (s) I converted earlier

* added keys to rows

found an error in the console alerting to the fact that each row should have a unique key, so I added keys
one concern: the upcoming notifications keys end up being the dates - could those ever be repetitive?

* removal of non-relevant code

took out the code that was a part of a different effort to prevent confusion, also removed commented out code form replacing elements

* replacing hard coded strings

the "Upcoming Notifications" and "Dummy Notification in 5 Seconds statements were hard coded, I've added them as internationalized strings and updated the en.json file

* start at storing data in better place

I started to convert the data storage, data is fine in general-settings.js but is failing to make it through main-control.html to ControlDataTable.jsx

* spelling

* starting to work with other rows of profile

this is where I'm struggling with the parameterization of i18n keys

* setting up issue in using key as parameter

Added in code so the broken setting row is enabled, note the console.log statement demoing the different ways the info comes through

* fixing strings

in Angular, string parameters need to be created as "'string'" - this should resolve some of the issues that I have been experiencing here

Co-authored-by: Jack Greenlee <[email protected]>

* text working on sample list item

after I learned how to pass strings, I was able to render the row as a list item, which will hopefully eventually be good for showing everything as a list, and can have icons built in

Icons and passing through functionality are next

* carry data storage change through

switching from plugin storage to scheduler storage

Co-authored-by: Jack Greenlee <[email protected]>

* polishing up - removing print statements, altering log

after fix from Jack (2nd place to update where notifs come from) added in optional chain to reduce errors in table, took out diagnostic log statements, updated Logger.log to show num, time, and first notif

* update comments, eliminate changes not a part of this PR

the setting-row process has been separated to More profile migrations #994

* action parameters for setting rows - some work

have a rough outline going of some setting rows that say and do the right thing! More complex actions, some text, and icons still need lots of work

* comments and spacing

I added a bunch of comments and whitespace to make it easier for myself to see what needs to be done -- I'll reformat once I have things working

* more row migrations

most rows now migrated, still need to handle some with slightly unique functionality, styling with icons also needed!

* rough draft - two rows unconverted

all rows ugly but functional but need guidance on reminder time and demographics button

* fixing strings - i18n

* enabling icons - copy Jack's related commit

6578d8a

* got icons in

still missing some visual cues (toggle switches, expansion flippers)

* tidy code - still ways to go

* combine logout and copy (eliminate copy)

* convert to use of IconButtons

now the button is what has action, not the entire row - there's a bug requiring an empty onPress in the list Item for the one in IconButton to work see issue callstack/react-native-paper#3898 and hopefully soon to be fix  callstack/react-native-paper#3908

* introduce toggle switches

the two items that had switches are now interactive again, there is work to be done with getting the switches to have the proper starting value

toggle switch: https://callstack.github.io/react-native-paper/docs/components/Switch/

* experiment with list accordian

converted the user data section to a list accordian - works great! Unfortunately relies right now on a lot of hard-coding

* use of .map for creating the collapsing list!

first-run at creating a drop-down part of the menu with map and passing in a data structure

* both drop-downs converted to ExpandMenu components

fully converted the userData and devZone to the react element, creates an accordian element that has SettingRow and ControlDataTable elements

* profile settings component draft

* profile settings in general settings

* first set settings now in ProfileSettingsComponent

creating an over-arching component for the ProfileSettings -- still passing in functions, some things have bugs/functional differences noted in comments

* different method of passing info to Profile Settings

* introduce Demographics Setting Row

* rough sketch everything in ProfileSettings

working towards full migration and pulling everything into a single react Component. This is not working perfectly, there are a lot of things to handle that are currently commented out

* more of migration to ProfileSettings component

removing some commented out code
in ExpandMenu.jsx, props is now the listed parameter, this allows to get the default parameter props.children to populate the inner components. the section Title is accessed with props.sectionTitle

* adding a value in the scope for the accuracy setting

working on the switches, and trying to get their displayed value to match the value of the think they control

* adding additional argument to angularize call

this is needed from changes in #993

* cleaned up irrelivant codes and comments

* Revert "fixing merge conflicts"

This reverts commit ffd2bc2, reversing
changes made to a3097ac.

---------

Co-authored-by: Jack Greenlee <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Address code reviews with "future"
Development

Successfully merging this pull request may close these issues.

2 participants