Skip to content

Commit

Permalink
Refactor components to use React Hooks (#368)
Browse files Browse the repository at this point in the history
* refactor About component

* refactor ButtonLink component

* Refactor CompleteError

* refactor Footer to use hooks

* refactor Home to use hooks

* cleanup of  references

* refactor NotFound

* address code review comments

* destructure props in Button

---------

Co-authored-by: sdzhong <[email protected]>
  • Loading branch information
cstavitsky and sdzhong authored Jan 26, 2024
1 parent 16f7d87 commit 11eeec5
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 184 deletions.
106 changes: 50 additions & 56 deletions react/src/components/About.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Component } from 'react';
import { Link } from 'react-router-dom';
import slugify from '../utils/slugify';
import * as Sentry from '@sentry/react';
import './about.css';
import { isOddReleaseWeek, busy_sleep } from '../utils/time';
import { useEffect } from 'react';

import Jane from './employees/jane';
import Lily from './employees/lily';
Expand All @@ -14,33 +14,29 @@ import Noah from './employees/noah';

const employees = [Jane, Lily, Keith, Mason, Emma, Noah];

class About extends Component {
constructor() {
super();
// must be inside the constructor to affect LCP, if in componentDidMount() only affects duration
function About({ backend }) {
useEffect(() => {
if (!isOddReleaseWeek()) {
// can't have async sleep in a constructor
busy_sleep(Math.random(25) + 100);
}
}

async componentDidMount() {
// Http requests to make in parallel, so the Transaction has more Spans
let request1 = fetch(this.props.backend + '/api', {
let request1 = fetch(backend + '/api', {
method: 'GET',
});
let request2 = fetch(this.props.backend + '/organization', {
let request2 = fetch(backend + '/organization', {
method: 'GET',
});
let request3 = fetch(this.props.backend + '/connect', {
let request3 = fetch(backend + '/connect', {
method: 'GET',
});

// Need Safari13 in tests/config.py in order for this modern javascript to work in Safari Browser
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled#browser_compatibility
// let response = await Promise.allSettled([request1, request2, request3])

const response = [await request1, await request2, await request3];
const response = [request1, request2, request3];

// Error Handling
response.forEach((r) => {
Expand All @@ -55,53 +51,51 @@ class About extends Component {
);
}
});
}
render() {
return (
<div className="about-page">
<div>
<div className="about-info">
<h1>About us</h1>
<p>
Empower Plant is an IoT company determined to keep house plants
happy. After reading Michael Pollan’s 2013 New Yorker article
(“The Intelligent Plant”), the wife-and-wife founding team
invested their life savings in measuring and improving the
emotional state of their leafy housemates. Seven years later, the
company’s grown from its humble roots in the couples’ backyard
greenhouse (converted from a garage) into a Series C-funded San
Francisco startup and the world’s most accurate plant mood
measurer (“a must-have for any responsible plant parent,”
according to Plant Parenthood Magazine). Their original
state-of-the-art product is a technological marvel built with a
plant-first mindset, and they now offer a range of plant-centric
options.
</p>
<p>
Today, the company employs 170 people (and 852 plants) in San
Francisco, New York City, Denver, and Kiev.
</p>
</div>
</div>
<div>
<ul className="employee-list">
{employees.map((employee) => {
return (
<li key={employee.name}>
<Link to={`/employee/${slugify(employee.url)}`}>
<img src={employee.img} alt={`${employee.name}`} />
<h5 className="employee-name" name={employee.name}>
{employee.name}
</h5>
</Link>
</li>
);
})}
</ul>
}, []);

return (
<div className="about-page">
<div>
<div className="about-info">
<h1>About us</h1>
<p>
Empower Plant is an IoT company determined to keep house plants
happy. After reading Michael Pollan’s 2013 New Yorker article (“The
Intelligent Plant”), the wife-and-wife founding team invested their
life savings in measuring and improving the emotional state of their
leafy housemates. Seven years later, the company’s grown from its
humble roots in the couples’ backyard greenhouse (converted from a
garage) into a Series C-funded San Francisco startup and the world’s
most accurate plant mood measurer (“a must-have for any responsible
plant parent,” according to Plant Parenthood Magazine). Their
original state-of-the-art product is a technological marvel built
with a plant-first mindset, and they now offer a range of
plant-centric options.
</p>
<p>
Today, the company employs 170 people (and 852 plants) in San
Francisco, New York City, Denver, and Kiev.
</p>
</div>
</div>
);
}
<div>
<ul className="employee-list">
{employees.map((employee) => {
return (
<li key={employee.name}>
<Link to={`/employee/${slugify(employee.url)}`}>
<img src={employee.img} alt={`${employee.name}`} />
<h5 className="employee-name" name={employee.name}>
{employee.name}
</h5>
</Link>
</li>
);
})}
</ul>
</div>
</div>
);
}

export default Sentry.withProfiler(About, { name: 'About' });
15 changes: 6 additions & 9 deletions react/src/components/ButtonLink.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { Component } from 'react';
import { Link } from 'react-router-dom';

class Button extends Component {
render() {
return (
<Link {...this.props} className="btn">
{this.props.children}
</Link>
);
}
function Button({ to, children }) {
return (
<Link to={to} className="btn">
{children}
</Link>
);
}

export default Button;
30 changes: 14 additions & 16 deletions react/src/components/CompleteError.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Component } from 'react';
import { Link } from 'react-router-dom';
import './complete.css';
import * as Sentry from '@sentry/react';
import { useEffect } from 'react';

class CompleteError extends Component {
componentDidMount() {
function CompleteError() {
useEffect(() => {
window.setTimeout(() => {
if (sessionStorage.getItem('userFeedback') === 'true') {
sessionStorage.removeItem('userFeedback');
Expand All @@ -19,20 +19,18 @@ class CompleteError extends Component {
}
}
}, 3500);
}
});

render() {
return (
<div className="checkout-container-complete sentry-unmask">
<h2>We're having some trouble</h2>
<p>
We were unable to process your order but will do everything we can to
make it right. Please <Link to="/">reach out to us</Link> if you have
been charged or have any questions.
</p>
</div>
);
}
return (
<div className="checkout-container-complete sentry-unmask">
<h2>We're having some trouble</h2>
<p>
We were unable to process your order but will do everything we can to
make it right. Please <Link to="/">reach out to us</Link> if you have
been charged or have any questions.
</p>
</div>
);
}

export default CompleteError;
109 changes: 51 additions & 58 deletions react/src/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,61 @@
import * as Sentry from '@sentry/react';
import { Fragment, Component } from 'react';
import { Fragment } from 'react';
import { Link } from 'react-router-dom';
import { useState } from 'react';
import './footer.css';

class Footer extends Component {
state = {
subscribed: false,
};

async shouldComponentUpdate() {
console.log('> Footer shouldComponentUpdate');
}
function Footer() {
const [subscribed, setSubscribed] = useState(false);

render() {
const handleSubmit = () => {
this.setState({ subscribed: true });
};
const handleSubmit = () => {
setSubscribed(true);
};

return (
<footer id="footer">
<div>
<h2 className="h3 sentry-unmask">Sign up for plant tech news</h2>
<Sentry.ErrorBoundary
onReset={() => {
this.setState({ subscribed: false });
}}
fallback={({ resetError, eventId }) => {
return (
<Fragment>
<div>An error has occurred. Sentry Event ID: {eventId}</div>
<button className="btn" onClick={resetError}>
Reset Form
</button>
</Fragment>
);
}}
>
<div className="formContainer">
<form onSubmitCapture={handleSubmit}>
<label htmlFor="email-subscribe" className="sentry-unmask">
Email
</label>
<input
type="email"
name="email-subscribe"
id="email-subscribe"
></input>
</form>
return (
<footer id="footer">
<div>
<h2 className="h3 sentry-unmask">Sign up for plant tech news</h2>
<Sentry.ErrorBoundary
onReset={() => {
setSubscribed(false);
}}
fallback={({ resetError, eventId }) => {
return (
<Fragment>
<div>An error has occurred. Sentry Event ID: {eventId}</div>
<button className="btn" onClick={resetError}>
Reset Form
</button>
</Fragment>
);
}}
>
<div className="formContainer">
<form onSubmitCapture={handleSubmit}>
<label htmlFor="email-subscribe" className="sentry-unmask">
Email
</label>
<input
type="submit"
value="Subscribe"
className="sentry-unmask"
onClick={handleSubmit}
/>
{this.state.subscribed && <SubscribedMessage />}
</div>
</Sentry.ErrorBoundary>
<p className="sentry-unmask">
© 2021 • Empower Plant • <Link to="/about">About us</Link>
</p>
</div>
</footer>
);
}
type="email"
name="email-subscribe"
id="email-subscribe"
></input>
</form>
<input
type="submit"
value="Subscribe"
className="sentry-unmask"
onClick={handleSubmit}
/>
{subscribed && <SubscribedMessage />}
</div>
</Sentry.ErrorBoundary>
<p className="sentry-unmask">
© 2021 • Empower Plant • <Link to="/about">About us</Link>
</p>
</div>
</footer>
);
}

function SubscribedMessage() {
Expand Down
39 changes: 16 additions & 23 deletions react/src/components/Home.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { Component } from 'react';
import Context from '../utils/context';
import * as Sentry from '@sentry/react';
import plantsBackground from '../assets/plants-background-img.jpg';
import Button from './ButtonLink';
import { useEffect } from 'react';

const divStyle = {
backgroundImage: 'url(' + plantsBackground + ')',
};

class Home extends Component {
static contextType = Context;

async componentDidMount() {
function Home({ frontendSlowdown, backend }) {
useEffect(() => {
try {
// This should be the only http request for home page, for health check purposes
await fetch(this.props.backend + '/success', {
fetch(backend + '/success', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Expand All @@ -23,24 +20,20 @@ class Home extends Component {
} catch (err) {
Sentry.captureException(err);
}
}
}, []);

render() {
return (
<div className="hero sentry-unmask">
<div className="hero-bg-img" style={divStyle}></div>
<div className="hero-content">
<h1>Empower your plants</h1>
<p>Keep your houseplants happy.</p>
<Button
to={this.props.frontendSlowdown ? '/products-fes' : '/products'}
>
Browse products
</Button>
</div>
return (
<div className="hero sentry-unmask">
<div className="hero-bg-img" style={divStyle}></div>
<div className="hero-content">
<h1>Empower your plants</h1>
<p>Keep your houseplants happy.</p>
<Button to={frontendSlowdown ? '/products-fes' : '/products'}>
Browse products
</Button>
</div>
);
}
</div>
);
}

export default Home;
Loading

0 comments on commit 11eeec5

Please sign in to comment.