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/api/protectedApiClient.ts b/src/api/protectedApiClient.ts index c1a55c5..2f96657 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: PostRequestData, + ) => Promise; + readonly getOnboardingData: () => Promise; } export enum ProtectedApiClientRoutes { @@ -13,6 +17,37 @@ export enum ProtectedApiClientRoutes { DELETE_USER = '/api/v1/protected/user/', } +export interface PostRequestData { + title: string; + body: string; + userId: number; +} + +export interface GetResponseData { + id: number; + title: string; + body: string; + userId: number; +} + +const postOnboardingForm = async ( + request: PostRequestData, +): Promise => { + const res = await AppAxiosInstance.post( + 'https://jsonplaceholder.typicode.com/posts', + request, + { headers: { 'Access-Control-Allow-Origin': '*' } }, + ); + return res.data; +}; + +const getOnboardingData = async (): Promise => { + const res = await AppAxiosInstance.get( + 'https://jsonplaceholder.typicode.com/posts', + ); + return res.data; +}; + const changePassword = (request: { currentPassword: string; newPassword: string; @@ -34,6 +69,8 @@ const deleteUser = (request: { password: string }): Promise => { const Client: ProtectedApiClient = Object.freeze({ changePassword, deleteUser, + postOnboardingForm, + getOnboardingData, }); export default Client; 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..b132704 --- /dev/null +++ b/src/containers/onboarding/index.tsx @@ -0,0 +1,178 @@ +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, { + GetResponseData, + PostRequestData, +} from '../../api/protectedApiClient'; +import { + AsyncRequest, + AsyncRequestCompleted, + AsyncRequestFailed, + asyncRequestIsComplete, + AsyncRequestLoading, + AsyncRequestNotStarted, +} from '../../utils/asyncRequest'; + +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 [createPostRequest, setCreatePostRequest] = useState< + AsyncRequest + >(AsyncRequestNotStarted()); + const [getPostsRequest, setGetPostsRequest] = useState< + AsyncRequest + >(AsyncRequestNotStarted()); + + const getPosts = async () => { + setCreatePostRequest(AsyncRequestLoading()); + await ProtectedApiClient.getOnboardingData() + .then((res) => { + setCreatePostRequest(AsyncRequestCompleted(res)); + }) + .catch((error) => { + setCreatePostRequest(AsyncRequestFailed(error)); + }); + }; + + const onFinish = async (values: PostRequestData) => { + setGetPostsRequest(AsyncRequestLoading()); + await ProtectedApiClient.postOnboardingForm(values) + .then((res) => { + setGetPostsRequest(AsyncRequestCompleted(res)); + }) + .catch((error) => { + setGetPostsRequest(AsyncRequestFailed(error)); + }); + }; + + const onFinishFailed = (errorInfo: any) => { + setGetPostsRequest(AsyncRequestFailed(errorInfo)); + }; + + return ( + <> + + + Code4Community Frontend Onboarding Tutorial! + + + Form! + This is an example form card to create a post. +
+ + + + + + + + + + + + +
+ {asyncRequestIsComplete(getPostsRequest) && ( + + Successfully created getPostsRequest with title ' + {getPostsRequest.result.title}'! + + )} +
+ Get Posts + + {asyncRequestIsComplete(createPostRequest) && + createPostRequest.result.map((post: GetResponseData, i: number) => { + return ( + + ); + })} + +
+ + ); +}; + +export default Onboarding; 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 ', () => { }, ); }); - }); });