Skip to content

Commit

Permalink
Merge branch 'release/2.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
DropsOfSerenity committed May 23, 2022
2 parents 0cadda0 + 0d9bd21 commit 6ee904e
Show file tree
Hide file tree
Showing 77 changed files with 813 additions and 857 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
}
],
"camelcase": "off",
"no-unsafe-optional-chaining": "off",
"jsx-a11y/click-events-have-key-events": "off",
"arrow-body-style": "off",
"react/no-unescaped-entities": "off",
Expand Down
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

This boilerplate has a [wiki](https://github.com/Shift3/boilerplate-client-react/wiki) which explains the project and its implementation in much greater detail than the code comments.

> Note that this repository used to be compatible with our NestJS
> backend, however we have switched to using django as our primary
> backend. If you are looking for the NestJS compatible version, we
> still maintain it in the `nestjs-compatibility` branch
- [Boilerplate Client React](#boilerplate-client-react)
- [Staging URL](#staging-url)
- [Quick Start](#quick-start)
Expand Down Expand Up @@ -51,7 +56,7 @@ To start the project, make sure yarn is installed on your local machine. If you

Open [http://localhost:4200](http://localhost:4200) to view the project in the browser.

The page will reload if you make edits.
The page will reload if you make edits.
You will also see any lint errors in the console.

### Running unit tests
Expand All @@ -72,7 +77,6 @@ It correctly bundles React in production mode and optimizes the build for the be
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!


## Learn More

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
Expand Down Expand Up @@ -141,27 +145,27 @@ The boilerplate can either be deployed manually, or automatically via CircleCI.

After your CircleCI project is set up, the only thing you need to do to get deployments working for production and staging is to set 4 environment variables in the CircleCI project settings.

* `STAGING_S3_BUCKET_NAME`
- This is the full S3 bucket name to deploy to.
- `my-app-bucket.shift3sandbox.com`
* `STAGING_AWS_ACCESS_KEY_ID`
- `STAGING_S3_BUCKET_NAME`
- This is the full S3 bucket name to deploy to.
- `my-app-bucket.shift3sandbox.com`
- `STAGING_AWS_ACCESS_KEY_ID`
- The AWS access key ID used to authenticate with AWS.
- `AKIAIOSFODNN7EXAMPLE`
* `STAGING_AWS_SECRET_ACCESS_KEY`
- The AWS secret key used to authenticate with AWS.
- `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`
* `STAGING_AWS_DEFAULT_REGION`
- The default region your infrastructure is deployed to.
- `us-west-2`
- `STAGING_AWS_SECRET_ACCESS_KEY`
- The AWS secret key used to authenticate with AWS.
- `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`
- `STAGING_AWS_DEFAULT_REGION`
- The default region your infrastructure is deployed to.
- `us-west-2`

Once these are set up, your project will be **automatically deployed** whenever new commits to the `development` branch are pushed to Github.

Production deploys from the `main` branch use the same set of environment variables, just with `PRODUCTION` instead of `STAGING` int the names. The list of those variables follow:

* `PRODUCTION_S3_BUCKET_NAME`
* `PRODUCTION_AWS_ACCESS_KEY_ID`
* `PRODUCTION_AWS_SECRET_ACCESS_KEY`
* `PRODUCTION_AWS_DEFAULT_REGION`
- `PRODUCTION_S3_BUCKET_NAME`
- `PRODUCTION_AWS_ACCESS_KEY_ID`
- `PRODUCTION_AWS_SECRET_ACCESS_KEY`
- `PRODUCTION_AWS_DEFAULT_REGION`

#### Manual Deployments

Expand Down Expand Up @@ -228,11 +232,10 @@ Currently the issue templates may have some things you don't want or need in you

If this project is being cloned to start a new project, there are a few things that need to be updated to make it work. The project name will need to be updated in the `README.md`, `package.json`. The README also refers to the boilerplate, both in the text and in the CircleCI badges.

The project `environment` files will need to be updated with the path to the APIs. The development `environment.dev.ts` and `environment.prod.ts` files assumes a local development server of `http://localhost:3000`, which might need to be updated.
The project `environment` files will need to be updated with the path to the APIs. The development `environment.dev.ts` and `environment.prod.ts` files assumes a local development server of `http://localhost:3000`, which might need to be updated.

After provisioning and before deploying, the `deploy:staging` and `deploy:production` script in `package.json` needs to be updated.


### Prettier

This project uses Prettier to enforce code style. It is highly opinionated by design with relatively scant options for customization. The thought process behind it is to ignore personal styling preferences and instead embrace consistency. There are .prettierrc and .prettierignore configuration files to adjust some options. Prettier is also wired up to a pre-commit hook. This DOES slightly slow down git, as it runs the hook on staged files every time git commit is executed.
Expand Down Expand Up @@ -269,7 +272,6 @@ The project includes [webpack-bundle-analyzer](https://github.com/webpack-contri
We are using [React Hook Form](https://react-hook-form.com/) to extend our forms and make easy to work with validation.
for more information see: https://react-hook-form.com/ts for typescript support.


### Yup

Yup is a JavaScript object schema validator. With Yup, a developer can define a schema (or structure) which specifies the expected data type of each property in an object. The schema can also specify additional validations such as if a property is optional/required, the min/max length of string properties, the min/max value of numeric properties, a regular expressions to match, etc.
Expand Down Expand Up @@ -339,7 +341,7 @@ const PersonForm = () => {
});

return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<form onSubmit={handleSubmit(d => console.log(d))}>
<input {...register('name')} />
<input type='number' {...register('age')} />
<input type='submit' />
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "client",
"version": "1.2.1",
"version": "2.0.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.1",
Expand All @@ -14,7 +14,6 @@
"dotenv": "^16.0.0",
"history": "^5.3.0",
"http-status-codes": "^2.1.4",
"moment": "^2.29.3",
"react": "^18.1.0",
"react-bootstrap": "^2.3.1",
"react-dom": "^18.1.0",
Expand Down Expand Up @@ -65,7 +64,6 @@
"@testing-library/react": "^13.1.1",
"@testing-library/react-hooks": "^8.0.0",
"@testing-library/user-event": "^14.1.1",
"@types/faker": "^6.6.9",
"@types/history": "^5.0.0",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.30",
Expand Down
32 changes: 16 additions & 16 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="React Boilerplate" content="BWTC React Boilerplate App" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React Boilerplate</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<style>
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="React Boilerplate" content="BWTC React Boilerplate App" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React Boilerplate</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<style>
body,
html {
margin: 0;
Expand Down Expand Up @@ -67,6 +67,6 @@
<span style="padding: 20px"> LOADING... </span>
</div>
</div>
</div>
</body>
</div>
</body>
</html>
5 changes: 3 additions & 2 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ErrorBoundary } from '@sentry/react';
import { Layout } from 'common/components/Layout';
import { NotFoundView } from 'common/components/NotFound';
import { NotFoundView } from 'common/components/NotFoundView';
import { NotificationContainer } from 'common/components/Notification';
import { environment } from 'environment';
import { AgentRoutes } from 'features/agent-dashboard';
Expand All @@ -15,6 +15,7 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import styled, { css, ThemeProvider } from 'styled-components';
import AppTheme from 'utils/styleValues';
import { GlobalStyle } from '../GlobalStyle';
import { Role } from 'common/models';

const StagingBanner = styled(Alert).attrs({
variant: 'warning',
Expand Down Expand Up @@ -89,7 +90,7 @@ export const App: FC = () => (
<Route
path='/users/*'
element={
<RequireAuth allowedRoles={['Admin', 'Super Administrator']}>
<RequireAuth allowedRoles={[ Role.ADMIN ]}>
<UserRoutes />
</RequireAuth>
}
Expand Down
24 changes: 19 additions & 5 deletions src/common/api/agentApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ export type UpdateAgentRequest = Pick<
'id' | 'description' | 'email' | 'name' | 'phoneNumber' | 'thumbnail' | 'address'
>;

export type GetAgentHistory = {
id: string | undefined;
page: number;
pageSize: number;
};

export const agentApi = createApi({
reducerPath: 'agentApi',

Expand All @@ -35,19 +41,26 @@ export const agentApi = createApi({
.setSortParam(sortBy)
.setFilterParam(filters)
.build();
return { url: `/agents?${queryParams}` };
return { url: `/agents/?${queryParams}` };
},
providesTags: ['Agent'],
}),

getAgentById: builder.query<Agent, number | string>({
query: id => ({ url: `/agents/${id}` }),
query: id => ({ url: `/agents/${id}/` }),
providesTags: ['Agent'],
}),

getAgentHistory: builder.query<PaginatedResult<unknown>, GetAgentHistory>({
query: arg => {
const queryParams = new QueryParamsBuilder().setPaginationParams(arg.page, arg.pageSize).build();
return { url: `/agents/${arg.id}/change-history?${queryParams}` };
},
}),

createAgent: builder.mutation<Agent, CreateAgentRequest>({
query: payload => ({
url: '/agents',
url: '/agents/',
method: 'POST',
body: payload,
}),
Expand All @@ -56,7 +69,7 @@ export const agentApi = createApi({

updateAgent: builder.mutation<Agent, UpdateAgentRequest>({
query: ({ id, ...agentUpdate }) => ({
url: `/agents/${id}`,
url: `/agents/${id}/`,
method: 'PUT',
body: agentUpdate,
}),
Expand All @@ -65,7 +78,7 @@ export const agentApi = createApi({

deleteAgent: builder.mutation<void, number>({
query: agentId => ({
url: `/agents/${agentId}`,
url: `/agents/${agentId}/`,
method: 'DELETE',
}),
invalidatesTags: ['Agent'],
Expand All @@ -76,6 +89,7 @@ export const agentApi = createApi({
export const {
useGetAgentsQuery,
useGetAgentByIdQuery,
useGetAgentHistoryQuery,
useCreateAgentMutation,
useUpdateAgentMutation,
useDeleteAgentMutation,
Expand Down
6 changes: 3 additions & 3 deletions src/common/api/authApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ export const authApi = createApi({
endpoints: (builder) => ({
login: builder.mutation<Session, LoginRequest>({
query: (credentials) => ({
url: '/auth/login',
url: '/token/login/',
method: 'POST',
body: credentials,
}),
}),

logout: builder.mutation<void, void>({
query: () => ({
url: '/auth/logout',
method: 'GET',
url: '/token/logout/',
method: 'POST',
}),
}),
}),
Expand Down
2 changes: 1 addition & 1 deletion src/common/api/customBaseQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const baseQuery = fetchBaseQuery({
const { token } = (getState() as RootState).auth;

if (token) {
headers.set('authorization', `Bearer ${token}`);
headers.set('authorization', `Token ${token}`);
}

return headers;
Expand Down
21 changes: 17 additions & 4 deletions src/common/api/handleApiError.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query';
import { ErrorResponse } from 'common/models';
import { isObject, isStringArray } from 'common/error/utilities';
import * as notificationService from 'common/services/notification';
import { StatusCodes } from 'http-status-codes';

export const handleApiError = <T>(error: FetchBaseQueryError): void => {
let message: string;
export function isFetchBaseQueryError(error: unknown): error is FetchBaseQueryError {
return typeof error === 'object' && error != null && 'status' in error;
}

export const handleApiError = (error: FetchBaseQueryError): void => {
let message = '';

switch (error.status) {
/* eslint-disable */
// An HTTP error response was received from the server.
// Each HTTP error can be handled separately if different logic is needed.
case StatusCodes.BAD_REQUEST:

case StatusCodes.UNAUTHORIZED:

case StatusCodes.FORBIDDEN:

case StatusCodes.INTERNAL_SERVER_ERROR:
message = (error.data as ErrorResponse<T>).message;
/* eslint-enable */
if (isObject(error.data)) {
if (isStringArray(error.data.nonFieldErrors)) {
message = error.data.nonFieldErrors.join(' ');
}
}
break;

// An error occured during the execution of the fetch function.
Expand Down
Loading

0 comments on commit 6ee904e

Please sign in to comment.