From b18530b3e41d4c2276da1edceeb6a48fa0f329b1 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:18:07 -0400 Subject: [PATCH 1/9] created onboarding page --- src/App.tsx | 12 +++ src/components/onboarding/index.tsx | 24 +++++ src/containers/onboarding/index.tsx | 139 ++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 src/components/onboarding/index.tsx create mode 100644 src/containers/onboarding/index.tsx diff --git a/src/App.tsx b/src/App.tsx index 5e6485c..253ac02 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,6 +17,7 @@ import { PrivilegeLevel } from './auth/ducks/types'; import { C4CState } from './store'; import { getPrivilegeLevel } from './auth/ducks/selectors'; import { useSelector } from 'react-redux'; +import Onboarding from './containers/onboarding'; const { Content } = Layout; @@ -32,6 +33,7 @@ export enum Routes { FORGOT_PASSWORD_REQUEST = '/forgot-password', FORGOT_PASSWORD_RESET = '/forgot-password-reset/:key', VERIFY_EMAIL = '/verify/:key', + ONBOARDING = '/onboarding', } const App: React.FC = () => { @@ -72,6 +74,11 @@ const App: React.FC = () => { exact component={VerifyEmail} /> + ); @@ -96,6 +103,11 @@ const App: React.FC = () => { exact component={VerifyEmail} /> + ); diff --git a/src/components/onboarding/index.tsx b/src/components/onboarding/index.tsx new file mode 100644 index 0000000..7fcce0f --- /dev/null +++ b/src/components/onboarding/index.tsx @@ -0,0 +1,24 @@ +import { Card, Typography } from 'antd'; +import React from 'react'; +const { Title, Paragraph } = Typography; + +interface ResponseCardProps { + id: number; + title: string; + body: string; + userId: number; +} + +export const ResponseCard: React.FC = ({ + id, + title, + body, + userId, +}) => { + return ( + + {id} + {body} + + ); +}; diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx new file mode 100644 index 0000000..3f8e130 --- /dev/null +++ b/src/containers/onboarding/index.tsx @@ -0,0 +1,139 @@ +import React, { useState } from 'react'; +import { Helmet } from 'react-helmet'; +import { Button, Card, Form, Input, Typography } from 'antd'; +import { ContentContainer } from '../../components'; +import styled from 'styled-components'; +import { values } from 'lodash'; +import { ResponseCard } from '../../components/onboarding'; + +const { Title, Paragraph } = Typography; + +const Container = styled.div` + display: flex; + flex-direction: column; + flex-wrap: wrap; + align-items: center; + width: 100%; +`; + +const FormCard = styled(Card)` + display: flex; + width: 50%; + border-radius: 5px; +`; + +const OnboardingPageTitle = styled(Title)` + display: flex; + width: 100%; + justify-content: center; +`; + +const FormInput = styled(Input)` + display: flex; + width: 80%; + border: 1px 1px black; +`; + +const StyledButton = styled(Button)` + width: 30%; + margin-top: 16px; +`; + +const ResponseContainer = styled.div` + width: 75%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-evenly; + margin-top: 16px; +`; + +const SuccessMessage = styled(Paragraph)` + color: green; +`; + +const Onboarding: React.FC = () => { + const [posts, setPosts] = useState([]); + const [formSuccess, setFormSuccess] = useState(false); + + const updatePosts = () => { + fetch('https://jsonplaceholder.typicode.com/posts', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }) + .then((response) => response.json()) + .then((json) => setPosts(json)); + }; + + const onFinish = (values: any) => { + setFormSuccess(false); + fetch('https://jsonplaceholder.typicode.com/posts', { + method: 'POST', + body: JSON.stringify(values), + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + }) + .then((response) => response.json()) + .then((json) => console.log(json)); + setFormSuccess(true); + }; + + const onFinishFailed = (errorInfo: any) => { + console.log('Failed:', errorInfo); + }; + + return ( + <> + + + Code4Community Frontend Onboarding Tutorial! + + + Form! + This is an example form card. +
+ + + + + + +
+ {formSuccess && Success!} +
+ Get Posts + + {posts.map(function (object, i) { + return ( + + ); + })} + +
+ + ); +}; + +export default Onboarding; From d6ca51008440b703afd05cff68f7718e932232a1 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:19:00 -0400 Subject: [PATCH 2/9] prettier --- src/containers/onboarding/index.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 3f8e130..3f48de6 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -1,9 +1,6 @@ import React, { useState } from 'react'; -import { Helmet } from 'react-helmet'; import { Button, Card, Form, Input, Typography } from 'antd'; -import { ContentContainer } from '../../components'; import styled from 'styled-components'; -import { values } from 'lodash'; import { ResponseCard } from '../../components/onboarding'; const { Title, Paragraph } = Typography; From 831bc99654b1dfb3f6f5f4347667e7400f8fe5d1 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:27:12 -0400 Subject: [PATCH 3/9] adding types --- src/containers/onboarding/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 3f48de6..6f7c592 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -49,6 +49,10 @@ const SuccessMessage = styled(Paragraph)` color: green; `; +interface OnboardingRequestData { + favoriteColor: string +} + const Onboarding: React.FC = () => { const [posts, setPosts] = useState([]); const [formSuccess, setFormSuccess] = useState(false); @@ -65,11 +69,11 @@ const Onboarding: React.FC = () => { .then((json) => setPosts(json)); }; - const onFinish = (values: any) => { + const onFinish = (values: OnboardingRequestData) => { setFormSuccess(false); fetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', - body: JSON.stringify(values), + body: JSON.stringify({favoriteColor: values.favoriteColor}), headers: { 'Content-Type': 'application/json', Accept: 'application/json', From 1e748c66d86fcc1c05f579ac6758ada1465bb91a Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:29:12 -0400 Subject: [PATCH 4/9] more types --- src/containers/onboarding/index.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 6f7c592..6b1e37a 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -53,8 +53,15 @@ interface OnboardingRequestData { favoriteColor: string } +interface OnboardingResponseData { + id: number; + title: string; + body: string; + userId: number; +} + const Onboarding: React.FC = () => { - const [posts, setPosts] = useState([]); + const [posts, setPosts] = useState([]); const [formSuccess, setFormSuccess] = useState(false); const updatePosts = () => { From 0ff13411449a613ebe710b84ab0c710a566f3c74 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:37:08 -0400 Subject: [PATCH 5/9] added async and await --- src/containers/onboarding/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 6b1e37a..bc059e8 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -64,8 +64,8 @@ const Onboarding: React.FC = () => { const [posts, setPosts] = useState([]); const [formSuccess, setFormSuccess] = useState(false); - const updatePosts = () => { - fetch('https://jsonplaceholder.typicode.com/posts', { + const updatePosts = async () => { + await fetch('https://jsonplaceholder.typicode.com/posts', { method: 'GET', headers: { 'Content-Type': 'application/json', @@ -76,9 +76,9 @@ const Onboarding: React.FC = () => { .then((json) => setPosts(json)); }; - const onFinish = (values: OnboardingRequestData) => { + const onFinish = async (values: OnboardingRequestData) => { setFormSuccess(false); - fetch('https://jsonplaceholder.typicode.com/posts', { + await fetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', body: JSON.stringify({favoriteColor: values.favoriteColor}), headers: { From 5b224fdc61bab8991152acf0a0a408c741fe3a95 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 18:38:09 -0400 Subject: [PATCH 6/9] prettier --- src/containers/onboarding/index.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index bc059e8..b9f0e08 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -50,14 +50,14 @@ const SuccessMessage = styled(Paragraph)` `; interface OnboardingRequestData { - favoriteColor: string + favoriteColor: string; } interface OnboardingResponseData { - id: number; - title: string; - body: string; - userId: number; + id: number; + title: string; + body: string; + userId: number; } const Onboarding: React.FC = () => { @@ -80,7 +80,7 @@ const Onboarding: React.FC = () => { setFormSuccess(false); await fetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', - body: JSON.stringify({favoriteColor: values.favoriteColor}), + body: JSON.stringify({ favoriteColor: values.favoriteColor }), headers: { 'Content-Type': 'application/json', Accept: 'application/json', From 9a914506333cefa41657892dee97164a29a1e0d1 Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Sun, 22 Aug 2021 19:41:24 -0400 Subject: [PATCH 7/9] updates --- src/api/protectedApiClient.ts | 35 +++++++++++ src/containers/onboarding/index.tsx | 96 ++++++++++++++++------------- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/api/protectedApiClient.ts b/src/api/protectedApiClient.ts index c1a55c5..2b4686b 100644 --- a/src/api/protectedApiClient.ts +++ b/src/api/protectedApiClient.ts @@ -6,6 +6,10 @@ export interface ProtectedApiClient { newPassword: string; }) => Promise; readonly deleteUser: (request: { password: string }) => Promise; + readonly postOnboardingForm: ( + request: OnboardingRequestData, + ) => Promise; + readonly getOnboardingData: () => Promise; } export enum ProtectedApiClientRoutes { @@ -13,6 +17,35 @@ export enum ProtectedApiClientRoutes { DELETE_USER = '/api/v1/protected/user/', } +export interface OnboardingRequestData { + favoriteColor: string; + id: number; +} + +export interface OnboardingResponseData { + id: number; + title: string; + body: string; + userId: number; +} + +const postOnboardingForm = ( + request: OnboardingRequestData, +): Promise => { + return AppAxiosInstance.post( + 'https://jsonplaceholder.typicode.com/posts', + request, + ) + .then((r) => r.data) + .catch((e) => e); +}; + +const getOnboardingData = (): Promise => { + return AppAxiosInstance.get('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data) + .catch((e) => e); +}; + const changePassword = (request: { currentPassword: string; newPassword: string; @@ -34,6 +67,8 @@ const deleteUser = (request: { password: string }): Promise => { const Client: ProtectedApiClient = Object.freeze({ changePassword, deleteUser, + postOnboardingForm, + getOnboardingData, }); export default Client; diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index b9f0e08..4620d7a 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -1,7 +1,17 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Button, Card, Form, Input, Typography } from 'antd'; import styled from 'styled-components'; import { ResponseCard } from '../../components/onboarding'; +import ProtectedApiClient from '../../api/protectedApiClient'; +import { OnboardingResponseData } from '../../api/protectedApiClient'; +import { + AsyncRequest, + AsyncRequestCompleted, + AsyncRequestFailed, + asyncRequestIsComplete, + AsyncRequestLoading, + AsyncRequestNotStarted, +} from '../../utils/asyncRequest'; const { Title, Paragraph } = Typography; @@ -51,44 +61,37 @@ const SuccessMessage = styled(Paragraph)` interface OnboardingRequestData { favoriteColor: string; -} - -interface OnboardingResponseData { id: number; - title: string; - body: string; - userId: number; } const Onboarding: React.FC = () => { - const [posts, setPosts] = useState([]); - const [formSuccess, setFormSuccess] = useState(false); + const [posts, setPosts] = useState< + AsyncRequest + >(AsyncRequestNotStarted()); + const [post, setPost] = useState>( + AsyncRequestNotStarted(), + ); - const updatePosts = async () => { - await fetch('https://jsonplaceholder.typicode.com/posts', { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }) - .then((response) => response.json()) - .then((json) => setPosts(json)); + const getPosts = async () => { + setPosts(AsyncRequestLoading()); + await ProtectedApiClient.getOnboardingData() + .then((res) => { + setPosts(AsyncRequestCompleted(res)); + }) + .catch((error) => { + setPosts(AsyncRequestFailed(error)); + }); }; const onFinish = async (values: OnboardingRequestData) => { - setFormSuccess(false); - await fetch('https://jsonplaceholder.typicode.com/posts', { - method: 'POST', - body: JSON.stringify({ favoriteColor: values.favoriteColor }), - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - }) - .then((response) => response.json()) - .then((json) => console.log(json)); - setFormSuccess(true); + setPost(AsyncRequestLoading()); + await ProtectedApiClient.postOnboardingForm(values) + .then((res) => { + setPost(AsyncRequestCompleted(res)); + }) + .catch((error) => { + setPost(AsyncRequestFailed(error)); + }); }; const onFinishFailed = (errorInfo: any) => { @@ -123,21 +126,26 @@ const Onboarding: React.FC = () => { - {formSuccess && Success!} + {asyncRequestIsComplete(post) && ( + + Success! Your favorite color is {post.result.favoriteColor}! + + )} - Get Posts + Get Posts - {posts.map(function (object, i) { - return ( - - ); - })} + {asyncRequestIsComplete(posts) && + posts.result.map(function (post, i) { + return ( + + ); + })} From cc7f86aa54c2675606b99098ba33834c8731b2da Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Mon, 23 Aug 2021 15:51:55 -0400 Subject: [PATCH 8/9] final changes --- src/api/protectedApiClient.ts | 39 +++++++------ src/containers/onboarding/index.tsx | 89 ++++++++++++++++++----------- 2 files changed, 78 insertions(+), 50 deletions(-) diff --git a/src/api/protectedApiClient.ts b/src/api/protectedApiClient.ts index 2b4686b..83b9731 100644 --- a/src/api/protectedApiClient.ts +++ b/src/api/protectedApiClient.ts @@ -7,9 +7,9 @@ export interface ProtectedApiClient { }) => Promise; readonly deleteUser: (request: { password: string }) => Promise; readonly postOnboardingForm: ( - request: OnboardingRequestData, - ) => Promise; - readonly getOnboardingData: () => Promise; + request: PostRequestData, + ) => Promise; + readonly getOnboardingData: () => Promise; } export enum ProtectedApiClientRoutes { @@ -17,33 +17,36 @@ export enum ProtectedApiClientRoutes { DELETE_USER = '/api/v1/protected/user/', } -export interface OnboardingRequestData { - favoriteColor: string; - id: number; +export interface PostRequestData { + title: string; + body: string; + userId: number; } -export interface OnboardingResponseData { +export interface GetResponseData { id: number; title: string; body: string; userId: number; } -const postOnboardingForm = ( - request: OnboardingRequestData, -): Promise => { - return AppAxiosInstance.post( +const postOnboardingForm = async ( + request: PostRequestData, +): Promise => { + console.log(request); + const res = await AppAxiosInstance.post( 'https://jsonplaceholder.typicode.com/posts', request, - ) - .then((r) => r.data) - .catch((e) => e); + { headers: { 'Access-Control-Allow-Origin': '*' } }, + ); + return res.data; }; -const getOnboardingData = (): Promise => { - return AppAxiosInstance.get('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data) - .catch((e) => e); +const getOnboardingData = async (): Promise => { + const res = await AppAxiosInstance.get( + 'https://jsonplaceholder.typicode.com/posts', + ); + return res.data; }; const changePassword = (request: { diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 4620d7a..43fc8fe 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -1,9 +1,11 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { Button, Card, Form, Input, Typography } from 'antd'; import styled from 'styled-components'; import { ResponseCard } from '../../components/onboarding'; -import ProtectedApiClient from '../../api/protectedApiClient'; -import { OnboardingResponseData } from '../../api/protectedApiClient'; +import ProtectedApiClient, { + GetResponseData, + PostRequestData, +} from '../../api/protectedApiClient'; import { AsyncRequest, AsyncRequestCompleted, @@ -59,38 +61,33 @@ const SuccessMessage = styled(Paragraph)` color: green; `; -interface OnboardingRequestData { - favoriteColor: string; - id: number; -} - const Onboarding: React.FC = () => { - const [posts, setPosts] = useState< - AsyncRequest + const [createPostRequest, setCreatePostRequest] = useState< + AsyncRequest + >(AsyncRequestNotStarted()); + const [getPostsRequest, setGetPostsRequest] = useState< + AsyncRequest >(AsyncRequestNotStarted()); - const [post, setPost] = useState>( - AsyncRequestNotStarted(), - ); const getPosts = async () => { - setPosts(AsyncRequestLoading()); + setCreatePostRequest(AsyncRequestLoading()); await ProtectedApiClient.getOnboardingData() .then((res) => { - setPosts(AsyncRequestCompleted(res)); + setCreatePostRequest(AsyncRequestCompleted(res)); }) .catch((error) => { - setPosts(AsyncRequestFailed(error)); + setCreatePostRequest(AsyncRequestFailed(error)); }); }; - const onFinish = async (values: OnboardingRequestData) => { - setPost(AsyncRequestLoading()); + const onFinish = async (values: PostRequestData) => { + setGetPostsRequest(AsyncRequestLoading()); await ProtectedApiClient.postOnboardingForm(values) .then((res) => { - setPost(AsyncRequestCompleted(res)); + setGetPostsRequest(AsyncRequestCompleted(res)); }) .catch((error) => { - setPost(AsyncRequestFailed(error)); + setGetPostsRequest(AsyncRequestFailed(error)); }); }; @@ -106,15 +103,42 @@ const Onboarding: React.FC = () => { Form! - This is an example form card. + + This is an example form card to create a getPostsRequest. +
+ + + + + + @@ -126,23 +150,24 @@ const Onboarding: React.FC = () => {
- {asyncRequestIsComplete(post) && ( + {asyncRequestIsComplete(getPostsRequest) && ( - Success! Your favorite color is {post.result.favoriteColor}! + Successfully created getPostsRequest with title ' + {getPostsRequest.result.title}'! )}
Get Posts - {asyncRequestIsComplete(posts) && - posts.result.map(function (post, i) { + {asyncRequestIsComplete(createPostRequest) && + createPostRequest.result.map(function (getPostsRequest, i) { return ( ); })} From 4eec7a357fa52817de102242e9216595f6987dcf Mon Sep 17 00:00:00 2001 From: Varun Thakkar Date: Mon, 23 Aug 2021 16:04:13 -0400 Subject: [PATCH 9/9] checks --- src/api/protectedApiClient.ts | 1 - src/containers/onboarding/index.tsx | 16 +++++++--------- src/utils/test/asyncRequest.test.ts | 6 +++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/api/protectedApiClient.ts b/src/api/protectedApiClient.ts index 83b9731..2f96657 100644 --- a/src/api/protectedApiClient.ts +++ b/src/api/protectedApiClient.ts @@ -33,7 +33,6 @@ export interface GetResponseData { const postOnboardingForm = async ( request: PostRequestData, ): Promise => { - console.log(request); const res = await AppAxiosInstance.post( 'https://jsonplaceholder.typicode.com/posts', request, diff --git a/src/containers/onboarding/index.tsx b/src/containers/onboarding/index.tsx index 43fc8fe..b132704 100644 --- a/src/containers/onboarding/index.tsx +++ b/src/containers/onboarding/index.tsx @@ -92,7 +92,7 @@ const Onboarding: React.FC = () => { }; const onFinishFailed = (errorInfo: any) => { - console.log('Failed:', errorInfo); + setGetPostsRequest(AsyncRequestFailed(errorInfo)); }; return ( @@ -103,9 +103,7 @@ const Onboarding: React.FC = () => { Form! - - This is an example form card to create a getPostsRequest. - + This is an example form card to create a post.
{ Get Posts {asyncRequestIsComplete(createPostRequest) && - createPostRequest.result.map(function (getPostsRequest, i) { + createPostRequest.result.map((post: GetResponseData, i: number) => { return ( ); })} diff --git a/src/utils/test/asyncRequest.test.ts b/src/utils/test/asyncRequest.test.ts index 7b2d1d9..b67d234 100644 --- a/src/utils/test/asyncRequest.test.ts +++ b/src/utils/test/asyncRequest.test.ts @@ -6,7 +6,9 @@ import { AsyncRequest, AsyncRequestCompleted, AsyncRequestFailed, - asyncRequestIsComplete, asyncRequestIsFailed, asyncRequestIsLoading, + asyncRequestIsComplete, + asyncRequestIsFailed, + asyncRequestIsLoading, asyncRequestIsNotStarted, AsyncRequestLoading, AsyncRequestNotStarted, @@ -183,7 +185,6 @@ describe('asyncRequest ', () => { ); }); - it('asyncRequestIsFailed identifies Failed asyncRequests', () => { asyncRequests.map( (asyncRequest: AsyncRequest, index: number) => { @@ -195,6 +196,5 @@ describe('asyncRequest ', () => { }, ); }); - }); });