Skip to content

Commit

Permalink
Merge commit '0b1d904e39bb4157124829e144d76cc8383baf34' into update-v…
Browse files Browse the repository at this point in the history
…10.0.0-from-upstream
  • Loading branch information
Gnito committed Feb 14, 2023
2 parents 4a05152 + 0b1d904 commit 925bc78
Show file tree
Hide file tree
Showing 141 changed files with 7,694 additions and 1,096 deletions.
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,25 @@ https://github.com/sharetribe/flex-template-web/

---

## Upcoming version 2022-XX-XX
## Upcoming version 2023-XX-XX

## [v12.0.0] 2023-02-14

### Updates from upstream (FTW-daily v10.0.0)

- [add] This adds support for page asset files that can be created in Console. These asset files are
taken into use for

- LandingPage
- TermsOfServicePage
- PrivacyPolicyPage
- AboutPage
- and other static pages can also be created through Console (they'll be visible in route:
/p/:asset-name/)

[#1520](https://github.com/sharetribe/ftw-daily/pull/1520)

[v12.0.0]: https://github.com/sharetribe/ftw-hourly/compare/v11.1.0.../v12.0.0

## [v11.1.0] 2023-02-07

Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app",
"version": "11.1.0",
"version": "12.0.0",
"private": true,
"license": "Apache-2.0",
"dependencies": {
Expand Down Expand Up @@ -55,11 +55,16 @@
"react-with-direction": "^1.4.0",
"redux": "^4.2.0",
"redux-thunk": "^2.4.1",
"rehype-react": "^6.2.1",
"rehype-sanitize": "^4.0.0",
"remark-parse": "^9.0.0",
"remark-rehype": "^8.1.0",
"seedrandom": "^3.0.5",
"sharetribe-flex-sdk": "^1.17.0",
"sharetribe-scripts": "6.0.1",
"smoothscroll-polyfill": "^0.4.0",
"source-map-support": "^0.5.21",
"unified": "^9.2.2",
"url": "^0.11.0"
},
"devDependencies": {
Expand Down
8 changes: 6 additions & 2 deletions server/csp.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const defaultDirectives = {
'*.stripe.com',
],
fontSrc: [self, data, 'assets-sharetribecom.sharetribe.com', 'fonts.gstatic.com'],
frameSrc: [self, '*.stripe.com'],
frameSrc: [self, '*.stripe.com', '*.youtube-nocookie.com'],
imgSrc: [
self,
data,
Expand All @@ -50,7 +50,8 @@ const defaultDirectives = {
'sharetribe.imgix.net', // Safari 9.1 didn't recognize asterisk rule.

// Styleguide placeholder images
'lorempixel.com',
'picsum.photos',
'*.picsum.photos',
'via.placeholder.com',

'api.mapbox.com',
Expand All @@ -65,6 +66,9 @@ const defaultDirectives = {
'www.google-analytics.com',
'stats.g.doubleclick.net',

// Youtube (static image)
'*.ytimg.com',

'*.stripe.com',
],
scriptSrc: [
Expand Down
21 changes: 11 additions & 10 deletions server/dataLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@ exports.loadData = function(requestUrl, sdk, appInfo) {
let translations = {};
const store = configureStore({}, sdk);

const dataLoadingCalls = matchedRoutes.reduce((calls, match) => {
const { route, params } = match;
if (typeof route.loadData === 'function' && !route.auth) {
calls.push(store.dispatch(route.loadData(params, query)));
}
return calls;
}, []);
const dataLoadingCalls = () =>
matchedRoutes.reduce((calls, match) => {
const { route, params } = match;
if (typeof route.loadData === 'function' && !route.auth) {
calls.push(store.dispatch(route.loadData(params, query)));
}
return calls;
}, []);

// First fetch app-wide assets
// Then make loadData calls
// And return object containing preloaded state and translations
// This order supports other asset (in the future) that should be fetched before data calls.
return store
.dispatch(fetchAppAssets(config.appCdnAssets))
.then(fetchedAssets => {
translations = fetchedAssets?.translations?.data || {};
return Promise.all(dataLoadingCalls);
.then(fetchedAppAssets => {
translations = fetchedAppAssets?.translations?.data || {};
return Promise.all(dataLoadingCalls());
})
.then(() => {
return { preloadedState: store.getState(), translations };
Expand Down
34 changes: 27 additions & 7 deletions src/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ const callLoadData = props => {
if (shouldLoadData) {
dispatch(loadData(match.params, location.search))
.then(() => {
// eslint-disable-next-line no-console
console.log(`loadData success for ${name} route`);
if (props.logLoadDataCalls) {
// This gives good input for debugging issues on live environments, but with test it's not needed.
console.log(`loadData success for ${name} route`);
}
})
.catch(e => {
log.error(e, 'load-data-failed', { routeName: name });
});
}
};

const setPageScrollPosition = location => {
const setPageScrollPosition = (location, delayed) => {
if (!location.hash) {
// No hash, scroll to top
window.scroll({
Expand All @@ -58,12 +60,23 @@ const setPageScrollPosition = location => {
block: 'start',
behavior: 'smooth',
});
} else {
// A naive attempt to make a delayed call to scrollIntoView
// Note: 300 milliseconds might not be enough, but adding too much delay
// might affect user initiated scrolling.
delayed = window.setTimeout(() => {
const reTry = document.querySelector(location.hash);
reTry.scrollIntoView({
block: 'start',
behavior: 'smooth',
});
}, 300);
}
}
};

const handleLocationChanged = (dispatch, location) => {
setPageScrollPosition(location);
const handleLocationChanged = (dispatch, location, delayed) => {
setPageScrollPosition(location, delayed);
const path = canonicalRoutePath(routeConfiguration(), location);
dispatch(locationChanged(location, path));
};
Expand All @@ -78,9 +91,10 @@ const handleLocationChanged = (dispatch, location) => {
*/
class RouteComponentRenderer extends Component {
componentDidMount() {
this.delayed = null;
// Calling loadData on initial rendering (on client side).
callLoadData(this.props);
handleLocationChanged(this.props.dispatch, this.props.location);
handleLocationChanged(this.props.dispatch, this.props.location, this.delayed);
}

componentDidUpdate(prevProps) {
Expand All @@ -91,7 +105,13 @@ class RouteComponentRenderer extends Component {
// This makes it possible to use loadData as default client side data loading technique.
// However it is better to fetch data before location change to avoid "Loading data" state.
callLoadData(this.props);
handleLocationChanged(this.props.dispatch, this.props.location);
handleLocationChanged(this.props.dispatch, this.props.location, this.delayed);
}
}

componentWillUnmount() {
if (this.delayed) {
window.clearTimeout(this.resetTimeoutId);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ const setupLocale = () => {
export const ClientApp = props => {
const { store, hostedTranslations = {} } = props;
setupLocale();
// This gives good input for debugging issues on live environments, but with test it's not needed.
const logLoadDataCalls = config?.env !== 'test';
return (
<IntlProvider
locale={config.locale}
Expand All @@ -101,7 +103,7 @@ export const ClientApp = props => {
<Provider store={store}>
<HelmetProvider>
<BrowserRouter>
<Routes routes={routeConfiguration()} />
<Routes routes={routeConfiguration()} logLoadDataCalls={logLoadDataCalls} />
</BrowserRouter>
</HelmetProvider>
</Provider>
Expand Down
17 changes: 15 additions & 2 deletions src/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@ afterAll(() => {
});

describe('Application - JSDOM environment', () => {
it('renders in the client without crashing', () => {
it('renders the LandingPage without crashing', () => {
window.google = { maps: {} };
const store = configureStore();

// LandingPage gets rendered and it calls hostedAsset > fetchPageAssets > sdk.assetByVersion
const pageData = {
data: {
sections: [],
_schema: './schema.json',
},
meta: {
version: 'bCsMYVYVawc8SMPzZWJpiw',
},
};
const resolvePageAssetCall = () => Promise.resolve(pageData);
const fakeSdk = { assetByVersion: resolvePageAssetCall, assetByAlias: resolvePageAssetCall };
const store = configureStore({}, fakeSdk);
const div = document.createElement('div');
ReactDOM.render(<ClientApp store={store} />, div);
delete window.google;
Expand Down
37 changes: 37 additions & 0 deletions src/components/AspectRatioWrapper/AspectRatioWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { node, number, string } from 'prop-types';
import classNames from 'classnames';

import css from './AspectRatioWrapper.module.css';

const AspectRatioWrapper = props => {
const { children, className, rootClassName, width, height, ...rest } = props;
const classes = classNames(rootClassName || css.root, className);

const aspectRatio = (height / width) * 100;
const paddingBottom = `${aspectRatio}%`;

return (
<div className={classes} {...rest}>
<div className={css.aspectPadding} style={{ paddingBottom }}>
<div className={css.aspectBox}>{children}</div>
</div>
</div>
);
};

AspectRatioWrapper.defaultProps = {
className: null,
rootClassName: null,
children: null,
};

AspectRatioWrapper.propTypes = {
className: string,
rootClassName: string,
width: number.isRequired,
height: number.isRequired,
children: node,
};

export default AspectRatioWrapper;
21 changes: 21 additions & 0 deletions src/components/AspectRatioWrapper/AspectRatioWrapper.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.root {
/* Layout */
display: block;
width: 100%;
position: relative;
}

/* Firefox doesn't support image aspect ratio inside flexbox */
/* Aspect ratio for is given inline */
.aspectPadding {
}

.aspectBox {
/* Layout - image will take space defined by aspect ratio wrapper */
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
}
4 changes: 2 additions & 2 deletions src/components/Avatar/Avatar.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ const userWithProfileImage = {
name: 'square-small',
width: 240,
height: 240,
url: 'https://lorempixel.com/240/240/people/',
url: 'https://picsum.photos/240/240/',
},
'square-small2x': {
name: 'square-small2x',
width: 480,
height: 480,
url: 'https://lorempixel.com/480/480/people/',
url: 'https://picsum.photos/480/480/',
},
},
},
Expand Down
9 changes: 7 additions & 2 deletions src/components/Footer/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const Footer = props => {
</NamedLink>
</li>
<li className={css.listItem}>
<NamedLink name="AboutPage" className={css.link}>
<NamedLink name="CMSPage" params={{ pageId: 'about' }} className={css.link}>
<FormattedMessage id="Footer.toAboutPage" />
</NamedLink>
</li>
Expand All @@ -104,7 +104,12 @@ const Footer = props => {
</NamedLink>
</li>
<li className={css.listItem}>
<NamedLink name="AboutPage" to={{ hash: '#contact' }} className={css.link}>
<NamedLink
name="CMSPage"
params={{ pageId: 'about' }}
to={{ hash: '#contact' }}
className={css.link}
>
<FormattedMessage id="Footer.toContactPage" />
</NamedLink>
</li>
Expand Down
Loading

0 comments on commit 925bc78

Please sign in to comment.