Просмотр исходного кода

Merge pull request #18419 from overleaf/mf-plans-page-permanent-url

[web] Create permanent URL for all plans and switch state in the plans page

GitOrigin-RevId: 5fa0af0e33868f8fa4f6a74627bedb4c22705cb0
M Fahru 2 лет назад
Родитель
Сommit
c722dcbc8d

+ 4 - 1
services/web/app/views/layout/fat-footer-website-redesign.pug

@@ -49,7 +49,10 @@ footer.fat-footer.hidden-print.website-redesign-fat-footer
 					li
 					li
 						a(href="/for/universities") #{translate('for_universities')}
 						a(href="/for/universities") #{translate('for_universities')}
 					li
 					li
-						a(href="/user/subscription/plans?itm_referrer=footer-for-students#view=student") #{translate('for_students')}
+						a(
+							data-ol-for-students-link
+							href="/user/subscription/plans?itm_referrer=footer-for-students#student-annual"
+						) #{translate('for_students')}
 						
 						
 			.footer-section
 			.footer-section
 				h2.footer-section-heading #{translate('get_involved')}
 				h2.footer-section-heading #{translate('get_involved')}

+ 4 - 1
services/web/app/views/layout/fat-footer.pug

@@ -49,7 +49,10 @@ footer.fat-footer.hidden-print
 					li
 					li
 						a(href="/for/universities") #{translate('for_universities')}
 						a(href="/for/universities") #{translate('for_universities')}
 					li
 					li
-						a(href="/user/subscription/plans?itm_referrer=footer-for-students#view=student") #{translate('for_students')}
+						a(
+							data-ol-for-students-link
+							href="/user/subscription/plans?itm_referrer=footer-for-students#student-annual"
+						) #{translate('for_students')}
 						
 						
 			.footer-section
 			.footer-section
 				h2.footer-section-heading #{translate('get_involved')}
 				h2.footer-section-heading #{translate('get_involved')}

+ 47 - 0
services/web/frontend/js/pages/user/subscription/plans-v2/plans-v2-hash.js

@@ -0,0 +1,47 @@
+export function getViewInfoFromHash() {
+  const hash = window.location.hash.substring(1)
+
+  switch (hash) {
+    case 'individual-monthly':
+      return ['individual', 'monthly']
+    case 'individual-annual':
+      return ['individual', 'annual']
+    case 'group':
+      return ['group', 'annual']
+    case 'student-monthly':
+      return ['student', 'monthly']
+    case 'student-annual':
+      return ['student', 'annual']
+    default:
+      return ['individual', 'monthly']
+  }
+}
+
+/**
+ *
+ * @param {individual | group | student} viewTab
+ * @param {monthly | annual} period
+ */
+export function setHashFromViewTab(viewTab, period) {
+  const newHash = viewTab === 'group' ? 'group' : `${viewTab}-${period}`
+  if (window.location.hash.substring(1)) {
+    window.location.hash = newHash
+  }
+}
+
+// this is only for the students link in footer
+export function handleForStudentsLinkInFooter() {
+  const links = document.querySelectorAll('[data-ol-for-students-link]')
+
+  links.forEach(function (link) {
+    link.addEventListener('click', function () {
+      if (window.location.pathname === '/user/subscription/plans') {
+        // reload location with the correct hash
+        const newURL =
+          '/user/subscription/plans?itm_referrer=footer-for-students#student-annual'
+        history.replaceState(null, '', newURL)
+        location.reload()
+      }
+    })
+  })
+}

+ 65 - 24
services/web/frontend/js/pages/user/subscription/plans-v2/plans-v2-main.js

@@ -13,6 +13,11 @@ import {
   updateMainGroupPlanPricing,
   updateMainGroupPlanPricing,
 } from './plans-v2-group-plan'
 } from './plans-v2-group-plan'
 import { setUpGroupSubscriptionButtonAction } from './plans-v2-subscription-button'
 import { setUpGroupSubscriptionButtonAction } from './plans-v2-subscription-button'
+import {
+  getViewInfoFromHash,
+  handleForStudentsLinkInFooter,
+  setHashFromViewTab,
+} from './plans-v2-hash'
 import getMeta from '../../../../utils/meta'
 import getMeta from '../../../../utils/meta'
 
 
 const currentCurrencyCode = getMeta('ol-recommendedCurrency')
 const currentCurrencyCode = getMeta('ol-recommendedCurrency')
@@ -116,6 +121,9 @@ function selectTab(viewTab) {
   updateMonthlyAnnualSwitchValue(viewTab)
   updateMonthlyAnnualSwitchValue(viewTab)
 
 
   toggleUniversityInfo(viewTab)
   toggleUniversityInfo(viewTab)
+
+  // update the hash to reflect the current view when switching individual, group, or student tabs
+  setHashFromViewTab(viewTab, currentMonthlyAnnualSwitchValue)
 }
 }
 
 
 function updateMonthlyAnnualSwitchValue(viewTab) {
 function updateMonthlyAnnualSwitchValue(viewTab) {
@@ -190,19 +198,22 @@ function toggleUniversityInfo(viewTab) {
   el.hidden = viewTab !== 'student'
   el.hidden = viewTab !== 'student'
 }
 }
 
 
-function selectViewFromHash() {
+// This is the old scheme for hashing redirection
+// This is deprecated and should be removed in the future
+// This is only used for backward compatibility
+function selectViewFromHashDeprecated() {
   try {
   try {
     const params = new URLSearchParams(window.location.hash.substring(1))
     const params = new URLSearchParams(window.location.hash.substring(1))
     const view = params.get('view')
     const view = params.get('view')
     if (view) {
     if (view) {
       // View params are expected to be of the format e.g. individual or individual-monthly
       // View params are expected to be of the format e.g. individual or individual-monthly
-      const [tab, cadence] = view.split('-')
+      const [tab, period] = view.split('-')
       // make sure the selected view is valid
       // make sure the selected view is valid
       if (document.querySelector(`[data-ol-plans-v2-view-tab="${tab}"]`)) {
       if (document.querySelector(`[data-ol-plans-v2-view-tab="${tab}"]`)) {
         selectTab(tab)
         selectTab(tab)
 
 
-        if (['monthly', 'annual'].includes(cadence)) {
-          currentMonthlyAnnualSwitchValue = cadence
+        if (['monthly', 'annual'].includes(period)) {
+          currentMonthlyAnnualSwitchValue = period
         } else {
         } else {
           // set annual as the default
           // set annual as the default
           currentMonthlyAnnualSwitchValue = 'annual'
           currentMonthlyAnnualSwitchValue = 'annual'
@@ -210,24 +221,8 @@ function selectViewFromHash() {
 
 
         updateMonthlyAnnualSwitchValue(tab)
         updateMonthlyAnnualSwitchValue(tab)
 
 
-        // clear the hash so it doesn't persist when switching plans
-        const currentURL = window.location.pathname + window.location.search
-        history.replaceState('', document.title, currentURL)
-
-        // Add a small delay since it seems the scroll won't behave correctly on this scenario:
-        // 1. Open plans page
-        // 2. Click on "Group Plans"
-        // 3. Scroll down to footer
-        // 4. Click "For students" link
-        //
-        // I assume this is happening because the `selectTab` function above is doing a lot
-        // of computation to change the view and it somehow prevents the `window.scrollTo` command
-        // to behave correctly.
-        const SCROLL_TO_TOP_DELAY = 50
-
-        window.setTimeout(() => {
-          window.scrollTo({ top: 0, behavior: 'smooth' })
-        }, SCROLL_TO_TOP_DELAY)
+        // change the hash with the new scheme
+        setHashFromViewTab(tab, currentMonthlyAnnualSwitchValue)
       }
       }
     }
     }
   } catch {
   } catch {
@@ -235,6 +230,35 @@ function selectViewFromHash() {
   }
   }
 }
 }
 
 
+function selectViewAndPeriodFromHash() {
+  const [viewTab, period] = getViewInfoFromHash()
+
+  // the sequence of these three lines is important
+  // because `currentMonthlyAnnualSwitchValue` is mutable.
+  // `selectTab` and `updateMonthlyAnnualSwitchValue` depend on the value of `currentMonthlyAnnualSwitchValue`
+  // to determine the UI state
+  currentMonthlyAnnualSwitchValue = period
+  selectTab(viewTab)
+  updateMonthlyAnnualSwitchValue(viewTab)
+
+  // handle the case where user access plans page while still on the plans page
+  // current example would the the "For students" link on the footer
+  const SCROLL_TO_TOP_DELAY = 50
+  window.setTimeout(() => {
+    window.scrollTo({ top: 0, behavior: 'smooth' })
+  }, SCROLL_TO_TOP_DELAY)
+}
+
+// call the function to select the view and period from the hash value
+// this is called once when the page is loaded
+if (window.location.hash) {
+  if (window.location.hash.includes('view')) {
+    selectViewFromHashDeprecated()
+  } else {
+    selectViewAndPeriodFromHash()
+  }
+}
+
 document
 document
   .querySelector('[data-ol-plans-v2-m-a-switch]')
   .querySelector('[data-ol-plans-v2-m-a-switch]')
   .addEventListener('click', () => {
   .addEventListener('click', () => {
@@ -249,6 +273,15 @@ document
     }
     }
 
 
     switchMonthlyAnnual(currentMonthlyAnnualSwitchValue)
     switchMonthlyAnnual(currentMonthlyAnnualSwitchValue)
+
+    // update the hash to reflect the current view when pressing the monthly-annual switch
+    const DEFAULT_VIEW_TAB = 'individual'
+    const viewTab =
+      document
+        .querySelector('[data-ol-plans-v2-m-a-switch-container]')
+        .getAttribute('data-ol-current-view') ?? DEFAULT_VIEW_TAB
+
+    setHashFromViewTab(viewTab, currentMonthlyAnnualSwitchValue)
   })
   })
 
 
 document
 document
@@ -261,6 +294,14 @@ setUpMonthlyAnnualSwitching()
 setUpGroupSubscriptionButtonAction()
 setUpGroupSubscriptionButtonAction()
 setUpStickyHeaderObserver()
 setUpStickyHeaderObserver()
 updateLinkTargets()
 updateLinkTargets()
+handleForStudentsLinkInFooter()
 
 
-selectViewFromHash()
-window.addEventListener('hashchange', selectViewFromHash)
+window.addEventListener('hashchange', () => {
+  if (window.location.hash) {
+    if (window.location.hash.includes('view')) {
+      selectViewFromHashDeprecated()
+    } else {
+      selectViewAndPeriodFromHash()
+    }
+  }
+})