Skip to content

Commit 15bac36

Browse files
committed
🎨 Changed share hash route from #/portal/share to #/share
ref #26866 This switches share routing to #/share and keeps the old hash path disabled for the requested breaking change.
1 parent 46a9ace commit 15bac36

6 files changed

Lines changed: 67 additions & 6 deletions

File tree

apps/portal/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ By default, the script adds a default floating trigger button on the bottom righ
2222

2323
Its possible to add custom trigger button of your own by adding data attribute `data-portal` to any HTML tag on page, and also specify a specific [page](https://github.com/TryGhost/Ghost/blob/main/ghost/portal/src/pages.js#L13-L22) to open from it by using it as `data-portal=signup`.
2424

25-
Share modal can be opened with `data-portal="share"` (or `#/portal/share`).
25+
Share modal can be opened with `data-portal="share"` (or `#/share`).
2626

2727
Default (zero-config) usage:
2828
```html

apps/portal/src/app.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ export default class App extends React.Component {
532532
const productYearlyPriceQueryRegex = /^(?:(\w+?))?\/yearly$/;
533533
const offersRegex = /^offers\/(\w+?)\/?$/;
534534
const linkRegex = /^\/portal\/?(?:\/(\w+(?:\/\w+)*))?\/?$/;
535+
const shareRegex = /^\/share\/?$/;
535536
const feedbackRegex = /^\/feedback\/(\w+?)\/(\w+?)\/?$/;
536537

537538
if (path && feedbackRegex.test(path)) {
@@ -561,8 +562,21 @@ export default class App extends React.Component {
561562
}
562563
}
563564
}
565+
if (path && shareRegex.test(path)) {
566+
return {
567+
showPopup: true,
568+
page: 'share'
569+
};
570+
}
571+
564572
if (path && linkRegex.test(path)) {
565573
const [,pagePath] = path.match(linkRegex);
574+
575+
// `#/portal/share` has been replaced with `#/share`.
576+
if (pagePath === 'share') {
577+
return {};
578+
}
579+
566580
const {page, pageQuery, pageData} = this.getPageFromLinkPath(pagePath) || {};
567581

568582
// If user is not logged in and trying to access an account page,
@@ -1118,7 +1132,7 @@ export default class App extends React.Component {
11181132
* portal. Especially useful for copy/pasted links from Admin screens.
11191133
*/
11201134
transformPortalLinksToRelative() {
1121-
document.querySelectorAll('a[href*="#/portal"]').forEach(transformPortalAnchorToRelative);
1135+
document.querySelectorAll('a[href*="#/portal"], a[href*="#/share"]').forEach(transformPortalAnchorToRelative);
11221136
}
11231137

11241138
render() {

apps/portal/src/utils/transform-portal-anchor-to-relative.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
export function transformPortalAnchorToRelative(anchor) {
22
const href = anchor.getAttribute('href');
33
const url = new URL(href, window.location.origin);
4+
const supportedHashPrefixes = ['#/portal', '#/share'];
5+
const hasSupportedHashPrefix = supportedHashPrefixes.some(prefix => url.hash.startsWith(prefix));
6+
const hasRelativeSupportedHashPrefix = supportedHashPrefixes.some(prefix => href.startsWith(prefix));
47

58
// ignore non-portal links
6-
if (!url.hash || !url.hash.startsWith('#/portal')) {
9+
if (!url.hash || !hasSupportedHashPrefix) {
710
return;
811
}
912

1013
// ignore already-relative links
11-
if (href.startsWith('#/portal')) {
14+
if (hasRelativeSupportedHashPrefix) {
1215
return;
1316
}
1417

apps/portal/test/app.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ describe('App', function () {
6363
expect(link.getAttribute('href')).toBe('#/portal/signup');
6464
});
6565

66+
test('transforms share links on render', async () => {
67+
const link = document.createElement('a');
68+
link.setAttribute('href', 'http://example.com/#/share');
69+
document.body.appendChild(link);
70+
71+
const ghostApi = setupApi();
72+
const utils = appRender(
73+
<App siteUrl="http://example.com" api={ghostApi} />
74+
);
75+
76+
await utils.findByTitle(/portal-popup/i);
77+
78+
expect(link.getAttribute('href')).toBe('#/share');
79+
});
80+
6681
test('prefers locale prop over site locale for i18n language', async () => {
6782
const ghostApi = setupApi({
6883
site: {

apps/portal/test/portal-links.test.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ describe('Portal Data links:', () => {
189189
});
190190
});
191191

192-
describe('#/portal/share', () => {
192+
describe('#/share', () => {
193193
test('opens portal share page', async () => {
194-
window.location.hash = '#/portal/share';
194+
window.location.hash = '#/share';
195195
let {
196196
popupFrame, triggerButtonFrame, ...utils
197197
} = await setup({
@@ -204,6 +204,19 @@ describe('Portal Data links:', () => {
204204
const shareTitle = within(popupFrame.contentDocument).queryByText(/^Share$/i);
205205
expect(shareTitle).toBeInTheDocument();
206206
});
207+
208+
test('does not open share page with legacy #/portal/share path', async () => {
209+
window.location.hash = '#/portal/share';
210+
const {
211+
triggerButtonFrame, queryByTitle
212+
} = await setup({
213+
site: FixtureSite.singleTier.basic,
214+
showPopup: false
215+
});
216+
217+
expect(triggerButtonFrame).toBeInTheDocument();
218+
expect(queryByTitle(/portal-popup/i)).not.toBeInTheDocument();
219+
});
207220
});
208221

209222
describe('#/portal/signup/free', () => {

apps/portal/test/unit/transform-portal-anchor-to-relative.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ describe('transformPortalAnchorToRelative', function () {
1919
expect(anchor.getAttribute('href')).toBe('#/portal/signup');
2020
});
2121

22+
test('ignores already-relative share links', function () {
23+
const anchor = document.createElement('a');
24+
anchor.setAttribute('href', '#/share');
25+
transformPortalAnchorToRelative(anchor);
26+
27+
expect(anchor.getAttribute('href')).toBe('#/share');
28+
});
29+
2230
test('ignores external links', function () {
2331
const anchor = document.createElement('a');
2432
anchor.setAttribute('href', 'https://example.com/#/portal/signup');
@@ -34,4 +42,12 @@ describe('transformPortalAnchorToRelative', function () {
3442

3543
expect(anchor.getAttribute('href')).toBe('#/portal/signup');
3644
});
45+
46+
test('converts absolute share links to relative links', function () {
47+
const anchor = document.createElement('a');
48+
anchor.setAttribute('href', 'http://localhost:3000/#/share');
49+
transformPortalAnchorToRelative(anchor);
50+
51+
expect(anchor.getAttribute('href')).toBe('#/share');
52+
});
3753
});

0 commit comments

Comments
 (0)