-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(app-platform): upgrade platform tools to use vite and react 18
- Loading branch information
Showing
34 changed files
with
3,559 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { CssReset, CssVariables } from '@dhis2/ui' | ||
import parse from 'html-react-parser' | ||
import React from 'react' | ||
import { HashRouter, Navigate, Routes, Route } from 'react-router-dom' | ||
import { | ||
ApplicationDescription, | ||
ApplicationLeftFooter, | ||
ApplicationRightFooter, | ||
ApplicationTitle, | ||
Flag, | ||
LanguageSelect, | ||
Logo, | ||
PoweredByDHIS2, | ||
} from './components/customizable-elements.jsx' | ||
import { Popup } from './components/pop-up.jsx' | ||
import { sanitizeMainHTML } from './helpers/handleHTML.js' | ||
import { | ||
LoginPage, | ||
CompleteRegistrationPage, | ||
CreateAccountPage, | ||
PasswordResetRequestPage, | ||
PasswordUpdatePage, | ||
SafeModePage, | ||
DownloadPage, | ||
} from './pages/index.js' | ||
import { LoginConfigProvider, useLoginConfig } from './providers/index.js' | ||
import i18n from './locales/index.js' // eslint-disable-line | ||
import { standard, sidebar } from './templates/index.js' | ||
|
||
const LoginRoutes = () => { | ||
return ( | ||
<> | ||
<Popup /> | ||
<Routes> | ||
<Route path="/" element={<LoginPage />} /> | ||
<Route path="/create-account" element={<CreateAccountPage />} /> | ||
<Route | ||
path="/complete-registration" | ||
element={<CompleteRegistrationPage />} | ||
/> | ||
<Route | ||
path="/reset-password" | ||
element={<PasswordResetRequestPage />} | ||
/> | ||
<Route | ||
path="/update-password" | ||
element={<PasswordUpdatePage />} | ||
/> | ||
<Route path="/safeMode" element={<SafeModePage />} /> | ||
<Route path="/download" element={<DownloadPage />} /> | ||
<Route path="*" element={<Navigate to="/" />} /> | ||
</Routes> | ||
</> | ||
) | ||
} | ||
|
||
const options = { | ||
replace: ({ attribs }) => { | ||
if (!attribs) { | ||
return | ||
} | ||
|
||
if (attribs.id === 'login-box') { | ||
return <LoginRoutes /> | ||
} | ||
|
||
if (attribs.id === 'application-title') { | ||
return <ApplicationTitle /> | ||
} | ||
|
||
if (attribs.id === 'application-introduction') { | ||
return <ApplicationDescription /> | ||
} | ||
|
||
if (attribs.id === 'flag') { | ||
return <Flag /> | ||
} | ||
|
||
if (attribs.id === 'logo') { | ||
return <Logo /> | ||
} | ||
|
||
if (attribs.id === 'powered-by') { | ||
return <PoweredByDHIS2 /> | ||
} | ||
|
||
if (attribs.id === 'application-left-footer') { | ||
return <ApplicationLeftFooter /> | ||
} | ||
|
||
if (attribs.id === 'application-right-footer') { | ||
return <ApplicationRightFooter /> | ||
} | ||
|
||
if (attribs.id === 'language-select') { | ||
return <LanguageSelect /> | ||
} | ||
}, | ||
} | ||
|
||
export const AppContent = () => { | ||
const { loginPageLayout, loginPageTemplate } = useLoginConfig() | ||
let html | ||
if (loginPageLayout === 'SIDEBAR') { | ||
html = sidebar | ||
} else if (loginPageLayout === 'CUSTOM') { | ||
html = loginPageTemplate ?? standard | ||
} else { | ||
html = standard | ||
} | ||
|
||
return <>{parse(sanitizeMainHTML(html), options)}</> | ||
} | ||
|
||
const App = () => ( | ||
<HashRouter> | ||
<LoginConfigProvider initialLocation={window?.location?.href}> | ||
<CssReset /> | ||
<CssVariables colors spacers theme elevations /> | ||
<AppContent /> | ||
</LoginConfigProvider> | ||
</HashRouter> | ||
) | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import { screen } from '@testing-library/react' | ||
import React from 'react' | ||
import { AppContent } from './app.jsx' | ||
import { useLoginConfig } from './providers/use-login-config.js' | ||
import { renderWithRouter } from './test-utils/index.js' | ||
|
||
jest.mock('./components/customizable-elements.js', () => ({ | ||
...jest.requireActual('./components/customizable-elements.js'), | ||
LanguageSelect: () => <div>MOCK_LANGUAGE_SELECT</div>, | ||
ApplicationTitle: () => <div>MOCK_APPLICATION_TITLE</div>, | ||
ApplicationDescription: () => <div>MOCK_APPLICATION_DESCRIPTION</div>, | ||
Flag: () => <div>MOCK_FLAG</div>, | ||
Logo: () => <div>MOCK_LOGO</div>, | ||
ApplicationLeftFooter: () => <div>MOCK_APPLICATION_LEFT_FOOTER</div>, | ||
ApplicationRightFooter: () => <div>MOCK_APPLICATION_RIGHT_FOOTER</div>, | ||
PoweredByDHIS2: () => <div>MOCK_POWERED_BY</div>, | ||
})) | ||
|
||
jest.mock('./providers/use-login-config.js', () => ({ | ||
useLoginConfig: jest.fn(() => ({ | ||
loginPageLayout: 'DEFAULT', | ||
loginPageTemplate: null, | ||
})), | ||
})) | ||
|
||
jest.mock('./templates/index.js', () => ({ | ||
__esModule: true, | ||
standard: '<div>STANDARD TEMPLATE</div>', | ||
sidebar: '<div>SIDEBAR TEMPLATE</div>', | ||
})) | ||
|
||
describe('AppContent', () => { | ||
afterEach(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
it('loads standard template if loginPageLayout is DEFAULT', () => { | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('STANDARD TEMPLATE')).toBeInTheDocument() | ||
}) | ||
|
||
it('loads sidebar template if loginPageLayout is SIDEBAR', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'SIDEBAR', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('SIDEBAR TEMPLATE')).toBeInTheDocument() | ||
}) | ||
|
||
it('loads standard template if loginPageLayout is CUSTOM and loginPageTemplate is null', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: null, | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('STANDARD TEMPLATE')).toBeInTheDocument() | ||
}) | ||
|
||
it('loads custom loginPageTemplate if loginPageLayout is CUSTOM and loginPageTemplate is not null', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div>CUSTOM TEMPLATE</div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('CUSTOM TEMPLATE')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-title element with ApplicationTitle component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-title"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_APPLICATION_TITLE')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-introduction element with ApplicationDescription component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-introduction"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect( | ||
screen.getByText('MOCK_APPLICATION_DESCRIPTION') | ||
).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-title element with ApplicationDescription component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-title"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_APPLICATION_TITLE')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-title element with ApplicationDescription component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-title"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_APPLICATION_TITLE')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces flag element with Flag component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="flag"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_FLAG')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces logo element with Logo component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="logo"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_LOGO')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces powered-by element with PoweredBy component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="powered-by"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect(screen.getByText('MOCK_POWERED_BY')).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-left-footer element with ApplicationLeftFooter component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-left-footer"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect( | ||
screen.getByText('MOCK_APPLICATION_LEFT_FOOTER') | ||
).toBeInTheDocument() | ||
}) | ||
|
||
it('replaces application-right-footer element with ApplicationRightFooter component ', () => { | ||
useLoginConfig.mockReturnValue({ | ||
loginPageLayout: 'CUSTOM', | ||
loginPageTemplate: '<div id="application-right-footer"></div>', | ||
}) | ||
renderWithRouter(<AppContent />) | ||
expect( | ||
screen.getByText('MOCK_APPLICATION_RIGHT_FOOTER') | ||
).toBeInTheDocument() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { render, screen, fireEvent } from '@testing-library/react' | ||
import PropTypes from 'prop-types' | ||
import React from 'react' | ||
import { MemoryRouter, Route, Routes } from 'react-router-dom' | ||
import { BackToLoginButton } from '../back-to-login-button.jsx' | ||
|
||
const MainPage = () => <div>MAIN PAGE</div> | ||
const OtherPage = ({ children }) => <>{children}</> | ||
|
||
OtherPage.propTypes = { | ||
children: PropTypes.oneOfType([ | ||
PropTypes.arrayOf(PropTypes.node), | ||
PropTypes.node, | ||
]), | ||
} | ||
|
||
const Wrapper = ({ children }) => ( | ||
<MemoryRouter initialEntries={['/other']}> | ||
<Routes> | ||
<Route path="/" element={<MainPage />} /> | ||
<Route path="/other" element={<OtherPage>{children}</OtherPage>} /> | ||
</Routes> | ||
</MemoryRouter> | ||
) | ||
|
||
Wrapper.propTypes = { | ||
children: PropTypes.oneOfType([ | ||
PropTypes.arrayOf(PropTypes.node), | ||
PropTypes.node, | ||
]), | ||
} | ||
|
||
describe('BackToLoginButton', () => { | ||
it('redirects to main page when clicked', () => { | ||
render( | ||
<Wrapper> | ||
<BackToLoginButton /> | ||
</Wrapper> | ||
) | ||
expect(screen.queryByText('MAIN PAGE')).toBe(null) | ||
fireEvent.click( | ||
screen.getByRole('button', { | ||
name: /back to log in/i, | ||
}) | ||
) | ||
expect(screen.getByText('MAIN PAGE')).not.toBe(null) | ||
}) | ||
}) |
Oops, something went wrong.