mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Refactered App structure and naming
no issue - Moved `ParentContainer.js` to redundant empty top level `App.js` to remove extra nesting and improved naming - Renamed `ParentContext` to `AppContext` and exported as default - Fixed imports in all the components and test-utils with new structure - Passed `siteUrl` to api setup from main App to allow easier configuration - Updated App tests
This commit is contained in:
parent
1fc8f86507
commit
8df822d317
14 changed files with 332 additions and 317 deletions
|
@ -1,13 +1,279 @@
|
|||
import React from 'react';
|
||||
import TriggerButton from './components/TriggerButton';
|
||||
import PopupModal from './components/PopupModal';
|
||||
import setupGhostApi from './utils/api';
|
||||
import AppContext from './AppContext';
|
||||
import './App.css';
|
||||
import ParentContainer from './components/ParentContainer';
|
||||
|
||||
function App(props) {
|
||||
return (
|
||||
<div className="App">
|
||||
<ParentContainer data={props.data} />
|
||||
</div>
|
||||
);
|
||||
const React = require('react');
|
||||
|
||||
export default class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// Setup custom trigger button handling
|
||||
this.setupCustomTriggerButton();
|
||||
|
||||
// testState is used by App.test to pass custom default state for testing
|
||||
this.state = props.testState || {
|
||||
site: null,
|
||||
member: null,
|
||||
page: 'loading',
|
||||
showPopup: false,
|
||||
action: 'init:running',
|
||||
initStatus: 'running',
|
||||
lastPage: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevState.showPopup !== this.state.showPopup) {
|
||||
this.handleCustomTriggerClassUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.customTriggerButtons.forEach((customTriggerButton) => {
|
||||
customTriggerButton.addEventListener('click', this.clickHandler);
|
||||
});
|
||||
}
|
||||
|
||||
handleCustomTriggerClassUpdate() {
|
||||
const popupOpenClass = 'gh-members-popup-open';
|
||||
const popupCloseClass = 'gh-members-popup-close';
|
||||
this.customTriggerButtons.forEach((customButton) => {
|
||||
const elAddClass = this.state.showPopup ? popupOpenClass : popupCloseClass;
|
||||
const elRemoveClass = this.state.showPopup ? popupCloseClass : popupOpenClass;
|
||||
customButton.classList.add(elAddClass);
|
||||
customButton.classList.remove(elRemoveClass);
|
||||
});
|
||||
}
|
||||
|
||||
getStripeUrlParam() {
|
||||
const url = new URL(window.location);
|
||||
return url.searchParams.get('stripe');
|
||||
}
|
||||
|
||||
getDefaultPage({member = this.state.member, stripeParam} = {}) {
|
||||
// Loads default page and popup state for local UI testing
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return {
|
||||
page: 'signup',
|
||||
showPopup: true
|
||||
};
|
||||
}
|
||||
if (!member && stripeParam === 'success') {
|
||||
return {page: 'magiclink', showPopup: true};
|
||||
}
|
||||
if (member) {
|
||||
return {
|
||||
page: 'accountHome'
|
||||
};
|
||||
}
|
||||
return {
|
||||
page: 'signup'
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch site and member session data with Ghost Apis
|
||||
async fetchData() {
|
||||
const {siteUrl} = this.props;
|
||||
try {
|
||||
this.GhostApi = setupGhostApi({siteUrl});
|
||||
const {site, member} = await this.GhostApi.init();
|
||||
site.isStripeConfigured = (site.isStripeConfigured === undefined) || site.isStripeConfigured;
|
||||
const stripeParam = this.getStripeUrlParam();
|
||||
const {page, showPopup = false} = this.getDefaultPage({member, stripeParam});
|
||||
this.setState({
|
||||
site,
|
||||
member,
|
||||
page,
|
||||
showPopup,
|
||||
action: 'init:success',
|
||||
initStatus: 'success'
|
||||
});
|
||||
} catch (e) {
|
||||
/* eslint-disable no-console */
|
||||
console.error(`[Members.js] Failed to initialize`);
|
||||
/* eslint-enable no-console */
|
||||
this.setState({
|
||||
action: 'init:failed',
|
||||
initStatus: 'failed'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setupCustomTriggerButton() {
|
||||
// Handler for custom buttons
|
||||
this.clickHandler = (event) => {
|
||||
const target = event.currentTarget;
|
||||
const page = target && target.dataset.membersTriggerButton;
|
||||
|
||||
event.preventDefault();
|
||||
this.onAction('openPopup', {page});
|
||||
};
|
||||
const customTriggerSelector = '[data-members-trigger-button]';
|
||||
const popupCloseClass = 'gh-members-popup-close';
|
||||
this.customTriggerButtons = document.querySelectorAll(customTriggerSelector) || [];
|
||||
this.customTriggerButtons.forEach((customTriggerButton) => {
|
||||
customTriggerButton.classList.add(popupCloseClass);
|
||||
customTriggerButton.addEventListener('click', this.clickHandler);
|
||||
});
|
||||
}
|
||||
|
||||
getActionData(action) {
|
||||
const [type, status, reason] = action.split(':');
|
||||
return {type, status, reason};
|
||||
}
|
||||
|
||||
getBrandColor() {
|
||||
return (this.state.site && this.state.site.brand && this.state.site.brand.primaryColor) || '#3db0ef';
|
||||
}
|
||||
|
||||
async onAction(action, data) {
|
||||
this.setState({
|
||||
action: `${action}:running`
|
||||
});
|
||||
try {
|
||||
if (action === 'switchPage') {
|
||||
this.setState({
|
||||
page: data.page,
|
||||
lastPage: data.lastPage || null
|
||||
});
|
||||
} else if (action === 'togglePopup') {
|
||||
this.setState({
|
||||
showPopup: !this.state.showPopup
|
||||
});
|
||||
} else if (action === 'openPopup') {
|
||||
this.setState({
|
||||
showPopup: true,
|
||||
page: data.page
|
||||
});
|
||||
} else if (action === 'back') {
|
||||
if (this.state.lastPage) {
|
||||
this.setState({
|
||||
page: this.state.lastPage
|
||||
});
|
||||
}
|
||||
} else if (action === 'closePopup') {
|
||||
const {page: defaultPage} = this.getDefaultPage();
|
||||
this.setState({
|
||||
showPopup: false,
|
||||
page: this.state.page === 'magiclink' ? defaultPage : this.state.page
|
||||
});
|
||||
} else if (action === 'signout') {
|
||||
await this.GhostApi.member.signout();
|
||||
this.setState({
|
||||
action: 'signout:success'
|
||||
});
|
||||
} else if (action === 'signin') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
this.setState({
|
||||
action: 'signin:success',
|
||||
page: 'magiclink'
|
||||
});
|
||||
} else if (action === 'signup') {
|
||||
const {plan, email, name} = data;
|
||||
if (plan.toLowerCase() === 'free') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
} else {
|
||||
await this.GhostApi.member.checkoutPlan({plan, email, name});
|
||||
}
|
||||
this.setState({
|
||||
action: 'signup:success',
|
||||
page: 'magiclink'
|
||||
});
|
||||
} else if (action === 'updateEmail') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
this.setState({
|
||||
action: 'updateEmail:success'
|
||||
});
|
||||
} else if (action === 'checkoutPlan') {
|
||||
const {plan} = data;
|
||||
await this.GhostApi.member.checkoutPlan({
|
||||
plan
|
||||
});
|
||||
} else if (action === 'updateSubscription') {
|
||||
const {plan, subscriptionId, cancelAtPeriodEnd} = data;
|
||||
await this.GhostApi.member.updateSubscription({
|
||||
planName: plan, subscriptionId, cancelAtPeriodEnd
|
||||
});
|
||||
const member = await this.GhostApi.member.sessionData();
|
||||
this.setState({
|
||||
action: 'updateSubscription:success',
|
||||
page: 'accountHome',
|
||||
member: member
|
||||
});
|
||||
} else if (action === 'editBilling') {
|
||||
await this.GhostApi.member.editBilling();
|
||||
} else if (action === 'updateMember') {
|
||||
const {name, subscribed} = data;
|
||||
const member = await this.GhostApi.member.update({name, subscribed});
|
||||
if (!member) {
|
||||
this.setState({
|
||||
action: 'updateMember:failed'
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
action: 'updateMember:success',
|
||||
member: member
|
||||
});
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
action: ''
|
||||
});
|
||||
}, 5000);
|
||||
} catch (e) {
|
||||
this.setState({
|
||||
action: `${action}:failed`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderPopup() {
|
||||
if (this.state.showPopup) {
|
||||
return (
|
||||
<PopupModal />
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderTriggerButton() {
|
||||
if (!this.customTriggerButtons || this.customTriggerButtons.length === 0) {
|
||||
return (
|
||||
<TriggerButton
|
||||
isPopupOpen={this.state.showPopup}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.initStatus === 'success') {
|
||||
const {site, member, action, page, lastPage} = this.state;
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={{
|
||||
site,
|
||||
member,
|
||||
action,
|
||||
brandColor: this.getBrandColor(),
|
||||
page,
|
||||
lastPage,
|
||||
onAction: (_action, data) => this.onAction(_action, data)
|
||||
}}>
|
||||
{this.renderPopup()}
|
||||
{this.renderTriggerButton()}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -1,13 +1,35 @@
|
|||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {site, member} from './utils/fixtures';
|
||||
import App from './App';
|
||||
|
||||
test('renders App', () => {
|
||||
const {container} = render(
|
||||
<App />
|
||||
const setup = (overrides) => {
|
||||
const testState = {
|
||||
site,
|
||||
member: member.free,
|
||||
action: 'init:success',
|
||||
brandColor: site.brand.primaryColor,
|
||||
page: 'signup',
|
||||
initStatus: 'success',
|
||||
showPopup: true
|
||||
};
|
||||
const {...utils} = render(
|
||||
<App testState={testState} />
|
||||
);
|
||||
const triggerButtonFrame = utils.getByTitle(/membersjs-trigger/i);
|
||||
const popupFrame = utils.getByTitle(/membersjs-popup/i);
|
||||
return {
|
||||
popupFrame,
|
||||
triggerButtonFrame,
|
||||
...utils
|
||||
};
|
||||
};
|
||||
|
||||
// dashboard component should be rendered on root route
|
||||
const element = container.querySelector('.App');
|
||||
expect(element).toBeInTheDocument();
|
||||
describe('App', () => {
|
||||
test('renders popup and trigger frames', () => {
|
||||
const {popupFrame, triggerButtonFrame} = setup();
|
||||
|
||||
expect(popupFrame).toBeInTheDocument();
|
||||
expect(triggerButtonFrame).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -1,10 +1,12 @@
|
|||
// Ref: https://reactjs.org/docs/context.html
|
||||
const React = require('react');
|
||||
|
||||
export const ParentContext = React.createContext({
|
||||
const AppContext = React.createContext({
|
||||
site: {},
|
||||
member: {},
|
||||
action: '',
|
||||
brandColor: '',
|
||||
onAction: () => {}
|
||||
});
|
||||
});
|
||||
|
||||
export default AppContext;
|
|
@ -1,275 +0,0 @@
|
|||
import TriggerButton from './TriggerButton';
|
||||
import PopupModal from './PopupModal';
|
||||
import setupGhostApi from '../utils/api';
|
||||
import {ParentContext} from './ParentContext';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
export default class ParentContainer extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Setup custom trigger button handling
|
||||
this.setupCustomTriggerButton();
|
||||
|
||||
this.state = {
|
||||
page: 'loading',
|
||||
showPopup: false,
|
||||
action: 'init:running',
|
||||
initStatus: 'running',
|
||||
lastPage: null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevState.showPopup !== this.state.showPopup) {
|
||||
this.handleCustomTriggerClassUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.customTriggerButtons.forEach((customTriggerButton) => {
|
||||
customTriggerButton.addEventListener('click', this.clickHandler);
|
||||
});
|
||||
}
|
||||
|
||||
handleCustomTriggerClassUpdate() {
|
||||
const popupOpenClass = 'gh-members-popup-open';
|
||||
const popupCloseClass = 'gh-members-popup-close';
|
||||
this.customTriggerButtons.forEach((customButton) => {
|
||||
const elAddClass = this.state.showPopup ? popupOpenClass : popupCloseClass;
|
||||
const elRemoveClass = this.state.showPopup ? popupCloseClass : popupOpenClass;
|
||||
customButton.classList.add(elAddClass);
|
||||
customButton.classList.remove(elRemoveClass);
|
||||
});
|
||||
}
|
||||
|
||||
getStripeUrlParam() {
|
||||
const url = new URL(window.location);
|
||||
return url.searchParams.get('stripe');
|
||||
}
|
||||
|
||||
getDefaultPage({member = this.state.member, stripeParam} = {}) {
|
||||
// Loads default page and popup state for local UI testing
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return {
|
||||
page: 'signup',
|
||||
showPopup: true
|
||||
};
|
||||
}
|
||||
if (!member && stripeParam === 'success') {
|
||||
return {page: 'magiclink', showPopup: true};
|
||||
}
|
||||
if (member) {
|
||||
return {
|
||||
page: 'accountHome'
|
||||
};
|
||||
}
|
||||
return {
|
||||
page: 'signup'
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch site and member session data with Ghost Apis
|
||||
async fetchData() {
|
||||
try {
|
||||
this.GhostApi = setupGhostApi();
|
||||
const {site, member} = await this.GhostApi.init();
|
||||
site.isStripeConfigured = (site.isStripeConfigured === undefined) || site.isStripeConfigured;
|
||||
const stripeParam = this.getStripeUrlParam();
|
||||
const {page, showPopup = false} = this.getDefaultPage({member, stripeParam});
|
||||
this.setState({
|
||||
site,
|
||||
member,
|
||||
page,
|
||||
showPopup,
|
||||
action: 'init:success',
|
||||
initStatus: 'success'
|
||||
});
|
||||
} catch (e) {
|
||||
/* eslint-disable no-console */
|
||||
console.error(`[Members.js] Failed to initialize`);
|
||||
/* eslint-enable no-console */
|
||||
this.setState({
|
||||
action: 'init:failed',
|
||||
initStatus: 'failed'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setupCustomTriggerButton() {
|
||||
// Handler for custom buttons
|
||||
this.clickHandler = (event) => {
|
||||
const target = event.currentTarget;
|
||||
const page = target && target.dataset.membersTriggerButton;
|
||||
|
||||
event.preventDefault();
|
||||
this.onAction('openPopup', {page});
|
||||
};
|
||||
const customTriggerSelector = '[data-members-trigger-button]';
|
||||
const popupCloseClass = 'gh-members-popup-close';
|
||||
this.customTriggerButtons = document.querySelectorAll(customTriggerSelector) || [];
|
||||
this.customTriggerButtons.forEach((customTriggerButton) => {
|
||||
customTriggerButton.classList.add(popupCloseClass);
|
||||
customTriggerButton.addEventListener('click', this.clickHandler);
|
||||
});
|
||||
}
|
||||
|
||||
getActionData(action) {
|
||||
const [type, status, reason] = action.split(':');
|
||||
return {type, status, reason};
|
||||
}
|
||||
|
||||
getBrandColor() {
|
||||
return (this.state.site && this.state.site.brand && this.state.site.brand.primaryColor) || '#3db0ef';
|
||||
}
|
||||
|
||||
async onAction(action, data) {
|
||||
this.setState({
|
||||
action: `${action}:running`
|
||||
});
|
||||
try {
|
||||
if (action === 'switchPage') {
|
||||
this.setState({
|
||||
page: data.page,
|
||||
lastPage: data.lastPage || null
|
||||
});
|
||||
} else if (action === 'togglePopup') {
|
||||
this.setState({
|
||||
showPopup: !this.state.showPopup
|
||||
});
|
||||
} else if (action === 'openPopup') {
|
||||
this.setState({
|
||||
showPopup: true,
|
||||
page: data.page
|
||||
});
|
||||
} else if (action === 'back') {
|
||||
if (this.state.lastPage) {
|
||||
this.setState({
|
||||
page: this.state.lastPage
|
||||
});
|
||||
}
|
||||
} else if (action === 'closePopup') {
|
||||
const {page: defaultPage} = this.getDefaultPage();
|
||||
this.setState({
|
||||
showPopup: false,
|
||||
page: this.state.page === 'magiclink' ? defaultPage : this.state.page
|
||||
});
|
||||
} else if (action === 'signout') {
|
||||
await this.GhostApi.member.signout();
|
||||
this.setState({
|
||||
action: 'signout:success'
|
||||
});
|
||||
} else if (action === 'signin') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
this.setState({
|
||||
action: 'signin:success',
|
||||
page: 'magiclink'
|
||||
});
|
||||
} else if (action === 'signup') {
|
||||
const {plan, email, name} = data;
|
||||
if (plan.toLowerCase() === 'free') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
} else {
|
||||
await this.GhostApi.member.checkoutPlan({plan, email, name});
|
||||
}
|
||||
this.setState({
|
||||
action: 'signup:success',
|
||||
page: 'magiclink'
|
||||
});
|
||||
} else if (action === 'updateEmail') {
|
||||
await this.GhostApi.member.sendMagicLink(data);
|
||||
this.setState({
|
||||
action: 'updateEmail:success'
|
||||
});
|
||||
} else if (action === 'checkoutPlan') {
|
||||
const {plan} = data;
|
||||
await this.GhostApi.member.checkoutPlan({
|
||||
plan
|
||||
});
|
||||
} else if (action === 'updateSubscription') {
|
||||
const {plan, subscriptionId, cancelAtPeriodEnd} = data;
|
||||
await this.GhostApi.member.updateSubscription({
|
||||
planName: plan, subscriptionId, cancelAtPeriodEnd
|
||||
});
|
||||
const member = await this.GhostApi.member.sessionData();
|
||||
this.setState({
|
||||
action: 'updateSubscription:success',
|
||||
page: 'accountHome',
|
||||
member: member
|
||||
});
|
||||
} else if (action === 'editBilling') {
|
||||
await this.GhostApi.member.editBilling();
|
||||
} else if (action === 'updateMember') {
|
||||
const {name, subscribed} = data;
|
||||
const member = await this.GhostApi.member.update({name, subscribed});
|
||||
if (!member) {
|
||||
this.setState({
|
||||
action: 'updateMember:failed'
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
action: 'updateMember:success',
|
||||
member: member
|
||||
});
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
action: ''
|
||||
});
|
||||
}, 5000);
|
||||
} catch (e) {
|
||||
this.setState({
|
||||
action: `${action}:failed`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderPopup() {
|
||||
if (this.state.showPopup) {
|
||||
return (
|
||||
<PopupModal />
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderTriggerButton() {
|
||||
if (!this.customTriggerButtons || this.customTriggerButtons.length === 0) {
|
||||
return (
|
||||
<TriggerButton
|
||||
isPopupOpen={this.state.showPopup}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.initStatus === 'success') {
|
||||
const {site, member} = this.state;
|
||||
|
||||
return (
|
||||
<ParentContext.Provider value={{
|
||||
site,
|
||||
member,
|
||||
action: this.state.action,
|
||||
brandColor: this.getBrandColor(),
|
||||
page: this.state.page,
|
||||
lastPage: this.state.lastPage,
|
||||
onAction: (action, data) => this.onAction(action, data)
|
||||
}}>
|
||||
{this.renderPopup()}
|
||||
{this.renderTriggerButton()}
|
||||
</ParentContext.Provider>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ import AccountHomePage from './pages/AccountHomePage';
|
|||
import MagicLinkPage from './pages/MagicLinkPage';
|
||||
import LoadingPage from './pages/LoadingPage';
|
||||
import {ReactComponent as CloseIcon} from '../images/icons/close.svg';
|
||||
import {ParentContext} from './ParentContext';
|
||||
import AppContext from '../AppContext';
|
||||
import FrameStyle from './Frame.styles';
|
||||
import AccountPlanPage from './pages/AccountPlanPage';
|
||||
import AccountProfilePage from './pages/AccountProfilePage';
|
||||
|
@ -42,6 +42,7 @@ const StylesWrapper = ({member}) => {
|
|||
width: '100%',
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
textAlign: 'center',
|
||||
backgroundColor: 'rgba(128,128,128,0.5)'
|
||||
},
|
||||
frame: {
|
||||
|
@ -123,7 +124,7 @@ const Pages = {
|
|||
};
|
||||
|
||||
export default class PopupModal extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
renderCurrentPage(page) {
|
||||
const PageComponent = Pages[page];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import Frame from './Frame';
|
||||
import MemberGravatar from './common/MemberGravatar';
|
||||
import {ParentContext} from './ParentContext';
|
||||
import AppContext from '../AppContext';
|
||||
import {ReactComponent as UserIcon} from '../images/icons/user.svg';
|
||||
import {ReactComponent as CloseIcon} from '../images/icons/close.svg';
|
||||
const React = require('react');
|
||||
|
@ -62,7 +62,7 @@ const Styles = ({brandColor}) => {
|
|||
};
|
||||
|
||||
export default class TriggerButton extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
onToggle() {
|
||||
this.context.onAction('togglePopup');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
import MemberAvatar from '../common/MemberGravatar';
|
||||
import ActionButton from '../common/ActionButton';
|
||||
import Switch from '../common/Switch';
|
||||
|
@ -59,7 +59,7 @@ const UserHeader = ({member}) => {
|
|||
};
|
||||
|
||||
class FreeAccountHomePage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
handleSignout(e) {
|
||||
e.preventDefault();
|
||||
|
@ -120,7 +120,7 @@ class FreeAccountHomePage extends React.Component {
|
|||
}
|
||||
|
||||
class PaidAccountHomePage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
handleSignout(e) {
|
||||
e.preventDefault();
|
||||
|
@ -254,7 +254,7 @@ class PaidAccountHomePage extends React.Component {
|
|||
}
|
||||
}
|
||||
export default class AccountHomePage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
render() {
|
||||
const {member} = this.context;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
import ActionButton from '../common/ActionButton';
|
||||
import PlansSection from '../common/PlansSection';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
export default class AccountPlanPage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
import MemberAvatar from '../common/MemberGravatar';
|
||||
import ActionButton from '../common/ActionButton';
|
||||
import InputField from '../common/InputField';
|
||||
|
@ -7,7 +7,7 @@ import Switch from '../common/Switch';
|
|||
const React = require('react');
|
||||
|
||||
export default class AccountProfilePage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ActionButton from '../common/ActionButton';
|
||||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
const React = require('react');
|
||||
|
||||
export default class MagicLinkPage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
renderFormHeader() {
|
||||
return (
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import ActionButton from '../common/ActionButton';
|
||||
import InputField from '../common/InputField';
|
||||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
export default class SigninPage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import ActionButton from '../common/ActionButton';
|
||||
import InputField from '../common/InputField';
|
||||
import {ParentContext} from '../ParentContext';
|
||||
import AppContext from '../../AppContext';
|
||||
import PlansSection from '../common/PlansSection';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
class SignupPage extends React.Component {
|
||||
static contextType = ParentContext;
|
||||
static contextType = AppContext;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import * as Fixtures from './fixtures';
|
||||
|
||||
function setupGhostApi() {
|
||||
function setupGhostApi({siteUrl = window.location.origin}) {
|
||||
const apiPath = 'members/api';
|
||||
const siteUrl = window.location.origin;
|
||||
|
||||
function endpointFor({type, resource}) {
|
||||
if (type === 'members') {
|
||||
return `${siteUrl}/${apiPath}/${resource}/`;
|
||||
return `${siteUrl.replace(/\/$/, '')}/${apiPath}/${resource}/`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
// Common test setup util - Ref: https://testing-library.com/docs/react-testing-library/setup#custom-render
|
||||
import React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {ParentContext} from '../components/ParentContext';
|
||||
import AppContext from '../AppContext';
|
||||
import {site, member} from './fixtures';
|
||||
|
||||
const setupProvider = (context) => {
|
||||
return ({children}) => {
|
||||
return (
|
||||
<ParentContext.Provider value={context}>
|
||||
<AppContext.Provider value={context}>
|
||||
{children}
|
||||
</ParentContext.Provider>
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue