Skip to content

Commit

Permalink
Merge pull request #51 from manh-t/release/0.2.0
Browse files Browse the repository at this point in the history
Release - 0.2.0
  • Loading branch information
manh-t authored Jul 19, 2023
2 parents ef0bcc6 + af06671 commit ef6fed1
Show file tree
Hide file tree
Showing 46 changed files with 1,864 additions and 606 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": [["@babel/plugin-proposal-private-property-in-object", { "loose": true }]]
}
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module.exports = {
rules: {
// Note: you must disable the base rule as it can report incorrect errors
'no-shadow': 'off',
'no-use-before-define': 'off',
'@typescript-eslint/no-shadow': 'off',
'@typescript-eslint/no-use-before-define': ['error'],
},
};
1,106 changes: 550 additions & 556 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
{
"name": "manh-react-survey",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"dependencies": {
"@reduxjs/toolkit": "1.9.5",
"@types/lodash": "4.14.195",
"axios": "1.4.0",
"classnames": "2.3.2",
"lodash": "4.17.21",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "8.1.0",
"react-router-dom": "6.3.0",
"react-scripts": "5.0.1",
"sass": "1.49.11"
Expand Down Expand Up @@ -41,7 +45,10 @@
]
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
"@babel/core": "7.22.5",
"@babel/eslint-parser": "7.22.5",
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
"@babel/preset-env": "7.22.5",
"@cypress/browserify-preprocessor": "3.0.2",
"@cypress/code-coverage": "3.10.7",
"@cypress/instrument-cra": "1.4.0",
Expand Down
43 changes: 43 additions & 0 deletions src/adapters/Authentication/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { post } from 'adapters/Base';
import { config } from 'config';

import { signIn } from '.';

jest.mock('adapters/Base');
jest.mock('config');

describe('AuthenticationAdapter', () => {
beforeEach(() => {
(post as jest.Mock).mockImplementation(() => jest.fn());
(config as jest.Mock).mockImplementation(() => ({
clientId: 'client id',
clientSecret: 'client secret',
}));
});

afterEach(() => {
jest.clearAllMocks();
});

describe('signIn', () => {
describe('given an email and a password', () => {
it('calls the post method from the base adapter', () => {
const email = '[email protected]';
const password = 'test';

const expectedPath = 'oauth/token';
const expectedPayload = {
grantType: 'password',
clientId: config().clientId,
clientSecret: config().clientSecret,
email,
password,
};

signIn(email, password);

expect(post).toHaveBeenCalledWith(expectedPath, expectedPayload);
});
});
});
});
11 changes: 11 additions & 0 deletions src/adapters/Authentication/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { post } from 'adapters/Base';
import { config } from 'config';

export const signIn = (email: string, password: string) =>
post('oauth/token', {
clientId: config().clientId,
clientSecret: config().clientSecret,
grantType: 'password',
email: email,
password: password,
});
49 changes: 49 additions & 0 deletions src/adapters/Base/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* eslint-disable camelcase */
import requestManager from 'lib/request/v1/requestManager';

import { get, post } from '.';

jest.mock('lib/request/v1/requestManager', () => jest.fn());

describe('BaseAdapter', () => {
const apiPath = '/sample';
const params = {
testKey: 'test value',
};

afterEach(() => {
jest.clearAllMocks();
});

describe('GET', () => {
describe('given only the api path', () => {
it('calls the GET method from request manager with the path and no params', () => {
get(apiPath);

expect(requestManager).toHaveBeenCalledWith('get', apiPath, {});
});
});

describe('given the api path and url params', () => {
it('calls the get method from request manager with the path and params with snake case keys', () => {
get(apiPath, params);

expect(requestManager).toHaveBeenCalledWith('get', apiPath, {
params: { test_key: params.testKey },
});
});
});
});

describe('POST', () => {
describe('given the path and url params', () => {
it('calls the post method from request manager with the path and data with snake case key', () => {
post(apiPath, params);

expect(requestManager).toHaveBeenCalledWith('post', apiPath, {
data: { test_key: params.testKey },
});
});
});
});
});
19 changes: 19 additions & 0 deletions src/adapters/Base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AxiosRequestConfig } from 'axios';

import { JSONObject, keysToSnakeCase } from 'helpers/json';
import requestManager from 'lib/request/v1/requestManager';

export function get(path: string, params?: JSONObject) {
const requestOptions: AxiosRequestConfig = {};
if (params) {
requestOptions.params = keysToSnakeCase(params);
}

return requestManager('get', path, requestOptions);
}

export const post = (path: string, params: JSONObject) => {
const requestOptions: AxiosRequestConfig = { data: keysToSnakeCase(params) };

return requestManager('post', path, requestOptions);
};
3 changes: 3 additions & 0 deletions src/assets/images/icons/alert.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/components/Alert/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import Alert from '.';

describe('Alert', () => {
const errors = ['Error 1'];
const dataTestId = 'alert';

it('renders an alert and its component', () => {
render(<Alert errors={errors} data-test-id={dataTestId} />);

const alert = screen.getByTestId(dataTestId);

expect(alert).toBeVisible();
expect(alert).toHaveTextContent('Error 1');
});
});
25 changes: 25 additions & 0 deletions src/components/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

import { ReactComponent as AlertIcon } from 'assets/images/icons/alert.svg';

interface AlertProps {
errors: string[];
'data-test-id'?: string;
}
const Alert = ({ errors, ...rest }: AlertProps): JSX.Element => (
<div role="alert" {...rest}>
<div className="bg-black-raisin bg-opacity-60 rounded-xl px-4 py-4 flex flex-row">
<AlertIcon className="mr-[19px] text-white" />
<div>
<p className="text-small text-white font-extrabold mb-2">Error</p>
<ul className="list-disc list-inside text-white opacity-60 text-x-small">
{errors.map((error, index) => (
<li key={`${index}${error}`}>{error}</li>
))}
</ul>
</div>
</div>
</div>
);

export default Alert;
17 changes: 17 additions & 0 deletions src/components/Dashboard/Empty/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import DashboardEmpty from '.';

describe('DashboardEmpty', () => {
it('renders DashboardEmpty and its components', () => {
const dataTestId = 'dashboard-empty';
render(<DashboardEmpty data-test-id={dataTestId} />);

const dashboardEmpty = screen.getByTestId(dataTestId);

expect(dashboardEmpty).toBeVisible();
expect(dashboardEmpty).toHaveTextContent('😎You‘ve completed all the surveys.Take a moment.');
});
});
20 changes: 20 additions & 0 deletions src/components/Dashboard/Empty/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';

interface DashboardEmptyProps {
'data-test-id'?: string;
}

const DashboardEmpty = (attributes: DashboardEmptyProps): JSX.Element => {
return (
<div className="flex flex-col items-center" {...attributes}>
<p className="text-[64px]">😎</p>
<p className="text-white text-large font-[850] text-center mt-8">
You&lsquo;ve completed all the surveys.
<br />
Take a moment.
</p>
</div>
);
};

export default DashboardEmpty;
30 changes: 30 additions & 0 deletions src/components/Dashboard/Header/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import DashboardHeader from '.';

describe('DashboardHeader', () => {
const dataTestId = 'dashboard-header';
it('renders DashboardHeader and its components', () => {
const dateTime = 'Monday, JUNE 15';
const daysAgo = 'Today';
const profileUrl = 'test url';
render(
<DashboardHeader dateTime={dateTime} daysAgo={daysAgo} profileUrl={profileUrl} data-test-id={dataTestId}>
Dashboard Header
</DashboardHeader>
);

const dashboardHeader = screen.getByTestId(dataTestId);
const avatar = screen.getByAltText('user avatar');

expect(dashboardHeader).toBeVisible();
expect(dashboardHeader).toHaveTextContent(dateTime);
expect(dashboardHeader).toHaveTextContent(dateTime);
expect(dashboardHeader).toHaveTextContent(dateTime);

expect(avatar).toBeVisible();
expect(avatar).toHaveAttribute('src', profileUrl);
});
});
36 changes: 36 additions & 0 deletions src/components/Dashboard/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';

import { ReactComponent as NimbleLogoWhite } from 'assets/images/icons/nimble-logo-white.svg';

interface DashboardHeaderProps {
dateTime: string;
daysAgo: string;
profileUrl: string;
children: React.ReactNode;
'data-test-id'?: string;
}
const DashboardHeader = ({ dateTime, daysAgo, profileUrl, children, ...rest }: DashboardHeaderProps): JSX.Element => {
return (
<header className="flex flex-col min-h-screen" {...rest}>
<div className="flex justify-between pt-8">
<NimbleLogoWhite />
<img className="w-[36px] h-[36px] rounded-full" src={profileUrl} alt="user avatar" />
</div>
<div className="flex justify-between">
<div className="w-1/5"></div>
<div className="flex flex-col text-white mt-10 flex-1">
<p className="text-x-small font-extrabold">{dateTime}</p>
<p className="text-x-large font-extrabold mt-1">{daysAgo}</p>
</div>
<div className="w-1/5"></div>
</div>
<div className="flex justify-between mt-8 grow">
<div className="w-1/5"></div>
<div className="flex-1">{children}</div>
<div className="w-1/5"></div>
</div>
</header>
);
};

export default DashboardHeader;
4 changes: 2 additions & 2 deletions src/components/ElevatedButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ interface ElevatedButtonProps extends React.ButtonHTMLAttributes<HTMLButtonEleme
isFullWidth: boolean;
}

const ElevatedButton = ({ children, isFullWidth, ...attributes }: ElevatedButtonProps): JSX.Element => {
const ElevatedButton = ({ children, isFullWidth, ...rest }: ElevatedButtonProps): JSX.Element => {
const DEFAULT_CLASS_NAMES =
'bg-white text-black-chinese font-bold text-regular tracking-survey-tight rounded-[10px] focus:outline-none focus:shadow-outline h-14';

return (
<button type="button" className={classNames(DEFAULT_CLASS_NAMES, { 'w-full': isFullWidth })} {...attributes}>
<button type="button" className={classNames(DEFAULT_CLASS_NAMES, { 'w-full': isFullWidth })} {...rest}>
{children}
</button>
);
Expand Down
17 changes: 17 additions & 0 deletions src/components/LoadingDialog/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import LoadingDialog from '.';

describe('LoadingDialog', () => {
const dataTestId = 'loading-dialog';

it('renders a loading dialog component', () => {
render(<LoadingDialog data-test-id={dataTestId} />);

const loadingDialog = screen.getByTestId(dataTestId);

expect(loadingDialog).toBeVisible();
});
});
22 changes: 22 additions & 0 deletions src/components/LoadingDialog/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';

interface LoadingDialogProps {
'data-test-id'?: string;
}

const LoadingDialog = (htmlAttributes: LoadingDialogProps): JSX.Element => {
return (
<div className="w-full h-full bg-black bg-opacity-60 fixed top-0 right-0" {...htmlAttributes}>
<div
className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-white absolute z-[1000] left-1/2 top-1/2 border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]"
role="status"
>
<span className="absolute -m-px h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)]">
Loading...
</span>
</div>
</div>
);
};

export default LoadingDialog;
2 changes: 2 additions & 0 deletions src/components/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type TextInputProps = {
required?: boolean;
placeholder?: string;
'data-test-id'?: string;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
};
className?: string;
};
Expand All @@ -34,6 +35,7 @@ const TextInput = ({ label, labelDataTestId, inputAttributes, className }: TextI
{...inputAttributes}
className={classNames(DEFAULT_CLASS_NAMES, className)}
placeholder={inputAttributes.placeholder}
onChange={inputAttributes.onChange}
/>
</div>
);
Expand Down
Loading

0 comments on commit ef6fed1

Please sign in to comment.