Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#26][#9][#10][#13] As a user, when I am authenticated I can see the paginated Survey List page #41

Draft
wants to merge 14 commits into
base: feature/17-request-new-password
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"react-router-dom": "6.3.0",
"react-scripts": "5.0.1",
"sass": "1.49.11",
"swiper": "9.1.0",
"web-vitals": "2.1.4"
},
"scripts": {
Expand Down Expand Up @@ -84,6 +85,9 @@
],
"coverageReporters": [
"json"
],
"transformIgnorePatterns": [
"!node_modules/"
]
},
"nyc": {
Expand Down
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const App = (): JSX.Element => {

return (
<div>
<main className="m-0 flex h-screen flex-col items-center justify-center p-0">{appRoutes}</main>
<main className="m-0 flex h-screen w-full flex-col items-center justify-center p-0">{appRoutes}</main>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import nock from 'nock';

import AuthAdapter, { OauthParams } from './authAdapter';
import SurveyAdapter, { OauthParams } from './surveyAdapter';

/* eslint-disable camelcase */
const mockLoginCredentials = {
Expand All @@ -20,7 +20,7 @@ const commonUserProfileResponse = {
},
};

describe('AuthAdapter', () => {
describe('SurveyAdapter', () => {
afterAll(() => {
nock.cleanAll();
nock.restore();
Expand All @@ -41,12 +41,12 @@ describe('AuthAdapter', () => {
.reply(200);

expect(scope.isDone()).toBe(false);
await AuthAdapter.loginWithEmailPassword({ ...mockLoginCredentials });
await SurveyAdapter.loginWithEmailPassword({ ...mockLoginCredentials });
expect(scope.isDone()).toBe(true);
});
});

describe('loginWithRefreshToken', () => {
describe('refreshAccessToken', () => {
test('The refresh token endpoint is called with refresh token from the request', async () => {
const scope = nock(`${process.env.REACT_APP_API_ENDPOINT}`)
.defaultReplyHeaders({
Expand All @@ -61,7 +61,7 @@ describe('AuthAdapter', () => {
.reply(200);

expect(scope.isDone()).toBe(false);
await AuthAdapter.loginWithRefreshToken('refresh_token');
await SurveyAdapter.refreshAccessToken('refresh_token');
expect(scope.isDone()).toBe(true);
});
});
Expand All @@ -77,7 +77,7 @@ describe('AuthAdapter', () => {
.reply(200, { ...commonUserProfileResponse });

expect(scope.isDone()).toBe(false);
expect(await AuthAdapter.getUser()).toEqual({ ...commonUserProfileResponse });
expect(await SurveyAdapter.getUser()).toEqual({ ...commonUserProfileResponse });
expect(scope.isDone()).toBe(true);
});
});
Expand All @@ -95,7 +95,7 @@ describe('AuthAdapter', () => {
.reply(200);

expect(scope.isDone()).toBe(false);
expect(await AuthAdapter.logout(token));
expect(await SurveyAdapter.logout(token));
expect(scope.isDone()).toBe(true);
});
});
Expand All @@ -111,7 +111,7 @@ describe('AuthAdapter', () => {
.reply(200);

expect(scope.isDone()).toBe(false);
expect(await AuthAdapter.resetPassword(mockLoginCredentials.email));
expect(await SurveyAdapter.resetPassword(mockLoginCredentials.email));
expect(scope.isDone()).toBe(true);
});
});
Expand Down
10 changes: 7 additions & 3 deletions src/adapters/authAdapter.ts → src/adapters/surveyAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const OauthParams = {
client_secret: process.env.REACT_APP_API_CLIENT_SECRET,
};
/* eslint-enable camelcase */
class AuthAdapter extends BaseAdapter {
class SurveyAdapter extends BaseAdapter {
static loginWithEmailPassword(authParams: LoginAuthType) {
/* eslint-disable camelcase */
const requestParams = {
Expand All @@ -24,7 +24,7 @@ class AuthAdapter extends BaseAdapter {
return this.prototype.postRequest('oauth/token', { data: requestParams });
}

static loginWithRefreshToken(refreshToken: string) {
static refreshAccessToken(refreshToken: string) {
/* eslint-disable camelcase */
const requestParams = {
...OauthParams,
Expand Down Expand Up @@ -59,6 +59,10 @@ class AuthAdapter extends BaseAdapter {
static getUser() {
return this.prototype.getRequest('me', {});
}

static list(page: number) {
return this.prototype.getRequest(`surveys?page[number]=${page}`, {});
}
}

export default AuthAdapter;
export default SurveyAdapter;
3 changes: 3 additions & 0 deletions src/assets/images/arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 29 additions & 1 deletion src/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
}

html {
width: 100%;
height: 100%;
margin: 0 auto;

Expand All @@ -34,3 +33,32 @@ html {
body {
height: 100%;
}

.survey-swiper {
.swiper-pagination-bullet {
width: 0.5rem;

opacity: 0.2;
background-color: #fff !important;
}

.swiper-pagination-bullet-active {
opacity: 1;
}

&.swiper-pagination {
bottom: 2rem !important;
}
}

.arrow-button {
width: 56px;
height: 56px;

border-radius: 9999px;

background-color: #fff;
background-image: url('../images/arrow.svg');
background-repeat: no-repeat;
background-position: center;
}
2 changes: 0 additions & 2 deletions src/components/PrivateRoute/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,5 @@ describe('PrivateRoute', () => {
render(<PrivateRoute />, { wrapper: MemoryRouter });

expect(screen.getByTestId('loading')).toHaveTextContent('Loading');

// expect(screen.getByTestId('loading')).not.toBeVisible();
});
});
4 changes: 2 additions & 2 deletions src/components/Sidebar/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BrowserRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import AuthAdapter from 'adapters/authAdapter';
import SurveyAdapter from 'adapters/surveyAdapter';
import { User } from 'types/User';

import Sidebar from '.';
Expand Down Expand Up @@ -37,7 +37,7 @@ describe('Sidebar', () => {
});

test('renders a sidebar on the page with a logout button that when clicked, calls Logout adapter and removes storage', async () => {
const mockLogout = jest.spyOn(AuthAdapter, 'logout');
const mockLogout = jest.spyOn(SurveyAdapter, 'logout');

// const mockClearToken = jest.spyOn(myStorage, 'clearItem');

Expand Down
4 changes: 2 additions & 2 deletions src/components/Sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useNavigate } from 'react-router-dom';

import AuthAdapter from 'adapters/authAdapter';
import SurveyAdapter from 'adapters/surveyAdapter';
import { getItem, clearItem } from 'helpers/localStorage';
import { User } from 'types/User';

Expand All @@ -18,7 +18,7 @@ function Sidebar({ user }: SidebarProps) {
e.stopPropagation();

const accessToken = getItem('UserProfile')?.auth.access_token;
await AuthAdapter.logout(accessToken);
await SurveyAdapter.logout(accessToken);
clearItem('UserProfile');
navigate(LOGIN_URL);
};
Expand Down
25 changes: 25 additions & 0 deletions src/components/Survey/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type SurveyProps = {
title: string;
description: string;
coverImageUrl: string;
};

function Survey({ title, description, coverImageUrl }: SurveyProps) {
return (
<div>
<img className="my-4 max-h-80 w-full rounded-xl" src={coverImageUrl} alt="cover" />
<div className="mt-8 flex items-center justify-between">
<div>
<p className="text-white"> {title}</p>
<p className="text-white opacity-60"> {description}</p>
</div>
<div>
{/* TODO: Convert to Link for Survey Detail page */}
<button className="arrow-button"></button>
</div>
</div>
</div>
);
}

export default Survey;
36 changes: 36 additions & 0 deletions src/components/SurveyList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Pagination } from 'swiper';
import { Swiper, SwiperSlide } from 'swiper/react';

import 'swiper/swiper-bundle.min.css';

import SurveyComponent from 'components/Survey';
import { Survey } from 'types/Survey';

type SurveyListProps = { surveys: Survey[]; onPageChange: () => void };

function SurveyList({ surveys, onPageChange }: SurveyListProps) {
return (
<>
<Swiper
className="survey-swiper"
modules={[Pagination]}
speed={800}
spaceBetween={100}
pagination={{ el: '.swiper-pagination', clickable: true, dynamicBullets: true }}
slidesPerView={1}
onReachEnd={onPageChange}
>
{surveys.map((survey) => {
return (
<SwiperSlide key={survey.id}>
<SurveyComponent {...survey} />
</SwiperSlide>
);
})}
</Swiper>
<div className="survey-swiper swiper-pagination"></div>
</>
);
}

export default SurveyList;
2 changes: 1 addition & 1 deletion src/lib/requestManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ describe('createResponseErrorInterceptor', () => {
JSON.stringify({ auth: mockTokenData, user: mockUserProfileData })
);

// 4 I can not expect storage to set the new token here as it seems to hit the catch block in the authAdapter
// 4 I can not expect storage to set the new token here as it seems to hit the catch block in the SurveyAdapter
// on the fetching of new access token
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/requestManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios, { Method as HTTPMethod, ResponseType, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';

import AuthAdapter from 'adapters/authAdapter';
import SurveyAdapter from 'adapters/surveyAdapter';
import { setItem, getItem, clearItem } from 'helpers/localStorage';

import { LOGIN_URL } from '../constants';
Expand Down Expand Up @@ -29,7 +29,7 @@ export function createResponseErrorInterceptor() {

if (userProfile?.auth?.refresh_token) {
try {
const response = await AuthAdapter.loginWithRefreshToken(userProfile.auth.refresh_token);
const response = await SurveyAdapter.refreshAccessToken(userProfile.auth.refresh_token);

const { attributes: authInfo } = await response.data;

Expand Down
6 changes: 3 additions & 3 deletions src/screens/Home/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ describe('HomeScreen', () => {
test('renders learn react link', () => {
render(<HomeScreen />);

const mainHeadingElement = screen.getByTestId('app-main-heading');
const surveyLoadingElement = screen.getByTestId('loading-surveys');

expect(mainHeadingElement).toBeInTheDocument();
expect(mainHeadingElement).toHaveTextContent('Home Screen');
expect(surveyLoadingElement).toBeInTheDocument();
expect(surveyLoadingElement).toHaveTextContent('Loading Surveys');
});
});
Loading