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

[$1000] Date of birth year deep link does not change the year #21261

Closed
4 of 6 tasks
kbecciv opened this issue Jun 21, 2023 · 56 comments
Closed
4 of 6 tasks

[$1000] Date of birth year deep link does not change the year #21261

kbecciv opened this issue Jun 21, 2023 · 56 comments
Assignees
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 Engineering External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors

Comments

@kbecciv
Copy link

kbecciv commented Jun 21, 2023

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Action Performed:

  1. Open the app and login with user A
  2. Open settings
  3. Open profile
  4. Open personal details
  5. Open date of birth
  6. Open year search
  7. Select any year and copy the url
  8. Logout and login with user B or login with user B in incognito
  9. Visit link copied in step 7 and observe that app changes the year in year selection but does not change the year in textbox above
  10. Change date and observe that app still considers old selected year and not the new year displayed in year selection

Expected Result:

I think it's odd that we change the link from https://staging.new.expensify.com/settings/profile/personal-details/date-of-birth to https://staging.new.expensify.com/settings/profile/personal-details/date-of-birth?year=YYYY when you select a different year of birth (before saving). But we don't change the link at all when adjusting month or day of birth.

IMO, the ideal behavior here is to stop changing the link when you adjust year of birth before saving. And then make it so you can't deep link to change your year of birth at all. This isn't something an actual user will frequently/ever be doing.

Actual Result:

App does not change the year in textbox above datepicker and also does not consider the new year on date selection if we visit modified year deep link

Workaround:

Unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

  • Android / native
  • Android / Chrome
  • iOS / native
  • iOS / Safari
  • MacOS / Chrome / Safari
  • MacOS / Desktop

Version Number: 1.3.27-6

Reproducible in staging?: y

Reproducible in production?: y

If this was caught during regression testing, add the test name, ID and link from TestRail:

Email or phone of affected tester (no customers):

Logs: https://stackoverflow.com/c/expensify/questions/4856

Notes/Photos/Videos: Any additional supporting documentation

deep.link.modified.year.not.working.1.mp4

Expensify/Expensify Issue URL:

Issue reported by: @dhanashree-sawant

Slack conversation: https://expensify.slack.com/archives/C049HHMV9SM/p1686756962010819

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~0190aa89bc7487f806
  • Upwork Job ID: 1671627605530898432
  • Last Price Increase: 2023-07-12
@kbecciv kbecciv added Daily KSv2 Needs Reproduction Reproducible steps needed Bug Something is broken. Auto assigns a BugZero manager. labels Jun 21, 2023
@melvin-bot
Copy link

melvin-bot bot commented Jun 21, 2023

Triggered auto assignment to @joekaufmanexpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

@melvin-bot
Copy link

melvin-bot bot commented Jun 21, 2023

Bug0 Triage Checklist (Main S/O)

  • This "bug" occurs on a supported platform (ensure Platforms in OP are ✅)
  • This bug is not a duplicate report (check E/App issues and #expensify-bugs)
    • If it is, comment with a link to the original report, close the issue and add any novel details to the original issue instead
  • This bug is reproducible using the reproduction steps in the OP. S/O
    • If the reproduction steps are clear and you're unable to reproduce the bug, check with the reporter and QA first, then close the issue.
    • If the reproduction steps aren't clear and you determine the correct steps, please update the OP.
  • This issue is filled out as thoroughly and clearly as possible
    • Pay special attention to the title, results, platforms where the bug occurs, and if the bug happens on staging/production.
  • I have reviewed and subscribed to the linked Slack conversation to ensure Slack/Github stay in sync

@joekaufmanexpensify
Copy link
Contributor

I can reproduce this. Though, I think it's odd that we change the link from https://staging.new.expensify.com/settings/profile/personal-details/date-of-birth to https://staging.new.expensify.com/settings/profile/personal-details/date-of-birth?year=YYYY when you select a different year of birth (before saving). But we don't change the link at all when adjusting month or day of birth.

IMO, the ideal behavior here is to stop changing the link when you adjust year of birth before saving. And then make it so you can't deep link to change your year of birth at all. This isn't something an actual user will frequently/ever be doing.

@joekaufmanexpensify joekaufmanexpensify added External Added to denote the issue can be worked on by a contributor and removed Needs Reproduction Reproducible steps needed labels Jun 21, 2023
@melvin-bot melvin-bot bot changed the title Date of birth year deep link does not change the year [$1000] Date of birth year deep link does not change the year Jun 21, 2023
@melvin-bot
Copy link

melvin-bot bot commented Jun 21, 2023

Job added to Upwork: https://www.upwork.com/jobs/~0190aa89bc7487f806

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Jun 21, 2023
@melvin-bot
Copy link

melvin-bot bot commented Jun 21, 2023

Current assignee @joekaufmanexpensify is eligible for the External assigner, not assigning anyone new.

@melvin-bot
Copy link

melvin-bot bot commented Jun 21, 2023

Triggered auto assignment to Contributor-plus team member for initial proposal review - @allroundexperts (External)

@ghost
Copy link

ghost commented Jun 21, 2023

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

selectedYear state variable in CalendarPicker component was not initialized by year param from route props, so it was initialized by dob

class CalendarPicker extends React.PureComponent {
constructor(props) {
super(props);
let currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
let currentDateView = currentSelection.toDate();
if (props.selectedYear) {
currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
}
if (props.selectedMonth != null) {
currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
}
if (props.maxDate < currentDateView) {
currentDateView = props.maxDate;
currentSelection = moment(props.maxDate);
} else if (props.minDate > currentDateView) {
currentDateView = props.minDate;
currentSelection = moment(props.minDate);
}
this.state = {
currentDateView,
selectedYear: currentSelection.get('year').toString(),
selectedMonth: this.getNumberStringWithLeadingZero(currentSelection.get('month') + 1),
selectedDay: this.getNumberStringWithLeadingZero(currentSelection.get('date')),
};

What changes do you think we should make in order to solve the problem?

need to initialize selectedYear need to be initialized by year param from route props and call onSelected callback which is one of props.

    const currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
    let currentDateView = currentSelection.toDate();

    if (props.selectedYear) {
        currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
    }
    if (props.selectedMonth != null) {
        currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
    }
    if (props.maxDate < currentDateView) {
        currentDateView = props.maxDate;
    } else if (props.minDate > currentDateView) {
        currentDateView = props.minDate;
    }

    this.state = {
        currentDateView,
        selectedYear: currentDateView.getFullYear().toString(),
        selectedMonth: this.getNumberStringWithLeadingZero(currentDateView.getMonth() + 1),
        selectedDay: this.getNumberStringWithLeadingZero(currentDateView.getDate()),
    };
    this.props.onSelected(this.getSelectedDateString());

Result:

Screen.Recording.2023-06-22.at.7.43.03.AM.mov

What alternative solutions did you explore? (Optional)

N/A

@wildan-m
Copy link
Contributor

wildan-m commented Jun 22, 2023

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

We are replacing the currentDateView year but not replacing currentSelection year from the route

if (props.selectedYear) {
currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
}

Also we are using the setParams when supply the param, this will generate the query string in the link

Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));

What changes do you think we should make in order to solve the problem?

I've noticed that currently currency selector not showing its query string param in the link after selecting the currency,
IOUCurrencySelector use Navigation.navigate and directly supply the param in the string.

Navigation.navigate(`${this.props.route.params.backTo}?currency=${option.currencyCode}`);

Since year-selector behave similarly, then we can follow the currency selector pattern to achieve the same.

We can change updateSelectedYear(selectedYear) to

   updateSelectedYear(selectedYear) {
        const backTo = lodashGet(this.props.route, 'params.backTo', '');
        // When we refresh the web, the date of birth route gets cleared from the navigation stack.
        // Navigating to "backTo" will result in forward navigation instead, causing disruption to the year selection.
        // To prevent any negative experience, we have made the decision to simply close the year selection page.
        if (_.isEmpty(backTo) || this.props.navigation.getState().routes.length === 1) {
            Navigation.goBack();
        } else {
            Navigation.navigate(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
        }
    }

What alternative solutions did you explore? (Optional)

If we decided not delete the year param from the URL, we can replace the year from the very beginning when we init currentSelection variable

We can move this code before declaring currentDateView

if (props.selectedYear) {
currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
}

And replace the code with

        if (props.selectedYear) {
            currentSelection.year(props.selectedYear);
        }

Final snippet:

    constructor(props) {
        super(props);
        let currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
        if (props.selectedYear) {
            currentSelection.year(props.selectedYear);
        }

        let currentDateView = currentSelection.toDate();
        if (props.selectedMonth != null) {
            currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
        }

@dukenv0307
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

When selecting a year in YearPickerPage we will set the selected year on the route and then in DateOfBirthPage we will get the selected year from the route to use

What changes do you think we should make in order to solve the problem?

When selecting a year we should save the selected year on ONYX. To do that we will create a new function to update value on ONYX

function updateSelectedYear(selectedYear) {
    Onyx.merge(ONYXKEYS.PRIVATE_PERSONAL_DETAILS, {selectedYear});
}

and using this function when the user selects the year
Here

Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);

we should call updateSelectedYear(selectedYear) before navigate back a nd remove year on the route like this

PersonalDetails.updateSelectedYear(selectedYear);
            Navigation.goBack(ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH);

Also removing year on route when clicking the back button here

onBackButtonPress={() => Navigation.goBack(`${this.props.route.params.backTo}?year=${this.currentYear}` || ROUTES.HOME)}

And in DateOFBirthPage

const selectedYear = lodashGet(route.params, 'year', dobYear);

we should get selected year from ONYX instead of the route like this

const selectedYear = lodashGet(privatePersonalDetails, 'selectedYear', dobYear);

What alternative solutions did you explore? (Optional)

@melvin-bot
Copy link

melvin-bot bot commented Jun 22, 2023

Looks like something related to react-navigation may have been mentioned in this issue discussion.

As a reminder, please make sure that all proposals are not workarounds and that any and all attempt to fix the issue holistically have been made before proceeding with a solution. Proposals to change our DeprecatedCustomActions.js files should not be accepted.

Feel free to drop a note in #expensify-open-source with any questions.

@joekaufmanexpensify
Copy link
Contributor

Next steps are to review proposals here

@jfquevedol2198
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

selectedYear state variable in CalendarPicker component was not initialized by year param from route props, so it was initialized by dob

class CalendarPicker extends React.PureComponent {
constructor(props) {
super(props);
let currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
let currentDateView = currentSelection.toDate();
if (props.selectedYear) {
currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
}
if (props.selectedMonth != null) {
currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
}
if (props.maxDate < currentDateView) {
currentDateView = props.maxDate;
currentSelection = moment(props.maxDate);
} else if (props.minDate > currentDateView) {
currentDateView = props.minDate;
currentSelection = moment(props.minDate);
}
this.state = {
currentDateView,
selectedYear: currentSelection.get('year').toString(),
selectedMonth: this.getNumberStringWithLeadingZero(currentSelection.get('month') + 1),
selectedDay: this.getNumberStringWithLeadingZero(currentSelection.get('date')),
};

What changes do you think we should make in order to solve the problem?

need to initialize selectedYear need to be initialized by year param from route props and call onSelected callback which is one of props.

    const currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
    let currentDateView = currentSelection.toDate();

    if (props.selectedYear) {
        currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
    }
    if (props.selectedMonth != null) {
        currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
    }
    if (props.maxDate < currentDateView) {
        currentDateView = props.maxDate;
    } else if (props.minDate > currentDateView) {
        currentDateView = props.minDate;
    }

    this.state = {
        currentDateView,
        selectedYear: currentDateView.getFullYear().toString(),
        selectedMonth: this.getNumberStringWithLeadingZero(currentDateView.getMonth() + 1),
        selectedDay: this.getNumberStringWithLeadingZero(currentDateView.getDate()),
    };
    this.props.onSelected(this.getSelectedDateString());

Result:

Screen.Recording.2023-06-22.at.7.43.03.AM.mov

What alternative solutions did you explore? (Optional)

N/A

I needed to close my previous github. This was my proposal and this is my new github.

@melvin-bot
Copy link

melvin-bot bot commented Jun 23, 2023

📣 @jfquevedol2198! 📣
Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork.
Please follow these steps:

  1. Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
  2. Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
  3. Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details.
    Screen Shot 2022-11-16 at 4 42 54 PM
    Format:
Contributor details
Your Expensify account email: <REPLACE EMAIL HERE>
Upwork Profile Link: <REPLACE LINK HERE>

@joekaufmanexpensify
Copy link
Contributor

@allroundexperts thoughts on the above proposals?

@allroundexperts
Copy link
Contributor

Thanks for your proposal @jfquevedol2198 and @wildan-m. But as per this comment, we're looking to NOT save the current year in the route param. Please create new proposals with the result as described here.

@joekaufmanexpensify can you please update the OP with the correct expected result?

@dukenv0307 Your proposal looks promising but attaching the selected year to Private Details key of Onyx would sort of make this component tied to Personal Details section only. Can you please propose a generic way to handle the year selection?

Also, I'm not entirely sold on using Onyx to store this data because we don't want to restore this selection if the user refreshes the page. We're not doing that on any other form as far as I know. Please correct me if you think otherwise.

@allroundexperts
Copy link
Contributor

Still looking for more proposals.

@jfquevedol2198
Copy link
Contributor

jfquevedol2198 commented Jun 26, 2023

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

updateSelectedYear callback that calls when select an year from YearPickerPage component is adding year param in route.

updateSelectedYear(selectedYear) {
// We have to navigate using concatenation here as it is not possible to pass a function as a route param
const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
if (dateOfBirthRoute) {
Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
Navigation.goBack();
} else {
Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
}
}

What changes do you think we should make in order to solve the problem?

We need to add a function onSelectYear in DateOfBirthPage page component and store it in EventEmitter.
then, when select new year on YearPickerPage component, need to emit the stored function in EventEmitter

  1. Switch selectedYear to state variable in DateOfBirthPage component, it will be initialized by dobYear

const selectedYear = lodashGet(route.params, 'year', dobYear);

after change:

const [selectedYear, setSelectedYear] = useState(dobYear);
  1. Add EventEmitter module in src/libs
 const listenersMap = {};

 function addListener(eventName, listener) {
   listenersMap[eventName] = listenersMap[eventName] || [];
   listenersMap[eventName].push(listener);
 }

 function removeListener(eventName, listener) {
   const lis = listenersMap[eventName];
   if (!lis) return;

   for (let i = lis.length - 1; i >= 0; i--) {
     if (lis[i] === listener) {
       lis.splice(i, 1);
       break;
     }
   }
 }

 function removeAllListeners(eventName) {
   listenersMap[eventName] = [];
 }

 function emit(eventName, ...params) {
   const listeners = listenersMap[eventName];
   if (!listeners) return false;
   listeners.forEach(fnc => {
     fnc(...params);
   });
   return true;
 }

 export default {
   addListener,
   removeListener,
   removeAllListeners,
   emit,
 };
  1. Add onSelectYear method in DateOfBirthPage component to get the new selected year from YearPickerPage and register onSelectYear method into EventEmitter.
    const onSelectYear = (year) => {
        setSelectedYear(year);
    }

    useEffect(() => {
        EventEmitter.addListener('onSelectYear', onSelectYear);
        return () => EventEmitter.removeListener('onSelectYear', onSelectYear);
    }, []);
  1. Update updateSelectedYear method on YearPickerPage component .
    original updateSelectedYear method:
    updateSelectedYear(selectedYear) {
    // We have to navigate using concatenation here as it is not possible to pass a function as a route param
    const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
    const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
    if (dateOfBirthRoute) {
    Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
    Navigation.goBack();
    } else {
    Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
    }
    }

after change:

    updateSelectedYear(selectedYear) {
        EventEmitter.emit('onSelectYear', `${selectedYear}`);
        Navigation.goBack();
    }

Result

Screen.Recording.2023-06-26.at.12.54.13.PM.mov

What alternative solutions did you explore? (Optional)

N/A

@joekaufmanexpensify
Copy link
Contributor

Updated expected behavior in OP!

@joekaufmanexpensify
Copy link
Contributor

Pending review of new proposal

@allroundexperts
Copy link
Contributor

Thanks for your updated proposal @jfquevedol2198. I'm not entirely convinced of the event emitter approach that you're trying to adopt. I would much prefer a React way to fix this.

@jfquevedol2198
Copy link
Contributor

jfquevedol2198 commented Jun 28, 2023

Proposal

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

updateSelectedYear callback that calls when select an year from YearPickerPage component is adding year param in route.

updateSelectedYear(selectedYear) {
// We have to navigate using concatenation here as it is not possible to pass a function as a route param
const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
if (dateOfBirthRoute) {
Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
Navigation.goBack();
} else {
Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
}
}

What changes do you think we should make in order to solve the problem?

Add a callback to handle the new year selection in DateOfBirthPage component and create an action to be called to update the selectedYear state variable of DateOfBirthPage from YearPickerPage component.

  1. Switch selectedYear to state variable in DateOfBirthPage component, it will be initialized by dobYear

const selectedYear = lodashGet(route.params, 'year', dobYear);

after change:

const [selectedYear, setSelectedYear] = useState(dobYear);
  1. Add an action in src/libs/actions/SelectYearAction
import React from 'react';

const onSelectYearRef = React.createRef();

function set(onSelectYear) {
 onSelectYearRef.current = onSelectYear;
}

function update(year) {
 if (!onSelectYearRef.current) return;
 onSelectYearRef.current(year);
}

export {set, update};
  1. Add onSelectYear method in DateOfBirthPage component to get the new selected year from YearPickerPage and register onSelectYear in SelectYearAction
    useEffect(() => {
        const onSelectYear = (year) => setSelectedYear(year);
        SelectYearAction.set(onSelectYear);
    }, [])
  1. Update updateSelectedYear method on YearPickerPage component .
    original updateSelectedYear method:
    updateSelectedYear(selectedYear) {
    // We have to navigate using concatenation here as it is not possible to pass a function as a route param
    const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
    const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
    if (dateOfBirthRoute) {
    Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
    Navigation.goBack();
    } else {
    Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
    }
    }

after change:

    updateSelectedYear(selectedYear) {
        SelectYearAction.update(selectedYear);
        Navigation.goBack();
    }
Result
Screen.Recording.2023-06-28.at.1.13.32.PM.mov

What alternative solutions did you explore? (Optional)

N/A

@melvin-bot
Copy link

melvin-bot bot commented Jul 5, 2023

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

@melvin-bot melvin-bot bot added the Overdue label Jul 5, 2023
@joekaufmanexpensify
Copy link
Contributor

@allroundexperts could you please re-review the updated proposals when you have a chance?

@melvin-bot melvin-bot bot removed the Overdue label Jul 5, 2023
@melvin-bot
Copy link

melvin-bot bot commented Jul 5, 2023

@allroundexperts @joekaufmanexpensify this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

@allroundexperts
Copy link
Contributor

@joekaufmanexpensify I'll have an update by tomorrow.

@joekaufmanexpensify
Copy link
Contributor

Great, thanks!

@joekaufmanexpensify
Copy link
Contributor

Pending review of updated proposals.

@melvin-bot melvin-bot bot added the Overdue label Jul 10, 2023
@joekaufmanexpensify
Copy link
Contributor

@allroundexperts bump on reviewing updated proposals when you have a sec?

@melvin-bot melvin-bot bot removed the Overdue label Jul 10, 2023
@allroundexperts
Copy link
Contributor

Ah. Not sure how I missed this. Will put this on top of my plate for today.

@joekaufmanexpensify
Copy link
Contributor

Great, ty!

@allroundexperts
Copy link
Contributor

@jfquevedol2198 Thanks for sharing your branch. The issue I can see with your current approach is that it won't be able to handle multiple Year selection fields on the same page. I think we can simplify this problem by using React Contexts. Let me know your thoughts.

@jfquevedol2198
Copy link
Contributor

jfquevedol2198 commented Jul 10, 2023

@allroundexperts You are right, if we have multiple Year selection fields, it won't work exactly.
I just updated it in the same branch.
React Ref can be turned into React Contexts if its better.
Main Concept is to add a inputID asRef in SelectYearAction for identifying of DatePicker of YearSelection and when select New Year, it will update proper state by the inputID

@jfquevedol2198
Copy link
Contributor

@allroundexperts here is the example with multiple Year selection on a page:

Screen.Recording.2023-07-11.at.7.56.54.AM.mov

@allroundexperts
Copy link
Contributor

@jfquevedol2198 Thanks for the update. Can you please update your proposal with the new changes as well?

@jfquevedol2198
Copy link
Contributor

jfquevedol2198 commented Jul 11, 2023

[Updated Proposal]

Please re-state the problem that we are trying to solve in this issue.

Date of birth year deep link does not change the year

What is the root cause of that problem?

updateSelectedYear callback that calls when select an year from YearPickerPage component is adding year param in route.

updateSelectedYear(selectedYear) {
// We have to navigate using concatenation here as it is not possible to pass a function as a route param
const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
if (dateOfBirthRoute) {
Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
Navigation.goBack();
} else {
Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
}
}

What changes do you think we should make in order to solve the problem?

Add a callback to handle the new year selection in DateOfBirthPage component and create an action to be called to update the selectedYear state variable of DateOfBirthPage from YearPickerPage component.
We can do this for currency selection, too.

  1. Switch selectedYear to state variable in DateOfBirthPage component, it will be initialized by dobYear

const selectedYear = lodashGet(route.params, 'year', dobYear);

after change:

const [selectedYear, setSelectedYear] = useState(dobYear);
  1. Add an action in src/libs/actions/SelectYearAction
import React from 'react';

// store action to handle Year Update
const onSelectYearRef = React.createRef();
// store inputID of DatePicker Form for identifying Form in the case of multiple `DatePicker` on same page
const inputIdRef = React.createRef();

function set(onSelectYear) {
 onSelectYearRef.current = onSelectYear;
}

function emit(year) {
 if (!onSelectYearRef.current) return;
 onSelectYearRef.current(inputIdRef.current, year);
}

function updateInputID(inputID) {
 inputIdRef.current = inputID;
}

export {set, emit, updateInputID};
  1. Add onSelectYear method in DateOfBirthPage component to get the new selected year from YearPickerPage and register onSelectYear in SelectYearAction
    useEffect(() => {
        const onSelectYear = (inputId, year) => {
            if (inputId !== 'dob') return;
            setSelectedYear(year.toString());
        }
        SelectYearAction.set(onSelectYear);
    }, [])
  1. Update CalendarPicker component by adding id prop to identify which DatePicker is selected for YearSelection, It will setup inputID by id prop onYearPickerPressed callback.
const propTypes = {
    /** A string to identify calendar picker */
    id: PropTypes.string,
    ...
}

onYearPickerPressed() {
        SelectYearAction.updateInputID(this.props.id);
        ...
}
  1. Update updateSelectedYear method on YearPickerPage component .
    original updateSelectedYear method:
    updateSelectedYear(selectedYear) {
    // We have to navigate using concatenation here as it is not possible to pass a function as a route param
    const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
    const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
    if (dateOfBirthRoute) {
    Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
    Navigation.goBack();
    } else {
    Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
    }
    }

after change:

    updateSelectedYear(selectedYear) {
        SelectYearAction.emit(selectedYear);
        Navigation.goBack();
    }
Result
Screen.Recording.2023-06-28.at.1.13.32.PM.mov

What alternative solutions did you explore? (Optional)

N/A

@joekaufmanexpensify
Copy link
Contributor

Pending review of updated proposal

@allroundexperts
Copy link
Contributor

I'm still not sure if using Actions is the correct way to do this. As such, I've asked here for more opinions.

@melvin-bot
Copy link

melvin-bot bot commented Jul 12, 2023

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

@joekaufmanexpensify
Copy link
Contributor

Sounds good, thanks!

@melvin-bot
Copy link

melvin-bot bot commented Jul 12, 2023

@allroundexperts @joekaufmanexpensify this issue is now 3 weeks old. There is one more week left before this issue breaks WAQ and will need to go internal. What needs to happen to get a PR in review this week? Please create a thread in #expensify-open-source to discuss. Thanks!

@mountiny
Copy link
Contributor

I am curious is this still a bug after the Calendar refactor we did here #21792?

@joekaufmanexpensify
Copy link
Contributor

Ah, yep good call. I just rechecked now, and it looks like this was fixed by that PR. We no longer specify the year in the link when you change the year of birth in the date picker. So I feel like we can go ahead and close this. Does that sound good to everyone?

@allroundexperts
Copy link
Contributor

Sounds good to me!

@joekaufmanexpensify
Copy link
Contributor

Cool cool. Closing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 Engineering External Added to denote the issue can be worked on by a contributor Help Wanted Apply this label when an issue is open to proposals by contributors
Projects
None yet
Development

No branches or pull requests

7 participants