Skip to content

Commit

Permalink
fix: Refactor tolgee-ui context TG-422
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 committed Dec 20, 2021
1 parent 2cc4715 commit 73384be
Show file tree
Hide file tree
Showing 13 changed files with 385 additions and 252 deletions.
3 changes: 2 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"rollup-plugin-terser": "7.0.2",
"ts-jest": "^27.0.5",
"ts-loader": "^9.2.6",
"typescript": "4.0.5"
"typescript": "4.0.5",
"use-context-selector": "^1.3.9"
},
"repository": {
"type": "git",
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/KeyDialog/KeyDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { BodyEnd } from '../common/BodyEnd';
import { TranslationDialogContextProvider } from './TranslationDialogContextProvider';
import { DialogProvider } from './TranslationDialogContextProvider';
import { TranslationDialog } from './TranslationDialog';
import { DependencyService } from '@tolgee/core/lib/services/DependencyService';

Expand Down Expand Up @@ -33,15 +33,15 @@ export class KeyDialog extends React.Component<Props> {
public render = () => (
<>
<BodyEnd>
<TranslationDialogContextProvider
<DialogProvider
dependencies={this.props.dependencies}
defaultValue={this.state.defaultValue}
open={this.state.dialogOpened}
input={this.state.key}
onClose={this.onClose}
>
<TranslationDialog />
</TranslationDialogContextProvider>
</DialogProvider>
</BodyEnd>
</>
);
Expand Down
64 changes: 44 additions & 20 deletions packages/ui/src/KeyDialog/KeyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import { TextHelper } from '@tolgee/core/lib/helpers/TextHelper';
import { styled, IconButton, Button } from '@mui/material';
import { OpenInNew } from '@mui/icons-material';

import { useTranslationDialogContext } from './useTranslationDialogContext';
import { TranslationFields } from './TranslationFields';
import { LanguageSelect } from './LanguageSelect';
import { LoadingButton } from '../common/LoadingButton';
import { ScreenshotGallery } from './ScreenshotGallery/ScreenshotGallery';
import { ScFieldTitle } from '../common/FieldTitle';
import {
useDialogContext,
useDialogDispatch,
} from './TranslationDialogContextProvider';

const ScContainer = styled('div')`
font-family: Rubik, Roboto, Arial;
Expand Down Expand Up @@ -73,15 +76,39 @@ const ScError = styled('div')`
`;

export const KeyForm = () => {
const context = useTranslationDialogContext();
const dispatch = useDialogDispatch();

const linkToPlatform = useDialogContext((c) => c.linkToPlatform);
const useBrowserWindow = useDialogContext((c) => c.useBrowserWindow);
const dependencies = useDialogContext((c) => c.dependencies);
const input = useDialogContext((c) => c.input);
const translations = useDialogContext((c) => c.translations);
const formDisabled = useDialogContext((c) => c.formDisabled);
const loading = useDialogContext((c) => c.loading);
const error = useDialogContext((c) => c.error);
const saving = useDialogContext((c) => c.saving);
const success = useDialogContext((c) => c.success);

const screenshotsView =
context.dependencies.coreService.isAuthorizedTo('screenshots.view');
dependencies.coreService.isAuthorizedTo('screenshots.view');

const setUseBrowserWindow = (value: boolean) => {
dispatch({ type: 'SET_USE_BROWSER_WINDOW', payload: value });
};

const onClose = () => {
dispatch({ type: 'ON_CLOSE' });
};

const onSave = () => {
dispatch({ type: 'ON_SAVE' });
};

return (
<ScContainer {...{ [RESTRICTED_ASCENDANT_ATTRIBUTE]: 'true' }}>
<ScHeading>
<a
href={context.linkToPlatform}
href={linkToPlatform}
target="_blank"
rel="noreferrer noopener"
id="_tolgee_platform_link"
Expand All @@ -107,10 +134,10 @@ export const KeyForm = () => {

<ScHeadingTitle>Quick translation</ScHeadingTitle>

{!context.useBrowserWindow && (
{!useBrowserWindow && (
<IconButton
title="Open in new window"
onClick={() => context.setUseBrowserWindow(true)}
onClick={() => setUseBrowserWindow(true)}
color="inherit"
size="small"
>
Expand All @@ -125,10 +152,9 @@ export const KeyForm = () => {

<ScFieldTitle>Key</ScFieldTitle>
<ScKey>
{context.input && TextHelper.removeEscapes(context.input)}
{input && TextHelper.removeEscapes(input)}
<ScKeyHint>
{context.translations?.keyId === undefined &&
" (key doesn't exist yet)"}
{translations?.keyId === undefined && " (key doesn't exist yet)"}
</ScKeyHint>
</ScKey>

Expand All @@ -142,30 +168,28 @@ export const KeyForm = () => {
</ScGalleryWrapper>
)}

{context.formDisabled && !context.loading && (
{formDisabled && !loading && (
<ScRestriction>{`Modification is restricted due to missing ${
context.translations?.keyId !== undefined
? 'translations.edit'
: 'keys.edit'
translations?.keyId !== undefined ? 'translations.edit' : 'keys.edit'
} scope in current api key settings.`}</ScRestriction>
)}

{context.error && <ScError>{context.error}</ScError>}
{error && <ScError>{error}</ScError>}
<ScControls>
<Button onClick={context.onClose} color="secondary">
<Button onClick={onClose} color="secondary">
Cancel
</Button>
<LoadingButton
loading={context.saving}
disabled={context.saving || context.formDisabled}
onClick={context.onSave}
loading={saving}
disabled={saving || formDisabled}
onClick={onSave}
color="primary"
variant="contained"
style={{ marginLeft: '10px' }}
>
{context.success
{success
? 'Saved! ✓'
: context.translations?.keyId === undefined
: translations?.keyId === undefined
? 'Create'
: 'Update'}
</LoadingButton>
Expand Down
27 changes: 17 additions & 10 deletions packages/ui/src/KeyDialog/LanguageSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,43 @@ import {
styled,
} from '@mui/material';

import { useTranslationDialogContext } from './useTranslationDialogContext';
import { DEVTOOLS_Z_INDEX } from '../constants';
import {
useDialogContext,
useDialogDispatch,
} from './TranslationDialogContextProvider';

const ScFormControl = styled(FormControl)`
min-width: 200px;
`;

export const LanguageSelect: React.FC = () => {
const context = useTranslationDialogContext();
const dispatch = useDialogDispatch();
const availableLanguages = useDialogContext((c) => c.availableLanguages);
const selectedLanguages = useDialogContext((c) => c.selectedLanguages);

const options = context.availableLanguages
? [...context.availableLanguages].map((lang) => ({
const options = availableLanguages
? [...availableLanguages].map((lang) => ({
label: lang.name,
value: lang.tag,
}))
: [];

const selected = options.filter((o) =>
context.selectedLanguages.has(o.value)
);
const selected = options.filter((o) => selectedLanguages.has(o.value));
const onChange = (e: SelectChangeEvent<string[]>) => {
const value = e.target.value;
context.onSelectedLanguagesChange(
new Set(typeof value === 'string' ? value.split(',') : value)
const languages = new Set(
typeof value === 'string' ? value.split(',') : value
);
dispatch({
type: 'ON_SELECTED_LANGUAGES_CHANGE',
payload: { languages },
});
};

return (
<>
{context.availableLanguages && (
{availableLanguages && (
<ScFormControl variant="outlined" size="small">
<Select
multiple
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import React, { FC, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { useTranslationDialogContext } from '../KeyDialog/useTranslationDialogContext';
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import {
useDialogContext,
useDialogDispatch,
} from './TranslationDialogContextProvider';

export const NewWindow: FC = (props) => {
const newWindow = useRef(null);
const { container, setContainer, onClose } = useTranslationDialogContext();
const [popup, setPopup] = useState<Window>(null);
const dispatch = useDialogDispatch();
const container = useDialogContext((c) => c.container);

const setContainer = (el: Element) => {
dispatch({ type: 'SET_CONTAINER', payload: el });
};
const onClose = () => {
dispatch({ type: 'ON_CLOSE' });
};

useEffect(() => {
// Create container element on client-side
Expand Down
40 changes: 26 additions & 14 deletions packages/ui/src/KeyDialog/ScreenshotGallery/ScreenshotGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import { CameraAlt, AddCircleOutline } from '@mui/icons-material';
import { ScreenshotDropzone } from './ScreenshotDropzone';
import { ScreenshotThumbnail } from './ScreenshotThumbnail';
import { MAX_FILE_COUNT } from './utils';
import { useTranslationDialogContext } from '../useTranslationDialogContext';
import { DEVTOOLS_Z_INDEX } from '../../constants';
import { ScreenshotInterface } from '../TranslationDialogContextProvider';
import {
ScreenshotInterface,
useDialogContext,
useDialogDispatch,
} from '../TranslationDialogContextProvider';
import { ScreenshotDetail } from './ScreenshotDetail';
import { ScFieldTitle } from '../../common/FieldTitle';
import { ExtensionPrompt } from './ExtensionPrompt';
Expand Down Expand Up @@ -52,16 +55,25 @@ const ALLOWED_UPLOAD_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
export const ScreenshotGallery: React.FC = () => {
const fileRef = useRef<HTMLInputElement>(null);
const [detail, setDetail] = useState<ScreenshotInterface | null>(null);
const {
handleUploadImages,
screenshots,
handleTakeScreenshot,
removeScreenshot,
screenshotsUploading,
pluginAvailable,
dependencies,
formDisabled,
} = useTranslationDialogContext();
const dispatch = useDialogDispatch();

const screenshots = useDialogContext((c) => c.screenshots);
const pluginAvailable = useDialogContext((c) => c.pluginAvailable);
const dependencies = useDialogContext((c) => c.dependencies);
const formDisabled = useDialogContext((c) => c.formDisabled);
const screenshotsUploading = useDialogContext((c) => c.screenshotsUploading);

const uploadImages = (files: File[]) => {
dispatch({ type: 'HANDLE_UPLOAD_IMAGES', payload: { files } });
};

const removeScreenshot = (id: number) => {
dispatch({ type: 'HANDLE_REMOVE_SCREENSHOT', payload: { id } });
};

const takeScreenshot = () => {
dispatch({ type: 'HANDLE_TAKE_SCREENSHOT' });
};

const [extensionPrompt, setExtensionPrompt] = useState(false);

Expand Down Expand Up @@ -107,7 +119,7 @@ export const ScreenshotGallery: React.FC = () => {
const validateAndUpload = (files: File[]) => {
const { valid } = validate(files);
if (valid) {
handleUploadImages(files);
uploadImages(files);
}
};

Expand Down Expand Up @@ -147,7 +159,7 @@ export const ScreenshotGallery: React.FC = () => {
<IconButton
onClick={
ableToTakeScreenshot
? handleTakeScreenshot
? takeScreenshot
: () => setExtensionPrompt(true)
}
>
Expand Down
5 changes: 1 addition & 4 deletions packages/ui/src/KeyDialog/TranslationDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import React from 'react';
import { TranslationDialogWrapper } from './TranslationDialogWrapper';
import { useTranslationDialogContext } from './useTranslationDialogContext';
import { KeyForm } from './KeyForm';
import { ThemeProvider } from '../ThemeProvider';

export const TranslationDialog = () => {
const context = useTranslationDialogContext();

return (
<ThemeProvider>
<TranslationDialogWrapper context={context}>
<TranslationDialogWrapper>
<KeyForm />
</TranslationDialogWrapper>
</ThemeProvider>
Expand Down
Loading

0 comments on commit 73384be

Please sign in to comment.