-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #57 from manh-t/release/0.3.0
Release - 0.3.0
- Loading branch information
Showing
36 changed files
with
776 additions
and
69 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# Team | ||
* @manh-t @nvminhtue @tyrro | ||
* @manh-t @nvminhtue @tyrro @hoangmirs |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* eslint camelcase: ["error", {allow: ["camel_case_key"]}] */ | ||
import { getToken } from 'helpers/authentication'; | ||
import requestManager from 'lib/request/v1/requestManager'; | ||
|
||
import { authenticatedHeader, getAuth, postAuth } from '.'; | ||
|
||
jest.mock('lib/request/v1/requestManager'); | ||
jest.mock('helpers/authentication'); | ||
|
||
describe('BaseAuthAdapter', () => { | ||
const path = '/path'; | ||
const params = { | ||
camelCaseKey: 'value', | ||
}; | ||
|
||
beforeEach(() => { | ||
(requestManager as jest.Mock).mockImplementation(() => jest.fn()); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('authenticatedHeader', () => { | ||
const mockAccessToken = 'access token'; | ||
const mockTokenType = 'token type'; | ||
const mockTokens = { | ||
id: 'id', | ||
resourceType: 'resource type', | ||
accessToken: mockAccessToken, | ||
refreshToken: 'refresh token', | ||
tokenType: mockTokenType, | ||
}; | ||
|
||
beforeEach(() => { | ||
(getToken as jest.Mock).mockImplementation(() => mockTokens); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('returns the headers that includes the token', () => { | ||
const expectedHeader = { | ||
Authorization: `${mockTokenType} ${mockAccessToken}`, | ||
}; | ||
|
||
expect(authenticatedHeader()).toEqual(expectedHeader); | ||
}); | ||
}); | ||
|
||
describe('getAuth', () => { | ||
describe('given only the path', () => { | ||
it('calls the get method from request manager with the path and authenticated header', () => { | ||
getAuth(path); | ||
|
||
expect(requestManager).toHaveBeenCalledWith('get', path, { headers: authenticatedHeader() }); | ||
}); | ||
}); | ||
|
||
describe('given the path and url params', () => { | ||
it('calls the get method from request manager with the path, params and authenticated header', () => { | ||
getAuth(path, params); | ||
|
||
expect(requestManager).toHaveBeenCalledWith('get', path, { | ||
params: { camel_case_key: params.camelCaseKey }, | ||
headers: authenticatedHeader(), | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('postAuth', () => { | ||
describe('given the path and params', () => { | ||
it('calls the post method from request manager with the path, params and authenticated header', () => { | ||
postAuth(path, params); | ||
|
||
expect(requestManager).toHaveBeenCalledWith('post', path, { | ||
data: { camel_case_key: params.camelCaseKey }, | ||
headers: authenticatedHeader(), | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { AxiosRequestConfig } from 'axios'; | ||
|
||
import { getToken } from 'helpers/authentication'; | ||
import { JSONObject, keysToSnakeCase } from 'helpers/json'; | ||
import requestManager from 'lib/request/v1/requestManager'; | ||
|
||
export const authenticatedHeader = (): { Authorization: string } => ({ | ||
Authorization: `${getToken()?.tokenType} ${getToken()?.accessToken}`, | ||
}); | ||
|
||
const defaultRequestOptions = (): AxiosRequestConfig => ({ headers: authenticatedHeader() }); | ||
|
||
export const getAuth = (path: string, params?: JSONObject) => { | ||
const requestOptions: AxiosRequestConfig = { ...defaultRequestOptions() }; | ||
if (params) { | ||
requestOptions.params = keysToSnakeCase(params); | ||
} | ||
|
||
return requestManager('get', path, requestOptions); | ||
}; | ||
|
||
export const postAuth = (path: string, params: JSONObject) => { | ||
const requestOptions: AxiosRequestConfig = { ...defaultRequestOptions(), data: keysToSnakeCase(params) }; | ||
|
||
return requestManager('post', path, requestOptions); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { getAuth } from 'adapters/BaseAuth'; | ||
|
||
import { getSurveys } from '.'; | ||
|
||
jest.mock('adapters/BaseAuth'); | ||
|
||
describe('SurveyAdapter', () => { | ||
beforeEach(() => { | ||
(getAuth as jest.Mock).mockImplementation(() => jest.fn()); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('getSurveys', () => { | ||
it('calls the get method from the base adapter', () => { | ||
const expectedPath = 'surveys?page[number]=1&page[size]=10'; | ||
|
||
getSurveys(); | ||
|
||
expect(getAuth).toHaveBeenCalledWith(expectedPath); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { getAuth } from 'adapters/BaseAuth'; | ||
|
||
export const getSurveys = () => getAuth('surveys?page[number]=1&page[size]=10'); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
|
||
import { render, screen } from '@testing-library/react'; | ||
|
||
import BackgroundImage, { backgroundImageTestIds } from '.'; | ||
|
||
describe('BackgroundImage', () => { | ||
it('renders BackgroundImage with the background image', () => { | ||
const imgUrl = 'test url'; | ||
|
||
render(<BackgroundImage backgroundUrl={imgUrl}>The children</BackgroundImage>); | ||
|
||
const backgroundImage = screen.getByTestId(backgroundImageTestIds.base); | ||
const backgroundImgElement = screen.getByAltText('background'); | ||
|
||
expect(backgroundImage).toBeVisible(); | ||
expect(backgroundImgElement).toHaveAttribute('src', imgUrl); | ||
}); | ||
|
||
it('renders BackgroundImage with the black as a background', () => { | ||
render(<BackgroundImage>The children</BackgroundImage>); | ||
|
||
const backgroundImage = screen.getByTestId(backgroundImageTestIds.base); | ||
|
||
expect(backgroundImage).toBeVisible(); | ||
expect(backgroundImage).toHaveClass('bg-black'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
|
||
export const backgroundImageTestIds = { | ||
base: 'background-image', | ||
}; | ||
|
||
interface BackgroundImageProps { | ||
children: React.ReactNode; | ||
backgroundUrl?: string; | ||
} | ||
|
||
const BackgroundImage = ({ backgroundUrl, children }: BackgroundImageProps): JSX.Element => { | ||
return backgroundUrl ? ( | ||
<div className="h-screen w-screen relative" data-test-id={backgroundImageTestIds.base}> | ||
<img src={backgroundUrl} alt="background" className="absolute w-full h-full z-[-1]" /> | ||
<div className="h-full backdrop-blur-[50px] bg-gradient-to-b from-black/20 to-black">{children}</div> | ||
</div> | ||
) : ( | ||
<div className="absolute w-full h-full z-[-1] bg-black" data-test-id={backgroundImageTestIds.base}> | ||
{children} | ||
</div> | ||
); | ||
}; | ||
|
||
export default BackgroundImage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React from 'react'; | ||
|
||
import { render, screen } from '@testing-library/react'; | ||
|
||
import DashboardContent, { dashboardDataTestIds } from '.'; | ||
|
||
describe('DashboardContent', () => { | ||
const surveys = [ | ||
{ | ||
id: '1', | ||
resourceType: 'survey', | ||
coverImageUrl: 'https://dhdbhh0jsld0o.cloudfront.net/m/1ea51560991bcb7d00d0_', | ||
title: 'Working from home Check-In', | ||
description: 'We would like to know how you feel about our work from home.', | ||
}, | ||
]; | ||
|
||
it('renders DashboardContent and its components', () => { | ||
render( | ||
<DashboardContent | ||
surveys={surveys} | ||
currentPosition={0} | ||
shouldShowShimmer={false} | ||
onNextSurvey={() => jest.fn()} | ||
onIndicatorTapped={() => jest.fn()} | ||
/> | ||
); | ||
|
||
const dashboardContent = screen.getByTestId(dashboardDataTestIds.content); | ||
|
||
expect(dashboardContent).toBeVisible(); | ||
expect(dashboardContent).toHaveTextContent(surveys[0].title); | ||
expect(dashboardContent).toHaveTextContent(surveys[0].description); | ||
}); | ||
|
||
it('does NOT render the DashboardContent components', () => { | ||
render( | ||
<DashboardContent | ||
surveys={surveys} | ||
currentPosition={0} | ||
shouldShowShimmer={true} | ||
onNextSurvey={() => jest.fn()} | ||
onIndicatorTapped={() => jest.fn()} | ||
/> | ||
); | ||
|
||
expect(screen.queryByTestId(dashboardDataTestIds.content)).not.toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React, { useEffect } from 'react'; | ||
|
||
import classNames from 'classnames'; | ||
|
||
import { ReactComponent as ArrowRight } from 'assets/images/icons/arrow-right.svg'; | ||
import Shimmer from 'components/Shimmer'; | ||
import { getHighResolutionImage } from 'helpers/image'; | ||
import { Survey } from 'types/survey'; | ||
|
||
export const dashboardDataTestIds = { | ||
content: 'dashboard__content', | ||
}; | ||
|
||
interface DashboardContentProps { | ||
surveys: Survey[]; | ||
currentPosition: number; | ||
shouldShowShimmer: boolean; | ||
onNextSurvey: () => void; | ||
onIndicatorTapped: (position: number) => void; | ||
} | ||
|
||
const DashboardContent = ({ | ||
surveys, | ||
currentPosition, | ||
shouldShowShimmer = true, | ||
onNextSurvey, | ||
onIndicatorTapped, | ||
}: DashboardContentProps): JSX.Element => { | ||
useEffect(() => { | ||
const interval = setInterval(() => { | ||
onNextSurvey(); | ||
}, 3000); | ||
return () => { | ||
clearInterval(interval); | ||
}; | ||
}); | ||
|
||
return shouldShowShimmer ? ( | ||
<div className="flex flex-col h-full"> | ||
<Shimmer classAttributes="h-[302px] rounded-[12px]" /> | ||
<div className="flex flex-row justify-between mt-[38px]"> | ||
<div className="flex flex-col justify-between"> | ||
<Shimmer classAttributes="w-[318px] h-[18px] rounded-[14px]" /> | ||
<Shimmer classAttributes="w-[212px] h-[18px] rounded-[14px]" /> | ||
</div> | ||
<Shimmer classAttributes="w-[56px] h-[56px] rounded-full" /> | ||
</div> | ||
</div> | ||
) : ( | ||
<div className="flex flex-col h-full" data-test-id={dashboardDataTestIds.content}> | ||
<div | ||
style={{ backgroundImage: `url(${getHighResolutionImage(surveys[currentPosition].coverImageUrl)})` }} | ||
className="w-full h-[302px] rounded-[12px] bg-cover duration-500 ease-in-out" | ||
></div> | ||
<div className="flex flex-row justify-between mt-[38px]"> | ||
<div className="flex flex-col justify-between"> | ||
<p className="text-white text-x-regular font-extrabold">{surveys[currentPosition].title}</p> | ||
<p className="text-white text-regular tracking-survey-tight opacity-60 mt-2">{surveys[currentPosition].description}</p> | ||
</div> | ||
<button | ||
type="button" | ||
className="w-[56px] h-[56px] bg-white rounded-full inline-flex items-center justify-center text-black-chinese" | ||
> | ||
<ArrowRight /> | ||
</button> | ||
</div> | ||
{/* <!-- Slider indicators --> */} | ||
<div className="flex-1 flex space-x-3 justify-center items-end mb-[42px]"> | ||
{surveys.map((surveyItem, index) => { | ||
return ( | ||
<button | ||
key={surveyItem.id} | ||
type="button" | ||
className={classNames('w-2 h-2 rounded-full bg-white', { 'bg-opacity-20': index !== currentPosition })} | ||
aria-current={index === currentPosition ? 'true' : 'false'} | ||
aria-label={`Slide ${surveyItem.id}`} | ||
data-carousel-slide-to={index} | ||
onClick={() => onIndicatorTapped(index)} | ||
></button> | ||
); | ||
})} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default DashboardContent; |
Oops, something went wrong.