Upgrade dependencies, etc. (#55)

* Run prettify

* Upgrade dependencies and switch out some libraries:

* timeago (freshly jquery dependent) -> ReactTimeAgo
* next-ga -> react-ga and custom plumbing

* Move static/ to public/static/

As per https://github.com/zeit/next.js/blob/master/errors/static-dir-deprecated.md

* Fix cons->icons typo

* Import only what's necessary from lodash (223 -> 180 kb)

* Asyncify MembershipInfoForm
This commit is contained in:
Aarni Koskela
2019-10-30 20:05:08 +02:00
committed by Riku Rouvila
parent db98341a51
commit dcf26deb0f
36 changed files with 3376 additions and 585 deletions

View File

@@ -1,9 +1,14 @@
import _ from "lodash";
import flatMap from "lodash/flatMap";
import sortBy from "lodash/sortBy";
import React from "react";
import request from "axios";
import timeago from "timeago";
import api from "./api";
import transformers from "./feed-transformers";
import ReactTimeAgo from "react-time-ago";
import JavascriptTimeAgo from "javascript-time-ago";
import timeagoFi from "javascript-time-ago/locale/fi";
JavascriptTimeAgo.locale(timeagoFi);
export default class Feed extends React.Component {
state = {
@@ -16,17 +21,13 @@ export default class Feed extends React.Component {
async updateFeed() {
const res = await request.get(api("feeds"));
const messages = _(res.data)
.map((messages, type) => transformers[type](messages))
.flatten()
.value();
const messages = sortBy(
flatMap(res.data, (messages, type) => transformers[type](messages)),
"timestamp"
);
messages.reverse(); // In-place
this.setState({
messages: _(messages)
.sortBy("timestamp")
.reverse()
.value()
.slice(0, 40),
messages: messages.slice(0, 40),
});
}
@@ -36,7 +37,12 @@ export default class Feed extends React.Component {
if (message.imageLink) {
image = (
<a target="_blank" href={message.imageLink} rel="noopener noreferrer" tabIndex="-1">
<a
target="_blank"
href={message.imageLink}
rel="noopener noreferrer"
tabIndex="-1"
>
{image}
</a>
);
@@ -44,7 +50,9 @@ export default class Feed extends React.Component {
return (
<div className="message" key={i}>
<div className="message__image" aria-hidden="true">{image}</div>
<div className="message__image" aria-hidden="true">
{image}
</div>
<div className="message__content">
<div className="message__user">
<a href={message.userLink}>{message.user}</a>
@@ -52,13 +60,13 @@ export default class Feed extends React.Component {
<div
className="message__body"
dangerouslySetInnerHTML={{ __html: message.body }}
></div>
/>
<div className="message__icon">
<i className={`fa fa-${message.type}`}></i>
<i className={`fa fa-${message.type}`} aria-hidden="true" />
</div>
<div className="message__details">
<span className="message__timestamp">
{timeago(message.timestamp)}
<ReactTimeAgo date={message.timestamp} locale="fi" />
</span>
<span className="message__meta">{message.meta}</span>
</div>

View File

@@ -24,19 +24,34 @@ export function Footer() {
</div>
<div className="contacts">
<div>
<a href="https://koodiklinikka.slack.com" aria-label="Koodiklinikka Slackissä">
<a
href="https://koodiklinikka.slack.com"
aria-label="Koodiklinikka Slackissä"
>
<i className="fa fa-slack" aria-hidden="true" />
</a>
<a href="https://github.com/koodiklinikka/koodiklinikka.fi" aria-label="Koodiklinikka Githubissa">
<a
href="https://github.com/koodiklinikka/koodiklinikka.fi"
aria-label="Koodiklinikka Githubissa"
>
<i className="fa fa-github" aria-hidden="true" />
</a>
<a href="https://twitter.com/koodiklinikka" aria-label="Koodiklinikka Twitterissä">
<a
href="https://twitter.com/koodiklinikka"
aria-label="Koodiklinikka Twitterissä"
>
<i className="fa fa-twitter" aria-hidden="true" />
</a>
<a href="https://www.linkedin.com/groups/12025476" aria-label="Koodiklinikka Linkedinissä">
<a
href="https://www.linkedin.com/groups/12025476"
aria-label="Koodiklinikka Linkedinissä"
>
<i className="fa fa-linkedin" aria-hidden="true" />
</a>
<a href="https://www.facebook.com/koodiklinikka" aria-label="Koodiklinikka Facebookissa">
<a
href="https://www.facebook.com/koodiklinikka"
aria-label="Koodiklinikka Facebookissa"
>
<i className="fa fa-facebook" aria-hidden="true" />
</a>
<div id="email">

View File

@@ -1,6 +1,6 @@
import React from "react";
import request from "axios";
import _ from "lodash";
import shuffle from "lodash/shuffle";
import api from "./api";
export default class Members extends React.Component {
@@ -15,14 +15,16 @@ export default class Members extends React.Component {
async refreshMembers() {
const res = await request.get(api("members"));
this.setState({
members: _.shuffle(res.data),
members: shuffle(res.data),
});
}
render() {
const members = this.state.members.map(member => {
const src = `${member.avatar_url}&s=120`;
return <img className="member" key={member.avatar_url} src={src} alt="" />;
return (
<img className="member" key={member.avatar_url} src={src} alt="" />
);
});
return (

View File

@@ -1,16 +1,23 @@
import _ from "lodash";
import lodashTemplate from "lodash/template";
import defaultTemplateSettings from "lodash/templateSettings";
import githubEvent from "parse-github-event";
import twitterText from "twitter-text";
const isVisibleGithubEvent = ({ type }) =>
type !== "PushEvent" && type !== "DeleteEvent";
const templateSettings = {
...defaultTemplateSettings,
interpolate: /{{([\s\S]+?)}}/g,
};
export default {
github(items) {
return items.filter(isVisibleGithubEvent).map(item => {
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
const template = _.template(githubEvent.parse(item).text);
const template = lodashTemplate(
githubEvent.parse(item).text,
templateSettings
);
const repository = `https://github.com/${item.repo.name}`;
let branch;

View File

@@ -1,4 +1,4 @@
import _ from "lodash";
import pick from "lodash/pick";
import request from "axios";
import React from "react";
import classSet from "classnames";
@@ -23,7 +23,7 @@ function validateEmail(email) {
const fieldNames = ["name", "email", "handle", "address", "postcode", "city"];
function getUserInfo(state) {
return _.pick(state, fieldNames);
return pick(state, fieldNames);
}
export default class MembershipInfoForm extends React.Component {
@@ -38,23 +38,21 @@ export default class MembershipInfoForm extends React.Component {
pristineFields: fieldNames,
};
onSubmit = () => {
onSubmit = async () => {
this.setState({
sending: true,
error: null,
});
request
.post(api("membership"), {
try {
await request.post(api("membership"), {
userInfo: getUserInfo(this.state),
})
.then(() => {
this.setState({ sending: false });
this.props.onSignupSuccess();
})
.catch(err => {
this.setState({ error: err, sending: false });
});
this.setState({ sending: false });
this.props.onSignupSuccess();
} catch (err) {
this.setState({ error: err, sending: false });
}
};
onChange = e => {
@@ -124,7 +122,7 @@ export default class MembershipInfoForm extends React.Component {
const inputFields = fieldNames.map(fieldName => {
const inputClasses = classSet({
input: true,
"has-error": _.includes(fieldsWithErrors, fieldName),
"has-error": fieldsWithErrors.includes(fieldName),
half: fieldName === "city" || fieldName === "postcode",
left: fieldName === "postcode",
});