Skip to content

Commit 056fd46

Browse files
authored
Merge branch 'develop' into fix/hindi-translation
2 parents 6245964 + d6a6c38 commit 056fd46

59 files changed

Lines changed: 4408 additions & 2053 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

client/common/Button.stories.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { action } from '@storybook/addon-actions';
33

4-
import { Button, ButtonDisplays, ButtonKinds, ButtonTypes } from './Button';
4+
import { Button, ButtonDisplays, ButtonTypes } from './Button';
55
import { GithubIcon, DropdownArrowIcon, PlusIcon } from './icons';
66

77
export default {

client/common/Button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export interface ButtonProps extends React.HTMLAttributes<HTMLElement> {
8080
/**
8181
* If using a native button, specifies on an onClick action
8282
*/
83-
onClick?: () => void;
83+
onClick?: (evt: React.MouseEvent<HTMLButtonElement>) => void;
8484
/**
8585
* If using a button, then type is defines the type of button
8686
*/

client/common/useSyncFormTranslations.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
import { useEffect, MutableRefObject } from 'react';
2+
import type { FormApi } from 'final-form';
23

3-
export interface FormLike {
4-
getState(): { values: Record<string, unknown> };
5-
reset(): void;
6-
change(field: string, value: unknown): void;
7-
}
4+
// Generic FormLike that mirrors FormApi for any form value type
5+
export interface FormLike<FormValues = Record<string, unknown>>
6+
extends Pick<FormApi<FormValues>, 'getState' | 'reset' | 'change'> {}
87

98
/**
109
* This hook ensures that form values are preserved when the language changes.
1110
* @param formRef
1211
* @param language
1312
*/
14-
export const useSyncFormTranslations = (
15-
formRef: MutableRefObject<FormLike>,
13+
export const useSyncFormTranslations = <FormValues extends Record<string, any>>(
14+
formRef: MutableRefObject<FormLike<FormValues> | null>,
1615
language: string
1716
) => {
1817
useEffect(() => {
19-
const form = formRef.current;
18+
const form = formRef?.current;
2019
if (!form) return;
2120

2221
const { values } = form.getState();
2322
form.reset();
2423

25-
Object.keys(values).forEach((field) => {
26-
if (values[field]) {
27-
form.change(field, values[field]);
24+
(Object.keys(values) as (keyof FormValues)[]).forEach((field) => {
25+
const value = values[field];
26+
if (value !== undefined && value !== null && value !== '') {
27+
form.change(field, value);
2828
}
2929
});
3030
}, [language]);

client/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { useTranslation } from 'react-i18next';
77
import browserHistory from './browserHistory';
88
import { setupStore } from './store';
99
import Routing from './routes';
10-
import ThemeProvider from './modules/App/components/ThemeProvider';
11-
import Loader from './modules/App/components/loader';
10+
import { ThemeProvider } from './modules/App/components/ThemeProvider';
11+
import { Loader } from './modules/App/components/Loader';
1212
import './i18n';
1313
import { SkipLink } from './components/SkipLink';
1414

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
1-
import PropTypes from 'prop-types';
21
import React, { useEffect, useRef, useState } from 'react';
32
import { useDispatch, useSelector } from 'react-redux';
43
import { useLocation } from 'react-router-dom';
54
import { showReduxDevTools } from '../../store';
6-
import DevTools from './components/DevTools';
5+
import { DevTools } from './components/DevTools';
76
import { setPreviousPath } from '../IDE/actions/ide';
87
import { setLanguage } from '../IDE/actions/preferences';
9-
import CookieConsent from '../User/components/CookieConsent';
8+
import { CookieConsent } from '../User/components/CookieConsent';
9+
import type { RootState } from '../../reducers';
1010

11-
function hideCookieConsent(pathname) {
11+
function hideCookieConsent(pathname: string) {
1212
if (pathname.includes('/full/') || pathname.includes('/embed/')) {
1313
return true;
1414
}
1515
return false;
1616
}
1717

18-
const App = ({ children }) => {
18+
export const App = ({ children }: { children?: React.ReactNode }) => {
1919
const dispatch = useDispatch();
2020

21-
const location = useLocation();
21+
const location = useLocation<{ skipSavingPath?: boolean }>();
2222

23-
const theme = useSelector((state) => state.preferences.theme);
23+
const theme = useSelector((state: RootState) => state.preferences.theme);
2424
useEffect(() => {
2525
document.body.className = theme;
2626
}, [theme]);
2727

2828
// TODO: this is only needed for the initial load and would be better handled elsewhere - Linda
29-
const language = useSelector((state) => state.preferences.language);
29+
const language = useSelector(
30+
(state: RootState) => state.preferences.language
31+
);
3032
useEffect(() => {
3133
dispatch(setLanguage(language, { persistPreference: false }));
3234
}, [language]);
3335

34-
// TODO: do we actually need this? - Linda
35-
const [isMounted, setIsMounted] = useState(false);
36-
useEffect(() => setIsMounted(true), []);
37-
3836
const previousLocationRef = useRef(location);
3937
useEffect(() => {
4038
const prevLocation = previousLocationRef.current;
@@ -52,18 +50,8 @@ const App = ({ children }) => {
5250
return (
5351
<div className="app">
5452
<CookieConsent hide={hide} />
55-
{isMounted && showReduxDevTools() && <DevTools />}
53+
{showReduxDevTools() && <DevTools />}
5654
{children}
5755
</div>
5856
);
5957
};
60-
61-
App.propTypes = {
62-
children: PropTypes.element
63-
};
64-
65-
App.defaultProps = {
66-
children: null
67-
};
68-
69-
export default App;

client/modules/App/components/DevTools.jsx renamed to client/modules/App/components/DevTools.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ const devTools = (
99
</DockMonitor>
1010
);
1111

12-
export default createDevTools(devTools);
12+
export const DevTools = createDevTools(devTools);
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@ const LoaderCircle = styled.div`
4444
}
4545
`;
4646

47-
const Loader = () => (
47+
export const Loader = () => (
4848
<Container>
4949
<LoaderWrapper>
5050
<LoaderCircle />
5151
<LoaderCircle />
5252
</LoaderWrapper>
5353
</Container>
5454
);
55-
export default Loader;
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,49 @@
1-
import PropTypes from 'prop-types';
21
import React, { useCallback, useRef } from 'react';
3-
import MediaQuery from 'react-responsive';
2+
import { useMediaQuery } from 'react-responsive';
43
import { useSelector } from 'react-redux';
54
import { useHistory } from 'react-router-dom';
65
import { useTranslation } from 'react-i18next';
76
import { useModalClose } from '../../../common/useModalClose';
7+
import type { RootState } from '../../../reducers';
88

99
import ExitIcon from '../../../images/exit.svg';
1010

11-
const Overlay = ({
11+
type OverlayProps = {
12+
children?: React.ReactNode;
13+
actions?: React.ReactNode;
14+
closeOverlay?: () => void;
15+
title?: string;
16+
ariaLabel?: string;
17+
isFixedHeight?: boolean;
18+
};
19+
20+
export const Overlay = ({
1221
actions,
13-
ariaLabel,
22+
ariaLabel = 'modal',
1423
children,
1524
closeOverlay,
16-
isFixedHeight,
17-
title
18-
}) => {
25+
isFixedHeight = false,
26+
title = 'Modal'
27+
}: OverlayProps) => {
1928
const { t } = useTranslation();
2029

21-
const previousPath = useSelector((state) => state.ide.previousPath);
30+
const previousPath = useSelector(
31+
(state: RootState) => state.ide.previousPath
32+
);
2233

23-
const ref = useRef(null);
34+
const ref = useRef<HTMLElement>(null);
2435

2536
const browserHistory = useHistory();
2637

38+
const isDesktop = useMediaQuery({ minWidth: 770 });
39+
const isMobile = useMediaQuery({ maxWidth: 769 });
40+
2741
const close = useCallback(() => {
2842
const node = ref.current;
2943
if (!node) return;
3044
// Only close if it is the last (and therefore the topmost overlay)
3145
const overlays = document.getElementsByClassName('overlay');
32-
if (node.parentElement.parentElement !== overlays[overlays.length - 1])
46+
if (node.parentElement?.parentElement !== overlays[overlays.length - 1])
3347
return;
3448

3549
if (!closeOverlay) {
@@ -55,7 +69,7 @@ const Overlay = ({
5569
<header className="overlay__header">
5670
<h2 className="overlay__title">{title}</h2>
5771
<div className="overlay__actions">
58-
<MediaQuery minWidth={770}>{actions}</MediaQuery>
72+
{isDesktop && actions}
5973
<button
6074
className="overlay__close-button"
6175
onClick={close}
@@ -65,34 +79,12 @@ const Overlay = ({
6579
</button>
6680
</div>
6781
</header>
68-
<MediaQuery maxWidth={769}>
69-
{actions && (
70-
<div className="overlay__actions-mobile">{actions}</div>
71-
)}
72-
</MediaQuery>
82+
{isMobile && actions && (
83+
<div className="overlay__actions-mobile">{actions}</div>
84+
)}
7385
{children}
7486
</section>
7587
</div>
7688
</div>
7789
);
7890
};
79-
80-
Overlay.propTypes = {
81-
children: PropTypes.element,
82-
actions: PropTypes.element,
83-
closeOverlay: PropTypes.func,
84-
title: PropTypes.string,
85-
ariaLabel: PropTypes.string,
86-
isFixedHeight: PropTypes.bool
87-
};
88-
89-
Overlay.defaultProps = {
90-
children: null,
91-
actions: null,
92-
title: 'Modal',
93-
closeOverlay: null,
94-
ariaLabel: 'modal',
95-
isFixedHeight: false
96-
};
97-
98-
export default Overlay;

client/modules/App/components/ThemeProvider.jsx

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import { useSelector } from 'react-redux';
3+
import { ThemeProvider as TProvider } from 'styled-components';
4+
import theme from '../../../theme';
5+
import type { RootState } from '../../../reducers';
6+
7+
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
8+
const currentTheme = useSelector(
9+
(state: RootState) => state.preferences.theme
10+
);
11+
return <TProvider theme={{ ...theme[currentTheme] }}>{children}</TProvider>;
12+
};

0 commit comments

Comments
 (0)