diff --git a/src/routes/login/LoginContainer.js b/src/routes/login/LoginContainer.ts
similarity index 57%
rename from src/routes/login/LoginContainer.js
rename to src/routes/login/LoginContainer.ts
index f9c2e4d74..8e212c269 100644
--- a/src/routes/login/LoginContainer.js
+++ b/src/routes/login/LoginContainer.ts
@@ -1,7 +1,11 @@
import { connect } from "react-redux";
import Login from "./Login";
+import { State } from "../../interfaces";
-const mapStateToProps = (state, ownProps) => ({
+const mapStateToProps = (
+ state: State,
+ ownProps: { team?: string; next?: string }
+) => ({
host: state.host,
team: ownProps.team,
next: ownProps.next,
diff --git a/src/routes/login/index.js b/src/routes/login/index.tsx
similarity index 85%
rename from src/routes/login/index.js
rename to src/routes/login/index.tsx
index b3c209b37..3c27d90ee 100644
--- a/src/routes/login/index.js
+++ b/src/routes/login/index.tsx
@@ -10,13 +10,14 @@
import React from "react";
import LayoutContainer from "../../components/Layout/LayoutContainer";
import renderIfLoggedOut from "../helpers/renderIfLoggedOut";
+import { AppContext } from "../../interfaces";
import LoginContainer from "./LoginContainer";
-function action(context) {
+function action(context: AppContext) {
const state = context.store.getState();
const subdomain = context.subdomain;
- const next = context.query.next;
+ const next = context.query?.next as string | undefined;
return renderIfLoggedOut(state, () => ({
chunks: ["login"],
diff --git a/src/routes/main/about/About.js b/src/routes/main/about/About.tsx
similarity index 100%
rename from src/routes/main/about/About.js
rename to src/routes/main/about/About.tsx
diff --git a/src/routes/main/about/index.js b/src/routes/main/about/index.tsx
similarity index 85%
rename from src/routes/main/about/index.js
rename to src/routes/main/about/index.tsx
index a491b7dc4..86274e7f4 100644
--- a/src/routes/main/about/index.js
+++ b/src/routes/main/about/index.tsx
@@ -9,11 +9,12 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../interfaces";
import About from "./About";
const title = "About / Privacy";
-export default (context) => ({
+export default (context: AppContext) => ({
title,
chunks: ["about"],
component: (
diff --git a/src/routes/main/account/Account.js b/src/routes/main/account/Account.tsx
similarity index 81%
rename from src/routes/main/account/Account.js
rename to src/routes/main/account/Account.tsx
index 88966c895..86fa306c8 100644
--- a/src/routes/main/account/Account.js
+++ b/src/routes/main/account/Account.tsx
@@ -1,5 +1,4 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { ChangeEvent, Component, FormEvent } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -7,15 +6,22 @@ import Form from "react-bootstrap/Form";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import { PASSWORD_MIN_LENGTH } from "../../../constants";
+import { Action, User } from "../../../interfaces";
import s from "./Account.scss";
-class Account extends Component {
- static propTypes = {
- updateCurrentUser: PropTypes.func.isRequired,
- user: PropTypes.object.isRequired,
- };
+interface AccountProps {
+ updateCurrentUser: (user: Partial
) => Promise;
+ user: User;
+}
+
+interface AccountState {
+ name?: string;
+ email?: string;
+ password?: string;
+}
- constructor(props) {
+class Account extends Component {
+ constructor(props: AccountProps) {
super(props);
const { user } = props;
@@ -27,10 +33,11 @@ class Account extends Component {
};
}
- handleChange = (field) => (event) =>
- this.setState({ [field]: event.target.value });
+ handleChange =
+ (field: keyof AccountState) => (event: ChangeEvent) =>
+ this.setState({ [field]: event.target.value });
- handleSubmit = (event) => {
+ handleSubmit = (event: FormEvent) => {
event.preventDefault();
this.props
.updateCurrentUser(this.state)
diff --git a/src/routes/main/account/AccountContainer.js b/src/routes/main/account/AccountContainer.ts
similarity index 69%
rename from src/routes/main/account/AccountContainer.js
rename to src/routes/main/account/AccountContainer.ts
index f01d68d7f..4ef36c9e9 100644
--- a/src/routes/main/account/AccountContainer.js
+++ b/src/routes/main/account/AccountContainer.ts
@@ -1,15 +1,16 @@
import { connect } from "react-redux";
import { flashSuccess } from "../../../actions/flash";
import { updateCurrentUser } from "../../../actions/user";
+import { Dispatch, State, User } from "../../../interfaces";
import { getCurrentUser } from "../../../selectors/user";
import Account from "./Account";
-const mapStateToProps = (state) => ({
+const mapStateToProps = (state: State) => ({
user: getCurrentUser(state),
});
-const mapDispatchToProps = (dispatch) => ({
- updateCurrentUser: (payload) =>
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ updateCurrentUser: (payload: Partial) =>
dispatch(updateCurrentUser(payload)).then(() =>
dispatch(flashSuccess("Account details updated."))
),
diff --git a/src/routes/main/account/index.js b/src/routes/main/account/index.tsx
similarity index 90%
rename from src/routes/main/account/index.js
rename to src/routes/main/account/index.tsx
index d8652a252..5d1aa43ea 100644
--- a/src/routes/main/account/index.js
+++ b/src/routes/main/account/index.tsx
@@ -9,12 +9,13 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../interfaces";
import redirectToLogin from "../../helpers/redirectToLogin";
import AccountContainer from "./AccountContainer";
const title = "Account";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
diff --git a/src/routes/main/index.js b/src/routes/main/index.ts
similarity index 93%
rename from src/routes/main/index.js
rename to src/routes/main/index.ts
index be787f419..1c9f391d9 100644
--- a/src/routes/main/index.js
+++ b/src/routes/main/index.ts
@@ -8,6 +8,8 @@
*/
/* eslint-disable global-require */
+import { Route } from "universal-router";
+import { AppContext, AppRoute } from "../../interfaces";
import rootAction from "../helpers/rootAction";
import invitation from "./invitation";
@@ -15,7 +17,7 @@ import password from "./password";
import users from "./users";
// The top-level (parent) route
-export default {
+const main: Route = {
path: "",
// Keep in mind, routes are evaluated in order
@@ -94,3 +96,5 @@ export default {
action: rootAction,
};
+
+export default main;
diff --git a/src/routes/main/invitation/create/Create.js b/src/routes/main/invitation/create/Create.tsx
similarity index 92%
rename from src/routes/main/invitation/create/Create.js
rename to src/routes/main/invitation/create/Create.tsx
index dc3b449bb..40ef045e0 100644
--- a/src/routes/main/invitation/create/Create.js
+++ b/src/routes/main/invitation/create/Create.tsx
@@ -4,7 +4,12 @@ import withStyles from "isomorphic-style-loader/withStyles";
import Container from "react-bootstrap/Container";
import s from "./Create.scss";
-class Create extends Component {
+interface CreateProps {
+ success?: string;
+ token?: string;
+}
+
+class Create extends Component {
static propTypes = {
success: PropTypes.string,
token: PropTypes.string,
diff --git a/src/routes/main/invitation/create/index.js b/src/routes/main/invitation/create/index.tsx
similarity index 79%
rename from src/routes/main/invitation/create/index.js
rename to src/routes/main/invitation/create/index.tsx
index d7a2f623f..f1071a406 100644
--- a/src/routes/main/invitation/create/index.js
+++ b/src/routes/main/invitation/create/index.tsx
@@ -9,11 +9,12 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import Create from "./Create";
-export default (context) => {
- const success = context.query.success;
- const token = context.query.token;
+export default (context: AppContext) => {
+ const success = context.query?.success;
+ const token = context.query?.token;
if (!success && !token) {
return {
diff --git a/src/routes/main/invitation/index.js b/src/routes/main/invitation/index.ts
similarity index 87%
rename from src/routes/main/invitation/index.js
rename to src/routes/main/invitation/index.ts
index d5d2301d3..06af50b5e 100644
--- a/src/routes/main/invitation/index.js
+++ b/src/routes/main/invitation/index.ts
@@ -9,6 +9,7 @@
/* eslint-disable global-require */
+import { AppContext } from "../../../interfaces";
import create from "./create";
import newAction from "./new";
@@ -25,7 +26,7 @@ export default [
// Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
{
path: "(.*)",
- action: async (context) =>
+ action: async (context: AppContext) =>
(
await import(/* webpackChunkName: 'not-found' */ "../../not-found")
).default(context),
diff --git a/src/routes/main/invitation/new/New.js b/src/routes/main/invitation/new/New.tsx
similarity index 78%
rename from src/routes/main/invitation/new/New.js
rename to src/routes/main/invitation/new/New.tsx
index 4ae791a21..86efb12c2 100644
--- a/src/routes/main/invitation/new/New.js
+++ b/src/routes/main/invitation/new/New.tsx
@@ -1,5 +1,4 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { Component, RefObject, createRef } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -8,17 +7,24 @@ import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import s from "./New.scss";
-class New extends Component {
- static propTypes = {
- email: PropTypes.string,
- };
+interface NewProps {
+ email?: string;
+}
+
+class New extends Component {
+ emailField: RefObject;
static defaultProps = {
email: "",
};
+ constructor(props: NewProps) {
+ super(props);
+ this.emailField = createRef();
+ }
+
componentDidMount() {
- this.emailField.focus();
+ this.emailField.current?.focus();
}
render() {
@@ -39,9 +45,7 @@ class New extends Component {
Email
{
- this.emailField = i;
- }}
+ ref={this.emailField}
name="email"
required
type="email"
diff --git a/src/routes/main/invitation/new/index.js b/src/routes/main/invitation/new/index.tsx
similarity index 81%
rename from src/routes/main/invitation/new/index.js
rename to src/routes/main/invitation/new/index.tsx
index 23beb3360..25134ec98 100644
--- a/src/routes/main/invitation/new/index.js
+++ b/src/routes/main/invitation/new/index.tsx
@@ -9,10 +9,11 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import New from "./New";
-export default (context) => {
- const email = context.query.email;
+export default (context: AppContext) => {
+ const email = context.query?.email;
return {
component: (
diff --git a/src/routes/main/landing/Landing.js b/src/routes/main/landing/Landing.tsx
similarity index 100%
rename from src/routes/main/landing/Landing.js
rename to src/routes/main/landing/Landing.tsx
diff --git a/src/routes/main/landing/index.js b/src/routes/main/landing/index.tsx
similarity index 89%
rename from src/routes/main/landing/index.js
rename to src/routes/main/landing/index.tsx
index 81167bfd7..0bdf20693 100644
--- a/src/routes/main/landing/index.js
+++ b/src/routes/main/landing/index.tsx
@@ -9,10 +9,11 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../interfaces";
import renderIfLoggedOut from "../../helpers/renderIfLoggedOut";
import Landing from "./Landing";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
return renderIfLoggedOut(state, () => ({
diff --git a/src/routes/main/new-team/NewTeam.js b/src/routes/main/new-team/NewTeam.tsx
similarity index 80%
rename from src/routes/main/new-team/NewTeam.js
rename to src/routes/main/new-team/NewTeam.tsx
index d347be75f..d91b48ae5 100644
--- a/src/routes/main/new-team/NewTeam.js
+++ b/src/routes/main/new-team/NewTeam.tsx
@@ -1,5 +1,5 @@
import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { ChangeEvent, Component, FormEvent } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -12,22 +12,26 @@ import defaultCoords from "../../../constants/defaultCoords";
import TeamGeosuggestContainer from "../../../components/TeamGeosuggest/TeamGeosuggestContainer";
import TeamMapContainer from "../../../components/TeamMap/TeamMapContainer";
import history from "../../../history";
+import { LatLng, Team } from "../../../interfaces";
import s from "./NewTeam.scss";
-class NewTeam extends Component {
- static propTypes = {
- center: PropTypes.shape({
- lat: PropTypes.number.isRequired,
- lng: PropTypes.number.isRequired,
- }),
- createTeam: PropTypes.func.isRequired,
- };
+interface NewTeamProps {
+ center?: LatLng;
+ createTeam: (team: Partial) => Promise;
+}
+interface NewTeamState {
+ name?: string;
+ slug?: string;
+ address?: string;
+}
+
+class NewTeam extends Component {
static defaultProps = {
center: defaultCoords,
};
- constructor(props) {
+ constructor(props: NewTeamProps) {
super(props);
this.state = {
@@ -37,16 +41,19 @@ class NewTeam extends Component {
};
}
- handleChange = (field) => (event) =>
- this.setState({ [field]: event.target.value });
+ handleGeosuggestChange = (value: string) => this.setState({ address: value });
+
+ handleChange =
+ (field: keyof NewTeamState) => (event: ChangeEvent) =>
+ this.setState({ [field]: event.target.value });
- handleSlugChange = (event) => {
+ handleSlugChange = (event: ChangeEvent) => {
this.setState({
slug: event.target.value.toLowerCase(),
});
};
- handleSubmit = (event) => {
+ handleSubmit = (event: FormEvent) => {
const { center, createTeam } = this.props;
event.preventDefault();
@@ -54,7 +61,7 @@ class NewTeam extends Component {
createTeam({
...center,
...this.state,
- }).then(() => history.push("/teams"));
+ }).then(() => history?.push("/teams"));
};
render() {
@@ -114,7 +121,7 @@ class NewTeam extends Component {
diff --git a/src/routes/main/new-team/NewTeamContainer.js b/src/routes/main/new-team/NewTeamContainer.tsx
similarity index 52%
rename from src/routes/main/new-team/NewTeamContainer.js
rename to src/routes/main/new-team/NewTeamContainer.tsx
index 7f3375678..bba423940 100644
--- a/src/routes/main/new-team/NewTeamContainer.js
+++ b/src/routes/main/new-team/NewTeamContainer.tsx
@@ -2,15 +2,16 @@ import { connect } from "react-redux";
import NewTeam from "./NewTeam";
import { setCenter } from "../../../actions/mapUi";
import { createTeam } from "../../../actions/teams";
+import { Dispatch, LatLng, State, Team } from "../../../interfaces";
import { getCenter } from "../../../selectors/mapUi";
-const mapStateToProps = (state) => ({
+const mapStateToProps = (state: State) => ({
center: getCenter(state),
});
-const mapDispatchToProps = (dispatch) => ({
- createTeam: (payload) => dispatch(createTeam(payload)),
- setCenter: (center) => dispatch(setCenter(center)),
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ createTeam: (payload: Partial) => dispatch(createTeam(payload)),
+ setCenter: (center: LatLng) => dispatch(setCenter(center)),
});
export default connect(mapStateToProps, mapDispatchToProps)(NewTeam);
diff --git a/src/routes/main/new-team/index.js b/src/routes/main/new-team/index.tsx
similarity index 88%
rename from src/routes/main/new-team/index.js
rename to src/routes/main/new-team/index.tsx
index f6a56ec5d..0dbcb2854 100644
--- a/src/routes/main/new-team/index.js
+++ b/src/routes/main/new-team/index.tsx
@@ -10,11 +10,12 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
import renderIfHasName from "../../helpers/renderIfHasName";
+import { AppContext } from "../../../interfaces";
import NewTeamContainer from "./NewTeamContainer";
const title = "New team";
-export default (context) =>
+export default (context: AppContext) =>
renderIfHasName(context, () => ({
title,
chunks: ["map", "new-team"],
diff --git a/src/routes/main/password/create/Create.js b/src/routes/main/password/create/Create.tsx
similarity index 83%
rename from src/routes/main/password/create/Create.js
rename to src/routes/main/password/create/Create.tsx
index db99447eb..8685359e8 100644
--- a/src/routes/main/password/create/Create.js
+++ b/src/routes/main/password/create/Create.tsx
@@ -1,15 +1,14 @@
-import PropTypes from "prop-types";
import React, { Component } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Container from "react-bootstrap/Container";
-import Link from "../../../../components/Link";
+import Link from "../../../../components/Link/Link";
import s from "./Create.scss";
-class Create extends Component {
- static propTypes = {
- success: PropTypes.string.isRequired,
- };
+interface CreateProps {
+ success: string;
+}
+class Create extends Component {
render() {
const { success } = this.props;
diff --git a/src/routes/main/password/create/index.js b/src/routes/main/password/create/index.tsx
similarity index 86%
rename from src/routes/main/password/create/index.js
rename to src/routes/main/password/create/index.tsx
index 2180ceed5..5cecf1946 100644
--- a/src/routes/main/password/create/index.js
+++ b/src/routes/main/password/create/index.tsx
@@ -9,13 +9,14 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import renderIfLoggedOut from "../../../helpers/renderIfLoggedOut";
import Create from "./Create";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
- const success = context.query.success;
+ const success = context.query?.success;
return renderIfLoggedOut(state, () => {
if (!success) {
diff --git a/src/routes/main/password/edit/Edit.js b/src/routes/main/password/edit/Edit.tsx
similarity index 78%
rename from src/routes/main/password/edit/Edit.js
rename to src/routes/main/password/edit/Edit.tsx
index 193c6791c..ac7fb9e1e 100644
--- a/src/routes/main/password/edit/Edit.js
+++ b/src/routes/main/password/edit/Edit.tsx
@@ -1,5 +1,4 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { Component, RefObject, createRef } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -9,13 +8,20 @@ import Row from "react-bootstrap/Row";
import { PASSWORD_MIN_LENGTH } from "../../../../constants";
import s from "./Edit.scss";
-class Edit extends Component {
- static propTypes = {
- token: PropTypes.string.isRequired,
- };
+interface EditProps {
+ token: string;
+}
+
+class Edit extends Component {
+ passwordField: RefObject;
+
+ constructor(props: EditProps) {
+ super(props);
+ this.passwordField = createRef();
+ }
componentDidMount() {
- this.passwordField.focus();
+ this.passwordField.current?.focus();
}
render() {
@@ -31,9 +37,7 @@ class Edit extends Component {
New password
{
- this.passwordField = i;
- }}
+ ref={this.passwordField}
minLength={PASSWORD_MIN_LENGTH}
name="password"
required
diff --git a/src/routes/main/password/edit/index.js b/src/routes/main/password/edit/index.tsx
similarity index 84%
rename from src/routes/main/password/edit/index.js
rename to src/routes/main/password/edit/index.tsx
index 895242912..48a355dbc 100644
--- a/src/routes/main/password/edit/index.js
+++ b/src/routes/main/password/edit/index.tsx
@@ -9,13 +9,14 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import renderIfLoggedOut from "../../../helpers/renderIfLoggedOut";
import Edit from "./Edit";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
- const token = context.query.token;
+ const token = context.query?.token as string | undefined;
return renderIfLoggedOut(state, () => {
if (!token) {
diff --git a/src/routes/main/password/index.js b/src/routes/main/password/index.ts
similarity index 89%
rename from src/routes/main/password/index.js
rename to src/routes/main/password/index.ts
index 9302ab9e9..4e201b8da 100644
--- a/src/routes/main/password/index.js
+++ b/src/routes/main/password/index.ts
@@ -9,6 +9,7 @@
/* eslint-disable global-require */
+import { AppContext } from "../../../interfaces";
import create from "./create";
import edit from "./edit";
import newAction from "./new";
@@ -30,7 +31,7 @@ export default [
// Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
{
path: "(.*)",
- action: async (context) =>
+ action: async (context: AppContext) =>
(
await import(/* webpackChunkName: 'not-found' */ "../../not-found")
).default(context),
diff --git a/src/routes/main/password/new/New.js b/src/routes/main/password/new/New.tsx
similarity index 78%
rename from src/routes/main/password/new/New.js
rename to src/routes/main/password/new/New.tsx
index 2ae75dfb4..d9b60c8ba 100644
--- a/src/routes/main/password/new/New.js
+++ b/src/routes/main/password/new/New.tsx
@@ -1,5 +1,4 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { Component, RefObject, createRef } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -8,17 +7,24 @@ import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import s from "./New.scss";
-class New extends Component {
- static propTypes = {
- email: PropTypes.string,
- };
+interface NewProps {
+ email?: string;
+}
+
+class New extends Component {
+ emailField: RefObject;
static defaultProps = {
email: "",
};
+ constructor(props: NewProps) {
+ super(props);
+ this.emailField = createRef();
+ }
+
componentDidMount() {
- this.emailField.focus();
+ this.emailField.current?.focus();
}
render() {
@@ -39,9 +45,7 @@ class New extends Component {
Email
{
- this.emailField = i;
- }}
+ ref={this.emailField}
name="email"
required
type="email"
diff --git a/src/routes/main/password/new/index.js b/src/routes/main/password/new/index.tsx
similarity index 84%
rename from src/routes/main/password/new/index.js
rename to src/routes/main/password/new/index.tsx
index 9daba2940..a18c7610b 100644
--- a/src/routes/main/password/new/index.js
+++ b/src/routes/main/password/new/index.tsx
@@ -9,13 +9,14 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import renderIfLoggedOut from "../../../helpers/renderIfLoggedOut";
import New from "./New";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
- const email = context.query.email;
+ const email = context.query?.email;
return renderIfLoggedOut(state, () => ({
component: (
diff --git a/src/routes/main/teams/Teams.js b/src/routes/main/teams/Teams.tsx
similarity index 80%
rename from src/routes/main/teams/Teams.js
rename to src/routes/main/teams/Teams.tsx
index 14f76a673..fd7d03e89 100644
--- a/src/routes/main/teams/Teams.js
+++ b/src/routes/main/teams/Teams.tsx
@@ -1,22 +1,22 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { Component, MouseEvent } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import ListGroup from "react-bootstrap/ListGroup";
import { FaTimes } from "react-icons/fa";
import Container from "react-bootstrap/Container";
-import Link from "../../../components/Link";
+import Link from "../../../components/Link/Link";
+import { ConfirmOpts, Team } from "../../../interfaces";
import s from "./Teams.scss";
-class Teams extends Component {
- static propTypes = {
- confirm: PropTypes.func.isRequired,
- host: PropTypes.string.isRequired,
- leaveTeam: PropTypes.func.isRequired,
- teams: PropTypes.array.isRequired,
- };
+interface TeamsProps {
+ confirm: (props: ConfirmOpts) => void;
+ host: string;
+ leaveTeam: (team: Team) => () => void;
+ teams: Team[];
+}
- confirmLeave = (team) => (event) => {
+class Teams extends Component {
+ confirmLeave = (team: Team) => (event: MouseEvent) => {
event.preventDefault();
this.props.confirm({
actionLabel: "Leave",
@@ -35,7 +35,7 @@ You will need to be invited back by another member.`,
{teams.length ? (
Visit one of your teams:
-
+
{teams.map((team) => (
({
+const mapStateToProps = (state: State) => ({
host: state.host,
user: getCurrentUser(state),
teams: getTeams(state),
- title: ownProps.title,
});
-const mapDispatchToProps = (dispatch) => ({
- confirm: (opts) => dispatch(showModal("confirm", opts)),
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ confirm: (opts: ConfirmOpts) => dispatch(showModal("confirm", opts)),
dispatch,
});
-const mergeProps = (stateProps, dispatchProps) => ({
+const mergeProps = (
+ stateProps: ReturnType,
+ dispatchProps: ReturnType
+) => ({
...stateProps,
...dispatchProps,
- leaveTeam: (team) => removeUser(stateProps.user.id, team),
+ leaveTeam: (team: Team) => removeUser(stateProps.user!.id, team),
});
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Teams);
diff --git a/src/routes/main/teams/index.js b/src/routes/main/teams/index.tsx
similarity index 83%
rename from src/routes/main/teams/index.js
rename to src/routes/main/teams/index.tsx
index 1aa0e5dcb..e71fbc828 100644
--- a/src/routes/main/teams/index.js
+++ b/src/routes/main/teams/index.tsx
@@ -1,11 +1,12 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../interfaces";
import renderIfHasName from "../../helpers/renderIfHasName";
import TeamsContainer from "./TeamsContainer";
/* eslint-disable global-require */
-export default (context) =>
+export default (context: AppContext) =>
renderIfHasName(context, () => ({
chunks: ["teams"],
component: (
diff --git a/src/routes/main/users/create/Create.js b/src/routes/main/users/create/Create.tsx
similarity index 100%
rename from src/routes/main/users/create/Create.js
rename to src/routes/main/users/create/Create.tsx
diff --git a/src/routes/main/users/create/index.js b/src/routes/main/users/create/index.tsx
similarity index 85%
rename from src/routes/main/users/create/index.js
rename to src/routes/main/users/create/index.tsx
index bf5e45b0e..c56e0729c 100644
--- a/src/routes/main/users/create/index.js
+++ b/src/routes/main/users/create/index.tsx
@@ -9,14 +9,15 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import render404 from "../../../helpers/render404";
import Create from "./Create";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
- if (user.superuser) {
+ if (user?.superuser) {
return {
component: (
diff --git a/src/routes/main/users/index.js b/src/routes/main/users/index.tsx
similarity index 87%
rename from src/routes/main/users/index.js
rename to src/routes/main/users/index.tsx
index d5d2301d3..06af50b5e 100644
--- a/src/routes/main/users/index.js
+++ b/src/routes/main/users/index.tsx
@@ -9,6 +9,7 @@
/* eslint-disable global-require */
+import { AppContext } from "../../../interfaces";
import create from "./create";
import newAction from "./new";
@@ -25,7 +26,7 @@ export default [
// Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
{
path: "(.*)",
- action: async (context) =>
+ action: async (context: AppContext) =>
(
await import(/* webpackChunkName: 'not-found' */ "../../not-found")
).default(context),
diff --git a/src/routes/main/users/new/New.js b/src/routes/main/users/new/New.tsx
similarity index 79%
rename from src/routes/main/users/new/New.js
rename to src/routes/main/users/new/New.tsx
index 893d1bc19..e7c16ae13 100644
--- a/src/routes/main/users/new/New.js
+++ b/src/routes/main/users/new/New.tsx
@@ -1,5 +1,4 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { Component, RefObject, createRef } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
@@ -8,17 +7,24 @@ import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import s from "./New.scss";
-class New extends Component {
- static propTypes = {
- email: PropTypes.string,
- };
+interface NewProps {
+ email?: string;
+}
+
+class New extends Component {
+ emailField: RefObject;
static defaultProps = {
email: "",
};
+ constructor(props: NewProps) {
+ super(props);
+ this.emailField = createRef();
+ }
+
componentDidMount() {
- this.emailField.focus();
+ this.emailField.current?.focus();
}
render() {
@@ -39,9 +45,7 @@ class New extends Component {
Email
{
- this.emailField = i;
- }}
+ ref={this.emailField}
name="email"
required
type="email"
diff --git a/src/routes/main/users/new/index.js b/src/routes/main/users/new/index.tsx
similarity index 82%
rename from src/routes/main/users/new/index.js
rename to src/routes/main/users/new/index.tsx
index fb7bd513b..cd470a384 100644
--- a/src/routes/main/users/new/index.js
+++ b/src/routes/main/users/new/index.tsx
@@ -9,16 +9,17 @@
import React from "react";
import LayoutContainer from "../../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../../interfaces";
import render404 from "../../../helpers/render404";
import New from "./New";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
- const email = context.query.email;
+ const email = context.query?.email;
- if (user.superuser) {
+ if (user?.superuser) {
return {
component: (
diff --git a/src/routes/main/welcome/Welcome.js b/src/routes/main/welcome/Welcome.tsx
similarity index 73%
rename from src/routes/main/welcome/Welcome.js
rename to src/routes/main/welcome/Welcome.tsx
index 1f78db35c..b255a3623 100644
--- a/src/routes/main/welcome/Welcome.js
+++ b/src/routes/main/welcome/Welcome.tsx
@@ -1,20 +1,24 @@
-import PropTypes from "prop-types";
-import React, { Component } from "react";
+import React, { ChangeEvent, Component, FormEvent } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import Col from "react-bootstrap/Col";
import Form from "react-bootstrap/Form";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
+import { User } from "../../../interfaces";
import s from "./Welcome.scss";
-class Welcome extends Component {
- static propTypes = {
- updateCurrentUser: PropTypes.func.isRequired,
- user: PropTypes.object.isRequired,
- };
+interface WelcomeProps {
+ updateCurrentUser: (user: Partial) => void;
+ user: User;
+}
+
+interface WelcomeState {
+ name?: string;
+}
- constructor(props) {
+class Welcome extends Component {
+ constructor(props: WelcomeProps) {
super(props);
const { user } = props;
@@ -24,9 +28,10 @@ class Welcome extends Component {
};
}
- handleChange = (event) => this.setState({ name: event.target.value });
+ handleChange = (event: ChangeEvent) =>
+ this.setState({ name: event.target.value });
- handleSubmit = (event) => {
+ handleSubmit = (event: FormEvent) => {
event.preventDefault();
this.props.updateCurrentUser(this.state);
};
diff --git a/src/routes/main/welcome/WelcomeContainer.js b/src/routes/main/welcome/WelcomeContainer.ts
similarity index 58%
rename from src/routes/main/welcome/WelcomeContainer.js
rename to src/routes/main/welcome/WelcomeContainer.ts
index 83ba73778..6a6e49400 100644
--- a/src/routes/main/welcome/WelcomeContainer.js
+++ b/src/routes/main/welcome/WelcomeContainer.ts
@@ -1,25 +1,31 @@
+import { ThunkDispatch } from "@reduxjs/toolkit";
import { connect } from "react-redux";
import { updateCurrentUser } from "../../../actions/user";
import history from "../../../history";
+import { Action, State, User } from "../../../interfaces";
import { getCurrentUser } from "../../../selectors/user";
import Welcome from "./Welcome";
-const mapStateToProps = (state) => ({
+const mapStateToProps = (state: State) => ({
host: state.host,
user: getCurrentUser(state),
});
-const mergeProps = (stateProps, dispatchProps, ownProps) => ({
+const mergeProps = (
+ stateProps: ReturnType,
+ dispatchProps: { dispatch: ThunkDispatch },
+ ownProps: { next?: string; team?: string }
+) => ({
...stateProps,
- updateCurrentUser: (payload) =>
+ updateCurrentUser: (payload: Partial) =>
dispatchProps.dispatch(updateCurrentUser(payload)).then(() => {
const team = ownProps.team;
if (team) {
window.location.href = `//${team}.${stateProps.host}${ownProps.next}`;
} else if (ownProps.next) {
- history.push(ownProps.next);
+ history!.push(ownProps.next);
} else {
- history.push("/");
+ history!.push("/");
}
}),
});
diff --git a/src/routes/main/welcome/index.js b/src/routes/main/welcome/index.tsx
similarity index 79%
rename from src/routes/main/welcome/index.js
rename to src/routes/main/welcome/index.tsx
index 87374e598..13119ef26 100644
--- a/src/routes/main/welcome/index.js
+++ b/src/routes/main/welcome/index.tsx
@@ -9,12 +9,13 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
+import { AppContext } from "../../../interfaces";
import redirectToLogin from "../../helpers/redirectToLogin";
import WelcomeContainer from "./WelcomeContainer";
const title = "Welcome!";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
@@ -25,8 +26,8 @@ export default (context) => {
component: (
),
diff --git a/src/routes/not-found/NotFound.js b/src/routes/not-found/NotFound.tsx
similarity index 85%
rename from src/routes/not-found/NotFound.js
rename to src/routes/not-found/NotFound.tsx
index a1f6fc1e5..3ad83b02a 100644
--- a/src/routes/not-found/NotFound.js
+++ b/src/routes/not-found/NotFound.tsx
@@ -8,12 +8,16 @@ import PropTypes from "prop-types";
* LICENSE.txt file in the root directory of this source tree.
*/
-import React from "react";
+import React, { Component } from "react";
import Container from "react-bootstrap/Container";
import withStyles from "isomorphic-style-loader/withStyles";
import s from "./NotFound.scss";
-class NotFound extends React.Component {
+interface NotFoundProps {
+ title: string;
+}
+
+class NotFound extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
};
diff --git a/src/routes/not-found/index.js b/src/routes/not-found/index.ts
similarity index 74%
rename from src/routes/not-found/index.js
rename to src/routes/not-found/index.ts
index 50616ca26..667fda53f 100644
--- a/src/routes/not-found/index.js
+++ b/src/routes/not-found/index.ts
@@ -7,6 +7,7 @@
* LICENSE.txt file in the root directory of this source tree.
*/
+import { AppContext } from "../../interfaces";
import render404 from "../helpers/render404";
-export default (context) => render404(context);
+export default (context: AppContext) => render404(context);
diff --git a/src/routes/team/home/Home.test.js b/src/routes/team/home/Home.test.tsx
similarity index 88%
rename from src/routes/team/home/Home.test.js
rename to src/routes/team/home/Home.test.tsx
index a9e3a32ac..aa790b070 100644
--- a/src/routes/team/home/Home.test.js
+++ b/src/routes/team/home/Home.test.tsx
@@ -2,10 +2,12 @@
/* eslint-disable padded-blocks, no-unused-expressions */
import React from "react";
-import { spy, useFakeTimers } from "sinon";
+import { SinonSpy, spy, useFakeTimers } from "sinon";
import { expect } from "chai";
import proxyquire from "proxyquire";
import { render, screen } from "../../../../test/test-utils";
+import { HomeProps } from "./Home";
+import { User } from "../../../interfaces";
const proxy = proxyquire.noCallThru();
@@ -48,15 +50,15 @@ const Home = proxy("./Home", {
})._Home;
describe("Home", () => {
- let props;
- let fetchDecisions;
- let fetchRestaurants;
- let fetchTags;
- let fetchUsers;
- let invalidateDecisions;
- let invalidateRestaurants;
- let invalidateTags;
- let invalidateUsers;
+ let props: HomeProps;
+ let fetchDecisions: SinonSpy;
+ let fetchRestaurants: SinonSpy;
+ let fetchTags: SinonSpy;
+ let fetchUsers: SinonSpy;
+ let invalidateDecisions: SinonSpy;
+ let invalidateRestaurants: SinonSpy;
+ let invalidateTags: SinonSpy;
+ let invalidateUsers: SinonSpy;
beforeEach(() => {
fetchDecisions = spy();
@@ -91,7 +93,7 @@ describe("Home", () => {
};
it("renders form if user is logged in", async () => {
- props.user = { id: 1 };
+ props.user = { id: 1 } as User;
await renderComponent();
diff --git a/src/routes/team/home/Home.js b/src/routes/team/home/Home.tsx
similarity index 82%
rename from src/routes/team/home/Home.js
rename to src/routes/team/home/Home.tsx
index f9f472bcd..c23166170 100644
--- a/src/routes/team/home/Home.js
+++ b/src/routes/team/home/Home.tsx
@@ -1,4 +1,3 @@
-import PropTypes from "prop-types";
import React, { Component } from "react";
import { canUseDOM } from "fbjs/lib/ExecutionEnvironment";
import RobustWebSocket from "robust-websocket";
@@ -10,23 +9,30 @@ import RestaurantMapContainer from "../../../components/RestaurantMap/Restaurant
import RestaurantListContainer from "../../../components/RestaurantList/RestaurantListContainer";
import RestaurantAddFormContainer from "../../../components/RestaurantAddForm/RestaurantAddFormContainer";
import TagFilterFormContainer from "../../../components/TagFilterForm/TagFilterFormContainer";
+import { User } from "../../../interfaces";
import s from "./Home.scss";
-export class _Home extends Component {
- static propTypes = {
- user: PropTypes.object,
- fetchDecisions: PropTypes.func.isRequired,
- fetchRestaurants: PropTypes.func.isRequired,
- fetchTags: PropTypes.func.isRequired,
- fetchUsers: PropTypes.func.isRequired,
- invalidateDecisions: PropTypes.func.isRequired,
- invalidateRestaurants: PropTypes.func.isRequired,
- invalidateTags: PropTypes.func.isRequired,
- invalidateUsers: PropTypes.func.isRequired,
- messageReceived: PropTypes.func.isRequired,
- pastDecisionsShown: PropTypes.bool.isRequired,
- wsPort: PropTypes.number.isRequired,
- };
+export interface HomeProps {
+ user?: User | null;
+ fetchDecisions: () => void;
+ fetchRestaurants: () => void;
+ fetchTags: () => void;
+ fetchUsers: () => void;
+ invalidateDecisions: () => void;
+ invalidateRestaurants: () => void;
+ invalidateTags: () => void;
+ invalidateUsers: () => void;
+ messageReceived: (event: MessageEvent) => void;
+ pastDecisionsShown: boolean;
+ wsPort: number;
+}
+
+export class _Home extends Component {
+ fetchAllInterval: NodeJS.Timer;
+
+ pingInterval: NodeJS.Timer;
+
+ socket: RobustWebSocket;
static defaultProps = {
user: null,
@@ -46,7 +52,7 @@ export class _Home extends Component {
window.location.port &&
typeof wsPort === "number" &&
wsPort !== 0 &&
- wsPort !== window.location.port
+ wsPort !== Number(window.location.port)
) {
host = `${window.location.hostname}:${wsPort}`;
}
@@ -55,7 +61,7 @@ export class _Home extends Component {
protocol = "wss:";
}
this.socket = new RobustWebSocket(`${protocol}//${host}/api`, null, {
- shouldReconnect: (event, ws) => {
+ shouldReconnect: (event: CloseEvent, ws: RobustWebSocket) => {
if (event.code === 1008 || event.code === 1011) return undefined;
return Math.min(1000 * ws.attempts, 5000);
},
diff --git a/src/routes/team/home/HomeContainer.js b/src/routes/team/home/HomeContainer.ts
similarity index 85%
rename from src/routes/team/home/HomeContainer.js
rename to src/routes/team/home/HomeContainer.ts
index 6856dec8d..fa8099513 100644
--- a/src/routes/team/home/HomeContainer.js
+++ b/src/routes/team/home/HomeContainer.ts
@@ -11,14 +11,15 @@ import { fetchTags, invalidateTags } from "../../../actions/tags";
import { fetchUsers, invalidateUsers } from "../../../actions/users";
import { messageReceived } from "../../../actions/websockets";
import Home from "./Home";
+import { Dispatch, State } from "../../../interfaces";
-const mapStateToProps = (state) => ({
+const mapStateToProps = (state: State) => ({
pastDecisionsShown: !!state.modals.pastDecisions,
user: state.user,
wsPort: state.wsPort,
});
-const mapDispatchToProps = (dispatch) => ({
+const mapDispatchToProps = (dispatch: Dispatch) => ({
fetchDecisions() {
dispatch(fetchDecisions());
},
@@ -43,7 +44,7 @@ const mapDispatchToProps = (dispatch) => ({
invalidateUsers() {
dispatch(invalidateUsers());
},
- messageReceived(event) {
+ messageReceived(event: MessageEvent) {
dispatch(messageReceived(event.data));
},
});
diff --git a/src/routes/team/home/index.tsx b/src/routes/team/home/index.tsx
index e7201b470..dedbc2ffc 100644
--- a/src/routes/team/home/index.tsx
+++ b/src/routes/team/home/index.tsx
@@ -3,18 +3,18 @@ import LayoutContainer from "../../../components/Layout/LayoutContainer";
import hasRole from "../../../helpers/hasRole";
import renderIfHasName from "../../helpers/renderIfHasName";
import render404 from "../../helpers/render404";
+import { AppContext } from "../../../interfaces";
import HomeContainer from "./HomeContainer";
-import { ResolveContext } from "universal-router";
/* eslint-disable global-require */
-export default (context: ResolveContext) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
const team = state.team;
return renderIfHasName(context, () => {
- if (team.id && hasRole(user, team)) {
+ if (team && hasRole(user, team)) {
return {
chunks: ["home", "map"],
component: (
diff --git a/src/routes/team/tags/Tags.js b/src/routes/team/tags/Tags.tsx
similarity index 79%
rename from src/routes/team/tags/Tags.js
rename to src/routes/team/tags/Tags.tsx
index e5c0c40fa..f116b3f51 100644
--- a/src/routes/team/tags/Tags.js
+++ b/src/routes/team/tags/Tags.tsx
@@ -1,4 +1,3 @@
-import PropTypes from "prop-types";
import React, { Component } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Container from "react-bootstrap/Container";
@@ -6,7 +5,12 @@ import Loading from "../../../components/Loading/Loading";
import TagManagerContainer from "../../../components/TagManager/TagManagerContainer";
import s from "./Tags.scss";
-class Tags extends Component {
+interface TagsProps {
+ fetchTagsIfNeeded: () => void;
+ tagListReady: boolean;
+}
+
+class Tags extends Component {
componentDidMount() {
this.props.fetchTagsIfNeeded();
}
@@ -27,9 +31,4 @@ class Tags extends Component {
}
}
-Tags.propTypes = {
- fetchTagsIfNeeded: PropTypes.func.isRequired,
- tagListReady: PropTypes.bool.isRequired,
-};
-
export default withStyles(s)(Tags);
diff --git a/src/routes/team/tags/TagsContainer.js b/src/routes/team/tags/TagsContainer.js
deleted file mode 100644
index f37d83dd3..000000000
--- a/src/routes/team/tags/TagsContainer.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { connect } from "react-redux";
-import { fetchTagsIfNeeded } from "../../../actions/tags";
-import { isTagListReady } from "../../../selectors";
-import Tags from "./Tags";
-
-const mapStateToProps = (state) => ({
- tagListReady: isTagListReady(state),
-});
-
-const mapDispatchToProps = (dispatch) => ({
- fetchTagsIfNeeded() {
- dispatch(fetchTagsIfNeeded());
- },
-});
-
-export default connect(mapStateToProps, mapDispatchToProps)(Tags);
diff --git a/src/routes/team/tags/TagsContainer.ts b/src/routes/team/tags/TagsContainer.ts
new file mode 100644
index 000000000..0213b4d0e
--- /dev/null
+++ b/src/routes/team/tags/TagsContainer.ts
@@ -0,0 +1,25 @@
+import { connect } from "react-redux";
+import { fetchTagsIfNeeded } from "../../../actions/tags";
+import { Dispatch, State } from "../../../interfaces";
+import { isTagListReady } from "../../../selectors";
+import Tags from "./Tags";
+
+const mapStateToProps = (state: State) => ({
+ tagListReady: isTagListReady(state),
+});
+
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ fetchTagsIfNeeded() {
+ dispatch(fetchTagsIfNeeded());
+ },
+});
+
+export default connect<
+ ReturnType,
+ ReturnType,
+ { title: string },
+ State
+>(
+ mapStateToProps,
+ mapDispatchToProps
+)(Tags);
diff --git a/src/routes/team/tags/index.test.js b/src/routes/team/tags/index.test.ts
similarity index 82%
rename from src/routes/team/tags/index.test.js
rename to src/routes/team/tags/index.test.ts
index 1a57f181c..07bfc38ff 100644
--- a/src/routes/team/tags/index.test.js
+++ b/src/routes/team/tags/index.test.ts
@@ -5,13 +5,14 @@ import { expect } from "chai";
import { configureMockStore } from "@jedmao/redux-mock-store";
import proxyquire from "proxyquire";
import mockEsmodule from "../../../../test/mockEsmodule";
+import { AppContext, AppRoute } from "../../../interfaces";
const proxyquireStrict = proxyquire.noCallThru();
const mockStore = configureMockStore();
describe("routes/team/tags", () => {
- let context;
- let render404;
+ let context: Omit;
+ let render404: string;
let team;
let landingProxy;
@@ -31,37 +32,32 @@ describe("routes/team/tags", () => {
});
describe("when user is not on team", () => {
- let result;
- beforeEach(() => {
+ it("renders 404", () => {
render404 = "render404";
landingProxy = proxyquireStrict("./index", {
"../../../helpers/hasRole": mockEsmodule({
default: () => false,
}),
"../../helpers/renderIfHasName": mockEsmodule({
- default: (_, cb) => cb(),
+ default: (_: AppContext, cb: () => void) => cb(),
}),
"../../helpers/render404": mockEsmodule({
default: () => render404,
}),
}).default;
- result = landingProxy(context);
- });
-
- it("renders 404", () => {
- expect(result).to.eq(render404);
+ expect(landingProxy(context)).to.eq(render404);
});
});
describe("when user is on team", () => {
- let result;
+ let result: AppRoute;
beforeEach(() => {
landingProxy = proxyquireStrict("./index", {
"../../../helpers/hasRole": mockEsmodule({
default: () => true,
}),
"../../helpers/renderIfHasName": mockEsmodule({
- default: (_, cb) => cb(),
+ default: (_: AppContext, cb: () => void) => cb(),
}),
}).default;
result = landingProxy(context);
diff --git a/src/routes/team/tags/index.js b/src/routes/team/tags/index.tsx
similarity index 88%
rename from src/routes/team/tags/index.js
rename to src/routes/team/tags/index.tsx
index d6d751053..6eb853c71 100644
--- a/src/routes/team/tags/index.js
+++ b/src/routes/team/tags/index.tsx
@@ -10,19 +10,20 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
import hasRole from "../../../helpers/hasRole";
+import { AppContext } from "../../../interfaces";
import renderIfHasName from "../../helpers/renderIfHasName";
import render404 from "../../helpers/render404";
import TagsContainer from "./TagsContainer";
const title = "Tags";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
const team = state.team;
return renderIfHasName(context, () => {
- if (team.id && hasRole(user, team)) {
+ if (team && hasRole(user, team)) {
return {
title,
chunks: ["tags"],
diff --git a/src/routes/team/team/Team.js b/src/routes/team/team/Team.tsx
similarity index 74%
rename from src/routes/team/team/Team.js
rename to src/routes/team/team/Team.tsx
index bf2a565a9..9e8b2c80a 100644
--- a/src/routes/team/team/Team.js
+++ b/src/routes/team/team/Team.tsx
@@ -1,4 +1,3 @@
-import PropTypes from "prop-types";
/**
* React Starter Kit (https://www.reactstarterkit.com/)
*
@@ -8,7 +7,7 @@ import PropTypes from "prop-types";
* LICENSE.txt file in the root directory of this source tree.
*/
-import React from "react";
+import React, { ChangeEvent } from "react";
import withStyles from "isomorphic-style-loader/withStyles";
import Button from "react-bootstrap/Button";
import ButtonToolbar from "react-bootstrap/ButtonToolbar";
@@ -17,6 +16,7 @@ import Container from "react-bootstrap/Container";
import Tab from "react-bootstrap/Tab";
import Tabs from "react-bootstrap/Tabs";
import Table from "react-bootstrap/Table";
+import { IntlShape } from "react-intl";
import Loading from "../../../components/Loading/Loading";
import AddUserFormContainer from "../../../components/AddUserForm/AddUserFormContainer";
import ChangeTeamURLModalContainer from "../../../components/ChangeTeamURLModal/ChangeTeamURLModalContainer";
@@ -25,68 +25,75 @@ import TeamFormContainer from "../../../components/TeamForm/TeamFormContainer";
import { globalMessageDescriptor as gm } from "../../../helpers/generateMessageDescriptor";
import getRole from "../../../helpers/getRole";
import canChangeUser from "../../../helpers/canChangeUser";
+import {
+ User,
+ Team as TeamType,
+ ConfirmOpts,
+ Action,
+} from "../../../interfaces";
import s from "./Team.scss";
-class Team extends React.Component {
- static propTypes = {
- changeTeamURLShown: PropTypes.bool.isRequired,
- changeUserRole: PropTypes.func.isRequired,
- confirm: PropTypes.func.isRequired,
- confirmChangeTeamURL: PropTypes.func.isRequired,
- confirmDeleteTeam: PropTypes.func.isRequired,
- currentUser: PropTypes.object.isRequired,
- deleteTeamShown: PropTypes.bool.isRequired,
- dispatch: PropTypes.func.isRequired,
- fetchUsersIfNeeded: PropTypes.func.isRequired,
- hasGuestRole: PropTypes.bool.isRequired,
- hasMemberRole: PropTypes.bool.isRequired,
- hasOwnerRole: PropTypes.bool.isRequired,
- intl: PropTypes.shape().isRequired,
- removeUserFromTeam: PropTypes.func.isRequired,
- userListReady: PropTypes.bool.isRequired,
- users: PropTypes.array.isRequired,
- team: PropTypes.object.isRequired,
- };
+interface TeamProps {
+ changeTeamURLShown: boolean;
+ changeUserRole: (userId: number, role: string) => Action;
+ confirm: (options: ConfirmOpts) => void;
+ confirmChangeTeamURL: () => void;
+ confirmDeleteTeam: () => void;
+ currentUser: User;
+ deleteTeamShown: boolean;
+ dispatch: (action: Action) => void;
+ fetchUsersIfNeeded: () => void;
+ hasGuestRole: boolean;
+ hasMemberRole: boolean;
+ hasOwnerRole: boolean;
+ intl: IntlShape;
+ removeUserFromTeam: (userId: number) => void;
+ userListReady: boolean;
+ users: User[];
+ team: TeamType;
+}
+class Team extends React.Component {
componentDidMount() {
this.props.fetchUsersIfNeeded();
}
- handleRoleChange = (user) => (event) => {
- const { currentUser, team } = this.props;
-
- const newRole = event.target.value;
-
- const changeRole = this.props.changeUserRole(user.id, newRole);
-
- if (
- event.target.value === "member" &&
- getRole(currentUser, team).type === "member"
- ) {
- this.props.confirm({
- actionLabel: "Promote",
- body: "Are you sure you want to promote this user to Member status? You will not be able to demote them later.",
- action: changeRole,
- });
- } else if (currentUser.id === user.id && !currentUser.superuser) {
- this.props.confirm({
- actionLabel: "Demote",
- body: "Are you sure you want to demote yourself? You will not be able to undo this by yourself.",
- action: changeRole,
- });
- } else {
- this.props.dispatch(changeRole);
- }
- };
-
- handleDeleteUserClicked = (id) => () => {
+ handleRoleChange =
+ (user: User) => (event: ChangeEvent) => {
+ const { currentUser, team } = this.props;
+
+ const newRole = event.target.value;
+
+ const changeRole = this.props.changeUserRole(user.id, newRole);
+
+ if (
+ event.target.value === "member" &&
+ getRole(currentUser, team)?.type === "member"
+ ) {
+ this.props.confirm({
+ actionLabel: "Promote",
+ body: "Are you sure you want to promote this user to Member status? You will not be able to demote them later.",
+ action: changeRole,
+ });
+ } else if (currentUser.id === user.id && !currentUser.superuser) {
+ this.props.confirm({
+ actionLabel: "Demote",
+ body: "Are you sure you want to demote yourself? You will not be able to undo this by yourself.",
+ action: changeRole,
+ });
+ } else {
+ this.props.dispatch(changeRole);
+ }
+ };
+
+ handleDeleteUserClicked = (id: number) => () => {
// eslint-disable-next-line no-restricted-globals, no-alert
if (confirm("Are you sure you want to remove this user from this team?")) {
this.props.removeUserFromTeam(id);
}
};
- roleOptions = (user) => {
+ roleOptions = (user: User) => {
const {
currentUser,
hasGuestRole,
diff --git a/src/routes/team/team/TeamContainer.js b/src/routes/team/team/TeamContainer.ts
similarity index 63%
rename from src/routes/team/team/TeamContainer.js
rename to src/routes/team/team/TeamContainer.ts
index 90a3092af..cad60da84 100644
--- a/src/routes/team/team/TeamContainer.js
+++ b/src/routes/team/team/TeamContainer.ts
@@ -6,13 +6,14 @@ import {
fetchUsersIfNeeded,
removeUser,
} from "../../../actions/users";
+import { ConfirmOpts, Dispatch, State } from "../../../interfaces";
import { currentUserHasRole, isUserListReady } from "../../../selectors";
import { getTeam } from "../../../selectors/team";
import { getCurrentUser } from "../../../selectors/user";
import { getUsers } from "../../../selectors/users";
import Team from "./Team";
-const mapStateToProps = (state) => ({
+const mapStateToProps = (state: State) => ({
changeTeamURLShown: !!state.modals.changeTeamURL,
currentUser: getCurrentUser(state),
deleteTeamShown: !!state.modals.deleteTeam,
@@ -24,16 +25,29 @@ const mapStateToProps = (state) => ({
team: getTeam(state),
});
-const mapDispatchToProps = (dispatch) => ({
- changeUserRole: (id, type) => changeUserRole(id, type),
- confirm: (opts) => dispatch(showModal("confirm", opts)),
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ changeUserRole,
+ confirm: (opts: ConfirmOpts) => dispatch(showModal("confirm", opts)),
confirmChangeTeamURL: () => dispatch(showModal("changeTeamURL")),
confirmDeleteTeam: () => dispatch(showModal("deleteTeam")),
dispatch,
fetchUsersIfNeeded() {
dispatch(fetchUsersIfNeeded());
},
- removeUserFromTeam: (id) => dispatch(removeUser(id)),
});
-export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Team));
+const mergeProps = (
+ stateProps: ReturnType,
+ dispatchProps: ReturnType
+) => ({
+ ...stateProps,
+ ...dispatchProps,
+ removeUserFromTeam: (id: number) =>
+ dispatchProps.dispatch(removeUser(id, stateProps.team!)),
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+ mergeProps
+)(injectIntl(Team));
diff --git a/src/routes/team/team/index.test.ts b/src/routes/team/team/index.test.ts
index 6752cb133..cd2fedd3d 100644
--- a/src/routes/team/team/index.test.ts
+++ b/src/routes/team/team/index.test.ts
@@ -5,15 +5,15 @@
import { expect } from "chai";
import proxyquire from "proxyquire";
-import { ResolveContext } from "universal-router";
import { configureMockStore } from "@jedmao/redux-mock-store";
import mockEsmodule from "../../../../test/mockEsmodule";
+import { AppContext } from "../../../interfaces";
const proxyquireStrict = proxyquire.noCallThru();
const mockStore = configureMockStore();
describe("routes/team/team", () => {
- let context: Partial;
+ let context: Omit;
let render404: string;
let team;
let landingProxy;
@@ -36,15 +36,14 @@ describe("routes/team/team", () => {
});
describe("when user is a guest", () => {
- it("renders 404", function test() {
- this.timeout(8000);
+ it("renders 404", () => {
render404 = "render404";
landingProxy = proxyquireStrict("./index", {
"../../../helpers/hasRole": mockEsmodule({
default: () => false,
}),
"../../helpers/renderIfHasName": mockEsmodule({
- default: (_: ResolveContext, cb: () => void) => cb(),
+ default: (_: AppContext, cb: () => void) => cb(),
}),
"../../helpers/render404": mockEsmodule({
default: () => render404,
@@ -61,7 +60,7 @@ describe("routes/team/team", () => {
default: () => true,
}),
"../../helpers/renderIfHasName": mockEsmodule({
- default: (_: ResolveContext, cb: () => void) => cb(),
+ default: (_: AppContext, cb: () => void) => cb(),
}),
}).default;
diff --git a/src/routes/team/team/index.js b/src/routes/team/team/index.tsx
similarity index 87%
rename from src/routes/team/team/index.js
rename to src/routes/team/team/index.tsx
index 96602c281..c0071031b 100644
--- a/src/routes/team/team/index.js
+++ b/src/routes/team/team/index.tsx
@@ -10,19 +10,20 @@
import React from "react";
import LayoutContainer from "../../../components/Layout/LayoutContainer";
import hasRole from "../../../helpers/hasRole";
+import { AppContext } from "../../../interfaces";
import renderIfHasName from "../../helpers/renderIfHasName";
import render404 from "../../helpers/render404";
import TeamContainer from "./TeamContainer";
const title = "Team";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const user = state.user;
const team = state.team;
return renderIfHasName(context, () => {
- if (team.id && hasRole(user, team, "member")) {
+ if (team && hasRole(user, team, "member")) {
return {
title,
chunks: ["team"],
diff --git a/src/routes/team/teams/index.js b/src/routes/team/teams/index.ts
similarity index 84%
rename from src/routes/team/teams/index.js
rename to src/routes/team/teams/index.ts
index 7872d1b49..65779292b 100644
--- a/src/routes/team/teams/index.js
+++ b/src/routes/team/teams/index.ts
@@ -8,17 +8,18 @@
*/
import hasRole from "../../../helpers/hasRole";
+import { AppContext } from "../../../interfaces";
import renderIfHasName from "../../helpers/renderIfHasName";
import render404 from "../../helpers/render404";
-export default (context) => {
+export default (context: AppContext) => {
const state = context.store.getState();
const host = state.host;
const team = state.team;
const user = state.user;
return renderIfHasName(context, () => {
- if (team.id && hasRole(user, team)) {
+ if (team && hasRole(user, team)) {
return {
redirect: `//${host}/teams`,
status: 301,
diff --git a/src/selectors/decisions.js b/src/selectors/decisions.ts
similarity index 78%
rename from src/selectors/decisions.js
rename to src/selectors/decisions.ts
index ee64de0fe..bf79d0bc9 100644
--- a/src/selectors/decisions.js
+++ b/src/selectors/decisions.ts
@@ -1,8 +1,10 @@
import { createSelector } from "reselect";
import dayjs from "dayjs";
+import { Decision, State } from "../interfaces";
-export const getDecisionIds = (state) => state.decisions.items.result || [];
-export const getDecisionEntities = (state) => {
+export const getDecisionIds = (state: State) =>
+ state.decisions.items.result || [];
+export const getDecisionEntities = (state: State) => {
if (state.decisions.items.entities) {
return state.decisions.items.entities.decisions;
}
@@ -11,9 +13,10 @@ export const getDecisionEntities = (state) => {
};
export const getDecisionsByDay = createSelector(
- [getDecisionIds, getDecisionEntities],
+ getDecisionIds,
+ getDecisionEntities,
(decisionIds, decisionEntities) =>
- decisionIds.reduce(
+ decisionIds.reduce<{ [index: number]: Decision[] }>(
(acc, curr) => {
const decision = decisionEntities[curr];
const createdAt = dayjs(decision.createdAt);
@@ -41,7 +44,7 @@ export const getDecisionsByRestaurantId = createSelector(
getDecisionIds,
getDecisionEntities,
(decisionIds, decisionEntities) =>
- decisionIds.reduce((acc, curr) => {
+ decisionIds.reduce<{ [index: number]: string }>((acc, curr) => {
const decision = decisionEntities[curr];
acc[decision.restaurantId] = new Date(
decision.createdAt
@@ -50,7 +53,8 @@ export const getDecisionsByRestaurantId = createSelector(
}, {})
);
-export const areDecisionsLoading = (state) => state.decisions.didInvalidate;
+export const areDecisionsLoading = (state: State) =>
+ state.decisions.didInvalidate;
export const getDecision = createSelector(
getDecisionIds,
diff --git a/src/selectors/index.js b/src/selectors/index.ts
similarity index 88%
rename from src/selectors/index.js
rename to src/selectors/index.ts
index 8eeeeecdd..0c49398d0 100644
--- a/src/selectors/index.js
+++ b/src/selectors/index.ts
@@ -1,5 +1,6 @@
import { createSelector } from "reselect";
import hasRole from "../helpers/hasRole";
+import { RoleType, State } from "../interfaces";
import { areDecisionsLoading } from "./decisions";
import {
areRestaurantsLoading,
@@ -17,8 +18,13 @@ import { areUsersLoading, getUserId, getUserById } from "./users";
import { getCurrentUser } from "./user";
import { getMapUi } from "./mapUi";
-export const getUserByVoteId = (state, voteId) =>
- getUserById(state, getVoteById(state, voteId).userId);
+export const getUserByVoteId = (state: State, voteId: number) => {
+ const vote = getVoteById(state, voteId);
+ if (vote) {
+ return getUserById(state, vote.userId);
+ }
+ return undefined;
+};
export const makeGetRestaurantVotesForUser = () =>
createSelector(
@@ -27,7 +33,7 @@ export const makeGetRestaurantVotesForUser = () =>
getUserId,
(restaurant, voteEntities, userId) =>
restaurant.votes.filter(
- (voteId) => voteEntities[voteId].userId === userId
+ (voteId) => voteEntities?.[voteId].userId === userId
)
);
@@ -87,7 +93,7 @@ export const getFilteredRestaurants = createSelector(
}
);
-const getRoleProp = (state, props) => props.role || props;
+const getRoleProp = (state: State, role: RoleType) => role;
export const currentUserHasRole = createSelector(
getCurrentUser,
getTeam,
diff --git a/src/selectors/listUi.js b/src/selectors/listUi.js
deleted file mode 100644
index c01cd85bf..000000000
--- a/src/selectors/listUi.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const blankUi = {};
-
-export const getListUi = (state) => state.listUi;
-export const getListUiItemForId = (state, props) =>
- getListUi(state)[typeof props === "object" ? props.restaurantId : props] ||
- blankUi;
-export const getNewlyAdded = (state) => state.listUi.newlyAdded;
-
-export const getFlipMove = (state) => state.listUi.flipMove;
diff --git a/src/selectors/listUi.ts b/src/selectors/listUi.ts
new file mode 100644
index 000000000..cdbfad7f1
--- /dev/null
+++ b/src/selectors/listUi.ts
@@ -0,0 +1,10 @@
+import { ListUiItem, State } from "../interfaces";
+
+const blankUi: ListUiItem = {};
+
+export const getListUi = (state: State) => state.listUi;
+export const getListUiItemForId = (state: State, restaurantId: number) =>
+ getListUi(state)[restaurantId] || blankUi;
+
+export const getNewlyAdded = (state: State) => state.listUi.newlyAdded;
+export const getFlipMove = (state: State) => state.listUi.flipMove;
diff --git a/src/selectors/locale.js b/src/selectors/locale.js
deleted file mode 100644
index c585c066f..000000000
--- a/src/selectors/locale.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { createSelector } from "reselect";
-import * as messages from "../core/messages";
-
-export const getLocale = (state) => state.locale;
-export const getMessages = createSelector(getLocale, (locale) => {
- const messagesForLocale = messages[locale];
- const flattenedMessages = {};
- Object.keys(messagesForLocale).forEach((component) => {
- const messagesForComponent = messagesForLocale[component];
- if (typeof messagesForComponent === "string") {
- flattenedMessages[component] = messagesForComponent;
- } else {
- Object.keys(messagesForComponent).forEach((id) => {
- flattenedMessages[`${component}.${id}`] = messagesForComponent[id];
- });
- }
- });
- return flattenedMessages;
-});
diff --git a/src/selectors/locale.ts b/src/selectors/locale.ts
new file mode 100644
index 000000000..f3d7cb976
--- /dev/null
+++ b/src/selectors/locale.ts
@@ -0,0 +1,23 @@
+import { createSelector } from "reselect";
+import * as messages from "../core/messages";
+import { State } from "../interfaces";
+
+export const getLocale = (state: State) => state.locale;
+export const getMessages = createSelector(getLocale, (locale) => {
+ const messagesForLocale = messages[locale];
+ const flattenedMessages: { [index: string]: string } = {};
+ Object.keys(messagesForLocale).forEach((component) => {
+ const componentKey = component as keyof typeof messagesForLocale;
+ const messagesForComponent = messagesForLocale[componentKey];
+ if (typeof messagesForComponent === "string") {
+ flattenedMessages[componentKey] = messagesForComponent;
+ } else {
+ Object.keys(messagesForComponent).forEach((id) => {
+ const idKey = id as keyof typeof messagesForComponent;
+ flattenedMessages[`${componentKey}.${id}`] =
+ messagesForComponent[idKey];
+ });
+ }
+ });
+ return flattenedMessages;
+});
diff --git a/src/selectors/mapUi.js b/src/selectors/mapUi.js
deleted file mode 100644
index 90306994f..000000000
--- a/src/selectors/mapUi.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export const getMapUi = (state) => state.mapUi;
-export const getCenter = (state) => state.mapUi.center;
diff --git a/src/selectors/mapUi.ts b/src/selectors/mapUi.ts
new file mode 100644
index 000000000..5b7f154c9
--- /dev/null
+++ b/src/selectors/mapUi.ts
@@ -0,0 +1,4 @@
+import { State } from "../interfaces";
+
+export const getMapUi = (state: State) => state.mapUi;
+export const getCenter = (state: State) => state.mapUi.center;
diff --git a/src/selectors/restaurants.js b/src/selectors/restaurants.js
deleted file mode 100644
index 93a45bf2b..000000000
--- a/src/selectors/restaurants.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { createSelector } from "reselect";
-
-export const areRestaurantsLoading = (state) => state.restaurants.didInvalidate;
-export const getRestaurantId = (state, props) =>
- typeof props === "object" ? props.restaurantId : props;
-export const getRestaurantIds = (state) => state.restaurants.items.result;
-export const getRestaurantEntities = (state) =>
- state.restaurants.items.entities.restaurants;
-
-export const getRestaurantById = createSelector(
- [getRestaurantEntities, getRestaurantId],
- (restaurantEntities, id) => restaurantEntities[id]
-);
-
-export const getRestaurants = createSelector(
- [getRestaurantIds, getRestaurantEntities],
- (restaurantIds, restaurantEntities) =>
- restaurantIds.map((id) => restaurantEntities[id])
-);
-
-export const getTagsForRestaurant = createSelector(
- [getRestaurantById],
- (restaurant) => restaurant.tags
-);
-
-export const getNameFilter = (state) => state.restaurants.nameFilter;
diff --git a/src/selectors/restaurants.ts b/src/selectors/restaurants.ts
new file mode 100644
index 000000000..cb561ce09
--- /dev/null
+++ b/src/selectors/restaurants.ts
@@ -0,0 +1,38 @@
+import { createSelector, Selector } from "reselect";
+import { Restaurant, State } from "../interfaces";
+
+type PartialState = Partial & Pick;
+
+export const areRestaurantsLoading: Selector = (state) =>
+ state.restaurants.didInvalidate;
+export const getRestaurantId: Selector = (
+ state,
+ props: number | { restaurantId: number }
+) => (typeof props === "number" ? props : props.restaurantId);
+export const getRestaurantIds: Selector = (state) =>
+ state.restaurants.items.result;
+export const getRestaurantEntities: Selector<
+ PartialState,
+ { [index: number]: Restaurant }
+> = (state) => state.restaurants.items.entities.restaurants;
+
+export const getRestaurantById = createSelector(
+ getRestaurantEntities,
+ getRestaurantId,
+ (restaurantEntities, id) => restaurantEntities[id]
+);
+
+export const getRestaurants = createSelector(
+ getRestaurantIds,
+ getRestaurantEntities,
+ (restaurantIds, restaurantEntities) =>
+ restaurantIds.map((id) => restaurantEntities[id])
+);
+
+export const getTagsForRestaurant = createSelector(
+ getRestaurantById,
+ (restaurant) => restaurant.tags
+);
+
+export const getNameFilter: Selector = (state) =>
+ state.restaurants.nameFilter;
diff --git a/src/selectors/tagExclusions.js b/src/selectors/tagExclusions.js
deleted file mode 100644
index 01127cd29..000000000
--- a/src/selectors/tagExclusions.js
+++ /dev/null
@@ -1 +0,0 @@
-export const getTagExclusions = (state) => state.tagExclusions;
diff --git a/src/selectors/tagExclusions.ts b/src/selectors/tagExclusions.ts
new file mode 100644
index 000000000..5a4b5da8b
--- /dev/null
+++ b/src/selectors/tagExclusions.ts
@@ -0,0 +1,3 @@
+import { State } from "../interfaces";
+
+export const getTagExclusions = (state: State) => state.tagExclusions;
diff --git a/src/selectors/tagFilters.js b/src/selectors/tagFilters.js
deleted file mode 100644
index 487112f23..000000000
--- a/src/selectors/tagFilters.js
+++ /dev/null
@@ -1 +0,0 @@
-export const getTagFilters = (state) => state.tagFilters;
diff --git a/src/selectors/tagFilters.ts b/src/selectors/tagFilters.ts
new file mode 100644
index 000000000..0741542c3
--- /dev/null
+++ b/src/selectors/tagFilters.ts
@@ -0,0 +1,3 @@
+import { State } from "../interfaces";
+
+export const getTagFilters = (state: State) => state.tagFilters;
diff --git a/src/selectors/tags.js b/src/selectors/tags.js
deleted file mode 100644
index 4e2f52f68..000000000
--- a/src/selectors/tags.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import { createSelector } from "reselect";
-
-const emptyObj = {};
-
-export const areTagsLoading = (state) => state.tags.didInvalidate;
-export const getTagIds = (state) => state.tags.items.result;
-export const getTagEntities = (state) =>
- state.tags.items.entities.tags || emptyObj;
-
-export const getTags = createSelector(
- [getTagIds, getTagEntities],
- (tagIds, tagEntities) => tagIds.map((id) => tagEntities[id])
-);
-
-export const getTagById = (state, props) =>
- getTagEntities(state)[typeof props === "object" ? props.tagId : props];
diff --git a/src/selectors/tags.ts b/src/selectors/tags.ts
new file mode 100644
index 000000000..49d1ad7e1
--- /dev/null
+++ b/src/selectors/tags.ts
@@ -0,0 +1,21 @@
+import { createSelector } from "reselect";
+import { State } from "../interfaces";
+
+const emptyObj = {};
+
+export const areTagsLoading = (state: State) => state.tags.didInvalidate;
+export const getTagIds = (state: Partial & Pick) =>
+ state.tags.items.result;
+export const getTagEntities = (state: Partial & Pick) =>
+ state.tags.items.entities.tags || emptyObj;
+
+export const getTags = createSelector(
+ getTagIds,
+ getTagEntities,
+ (tagIds, tagEntities) => tagIds.map((id) => tagEntities[id])
+);
+
+export const getTagById = (
+ state: Partial & Pick,
+ props: { tagId: number } | number
+) => getTagEntities(state)[typeof props === "object" ? props.tagId : props];
diff --git a/src/selectors/team.js b/src/selectors/team.js
deleted file mode 100644
index 8d936c317..000000000
--- a/src/selectors/team.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createSelector } from "reselect";
-
-export const getTeam = (state) => state.team;
-export const getTeamDefaultZoom = (state) => state.team.defaultZoom;
-export const getTeamSortDuration = (state) => state.team.sortDuration;
-
-export const getTeamLatLng = createSelector(getTeam, (team) => ({
- lat: team.lat,
- lng: team.lng,
-}));
diff --git a/src/selectors/team.ts b/src/selectors/team.ts
new file mode 100644
index 000000000..3d006fccd
--- /dev/null
+++ b/src/selectors/team.ts
@@ -0,0 +1,11 @@
+import { createSelector } from "reselect";
+import { State } from "../interfaces";
+
+export const getTeam = (state: State) => state.team;
+export const getTeamDefaultZoom = (state: State) => state.team?.defaultZoom;
+export const getTeamSortDuration = (state: State) => state.team?.sortDuration;
+
+export const getTeamLatLng = createSelector(getTeam, (team) => ({
+ lat: team!.lat,
+ lng: team!.lng,
+}));
diff --git a/src/selectors/teams.js b/src/selectors/teams.js
deleted file mode 100644
index 051eb88ce..000000000
--- a/src/selectors/teams.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createSelector } from "reselect";
-
-export const getTeamIds = (state) => state.teams.items.result;
-export const getTeamEntities = (state) => state.teams.items.entities.teams;
-
-export const getTeams = createSelector(
- getTeamIds,
- getTeamEntities,
- (teamIds, teamEntities) => teamIds.map((id) => teamEntities[id])
-);
diff --git a/src/selectors/teams.ts b/src/selectors/teams.ts
new file mode 100644
index 000000000..d42fe58b0
--- /dev/null
+++ b/src/selectors/teams.ts
@@ -0,0 +1,12 @@
+import { createSelector } from "reselect";
+import { State } from "../interfaces";
+
+export const getTeamIds = (state: State) => state.teams.items.result;
+export const getTeamEntities = (state: State) =>
+ state.teams.items.entities.teams;
+
+export const getTeams = createSelector(
+ getTeamIds,
+ getTeamEntities,
+ (teamIds, teamEntities) => teamIds.map((id) => teamEntities[id])
+);
diff --git a/src/selectors/tests/decisions.test.js b/src/selectors/tests/decisions.test.ts
similarity index 58%
rename from src/selectors/tests/decisions.test.js
rename to src/selectors/tests/decisions.test.ts
index a086237be..da48c00d5 100644
--- a/src/selectors/tests/decisions.test.js
+++ b/src/selectors/tests/decisions.test.ts
@@ -2,31 +2,34 @@
import dayjs from "dayjs";
import { expect } from "chai";
import { getDecisionsByDay } from "../decisions";
+import { Decision, State } from "../../interfaces";
describe("selectors/decisions", () => {
describe("getDecisionsByDay", () => {
- let state;
+ let state: Pick;
beforeEach(() => {
const now = dayjs();
state = {
decisions: {
+ didInvalidate: false,
+ isFetching: false,
items: {
result: [1, 2, 3, 4],
entities: {
decisions: {
1: {
- createdAt: dayjs(now),
- },
+ createdAt: dayjs(now).toDate(),
+ } as Decision,
2: {
- createdAt: dayjs(now).subtract(23, "hours"),
- },
+ createdAt: dayjs(now).subtract(23, "hours").toDate(),
+ } as Decision,
3: {
- createdAt: dayjs(now).subtract(25, "hours"),
- },
+ createdAt: dayjs(now).subtract(25, "hours").toDate(),
+ } as Decision,
4: {
- createdAt: dayjs(now).subtract(48, "hours"),
- },
+ createdAt: dayjs(now).subtract(48, "hours").toDate(),
+ } as Decision,
},
},
},
@@ -36,7 +39,7 @@ describe("selectors/decisions", () => {
it("groups decisions into per-day arrays", () => {
const decisions = state.decisions.items.entities.decisions;
- expect(getDecisionsByDay(state)).to.eql({
+ expect(getDecisionsByDay(state as State)).to.eql({
0: [decisions[1]],
1: [decisions[2], decisions[3]],
2: [decisions[4]],
diff --git a/src/selectors/tests/index.test.js b/src/selectors/tests/index.test.ts
similarity index 84%
rename from src/selectors/tests/index.test.js
rename to src/selectors/tests/index.test.ts
index ade982e9a..63660bb43 100644
--- a/src/selectors/tests/index.test.js
+++ b/src/selectors/tests/index.test.ts
@@ -1,14 +1,15 @@
/* eslint-env mocha */
import { expect } from "chai";
import proxyquire from "proxyquire";
+import { Restaurant } from "../../interfaces";
describe("selectors/index", () => {
describe("getFilteredRestaurants", () => {
- let restaurantIds;
- let nameFilter;
- let tagFilters;
- let tagExclusions;
- let restaurantEntities;
+ let restaurantIds: number[];
+ let nameFilter: string;
+ let tagFilters: number[];
+ let tagExclusions: number[];
+ let restaurantEntities: { [index: number]: Restaurant };
const proxyIndex = proxyquire("../index", {
"./restaurants": {
getRestaurantIds: () => restaurantIds,
@@ -33,12 +34,12 @@ describe("selectors/index", () => {
id: 1,
name: "foo",
tags: [1],
- },
+ } as Restaurant,
2: {
id: 1,
name: "bar",
- tags: [],
- },
+ tags: [] as number[],
+ } as Restaurant,
};
});
diff --git a/src/selectors/users.js b/src/selectors/users.js
deleted file mode 100644
index 0973b3e94..000000000
--- a/src/selectors/users.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { createSelector } from "reselect";
-
-const emptyObj = {};
-
-export const areUsersLoading = (state) => state.users.didInvalidate;
-export const getUserId = (state, props) => props.userId;
-export const getUserIds = (state) => state.users.items.result;
-export const getUserEntities = (state) =>
- state.users.items.entities.users || emptyObj;
-
-export const getUsers = createSelector(
- getUserIds,
- getUserEntities,
- (ids, entities) => ids.map((id) => entities[id])
-);
-
-export const getUserById = (state, props) =>
- getUserEntities(state)[typeof props === "object" ? props.userId : props];
diff --git a/src/selectors/users.ts b/src/selectors/users.ts
new file mode 100644
index 000000000..6beb5de66
--- /dev/null
+++ b/src/selectors/users.ts
@@ -0,0 +1,20 @@
+import { createSelector } from "reselect";
+import { State } from "../interfaces";
+
+const emptyObj = {};
+
+export const areUsersLoading = (state: State) => state.users.didInvalidate;
+export const getUserId = (state: State, props: { userId: number }) =>
+ props.userId;
+export const getUserIds = (state: State) => state.users.items.result;
+export const getUserEntities = (state: State) =>
+ state.users.items.entities.users || emptyObj;
+
+export const getUsers = createSelector(
+ getUserIds,
+ getUserEntities,
+ (ids, entities) => ids.map((id) => entities[id])
+);
+
+export const getUserById = (state: State, props: { userId: number } | number) =>
+ getUserEntities(state)[typeof props === "object" ? props.userId : props];
diff --git a/src/selectors/votes.js b/src/selectors/votes.js
deleted file mode 100644
index e2b9a38c6..000000000
--- a/src/selectors/votes.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export const getVoteEntities = (state) =>
- state.restaurants.items.entities.votes;
-export const getVoteById = (state, props) =>
- getVoteEntities(state)[typeof props === "object" ? props.voteId : props];
diff --git a/src/selectors/votes.ts b/src/selectors/votes.ts
new file mode 100644
index 000000000..996a81101
--- /dev/null
+++ b/src/selectors/votes.ts
@@ -0,0 +1,6 @@
+import { State } from "../interfaces";
+
+export const getVoteEntities = (state: State) =>
+ state.restaurants.items.entities.votes;
+export const getVoteById = (state: State, props: { voteId: number } | number) =>
+ getVoteEntities(state)?.[typeof props === "object" ? props.voteId : props];
diff --git a/src/server.tsx b/src/server.tsx
index 2d3b4093e..b01fb999a 100644
--- a/src/server.tsx
+++ b/src/server.tsx
@@ -7,7 +7,6 @@
* LICENSE.txt file in the root directory of this source tree.
*/
-import "isomorphic-fetch";
import path from "path";
import fs from "fs";
import { createStream } from "rotating-file-stream";
@@ -30,29 +29,26 @@ import session from "express-session";
import connectSessionSequelize from "connect-session-sequelize";
import flash from "connect-flash";
import { expressjwt, UnauthorizedError as Jwt401Error } from "express-jwt";
-import nodeFetch from "node-fetch";
import React from "react";
import ReactDOM from "react-dom/server";
import expressWs from "express-ws";
import Honeybadger from "@honeybadger-io/js";
import PrettyError from "pretty-error";
import { v1 } from "uuid";
-import { ResolveContext } from "universal-router";
-import App from "./components/App";
-import Html from "./components/Html";
+import AppComponent from "./components/App";
+import Html, { HtmlProps } from "./components/Html";
import { ErrorPageWithoutStyle } from "./components/ErrorPage/ErrorPage";
import errorPageStyle from "./components/ErrorPage/ErrorPage.scss";
import generateUrl from "./helpers/generateUrl";
import hasRole from "./helpers/hasRole";
import teamRoutes from "./routes/team";
import mainRoutes from "./routes/main";
-import createFetch from "./createFetch";
import passport from "./passport";
import routerCreator from "./router";
// @ts-ignore
import chunks from "./chunk-manifest.json"; // eslint-disable-line import/no-unresolved
import configureStore from "./store/configureStore";
-import config from "./config";
+import * as config from "./config";
import makeInitialState from "./initialState";
import invitationMiddleware from "./middlewares/invitation";
import loginMiddleware from "./middlewares/login";
@@ -60,7 +56,8 @@ import passwordMiddleware from "./middlewares/password";
import usersMiddleware from "./middlewares/users";
import api from "./api";
import { sequelize, Team, User } from "./db";
-import { ExtWebSocket, Flash, StateData } from "./interfaces";
+import { App, AppContext, ExtWebSocket, Flash, StateData } from "./interfaces";
+import { InsertCSS } from "isomorphic-style-loader/StyleContext";
process.on("unhandledRejection", (reason, p) => {
console.error("Unhandled Rejection at:", p, "reason:", reason);
@@ -355,29 +352,19 @@ const render: RequestHandler = async (req, res, next) => {
// Enables critical path CSS rendering
// https://github.com/kriasoft/isomorphic-style-loader
- const insertCss = (...styles: Style[]) => {
+ const insertCss: InsertCSS = (...styles) => {
// eslint-disable-next-line no-underscore-dangle
styles.forEach((style) => css.add(style._getCss()));
};
- // Universal HTTP client
- const fetch = createFetch(nodeFetch, {
- baseUrl: config.api.serverUrl,
- cookie: req.headers.cookie as string,
- });
-
const initialState = makeInitialState(stateData as Required);
- const store = configureStore(initialState, {
- fetch,
- // I should not use `history` on server.. but how I do redirection? follow universal-router
- });
+ const store = configureStore(initialState);
// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
- const context: ResolveContext = {
+ const context: AppContext = {
insertCss,
- fetch,
- googleApiKey: config.googleApiKey,
+ googleApiKey: config.googleApiKey!,
// The twins below are wild, be careful!
pathname: req.path,
query: req.query,
@@ -404,22 +391,22 @@ const render: RequestHandler = async (req, res, next) => {
const pageTitle = route.title || "Lunch";
- const data = {
+ const data: HtmlProps = {
...route,
title: pageTitle,
ogTitle: route.ogTitle || pageTitle,
description:
"A simple lunch voting app for you and your team. Search nearby restaurants, add them to your list, vote for as many as you like, and decide on today’s pick!",
- body: "",
- root: generateUrl(req, req.get("host")),
+ children: "",
+ root: generateUrl(req, req.get("host")!),
};
data.children = ReactDOM.renderToString(
- {route.component}
+ {route.component}
);
data.styles = [{ id: "css", cssText: [...css].join("") }];
- const scripts = new Set();
+ const scripts = new Set();
const addChunk = (chunk: string) => {
if (chunks[chunk]) {
chunks[chunk].forEach((asset: string) => scripts.add(asset));
@@ -434,7 +421,7 @@ const render: RequestHandler = async (req, res, next) => {
data.scripts = Array.from(scripts);
data.app = {
apiUrl: config.api.clientUrl,
- googleApiKey: config.googleApiKey,
+ googleApiKey: config.googleApiKey!,
state: initialState,
};
diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts
index fe5272c43..340441160 100644
--- a/src/store/configureStore.ts
+++ b/src/store/configureStore.ts
@@ -38,7 +38,7 @@ const generateReducers = (
// Add the reducer to your store on the `routing` key
export default function configureStore(
initialState: NonNormalizedState,
- helpersConfig: StateHelpers
+ helpersConfig: StateHelpers = {}
) {
const normalizedInitialState = JSON.parse(JSON.stringify(initialState));
diff --git a/src/store/createHelpers.ts b/src/store/createHelpers.ts
index d61f4e8ac..076fa20a2 100644
--- a/src/store/createHelpers.ts
+++ b/src/store/createHelpers.ts
@@ -1,8 +1,7 @@
import { StateHelpers } from "../interfaces";
-export default function createHelpers({ fetch, history }: StateHelpers) {
+export default function createHelpers({ history }: StateHelpers) {
return {
- fetch,
history,
};
}
diff --git a/test/mocha-setup.js b/test/mocha-setup.ts
similarity index 100%
rename from test/mocha-setup.js
rename to test/mocha-setup.ts
diff --git a/test/mockEsmodule.js b/test/mockEsmodule.ts
similarity index 72%
rename from test/mockEsmodule.js
rename to test/mockEsmodule.ts
index 8c3f28a57..d9a8233b1 100644
--- a/test/mockEsmodule.js
+++ b/test/mockEsmodule.ts
@@ -1,4 +1,4 @@
-export default (obj) => {
+export default (obj?: Record) => {
const esModule = obj || {};
Object.defineProperty(esModule, "__esModule", {
value: true,
diff --git a/test/setup.js b/test/setup.ts
similarity index 80%
rename from test/setup.js
rename to test/setup.ts
index 20ce9332c..0eae4c723 100644
--- a/test/setup.js
+++ b/test/setup.ts
@@ -11,8 +11,6 @@
require("global-jsdom/register");
-require("core-js/stable");
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { use } = require("chai");
// eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -20,13 +18,6 @@ const chaiJSDOM = require("chai-jsdom");
use(chaiJSDOM);
-// eslint-disable-next-line @typescript-eslint/no-var-requires
-const babelRegister = require("@babel/register").default;
-
-babelRegister({ extensions: [".js", ".jsx"] });
-
-require("ts-node/register");
-
process.env.NODE_ENV = "test";
function noop() {
diff --git a/tools/deploy.js b/tools/deploy.js
index bd89c24dd..8b0eb5ca4 100644
--- a/tools/deploy.js
+++ b/tools/deploy.js
@@ -8,7 +8,6 @@
*/
import path from "path";
-import fetch from "node-fetch";
import { spawn } from "./lib/cp";
import { makeDir, moveDir, cleanDir } from "./lib/fs";
import run from "./run";
diff --git a/tools/render.js b/tools/render.js
index e89ab7035..75a42c37a 100644
--- a/tools/render.js
+++ b/tools/render.js
@@ -8,7 +8,6 @@
*/
import path from "path";
-import fetch from "node-fetch";
import { writeFile, makeDir } from "./lib/fs";
import runServer from "./runServer";
diff --git a/tools/run.js b/tools/run.ts
similarity index 88%
rename from tools/run.js
rename to tools/run.ts
index 9f57529f3..84ad028ca 100644
--- a/tools/run.js
+++ b/tools/run.ts
@@ -9,11 +9,10 @@
/* eslint-disable @typescript-eslint/no-var-requires */
-export function format(time) {
- return time.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
-}
+export const format = (time: Date) =>
+ time.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
-function run(fn, options) {
+function run(task: (o?: string) => Promise, options?: string) {
// eslint-disable-next-line global-require
const path = require("path");
@@ -27,7 +26,6 @@ function run(fn, options) {
// eslint-disable-next-line global-require
require("dotenv").config();
- const task = typeof fn.default === "undefined" ? fn : fn.default;
const start = new Date();
console.info(
`[${format(start)}] Starting '${task.name}${
diff --git a/tools/webpack.config.js b/tools/webpack.config.js
index d4a8da950..3cf2c765f 100644
--- a/tools/webpack.config.js
+++ b/tools/webpack.config.js
@@ -19,7 +19,6 @@ import { InjectManifest } from "workbox-webpack-plugin";
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin";
import overrideRules from "./lib/overrideRules";
-import pkg from "../package.json";
const ROOT_DIR = path.resolve(__dirname, "..");
const resolvePath = (...args) => path.resolve(ROOT_DIR, ...args);
@@ -92,49 +91,6 @@ const config = {
use: "ts-loader",
exclude: /node_modules/,
},
- // Rules for JS / JSX
- {
- test: /\.(js|jsx|mjs)$/,
- include: [ROOT_DIR, resolvePath("tools")],
- loader: "babel-loader",
- options: {
- // https://github.com/babel/babel-loader#options
- cacheDirectory: isDebug,
-
- // https://babeljs.io/docs/usage/options/
- babelrc: false,
- configFile: false,
- presets: [
- // A Babel preset that can automatically determine the Babel plugins and polyfills
- // https://github.com/babel/babel-preset-env
- [
- "@babel/preset-env",
- {
- forceAllTransforms: !isDebug, // for UglifyJS
- },
- ],
- // JSX
- // https://github.com/babel/babel/tree/master/packages/babel-preset-react
- ["@babel/preset-react", { development: isDebug }],
- ],
- plugins: [
- "@babel/plugin-syntax-dynamic-import",
- // Treat React JSX elements as value types and hoist them to the highest scope
- // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-constant-elements
- ...(isDebug ? [] : ["@babel/transform-react-constant-elements"]),
- // Replaces the React.createElement function with one that is more optimized for production
- // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-inline-elements
- ...(isDebug ? [] : ["@babel/transform-react-inline-elements"]),
- // Remove unnecessary React propTypes from the production build
- // https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types
- ...(isDebug ? [] : ["transform-react-remove-prop-types"]),
- ...(isDebug && process.env.NODE_ENV !== "test"
- ? ["react-refresh/babel"]
- : []),
- ],
- },
- },
-
// Rules for Style Sheets
{
test: reStyle,
@@ -409,6 +365,7 @@ const clientConfig = {
// Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk).
optimization: {
+ sideEffects: false,
splitChunks: {
cacheGroups: {
commons: {
@@ -467,31 +424,6 @@ const serverConfig = {
...config.module,
rules: overrideRules(config.module.rules, (rule) => {
- // Override babel-preset-env configuration for Node.js
- if (rule.loader === "babel-loader") {
- return {
- ...rule,
- options: {
- ...rule.options,
- presets: rule.options.presets.map((preset) =>
- preset[0] !== "@babel/preset-env"
- ? preset
- : [
- "@babel/preset-env",
- {
- targets: {
- node: pkg.engines.node.match(/(\d+\.?)+/)[0],
- },
- modules: false,
- useBuiltIns: false,
- debug: false,
- },
- ]
- ),
- },
- };
- }
-
// Override paths to static assets
if (
rule.loader === "file-loader" ||
diff --git a/tsconfig.json b/tsconfig.json
index ca517b050..2d4e9f7d4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,17 +18,16 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"strictPropertyInitialization": false,
- // Ensure that .d.ts files are created by tsc, but not .js files
- "declaration": true,
- "emitDeclarationOnly": true,
- // Ensure that Babel can safely transpile files in the TypeScript project
- "isolatedModules": true,
"typeRoots": ["./typings", "node_modules/@types"]
},
"files": ["./global.d.ts"],
"include": ["./**/*.ts", "./**/*.tsx", "./*.d.ts"],
"exclude": ["node_modules"],
"ts-node": {
- "files": true
+ "files": true,
+ "transpileOnly": true, // you can specify ts-node options here
+ "compilerOptions": {
+ "module": "commonjs" // you can also override compilerOptions. Only ts-node will use these overrides
+ }
}
}
diff --git a/typings/common-password.d.ts b/typings/common-password.d.ts
new file mode 100644
index 000000000..533dc9f7f
--- /dev/null
+++ b/typings/common-password.d.ts
@@ -0,0 +1,4 @@
+declare module "common-password" {
+ function commonPassword(str: string): boolean;
+ export default commonPassword;
+}
diff --git a/typings/express.ts b/typings/express.ts
index 800a08b36..ceedf4813 100644
--- a/typings/express.ts
+++ b/typings/express.ts
@@ -3,9 +3,6 @@ import WebSocket from "ws";
import { Team, User as UserInterface } from "../src/interfaces";
declare global {
- interface Window {
- App: any;
- }
namespace Express {
export interface Request {
broadcast: (teamId: number, data: Action) => void;
diff --git a/typings/react-bootstrap.d.ts b/typings/react-bootstrap.d.ts
new file mode 100644
index 000000000..fc60bf0f1
--- /dev/null
+++ b/typings/react-bootstrap.d.ts
@@ -0,0 +1,7 @@
+import { ButtonProps } from "react-bootstrap/Button";
+
+declare module "react-bootstrap/Button" {
+ export interface ButtonPropsWithXsSize extends ButtonProps {
+ size?: "sm" | "lg" | "xs";
+ }
+}
diff --git a/typings/react-geosuggest.d.ts b/typings/react-geosuggest.d.ts
new file mode 100644
index 000000000..d38096960
--- /dev/null
+++ b/typings/react-geosuggest.d.ts
@@ -0,0 +1,12 @@
+import "react-geosuggest";
+
+declare module "react-geosuggest" {
+ export interface Suggest {
+ description: string;
+ place_id: string;
+ terms: { value: string }[];
+ }
+ export default interface Geosuggest {
+ showSuggests: () => void;
+ }
+}
diff --git a/typings/robust-websocket.d.ts b/typings/robust-websocket.d.ts
new file mode 100644
index 000000000..29c676ba4
--- /dev/null
+++ b/typings/robust-websocket.d.ts
@@ -0,0 +1,13 @@
+class RobustWebSocket extends WebSocket {
+ attempts: number;
+
+ constructor(
+ url: Parameters[0],
+ protocols: Parameters[1],
+ options?: Record
+ ): RobustWebsocket;
+}
+
+declare module "robust-websocket" {
+ export default RobustWebSocket;
+}
diff --git a/typings/sequelize-mock.d.ts b/typings/sequelize-mock.d.ts
index e44563cda..03f1034e6 100644
--- a/typings/sequelize-mock.d.ts
+++ b/typings/sequelize-mock.d.ts
@@ -1,8 +1,10 @@
interface SequelizeMockObject {
create: () => void;
destroy: () => void;
+ findAll: () => Promise;
findAllForUser: (userId: string) => Promise;
findOne: () => Promise;
+ getSessionUser: () => Promise;
hasMany: (obj: SequelizeMockObject) => void;
scope: () => void;
}
diff --git a/yarn.lock b/yarn.lock
index 936cf4279..b0d1aad39 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -51,7 +51,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/core@npm:^7.0.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3, @babel/core@npm:^7.20.12, @babel/core@npm:^7.7.5":
+"@babel/core@npm:^7.0.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.7.5":
version: 7.21.8
resolution: "@babel/core@npm:7.21.8"
dependencies:
@@ -74,20 +74,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/eslint-parser@npm:^7.19.1":
- version: 7.19.1
- resolution: "@babel/eslint-parser@npm:7.19.1"
- dependencies:
- "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1
- eslint-visitor-keys: ^2.1.0
- semver: ^6.3.0
- peerDependencies:
- "@babel/core": ">=7.11.0"
- eslint: ^7.5.0 || ^8.0.0
- checksum: 6d5360f62f25ed097250657deb1bc4c4f51a5f5f2fe456e98cda13727753fdf7a11a109b4cfa03ef0dd6ced3beaeb703b76193c1141e29434d1f91f1bac0517d
- languageName: node
- linkType: hard
-
"@babel/generator@npm:^7.21.5":
version: 7.21.5
resolution: "@babel/generator@npm:7.21.5"
@@ -119,16 +105,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-builder-react-jsx@npm:^7.18.6":
- version: 7.19.0
- resolution: "@babel/helper-builder-react-jsx@npm:7.19.0"
- dependencies:
- "@babel/helper-annotate-as-pure": ^7.18.6
- "@babel/types": ^7.19.0
- checksum: a84a815e96e52ff40e5a5634c3f79f7a83fa64c119c5e858a7faeb4f7761ec358f7c502329f8807f37324bb5586a75751827ddb1ec758f5a6047024c53e3e600
- languageName: node
- linkType: hard
-
"@babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.18.9, @babel/helper-compilation-targets@npm:^7.20.0, @babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.21.5":
version: 7.21.5
resolution: "@babel/helper-compilation-targets@npm:7.21.5"
@@ -144,7 +120,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.20.5, @babel/helper-create-class-features-plugin@npm:^7.20.7, @babel/helper-create-class-features-plugin@npm:^7.21.0":
+"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.20.5, @babel/helper-create-class-features-plugin@npm:^7.20.7":
version: 7.21.0
resolution: "@babel/helper-create-class-features-plugin@npm:7.21.0"
dependencies:
@@ -385,25 +361,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/node@npm:^7.20.7":
- version: 7.20.7
- resolution: "@babel/node@npm:7.20.7"
- dependencies:
- "@babel/register": ^7.18.9
- commander: ^4.0.1
- core-js: ^3.26.0
- node-environment-flags: ^1.0.5
- regenerator-runtime: ^0.13.11
- v8flags: ^3.1.1
- peerDependencies:
- "@babel/core": ^7.0.0-0
- bin:
- babel-node: ./bin/babel-node.js
- checksum: 3a5c307db92666bba1856d4fbf147df17332185a6cfbf4e9e2b3e08bc2fb1efa1ba963b88e05d0e0da4e1e5fd6cdb7a2e3e644c00a8e7dea883a900ad9f631e5
- languageName: node
- linkType: hard
-
-"@babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8":
+"@babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8":
version: 7.21.8
resolution: "@babel/parser@npm:7.21.8"
bin:
@@ -475,21 +433,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-proposal-decorators@npm:^7.21.0":
- version: 7.21.0
- resolution: "@babel/plugin-proposal-decorators@npm:7.21.0"
- dependencies:
- "@babel/helper-create-class-features-plugin": ^7.21.0
- "@babel/helper-plugin-utils": ^7.20.2
- "@babel/helper-replace-supers": ^7.20.7
- "@babel/helper-split-export-declaration": ^7.18.6
- "@babel/plugin-syntax-decorators": ^7.21.0
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 2889a060010af7ac2e24f7a193262e50a94e254dd86d273e25a2bec2a2f97dd95b136bb933f63448c1cdde4f38ac7877837685657aa8161699eb226d9f1eb453
- languageName: node
- linkType: hard
-
"@babel/plugin-proposal-dynamic-import@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/plugin-proposal-dynamic-import@npm:7.18.6"
@@ -673,17 +616,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-decorators@npm:^7.21.0":
- version: 7.21.0
- resolution: "@babel/plugin-syntax-decorators@npm:7.21.0"
- dependencies:
- "@babel/helper-plugin-utils": ^7.20.2
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 31108e73c3e569f2795ddb4f5f1f32c13c6be97a107d41e318c8f58ca3fde0fa958af3d1a302ab64f36f73ce4d6dda7889732243561c087a7cc3b22192d42a65
- languageName: node
- linkType: hard
-
"@babel/plugin-syntax-dynamic-import@npm:^7.8.3":
version: 7.8.3
resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3"
@@ -728,17 +660,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-jsx@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/plugin-syntax-jsx@npm:7.18.6"
- dependencies:
- "@babel/helper-plugin-utils": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 6d37ea972970195f1ffe1a54745ce2ae456e0ac6145fae9aa1480f297248b262ea6ebb93010eddb86ebfacb94f57c05a1fc5d232b9a67325b09060299d515c67
- languageName: node
- linkType: hard
-
"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4":
version: 7.10.4
resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4"
@@ -827,17 +748,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-syntax-typescript@npm:^7.20.0":
- version: 7.20.0
- resolution: "@babel/plugin-syntax-typescript@npm:7.20.0"
- dependencies:
- "@babel/helper-plugin-utils": ^7.19.0
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 6189c0b5c32ba3c9a80a42338bd50719d783b20ef29b853d4f03929e971913d3cefd80184e924ae98ad6db09080be8fe6f1ffde9a6db8972523234f0274d36f7
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-arrow-functions@npm:^7.18.6":
version: 7.20.7
resolution: "@babel/plugin-transform-arrow-functions@npm:7.20.7"
@@ -1019,7 +929,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-modules-commonjs@npm:^7.19.6, @babel/plugin-transform-modules-commonjs@npm:^7.20.11":
+"@babel/plugin-transform-modules-commonjs@npm:^7.19.6":
version: 7.20.11
resolution: "@babel/plugin-transform-modules-commonjs@npm:7.20.11"
dependencies:
@@ -1115,78 +1025,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-react-constant-elements@npm:^7.20.2":
- version: 7.20.2
- resolution: "@babel/plugin-transform-react-constant-elements@npm:7.20.2"
- dependencies:
- "@babel/helper-plugin-utils": ^7.20.2
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 7b041b726e7c14b8c26a0dd240defac5f93a1f449371c6bdc5e6b46d581211300cc1a79da4140bdf20347f49e175dcb4f469812399206864024d1fdc81171193
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-react-display-name@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/plugin-transform-react-display-name@npm:7.18.6"
- dependencies:
- "@babel/helper-plugin-utils": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 51c087ab9e41ef71a29335587da28417536c6f816c292e092ffc0e0985d2f032656801d4dd502213ce32481f4ba6c69402993ffa67f0818a07606ff811e4be49
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-react-inline-elements@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/plugin-transform-react-inline-elements@npm:7.18.6"
- dependencies:
- "@babel/helper-builder-react-jsx": ^7.18.6
- "@babel/helper-plugin-utils": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 42ae472eb28b183201236310d5b4b2fe34ed5976d16463adce9e6650a9fae8f3d248dfac5d294cb0ac9e0cbb5339aca3806e784ec15211c775816c99e55c9030
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-react-jsx-development@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/plugin-transform-react-jsx-development@npm:7.18.6"
- dependencies:
- "@babel/plugin-transform-react-jsx": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: ec9fa65db66f938b75c45e99584367779ac3e0af8afc589187262e1337c7c4205ea312877813ae4df9fb93d766627b8968d74ac2ba702e4883b1dbbe4953ecee
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-react-jsx@npm:^7.18.6":
- version: 7.20.13
- resolution: "@babel/plugin-transform-react-jsx@npm:7.20.13"
- dependencies:
- "@babel/helper-annotate-as-pure": ^7.18.6
- "@babel/helper-module-imports": ^7.18.6
- "@babel/helper-plugin-utils": ^7.20.2
- "@babel/plugin-syntax-jsx": ^7.18.6
- "@babel/types": ^7.20.7
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: b1daaa9b093ab59f71572dde7ad05ed3490433a47de103fc866f60347da55fa7fe84cf9b4c9fa22917517d52f70ab5e05ec631bba1c348733c0d8ebbd7de8c68
- languageName: node
- linkType: hard
-
-"@babel/plugin-transform-react-pure-annotations@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.18.6"
- dependencies:
- "@babel/helper-annotate-as-pure": ^7.18.6
- "@babel/helper-plugin-utils": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 97c4873d409088f437f9084d084615948198dd87fc6723ada0e7e29c5a03623c2f3e03df3f52e7e7d4d23be32a08ea00818bff302812e48713c706713bd06219
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-regenerator@npm:^7.18.6":
version: 7.20.5
resolution: "@babel/plugin-transform-regenerator@npm:7.20.5"
@@ -1266,19 +1104,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/plugin-transform-typescript@npm:^7.21.0":
- version: 7.21.0
- resolution: "@babel/plugin-transform-typescript@npm:7.21.0"
- dependencies:
- "@babel/helper-create-class-features-plugin": ^7.21.0
- "@babel/helper-plugin-utils": ^7.20.2
- "@babel/plugin-syntax-typescript": ^7.20.0
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 091931118eb515738a4bc8245875f985fc9759d3f85cdf08ee641779b41520241b369404e2bb86fc81907ad827678fdb704e8e5a995352def5dd3051ea2cd870
- languageName: node
- linkType: hard
-
"@babel/plugin-transform-unicode-escapes@npm:^7.18.10":
version: 7.18.10
resolution: "@babel/plugin-transform-unicode-escapes@npm:7.18.10"
@@ -1302,7 +1127,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.20.2":
+"@babel/preset-env@npm:^7.11.0":
version: 7.20.2
resolution: "@babel/preset-env@npm:7.20.2"
dependencies:
@@ -1402,50 +1227,6 @@ __metadata:
languageName: node
linkType: hard
-"@babel/preset-react@npm:^7.18.6":
- version: 7.18.6
- resolution: "@babel/preset-react@npm:7.18.6"
- dependencies:
- "@babel/helper-plugin-utils": ^7.18.6
- "@babel/helper-validator-option": ^7.18.6
- "@babel/plugin-transform-react-display-name": ^7.18.6
- "@babel/plugin-transform-react-jsx": ^7.18.6
- "@babel/plugin-transform-react-jsx-development": ^7.18.6
- "@babel/plugin-transform-react-pure-annotations": ^7.18.6
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 540d9cf0a0cc0bb07e6879994e6fb7152f87dafbac880b56b65e2f528134c7ba33e0cd140b58700c77b2ebf4c81fa6468fed0ba391462d75efc7f8c1699bb4c3
- languageName: node
- linkType: hard
-
-"@babel/preset-typescript@npm:^7.21.0":
- version: 7.21.0
- resolution: "@babel/preset-typescript@npm:7.21.0"
- dependencies:
- "@babel/helper-plugin-utils": ^7.20.2
- "@babel/helper-validator-option": ^7.21.0
- "@babel/plugin-transform-typescript": ^7.21.0
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 6e1f4d7294de2678fbaf36035e98847b2be432f40fe7a1204e5e45b8b05bcbe22902fe0d726e16af14de5bc08987fae28a7899871503fd661050d85f58755af6
- languageName: node
- linkType: hard
-
-"@babel/register@npm:^7.18.9":
- version: 7.18.9
- resolution: "@babel/register@npm:7.18.9"
- dependencies:
- clone-deep: ^4.0.1
- find-cache-dir: ^2.0.0
- make-dir: ^2.1.0
- pirates: ^4.0.5
- source-map-support: ^0.5.16
- peerDependencies:
- "@babel/core": ^7.0.0-0
- checksum: 4aeaff97e061a397f632659082ba86c539ef8194697b236d991c10d1c2ea8f73213d3b5b3b2c24625951a1ef726b7a7d2e70f70ffcb37f79ef0c1a745eebef21
- languageName: node
- linkType: hard
-
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.21.5
resolution: "@babel/runtime@npm:7.21.5"
@@ -1484,7 +1265,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.19.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
+"@babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
version: 7.21.5
resolution: "@babel/types@npm:7.21.5"
dependencies:
@@ -1789,6 +1570,17 @@ __metadata:
languageName: node
linkType: hard
+"@istanbuljs/nyc-config-typescript@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "@istanbuljs/nyc-config-typescript@npm:1.0.2"
+ dependencies:
+ "@istanbuljs/schema": ^0.1.2
+ peerDependencies:
+ nyc: ">=15"
+ checksum: df6f9c9b17df8f1d8813f768c11ca31ec125d60bcd82d8273a467022e414d2d686ee80abb7b0f0e3c512b7ed686771fadb7fb5be8881619b9f6cb1f31b86e9f3
+ languageName: node
+ linkType: hard
+
"@istanbuljs/schema@npm:^0.1.2":
version: 0.1.3
resolution: "@istanbuljs/schema@npm:0.1.3"
@@ -1932,15 +1724,6 @@ __metadata:
languageName: node
linkType: hard
-"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1":
- version: 5.1.1-v1
- resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1"
- dependencies:
- eslint-scope: 5.1.1
- checksum: f2e3b2d6a6e2d9f163ca22105910c9f850dc4897af0aea3ef0a5886b63d8e1ba6505b71c99cb78a3bba24a09557d601eb21c8dede3f3213753fcfef364eb0e57
- languageName: node
- linkType: hard
-
"@nodelib/fs.scandir@npm:2.1.5":
version: 2.1.5
resolution: "@nodelib/fs.scandir@npm:2.1.5"
@@ -2207,6 +1990,35 @@ __metadata:
languageName: node
linkType: hard
+"@sendgrid/client@npm:^7.7.0":
+ version: 7.7.0
+ resolution: "@sendgrid/client@npm:7.7.0"
+ dependencies:
+ "@sendgrid/helpers": ^7.7.0
+ axios: ^0.26.0
+ checksum: 81299ff65b67de3df8c20f545aa7c3416519865079a2d21ce1ee80c76da568799679eb680fca51ef0df0ad34628e695e1991ea9cd8809baa9173ce5cda17fa50
+ languageName: node
+ linkType: hard
+
+"@sendgrid/helpers@npm:^7.7.0":
+ version: 7.7.0
+ resolution: "@sendgrid/helpers@npm:7.7.0"
+ dependencies:
+ deepmerge: ^4.2.2
+ checksum: 20387aae1bff06b9febc39f82cd184dd6e59d0e1ae2e74565d88802a6c6a5e4e571924335bfc8b1493f5f09e832f526f71d81e813295b2060379cb6e53786429
+ languageName: node
+ linkType: hard
+
+"@sendgrid/mail@npm:^7.7.0":
+ version: 7.7.0
+ resolution: "@sendgrid/mail@npm:7.7.0"
+ dependencies:
+ "@sendgrid/client": ^7.7.0
+ "@sendgrid/helpers": ^7.7.0
+ checksum: 8bd446c367983e70b5d1f7a9a5796b2db3dd9304a3d6adf36fb3ee87ff0021e69223222e9ddfa62a40749ed9b136d0e6e4567e9dc4ad66b4ae38a404b07f24e1
+ languageName: node
+ linkType: hard
+
"@sinclair/typebox@npm:^0.25.16":
version: 0.25.24
resolution: "@sinclair/typebox@npm:0.25.24"
@@ -2630,6 +2442,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/google.maps@npm:*":
+ version: 3.53.1
+ resolution: "@types/google.maps@npm:3.53.1"
+ checksum: b2d59b3772e7a3d39517089752a5211d7f0e6778e5cc97598a680c8dde4f307968902910bad4e5135a79a965d7e74c9571eafa3dcb5af9e264673601f8fada14
+ languageName: node
+ linkType: hard
+
"@types/google.maps@npm:^3.52.1":
version: 3.52.1
resolution: "@types/google.maps@npm:3.52.1"
@@ -2716,6 +2535,22 @@ __metadata:
languageName: node
linkType: hard
+"@types/lodash.get@npm:^4.4.7":
+ version: 4.4.7
+ resolution: "@types/lodash.get@npm:4.4.7"
+ dependencies:
+ "@types/lodash": "*"
+ checksum: 0dbf1960606e4707c34e8ffbe97ffaad0e47fc5df7a6e24ea6e4fe5838d2468aa13360f38815c77b06e3c9932631ae15662b4139036a69ee16aeb54827a21405
+ languageName: node
+ linkType: hard
+
+"@types/lodash@npm:*":
+ version: 4.14.195
+ resolution: "@types/lodash@npm:4.14.195"
+ checksum: 39b75ca635b3fa943d17d3d3aabc750babe4c8212485a4df166fe0516e39288e14b0c60afc6e21913cc0e5a84734633c71e617e2bd14eaa1cf51b8d7799c432e
+ languageName: node
+ linkType: hard
+
"@types/method-override@npm:^0.0.32":
version: 0.0.32
resolution: "@types/method-override@npm:0.0.32"
@@ -2769,16 +2604,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/node-fetch@npm:^2.6.2":
- version: 2.6.2
- resolution: "@types/node-fetch@npm:2.6.2"
- dependencies:
- "@types/node": "*"
- form-data: ^3.0.0
- checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6
- languageName: node
- linkType: hard
-
"@types/node@npm:*, @types/node@npm:>=10.0.0":
version: 18.11.19
resolution: "@types/node@npm:18.11.19"
@@ -2793,6 +2618,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/node@npm:^20.2.5":
+ version: 20.2.5
+ resolution: "@types/node@npm:20.2.5"
+ checksum: 38ce7c7e9d76880dc632f71d71e0d5914fcda9d5e9a7095d6c339abda55ca4affb0f2a882aeb29398f8e09d2c5151f0b6586c81c8ccdfe529c34b1ea3337425e
+ languageName: node
+ linkType: hard
+
"@types/normalize-package-data@npm:^2.4.0":
version: 2.4.1
resolution: "@types/normalize-package-data@npm:2.4.1"
@@ -2896,6 +2728,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-autosuggest@npm:^10.1.6":
+ version: 10.1.6
+ resolution: "@types/react-autosuggest@npm:10.1.6"
+ dependencies:
+ "@types/react": "*"
+ checksum: 61a3dc9548607d4abef1463a35e7409540e5893ad7400e0a0fb3617f1a97967822f7ad0f7146824aa188648efe8db377549599db80d5d86c5b79cd0b19792227
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4":
version: 18.2.4
resolution: "@types/react-dom@npm:18.2.4"
@@ -2905,6 +2746,25 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-geosuggest@npm:^2.7.13":
+ version: 2.7.13
+ resolution: "@types/react-geosuggest@npm:2.7.13"
+ dependencies:
+ "@types/google.maps": "*"
+ "@types/react": "*"
+ checksum: 38744592d1f4f5086b7b90ed3fdbe7877d0e726cc650cfaf2b7cfe5005a5723a0ba131a4026dc4d7c0d208a2a3ecad97f700090cb240c362c27621bb4df06b09
+ languageName: node
+ linkType: hard
+
+"@types/react-scroll@npm:^1.8.7":
+ version: 1.8.7
+ resolution: "@types/react-scroll@npm:1.8.7"
+ dependencies:
+ "@types/react": "*"
+ checksum: 1308d2d24bcd9e2e78eaaff3b29ed6df59d903c32d0e0d94536ade4b34f544d09737a18798e38ed1c613d2b8b634f83736a64ef55a072686dacdca1e94f4cc05
+ languageName: node
+ linkType: hard
+
"@types/react-transition-group@npm:^4.4.4":
version: 4.4.5
resolution: "@types/react-transition-group@npm:4.4.5"
@@ -2958,6 +2818,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/serialize-javascript@npm:^5.0.2":
+ version: 5.0.2
+ resolution: "@types/serialize-javascript@npm:5.0.2"
+ checksum: eb14df7716b88740d6322e1c17863fa08350287d9594fae99e686aae9d584ac9d7f9e5498e06e20f5c292e214bc56a23cbf2a954ff804b97be6ff5b0af642ec8
+ languageName: node
+ linkType: hard
+
"@types/serve-static@npm:*":
version: 1.15.0
resolution: "@types/serve-static@npm:1.15.0"
@@ -3507,13 +3374,6 @@ __metadata:
languageName: node
linkType: hard
-"addressparser@npm:~1.0.1":
- version: 1.0.1
- resolution: "addressparser@npm:1.0.1"
- checksum: 389051bc6a3a44082a6e7d6256c15e2aba55ae4799f1eed620e34f1c77ddf4dfe9baacc41c6ad25eb5f795195ff8a506dc07ef9e4bc033ee1ab3882edfed396d
- languageName: node
- linkType: hard
-
"agent-base@npm:6, agent-base@npm:^6.0.2":
version: 6.0.2
resolution: "agent-base@npm:6.0.2"
@@ -3930,97 +3790,6 @@ __metadata:
languageName: node
linkType: hard
-"async.ensureasync@npm:^0.5.2":
- version: 0.5.2
- resolution: "async.ensureasync@npm:0.5.2"
- dependencies:
- async.util.ensureasync: 0.5.2
- checksum: d80a54984eaded097fc488bc968b17e7381841c93fef554ffac1679235f4c91c812d18eb4f47740a37788f6c8ba4a6bcf4d257a02bd6d10d76c8debfb63f3e07
- languageName: node
- linkType: hard
-
-"async.queue@npm:^0.5.2":
- version: 0.5.2
- resolution: "async.queue@npm:0.5.2"
- dependencies:
- async.util.queue: 0.5.2
- checksum: e922a21aee5860bc0ba1109cac8999d6b274100de0d1aef2a94f2841c700d61347e54b1ab0119f677a0bc9df00f9aaef469f4a6acdfc8a14a775a1dcd5c93349
- languageName: node
- linkType: hard
-
-"async.util.arrayeach@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.arrayeach@npm:0.5.2"
- checksum: 9ebdc500a971404735694776879cd7a33f1b91cafb4081e77cc459357532ebd3668c80d8be99c0e98fb71f6c8fab4640467db0e52c65cd8fbc44bfed89cdb4c4
- languageName: node
- linkType: hard
-
-"async.util.ensureasync@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.ensureasync@npm:0.5.2"
- dependencies:
- async.util.restparam: 0.5.2
- async.util.setimmediate: 0.5.2
- checksum: 059cd7aecf99ff7f5f85be6ef8e44e76580fbe878d5e7fa703cccf6865dd8f72eeee4144739efd3867e48b6d9a96e404184eadccdacc421335cf220596993c9d
- languageName: node
- linkType: hard
-
-"async.util.isarray@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.isarray@npm:0.5.2"
- checksum: 9f31c2ef342267ab9f4019d043f9ff8727658a99d40c729da97cb341761db078c54a08283c79c0430cea3930ca435f1a08cc13d3e01ec93cbe5bdb81ccad8f51
- languageName: node
- linkType: hard
-
-"async.util.map@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.map@npm:0.5.2"
- checksum: 33a1d4251b0c8f8cf44909a5ee0f8190f2207cada352a78b27cb886f520799c56497c1576107b16e5de4fbc3b259713800f687b5abd4322223a9ccc6d8773759
- languageName: node
- linkType: hard
-
-"async.util.noop@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.noop@npm:0.5.2"
- checksum: 56d83f77ccc0507ab524f9754771831b6903f914a9abbd994de55767ae0ca54f2b0daba1d8977d6c9edb72f0873b92c9281477d6c73a821f0567143781622d27
- languageName: node
- linkType: hard
-
-"async.util.onlyonce@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.onlyonce@npm:0.5.2"
- checksum: 45df5c2ef5fcf01a1079adcd89fb03aef7339738c949bb4f34886e2a7dadfd46a240aaaf4cade7764d8f9be60aef0527959d53766fc067dded18c6bbf1769a2c
- languageName: node
- linkType: hard
-
-"async.util.queue@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.queue@npm:0.5.2"
- dependencies:
- async.util.arrayeach: 0.5.2
- async.util.isarray: 0.5.2
- async.util.map: 0.5.2
- async.util.noop: 0.5.2
- async.util.onlyonce: 0.5.2
- async.util.setimmediate: 0.5.2
- checksum: 193ad898b4217312a47fa09f8fa24bdd5a88e54d468a60d7178ec9f35b937a0a65d7c6f9aa411057d7443db3b63b3a79b1eca1468e3e810195030e129616cf35
- languageName: node
- linkType: hard
-
-"async.util.restparam@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.restparam@npm:0.5.2"
- checksum: 6c6912abb2e2370cbfcb3b65c0f8050c4cafec3f74cc280e68e15c869ba90301d930e00725f3f788be65e051d085d718c49e7161dd8bb93f88c0b82126da4a99
- languageName: node
- linkType: hard
-
-"async.util.setimmediate@npm:0.5.2":
- version: 0.5.2
- resolution: "async.util.setimmediate@npm:0.5.2"
- checksum: 4b536f18a4f9c5796c78ab41ba3aa0640d263cd37b393b5ae5d8565f5116e4df1f867211726650daab391ad8f32ca7af06f00b622bcb22e924fbbb7eee57d488
- languageName: node
- linkType: hard
-
"async@npm:^2.6.0":
version: 2.6.4
resolution: "async@npm:2.6.4"
@@ -4113,6 +3882,15 @@ __metadata:
languageName: node
linkType: hard
+"axios@npm:^0.26.0":
+ version: 0.26.1
+ resolution: "axios@npm:0.26.1"
+ dependencies:
+ follow-redirects: ^1.14.8
+ checksum: d9eb58ff4bc0b36a04783fc9ff760e9245c829a5a1052ee7ca6013410d427036b1d10d04e7380c02f3508c5eaf3485b1ae67bd2adbfec3683704745c8d7a6e1a
+ languageName: node
+ linkType: hard
+
"axobject-query@npm:^3.1.1":
version: 3.1.1
resolution: "axobject-query@npm:3.1.1"
@@ -4122,32 +3900,6 @@ __metadata:
languageName: node
linkType: hard
-"babel-loader@npm:^9.1.0":
- version: 9.1.2
- resolution: "babel-loader@npm:9.1.2"
- dependencies:
- find-cache-dir: ^3.3.2
- schema-utils: ^4.0.0
- peerDependencies:
- "@babel/core": ^7.12.0
- webpack: ">=5"
- checksum: f0edb8e157f9806b810ba3f2c8ca8fa489d377ae5c2b7b00c2ace900a6925641ce4ec520b9c12f70e37b94aa5366e7003e0f6271b26821643e109966ce741cb7
- languageName: node
- linkType: hard
-
-"babel-plugin-istanbul@npm:^6.1.1":
- version: 6.1.1
- resolution: "babel-plugin-istanbul@npm:6.1.1"
- dependencies:
- "@babel/helper-plugin-utils": ^7.0.0
- "@istanbuljs/load-nyc-config": ^1.0.0
- "@istanbuljs/schema": ^0.1.2
- istanbul-lib-instrument: ^5.0.4
- test-exclude: ^6.0.0
- checksum: cb4fd95738219f232f0aece1116628cccff16db891713c4ccb501cddbbf9272951a5df81f2f2658dfdf4b3e7b236a9d5cbcf04d5d8c07dd5077297339598061a
- languageName: node
- linkType: hard
-
"babel-plugin-polyfill-corejs2@npm:^0.3.3":
version: 0.3.3
resolution: "babel-plugin-polyfill-corejs2@npm:0.3.3"
@@ -4184,22 +3936,6 @@ __metadata:
languageName: node
linkType: hard
-"babel-plugin-transform-react-remove-prop-types@npm:^0.4.18":
- version: 0.4.18
- resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.18"
- checksum: 9d65bc1cf20a3a37c0a6c9cf1f741f553eb26918c3a4a088def22ac3a670fde42c87fcb3cee870f70f868dfb9c8bb0fd33d58b0624636dc37396e0f52e5c0ebb
- languageName: node
- linkType: hard
-
-"babel-plugin-transform-typescript-metadata@npm:^0.3.2":
- version: 0.3.2
- resolution: "babel-plugin-transform-typescript-metadata@npm:0.3.2"
- dependencies:
- "@babel/helper-plugin-utils": ^7.0.0
- checksum: 15aa2a05c9ec2817155cc15746e55e0e06dd57762e7fc1eea168ce9a65fd89372174ecc7506434b6abde367a264c5953f27468a0c3dcab2fb4a14bec1c719536
- languageName: node
- linkType: hard
-
"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
@@ -4332,13 +4068,6 @@ __metadata:
languageName: node
linkType: hard
-"bottleneck@npm:^1.12.0":
- version: 1.16.0
- resolution: "bottleneck@npm:1.16.0"
- checksum: 2dd5f7b6c27dfd88aef38015a34c694ff0610364c8d5fa6ee51e7eecde2bfdf8737e432200915e347ce5e501fdb59cfc4d9b81ae99c84b9522f9c7fd5034d298
- languageName: node
- linkType: hard
-
"brace-expansion@npm:^1.1.7":
version: 1.1.11
resolution: "brace-expansion@npm:1.1.11"
@@ -4995,13 +4724,6 @@ __metadata:
languageName: node
linkType: hard
-"commander@npm:^4.0.1":
- version: 4.1.1
- resolution: "commander@npm:4.1.1"
- checksum: d7b9913ff92cae20cb577a4ac6fcc121bd6223319e54a40f51a14740a681ad5c574fd29a57da478a5f234a6fa6c52cbf0b7c641353e03c648b1ae85ba670b977
- languageName: node
- linkType: hard
-
"commander@npm:^5.1.0":
version: 5.1.0
resolution: "commander@npm:5.1.0"
@@ -5229,7 +4951,7 @@ __metadata:
languageName: node
linkType: hard
-"core-js@npm:^3.0.0, core-js@npm:^3.26.0, core-js@npm:^3.30.2":
+"core-js@npm:^3.0.0":
version: 3.30.2
resolution: "core-js@npm:3.30.2"
checksum: 73d47e2b9d9f502800973982d08e995bbf04832e20b04e04be31dd7607247158271315e9328788a2408190e291c7ffbefad141167b1e57dea9f983e1e723541e
@@ -5668,7 +5390,7 @@ __metadata:
languageName: node
linkType: hard
-"decode-uri-component@npm:^0.2.0, decode-uri-component@npm:^0.2.2":
+"decode-uri-component@npm:^0.2.0":
version: 0.2.2
resolution: "decode-uri-component@npm:0.2.2"
checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139
@@ -6105,7 +5827,7 @@ __metadata:
languageName: node
linkType: hard
-"encoding@npm:^0.1.12, encoding@npm:^0.1.13, encoding@npm:~0.1.12":
+"encoding@npm:^0.1.12, encoding@npm:^0.1.13":
version: 0.1.13
resolution: "encoding@npm:0.1.13"
dependencies:
@@ -6235,7 +5957,7 @@ __metadata:
languageName: node
linkType: hard
-"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.4.3, es-abstract@npm:^1.5.1":
+"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.4.3":
version: 1.21.1
resolution: "es-abstract@npm:1.21.1"
dependencies:
@@ -6410,7 +6132,7 @@ __metadata:
languageName: node
linkType: hard
-"escape-string-regexp@npm:^1.0.5, escape-string-regexp@npm:~1.0.5":
+"escape-string-regexp@npm:^1.0.5":
version: 1.0.5
resolution: "escape-string-regexp@npm:1.0.5"
checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410
@@ -6637,7 +6359,7 @@ __metadata:
languageName: node
linkType: hard
-"eslint-visitor-keys@npm:^2.0.0, eslint-visitor-keys@npm:^2.1.0":
+"eslint-visitor-keys@npm:^2.0.0":
version: 2.1.0
resolution: "eslint-visitor-keys@npm:2.1.0"
checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d
@@ -6974,7 +6696,7 @@ __metadata:
languageName: node
linkType: hard
-"extend@npm:~3.0.0, extend@npm:~3.0.2":
+"extend@npm:~3.0.2":
version: 3.0.2
resolution: "extend@npm:3.0.2"
checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515
@@ -7199,13 +6921,6 @@ __metadata:
languageName: node
linkType: hard
-"filter-obj@npm:^1.1.0":
- version: 1.1.0
- resolution: "filter-obj@npm:1.1.0"
- checksum: cf2104a7c45ff48e7f505b78a3991c8f7f30f28bd8106ef582721f321f1c6277f7751aacd5d83026cb079d9d5091082f588d14a72e7c5d720ece79118fa61e10
- languageName: node
- linkType: hard
-
"finalhandler@npm:1.1.0":
version: 1.1.0
resolution: "finalhandler@npm:1.1.0"
@@ -7236,18 +6951,7 @@ __metadata:
languageName: node
linkType: hard
-"find-cache-dir@npm:^2.0.0":
- version: 2.1.0
- resolution: "find-cache-dir@npm:2.1.0"
- dependencies:
- commondir: ^1.0.1
- make-dir: ^2.0.0
- pkg-dir: ^3.0.0
- checksum: 60ad475a6da9f257df4e81900f78986ab367d4f65d33cf802c5b91e969c28a8762f098693d7a571b6e4dd4c15166c2da32ae2d18b6766a18e2071079448fdce4
- languageName: node
- linkType: hard
-
-"find-cache-dir@npm:^3.2.0, find-cache-dir@npm:^3.3.2":
+"find-cache-dir@npm:^3.2.0":
version: 3.3.2
resolution: "find-cache-dir@npm:3.3.2"
dependencies:
@@ -7322,7 +7026,16 @@ __metadata:
languageName: node
linkType: hard
-"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0":
+"flip-toolkit@npm:^7.1.0":
+ version: 7.1.0
+ resolution: "flip-toolkit@npm:7.1.0"
+ dependencies:
+ rematrix: 0.2.2
+ checksum: e6cda6f4e1f1ca54da47cdcb2b28409fa1983696be380e73352fd70d046dc3bfa0c3d0a8213093c492ed350d6dbca4b913813d3703b595f2eacd3ba040c7ee21
+ languageName: node
+ linkType: hard
+
+"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8":
version: 1.15.2
resolution: "follow-redirects@npm:1.15.2"
peerDependenciesMeta:
@@ -7416,17 +7129,6 @@ __metadata:
languageName: node
linkType: hard
-"form-data@npm:^3.0.0":
- version: 3.0.1
- resolution: "form-data@npm:3.0.1"
- dependencies:
- asynckit: ^0.4.0
- combined-stream: ^1.0.8
- mime-types: ^2.1.12
- checksum: b019e8d35c8afc14a2bd8a7a92fa4f525a4726b6d5a9740e8d2623c30e308fbb58dc8469f90415a856698933c8479b01646a9dff33c87cc4e76d72aedbbf860d
- languageName: node
- linkType: hard
-
"form-data@npm:^4.0.0":
version: 4.0.0
resolution: "form-data@npm:4.0.0"
@@ -8104,15 +7806,6 @@ __metadata:
languageName: node
linkType: hard
-"homedir-polyfill@npm:^1.0.1":
- version: 1.0.1
- resolution: "homedir-polyfill@npm:1.0.1"
- dependencies:
- parse-passwd: ^1.0.0
- checksum: 15fb2b5e6a5d6921f4c4b69c10ad186736cd14ffb7a6a7b200a2cc349f64967127aeebf667e56d7b81b0396e0b196944d7f38a8468a09a693c50315c6cb608b2
- languageName: node
- linkType: hard
-
"hosted-git-info@npm:^2.1.4":
version: 2.8.9
resolution: "hosted-git-info@npm:2.8.9"
@@ -9003,16 +8696,6 @@ __metadata:
languageName: node
linkType: hard
-"isomorphic-fetch@npm:^3.0.0":
- version: 3.0.0
- resolution: "isomorphic-fetch@npm:3.0.0"
- dependencies:
- node-fetch: ^2.6.1
- whatwg-fetch: ^3.4.1
- checksum: e5ab79a56ce5af6ddd21265f59312ad9a4bc5a72cebc98b54797b42cb30441d5c5f8d17c5cd84a99e18101c8af6f90c081ecb8d12fd79e332be1778d58486d75
- languageName: node
- linkType: hard
-
"isomorphic-style-loader@npm:^5.3.2":
version: 5.3.2
resolution: "isomorphic-style-loader@npm:5.3.2"
@@ -9062,19 +8745,6 @@ __metadata:
languageName: node
linkType: hard
-"istanbul-lib-instrument@npm:^5.0.4":
- version: 5.2.1
- resolution: "istanbul-lib-instrument@npm:5.2.1"
- dependencies:
- "@babel/core": ^7.12.3
- "@babel/parser": ^7.14.7
- "@istanbuljs/schema": ^0.1.2
- istanbul-lib-coverage: ^3.2.0
- semver: ^6.3.0
- checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272
- languageName: node
- linkType: hard
-
"istanbul-lib-processinfo@npm:^2.0.2":
version: 2.0.3
resolution: "istanbul-lib-processinfo@npm:2.0.3"
@@ -9756,13 +9426,6 @@ __metadata:
languageName: node
linkType: hard
-"lodash.chunk@npm:^4.2.0":
- version: 4.2.0
- resolution: "lodash.chunk@npm:4.2.0"
- checksum: 6286c6d06814fbeda502164015c42ef53a9194e6ebaac52ec2b41e83344aefe7bc3d94fdfec525adcd2c66cefdf05dc333b6a1128e4de739797342315c17cbc7
- languageName: node
- linkType: hard
-
"lodash.debounce@npm:^4.0.6, lodash.debounce@npm:^4.0.8":
version: 4.0.8
resolution: "lodash.debounce@npm:4.0.8"
@@ -9937,26 +9600,16 @@ __metadata:
version: 0.0.0-use.local
resolution: "lunch@workspace:."
dependencies:
- "@babel/core": ^7.20.12
- "@babel/eslint-parser": ^7.19.1
- "@babel/node": ^7.20.7
- "@babel/plugin-proposal-class-properties": ^7.18.6
- "@babel/plugin-proposal-decorators": ^7.21.0
- "@babel/plugin-syntax-dynamic-import": ^7.8.3
- "@babel/plugin-transform-modules-commonjs": ^7.20.11
- "@babel/plugin-transform-react-constant-elements": ^7.20.2
- "@babel/plugin-transform-react-inline-elements": ^7.18.6
- "@babel/preset-env": ^7.20.2
- "@babel/preset-react": ^7.18.6
- "@babel/preset-typescript": ^7.21.0
- "@babel/register": ^7.18.9
"@googlemaps/js-api-loader": ^1.15.1
"@honeybadger-io/js": ^5.0.0
+ "@istanbuljs/nyc-config-typescript": ^1.0.2
"@jedmao/redux-mock-store": ^3.0.5
"@pmmmwh/react-refresh-webpack-plugin": ^0.5.10
"@popperjs/core": ^2.11.7
"@redux-devtools/extension": ^3.2.5
"@reduxjs/toolkit": ^1.9.2
+ "@sendgrid/helpers": ^7.7.0
+ "@sendgrid/mail": ^7.7.0
"@testing-library/dom": ^9.2.0
"@testing-library/react": ^14.0.0
"@testing-library/user-event": ^14.4.3
@@ -9973,15 +9626,20 @@ __metadata:
"@types/google-map-react": ^2.1.7
"@types/google.analytics": ^0.0.42
"@types/google.maps": ^3.52.1
+ "@types/lodash.get": ^4.4.7
"@types/method-override": ^0.0.32
"@types/mocha": ^10.0.1
"@types/morgan": ^1.9.4
- "@types/node-fetch": ^2.6.2
+ "@types/node": ^20.2.5
"@types/passport": ^1.0.11
"@types/passport-google-oauth20": ^2.0.11
"@types/passport-local": ^1.0.35
"@types/proxyquire": ^1.3.28
+ "@types/react-autosuggest": ^10.1.6
"@types/react-dom": ^18.2.4
+ "@types/react-geosuggest": ^2.7.13
+ "@types/react-scroll": ^1.8.7
+ "@types/serialize-javascript": ^5.0.2
"@types/sinon": ^10.0.15
"@types/supertest": ^2.0.12
"@types/uuid": ^9.0.0
@@ -9991,10 +9649,6 @@ __metadata:
"@typescript-eslint/parser": ^5.59.1
assets-webpack-plugin: ^7.1.1
autoprefixer: ^9.1.5
- babel-loader: ^9.1.0
- babel-plugin-istanbul: ^6.1.1
- babel-plugin-transform-react-remove-prop-types: ^0.4.18
- babel-plugin-transform-typescript-metadata: ^0.3.2
bcrypt: ^5.1.0
body-parser: ^1.18.3
bootstrap: ^5.2.3
@@ -10008,7 +9662,6 @@ __metadata:
connect-flash: ^0.1.1
connect-session-sequelize: ^7.1.5
cookie-parser: ^1.4.6
- core-js: ^3.30.2
cors: ^2.8.3
cross-env: ^5.0.1
css-loader: ^6.7.3
@@ -10039,6 +9692,7 @@ __metadata:
fbjs: ^3.0.4
fetch-mock: ^9.11.0
file-loader: ^6.2.0
+ flip-toolkit: ^7.1.0
fork-ts-checker-webpack-plugin: ^7.3.0
git-repository: ^0.1.4
glob: ^7.1.3
@@ -10048,18 +9702,17 @@ __metadata:
husky: ^8.0.3
identity-obj-proxy: ^3.0.0
immutability-helper: ^3.1.1
- isomorphic-fetch: ^3.0.0
isomorphic-style-loader: ^5.3.2
jsdom: ^22.0.0
json-loader: ^0.5.7
jsonwebtoken: ^9.0.0
lint-staged: ^13.2.2
+ lodash.get: ^4.4.2
method-override: ^3.0.0
mkdirp: ^2.1.3
mocha: ^10.2.0
mocha-junit-reporter: ^2.2.0
morgan: ^1.10.0
- node-fetch: ^2.6.9
normalizr: ^3.2.2
npm-run-all: ^4.1.5
null-loader: ^4.0.1
@@ -10075,7 +9728,7 @@ __metadata:
pretty-error: ^3.0.4
prop-types: ^15.8.1
proxyquire: ^1.7.11
- query-string: ^7.1.3
+ qs: ^6.11.2
raw-loader: ^0.5.1
react: ^18.2.0
react-autosuggest: ^10.0.2
@@ -10101,14 +9754,13 @@ __metadata:
rotating-file-stream: ^3.1.0
sass: ^1.58.0
sass-loader: ^13.2.0
- sendgrid: ^5.2.3
sequelize: ^6.29.0
sequelize-cli: ^6.6.0
sequelize-mock: ^0.7.0
sequelize-typescript: ^2.1.5
serialize-javascript: ^6.0.1
sinon: ^15.1.0
- source-map-support: ^0.5.9
+ source-map-support: ^0.5.21
sqlite3: ^5.1.5
style-loader: ^0.13.2
stylelint: ^15.6.2
@@ -10118,7 +9770,7 @@ __metadata:
svg-url-loader: ^8.0.0
ts-loader: ^9.4.2
ts-node: ^10.9.1
- typescript: ^5.0.4
+ typescript: ^5.1.3
universal-router: ^8.1.0
url-loader: ^4.1.1
uuid: ^9.0.0
@@ -10129,7 +9781,6 @@ __metadata:
webpack-dev-middleware: ^6.0.1
webpack-hot-middleware: ^2.25.3
webpack-node-externals: ^3.0.0
- whatwg-fetch: ^3.0.0
workbox-webpack-plugin: ^6.5.4
languageName: unknown
linkType: soft
@@ -10152,28 +9803,6 @@ __metadata:
languageName: node
linkType: hard
-"mailparser@npm:^0.6.1":
- version: 0.6.2
- resolution: "mailparser@npm:0.6.2"
- dependencies:
- encoding: ^0.1.12
- mime: ^1.3.4
- mimelib: ^0.3.0
- uue: ^3.1.0
- checksum: 47f540b286ac03ad2d5f5fe83fe45d6fe1cf1b6dc4c409ef9a55a7aa889e42ae311b6eae605f1e1c390e3a4c26a0a15c8499c9eea17de3693e616ced2db058a3
- languageName: node
- linkType: hard
-
-"make-dir@npm:^2.0.0, make-dir@npm:^2.1.0":
- version: 2.1.0
- resolution: "make-dir@npm:2.1.0"
- dependencies:
- pify: ^4.0.1
- semver: ^5.6.0
- checksum: 043548886bfaf1820323c6a2997e6d2fa51ccc2586ac14e6f14634f7458b4db2daf15f8c310e2a0abd3e0cddc64df1890d8fc7263033602c47bb12cbfcf86aab
- languageName: node
- linkType: hard
-
"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2, make-dir@npm:^3.1.0":
version: 3.1.0
resolution: "make-dir@npm:3.1.0"
@@ -10431,7 +10060,7 @@ __metadata:
languageName: node
linkType: hard
-"mime@npm:1.6.0, mime@npm:^1.3.4":
+"mime@npm:1.6.0":
version: 1.6.0
resolution: "mime@npm:1.6.0"
bin:
@@ -10449,16 +10078,6 @@ __metadata:
languageName: node
linkType: hard
-"mimelib@npm:^0.3.0":
- version: 0.3.1
- resolution: "mimelib@npm:0.3.1"
- dependencies:
- addressparser: ~1.0.1
- encoding: ~0.1.12
- checksum: c1d36a8f981d9059cc05c10085ad41ce5415c0444329c5831d1e8d195cd6f4b93611931479848bbfdd866bc64fb60685a6aa7c67cd82ab891efb601f127eb184
- languageName: node
- linkType: hard
-
"mimic-fn@npm:^2.1.0":
version: 2.1.0
resolution: "mimic-fn@npm:2.1.0"
@@ -10853,16 +10472,6 @@ __metadata:
languageName: node
linkType: hard
-"node-environment-flags@npm:^1.0.5":
- version: 1.0.6
- resolution: "node-environment-flags@npm:1.0.6"
- dependencies:
- object.getownpropertydescriptors: ^2.0.3
- semver: ^5.7.0
- checksum: 268139ed0f7fabdca346dcb26931300ec7a1dc54a58085a849e5c78a82b94967f55df40177a69d4e819da278d98686d5c4fd49ab0d7bcff16fda25b6fffc4ca3
- languageName: node
- linkType: hard
-
"node-fetch@npm:2.6.7":
version: 2.6.7
resolution: "node-fetch@npm:2.6.7"
@@ -10877,7 +10486,7 @@ __metadata:
languageName: node
linkType: hard
-"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.9":
+"node-fetch@npm:^2.6.7":
version: 2.6.9
resolution: "node-fetch@npm:2.6.9"
dependencies:
@@ -11228,16 +10837,6 @@ __metadata:
languageName: node
linkType: hard
-"object.getownpropertydescriptors@npm:^2.0.3":
- version: 2.0.3
- resolution: "object.getownpropertydescriptors@npm:2.0.3"
- dependencies:
- define-properties: ^1.1.2
- es-abstract: ^1.5.1
- checksum: bf79fae8ff49be1c7e3822b4e649993775fb3abd9c6e83a46a1c91356c7b048f699166916f85b74ef44a61e18900a448154d3b84cab8436095aeaf59c376d345
- languageName: node
- linkType: hard
-
"object.hasown@npm:^1.1.2":
version: 1.1.2
resolution: "object.hasown@npm:1.1.2"
@@ -11494,13 +11093,6 @@ __metadata:
languageName: node
linkType: hard
-"parse-passwd@npm:^1.0.0":
- version: 1.0.0
- resolution: "parse-passwd@npm:1.0.0"
- checksum: 4e55e0231d58f828a41d0f1da2bf2ff7bcef8f4cb6146e69d16ce499190de58b06199e6bd9b17fbf0d4d8aef9052099cdf8c4f13a6294b1a522e8e958073066e
- languageName: node
- linkType: hard
-
"parse5@npm:^7.0.0, parse5@npm:^7.1.2":
version: 7.1.2
resolution: "parse5@npm:7.1.2"
@@ -11821,13 +11413,6 @@ __metadata:
languageName: node
linkType: hard
-"pify@npm:^4.0.1":
- version: 4.0.1
- resolution: "pify@npm:4.0.1"
- checksum: 9c4e34278cb09987685fa5ef81499c82546c033713518f6441778fbec623fc708777fe8ac633097c72d88470d5963094076c7305cafc7ad340aae27cfacd856b
- languageName: node
- linkType: hard
-
"pinkie-promise@npm:^2.0.0":
version: 2.0.1
resolution: "pinkie-promise@npm:2.0.1"
@@ -11844,22 +11429,6 @@ __metadata:
languageName: node
linkType: hard
-"pirates@npm:^4.0.5":
- version: 4.0.5
- resolution: "pirates@npm:4.0.5"
- checksum: c9994e61b85260bec6c4fc0307016340d9b0c4f4b6550a957afaaff0c9b1ad58fbbea5cfcf083860a25cb27a375442e2b0edf52e2e1e40e69934e08dcc52d227
- languageName: node
- linkType: hard
-
-"pkg-dir@npm:^3.0.0":
- version: 3.0.0
- resolution: "pkg-dir@npm:3.0.0"
- dependencies:
- find-up: ^3.0.0
- checksum: 70c9476ffefc77552cc6b1880176b71ad70bfac4f367604b2b04efd19337309a4eec985e94823271c7c0e83946fa5aeb18cd360d15d10a5d7533e19344bfa808
- languageName: node
- linkType: hard
-
"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0":
version: 4.2.0
resolution: "pkg-dir@npm:4.2.0"
@@ -12289,6 +11858,15 @@ __metadata:
languageName: node
linkType: hard
+"qs@npm:^6.11.2":
+ version: 6.11.2
+ resolution: "qs@npm:6.11.2"
+ dependencies:
+ side-channel: ^1.0.4
+ checksum: e812f3c590b2262548647d62f1637b6989cc56656dc960b893fe2098d96e1bd633f36576f4cd7564dfbff9db42e17775884db96d846bebe4f37420d073ecdc0b
+ languageName: node
+ linkType: hard
+
"qs@npm:~6.5.2":
version: 6.5.3
resolution: "qs@npm:6.5.3"
@@ -12296,18 +11874,6 @@ __metadata:
languageName: node
linkType: hard
-"query-string@npm:^7.1.3":
- version: 7.1.3
- resolution: "query-string@npm:7.1.3"
- dependencies:
- decode-uri-component: ^0.2.2
- filter-obj: ^1.1.0
- split-on-first: ^1.0.0
- strict-uri-encode: ^2.0.0
- checksum: 91af02dcd9cc9227a052841d5c2eecb80a0d6489d05625df506a097ef1c59037cfb5e907f39b84643cbfd535c955abec3e553d0130a7b510120c37d06e0f4346
- languageName: node
- linkType: hard
-
"querystring@npm:^0.2.0":
version: 0.2.1
resolution: "querystring@npm:0.2.1"
@@ -13362,7 +12928,7 @@ __metadata:
languageName: node
linkType: hard
-"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.0":
+"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.6.0":
version: 5.7.1
resolution: "semver@npm:5.7.1"
bin:
@@ -13433,28 +12999,6 @@ __metadata:
languageName: node
linkType: hard
-"sendgrid-rest@npm:^2.3.0":
- version: 2.4.0
- resolution: "sendgrid-rest@npm:2.4.0"
- checksum: 0716e2c7ec1d508369c4603d76b691b85c7ca323334cafb1440896f5d342e578ab42e0ec89f01f6cdbb35e10d21c37b2104bb23c38faa9efdb7939a9306127f3
- languageName: node
- linkType: hard
-
-"sendgrid@npm:^5.2.3":
- version: 5.2.3
- resolution: "sendgrid@npm:5.2.3"
- dependencies:
- async.ensureasync: ^0.5.2
- async.queue: ^0.5.2
- bottleneck: ^1.12.0
- debug: ^2.2.0
- lodash.chunk: ^4.2.0
- mailparser: ^0.6.1
- sendgrid-rest: ^2.3.0
- checksum: e366ad213632701d9be5a63c98ae3c2c971c29ab9fd2052e782b947367f628c8478c48e5ac10e6e226c5de5b3146d2bb0217f704865f84c0093e0e9d31a1e4e3
- languageName: node
- linkType: hard
-
"sequelize-cli@npm:^6.6.0":
version: 6.6.0
resolution: "sequelize-cli@npm:6.6.0"
@@ -13922,7 +13466,7 @@ __metadata:
languageName: node
linkType: hard
-"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.9, source-map-support@npm:~0.5.20":
+"source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.20":
version: 0.5.21
resolution: "source-map-support@npm:0.5.21"
dependencies:
@@ -14010,13 +13554,6 @@ __metadata:
languageName: node
linkType: hard
-"split-on-first@npm:^1.0.0":
- version: 1.1.0
- resolution: "split-on-first@npm:1.1.0"
- checksum: 16ff85b54ddcf17f9147210a4022529b343edbcbea4ce977c8f30e38408b8d6e0f25f92cd35b86a524d4797f455e29ab89eb8db787f3c10708e0b47ebf528d30
- languageName: node
- linkType: hard
-
"split2@npm:^3.1.1":
version: 3.2.2
resolution: "split2@npm:3.2.2"
@@ -14159,13 +13696,6 @@ __metadata:
languageName: node
linkType: hard
-"strict-uri-encode@npm:^2.0.0":
- version: 2.0.0
- resolution: "strict-uri-encode@npm:2.0.0"
- checksum: eaac4cf978b6fbd480f1092cab8b233c9b949bcabfc9b598dd79a758f7243c28765ef7639c876fa72940dac687181b35486ea01ff7df3e65ce3848c64822c581
- languageName: node
- linkType: hard
-
"string-argv@npm:^0.3.1":
version: 0.3.1
resolution: "string-argv@npm:0.3.1"
@@ -15130,23 +14660,23 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:^5.0.4":
- version: 5.0.4
- resolution: "typescript@npm:5.0.4"
+"typescript@npm:^5.1.3":
+ version: 5.1.3
+ resolution: "typescript@npm:5.1.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: 82b94da3f4604a8946da585f7d6c3025fff8410779e5bde2855ab130d05e4fd08938b9e593b6ebed165bda6ad9292b230984f10952cf82f0a0ca07bbeaa08172
+ checksum: d9d51862d98efa46534f2800a1071a613751b1585dc78884807d0c179bcd93d6e9d4012a508e276742f5f33c480adefc52ffcafaf9e0e00ab641a14cde9a31c7
languageName: node
linkType: hard
-"typescript@patch:typescript@^5.0.4#~builtin":
- version: 5.0.4
- resolution: "typescript@patch:typescript@npm%3A5.0.4#~builtin::version=5.0.4&hash=b5f058"
+"typescript@patch:typescript@^5.1.3#~builtin":
+ version: 5.1.3
+ resolution: "typescript@patch:typescript@npm%3A5.1.3#~builtin::version=5.1.3&hash=77c9e2"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
- checksum: d26b6ba97b6d163c55dbdffd9bbb4c211667ebebc743accfeb2c8c0154aace7afd097b51165a72a5bad2cf65a4612259344ff60f8e642362aa1695c760d303ac
+ checksum: 32a25b2e128a4616f999d4ee502aabb1525d5647bc8955e6edf05d7fbc53af8aa98252e2f6ba80bcedfc0260c982b885f3c09cfac8bb65d2924f3133ad1e1e62
languageName: node
linkType: hard
@@ -15431,16 +14961,6 @@ __metadata:
languageName: node
linkType: hard
-"uue@npm:^3.1.0":
- version: 3.1.1
- resolution: "uue@npm:3.1.1"
- dependencies:
- escape-string-regexp: ~1.0.5
- extend: ~3.0.0
- checksum: 6535b3cd3d71ae9a37f42b7c88c35f12f30de159db3b81ed9dd3fa9e9db7a8bc0d718418fb0bf4f68f5dccefc18d5854edc30e696d1350ff27c29f6f655418fe
- languageName: node
- linkType: hard
-
"uuid@npm:^8.3.2":
version: 8.3.2
resolution: "uuid@npm:8.3.2"
@@ -15473,15 +14993,6 @@ __metadata:
languageName: node
linkType: hard
-"v8flags@npm:^3.1.1":
- version: 3.1.1
- resolution: "v8flags@npm:3.1.1"
- dependencies:
- homedir-polyfill: ^1.0.1
- checksum: 1c61ed3fe5970ebc9ea965d48a3bae9fa9ae0e3bf86d553060cc562f9c0ed70ce4c1c0f0f91d65bcf5280d27420da9621507dd2c6f9fcb63d79c2e7aa2f580a1
- languageName: node
- linkType: hard
-
"validate-npm-package-license@npm:^3.0.1":
version: 3.0.3
resolution: "validate-npm-package-license@npm:3.0.3"
@@ -15741,13 +15252,6 @@ __metadata:
languageName: node
linkType: hard
-"whatwg-fetch@npm:^3.0.0, whatwg-fetch@npm:^3.4.1":
- version: 3.6.2
- resolution: "whatwg-fetch@npm:3.6.2"
- checksum: ee976b7249e7791edb0d0a62cd806b29006ad7ec3a3d89145921ad8c00a3a67e4be8f3fb3ec6bc7b58498724fd568d11aeeeea1f7827e7e1e5eae6c8a275afed
- languageName: node
- linkType: hard
-
"whatwg-mimetype@npm:^3.0.0":
version: 3.0.0
resolution: "whatwg-mimetype@npm:3.0.0"