From ddad76393308c85290ba1dd51acaf2dbcd94ebea Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Fri, 11 Mar 2022 08:43:56 -0800 Subject: [PATCH 01/20] PLAT-754 #comment remove commented out tests #time 5m --- src/App.test.tsx | 16 +-- src/header/Header.test.tsx | 14 +-- src/header/logo/Logo.test.tsx | 28 +---- .../tool-selectors/ToolSelectors.test.tsx | 14 +-- .../ToolSelectorsNarrow.test.tsx | 24 +--- .../ToolSelectorNarrow.test.tsx | 14 +-- .../ToolSelectorsWide.test.tsx | 14 +-- .../ToolSelectorWide.test.tsx | 34 +----- .../ProfileSelector/ProfileSelector.test.tsx | 111 ++---------------- .../ProfileLoggedIn.test.tsx | 14 +-- .../ProfileNotLoggedIn.test.tsx | 14 +-- .../UtilitySelectors.test.tsx | 14 +-- src/lib/avatar/Avatar.test.tsx | 70 +---------- src/lib/content-layout/ContentLayout.test.tsx | 16 +-- .../content-layout/sections/Sections.test.tsx | 24 +--- .../Section-Selector.test.tsx | 14 +-- .../analytics.service.test.ts | 5 +- .../authentication.service.test.ts | 5 +- .../fetch-service/fetch.service.test.ts | 4 +- .../logging-service/logging.service.test.ts | 4 +- src/tools/design-lib/DesignLib.test.tsx | 9 +- src/tools/design-lib/buttons/Buttons.test.tsx | 9 +- src/tools/design-lib/fonts/Fonts.test.tsx | 9 +- src/tools/design-lib/home/Home.test.tsx | 9 +- src/tools/design-lib/icons/Icons.test.tsx | 9 +- src/tools/self-service/SelfService.test.tsx | 9 +- src/tools/tool/Tool.test.tsx | 10 +- src/utils/home/Home.test.tsx | 14 +-- 28 files changed, 47 insertions(+), 484 deletions(-) diff --git a/src/App.test.tsx b/src/App.test.tsx index cbf7a350e..112d36d48 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,18 +1,4 @@ -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import App from './App' - describe('', () => { - // TODO: figure out how to mock AuthenticationService - test('renders the body of the application', () => { - /* const result: RenderResult = render( - - - - ) - const bodyElement: HTMLBodyElement | null = result.container.querySelector('body') - expect(bodyElement).toBeDefined() */ - }) + test('renders the body of the application', () => {}) }) diff --git a/src/header/Header.test.tsx b/src/header/Header.test.tsx index 25d3f881b..d1922dc20 100644 --- a/src/header/Header.test.tsx +++ b/src/header/Header.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import Header from './Header' describe('
', () => { - test('it should render the header', () => { -/* const renderResult: RenderResult = render( - -
- - ) - const headerElement: HTMLElement | null = renderResult.container.querySelector('header') - expect(headerElement).toBeInTheDocument() */ - }) + test('it should render the header', () => {}) }) diff --git a/src/header/logo/Logo.test.tsx b/src/header/logo/Logo.test.tsx index 6210e85d8..4e00d827a 100644 --- a/src/header/logo/Logo.test.tsx +++ b/src/header/logo/Logo.test.tsx @@ -1,31 +1,11 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' -import LogoLink from './LogoLink' +describe(' is on the home page', () => { -describe(' is on the home page', () => { - - test('it should only display the logo and should NOT be a link', async () => { - /* const result: RenderResult = render( - - - - ) - const aTag: HTMLAnchorElement | null = result.container.querySelector('a') - expect(aTag).not.toBeInTheDocument() */ - }) + test('it should only display the logo and should NOT be a link', async () => { }) }) -describe(' is NOT on the home page', () => { +describe(' is NOT on the home page', () => { - test('it should display the logo and have it be a link', async () => { - /* const result: RenderResult = render( - - - - ) - const aTag: HTMLAnchorElement | null = result.container.querySelector('a') - expect(aTag).toBeInTheDocument() */ - }) + test('it should display the logo and have it be a link', async () => { }) }) diff --git a/src/header/tool-selectors/ToolSelectors.test.tsx b/src/header/tool-selectors/ToolSelectors.test.tsx index 53a6668b3..0a8b36550 100644 --- a/src/header/tool-selectors/ToolSelectors.test.tsx +++ b/src/header/tool-selectors/ToolSelectors.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ToolSelectors from './ToolSelectors' describe('', () => { - test('it should render the tool sections', () => { - /* const renderResult: RenderResult = render( - - - - ) - const headerElement: HTMLElement | null = renderResult.container.querySelector('.tool-selectors') - expect(headerElement).toBeInTheDocument() */ - }) + test('it should render the tool sections', () => { }) }) diff --git a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.test.tsx b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.test.tsx index fff28a776..f29765cf5 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.test.tsx +++ b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.test.tsx @@ -1,31 +1,11 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ToolSelectorsNarrow from './ToolSelectorsNarrow' describe(' is closed', () => { - test('it should render the tool-selectors-narrow-closed icon', () => { - /* const renderResult: RenderResult = render( - - - - ) - const menuElement: HTMLElement | null = renderResult.container.querySelector('.tool-selectors-narrow-closed') - expect(menuElement).toBeInTheDocument() */ - }) + test('it should render the tool-selectors-narrow-closed icon', () => { }) }) describe(' is open', () => { - test('it should render the tool-selectors-narrow-open icon', () => { - /* const renderResult: RenderResult = render( - - - - ) - const menuElement: HTMLElement | null = renderResult.container.querySelector('.tool-selectors-narrow-opened') - expect(menuElement).toBeInTheDocument() */ - }) + test('it should render the tool-selectors-narrow-open icon', () => { }) }) diff --git a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.test.tsx b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.test.tsx index a53a25feb..a80e60ec4 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.test.tsx +++ b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ToolSelectorNarrow from './ToolSelectorNarrow' describe(' is NOT open', () => { - test('it should render the tool-selector-narrow icon', () => { - /* const renderResult: RenderResult = render( - - - - ) - const home: HTMLElement = renderResult.container.querySelector('.tool-selector-narrow') - expect(home).toBeInTheDocument() */ - }) + test('it should render the tool-selector-narrow icon', () => { }) }) diff --git a/src/header/tool-selectors/tool-selectors-wide/ToolSelectorsWide.test.tsx b/src/header/tool-selectors/tool-selectors-wide/ToolSelectorsWide.test.tsx index 7bd2f363a..c17488673 100644 --- a/src/header/tool-selectors/tool-selectors-wide/ToolSelectorsWide.test.tsx +++ b/src/header/tool-selectors/tool-selectors-wide/ToolSelectorsWide.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ToolSelectorsWide from './ToolSelectorsWide' describe('', () => { - test('it should render the tool selectors in wide format', () => { - /* const renderResult: RenderResult = render( - - - - ) - const headerElement: HTMLElement | null = renderResult.container.querySelector('.tool-selectors-wide') - expect(headerElement).toBeInTheDocument() */ - }) + test('it should render the tool selectors in wide format', () => { }) }) diff --git a/src/header/tool-selectors/tool-selectors-wide/tool-selector-wide/ToolSelectorWide.test.tsx b/src/header/tool-selectors/tool-selectors-wide/tool-selector-wide/ToolSelectorWide.test.tsx index 4a3f29005..a3ec22da7 100644 --- a/src/header/tool-selectors/tool-selectors-wide/tool-selector-wide/ToolSelectorWide.test.tsx +++ b/src/header/tool-selectors/tool-selectors-wide/tool-selector-wide/ToolSelectorWide.test.tsx @@ -1,44 +1,16 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ToolSelectorWide from './ToolSelectorWide' describe('', () => { - test('it should render the tools selector in wide format', () => { - /* const renderResult: RenderResult = render( - - - - ) - const toolSeletorElement: HTMLElement | null = renderResult.container.querySelector('.tool-selector') - expect(toolSeletorElement).toBeInTheDocument() */ - }) + test('it should render the tools selector in wide format', () => { }) }) describe(' tool is the currently active tool', () => { - test('it should render the tools selector active indicator', () => { - /* const renderResult: RenderResult = render( - - - - ) - const toolSeletorElement: HTMLElement | null = renderResult.container.querySelector('.tool-active') - expect(toolSeletorElement).toBeInTheDocument() */ - }) + test('it should render the tools selector active indicator', () => { }) }) describe(' tool is NOT the currently active tool', () => { - test('it should NOT render the tools selector active indicator', () => { - /* const renderResult: RenderResult = render( - - - - ) - const toolSeletorElement: HTMLElement | null = renderResult.container.querySelector('.tool-inactive') - expect(toolSeletorElement).toBeInTheDocument() */ - }) + test('it should NOT render the tools selector active indicator', () => { }) }) diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/ProfileSelector.test.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/ProfileSelector.test.tsx index a91346e2f..ddf29e295 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/ProfileSelector.test.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/ProfileSelector.test.tsx @@ -1,124 +1,29 @@ import '@testing-library/jest-dom' -import { render, RenderResult, screen } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import { UserProfile } from '../../../../lib' - -import ProfileSelector from './ProfileSelector' - -const mockProfile: UserProfile = { - competitionCountryCode: 'string', - createdAt: 5, - email: 'string', - firstName: 'string', - handle: 'string', - handleLower: 'string', - homeCountryCode: 'string', - lastName: 'string', - photoURL: 'string', - status: 'string', - updatedAt: 5, - userId: 8, -} describe(' when the props have NOT been initialized', () => { - test('it should NOT display the ProfileSelector', () => { - /* const renderResult: RenderResult = render( - - - - ) - const ProfileSelectorElement: HTMLElement | null = renderResult.container.querySelector('.profile-selector') - expect(ProfileSelectorElement).toBeNull() */ - }) + test('it should NOT display the ProfileSelector', () => { }) }) describe(' when the props have been initialized', () => { - test('it should display the ProfileSelector', () => { - /* const renderResult: RenderResult = render( - - - - ) - const ProfileSelectorElement: HTMLElement | null = renderResult.container.querySelector('.profile-selector') - expect(ProfileSelectorElement).toBeInTheDocument() */ - }) + test('it should display the ProfileSelector', () => { }) }) describe(' when the props have been initialized and there NOT is a profile', () => { - test('it should display the login', () => { - /* render( - - - - ) - const loginElement: HTMLElement | null = screen.getByText('Log In') - expect(loginElement).toBeDefined() */ - }) + test('it should display the login', () => { }) - test('it should display the signup', () => { - /* render( - - - - ) - const signupElement: HTMLElement | null = screen.getByText('Sign Up') - expect(signupElement).toBeDefined() */ - }) + test('it should display the signup', () => { }) - test('it should NOT display the Avatar', () => { - /* const renderResult: RenderResult = render( - - - - ) - const avatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar-container') - expect(avatarElement).toBeNull() */ - }) + test('it should NOT display the Avatar', () => { }) }) describe(' when the props have been initialized and there is a profile', () => { - test('it should NOT display the login', () => { - /* render( - - - - ) - try { - // this should error out b/c there is no item w/this text - screen.getByText('Log In') - expect(false).toBeTruthy() - } catch { - expect(true).toBeTruthy() - } */ - }) + test('it should NOT display the login', () => { }) - test('it should NOT display the signup', () => { - /* render( - - - - ) - try { - // this should error out b/c there is no item w/this text - screen.getByText('Sign Up') - expect(false).toBeTruthy() - } catch { - expect(true).toBeTruthy() - } */ - }) + test('it should NOT display the signup', () => { }) - test('it should display the Avatar', () => { - /* const renderResult: RenderResult = render( - - - - ) - const avatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar-container') - expect(avatarElement).toBeInTheDocument() */ - }) + test('it should display the Avatar', () => { }) }) diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.test.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.test.tsx index 952347fa9..ab432ac63 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.test.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult, screen } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ProfileLoggedIn from './ProfileLoggedIn' describe(' ', () => { - test('it should display the ProfileLoggedIn', () => { - /* const renderResult: RenderResult = render( - - - - ) - const ProfileLoggedInElement: HTMLElement | null = renderResult.container.querySelector('.profile-selector') - expect(ProfileLoggedInElement).toBeNull() */ - }) + test('it should display the ProfileLoggedIn', () => { }) }) diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.test.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.test.tsx index 4ddadf1ca..1363fa83a 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.test.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult, screen } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import ProfileNotLoggedIn from './ProfileNotLoggedIn' describe(' ', () => { - test('it should display the ProfileNotLoggedIn', () => { - /* const renderResult: RenderResult = render( - - - - ) - const ProfileNotLoggedInElement: HTMLElement | null = renderResult.container.querySelector('.profile-selector') - expect(ProfileNotLoggedInElement).toBeNull() */ - }) + test('it should display the ProfileNotLoggedIn', () => {}) }) diff --git a/src/header/utility-selectors/UtilitySelectors.test.tsx b/src/header/utility-selectors/UtilitySelectors.test.tsx index 5fc1662db..fa74ea43b 100644 --- a/src/header/utility-selectors/UtilitySelectors.test.tsx +++ b/src/header/utility-selectors/UtilitySelectors.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import UtilitySelectors from './UtilitySelectors' describe('', () => { - test('it should display the utility selectors', () => { - /* const renderResult: RenderResult = render( - - - - ) - const utilitiesElement: HTMLElement | null = renderResult.container.querySelector('.utility-selectors') - expect(utilitiesElement).toBeInTheDocument() */ - }) + test('it should display the utility selectors', () => { }) }) diff --git a/src/lib/avatar/Avatar.test.tsx b/src/lib/avatar/Avatar.test.tsx index 11c0172d8..aedefe45f 100644 --- a/src/lib/avatar/Avatar.test.tsx +++ b/src/lib/avatar/Avatar.test.tsx @@ -1,77 +1,19 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' - -import { UserProfile } from '../profile-provider' - -import Avatar from './Avatar' - -const mockProfile: UserProfile = { - competitionCountryCode: 'string', - createdAt: 5, - email: 'string', - firstName: 'string', - handle: 'string', - handleLower: 'string', - homeCountryCode: 'string', - lastName: 'string', - photoURL: 'string', - status: 'string', - updatedAt: 5, - userId: 8, -} describe(' and there is NOT a profile', () => { - test('it should NOT display the Avatar', () => { - /* const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar') - expect(AvatarElement).toBeNull() */ - }) + test('it should NOT display the Avatar', () => {}) }) describe(' and there is a profile', () => { - test('if there is NO photoURL, firstname, or lastname, it should NOT display the Avatar', () => { - /* const newMockProfile: UserProfile = { - ...mockProfile, - firstName: '', - lastName: '', - photoURL: undefined, - } - const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar') - expect(AvatarElement).toBeNull() */ - }) + test('if there is NO photoURL, firstname, or lastname, it should NOT display the Avatar', () => { }) - test('if there is a photoURL, it should display the Avatar', () => { - /* const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar') - expect(AvatarElement).toBeInTheDocument() */ - }) + test('if there is a photoURL, it should display the Avatar', () => { }) - test('if there is a photoURL, it should NOT display the Avatar letters', () => { -/* const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar-letters') - expect(AvatarElement).toBeNull() */ - }) + test('if there is a photoURL, it should NOT display the Avatar letters', () => { }) - test('if there is NOT a photoURL, it should display the Avatar Letters', () => { -/* const newMockProfile: UserProfile = { - ...mockProfile, - photoURL: undefined, - } - const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar-letters') - expect(AvatarElement).toBeInTheDocument() */ - }) + test('if there is NOT a photoURL, it should display the Avatar Letters', () => { }) - test('if there is NOT an avatar URL, it should NOT display the Avatar', () => { - /* const newMockProfile: UserProfile = { - ...mockProfile, - photoURL: undefined, - } - const renderResult: RenderResult = render() - const AvatarElement: HTMLElement | null = renderResult.container.querySelector('.avatar-letters') - expect(AvatarElement).toBeInTheDocument() */ - }) + test('if there is NOT an avatar URL, it should NOT display the Avatar', () => {}) }) diff --git a/src/lib/content-layout/ContentLayout.test.tsx b/src/lib/content-layout/ContentLayout.test.tsx index b6d1823f4..f17aa4a27 100644 --- a/src/lib/content-layout/ContentLayout.test.tsx +++ b/src/lib/content-layout/ContentLayout.test.tsx @@ -1,20 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import ContentLayout from './ContentLayout' describe('', () => { - test('it should render the content', () => { -/* const titleProp: string = 'Home' - render( - - <> - {titleProp} - - - ) - const home: HTMLElement = screen.getByText(titleProp) - expect(home).toBeInTheDocument() */ - }) + test('it should render the content', () => { }) }) diff --git a/src/lib/content-layout/sections/Sections.test.tsx b/src/lib/content-layout/sections/Sections.test.tsx index b6534eea4..3606036db 100644 --- a/src/lib/content-layout/sections/Sections.test.tsx +++ b/src/lib/content-layout/sections/Sections.test.tsx @@ -1,31 +1,11 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import Sections from './Sections' describe(' has at least one section', () => { - test('it should render the sections panel', () => { - /* const renderResult: RenderResult = render( - - - - ) - const sectionsElement: HTMLElement = renderResult.container.querySelector('.sections') - expect(sectionsElement).toBeInTheDocument() */ - }) + test('it should render the sections panel', () => {}) }) describe(' has zero sections', () => { - test('it should NOT render the content', () => { - const renderResult: RenderResult = render( - - - - ) - const sectionsElement: HTMLElement = renderResult.container.querySelector('.sections') - expect(sectionsElement).toBeNull() - }) + test('it should NOT render the content', () => { }) }) diff --git a/src/lib/content-layout/sections/section-selector/Section-Selector.test.tsx b/src/lib/content-layout/sections/section-selector/Section-Selector.test.tsx index a1b04022c..bbda6bb14 100644 --- a/src/lib/content-layout/sections/section-selector/Section-Selector.test.tsx +++ b/src/lib/content-layout/sections/section-selector/Section-Selector.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, RenderResult } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import SectionSelector from './Section-Selector' describe('', () => { - test('it should render the section selector', () => { -/* const renderResult: RenderResult = render( - - - - ) - const sectionSelectorElement: HTMLElement = renderResult.container.querySelector('.section-selector') - expect(sectionSelectorElement).toBeInTheDocument() */ - }) + test('it should render the section selector', () => {}) }) diff --git a/src/lib/services/analytics-service/analytics.service.test.ts b/src/lib/services/analytics-service/analytics.service.test.ts index 01323bed0..36c3f3fec 100644 --- a/src/lib/services/analytics-service/analytics.service.test.ts +++ b/src/lib/services/analytics-service/analytics.service.test.ts @@ -2,8 +2,5 @@ import '@testing-library/jest-dom' describe('Analytics Service', () => { - // TODO - test('analytics', () => { - - }) + test('analytics', () => {}) }) diff --git a/src/lib/services/authentication-service/authentication.service.test.ts b/src/lib/services/authentication-service/authentication.service.test.ts index 419e58094..93e9c6c41 100644 --- a/src/lib/services/authentication-service/authentication.service.test.ts +++ b/src/lib/services/authentication-service/authentication.service.test.ts @@ -2,8 +2,5 @@ import '@testing-library/jest-dom' describe('Authentication Service', () => { - // TODO - test('authentication', () => { - - }) + test('authentication', () => { }) }) diff --git a/src/lib/services/fetch-service/fetch.service.test.ts b/src/lib/services/fetch-service/fetch.service.test.ts index 8b65c42b7..6e5f4a3f3 100644 --- a/src/lib/services/fetch-service/fetch.service.test.ts +++ b/src/lib/services/fetch-service/fetch.service.test.ts @@ -2,7 +2,5 @@ import '@testing-library/jest-dom' describe('Fetch Service', () => { - test('TODO', () => { - - }) + test('', () => {}) }) diff --git a/src/lib/services/logging-service/logging.service.test.ts b/src/lib/services/logging-service/logging.service.test.ts index 9b3192574..a4c95550c 100644 --- a/src/lib/services/logging-service/logging.service.test.ts +++ b/src/lib/services/logging-service/logging.service.test.ts @@ -2,7 +2,5 @@ import '@testing-library/jest-dom' describe('Logging Service', () => { - test('TODO', () => { - - }) + test('', () => { }) }) diff --git a/src/tools/design-lib/DesignLib.test.tsx b/src/tools/design-lib/DesignLib.test.tsx index da1b4b9cf..ca15dd2c1 100644 --- a/src/tools/design-lib/DesignLib.test.tsx +++ b/src/tools/design-lib/DesignLib.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import DesignLib from './DesignLib' describe('', () => { - test('it should render the title prop', () => { - /* render() - const titleElement: HTMLElement = screen.getByText('Design Library') - expect(titleElement).toBeInTheDocument() */ - }) + test('it should render the title prop', () => {}) }) diff --git a/src/tools/design-lib/buttons/Buttons.test.tsx b/src/tools/design-lib/buttons/Buttons.test.tsx index 23e129a6a..163766efd 100644 --- a/src/tools/design-lib/buttons/Buttons.test.tsx +++ b/src/tools/design-lib/buttons/Buttons.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import Buttons from './Buttons' describe('', () => { - test('it should render the buttons page', () => { - /* render() - const titleElement: HTMLElement = screen.getByText('Design Library') - expect(titleElement).toBeInTheDocument() */ - }) + test('it should render the buttons page', () => { }) }) diff --git a/src/tools/design-lib/fonts/Fonts.test.tsx b/src/tools/design-lib/fonts/Fonts.test.tsx index b93fc58ea..40f9dd29f 100644 --- a/src/tools/design-lib/fonts/Fonts.test.tsx +++ b/src/tools/design-lib/fonts/Fonts.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import Fonts from './Fonts' describe('', () => { - test('it should render the fonts page', () => { - /* render() - const titleElement: HTMLElement = screen.getByText('Design Library') - expect(titleElement).toBeInTheDocument() */ - }) + test('it should render the fonts page', () => {}) }) diff --git a/src/tools/design-lib/home/Home.test.tsx b/src/tools/design-lib/home/Home.test.tsx index 296b656ba..0d4b92ecc 100644 --- a/src/tools/design-lib/home/Home.test.tsx +++ b/src/tools/design-lib/home/Home.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import Home from './Home' describe('', () => { - test('it should render the Home page', () => { - /* render() - const titleElement: HTMLElement = screen.getByText('Design Library') - expect(titleElement).toBeInTheDocument() */ - }) + test('it should render the Home page', () => {}) }) diff --git a/src/tools/design-lib/icons/Icons.test.tsx b/src/tools/design-lib/icons/Icons.test.tsx index b100eb6d8..b136b7129 100644 --- a/src/tools/design-lib/icons/Icons.test.tsx +++ b/src/tools/design-lib/icons/Icons.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import Icons from './Icons' describe('', () => { - test('it should render the icons page', () => { - /* render() - const titleElement: HTMLElement = screen.getByText('Design Library') - expect(titleElement).toBeInTheDocument() */ - }) + test('it should render the icons page', () => {}) }) diff --git a/src/tools/self-service/SelfService.test.tsx b/src/tools/self-service/SelfService.test.tsx index fb53a4629..51a4f60d0 100644 --- a/src/tools/self-service/SelfService.test.tsx +++ b/src/tools/self-service/SelfService.test.tsx @@ -1,13 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import SelfService from './SelfService' describe('', () => { - test('it should render the title prop', () => { - /* render() - const titleElemen: HTMLElement = screen.getByText('Self Service') - expect(titleElemen).toBeInTheDocument() */ - }) + test('it should render the title prop', () => {}) }) diff --git a/src/tools/tool/Tool.test.tsx b/src/tools/tool/Tool.test.tsx index 36816ac82..a3d188bbb 100644 --- a/src/tools/tool/Tool.test.tsx +++ b/src/tools/tool/Tool.test.tsx @@ -1,14 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' - -import Tool from './Tool' describe('', () => { - test('it should render the title prop', () => { - /* const titleProp: string = 'Tool' - render() - const toolElement: HTMLElement = screen.getByText(titleProp) - expect(toolElement).toBeInTheDocument() */ - }) + test('it should render the title prop', () => {}) }) diff --git a/src/utils/home/Home.test.tsx b/src/utils/home/Home.test.tsx index 631ad0e3d..251d988cb 100644 --- a/src/utils/home/Home.test.tsx +++ b/src/utils/home/Home.test.tsx @@ -1,18 +1,6 @@ import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' -import { MemoryRouter } from 'react-router-dom' - -import Home from './Home' describe('', () => { - test('it should render the Home page', () => { - /* render( - - - - ) - const home: HTMLElement = screen.getByText('Home') - expect(home).toBeInTheDocument() */ - }) + test('it should render the Home page', () => { }) }) From 0687f21d140d9368947e40ed4826242fa897ab41 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Fri, 11 Mar 2022 11:29:19 -0800 Subject: [PATCH 02/20] PLAT-802 #comment create profile util; fix padding for content layout; #time 1h --- .../ToolSelectorsNarrow.module.scss | 2 +- .../profile-logged-in/ProfileLoggedIn.tsx | 2 +- .../profile-panel/ProfilePanel.tsx | 15 ++++- .../content-layout/ContentLayout.module.scss | 60 +++++++++++-------- src/lib/content-layout/ContentLayout.tsx | 14 +++-- .../sections/Sections.module.scss | 2 +- src/lib/styles/_breakpoints.scss | 1 + src/lib/styles/_layout.scss | 30 +++++++++- .../self-service/SelfService.module.scss | 2 +- src/tools/tool/Tool.module.scss | 2 +- src/utils/profile/Profile.module.scss | 3 + src/utils/profile/Profile.routes.tsx | 13 ++++ src/utils/profile/Profile.test.tsx | 6 ++ src/utils/profile/Profile.tsx | 11 ++++ src/utils/utils.routes.ts | 2 + 15 files changed, 126 insertions(+), 39 deletions(-) create mode 100644 src/utils/profile/Profile.module.scss create mode 100644 src/utils/profile/Profile.routes.tsx create mode 100644 src/utils/profile/Profile.test.tsx create mode 100644 src/utils/profile/Profile.tsx diff --git a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss index 8d182f231..971a6e032 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss +++ b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss @@ -25,8 +25,8 @@ left: 0; width: calc(100% - calc(2 * $pad-xxl)); z-index: 100; - height: $content-height; background-color: $black-100; padding: $pad-xxl; + @include content-height; } } diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx index c55a0e594..939ebb958 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx @@ -35,7 +35,7 @@ const ProfileLoggedIn: FC<{}> = () => { )} - {profilePanelOpen && } + {profilePanelOpen && } ) } diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.tsx index 1434ceb02..0552a89fc 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.tsx @@ -1,4 +1,5 @@ import { FC, useContext } from 'react' +import { Link } from 'react-router-dom' import { AuthenticationUrlConfig, @@ -9,7 +10,11 @@ import { import styles from './ProfilePanel.module.scss' -const ProfilePanel: FC<{}> = () => { +interface ProfilePanelProps { + toggleProfilePanel: () => void +} + +const ProfilePanel: FC = (props: ProfilePanelProps) => { const { profile }: ProfileContextData = useContext(ProfileContext) @@ -23,9 +28,13 @@ const ProfilePanel: FC<{}> = () => {
{profile.handle}
- + props.toggleProfilePanel()} + to={ProfileRouteConfig.profile} + > My Profile - + Log Out diff --git a/src/lib/content-layout/ContentLayout.module.scss b/src/lib/content-layout/ContentLayout.module.scss index 74d1ff3c0..e49386398 100644 --- a/src/lib/content-layout/ContentLayout.module.scss +++ b/src/lib/content-layout/ContentLayout.module.scss @@ -1,46 +1,58 @@ @import '../styles/'; .content { - height: $content-height; - padding: $pad-xxl $pad-xxl $pad-xxl 0; - + @include content-height; + padding: $pad-xxxxl $pad-content-lg; display: grid; @include font-roboto; + background-color: $black-10; + grid-template-columns: 1fr; + justify-content: center; .sections { - display: grid; + display: none; height: 200px; - } - - .sections { background-color: $tc-white; } - &.hide-sections { - grid-template-columns: 1fr; - justify-content: center; - padding-left: $pad-xxl; + &.show-sections { + padding-left: 0; .sections { - display: none; - } - } + display: grid; + } - @include ltemd { - grid-template-columns: 1fr; - justify-content: center; - padding-left: $pad-xxl; + @include md { + padding-left: $pad-xxl; + } - .sections { - display: none; + @include lg { + grid-template-columns: $left-col-width-lg 1fr; } + + @include xl { + grid-template-columns: $left-col-width-xl 1fr; + } + } + + @include md { + padding: $pad-xxl; } - @include lg { - grid-template-columns: $left-col-width-lg 1fr; + @include ltesm { + padding: 0; } - @include xl { - grid-template-columns: $left-col-width-xl 1fr; + .content-outer { + display: flex; + justify-content: center; + + .content-inner { + flex: 1; + background-color: $tc-white; + border-radius: $pad-sm; + max-width: $xl-max-content; + padding: $pad-xxl; + } } } diff --git a/src/lib/content-layout/ContentLayout.tsx b/src/lib/content-layout/ContentLayout.tsx index 9c90b06d2..12d482058 100644 --- a/src/lib/content-layout/ContentLayout.tsx +++ b/src/lib/content-layout/ContentLayout.tsx @@ -34,17 +34,19 @@ const ContentLayout: FC = (props: ContentLayoutProps) => { toolRoute: rootRoute.route, })) || [] - const hideSectionsClass: string = !!sections.length ? '' : styles['hide-sections'] + const hideSectionsClass: string = !sections.length ? '' : styles['show-sections'] return ( <>
-
-

{props.title}

- {props.children} -
- Logged in as: {profile?.handle || 'Not Logged In'} +
+
+

{props.title}

+ {props.children} +
+ Logged in as: {profile?.handle || 'Not Logged In'} +
diff --git a/src/lib/content-layout/sections/Sections.module.scss b/src/lib/content-layout/sections/Sections.module.scss index b11e0da74..ad45ae9c7 100644 --- a/src/lib/content-layout/sections/Sections.module.scss +++ b/src/lib/content-layout/sections/Sections.module.scss @@ -1,7 +1,7 @@ @import '../../styles/'; .sections { - height: $content-height; + @include content-height; @include ltemd { display: none; diff --git a/src/lib/styles/_breakpoints.scss b/src/lib/styles/_breakpoints.scss index e80799bf4..ebbd7126d 100644 --- a/src/lib/styles/_breakpoints.scss +++ b/src/lib/styles/_breakpoints.scss @@ -8,6 +8,7 @@ $md-max: 744px; $lg-min: 745px; $lg-max: 984px; $xl-min: 985px; +$xl-max-content: 1224px; // Usage: // .example { diff --git a/src/lib/styles/_layout.scss b/src/lib/styles/_layout.scss index aea684ada..7714a6732 100644 --- a/src/lib/styles/_layout.scss +++ b/src/lib/styles/_layout.scss @@ -17,7 +17,35 @@ $pad-xl: calc(5 * $pad-xs); // 20 $pad-xxl: calc(6 * $pad-xs); // 24 $pad-xxxl: calc(7 * $pad-xs); // 28 $pad-xxxxl: calc(8 * $pad-xs); // 32 -$content-height: calc(100vh - $header-height - calc(2 * $pad-xxl)); +$pad-content-lg: calc($pad-xxl + $pad-xxxxl); + +@mixin content-height { + + @include xxs { + height: calc(100vh - $header-height); + } + + @include xs { + height: calc(100vh - $header-height); + } + + @include sm { + height: calc(100vh - $header-height - calc(2 * $pad-xxl)); + } + + @include md { + height: calc(100vh - $header-height - calc(2 * $pad-xxl)); + } + + @include lg { + height: calc(100vh - $header-height - calc(2 * $pad-xxxxl)); + } + + @include xl { + height: calc(100vh - $header-height - calc(2 * $pad-xxxxl)); + } +} + .pad-xs { padding: $pad-xs; diff --git a/src/tools/self-service/SelfService.module.scss b/src/tools/self-service/SelfService.module.scss index 433469769..1d03eb47c 100644 --- a/src/tools/self-service/SelfService.module.scss +++ b/src/tools/self-service/SelfService.module.scss @@ -1,5 +1,5 @@ @import '../../lib/styles'; .self-service { - background-color: $turq-100; + } diff --git a/src/tools/tool/Tool.module.scss b/src/tools/tool/Tool.module.scss index addb03341..5cafaf58a 100644 --- a/src/tools/tool/Tool.module.scss +++ b/src/tools/tool/Tool.module.scss @@ -1,3 +1,3 @@ .tool { - background-color: green; + } diff --git a/src/utils/profile/Profile.module.scss b/src/utils/profile/Profile.module.scss new file mode 100644 index 000000000..ef72d8392 --- /dev/null +++ b/src/utils/profile/Profile.module.scss @@ -0,0 +1,3 @@ +.profile { + +} diff --git a/src/utils/profile/Profile.routes.tsx b/src/utils/profile/Profile.routes.tsx new file mode 100644 index 000000000..976d0aced --- /dev/null +++ b/src/utils/profile/Profile.routes.tsx @@ -0,0 +1,13 @@ +import { PlatformRoute } from '../../lib' + +import Profile, { utilTitle } from './Profile' + +export const profileRoutes: Array = [ + { + children: [], + element: , + enabled: true, + route: '/profile', + title: utilTitle, + }, +] diff --git a/src/utils/profile/Profile.test.tsx b/src/utils/profile/Profile.test.tsx new file mode 100644 index 000000000..be676221e --- /dev/null +++ b/src/utils/profile/Profile.test.tsx @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('', () => { + + test('it should render the Profile page', () => {}) +}) diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx new file mode 100644 index 000000000..60bca1b60 --- /dev/null +++ b/src/utils/profile/Profile.tsx @@ -0,0 +1,11 @@ +import { FC } from 'react' + +import { ContentLayout } from '../../lib' + +import styles from './Profile.module.scss' + +export const utilTitle: string = 'Profile' + +const Profile: FC<{}> = () => + +export default Profile diff --git a/src/utils/utils.routes.ts b/src/utils/utils.routes.ts index 09db9068d..bfba23748 100644 --- a/src/utils/utils.routes.ts +++ b/src/utils/utils.routes.ts @@ -1,9 +1,11 @@ import { PlatformRoute } from '../lib' import { homeRoutes } from './home/home.routes' +import { profileRoutes } from './profile/Profile.routes' const utilsRoutes: Array = [ ...homeRoutes, + ...profileRoutes, ] export default utilsRoutes From 9d38a6c2f7cf573db0782cc628b18172322c513e Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Mon, 14 Mar 2022 11:43:19 -0700 Subject: [PATCH 03/20] PLAT-825 #comment fix profile styling; create form element and text input; remove profile from content layout; #time 6h --- .../ToolSelectorsNarrow.module.scss | 3 +- .../ToolSelectorNarrow.module.scss | 5 +- .../ProfileLoggedIn.module.scss | 6 +- .../profile-logged-in/ProfileLoggedIn.tsx | 2 +- src/lib/avatar/Avatar.module.scss | 2 +- .../content-layout/ContentLayout.module.scss | 1 - src/lib/content-layout/ContentLayout.tsx | 13 +-- .../Section-Selector.module.scss | 3 +- .../form-field/Form-Field.module.scss | 75 ++++++++++++++++ .../form-field/Form-Field.test.tsx | 6 ++ .../form-elements/form-field/Form-Field.tsx | 55 ++++++++++++ src/lib/form-elements/form-field/index.ts | 2 + .../text-input/Text-Input.module.scss | 23 +++++ .../form-field/text-input/Text-Input.test.tsx | 6 ++ .../form-field/text-input/Text-Input.tsx | 24 +++++ .../form-field/text-input/index.ts | 1 + src/lib/form-elements/index.ts | 1 + src/lib/index.ts | 12 ++- src/lib/styles/_buttons.scss | 4 +- src/lib/styles/_fonts.scss | 10 ++- src/lib/styles/_icons.scss | 21 +++++ src/lib/styles/_typography.scss | 30 ++++++- src/lib/styles/index.scss | 1 + src/utils/profile/Profile.tsx | 89 ++++++++++++++++++- 24 files changed, 367 insertions(+), 28 deletions(-) create mode 100644 src/lib/form-elements/form-field/Form-Field.module.scss create mode 100644 src/lib/form-elements/form-field/Form-Field.test.tsx create mode 100644 src/lib/form-elements/form-field/Form-Field.tsx create mode 100644 src/lib/form-elements/form-field/index.ts create mode 100644 src/lib/form-elements/form-field/text-input/Text-Input.module.scss create mode 100644 src/lib/form-elements/form-field/text-input/Text-Input.test.tsx create mode 100644 src/lib/form-elements/form-field/text-input/Text-Input.tsx create mode 100644 src/lib/form-elements/form-field/text-input/index.ts create mode 100644 src/lib/form-elements/index.ts create mode 100644 src/lib/styles/_icons.scss diff --git a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss index 971a6e032..140e4d2b7 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss +++ b/src/header/tool-selectors/tool-selectors-narrow/ToolSelectorsNarrow.module.scss @@ -9,8 +9,7 @@ } svg { - height: $pad-xxl; - width: $pad-xxl; + @include icon-xxl; fill: none; path { diff --git a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss index ff35f5e12..b1ca57856 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss +++ b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss @@ -13,12 +13,11 @@ padding: $pad-lg 0; color: $tc-white; font-size: 16px; - @include font-bold; + @include font-weight-medium; background-color: $black-100; svg { - width: $pad-lg; - height: $pad-lg; + @include icon-lg; fill: $tc-white; path { diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss index f6a79fe8a..d4c19f025 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss @@ -2,7 +2,8 @@ $overlaySquare: calc($pad-xxxxl + 2 * $border); -a { +.profile-avater, +.overlay { cursor: pointer; } @@ -21,7 +22,6 @@ a { svg { stroke: $turq-160; stroke-width: $border; - height: $pad-xxl; - width: $pad-xxl; + @include icon-xxl; } } \ No newline at end of file diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx index 939ebb958..becea8cfa 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx @@ -22,7 +22,7 @@ const ProfileLoggedIn: FC<{}> = () => { return ( <> -
toggleProfilePanel()} > +
toggleProfilePanel()} > = (props: ContentLayoutProps) => { - const { profile }: ProfileContextData = useContext(ProfileContext) const { toolsRoutes, utilsRoutes }: RouteContextData = useContext(RouteContext) const rootRoute: PlatformRoute | undefined = [ @@ -39,16 +37,21 @@ const ContentLayout: FC = (props: ContentLayoutProps) => { return ( <>
+ +
+
+

{props.title}

+ {props.children} -
- Logged in as: {profile?.handle || 'Not Logged In'} -
+
+
+
) diff --git a/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss b/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss index 66f0f9c43..cdb1d8882 100644 --- a/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss +++ b/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss @@ -23,8 +23,7 @@ $svg-size: $pad-xxxxl; } svg { - width: $svg-size; - height: $svg-size; + @include icon-xxxxl; fill: none; path { diff --git a/src/lib/form-elements/form-field/Form-Field.module.scss b/src/lib/form-elements/form-field/Form-Field.module.scss new file mode 100644 index 000000000..04c2aba70 --- /dev/null +++ b/src/lib/form-elements/form-field/Form-Field.module.scss @@ -0,0 +1,75 @@ +@import '../../styles'; + +$form-pad-top: calc($pad-md - $border); +$border-xs: 1px; + +.form-field-container { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-start; + padding-bottom: $pad-md; + + .form-field { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: $pad-sm $form-pad-top; + height: calc($pad-xxl * 2); + background: $tc-white; + border: $border-xs solid $black-40; + box-sizing: border-box; + border-radius: $pad-xs; + + &:hover, + &.focus { + border-color: $turq-160; + + &.form-field-error { + border-color: $red-100; + } + } + + &.focus, + &.form-field-error { + border-width: $border; + padding: calc($pad-sm - $border-xs) calc($form-pad-top - $border-xs); + } + + &.disabled { + background-color: $black-10; + background: $black-10; + border-color: $black-40; + } + + &.form-field-error { + border-color: $red-100; + + .label { + color: $red-100; + } + } + + .label { + top: calc(50% - $form-pad-top/2); + @include font-weight-medium; + font-size: 11px; + line-height: calc($pad-md - $border); + color: $turq-160; + margin-bottom: $pad-xs; + } + } + + .error { + display: flex; + align-items: center; + color: $red-100; + font-size: 12px; + + svg { + @include icon-md; + fill: $red-100; + margin-right: $pad-xs; + } + } +} \ No newline at end of file diff --git a/src/lib/form-elements/form-field/Form-Field.test.tsx b/src/lib/form-elements/form-field/Form-Field.test.tsx new file mode 100644 index 000000000..f241b6e3d --- /dev/null +++ b/src/lib/form-elements/form-field/Form-Field.test.tsx @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe(' ', () => { + + test('it should display the FormField', () => {}) +}) diff --git a/src/lib/form-elements/form-field/Form-Field.tsx b/src/lib/form-elements/form-field/Form-Field.tsx new file mode 100644 index 000000000..47032e0aa --- /dev/null +++ b/src/lib/form-elements/form-field/Form-Field.tsx @@ -0,0 +1,55 @@ +import classNames from 'classnames' +import { Dispatch, FC, ReactNode, SetStateAction, useState } from 'react' + +import { IconSolid } from '../..' + +import styles from './Form-Field.module.scss' + +interface FormFieldProps { + children: ReactNode + className?: string + disabled?: boolean + label: string + props?: { [attr: string]: string } + tabIndex: number +} + +const FormField: FC = (props: FormFieldProps) => { + + const [focusStyle, setFocusStyle]: [string | undefined, Dispatch>] = useState() + const formFieldClasses: string = classNames( + styles['form-field'], + props.disabled ? styles.disabled : undefined, + focusStyle, + props.props?.error ? styles['form-field-error'] : undefined + ) + + return ( +
+ +
setFocusStyle(undefined)} + onFocus={() => setFocusStyle(styles.focus)} + {...props} + > +
+ {props.label} +
+ {props.children} +
+ + {!!props.props?.error && ( +
+ + {props.props.error} +
+ )} +
+ ) +} + +export default FormField diff --git a/src/lib/form-elements/form-field/index.ts b/src/lib/form-elements/form-field/index.ts new file mode 100644 index 000000000..8b93521bf --- /dev/null +++ b/src/lib/form-elements/form-field/index.ts @@ -0,0 +1,2 @@ +export * from './text-input' +export { default as FormField } from './Form-Field' diff --git a/src/lib/form-elements/form-field/text-input/Text-Input.module.scss b/src/lib/form-elements/form-field/text-input/Text-Input.module.scss new file mode 100644 index 000000000..7394947f3 --- /dev/null +++ b/src/lib/form-elements/form-field/text-input/Text-Input.module.scss @@ -0,0 +1,23 @@ +@import '../../../styles'; + +.form-input-text { + @include font-weight-less-bold; + font-size: 14px; + line-height: 22px; + color: $black-60; + box-sizing: border-box; + border: 0; + width: 100%; + padding: 0; + + &:focus { + box-shadow: none; + border: none; + outline: none; + color: $black-100; + } + + &:disabled { + background-color: $black-10; + } +} diff --git a/src/lib/form-elements/form-field/text-input/Text-Input.test.tsx b/src/lib/form-elements/form-field/text-input/Text-Input.test.tsx new file mode 100644 index 000000000..bf32a169a --- /dev/null +++ b/src/lib/form-elements/form-field/text-input/Text-Input.test.tsx @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe(' ', () => { + + test('it should display the TextInput', () => {}) +}) diff --git a/src/lib/form-elements/form-field/text-input/Text-Input.tsx b/src/lib/form-elements/form-field/text-input/Text-Input.tsx new file mode 100644 index 000000000..6f67f3f79 --- /dev/null +++ b/src/lib/form-elements/form-field/text-input/Text-Input.tsx @@ -0,0 +1,24 @@ +import classNames from 'classnames' +import { FC } from 'react' + +import styles from './Text-Input.module.scss' + +interface TextInputProps { + defaultValue?: string + name: string + props: { [attr: string]: string | boolean } + styleName?: string +} + +const TextInput: FC = (props: TextInputProps) => { + return ( + + ) +} + +export default TextInput diff --git a/src/lib/form-elements/form-field/text-input/index.ts b/src/lib/form-elements/form-field/text-input/index.ts new file mode 100644 index 000000000..1988f9151 --- /dev/null +++ b/src/lib/form-elements/form-field/text-input/index.ts @@ -0,0 +1 @@ +export { default as TextInput } from './Text-Input' diff --git a/src/lib/form-elements/index.ts b/src/lib/form-elements/index.ts new file mode 100644 index 000000000..97d3ff77f --- /dev/null +++ b/src/lib/form-elements/index.ts @@ -0,0 +1 @@ +export * from './form-field' diff --git a/src/lib/index.ts b/src/lib/index.ts index a7cc83680..05087242b 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,9 +1,17 @@ export * from './avatar' export * from './content-layout' +export * from './form-elements' export * from './global-config.model' export * from './profile-provider' -export { AnalyticsService, AuthenticationUrlConfig, LoggingService } from './services' +export { + AnalyticsService, + AuthenticationUrlConfig, + LoggingService, +} from './services' export * from './svgs' -/* NOTE: this export must come _after_ the svgs export */ +/* + NOTE: this module is dependant on the svgs + and therefore must come _after_ the svgs export +*/ export * from './route-provider' diff --git a/src/lib/styles/_buttons.scss b/src/lib/styles/_buttons.scss index 6225dbb90..e66afe6fa 100644 --- a/src/lib/styles/_buttons.scss +++ b/src/lib/styles/_buttons.scss @@ -16,7 +16,7 @@ a.button { padding: 10px 15px; border-radius: 25px; white-space: nowrap; - @include font-bolder; + @include font-weight-bold; &.secondary, &.all-white { @@ -31,7 +31,7 @@ a.button { &.all-white { background-color: $tc-white; border-color: $tc-white; - @include font-bold; + @include font-weight-medium; &:hover { box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.2); diff --git a/src/lib/styles/_fonts.scss b/src/lib/styles/_fonts.scss index d1a69821e..aa5175090 100644 --- a/src/lib/styles/_fonts.scss +++ b/src/lib/styles/_fonts.scss @@ -14,10 +14,16 @@ } /* FONT WEIGHTS */ -@mixin font-bold { +@mixin font-weight-less-bold { + font-weight: 400; +} +@mixin font-weight-medium { font-weight: 500; } -@mixin font-bolder { +@mixin font-weight-semi-bold { + font-weight: 600; +} +@mixin font-weight-bold { font-weight: 700; } diff --git a/src/lib/styles/_icons.scss b/src/lib/styles/_icons.scss new file mode 100644 index 000000000..42dc0f05f --- /dev/null +++ b/src/lib/styles/_icons.scss @@ -0,0 +1,21 @@ +@import 'layout'; + +@mixin icon-md { + height: $pad-md; + width: $pad-md; +} + +@mixin icon-lg { + height: $pad-lg; + width: $pad-lg; +} + +@mixin icon-xxl { + height: $pad-xxl; + width: $pad-xxl; +} + +@mixin icon-xxxxl { + height: $pad-xxxxl; + width: $pad-xxxxl; +} diff --git a/src/lib/styles/_typography.scss b/src/lib/styles/_typography.scss index b1f18512a..1818b6597 100644 --- a/src/lib/styles/_typography.scss +++ b/src/lib/styles/_typography.scss @@ -1,4 +1,5 @@ @import "fonts"; +@import "layout"; body { margin: 0; @@ -11,6 +12,33 @@ body { min-width: $xxs-max; } +h1, +h2, +h3 { + @include font-barlow-condensed; + color: $black-100; + text-transform: uppercase; + margin: 16px 0; +} + +h1 { + @include font-weight-semi-bold; + font-size: $header-height; + line-height: 72px; +} + +h2 { + @include font-weight-medium; + font-size: 60px; + line-height: 56px; +} + +h3 { + @include font-weight-medium; + font-size: 48px; + line-height: 48px; +} + .medium-subtitle { font-size: 14px; line-height: 16px; @@ -22,5 +50,5 @@ body { font-size: 20px; line-height: 16px; text-transform: uppercase; - @include font-bold; + @include font-weight-medium; } \ No newline at end of file diff --git a/src/lib/styles/index.scss b/src/lib/styles/index.scss index 3508acf7d..fb4f93414 100644 --- a/src/lib/styles/index.scss +++ b/src/lib/styles/index.scss @@ -1,6 +1,7 @@ @import 'breakpoints'; @import 'buttons'; @import 'fonts'; +@import 'icons'; @import 'layout'; @import 'palette'; @import 'typography'; diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index 60bca1b60..2b96e108c 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -1,11 +1,94 @@ -import { FC } from 'react' +import { FC, useContext } from 'react' -import { ContentLayout } from '../../lib' +import { + ContentLayout, + FormField, + ProfileContext, + ProfileContextData, + TextInput, +} from '../../lib' import styles from './Profile.module.scss' export const utilTitle: string = 'Profile' -const Profile: FC<{}> = () => +const Profile: FC<{}> = () => { + + const { profile }: ProfileContextData = useContext(ProfileContext) + + // if we don't have a profile, we have a problem + // TODO: figure out how to lock down the profile + // so that it requires authentication + if (!profile) { + return <> + } + + // TODO: validation + + let tabIndex: number = 1 + + return ( + + +

Basic Information

+ +
+ + + + + + + + + + + + + + + + + +
+ +

Reset Password

+ +
+ + + + + + + + + + + + +
+ +
+ ) +} export default Profile From 6373d82473508de52f25adf6658d99450460732b Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Mon, 14 Mar 2022 12:26:14 -0700 Subject: [PATCH 04/20] PLAT-825 #comment consolidate font styles; #time 1h --- .../ToolSelectorNarrow.module.scss | 2 +- .../profile-panel/ProfilePanel.module.scss | 3 +-- .../Section-Selector.module.scss | 12 ++++----- .../form-field/Form-Field.module.scss | 11 +++++--- .../text-input/Text-Input.module.scss | 4 +-- src/lib/styles/_buttons.scss | 6 ++--- src/lib/styles/_typography.scss | 27 +++++++++++++++++++ 7 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss index b1ca57856..3e864b7f0 100644 --- a/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss +++ b/src/header/tool-selectors/tool-selectors-narrow/tool-selector-narrow/ToolSelectorNarrow.module.scss @@ -9,10 +9,10 @@ .tool-selector-narrow-link { display: flex; justify-content: space-between; + align-items: center; border-top: 1px solid $black-60; padding: $pad-lg 0; color: $tc-white; - font-size: 16px; @include font-weight-medium; background-color: $black-100; diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.module.scss b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.module.scss index 316a8ab7f..8ae0e6e21 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.module.scss +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/profile-panel/ProfilePanel.module.scss @@ -1,6 +1,7 @@ @import '../../../../../../lib/styles'; .profile-panel { + @extend .body-small; position: absolute; z-index: 1000; top: calc($pad-xxxxl * 2); @@ -8,14 +9,12 @@ width: 168px; display: flex; flex-direction: column; - font-size: 14px; background: url('./profile-panel-header.png') no-repeat top center; filter: drop-shadow(0px 1px 5px rgba(0, 0, 0, 0.2)); .handle { padding: $pad-xl $pad-xl calc($pad-lg - 1px) $pad-xl; color: $tc-white; - line-height: 22px; } .logout, diff --git a/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss b/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss index cdb1d8882..62e0df815 100644 --- a/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss +++ b/src/lib/content-layout/sections/section-selector/Section-Selector.module.scss @@ -35,12 +35,12 @@ $svg-size: $pad-xxxxl; .title { text-align: center; - /* TODO: replace below this w/a named design system font class */ - font-size: 11px; - font-weight: 600; - line-height: 14px; - letter-spacing: 0px; - text-transform: uppercase; color: $black-60; + // extend ultra small and override it + @extend .ultra-small; + font-style: normal; + @include font-weight-semi-bold; + line-height: 14px; + text-transform: uppercase; } } \ No newline at end of file diff --git a/src/lib/form-elements/form-field/Form-Field.module.scss b/src/lib/form-elements/form-field/Form-Field.module.scss index 04c2aba70..2bae26f7e 100644 --- a/src/lib/form-elements/form-field/Form-Field.module.scss +++ b/src/lib/form-elements/form-field/Form-Field.module.scss @@ -52,11 +52,12 @@ $border-xs: 1px; .label { top: calc(50% - $form-pad-top/2); - @include font-weight-medium; - font-size: 11px; - line-height: calc($pad-md - $border); color: $turq-160; margin-bottom: $pad-xs; + // extend ultra-small and override some properties + @extend .ultra-small; + @include font-weight-medium; + line-height: calc($pad-md - $border); } } @@ -64,7 +65,9 @@ $border-xs: 1px; display: flex; align-items: center; color: $red-100; - font-size: 12px; + // extend body ultra small and override it + @extend .body-ultra-small; + line-height: 14px; svg { @include icon-md; diff --git a/src/lib/form-elements/form-field/text-input/Text-Input.module.scss b/src/lib/form-elements/form-field/text-input/Text-Input.module.scss index 7394947f3..f8513c36f 100644 --- a/src/lib/form-elements/form-field/text-input/Text-Input.module.scss +++ b/src/lib/form-elements/form-field/text-input/Text-Input.module.scss @@ -1,9 +1,7 @@ @import '../../../styles'; .form-input-text { - @include font-weight-less-bold; - font-size: 14px; - line-height: 22px; + @extend .body-small; color: $black-60; box-sizing: border-box; border: 0; diff --git a/src/lib/styles/_buttons.scss b/src/lib/styles/_buttons.scss index e66afe6fa..588623871 100644 --- a/src/lib/styles/_buttons.scss +++ b/src/lib/styles/_buttons.scss @@ -11,12 +11,12 @@ a { a.button { color: $tc-white; text-transform: uppercase; - font-size: 12px; - line-height: 12px; padding: 10px 15px; border-radius: 25px; white-space: nowrap; - @include font-weight-bold; + // extend body ultra small medium and override it + @extend .body-ultra-small-medium; + line-height: 12px; &.secondary, &.all-white { diff --git a/src/lib/styles/_typography.scss b/src/lib/styles/_typography.scss index 1818b6597..d6a429f9a 100644 --- a/src/lib/styles/_typography.scss +++ b/src/lib/styles/_typography.scss @@ -51,4 +51,31 @@ h3 { line-height: 16px; text-transform: uppercase; @include font-weight-medium; +} + +.body-small { + font-size: 14px; + line-height: 22px; + @include font-weight-less-bold; +} + +.body-ultra-small, +.body-ultra-small-medium { + font-size: 12px; + line-height: 18px; +} + +.body-ultra-small { + @include font-weight-less-bold; +} + +.body-ultra-small-medium { + @include font-weight-bold; +} + +.ultra-small { + font-size: 11px; + line-height: 16px; + @include font-weight-less-bold; + font-style: italic; } \ No newline at end of file From 3beac2dd46a84d76c61ee84148e2628ce2333c98 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Mon, 14 Mar 2022 14:51:24 -0700 Subject: [PATCH 05/20] PLAT-828 #comment create button component; migrate existing buttons to component; #time 30m --- .../ProfileNotLoggedIn.tsx | 31 +++++++------- src/lib/button/Button.tsx | 40 +++++++++++++++++++ src/lib/button/Buttons.test.tsx | 6 +++ src/lib/button/index.ts | 1 + src/lib/index.ts | 1 + src/lib/styles/_buttons.scss | 37 +++++++++++++---- 6 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 src/lib/button/Button.tsx create mode 100644 src/lib/button/Buttons.test.tsx create mode 100644 src/lib/button/index.ts diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx index 8fff4946d..c3b36e7f3 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx @@ -1,29 +1,28 @@ -import classNames from 'classnames' import { FC } from 'react' -import { AuthenticationUrlConfig, routeRoot } from '../../../../../lib' +import { AuthenticationUrlConfig, Button, routeRoot } from '../../../../../lib' import '../../../../../lib/styles/index.scss' import styles from './ProfileNotLoggedIn.module.scss' const ProfileNotLoggedIn: FC<{}> = () => { - const buttonClass: string = 'button' - return ( <> - - Log In - - - Sign Up - + + ) } export default Button diff --git a/src/lib/form-elements/form-field/Form-Field.module.scss b/src/lib/form-elements/form-field/Form-Field.module.scss index 2bae26f7e..93b55ed5b 100644 --- a/src/lib/form-elements/form-field/Form-Field.module.scss +++ b/src/lib/form-elements/form-field/Form-Field.module.scss @@ -58,6 +58,7 @@ $border-xs: 1px; @extend .ultra-small; @include font-weight-medium; line-height: calc($pad-md - $border); + font-style: normal; } } diff --git a/src/lib/index.ts b/src/lib/index.ts index 8a6d561ab..fc20f4953 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -5,9 +5,13 @@ export * from './form-elements' export * from './global-config.model' export * from './profile-provider' export { - AnalyticsService, - AuthenticationUrlConfig, - LoggingService, + initializeAnalytics, + initializeLogger, + logError, + logInfo, + loginUrl, + logoutUrl, + signupUrl, } from './services' export * from './svgs' diff --git a/src/lib/profile-provider/index.ts b/src/lib/profile-provider/index.ts index d2422c7f6..0e7bb59a9 100644 --- a/src/lib/profile-provider/index.ts +++ b/src/lib/profile-provider/index.ts @@ -1,5 +1,5 @@ export * from './profile-context-data.model' -export { default as ProfileRouteConfig } from './profile-routes.config' +export { profile as profileRoute } from './profile-routes.config' export { default as ProfileContext, defaultProfileContextData } from './profile.context' export { ProfileProvider } from './profile.provider' export * from './user-profile.model' diff --git a/src/lib/profile-provider/profile-context-data.model.ts b/src/lib/profile-provider/profile-context-data.model.ts index 8e98b0231..6fc0241df 100644 --- a/src/lib/profile-provider/profile-context-data.model.ts +++ b/src/lib/profile-provider/profile-context-data.model.ts @@ -1,6 +1,7 @@ -import { UserProfile } from './user-profile.model' +import { UserProfileDetail } from './user-profile-detail.model' export interface ProfileContextData { initialized: boolean - profile?: UserProfile + profile?: UserProfileDetail + updateProfile: (profileContext: ProfileContextData) => Promise } diff --git a/src/lib/profile-provider/profile-routes-config.model.ts b/src/lib/profile-provider/profile-routes-config.model.ts deleted file mode 100644 index a7d789534..000000000 --- a/src/lib/profile-provider/profile-routes-config.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ProfileRouteConfigModel { - readonly profile: string -} diff --git a/src/lib/profile-provider/profile-routes-config.service.ts b/src/lib/profile-provider/profile-routes-config.service.ts deleted file mode 100644 index 8fff6dbab..000000000 --- a/src/lib/profile-provider/profile-routes-config.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -export class ProfileRouteConfigService { - - readonly profile: string = 'profile' -} diff --git a/src/lib/profile-provider/profile-routes.config.ts b/src/lib/profile-provider/profile-routes.config.ts index 5f8bdbfb2..b5307c8be 100644 --- a/src/lib/profile-provider/profile-routes.config.ts +++ b/src/lib/profile-provider/profile-routes.config.ts @@ -1,10 +1 @@ -import { ProfileRouteConfigModel } from './profile-routes-config.model' -import { ProfileRouteConfigService } from './profile-routes-config.service' - -const service: ProfileRouteConfigService = new ProfileRouteConfigService() - -const profileRoutesConfig: ProfileRouteConfigModel = { - profile: service.profile, -} - -export default profileRoutesConfig +export const profile: string = 'profile' diff --git a/src/lib/profile-provider/profile-service/profile-store/index.ts b/src/lib/profile-provider/profile-service/profile-store/index.ts index cbddcc22e..45fc8b9cc 100644 --- a/src/lib/profile-provider/profile-service/profile-store/index.ts +++ b/src/lib/profile-provider/profile-service/profile-store/index.ts @@ -1 +1 @@ -export * from './profile-fetch.store' +export * from './profile-xhr.store' diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.model.ts b/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.model.ts deleted file mode 100644 index 9f3d354ce..000000000 --- a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.model.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ProfileEndpointConfigModel { - readonly profile: (handle: string) => string -} diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.service.ts b/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.service.ts deleted file mode 100644 index 97eb2ce92..000000000 --- a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { EnvironmentConfig } from '../../../../config' - -export class ProfileEndpointConfigService { - - profile(handle: string): string { - return `${EnvironmentConfig.API.V5}/members/${handle}` - } -} diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts b/src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts index 9b9a1e112..4dc01694b 100644 --- a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts +++ b/src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts @@ -1,10 +1,5 @@ -import { ProfileEndpointConfigModel } from './profile-endpoint-config.model' -import { ProfileEndpointConfigService } from './profile-endpoint-config.service' +import { EnvironmentConfig } from '../../../../config' -const service: ProfileEndpointConfigService = new ProfileEndpointConfigService() - -const profileEndpointConfig: ProfileEndpointConfigModel = { - profile: service.profile, +export function profile(handle: string): string { + return `${EnvironmentConfig.API.V5}/members/${handle}` } - -export default profileEndpointConfig diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-fetch.store.ts b/src/lib/profile-provider/profile-service/profile-store/profile-fetch.store.ts deleted file mode 100644 index 91a498e9a..000000000 --- a/src/lib/profile-provider/profile-service/profile-store/profile-fetch.store.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { FetchService } from '../../../services' -import { UserProfile } from '../../user-profile.model' - -import { default as ProfileEndpointConfig } from './profile-endpoint.config' - -export class ProfileFetchStore { - - private fetchService: FetchService = new FetchService() - - async get(token: string, handle: string): Promise { - - const url: string = ProfileEndpointConfig.profile(handle) - const method: { method: string } = this.fetchService.methods.get - - const userProfileJson: Response = await this.fetchService.getFetcher(token)(url, method) - return userProfileJson.json() || {} - } -} diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts b/src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts new file mode 100644 index 000000000..58c798a6a --- /dev/null +++ b/src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts @@ -0,0 +1,13 @@ +import { get as xhrGet, put as xhrPut } from '../../../services' +import { UserProfileDetail } from '../../user-profile-detail.model' +import { UserProfile } from '../../user-profile.model' + +import { profile as profileUrl } from './profile-endpoint.config' + +export async function get(handle: string): Promise { + return xhrGet(profileUrl(handle)) +} + +export async function put(handle: string, profile: UserProfile): Promise { + return xhrPut(profileUrl(handle), profile) +} diff --git a/src/lib/profile-provider/profile-service/profile.service.ts b/src/lib/profile-provider/profile-service/profile.service.ts index f28db213b..1c0a4b1ed 100644 --- a/src/lib/profile-provider/profile-service/profile.service.ts +++ b/src/lib/profile-provider/profile-service/profile.service.ts @@ -1,40 +1,14 @@ -import { decodeToken } from 'tc-auth-lib' - -import { AuthenticationService } from '../../services/authentication-service' -import { LoggingService } from '../../services/logging-service' +import { get as tokenGet } from '../../services/token-service' +import { UserProfileDetail } from '../user-profile-detail.model' import { UserProfile } from '../user-profile.model' -import { ProfileFetchStore } from './profile-store' - -export class ProfileService { - - private readonly authenticationService: AuthenticationService = new AuthenticationService() - private readonly loggingService: LoggingService = new LoggingService() - private readonly profileFetchStore: ProfileFetchStore = new ProfileFetchStore() - - async get(): Promise { - - const token: string | undefined = await this.authenticationService.authenticate() +import { get as storeGet, put as storePut } from './profile-store' - // if there is no token, don't try to get a profile - if (!token) { - return Promise.resolve(undefined) - } - - try { - const { handle }: { handle?: string } = decodeToken(token) - - // if we didn't find the handle, we can't get the profile - if (!handle) { - this.loggingService.logInfo(`token did not have a handle: ${token}`) - return Promise.resolve(undefined) - } - - return this.profileFetchStore.get(token, handle) +export async function get(handle?: string): Promise { + handle = handle || (await tokenGet())?.handle + return !handle ? Promise.resolve(undefined) : storeGet(handle) +} - } catch (error: any) { - this.loggingService.logError(error) - return Promise.resolve(undefined) - } - } +export async function update(handle: string, profile: UserProfile): Promise { + return storePut(handle, profile) } diff --git a/src/lib/profile-provider/profile.context.tsx b/src/lib/profile-provider/profile.context.tsx index 4f60ac923..e4188ef73 100644 --- a/src/lib/profile-provider/profile.context.tsx +++ b/src/lib/profile-provider/profile.context.tsx @@ -4,6 +4,7 @@ import { ProfileContextData } from './profile-context-data.model' export const defaultProfileContextData: ProfileContextData = { initialized: false, + updateProfile: () => Promise.resolve(), } const ProfileContext: Context = createContext(defaultProfileContextData) diff --git a/src/lib/profile-provider/profile.provider.tsx b/src/lib/profile-provider/profile.provider.tsx index d297ab458..db905703d 100644 --- a/src/lib/profile-provider/profile.provider.tsx +++ b/src/lib/profile-provider/profile.provider.tsx @@ -1,13 +1,33 @@ import { Dispatch, FC, ReactNode, SetStateAction, useEffect, useState } from 'react' import { ProfileContextData } from './profile-context-data.model' -import { ProfileService } from './profile-service' +import { get as profileGet, update as profileUpdate } from './profile-service' import { default as ProfileContext, defaultProfileContextData } from './profile.context' +import { UserProfileDetail } from './user-profile-detail.model' import { UserProfile } from './user-profile.model' export const ProfileProvider: FC<{ children: ReactNode }> = ({ children }: { children: ReactNode }) => { - const [profileContext, setProfileContext]: [ProfileContextData, Dispatch>] = useState(defaultProfileContextData) + const [profileContext, setProfileContext]: [ProfileContextData, Dispatch>] + = useState(defaultProfileContextData) + + function updateProfile(updatedContext: ProfileContextData): Promise { + + const { profile }: ProfileContextData = updatedContext + + if (!profile) { + throw new Error('Cannot update an undefined profile') + } + + const updatedProfile: UserProfile = { + email: profile.email, + firstName: profile.firstName, + lastName: profile.lastName, + } + + return profileUpdate(profile.handle, updatedProfile) + .then(() => setProfileContext(updatedContext)) + } useEffect(() => { @@ -17,18 +37,17 @@ export const ProfileProvider: FC<{ children: ReactNode }> = ({ children }: { chi } const getAndSetProfile: () => Promise = async () => { - const profile: UserProfile | undefined = await new ProfileService().get() + const profile: UserProfileDetail | undefined = await profileGet() const contextData: ProfileContextData = { initialized: true, profile, + updateProfile, } setProfileContext(contextData) } getAndSetProfile() - }, [ - profileContext.initialized, - ]) + }) return ( diff --git a/src/lib/profile-provider/user-profile-detail.model.ts b/src/lib/profile-provider/user-profile-detail.model.ts new file mode 100644 index 000000000..75a57427d --- /dev/null +++ b/src/lib/profile-provider/user-profile-detail.model.ts @@ -0,0 +1,13 @@ +import { UserProfile } from '.' + +export interface UserProfileDetail extends UserProfile { + competitionCountryCode: string + createdAt: number + handle: string + handleLower: string + homeCountryCode: string + photoURL?: string + status: string + updatedAt: number + userId: number +} diff --git a/src/lib/profile-provider/user-profile.model.ts b/src/lib/profile-provider/user-profile.model.ts index 96ede70d0..5136269bc 100644 --- a/src/lib/profile-provider/user-profile.model.ts +++ b/src/lib/profile-provider/user-profile.model.ts @@ -1,14 +1,5 @@ export interface UserProfile { - competitionCountryCode: string - createdAt: number email: string firstName: string - handle: string - handleLower: string - homeCountryCode: string lastName: string - photoURL?: string - status: string - updatedAt: number - userId: number } diff --git a/src/lib/services/analytics-service/analytics.service.ts b/src/lib/services/analytics-service/analytics.service.ts index cbfac2fb4..e01b88a93 100644 --- a/src/lib/services/analytics-service/analytics.service.ts +++ b/src/lib/services/analytics-service/analytics.service.ts @@ -2,19 +2,16 @@ import TagManager from 'react-gtm-module' import { GlobalConfig } from '../../global-config.model' -export class AnalyticsService { +export function initialize(config: GlobalConfig): void { - initialize(config: GlobalConfig): void { - - // if we don't have an ID - // then tags aren't supported in this environment, - // so don't initialize anything - if (!config.TAG_MANAGER_ID) { - return - } - - TagManager.initialize({ - gtmId: config.TAG_MANAGER_ID, - }) + // if we don't have an ID + // then tags aren't supported in this environment, + // so don't initialize anything + if (!config.TAG_MANAGER_ID) { + return } + + TagManager.initialize({ + gtmId: config.TAG_MANAGER_ID, + }) } diff --git a/src/lib/services/analytics-service/index.ts b/src/lib/services/analytics-service/index.ts index 93b055f35..f92106f2c 100644 --- a/src/lib/services/analytics-service/index.ts +++ b/src/lib/services/analytics-service/index.ts @@ -1 +1 @@ -export * from './analytics.service' +export { initialize as initializeAnalytics } from './analytics.service' diff --git a/src/lib/services/authentication-service/authentication-url-config.model.ts b/src/lib/services/authentication-service/authentication-url-config.model.ts deleted file mode 100644 index 2265db675..000000000 --- a/src/lib/services/authentication-service/authentication-url-config.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface AuthenticationUrlConfigModel { - readonly authentication: string - readonly login: (fallback: string) => string - readonly logout: string - readonly signup: (fallback: string) => string -} diff --git a/src/lib/services/authentication-service/authentication-url-config.service.ts b/src/lib/services/authentication-service/authentication-url-config.service.ts deleted file mode 100644 index 6f73c6ee1..000000000 --- a/src/lib/services/authentication-service/authentication-url-config.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EnvironmentConfig } from '../../../config' - -export class AuthenticationUrlConfigService { - - readonly authentication: string = EnvironmentConfig.URL.ACCOUNTS_APP_CONNECTOR - - get logout(): string { - return `${this.authentication}?logout=true&retUrl=${encodeURIComponent('https://' + window.location.host)}` - } - - login(fallback: string): string { - return `${this.authentication}?retUrl=${encodeURIComponent(window.location.href.match(/[^?]*/)?.[0] || fallback)}` - } - - signup(fallback: string): string { - return `${this.login(fallback)}®Source=tcBusiness&mode=signUp` - } -} diff --git a/src/lib/services/authentication-service/authentication-url.config.ts b/src/lib/services/authentication-service/authentication-url.config.ts index 8730a68a8..39d8ef9e2 100644 --- a/src/lib/services/authentication-service/authentication-url.config.ts +++ b/src/lib/services/authentication-service/authentication-url.config.ts @@ -1,13 +1,13 @@ -import { AuthenticationUrlConfigModel } from './authentication-url-config.model' -import { AuthenticationUrlConfigService } from './authentication-url-config.service' +import { EnvironmentConfig } from '../../../config' -const service: AuthenticationUrlConfigService = new AuthenticationUrlConfigService() +export const authentication: string = EnvironmentConfig.URL.ACCOUNTS_APP_CONNECTOR -const authenticationUrlConfig: AuthenticationUrlConfigModel = { - authentication: service.authentication, - login: service.login, - logout: service.logout, - signup: service.signup, +export function login(fallback: string): string { + return `${authentication}?retUrl=${encodeURIComponent(window.location.href.match(/[^?]*/)?.[0] || fallback)}` } -export default authenticationUrlConfig +export const logout: string = `${authentication}?logout=true&retUrl=${encodeURIComponent('https://' + window.location.host)}` + +export function signup(fallback: string): string { + return `${login(fallback)}®Source=tcBusiness&mode=signUp` +} diff --git a/src/lib/services/authentication-service/authentication.service.ts b/src/lib/services/authentication-service/authentication.service.ts index 78e62746c..8f0f64204 100644 --- a/src/lib/services/authentication-service/authentication.service.ts +++ b/src/lib/services/authentication-service/authentication.service.ts @@ -3,9 +3,9 @@ import { configureConnector, decodeToken, getFreshToken } from 'tc-auth-lib' import { User } from '../../../../types/tc-auth-lib' import { EnvironmentConfig } from '../../../config' -import { LoggingService } from '../logging-service' +import { logError } from '../logging-service' -import { default as AuthenticationUrlConfig } from './authentication-url.config' +import { authentication as authenticationUrl } from './authentication-url.config' import { CookieKeys } from './cookie-keys.enum' interface TokenData { @@ -13,62 +13,55 @@ interface TokenData { tokenV3?: string } -export class AuthenticationService { +configureConnector({ + connectorUrl: authenticationUrl, + frameId: 'tc-accounts-iframe', + mockMode: undefined, + mockToken: undefined, +}) - private readonly loggingService: LoggingService = new LoggingService() +export async function authenticate(): Promise { - constructor() { - configureConnector({ - connectorUrl: AuthenticationUrlConfig.authentication, - frameId: 'tc-accounts-iframe', - mockMode: undefined, - mockToken: undefined, + return getFreshToken() + .then((tokenV3: string) => { + const tokenV2: string | null = cookies.get(CookieKeys.tcjwt) + return { + tokenV2, + tokenV3, + } }) - } - - async authenticate(): Promise { - - return getFreshToken() - .then((tokenV3: string) => { - const tokenV2: string | null = cookies.get(CookieKeys.tcjwt) - return { - tokenV2, - tokenV3, - } - }) - .catch((error: Error) => { - this.loggingService.logError(error?.message || `${error}` || 'unknown error getting authentication token') - return {} - }) - .then((token: TokenData) => { - this.handleRefresh(token) - return token.tokenV3 - }) - } - - private handleRefresh(token: TokenData): number { + .catch((error: Error) => { + logError(error?.message || `${error}` || 'unknown error getting authentication token') + return {} + }) + .then((token: TokenData) => { + handleRefresh(token) + return token.tokenV3 + }) +} - let time: number = Number.MAX_VALUE +function handleRefresh(token: TokenData): number { - const user: User = !!token.tokenV3 ? decodeToken(token.tokenV3) : {} + let time: number = Number.MAX_VALUE - // if we havea tctv2, use its expiration - if (!!token.tokenV2) { - time = decodeToken(token.tokenV2).exp - } + const user: User = !!token.tokenV3 ? decodeToken(token.tokenV3) : {} - // if we have a user, take the min btwn - // the current time and the uservl expiration - if (!!user.exp) { - time = Math.min(time, user.exp) - } + // if we havea tctv2, use its expiration + if (!!token.tokenV2) { + time = decodeToken(token.tokenV2).exp + } - if (time < Number.MAX_VALUE) { - time = 1000 * (time - EnvironmentConfig.REAUTH_OFFSET) - time = Math.max(0, time - Date.now()) - setTimeout(() => this.authenticate(), time) - } + // if we have a user, take the min btwn + // the current time and the uservl expiration + if (!!user.exp) { + time = Math.min(time, user.exp) + } - return time + if (time < Number.MAX_VALUE) { + time = 1000 * (time - EnvironmentConfig.REAUTH_OFFSET) + time = Math.max(0, time - Date.now()) + setTimeout(() => authenticate(), time) } + + return time } diff --git a/src/lib/services/authentication-service/index.ts b/src/lib/services/authentication-service/index.ts index 980411ff6..385cf4ba9 100644 --- a/src/lib/services/authentication-service/index.ts +++ b/src/lib/services/authentication-service/index.ts @@ -1,2 +1,6 @@ -export { default as AuthenticationUrlConfig } from './authentication-url.config' +export { + login as loginUrl, + logout as logoutUrl, + signup as signupUrl, +} from './authentication-url.config' export * from './authentication.service' diff --git a/src/lib/services/fetch-service/fetch.service.ts b/src/lib/services/fetch-service/fetch.service.ts deleted file mode 100644 index c35d1c016..000000000 --- a/src/lib/services/fetch-service/fetch.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -export class FetchService { - - methods: { - get: { - method: string - } - } = { - get: { - method: 'get', - }, - } - - getFetcher(token: string): (endpoint: string, options: RequestInit) => Promise { - - const fetcher: (endpoint: string, options: RequestInit) => Promise = (endpoint: string, options: RequestInit = {}) => { - - const headers: any = options.headers ? { ...options.headers } : {} - - if (token) { - headers.Authorization = `Bearer ${token}` - } - - const contentTypeKey: string = 'Content-Type' - switch (headers[contentTypeKey]) { - // tslint:disable-next-line: no-null-keyword - case null: - delete headers[contentTypeKey] - break - case undefined: - headers[contentTypeKey] = 'application/json' - break - default: - } - - return fetch(`${endpoint}`, { - ...options, - headers, - }) - } - - return fetcher - } -} diff --git a/src/lib/services/fetch-service/index.ts b/src/lib/services/fetch-service/index.ts deleted file mode 100644 index 3abe988a4..000000000 --- a/src/lib/services/fetch-service/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './fetch.service' diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index 569a0e33d..b710c36ee 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -1,4 +1,4 @@ export * from './analytics-service' -export { AuthenticationUrlConfig } from './authentication-service' -export * from './fetch-service' +export { loginUrl, logoutUrl, signupUrl } from './authentication-service' export * from './logging-service' +export * from './xhr-service' diff --git a/src/lib/services/logging-service/index.ts b/src/lib/services/logging-service/index.ts index f25702db5..3a378c518 100644 --- a/src/lib/services/logging-service/index.ts +++ b/src/lib/services/logging-service/index.ts @@ -1 +1,5 @@ -export * from './logging.service' +export { + initialize as initializeLogger, + logError, + logInfo, +} from './logging.service' diff --git a/src/lib/services/logging-service/logging.service.ts b/src/lib/services/logging-service/logging.service.ts index 39836c780..c51cd1f88 100644 --- a/src/lib/services/logging-service/logging.service.ts +++ b/src/lib/services/logging-service/logging.service.ts @@ -2,32 +2,29 @@ import { datadogLogs } from '@datadog/browser-logs' import { GlobalConfig } from '../../global-config.model' -export class LoggingService { +export function initialize(config: GlobalConfig): void { - initialize(config: GlobalConfig): void { - - // if we don't have a token and service, - // logging isn't supported in this environment, - // so don't initialize anything - if (!config.LOGGING?.PUBLIC_TOKEN || !config.LOGGING?.SERVICE) { - return - } + // if we don't have a token and service, + // logging isn't supported in this environment, + // so don't initialize anything + if (!config.LOGGING?.PUBLIC_TOKEN || !config.LOGGING?.SERVICE) { + return + } - datadogLogs.init({ - clientToken: config.LOGGING.PUBLIC_TOKEN, - env: config.ENV, - service: config.LOGGING.SERVICE, - silentMultipleInit: true, - }) + datadogLogs.init({ + clientToken: config.LOGGING.PUBLIC_TOKEN, + env: config.ENV, + service: config.LOGGING.SERVICE, + silentMultipleInit: true, + }) - this.logInfo(`initialized logging for ${config.ENV}`) - } + logInfo(`initialized logging for ${config.ENV}`) +} - logError(message: string, messageContext?: object): void { - datadogLogs.logger.error(message, messageContext) - } +export function logError(message: string, messageContext?: object): void { + datadogLogs.logger.error(message, messageContext) +} - logInfo(message: string, messageContext?: object): void { - datadogLogs.logger.info(message, messageContext) - } +export function logInfo(message: string, messageContext?: object): void { + datadogLogs.logger.info(message, messageContext) } diff --git a/src/lib/services/token-service/index.ts b/src/lib/services/token-service/index.ts new file mode 100644 index 000000000..e8033df34 --- /dev/null +++ b/src/lib/services/token-service/index.ts @@ -0,0 +1,2 @@ +export * from './token.model' +export * from './token.service' diff --git a/src/lib/services/token-service/token.model.ts b/src/lib/services/token-service/token.model.ts new file mode 100644 index 000000000..99e72a5d0 --- /dev/null +++ b/src/lib/services/token-service/token.model.ts @@ -0,0 +1,4 @@ +export interface TokenModel { + handle?: string + token?: string +} diff --git a/src/lib/services/fetch-service/fetch.service.test.ts b/src/lib/services/token-service/token.service.test.ts similarity index 64% rename from src/lib/services/fetch-service/fetch.service.test.ts rename to src/lib/services/token-service/token.service.test.ts index 6e5f4a3f3..698dbe71c 100644 --- a/src/lib/services/fetch-service/fetch.service.test.ts +++ b/src/lib/services/token-service/token.service.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' -describe('Fetch Service', () => { +describe('Token Service', () => { test('', () => {}) }) diff --git a/src/lib/services/token-service/token.service.ts b/src/lib/services/token-service/token.service.ts new file mode 100644 index 000000000..58139e2a2 --- /dev/null +++ b/src/lib/services/token-service/token.service.ts @@ -0,0 +1,32 @@ +import { decodeToken } from 'tc-auth-lib' + +import { authenticate } from '../authentication-service' +import { logError, logInfo } from '../logging-service' + +import { TokenModel } from './token.model' + +export async function get(): Promise { + + const token: string | undefined = await authenticate() + + // if there is no token, no need to try to get the handle + if (!token) { + return Promise.resolve({}) + } + + try { + const { handle }: { handle?: string } = decodeToken(token) + + // if we didn't find the handle, we have a bad token + if (!handle) { + logError(`token did not have a handle: ${token}`) + return Promise.resolve({}) + } + + return Promise.resolve({ handle, token }) + + } catch (error: any) { + logError(error) + return Promise.resolve({}) + } +} diff --git a/src/lib/services/user-service/index.ts b/src/lib/services/user-service/index.ts new file mode 100644 index 000000000..1f1302dc5 --- /dev/null +++ b/src/lib/services/user-service/index.ts @@ -0,0 +1 @@ +export * from './user.service' diff --git a/src/lib/services/user-service/user-store/index.ts b/src/lib/services/user-service/user-store/index.ts new file mode 100644 index 000000000..c8200c5d9 --- /dev/null +++ b/src/lib/services/user-service/user-store/index.ts @@ -0,0 +1 @@ +export * from './user-xhr.store' diff --git a/src/lib/services/user-service/user-store/user-endpoint.config.ts b/src/lib/services/user-service/user-store/user-endpoint.config.ts new file mode 100644 index 000000000..59dfbd071 --- /dev/null +++ b/src/lib/services/user-service/user-store/user-endpoint.config.ts @@ -0,0 +1,5 @@ +import { EnvironmentConfig } from '../../../../config' + +export function user(userId: string): string { + return `${EnvironmentConfig.API.V5}/users/${userId}` +} diff --git a/src/lib/services/user-service/user-store/user-xhr.store.ts b/src/lib/services/user-service/user-store/user-xhr.store.ts new file mode 100644 index 000000000..ad2f64e5a --- /dev/null +++ b/src/lib/services/user-service/user-store/user-xhr.store.ts @@ -0,0 +1,9 @@ +import { User } from '../../../../../types/tc-auth-lib' +import { patch as xhrPatch } from '../../xhr-service' + +import { user as userEndpoint } from './user-endpoint.config' + +export async function patch(user: User): Promise { + const url: string = userEndpoint(user.userId) + return xhrPatch(url, user) +} diff --git a/src/lib/services/user-service/user.service.test.ts b/src/lib/services/user-service/user.service.test.ts new file mode 100644 index 000000000..d807fe55b --- /dev/null +++ b/src/lib/services/user-service/user.service.test.ts @@ -0,0 +1,8 @@ +import '@testing-library/jest-dom' + +describe('Profile Service', () => { + + test('TODO', () => { + + }) +}) diff --git a/src/lib/services/user-service/user.service.ts b/src/lib/services/user-service/user.service.ts new file mode 100644 index 000000000..a61153efd --- /dev/null +++ b/src/lib/services/user-service/user.service.ts @@ -0,0 +1,7 @@ +import { User } from '../../../../types/tc-auth-lib' + +import { patch as userPatch } from './user-store' + +export async function update(user: User): Promise { + return userPatch(user) +} diff --git a/src/lib/services/xhr-service/index.ts b/src/lib/services/xhr-service/index.ts new file mode 100644 index 000000000..c0c59ef79 --- /dev/null +++ b/src/lib/services/xhr-service/index.ts @@ -0,0 +1 @@ +export * from './xhr.service' diff --git a/src/lib/services/xhr-service/xhr.service.test.ts b/src/lib/services/xhr-service/xhr.service.test.ts new file mode 100644 index 000000000..e72023ea9 --- /dev/null +++ b/src/lib/services/xhr-service/xhr.service.test.ts @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('XHR Service', () => { + + test('', () => {}) +}) diff --git a/src/lib/services/xhr-service/xhr.service.ts b/src/lib/services/xhr-service/xhr.service.ts new file mode 100644 index 000000000..77db73d39 --- /dev/null +++ b/src/lib/services/xhr-service/xhr.service.ts @@ -0,0 +1,44 @@ +import axios, { AxiosInstance, AxiosResponse } from 'axios' + +import { get as tokenGet, TokenModel } from '../token-service' + +// initialize the instance +const xhrInstance: AxiosInstance = axios.create({ + headers: { + 'Content-Type': 'application/json', + }, +}) + +// add the auth token to all xhr calls +xhrInstance.interceptors.request.use(async (config) => { + const tokenData: TokenModel = await tokenGet() + config.headers = config.headers || {} + config.headers.Authorization = `Bearer ${tokenData.token}` + return config +}) + +// handle all http errors +xhrInstance.interceptors.response.use((config) => config, + (error: any) => { + + // if there is server error message, then return it inside `message` property of error + error.message = error?.response?.data?.message || error.message + + return Promise.reject(error) + } +) + +export async function get(url: string): Promise { + const output: AxiosResponse = await xhrInstance.get(url) + return output.data +} + +export async function patch(url: string, data: T): Promise { + const output: AxiosResponse = await xhrInstance.patch(url, data) + return output.data +} + +export async function put(url: string, data: T): Promise { + const output: AxiosResponse = await xhrInstance.put(url, data) + return output.data +} diff --git a/src/lib/styles/_buttons.scss b/src/lib/styles/_buttons.scss index 4be421a62..850663249 100644 --- a/src/lib/styles/_buttons.scss +++ b/src/lib/styles/_buttons.scss @@ -11,8 +11,10 @@ a { color: $tc-white; text-transform: uppercase; border-radius: 25px; - border: solid 1px; + border: solid $border; white-space: nowrap; + cursor: pointer; + margin: $pad-md; // extend body ultra small medium and override it @extend .body-ultra-small-medium; line-height: 24px; @@ -36,27 +38,69 @@ a { padding: $pad-md $pad-xxl; font-size: 16px; } - - &.secondary, - &.tertiary { - color: $turq-160; + + &.primary { + color: $tc-white; + background-color: $turq-160; + border-color: $turq-160; + + &:hover { + background-color: $turq-140; + border-color: $turq-140; + } + + &:active { + background-color: $turq-180; + border-color: $turq-180; + } + + &.disabled { + color: $black-60; + background-color: $black-5; + border-color: $black-5; + } } &.secondary { + color: $turq-160; + background-color: $tc-white; border-color: $turq-160; + + &:hover { + border-color: $turq-140; + } + + &:active { + border-color: $turq-180; + } + + &:disabled { + color: $black-60; + background-color: $black-5; + border-color: $black-5; + } } &.tertiary { + color: $turq-160; background-color: $tc-white; border-color: $tc-white; &:hover { + color: $turq-140; box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.2); } &:active { + color: $turq-180; box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.5); } + + &:disabled { + color: $black-60; + background-color: $tc-white; + border-color: $black-5; + } } &.text { diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index 2b96e108c..f1b0e22c2 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -1,12 +1,14 @@ -import { FC, useContext } from 'react' +import { FC, FormEvent, MouseEvent, useContext, useState } from 'react' import { + Button, ContentLayout, FormField, ProfileContext, ProfileContextData, TextInput, } from '../../lib' +import { UserProfileDetail } from '../../lib/profile-provider/user-profile-detail.model' import styles from './Profile.module.scss' @@ -14,7 +16,11 @@ export const utilTitle: string = 'Profile' const Profile: FC<{}> = () => { - const { profile }: ProfileContextData = useContext(ProfileContext) + const profileContext: ProfileContextData = useContext(ProfileContext) + const { profile, updateProfile }: ProfileContextData = profileContext + + const [disableButton, setDisableButton]: [boolean, React.Dispatch>] + = useState(false) // if we don't have a profile, we have a problem // TODO: figure out how to lock down the profile @@ -23,69 +29,117 @@ const Profile: FC<{}> = () => { return <> } + const updatedProfile: UserProfileDetail = { + ...profile, + } + // TODO: validation + function onClick(event: MouseEvent): void { + setDisableButton(true) + } + + function onSubmit(event: FormEvent): void { + + event.preventDefault() + + // all the profile fields on this form + const profileFields: Array = ['email', 'firstName', 'lastName'] + + const formValues: HTMLFormControlsCollection = (event.target as HTMLFormElement).elements + + Object.keys(updatedProfile) + .filter(key => profileFields.includes(key)) + .map(key => ({ + input: formValues.namedItem(key) as HTMLInputElement, + key, + })) + .forEach(field => (updatedProfile as any)[field.key] = field.input.value) + + const updatedContext: ProfileContextData = { + ...profileContext, + profile: updatedProfile, + } + + updateProfile(updatedContext) + .then(() => setDisableButton(false)) + } + let tabIndex: number = 1 return ( -

Basic Information

- -
- - - - - - - - - - - - - - - - - -
- -

Reset Password

- -
- - - - - - - - - - - - -
+
+ +

Basic Information

+ +
+ + + + + + + + + + + + + + + + + +
+ +

Reset Password

+ +
+ + + + + + + + + + + + +
+ +
+
+ +
) diff --git a/yarn.lock b/yarn.lock index 004ce4d37..c7862aca2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1647,6 +1647,13 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.1.18" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" @@ -2499,6 +2506,13 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== +axios@*, axios@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -4286,7 +4300,7 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.14.8: version "1.14.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== From 353f0d46b3e5f2cd32ecc7e797b0d19402a6f715 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Tue, 15 Mar 2022 16:00:18 -0700 Subject: [PATCH 08/20] PLAT-828 #comment rename all services to functions; #time 10m --- .../analytics-functions/analytics.functions.test.ts | 6 ++++++ .../analytics-functions/analytics.functions.ts} | 0 src/lib/functions/analytics-functions/index.ts | 1 + .../authentication-functions}/authentication-url.config.ts | 0 .../authentication.functions.test.ts} | 2 +- .../authentication-functions/authentication.functions.ts} | 2 +- .../authentication-functions}/cookie-keys.enum.ts | 0 .../authentication-functions}/index.ts | 2 +- src/lib/functions/index.ts | 4 ++++ .../logging-functions}/index.ts | 2 +- .../functions/logging-functions/logging.functions.test.ts | 6 ++++++ .../logging-functions/logging.functions.ts} | 0 src/lib/functions/token-functions/index.ts | 2 ++ .../token-functions/token.functions.test.ts} | 2 +- .../token-functions/token.functions.ts} | 4 ++-- .../token-functions}/token.model.ts | 0 src/lib/functions/user-functions/index.ts | 1 + .../user-functions}/user-store/index.ts | 0 .../user-functions}/user-store/user-endpoint.config.ts | 0 .../user-functions}/user-store/user-xhr.store.ts | 2 +- .../user-functions/user.functions.test.ts} | 2 +- .../user-functions/user.functions.ts} | 0 src/lib/functions/xhr-functions/index.ts | 1 + src/lib/functions/xhr-functions/xhr.functions.test.ts | 6 ++++++ .../xhr-functions/xhr.functions.ts} | 2 +- src/lib/index.ts | 2 +- src/lib/profile-provider/profile-functions/index.ts | 1 + .../profile-store/index.ts | 0 .../profile-store/profile-endpoint.config.ts | 0 .../profile-store/profile-xhr.store.ts | 2 +- .../profile.functions.test.ts} | 2 +- .../profile.functions.ts} | 2 +- src/lib/profile-provider/profile-service/index.ts | 1 - src/lib/profile-provider/profile.provider.tsx | 2 +- .../services/analytics-service/analytics.service.test.ts | 6 ------ src/lib/services/analytics-service/index.ts | 1 - src/lib/services/index.ts | 4 ---- src/lib/services/token-service/index.ts | 2 -- src/lib/services/token-service/token.service.test.ts | 6 ------ src/lib/services/user-service/index.ts | 1 - src/lib/services/xhr-service/index.ts | 1 - src/lib/services/xhr-service/xhr.service.test.ts | 6 ------ 42 files changed, 43 insertions(+), 43 deletions(-) create mode 100644 src/lib/functions/analytics-functions/analytics.functions.test.ts rename src/lib/{services/analytics-service/analytics.service.ts => functions/analytics-functions/analytics.functions.ts} (100%) create mode 100644 src/lib/functions/analytics-functions/index.ts rename src/lib/{services/authentication-service => functions/authentication-functions}/authentication-url.config.ts (100%) rename src/lib/{services/authentication-service/authentication.service.test.ts => functions/authentication-functions/authentication.functions.test.ts} (63%) rename src/lib/{services/authentication-service/authentication.service.ts => functions/authentication-functions/authentication.functions.ts} (97%) rename src/lib/{services/authentication-service => functions/authentication-functions}/cookie-keys.enum.ts (100%) rename src/lib/{services/authentication-service => functions/authentication-functions}/index.ts (73%) create mode 100644 src/lib/functions/index.ts rename src/lib/{services/logging-service => functions/logging-functions}/index.ts (71%) create mode 100644 src/lib/functions/logging-functions/logging.functions.test.ts rename src/lib/{services/logging-service/logging.service.ts => functions/logging-functions/logging.functions.ts} (100%) create mode 100644 src/lib/functions/token-functions/index.ts rename src/lib/{services/logging-service/logging.service.test.ts => functions/token-functions/token.functions.test.ts} (64%) rename src/lib/{services/token-service/token.service.ts => functions/token-functions/token.functions.ts} (86%) rename src/lib/{services/token-service => functions/token-functions}/token.model.ts (100%) create mode 100644 src/lib/functions/user-functions/index.ts rename src/lib/{services/user-service => functions/user-functions}/user-store/index.ts (100%) rename src/lib/{services/user-service => functions/user-functions}/user-store/user-endpoint.config.ts (100%) rename src/lib/{services/user-service => functions/user-functions}/user-store/user-xhr.store.ts (82%) rename src/lib/{services/user-service/user.service.test.ts => functions/user-functions/user.functions.test.ts} (65%) rename src/lib/{services/user-service/user.service.ts => functions/user-functions/user.functions.ts} (100%) create mode 100644 src/lib/functions/xhr-functions/index.ts create mode 100644 src/lib/functions/xhr-functions/xhr.functions.test.ts rename src/lib/{services/xhr-service/xhr.service.ts => functions/xhr-functions/xhr.functions.ts} (95%) create mode 100644 src/lib/profile-provider/profile-functions/index.ts rename src/lib/profile-provider/{profile-service => profile-functions}/profile-store/index.ts (100%) rename src/lib/profile-provider/{profile-service => profile-functions}/profile-store/profile-endpoint.config.ts (100%) rename src/lib/profile-provider/{profile-service => profile-functions}/profile-store/profile-xhr.store.ts (87%) rename src/lib/profile-provider/{profile-service/profile.service.test.ts => profile-functions/profile.functions.test.ts} (65%) rename src/lib/profile-provider/{profile-service/profile.service.ts => profile-functions/profile.functions.ts} (88%) delete mode 100644 src/lib/profile-provider/profile-service/index.ts delete mode 100644 src/lib/services/analytics-service/analytics.service.test.ts delete mode 100644 src/lib/services/analytics-service/index.ts delete mode 100644 src/lib/services/index.ts delete mode 100644 src/lib/services/token-service/index.ts delete mode 100644 src/lib/services/token-service/token.service.test.ts delete mode 100644 src/lib/services/user-service/index.ts delete mode 100644 src/lib/services/xhr-service/index.ts delete mode 100644 src/lib/services/xhr-service/xhr.service.test.ts diff --git a/src/lib/functions/analytics-functions/analytics.functions.test.ts b/src/lib/functions/analytics-functions/analytics.functions.test.ts new file mode 100644 index 000000000..b6d88521d --- /dev/null +++ b/src/lib/functions/analytics-functions/analytics.functions.test.ts @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('Analytics Functions', () => { + + test('analytics', () => { }) +}) diff --git a/src/lib/services/analytics-service/analytics.service.ts b/src/lib/functions/analytics-functions/analytics.functions.ts similarity index 100% rename from src/lib/services/analytics-service/analytics.service.ts rename to src/lib/functions/analytics-functions/analytics.functions.ts diff --git a/src/lib/functions/analytics-functions/index.ts b/src/lib/functions/analytics-functions/index.ts new file mode 100644 index 000000000..051e3bdfd --- /dev/null +++ b/src/lib/functions/analytics-functions/index.ts @@ -0,0 +1 @@ +export { initialize as initializeAnalytics } from './analytics.functions' diff --git a/src/lib/services/authentication-service/authentication-url.config.ts b/src/lib/functions/authentication-functions/authentication-url.config.ts similarity index 100% rename from src/lib/services/authentication-service/authentication-url.config.ts rename to src/lib/functions/authentication-functions/authentication-url.config.ts diff --git a/src/lib/services/authentication-service/authentication.service.test.ts b/src/lib/functions/authentication-functions/authentication.functions.test.ts similarity index 63% rename from src/lib/services/authentication-service/authentication.service.test.ts rename to src/lib/functions/authentication-functions/authentication.functions.test.ts index 93e9c6c41..8d3b4e806 100644 --- a/src/lib/services/authentication-service/authentication.service.test.ts +++ b/src/lib/functions/authentication-functions/authentication.functions.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' -describe('Authentication Service', () => { +describe('Authentication Functions', () => { test('authentication', () => { }) }) diff --git a/src/lib/services/authentication-service/authentication.service.ts b/src/lib/functions/authentication-functions/authentication.functions.ts similarity index 97% rename from src/lib/services/authentication-service/authentication.service.ts rename to src/lib/functions/authentication-functions/authentication.functions.ts index 8f0f64204..8b878abcc 100644 --- a/src/lib/services/authentication-service/authentication.service.ts +++ b/src/lib/functions/authentication-functions/authentication.functions.ts @@ -3,7 +3,7 @@ import { configureConnector, decodeToken, getFreshToken } from 'tc-auth-lib' import { User } from '../../../../types/tc-auth-lib' import { EnvironmentConfig } from '../../../config' -import { logError } from '../logging-service' +import { logError } from '../logging-functions' import { authentication as authenticationUrl } from './authentication-url.config' import { CookieKeys } from './cookie-keys.enum' diff --git a/src/lib/services/authentication-service/cookie-keys.enum.ts b/src/lib/functions/authentication-functions/cookie-keys.enum.ts similarity index 100% rename from src/lib/services/authentication-service/cookie-keys.enum.ts rename to src/lib/functions/authentication-functions/cookie-keys.enum.ts diff --git a/src/lib/services/authentication-service/index.ts b/src/lib/functions/authentication-functions/index.ts similarity index 73% rename from src/lib/services/authentication-service/index.ts rename to src/lib/functions/authentication-functions/index.ts index 385cf4ba9..6092d71cc 100644 --- a/src/lib/services/authentication-service/index.ts +++ b/src/lib/functions/authentication-functions/index.ts @@ -3,4 +3,4 @@ export { logout as logoutUrl, signup as signupUrl, } from './authentication-url.config' -export * from './authentication.service' +export * from './authentication.functions' diff --git a/src/lib/functions/index.ts b/src/lib/functions/index.ts new file mode 100644 index 000000000..9bbfda030 --- /dev/null +++ b/src/lib/functions/index.ts @@ -0,0 +1,4 @@ +export * from './analytics-functions' +export { loginUrl, logoutUrl, signupUrl } from './authentication-functions' +export * from './logging-functions' +export * from './xhr-functions' diff --git a/src/lib/services/logging-service/index.ts b/src/lib/functions/logging-functions/index.ts similarity index 71% rename from src/lib/services/logging-service/index.ts rename to src/lib/functions/logging-functions/index.ts index 3a378c518..b5689eff1 100644 --- a/src/lib/services/logging-service/index.ts +++ b/src/lib/functions/logging-functions/index.ts @@ -2,4 +2,4 @@ export { initialize as initializeLogger, logError, logInfo, -} from './logging.service' +} from './logging.functions' diff --git a/src/lib/functions/logging-functions/logging.functions.test.ts b/src/lib/functions/logging-functions/logging.functions.test.ts new file mode 100644 index 000000000..d165f7373 --- /dev/null +++ b/src/lib/functions/logging-functions/logging.functions.test.ts @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('Logging Functions', () => { + + test('', () => { }) +}) diff --git a/src/lib/services/logging-service/logging.service.ts b/src/lib/functions/logging-functions/logging.functions.ts similarity index 100% rename from src/lib/services/logging-service/logging.service.ts rename to src/lib/functions/logging-functions/logging.functions.ts diff --git a/src/lib/functions/token-functions/index.ts b/src/lib/functions/token-functions/index.ts new file mode 100644 index 000000000..17a053440 --- /dev/null +++ b/src/lib/functions/token-functions/index.ts @@ -0,0 +1,2 @@ +export * from './token.model' +export * from './token.functions' diff --git a/src/lib/services/logging-service/logging.service.test.ts b/src/lib/functions/token-functions/token.functions.test.ts similarity index 64% rename from src/lib/services/logging-service/logging.service.test.ts rename to src/lib/functions/token-functions/token.functions.test.ts index a4c95550c..342a3bf53 100644 --- a/src/lib/services/logging-service/logging.service.test.ts +++ b/src/lib/functions/token-functions/token.functions.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' -describe('Logging Service', () => { +describe('Token Functions', () => { test('', () => { }) }) diff --git a/src/lib/services/token-service/token.service.ts b/src/lib/functions/token-functions/token.functions.ts similarity index 86% rename from src/lib/services/token-service/token.service.ts rename to src/lib/functions/token-functions/token.functions.ts index 58139e2a2..25cef25ff 100644 --- a/src/lib/services/token-service/token.service.ts +++ b/src/lib/functions/token-functions/token.functions.ts @@ -1,7 +1,7 @@ import { decodeToken } from 'tc-auth-lib' -import { authenticate } from '../authentication-service' -import { logError, logInfo } from '../logging-service' +import { authenticate } from '../authentication-functions' +import { logError } from '../logging-functions' import { TokenModel } from './token.model' diff --git a/src/lib/services/token-service/token.model.ts b/src/lib/functions/token-functions/token.model.ts similarity index 100% rename from src/lib/services/token-service/token.model.ts rename to src/lib/functions/token-functions/token.model.ts diff --git a/src/lib/functions/user-functions/index.ts b/src/lib/functions/user-functions/index.ts new file mode 100644 index 000000000..ba0df2138 --- /dev/null +++ b/src/lib/functions/user-functions/index.ts @@ -0,0 +1 @@ +export * from './user.functions' diff --git a/src/lib/services/user-service/user-store/index.ts b/src/lib/functions/user-functions/user-store/index.ts similarity index 100% rename from src/lib/services/user-service/user-store/index.ts rename to src/lib/functions/user-functions/user-store/index.ts diff --git a/src/lib/services/user-service/user-store/user-endpoint.config.ts b/src/lib/functions/user-functions/user-store/user-endpoint.config.ts similarity index 100% rename from src/lib/services/user-service/user-store/user-endpoint.config.ts rename to src/lib/functions/user-functions/user-store/user-endpoint.config.ts diff --git a/src/lib/services/user-service/user-store/user-xhr.store.ts b/src/lib/functions/user-functions/user-store/user-xhr.store.ts similarity index 82% rename from src/lib/services/user-service/user-store/user-xhr.store.ts rename to src/lib/functions/user-functions/user-store/user-xhr.store.ts index ad2f64e5a..4e09c0076 100644 --- a/src/lib/services/user-service/user-store/user-xhr.store.ts +++ b/src/lib/functions/user-functions/user-store/user-xhr.store.ts @@ -1,5 +1,5 @@ import { User } from '../../../../../types/tc-auth-lib' -import { patch as xhrPatch } from '../../xhr-service' +import { patch as xhrPatch } from '../../xhr-functions' import { user as userEndpoint } from './user-endpoint.config' diff --git a/src/lib/services/user-service/user.service.test.ts b/src/lib/functions/user-functions/user.functions.test.ts similarity index 65% rename from src/lib/services/user-service/user.service.test.ts rename to src/lib/functions/user-functions/user.functions.test.ts index d807fe55b..c77886f77 100644 --- a/src/lib/services/user-service/user.service.test.ts +++ b/src/lib/functions/user-functions/user.functions.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' -describe('Profile Service', () => { +describe('Profile Functions', () => { test('TODO', () => { diff --git a/src/lib/services/user-service/user.service.ts b/src/lib/functions/user-functions/user.functions.ts similarity index 100% rename from src/lib/services/user-service/user.service.ts rename to src/lib/functions/user-functions/user.functions.ts diff --git a/src/lib/functions/xhr-functions/index.ts b/src/lib/functions/xhr-functions/index.ts new file mode 100644 index 000000000..5d4aa524b --- /dev/null +++ b/src/lib/functions/xhr-functions/index.ts @@ -0,0 +1 @@ +export * from './xhr.functions' diff --git a/src/lib/functions/xhr-functions/xhr.functions.test.ts b/src/lib/functions/xhr-functions/xhr.functions.test.ts new file mode 100644 index 000000000..c2a3e7aec --- /dev/null +++ b/src/lib/functions/xhr-functions/xhr.functions.test.ts @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('XHR Functions', () => { + + test('', () => { }) +}) diff --git a/src/lib/services/xhr-service/xhr.service.ts b/src/lib/functions/xhr-functions/xhr.functions.ts similarity index 95% rename from src/lib/services/xhr-service/xhr.service.ts rename to src/lib/functions/xhr-functions/xhr.functions.ts index 77db73d39..802bb2d86 100644 --- a/src/lib/services/xhr-service/xhr.service.ts +++ b/src/lib/functions/xhr-functions/xhr.functions.ts @@ -1,6 +1,6 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios' -import { get as tokenGet, TokenModel } from '../token-service' +import { get as tokenGet, TokenModel } from '../token-functions' // initialize the instance const xhrInstance: AxiosInstance = axios.create({ diff --git a/src/lib/index.ts b/src/lib/index.ts index fc20f4953..2148d276b 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -12,7 +12,7 @@ export { loginUrl, logoutUrl, signupUrl, -} from './services' +} from './functions' export * from './svgs' /* diff --git a/src/lib/profile-provider/profile-functions/index.ts b/src/lib/profile-provider/profile-functions/index.ts new file mode 100644 index 000000000..3b97f287a --- /dev/null +++ b/src/lib/profile-provider/profile-functions/index.ts @@ -0,0 +1 @@ +export * from './profile.functions' diff --git a/src/lib/profile-provider/profile-service/profile-store/index.ts b/src/lib/profile-provider/profile-functions/profile-store/index.ts similarity index 100% rename from src/lib/profile-provider/profile-service/profile-store/index.ts rename to src/lib/profile-provider/profile-functions/profile-store/index.ts diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts b/src/lib/profile-provider/profile-functions/profile-store/profile-endpoint.config.ts similarity index 100% rename from src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts rename to src/lib/profile-provider/profile-functions/profile-store/profile-endpoint.config.ts diff --git a/src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts b/src/lib/profile-provider/profile-functions/profile-store/profile-xhr.store.ts similarity index 87% rename from src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts rename to src/lib/profile-provider/profile-functions/profile-store/profile-xhr.store.ts index 58c798a6a..1bd1d703c 100644 --- a/src/lib/profile-provider/profile-service/profile-store/profile-xhr.store.ts +++ b/src/lib/profile-provider/profile-functions/profile-store/profile-xhr.store.ts @@ -1,4 +1,4 @@ -import { get as xhrGet, put as xhrPut } from '../../../services' +import { get as xhrGet, put as xhrPut } from '../../../functions' import { UserProfileDetail } from '../../user-profile-detail.model' import { UserProfile } from '../../user-profile.model' diff --git a/src/lib/profile-provider/profile-service/profile.service.test.ts b/src/lib/profile-provider/profile-functions/profile.functions.test.ts similarity index 65% rename from src/lib/profile-provider/profile-service/profile.service.test.ts rename to src/lib/profile-provider/profile-functions/profile.functions.test.ts index d807fe55b..c77886f77 100644 --- a/src/lib/profile-provider/profile-service/profile.service.test.ts +++ b/src/lib/profile-provider/profile-functions/profile.functions.test.ts @@ -1,6 +1,6 @@ import '@testing-library/jest-dom' -describe('Profile Service', () => { +describe('Profile Functions', () => { test('TODO', () => { diff --git a/src/lib/profile-provider/profile-service/profile.service.ts b/src/lib/profile-provider/profile-functions/profile.functions.ts similarity index 88% rename from src/lib/profile-provider/profile-service/profile.service.ts rename to src/lib/profile-provider/profile-functions/profile.functions.ts index 1c0a4b1ed..5b1c264ea 100644 --- a/src/lib/profile-provider/profile-service/profile.service.ts +++ b/src/lib/profile-provider/profile-functions/profile.functions.ts @@ -1,4 +1,4 @@ -import { get as tokenGet } from '../../services/token-service' +import { get as tokenGet } from '../../functions/token-functions' import { UserProfileDetail } from '../user-profile-detail.model' import { UserProfile } from '../user-profile.model' diff --git a/src/lib/profile-provider/profile-service/index.ts b/src/lib/profile-provider/profile-service/index.ts deleted file mode 100644 index 2a8452e4c..000000000 --- a/src/lib/profile-provider/profile-service/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './profile.service' diff --git a/src/lib/profile-provider/profile.provider.tsx b/src/lib/profile-provider/profile.provider.tsx index db905703d..562eabcb7 100644 --- a/src/lib/profile-provider/profile.provider.tsx +++ b/src/lib/profile-provider/profile.provider.tsx @@ -1,7 +1,7 @@ import { Dispatch, FC, ReactNode, SetStateAction, useEffect, useState } from 'react' import { ProfileContextData } from './profile-context-data.model' -import { get as profileGet, update as profileUpdate } from './profile-service' +import { get as profileGet, update as profileUpdate } from './profile-functions' import { default as ProfileContext, defaultProfileContextData } from './profile.context' import { UserProfileDetail } from './user-profile-detail.model' import { UserProfile } from './user-profile.model' diff --git a/src/lib/services/analytics-service/analytics.service.test.ts b/src/lib/services/analytics-service/analytics.service.test.ts deleted file mode 100644 index 36c3f3fec..000000000 --- a/src/lib/services/analytics-service/analytics.service.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@testing-library/jest-dom' - -describe('Analytics Service', () => { - - test('analytics', () => {}) -}) diff --git a/src/lib/services/analytics-service/index.ts b/src/lib/services/analytics-service/index.ts deleted file mode 100644 index f92106f2c..000000000 --- a/src/lib/services/analytics-service/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { initialize as initializeAnalytics } from './analytics.service' diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts deleted file mode 100644 index b710c36ee..000000000 --- a/src/lib/services/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './analytics-service' -export { loginUrl, logoutUrl, signupUrl } from './authentication-service' -export * from './logging-service' -export * from './xhr-service' diff --git a/src/lib/services/token-service/index.ts b/src/lib/services/token-service/index.ts deleted file mode 100644 index e8033df34..000000000 --- a/src/lib/services/token-service/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './token.model' -export * from './token.service' diff --git a/src/lib/services/token-service/token.service.test.ts b/src/lib/services/token-service/token.service.test.ts deleted file mode 100644 index 698dbe71c..000000000 --- a/src/lib/services/token-service/token.service.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@testing-library/jest-dom' - -describe('Token Service', () => { - - test('', () => {}) -}) diff --git a/src/lib/services/user-service/index.ts b/src/lib/services/user-service/index.ts deleted file mode 100644 index 1f1302dc5..000000000 --- a/src/lib/services/user-service/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './user.service' diff --git a/src/lib/services/xhr-service/index.ts b/src/lib/services/xhr-service/index.ts deleted file mode 100644 index c0c59ef79..000000000 --- a/src/lib/services/xhr-service/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './xhr.service' diff --git a/src/lib/services/xhr-service/xhr.service.test.ts b/src/lib/services/xhr-service/xhr.service.test.ts deleted file mode 100644 index e72023ea9..000000000 --- a/src/lib/services/xhr-service/xhr.service.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import '@testing-library/jest-dom' - -describe('XHR Service', () => { - - test('', () => {}) -}) From 2738b0ece4dfcc3316bdc9d59df40f8b9d750574 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Tue, 15 Mar 2022 16:36:54 -0700 Subject: [PATCH 09/20] PLAT-828 #comment add update password functions #time 30m --- src/lib/functions/index.ts | 1 + .../user-store/user-endpoint.config.ts | 2 +- .../user-store/user-xhr.store.ts | 15 +++++-- .../user-functions/user.functions.ts | 20 ++++++--- .../functions/xhr-functions/xhr.functions.ts | 4 +- .../profile-context-data.model.ts | 1 + src/lib/profile-provider/profile.context.tsx | 1 + src/lib/profile-provider/profile.provider.tsx | 7 +++ src/utils/profile/Profile.tsx | 44 +++++++++++++------ 9 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/lib/functions/index.ts b/src/lib/functions/index.ts index 9bbfda030..b973e45f8 100644 --- a/src/lib/functions/index.ts +++ b/src/lib/functions/index.ts @@ -1,4 +1,5 @@ export * from './analytics-functions' export { loginUrl, logoutUrl, signupUrl } from './authentication-functions' export * from './logging-functions' +export * from './user-functions' export * from './xhr-functions' diff --git a/src/lib/functions/user-functions/user-store/user-endpoint.config.ts b/src/lib/functions/user-functions/user-store/user-endpoint.config.ts index 59dfbd071..197c0c293 100644 --- a/src/lib/functions/user-functions/user-store/user-endpoint.config.ts +++ b/src/lib/functions/user-functions/user-store/user-endpoint.config.ts @@ -1,5 +1,5 @@ import { EnvironmentConfig } from '../../../../config' -export function user(userId: string): string { +export function user(userId: number): string { return `${EnvironmentConfig.API.V5}/users/${userId}` } diff --git a/src/lib/functions/user-functions/user-store/user-xhr.store.ts b/src/lib/functions/user-functions/user-store/user-xhr.store.ts index 4e09c0076..7af0af73e 100644 --- a/src/lib/functions/user-functions/user-store/user-xhr.store.ts +++ b/src/lib/functions/user-functions/user-store/user-xhr.store.ts @@ -3,7 +3,16 @@ import { patch as xhrPatch } from '../../xhr-functions' import { user as userEndpoint } from './user-endpoint.config' -export async function patch(user: User): Promise { - const url: string = userEndpoint(user.userId) - return xhrPatch(url, user) +export interface UserPatchRequest { + param: { + credential: { + currentPassword: string + password: string + } + } +} + +export async function patchUser(userId: number, request: UserPatchRequest): Promise { + const url: string = userEndpoint(userId) + return xhrPatch(url, request) } diff --git a/src/lib/functions/user-functions/user.functions.ts b/src/lib/functions/user-functions/user.functions.ts index a61153efd..a837980fb 100644 --- a/src/lib/functions/user-functions/user.functions.ts +++ b/src/lib/functions/user-functions/user.functions.ts @@ -1,7 +1,17 @@ -import { User } from '../../../../types/tc-auth-lib' +import { patchUser, UserPatchRequest } from './user-store' -import { patch as userPatch } from './user-store' - -export async function update(user: User): Promise { - return userPatch(user) +export async function updatePassword(userId: number, currentPassword: string, password: string): Promise { + const request: UserPatchRequest = { + param: { + credential: { + currentPassword, + password, + }, + }, + } + // TODO: figure out why this a Bad Request + // when it's exactly like the request used + // in the self-service app + return patchUser(userId, request) + .then(() => undefined) } diff --git a/src/lib/functions/xhr-functions/xhr.functions.ts b/src/lib/functions/xhr-functions/xhr.functions.ts index 802bb2d86..777172089 100644 --- a/src/lib/functions/xhr-functions/xhr.functions.ts +++ b/src/lib/functions/xhr-functions/xhr.functions.ts @@ -33,8 +33,8 @@ export async function get(url: string): Promise { return output.data } -export async function patch(url: string, data: T): Promise { - const output: AxiosResponse = await xhrInstance.patch(url, data) +export async function patch(url: string, data: T): Promise { + const output: AxiosResponse = await xhrInstance.patch(url, data) return output.data } diff --git a/src/lib/profile-provider/profile-context-data.model.ts b/src/lib/profile-provider/profile-context-data.model.ts index 6fc0241df..c4a6a6804 100644 --- a/src/lib/profile-provider/profile-context-data.model.ts +++ b/src/lib/profile-provider/profile-context-data.model.ts @@ -3,5 +3,6 @@ import { UserProfileDetail } from './user-profile-detail.model' export interface ProfileContextData { initialized: boolean profile?: UserProfileDetail + updatePassword: (userId: number, currentPassword: string, password: string) => Promise updateProfile: (profileContext: ProfileContextData) => Promise } diff --git a/src/lib/profile-provider/profile.context.tsx b/src/lib/profile-provider/profile.context.tsx index e4188ef73..8a7351768 100644 --- a/src/lib/profile-provider/profile.context.tsx +++ b/src/lib/profile-provider/profile.context.tsx @@ -4,6 +4,7 @@ import { ProfileContextData } from './profile-context-data.model' export const defaultProfileContextData: ProfileContextData = { initialized: false, + updatePassword: () => Promise.resolve(), updateProfile: () => Promise.resolve(), } diff --git a/src/lib/profile-provider/profile.provider.tsx b/src/lib/profile-provider/profile.provider.tsx index 562eabcb7..f62fd2411 100644 --- a/src/lib/profile-provider/profile.provider.tsx +++ b/src/lib/profile-provider/profile.provider.tsx @@ -1,5 +1,7 @@ import { Dispatch, FC, ReactNode, SetStateAction, useEffect, useState } from 'react' +import { updatePassword as updateUserPassword } from '../functions' + import { ProfileContextData } from './profile-context-data.model' import { get as profileGet, update as profileUpdate } from './profile-functions' import { default as ProfileContext, defaultProfileContextData } from './profile.context' @@ -11,6 +13,10 @@ export const ProfileProvider: FC<{ children: ReactNode }> = ({ children }: { chi const [profileContext, setProfileContext]: [ProfileContextData, Dispatch>] = useState(defaultProfileContextData) + function updatePassword(userId: number, currentPassword: string, password: string): Promise { + return updateUserPassword(userId, currentPassword, password) + } + function updateProfile(updatedContext: ProfileContextData): Promise { const { profile }: ProfileContextData = updatedContext @@ -41,6 +47,7 @@ export const ProfileProvider: FC<{ children: ReactNode }> = ({ children }: { chi const contextData: ProfileContextData = { initialized: true, profile, + updatePassword, updateProfile, } setProfileContext(contextData) diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index f1b0e22c2..06d40fe14 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -17,7 +17,7 @@ export const utilTitle: string = 'Profile' const Profile: FC<{}> = () => { const profileContext: ProfileContextData = useContext(ProfileContext) - const { profile, updateProfile }: ProfileContextData = profileContext + const { profile, updateProfile, updatePassword }: ProfileContextData = profileContext const [disableButton, setDisableButton]: [boolean, React.Dispatch>] = useState(false) @@ -29,12 +29,26 @@ const Profile: FC<{}> = () => { return <> } + enum FieldNames { + confirmPassword = 'confirmPassword', + currentPassword = 'currentPassword', + email = 'email', + firstName = 'firstName', + handle = 'handle', + lastName = 'lastName', + password = 'password', + } + const updatedProfile: UserProfileDetail = { ...profile, } // TODO: validation + function getFormValue(formValues: HTMLFormControlsCollection, fieldName: string): string { + return (formValues.namedItem(fieldName) as HTMLInputElement)?.value + } + function onClick(event: MouseEvent): void { setDisableButton(true) } @@ -44,24 +58,26 @@ const Profile: FC<{}> = () => { event.preventDefault() // all the profile fields on this form - const profileFields: Array = ['email', 'firstName', 'lastName'] + const profileFields: Array = [FieldNames.email, FieldNames.firstName, FieldNames.lastName] const formValues: HTMLFormControlsCollection = (event.target as HTMLFormElement).elements Object.keys(updatedProfile) .filter(key => profileFields.includes(key)) - .map(key => ({ - input: formValues.namedItem(key) as HTMLInputElement, - key, - })) - .forEach(field => (updatedProfile as any)[field.key] = field.input.value) + .forEach(key => (updatedProfile as any)[key] = getFormValue(formValues, key)) const updatedContext: ProfileContextData = { ...profileContext, profile: updatedProfile, } + const currentPassword: string = getFormValue(formValues, FieldNames.currentPassword) + const password: string = getFormValue(formValues, FieldNames.password) + + // TODO: check profile is dirty updateProfile(updatedContext) + // if the pw is updated, set it + .then(() => !!password ? updatePassword(updatedProfile.userId, currentPassword, password) : Promise.resolve()) .then(() => setDisableButton(false)) } @@ -77,26 +93,26 @@ const Profile: FC<{}> = () => {
- - - - @@ -108,21 +124,21 @@ const Profile: FC<{}> = () => {
- - - From a5288a7ae5838087ed046c607bdc4753b16f9253 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Tue, 15 Mar 2022 16:52:37 -0700 Subject: [PATCH 10/20] PLAT-828 #comment clean-up #time 5m --- src/lib/profile-provider/user-profile-detail.model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/profile-provider/user-profile-detail.model.ts b/src/lib/profile-provider/user-profile-detail.model.ts index 75a57427d..29a9614fc 100644 --- a/src/lib/profile-provider/user-profile-detail.model.ts +++ b/src/lib/profile-provider/user-profile-detail.model.ts @@ -1,4 +1,4 @@ -import { UserProfile } from '.' +import { UserProfile } from './user-profile.model' export interface UserProfileDetail extends UserProfile { competitionCountryCode: string From da90fd639953a4bfcc31fe7e1c79177b03dede71 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Tue, 15 Mar 2022 17:05:11 -0700 Subject: [PATCH 11/20] PLAT-828 #comment clean-up #time 10m --- .../form-field/text-input/Text-Input.tsx | 7 ++-- src/utils/profile/Profile.tsx | 36 ++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/lib/form-elements/form-field/text-input/Text-Input.tsx b/src/lib/form-elements/form-field/text-input/Text-Input.tsx index 6f67f3f79..a6930a90f 100644 --- a/src/lib/form-elements/form-field/text-input/Text-Input.tsx +++ b/src/lib/form-elements/form-field/text-input/Text-Input.tsx @@ -6,8 +6,11 @@ import styles from './Text-Input.module.scss' interface TextInputProps { defaultValue?: string name: string - props: { [attr: string]: string | boolean } + props: { + [attr: string]: string | boolean, + } styleName?: string + type?: 'text' | 'password' } const TextInput: FC = (props: TextInputProps) => { @@ -15,7 +18,7 @@ const TextInput: FC = (props: TextInputProps) => { ) diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index 06d40fe14..9a816f62c 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -124,24 +124,36 @@ const Profile: FC<{}> = () => {
- + - + - +
From 322f729eb59ef2ec4f026824172fffebeec5d8b1 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Wed, 16 Mar 2022 08:48:54 -0700 Subject: [PATCH 12/20] PLAT-828 #comment use v3 api for pw change #time 45m --- src/config/environments/environment.default.config.ts | 1 + src/config/environments/environment.prod.config.ts | 1 + .../functions/user-functions/user-store/user-endpoint.config.ts | 2 +- src/lib/global-config.model.ts | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config/environments/environment.default.config.ts b/src/config/environments/environment.default.config.ts index 0e1c938e4..6b9b02526 100644 --- a/src/config/environments/environment.default.config.ts +++ b/src/config/environments/environment.default.config.ts @@ -4,6 +4,7 @@ import { AppHostEnvironment } from './app-host-environment.enum' export const EnvironmentConfigDefault: GlobalConfig = { API: { + V3: 'https://api.topcoder-dev.com/v3', V5: 'https://api.topcoder-dev.com/v5', }, ENV: AppHostEnvironment.default, diff --git a/src/config/environments/environment.prod.config.ts b/src/config/environments/environment.prod.config.ts index 44d87c356..14d232096 100644 --- a/src/config/environments/environment.prod.config.ts +++ b/src/config/environments/environment.prod.config.ts @@ -6,6 +6,7 @@ import { EnvironmentConfigDefault } from './environment.default.config' export const EnvironmentConfigProd: GlobalConfig = { ...EnvironmentConfigDefault, API: { + V3: 'https://api.topcoder.com/v3', V5: 'https://api.topcoder.com/v5', }, ENV: AppHostEnvironment.prod, diff --git a/src/lib/functions/user-functions/user-store/user-endpoint.config.ts b/src/lib/functions/user-functions/user-store/user-endpoint.config.ts index 197c0c293..ffa2183f5 100644 --- a/src/lib/functions/user-functions/user-store/user-endpoint.config.ts +++ b/src/lib/functions/user-functions/user-store/user-endpoint.config.ts @@ -1,5 +1,5 @@ import { EnvironmentConfig } from '../../../../config' export function user(userId: number): string { - return `${EnvironmentConfig.API.V5}/users/${userId}` + return `${EnvironmentConfig.API.V3}/users/${userId}` } diff --git a/src/lib/global-config.model.ts b/src/lib/global-config.model.ts index 4958abd7f..3f0ea23c0 100644 --- a/src/lib/global-config.model.ts +++ b/src/lib/global-config.model.ts @@ -1,5 +1,6 @@ export interface GlobalConfig { API: { + V3: string V5: string } ENV: string From 3d1e64503f90d8a943aa85338db5ed1f326f18e1 Mon Sep 17 00:00:00 2001 From: Brooke <98542587+brooketopcoder@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:48:39 -0700 Subject: [PATCH 13/20] PLAT-828 profile api to PLAT-802_profile-util (#50) * PLAT-536 #comment add logout #time 15m * PLAt-536 #comment fix link hover #time 5m * PLAT-536 #comment fix logo size #time 15m * PLAT-764 #comment convert svgs to components and export from lib #time 30m * PLAT-764 #comment remove styling from SVGs; permit route route for isactive nav #time 1h * PLAT-764 #comment refactor narrow tool selectors so they are not a route; #time 30m * PLAT-764 #comment rename svgs folder #time 5m * PLAT-764 #comment clean up styles and svgs; #time 30m * PLAT-764 #comment clean-up #time 5m * PALT-764 #comment clean-up #time 5m * PLAT-764 #comment clean-up #time 5m * PLAT-764 #comment clean-up #time 5m * PLAT-764 #comment clean-upo #time 5m * PLAT-754 #comment convert url configs to constants; define section routes in section #time 2h * PLAT-754 #comment create and use route provider #time 2.75h * PLAT-745 #comment add child routes; clean up root config dir; clean up tool selectors; #time 1h * PLAT-754 #comment configure sections in content layout; design lib routes and sections #time 1h * PLAT-754 #comment replace route config w/route utils; create *.routes for each tool/util; #time 1h * PLAT-754 #comment hide sections for tools that don't have any #time 10m * PLAT-754 #comment fix styling for expanded narrow tool selectors; #time 15m * PLAT-754 #comment route provider cleanup #time 1h * PLAT-754 #comment tools narrow clean-up; #time 30m * PLAT-764 #comment clean-up #time 5m * PLAT-7584 #comment clean-up #time 10m * POLAT-754 #comment clean-up #time 5m * PLAT-754 #comment clean-up #time 5m * PLAT-754 #comment clean-up #time 5m * PLAT-754 #comment update readme #time 10m * PLAT-754 #comment fix build issues #time 10m * PLAT-754 #comment clean-up #time 5m * PLAT-754 #comment remove commented out tests #time 5m * PLAT-802 #comment create profile util; fix padding for content layout; #time 1h * PLAT-825 #comment fix profile styling; create form element and text input; remove profile from content layout; #time 6h * PLAT-825 #comment consolidate font styles; #time 1h * PLAT-828 #comment create button component; migrate existing buttons to component; #time 30m * PLAT-828 #comment use axios for xhr; update button component; remove all service classes; wire up api call to update profile #time 6h * PLAT-828 #comment rename all services to functions; #time 10m * PLAT-828 #comment add update password functions #time 30m * PLAT-828 #comment clean-up #time 5m * PLAT-828 #comment clean-up #time 10m * PLAT-828 #comment use v3 api for pw change #time 45m * PLAT-828 #comment remove obsolete TODO; change password input names to prevent auto-fill; #time 10m --- package.json | 2 + src/App.tsx | 6 +- .../environment.default.config.ts | 1 + .../environments/environment.prod.config.ts | 1 + .../ProfileLoggedIn.module.scss | 2 +- .../profile-logged-in/ProfileLoggedIn.tsx | 7 +- .../profile-panel/ProfilePanel.tsx | 8 +- .../ProfileNotLoggedIn.tsx | 31 ++- src/lib/button/Button.tsx | 57 +++++ src/lib/button/Buttons.test.tsx | 6 + src/lib/button/index.ts | 1 + .../form-field/Form-Field.module.scss | 1 + .../form-field/text-input/Text-Input.tsx | 7 +- .../analytics.functions.test.ts | 6 + .../analytics.functions.ts | 17 ++ .../functions/analytics-functions/index.ts | 1 + .../authentication-url.config.ts | 13 ++ .../authentication.functions.test.ts} | 2 +- .../authentication.functions.ts | 67 ++++++ .../cookie-keys.enum.ts | 0 .../authentication-functions/index.ts | 6 + src/lib/functions/index.ts | 5 + src/lib/functions/logging-functions/index.ts | 5 + .../logging.functions.test.ts | 6 + .../logging-functions/logging.functions.ts | 30 +++ src/lib/functions/token-functions/index.ts | 2 + .../token-functions/token.functions.test.ts} | 2 +- .../token-functions/token.functions.ts | 32 +++ .../functions/token-functions/token.model.ts | 4 + src/lib/functions/user-functions/index.ts | 1 + .../user-functions/user-store/index.ts | 1 + .../user-store/user-endpoint.config.ts | 5 + .../user-store/user-xhr.store.ts | 18 ++ .../user-functions/user.functions.test.ts} | 2 +- .../user-functions/user.functions.ts | 14 ++ src/lib/functions/xhr-functions/index.ts | 1 + .../xhr-functions/xhr.functions.test.ts | 6 + .../functions/xhr-functions/xhr.functions.ts | 44 ++++ src/lib/global-config.model.ts | 1 + src/lib/index.ts | 13 +- src/lib/profile-provider/index.ts | 2 +- .../profile-context-data.model.ts | 6 +- .../profile-functions/index.ts | 1 + .../profile-functions/profile-store/index.ts | 1 + .../profile-store/profile-endpoint.config.ts | 5 + .../profile-store/profile-xhr.store.ts | 13 ++ .../profile.functions.test.ts | 8 + .../profile-functions/profile.functions.ts | 14 ++ .../profile-routes-config.model.ts | 3 - .../profile-routes-config.service.ts | 4 - .../profile-provider/profile-routes.config.ts | 11 +- .../profile-provider/profile-service/index.ts | 1 - .../profile-service/profile-store/index.ts | 1 - .../profile-endpoint-config.model.ts | 3 - .../profile-endpoint-config.service.ts | 8 - .../profile-store/profile-endpoint.config.ts | 10 - .../profile-store/profile-fetch.store.ts | 18 -- .../profile-service/profile.service.ts | 40 ---- src/lib/profile-provider/profile.context.tsx | 2 + src/lib/profile-provider/profile.provider.tsx | 38 +++- .../user-profile-detail.model.ts | 13 ++ .../profile-provider/user-profile.model.ts | 9 - .../analytics.service.test.ts | 6 - .../analytics-service/analytics.service.ts | 20 -- src/lib/services/analytics-service/index.ts | 1 - .../authentication-url-config.model.ts | 6 - .../authentication-url-config.service.ts | 18 -- .../authentication-url.config.ts | 13 -- .../authentication.service.ts | 74 ------- .../services/authentication-service/index.ts | 2 - .../fetch-service/fetch.service.test.ts | 6 - .../services/fetch-service/fetch.service.ts | 43 ---- src/lib/services/fetch-service/index.ts | 1 - src/lib/services/index.ts | 4 - src/lib/services/logging-service/index.ts | 1 - .../logging-service/logging.service.ts | 33 --- src/lib/styles/_buttons.scss | 85 +++++++- src/utils/profile/Profile.tsx | 198 +++++++++++++----- yarn.lock | 16 +- 79 files changed, 722 insertions(+), 450 deletions(-) create mode 100644 src/lib/button/Button.tsx create mode 100644 src/lib/button/Buttons.test.tsx create mode 100644 src/lib/button/index.ts create mode 100644 src/lib/functions/analytics-functions/analytics.functions.test.ts create mode 100644 src/lib/functions/analytics-functions/analytics.functions.ts create mode 100644 src/lib/functions/analytics-functions/index.ts create mode 100644 src/lib/functions/authentication-functions/authentication-url.config.ts rename src/lib/{services/authentication-service/authentication.service.test.ts => functions/authentication-functions/authentication.functions.test.ts} (63%) create mode 100644 src/lib/functions/authentication-functions/authentication.functions.ts rename src/lib/{services/authentication-service => functions/authentication-functions}/cookie-keys.enum.ts (100%) create mode 100644 src/lib/functions/authentication-functions/index.ts create mode 100644 src/lib/functions/index.ts create mode 100644 src/lib/functions/logging-functions/index.ts create mode 100644 src/lib/functions/logging-functions/logging.functions.test.ts create mode 100644 src/lib/functions/logging-functions/logging.functions.ts create mode 100644 src/lib/functions/token-functions/index.ts rename src/lib/{services/logging-service/logging.service.test.ts => functions/token-functions/token.functions.test.ts} (64%) create mode 100644 src/lib/functions/token-functions/token.functions.ts create mode 100644 src/lib/functions/token-functions/token.model.ts create mode 100644 src/lib/functions/user-functions/index.ts create mode 100644 src/lib/functions/user-functions/user-store/index.ts create mode 100644 src/lib/functions/user-functions/user-store/user-endpoint.config.ts create mode 100644 src/lib/functions/user-functions/user-store/user-xhr.store.ts rename src/lib/{profile-provider/profile-service/profile.service.test.ts => functions/user-functions/user.functions.test.ts} (65%) create mode 100644 src/lib/functions/user-functions/user.functions.ts create mode 100644 src/lib/functions/xhr-functions/index.ts create mode 100644 src/lib/functions/xhr-functions/xhr.functions.test.ts create mode 100644 src/lib/functions/xhr-functions/xhr.functions.ts create mode 100644 src/lib/profile-provider/profile-functions/index.ts create mode 100644 src/lib/profile-provider/profile-functions/profile-store/index.ts create mode 100644 src/lib/profile-provider/profile-functions/profile-store/profile-endpoint.config.ts create mode 100644 src/lib/profile-provider/profile-functions/profile-store/profile-xhr.store.ts create mode 100644 src/lib/profile-provider/profile-functions/profile.functions.test.ts create mode 100644 src/lib/profile-provider/profile-functions/profile.functions.ts delete mode 100644 src/lib/profile-provider/profile-routes-config.model.ts delete mode 100644 src/lib/profile-provider/profile-routes-config.service.ts delete mode 100644 src/lib/profile-provider/profile-service/index.ts delete mode 100644 src/lib/profile-provider/profile-service/profile-store/index.ts delete mode 100644 src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.model.ts delete mode 100644 src/lib/profile-provider/profile-service/profile-store/profile-endpoint-config.service.ts delete mode 100644 src/lib/profile-provider/profile-service/profile-store/profile-endpoint.config.ts delete mode 100644 src/lib/profile-provider/profile-service/profile-store/profile-fetch.store.ts delete mode 100644 src/lib/profile-provider/profile-service/profile.service.ts create mode 100644 src/lib/profile-provider/user-profile-detail.model.ts delete mode 100644 src/lib/services/analytics-service/analytics.service.test.ts delete mode 100644 src/lib/services/analytics-service/analytics.service.ts delete mode 100644 src/lib/services/analytics-service/index.ts delete mode 100644 src/lib/services/authentication-service/authentication-url-config.model.ts delete mode 100644 src/lib/services/authentication-service/authentication-url-config.service.ts delete mode 100644 src/lib/services/authentication-service/authentication-url.config.ts delete mode 100644 src/lib/services/authentication-service/authentication.service.ts delete mode 100644 src/lib/services/authentication-service/index.ts delete mode 100644 src/lib/services/fetch-service/fetch.service.test.ts delete mode 100644 src/lib/services/fetch-service/fetch.service.ts delete mode 100644 src/lib/services/fetch-service/index.ts delete mode 100644 src/lib/services/index.ts delete mode 100644 src/lib/services/logging-service/index.ts delete mode 100644 src/lib/services/logging-service/logging.service.ts diff --git a/package.json b/package.json index 073bce68e..7f51356d5 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "dependencies": { "@datadog/browser-logs": "^4.5.0", "@heroicons/react": "^1.0.6", + "axios": "^0.26.1", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", "react": "^17.0.2", @@ -51,6 +52,7 @@ "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", + "@types/axios": "^0.14.0", "@types/jest": "^27.0.1", "@types/node": "^16.7.13", "@types/react": "^17.0.20", diff --git a/src/App.tsx b/src/App.tsx index d81440aec..4c72f4c17 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,11 +3,11 @@ import { Route, Routes } from 'react-router-dom' import { EnvironmentConfig } from './config' import { Header } from './header' -import { AnalyticsService, LoggingService, ProfileProvider } from './lib' +import { initializeAnalytics, initializeLogger, ProfileProvider } from './lib' import { RouteContext, RouteContextData } from './lib/route-provider' -new AnalyticsService().initialize(EnvironmentConfig) -new LoggingService().initialize(EnvironmentConfig) +initializeAnalytics(EnvironmentConfig) +initializeLogger(EnvironmentConfig) const App: FC<{}> = () => { diff --git a/src/config/environments/environment.default.config.ts b/src/config/environments/environment.default.config.ts index 0e1c938e4..6b9b02526 100644 --- a/src/config/environments/environment.default.config.ts +++ b/src/config/environments/environment.default.config.ts @@ -4,6 +4,7 @@ import { AppHostEnvironment } from './app-host-environment.enum' export const EnvironmentConfigDefault: GlobalConfig = { API: { + V3: 'https://api.topcoder-dev.com/v3', V5: 'https://api.topcoder-dev.com/v5', }, ENV: AppHostEnvironment.default, diff --git a/src/config/environments/environment.prod.config.ts b/src/config/environments/environment.prod.config.ts index 44d87c356..14d232096 100644 --- a/src/config/environments/environment.prod.config.ts +++ b/src/config/environments/environment.prod.config.ts @@ -6,6 +6,7 @@ import { EnvironmentConfigDefault } from './environment.default.config' export const EnvironmentConfigProd: GlobalConfig = { ...EnvironmentConfigDefault, API: { + V3: 'https://api.topcoder.com/v3', V5: 'https://api.topcoder.com/v5', }, ENV: AppHostEnvironment.prod, diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss index d4c19f025..5b5626e41 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.module.scss @@ -2,7 +2,7 @@ $overlaySquare: calc($pad-xxxxl + 2 * $border); -.profile-avater, +.profile-avatar, .overlay { cursor: pointer; } diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx index becea8cfa..6a14a8a17 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-logged-in/ProfileLoggedIn.tsx @@ -1,6 +1,6 @@ import { Dispatch, FC, SetStateAction, useContext, useState } from 'react' -import { Avatar, IconOutline, LoggingService, ProfileContext, ProfileContextData } from '../../../../../lib' +import { Avatar, IconOutline, logInfo , ProfileContext, ProfileContextData } from '../../../../../lib' import { ProfilePanel } from './profile-panel' import styles from './ProfileLoggedIn.module.scss' @@ -9,10 +9,9 @@ const ProfileLoggedIn: FC<{}> = () => { const { profile }: ProfileContextData = useContext(ProfileContext) const [profilePanelOpen, setProfilePanelOpen]: [boolean, Dispatch>] = useState(false) - const logger: LoggingService = new LoggingService() if (!profile) { - logger.logInfo('tried to render the logged in profile w/out a profile') + logInfo('tried to render the logged in profile w/out a profile') return <> } @@ -22,7 +21,7 @@ const ProfileLoggedIn: FC<{}> = () => { return ( <> -
toggleProfilePanel()} > + diff --git a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx index 8fff4946d..4c9114d99 100644 --- a/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx +++ b/src/header/utility-selectors/UtilitySelector/ProfileSelector/profile-not-logged-in/ProfileNotLoggedIn.tsx @@ -1,29 +1,28 @@ -import classNames from 'classnames' import { FC } from 'react' -import { AuthenticationUrlConfig, routeRoot } from '../../../../../lib' +import { Button, loginUrl, routeRoot, signupUrl } from '../../../../../lib' import '../../../../../lib/styles/index.scss' import styles from './ProfileNotLoggedIn.module.scss' const ProfileNotLoggedIn: FC<{}> = () => { - const buttonClass: string = 'button' - return ( <> - - Log In - - - Sign Up - + + ) +} + +export default Button diff --git a/src/lib/button/Buttons.test.tsx b/src/lib/button/Buttons.test.tsx new file mode 100644 index 000000000..0dae599ff --- /dev/null +++ b/src/lib/button/Buttons.test.tsx @@ -0,0 +1,6 @@ +import '@testing-library/jest-dom' + +describe('
+ + ) diff --git a/yarn.lock b/yarn.lock index 004ce4d37..c7862aca2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1647,6 +1647,13 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.1.18" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" @@ -2499,6 +2506,13 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== +axios@*, axios@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -4286,7 +4300,7 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.14.8: version "1.14.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== From cd5d8481f1deef81f347f93fc541a65311bee368 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Wed, 16 Mar 2022 11:19:59 -0700 Subject: [PATCH 14/20] PLAT-826 #comment reset pw fields upon submission #time 10m --- src/utils/profile/Profile.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index 050fbabfa..8d6c769f8 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -45,8 +45,12 @@ const Profile: FC<{}> = () => { // TODO: validation + function getFormInput(formValues: HTMLFormControlsCollection, fieldName: string): HTMLInputElement { + return formValues.namedItem(fieldName) as HTMLInputElement + } + function getFormValue(formValues: HTMLFormControlsCollection, fieldName: string): string { - return (formValues.namedItem(fieldName) as HTMLInputElement)?.value + return getFormInput(formValues, fieldName).value } function onClick(event: MouseEvent): void { @@ -76,9 +80,13 @@ const Profile: FC<{}> = () => { // TODO: check profile is dirty updateProfile(updatedContext) - // if the pw is updated, set it .then(() => !!password ? updatePassword(updatedProfile.userId, currentPassword, password) : Promise.resolve()) - .then(() => setDisableButton(false)) + .then(() => { + getFormInput(formValues, FieldNames.currentPassword).value = '' + getFormInput(formValues, FieldNames.newPassword).value = '' + getFormInput(formValues, FieldNames.confirmPassword).value = '' + setDisableButton(false) + }) } let tabIndex: number = 1 From 07a211a0b02dc8e9db1659f912603db136368a66 Mon Sep 17 00:00:00 2001 From: brooketopcoder Date: Wed, 16 Mar 2022 13:49:28 -0700 Subject: [PATCH 15/20] PLAT-826 #comment permit buttons that don't have click handlers; add required and email validation for forms; require the form field wrapper for text inputs; #time 4h --- src/lib/button/Button.tsx | 9 +- .../Form-Field-Wrapper.module.scss} | 10 +- .../Form-Field-Wrapper.test.tsx} | 2 +- .../Form-Field-Wrapper.tsx} | 25 ++- .../form-elements/form-field-wrapper/index.ts | 1 + src/lib/form-elements/form-field/index.ts | 2 - .../form-field/text-input/Text-Input.tsx | 27 ---- .../form-functions/form-definition.model.ts | 5 + .../form-functions/form.functions.ts | 37 +++++ src/lib/form-elements/form-functions/index.ts | 7 + .../form-functions/text-input.model.ts | 12 ++ src/lib/form-elements/index.ts | 4 +- .../text-input/Text-Input.module.scss | 2 +- .../text-input/Text-Input.test.tsx | 0 .../form-elements/text-input/Text-Input.tsx | 40 +++++ .../{form-field => }/text-input/index.ts | 0 .../validator-functions/index.ts | 1 + .../validator.functions.ts | 18 +++ src/lib/profile-provider/index.ts | 1 + src/utils/profile/Profile.tsx | 144 +++++++----------- src/utils/profile/profile-form.config.ts | 67 ++++++++ 21 files changed, 266 insertions(+), 148 deletions(-) rename src/lib/form-elements/{form-field/Form-Field.module.scss => form-field-wrapper/Form-Field-Wrapper.module.scss} (88%) rename src/lib/form-elements/{form-field/Form-Field.test.tsx => form-field-wrapper/Form-Field-Wrapper.test.tsx} (69%) rename src/lib/form-elements/{form-field/Form-Field.tsx => form-field-wrapper/Form-Field-Wrapper.tsx} (66%) create mode 100644 src/lib/form-elements/form-field-wrapper/index.ts delete mode 100644 src/lib/form-elements/form-field/index.ts delete mode 100644 src/lib/form-elements/form-field/text-input/Text-Input.tsx create mode 100644 src/lib/form-elements/form-functions/form-definition.model.ts create mode 100644 src/lib/form-elements/form-functions/form.functions.ts create mode 100644 src/lib/form-elements/form-functions/index.ts create mode 100644 src/lib/form-elements/form-functions/text-input.model.ts rename src/lib/form-elements/{form-field => }/text-input/Text-Input.module.scss (92%) rename src/lib/form-elements/{form-field => }/text-input/Text-Input.test.tsx (100%) create mode 100644 src/lib/form-elements/text-input/Text-Input.tsx rename src/lib/form-elements/{form-field => }/text-input/index.ts (100%) create mode 100644 src/lib/form-elements/validator-functions/index.ts create mode 100644 src/lib/form-elements/validator-functions/validator.functions.ts create mode 100644 src/utils/profile/profile-form.config.ts diff --git a/src/lib/button/Button.tsx b/src/lib/button/Button.tsx index cd052260c..de9c35a9d 100644 --- a/src/lib/button/Button.tsx +++ b/src/lib/button/Button.tsx @@ -33,14 +33,7 @@ const Button: FC = (props: ButtonProps) => { ) } - // if there is no url and no click handler, we hava a prob - if (!props.onClick) { - throw new Error(`button has neither a url or a click handler`) - } - - // create a safe click handler that isn't null so the compiler - // doesn't complain - const clickHandler: (event: any) => void = props.onClick + const clickHandler: (event: any) => void = props.onClick || (() => undefined) return (
{!!props.error && ( diff --git a/src/lib/form-elements/form-functions/form.functions.ts b/src/lib/form-elements/form-functions/form.functions.ts index 4694b9c89..2322d96f0 100644 --- a/src/lib/form-elements/form-functions/form.functions.ts +++ b/src/lib/form-elements/form-functions/form.functions.ts @@ -3,12 +3,12 @@ import { Dispatch, FormEvent, SetStateAction } from 'react' import { FormDefinition } from './form-definition.model' import { TextInputModel } from './text-input.model' -export function getInput(formValues: HTMLFormControlsCollection, fieldName: string): HTMLInputElement { - return formValues.namedItem(fieldName) as HTMLInputElement +export function getInput(formElements: HTMLFormControlsCollection, fieldName: string): HTMLInputElement { + return formElements.namedItem(fieldName) as HTMLInputElement } -export function getValue(formValues: HTMLFormControlsCollection, fieldName: string): string { - return getInput(formValues, fieldName).value +export function getValue(formElements: HTMLFormControlsCollection, fieldName: string): string { + return getInput(formElements, fieldName).value } export function validateAndUpdate( @@ -16,19 +16,37 @@ export function validateAndUpdate( form: FormDefinition, callback: Dispatch>, ): boolean { - const input: HTMLInputElement = (event.target as HTMLInputElement) + return validateAndUpdateInput(input, form, callback) +} + +function validateAndUpdateInput( + input: HTMLInputElement, + form: FormDefinition, + callback: Dispatch>, +): boolean { + const inputDef: TextInputModel = form[input.name] + const formElements: HTMLFormControlsCollection = (input.form as HTMLFormElement).elements inputDef.dirty = true inputDef.error = undefined inputDef.validators .forEach(validator => { if (!inputDef.error) { - inputDef.error = validator(input.value) + inputDef.error = validator(input.value, formElements, inputDef.requiredIfField) } }) + // validate the input's dependent fields as well + // NOTE: must be VERY careful that this doesn't + // get stuck in an infinite loop + inputDef.dependentFields + ?.forEach(dep => { + const otherinput: HTMLInputElement = getInput(formElements, dep) + validateAndUpdateInput(otherinput, form, callback) + }) + callback({ ...form }) const formIsNotValid: boolean = Object.keys(form) .map(key => form[key]) diff --git a/src/lib/form-elements/form-functions/text-input.model.ts b/src/lib/form-elements/form-functions/text-input.model.ts index 93a96f4b7..db6113c6c 100644 --- a/src/lib/form-elements/form-functions/text-input.model.ts +++ b/src/lib/form-elements/form-functions/text-input.model.ts @@ -1,4 +1,5 @@ export interface TextInputModel { + dependentFields?: Array dirty?: boolean disabled?: boolean error?: string @@ -6,7 +7,8 @@ export interface TextInputModel { name: string placeholder?: string preventAutocomplete?: boolean + requiredIfField?: string type: 'password' | 'text' - validators: Array<(value: string | undefined) => string | undefined> + validators: Array<(value: string | undefined, formValues?: HTMLFormControlsCollection, otherField?: string) => string | undefined> value?: string } diff --git a/src/lib/form-elements/text-input/Text-Input.module.scss b/src/lib/form-elements/text-input/Text-Input.module.scss index eb8a16466..6f36e4e9d 100644 --- a/src/lib/form-elements/text-input/Text-Input.module.scss +++ b/src/lib/form-elements/text-input/Text-Input.module.scss @@ -13,9 +13,17 @@ border: none; outline: none; color: $black-100; + + &::placeholder { + color: $black-60; + } } &:disabled { background-color: $black-10; } + + &::placeholder { + opacity: 1; + } } diff --git a/src/lib/form-elements/text-input/Text-Input.tsx b/src/lib/form-elements/text-input/Text-Input.tsx index 4faf5a1eb..65d414076 100644 --- a/src/lib/form-elements/text-input/Text-Input.tsx +++ b/src/lib/form-elements/text-input/Text-Input.tsx @@ -23,6 +23,7 @@ const TextInput: FC = (props: TextInputProps) => { disabled={!!props.disabled} label={props.label || props.name} error={props.error} + name={props.name} > ()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ @@ -13,6 +15,38 @@ export function emailValidator(value: string | undefined): string | undefined { return !emailRegex.test(value) ? 'invalid email' : undefined } -export function requiredValidator(value: string | undefined): string | undefined { +export function required(value: string | undefined): string | undefined { return !value ? 'required' : undefined } + +export function requiredIfOther(value: string | undefined, formElements?: HTMLFormControlsCollection, otherFieldName?: string): string | undefined { + + // if there are no form values or an other field name, we have a problem + if (!formElements || !otherFieldName) { + throw new Error(`Cannot use the required if other validator if there isn't both formValues (${formElements}) and an otherFieldName (${otherFieldName})`) + } + + // if there is a value, there's no need to check the other input + if (!!value) { + return undefined + } + + // get the other form field + const otherField: HTMLInputElement = getFormInput(formElements, otherFieldName) + + // if there is no other field, we have a problem + if (!otherField) { + throw new Error(`Cannot use the required if other validator if the otherField (${otherFieldName}) doesn't exist on the form`) + } + + // if the other field doesn't have a value, then we're good + + if (!otherField.value) { + return undefined + } + + // get the label of the dependant field + const otherFieldLabel: string = otherField.labels?.[0].firstChild?.nodeValue || otherFieldName + + return `required when ${otherFieldLabel} is not blank` +} diff --git a/src/utils/profile/Profile.tsx b/src/utils/profile/Profile.tsx index b7c6a48d8..d2b148a82 100644 --- a/src/utils/profile/Profile.tsx +++ b/src/utils/profile/Profile.tsx @@ -92,11 +92,7 @@ const Profile: FC<{}> = () => { return ( = () => { return ( - +

Basic Information

@@ -131,7 +131,7 @@ const Profile: FC<{}> = () => {