diff --git a/src/client/components/Buttons/ButtonEdit/ButtonEdit.tsx b/src/client/components/Buttons/ButtonEdit/ButtonEdit.tsx index 4fe79a79bd..88de6d065c 100644 --- a/src/client/components/Buttons/ButtonEdit/ButtonEdit.tsx +++ b/src/client/components/Buttons/ButtonEdit/ButtonEdit.tsx @@ -4,17 +4,31 @@ import { Link } from 'react-router-dom' import Icon from 'client/components/Icon' -type Props = { +type LinkProps = { url: string } +type ButtonProps = { + onClick: () => void +} + +type Props = LinkProps | ButtonProps + const ButtonEdit: React.FC = (props) => { - const { url } = props + if ('url' in props) { + const { url } = props + return ( + + + + ) + } + const { onClick } = props return ( - + ) } diff --git a/src/client/components/EditorWYSIWYG/EditorWYSIWYGLinks/context/selectedFilesContext.tsx b/src/client/components/EditorWYSIWYG/EditorWYSIWYGLinks/context/selectedFilesContext.tsx index 8d2ee8271d..96b9beed20 100644 --- a/src/client/components/EditorWYSIWYG/EditorWYSIWYGLinks/context/selectedFilesContext.tsx +++ b/src/client/components/EditorWYSIWYG/EditorWYSIWYGLinks/context/selectedFilesContext.tsx @@ -2,13 +2,21 @@ import React, { createContext, Dispatch, SetStateAction, useContext, useMemo, us import { AssessmentFile } from 'meta/cycleData' +/** + * @deprecated + */ type SelectedFilesContextType = { selectedFiles: AssessmentFile[] setSelectedFiles: Dispatch> } - +/** + * @deprecated + */ const SelectedFilesContext = createContext(undefined) +/** + * @deprecated + */ export const SelectedFilesProvider: React.FC = ({ children }) => { const [selectedFiles, setSelectedFiles] = useState>([]) @@ -17,4 +25,7 @@ export const SelectedFilesProvider: React.FC = ({ child return {children} } +/** + * @deprecated + */ export const useSelectedFileContext = (): SelectedFilesContextType => useContext(SelectedFilesContext) diff --git a/src/client/components/FileUpload/FileUploadProvider.tsx b/src/client/components/FileUpload/FileUploadProvider.tsx new file mode 100644 index 0000000000..7e2ecfce38 --- /dev/null +++ b/src/client/components/FileUpload/FileUploadProvider.tsx @@ -0,0 +1,18 @@ +import React, { createContext, Dispatch, SetStateAction, useContext, useMemo, useState } from 'react' + +type FileUploadContextType = { + files: FileList + setFiles: Dispatch> +} + +const FileUploadContext = createContext(undefined) + +export const FileUploadProvider: React.FC = ({ children }) => { + const [files, setFiles] = useState(null) + + const value = useMemo(() => ({ files, setFiles }), [files]) + + return {children} +} + +export const useFileUploadContext = (): FileUploadContextType => useContext(FileUploadContext) diff --git a/src/client/components/FileUpload/index.ts b/src/client/components/FileUpload/index.ts new file mode 100644 index 0000000000..6d4c6da713 --- /dev/null +++ b/src/client/components/FileUpload/index.ts @@ -0,0 +1 @@ +export { FileUploadProvider, useFileUploadContext } from './FileUploadProvider' diff --git a/src/client/components/MessageCenter/Topic/Topic.tsx b/src/client/components/MessageCenter/Topic/Topic.tsx index 96dbcf8965..ffe7351318 100644 --- a/src/client/components/MessageCenter/Topic/Topic.tsx +++ b/src/client/components/MessageCenter/Topic/Topic.tsx @@ -182,7 +182,7 @@ const Topic: React.FC = (props) => { onClick={postMessage} type="submit" > - {i18n.t('review.add')} + {i18n.t('common.add')} diff --git a/src/client/components/SlidingPanel/SlidingPanel.tsx b/src/client/components/SlidingPanel/SlidingPanel.tsx index ffa05342be..88b915190d 100644 --- a/src/client/components/SlidingPanel/SlidingPanel.tsx +++ b/src/client/components/SlidingPanel/SlidingPanel.tsx @@ -7,6 +7,7 @@ import Icon from 'client/components/Icon' type Props = { openPanel: boolean + // TODO: Rename this to closePanel setOpenPanel: (isOpen: boolean) => void } diff --git a/src/client/pages/CountryHome/Repository/Actions/Actions.tsx b/src/client/pages/CountryHome/Repository/Actions/Actions.tsx index 729621345d..c86e8c2a3d 100644 --- a/src/client/pages/CountryHome/Repository/Actions/Actions.tsx +++ b/src/client/pages/CountryHome/Repository/Actions/Actions.tsx @@ -1,36 +1,28 @@ import './Actions.scss' import React from 'react' -import { useTranslation } from 'react-i18next' -import Icon from 'client/components/Icon' -import SlidingPanel from 'client/components/SlidingPanel' +import { RepositoryItem } from 'meta/cycleData' -const Actions: React.FC = () => { - const { t } = useTranslation() - const [openPanel, setOpenPanel] = React.useState(false) +import { useAppDispatch } from 'client/store' +import { RepositoryActions } from 'client/store/ui/repository' +import ButtonEdit from 'client/components/Buttons/ButtonEdit' + +type Props = { + repositoryItem: RepositoryItem +} + +const Actions: React.FC = (props) => { + const { repositoryItem } = props + const dispatch = useAppDispatch() return ( - <> -
- -
- - - - - +
+ { + dispatch(RepositoryActions.setRepositoryItem(repositoryItem)) + }} + /> +
) } diff --git a/src/client/pages/CountryHome/Repository/EditForm/EditForm.tsx b/src/client/pages/CountryHome/Repository/EditForm/EditForm.tsx index f038eeefa1..ea418cb9ab 100644 --- a/src/client/pages/CountryHome/Repository/EditForm/EditForm.tsx +++ b/src/client/pages/CountryHome/Repository/EditForm/EditForm.tsx @@ -5,24 +5,19 @@ import { useTranslation } from 'react-i18next' import Icon from 'client/components/Icon' import Panel from 'client/pages/CountryHome/Repository/Panel' +import { useOpenPanel } from '../hooks/useOpenPanel' + const EditForm: React.FC = () => { const { t } = useTranslation() - const [openPanel, setOpenPanel] = React.useState(false) + const openPanel = useOpenPanel() return (
- - - +
) } diff --git a/src/client/pages/CountryHome/Repository/Panel/Actions/Actions.tsx b/src/client/pages/CountryHome/Repository/Panel/Actions/Actions.tsx index 93c591553c..d626e816aa 100644 --- a/src/client/pages/CountryHome/Repository/Panel/Actions/Actions.tsx +++ b/src/client/pages/CountryHome/Repository/Panel/Actions/Actions.tsx @@ -3,31 +3,43 @@ import React from 'react' import { useTranslation } from 'react-i18next' import classNames from 'classnames' +import { Objects } from 'utils/objects' -import { useIsRepositoryLoading } from 'client/store/ui/repository/hooks' +import { useIsRepositoryLoading, useRepositoryItem } from 'client/store/ui/repository/hooks' -type Props = { - setOpenPanel: (open: boolean) => void - onSave: () => void -} +import { useClosePanel } from '../../hooks/useClosePanel' +import { useUpsertRepositoryItem } from './hooks/useUpsertRepositoryItem' -const Actions: React.FC = (props: Props) => { - const { setOpenPanel, onSave } = props +const Actions: React.FC = () => { const { t } = useTranslation() + const repositoryItem = useRepositoryItem() + + const upsertRepositoryItem = useUpsertRepositoryItem() + const closePanel = useClosePanel() const disabled = useIsRepositoryLoading() + if (!repositoryItem) return null + const showDelete = !Objects.isEmpty(repositoryItem.uuid) + return (
- + )} + +
diff --git a/src/client/pages/CountryHome/Repository/Panel/hooks/useOnSaveFile.ts b/src/client/pages/CountryHome/Repository/Panel/Actions/hooks/useUpsertRepositoryItem.ts similarity index 57% rename from src/client/pages/CountryHome/Repository/Panel/hooks/useOnSaveFile.ts rename to src/client/pages/CountryHome/Repository/Panel/Actions/hooks/useUpsertRepositoryItem.ts index eedb03e151..70904bb4ef 100644 --- a/src/client/pages/CountryHome/Repository/Panel/hooks/useOnSaveFile.ts +++ b/src/client/pages/CountryHome/Repository/Panel/Actions/hooks/useUpsertRepositoryItem.ts @@ -5,20 +5,21 @@ import { CountryIso } from 'meta/area' import { useAppDispatch } from 'client/store' import { RepositoryActions } from 'client/store/ui/repository' import { useCountryRouteParams } from 'client/hooks/useRouteParams' -import { RepositoryEdit } from 'client/pages/CountryHome/Repository/Panel/repositoryEdit' +import { useFileUploadContext } from 'client/components/FileUpload' -type Returned = () => Promise +type Returned = () => void -export const useOnSaveFile = (file: RepositoryEdit | null, setOpenPanel: (open: boolean) => void): Returned => { +export const useUpsertRepositoryItem = (): Returned => { const dispatch = useAppDispatch() const { assessmentName, cycleName, countryIso } = useCountryRouteParams() + const { files, setFiles } = useFileUploadContext() return useCallback(async () => { - const saveParams = { assessmentName, cycleName, countryIso, file } - dispatch(RepositoryActions.save(saveParams)) + const saveParams = { assessmentName, cycleName, countryIso, file: files?.[0] } + dispatch(RepositoryActions.upsertRepositoryItem(saveParams)) .unwrap() .then(() => { - setOpenPanel(false) + setFiles(null) }) - }, [assessmentName, cycleName, countryIso, file, dispatch, setOpenPanel]) + }, [assessmentName, cycleName, countryIso, dispatch, files, setFiles]) } diff --git a/src/client/pages/CountryHome/Repository/Panel/InputField/InputField.tsx b/src/client/pages/CountryHome/Repository/Panel/InputField/InputField.tsx index 0df03cfd06..245ce947a4 100644 --- a/src/client/pages/CountryHome/Repository/Panel/InputField/InputField.tsx +++ b/src/client/pages/CountryHome/Repository/Panel/InputField/InputField.tsx @@ -1,37 +1,33 @@ import './InputField.scss' -import React from 'react' +import React, { useCallback } from 'react' import { useTranslation } from 'react-i18next' type Props = { - className?: string label: string name: string - onChange: (name: string, value: File | string) => void - type: string + onChange: (name: string, value: string) => void + value: string } const InputField: React.FC = (props: Props) => { - const { label, name, type, className, onChange } = props + const { label, name, onChange, value = '' } = props const { t } = useTranslation() - const _onChange = (event: React.ChangeEvent) => { - if (name === 'file') { - onChange(name, event.target.files[0]) - return - } - onChange(name, event.target.value) - } + const _onChange = useCallback( + (event: React.ChangeEvent) => onChange(name, event.target.value), + [name, onChange] + ) + + const id = `repository_edit-input-${name}` return ( -
-
{t(label)}
- +
+ +
) } -InputField.defaultProps = { - className: '', -} - export default InputField diff --git a/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/InputFieldFile.tsx b/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/InputFieldFile.tsx new file mode 100644 index 0000000000..d8d04293fe --- /dev/null +++ b/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/InputFieldFile.tsx @@ -0,0 +1,28 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' + +import { useFileUploadContext } from 'client/components/FileUpload' + +const FileInputField: React.FC = () => { + const { t } = useTranslation() + + const { setFiles } = useFileUploadContext() + + const _onChange = (event: React.ChangeEvent) => { + setFiles(event.target.files) + } + + const label = `common.file` + const id = `repository_form-input-file` + + return ( +
+ + +
+ ) +} + +export default FileInputField diff --git a/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/index.ts b/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/index.ts new file mode 100644 index 0000000000..df18a691ab --- /dev/null +++ b/src/client/pages/CountryHome/Repository/Panel/InputFieldFile/index.ts @@ -0,0 +1 @@ +export { default } from './InputFieldFile' diff --git a/src/client/pages/CountryHome/Repository/Panel/Panel.tsx b/src/client/pages/CountryHome/Repository/Panel/Panel.tsx index 3804785729..ff505858bf 100644 --- a/src/client/pages/CountryHome/Repository/Panel/Panel.tsx +++ b/src/client/pages/CountryHome/Repository/Panel/Panel.tsx @@ -1,33 +1,33 @@ import './Panel.scss' import React from 'react' +import { Objects } from 'utils/objects' + +import { useRepositoryItem } from 'client/store/ui/repository/hooks' import SlidingPanel from 'client/components/SlidingPanel' import Actions from 'client/pages/CountryHome/Repository/Panel/Actions' import InputField from 'client/pages/CountryHome/Repository/Panel/InputField' +import InputFieldFile from 'client/pages/CountryHome/Repository/Panel/InputFieldFile' import Separator from 'client/pages/CountryHome/Repository/Panel/Separator' +import { useClosePanel } from '../hooks/useClosePanel' import { useOnChange } from './hooks/useOnChange' -import { useOnSaveFile } from './hooks/useOnSaveFile' - -interface Props { - openPanel: boolean - setOpenPanel: (open: boolean) => void -} -const Panel: React.FC = (props: Props) => { - const { openPanel, setOpenPanel } = props +const Panel: React.FC = () => { + const repositoryItem = useRepositoryItem() + const openPanel = !Objects.isEmpty(repositoryItem) - const { file, onChange } = useOnChange() - const onSaveFile = useOnSaveFile(file, setOpenPanel) + const onChange = useOnChange() + const closePanel = useClosePanel() return ( - +
- - + + - - + +
) diff --git a/src/client/pages/CountryHome/Repository/Panel/hooks/useOnChange.ts b/src/client/pages/CountryHome/Repository/Panel/hooks/useOnChange.ts index 4ac52b9627..a960d6da0d 100644 --- a/src/client/pages/CountryHome/Repository/Panel/hooks/useOnChange.ts +++ b/src/client/pages/CountryHome/Repository/Panel/hooks/useOnChange.ts @@ -1,25 +1,34 @@ -import { useCallback, useState } from 'react' +import { useCallback, useEffect } from 'react' -import { RepositoryEdit } from 'client/pages/CountryHome/Repository/Panel/repositoryEdit' +import { useAppDispatch } from 'client/store' +import { RepositoryActions } from 'client/store/ui/repository' +import { useRepositoryItem } from 'client/store/ui/repository/hooks' +import { useFileUploadContext } from 'client/components/FileUpload' -type OnChange = (name: string, value: string | File) => void - -type Returned = { - file: RepositoryEdit | null - onChange: OnChange -} +type Returned = (name: string, value: string) => void export const useOnChange = (): Returned => { - const [file, setFile] = useState(null) - const onChange = useCallback( - (name: string, value: string | File) => { - if (name === 'file') { - setFile({ ...file, file: value as File }) - } else { - setFile({ ...file, [name]: value }) - } + const dispatch = useAppDispatch() + const repositoryItem = useRepositoryItem() + + const { files } = useFileUploadContext() + + const onChange = useCallback( + (name: string, value: string) => { + dispatch(RepositoryActions.setRepositoryItem({ ...repositoryItem, [name]: value })) }, - [file] + [dispatch, repositoryItem] ) - return { file, onChange } + + // When a file is selected and the name is empty, + // set the name to the file name + useEffect(() => { + if (files?.length > 0 && repositoryItem?.name === '') { + const file = files[0] + const name = file.name.split('.')[0] + onChange('name', name) + } + }, [files, onChange, repositoryItem?.name]) + + return onChange } diff --git a/src/client/pages/CountryHome/Repository/Panel/index.ts b/src/client/pages/CountryHome/Repository/Panel/index.ts deleted file mode 100644 index 55b359becd..0000000000 --- a/src/client/pages/CountryHome/Repository/Panel/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Panel' diff --git a/src/client/pages/CountryHome/Repository/Panel/index.tsx b/src/client/pages/CountryHome/Repository/Panel/index.tsx new file mode 100644 index 0000000000..fdb5b4eef9 --- /dev/null +++ b/src/client/pages/CountryHome/Repository/Panel/index.tsx @@ -0,0 +1,15 @@ +import React from 'react' + +import { FileUploadProvider } from 'client/components/FileUpload' + +import Panel from './Panel' + +const WrappedPanel: React.FC = () => { + return ( + + + + ) +} + +export default WrappedPanel diff --git a/src/client/pages/CountryHome/Repository/Panel/repositoryEdit.ts b/src/client/pages/CountryHome/Repository/Panel/repositoryEdit.ts deleted file mode 100644 index 1907f24d47..0000000000 --- a/src/client/pages/CountryHome/Repository/Panel/repositoryEdit.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type RepositoryEdit = { - name: string - link: string - file: File -} diff --git a/src/client/pages/CountryHome/Repository/hooks/useClosePanel.ts b/src/client/pages/CountryHome/Repository/hooks/useClosePanel.ts new file mode 100644 index 0000000000..533cce4d52 --- /dev/null +++ b/src/client/pages/CountryHome/Repository/hooks/useClosePanel.ts @@ -0,0 +1,16 @@ +import { useCallback } from 'react' + +import { useAppDispatch } from 'client/store' +import { RepositoryActions } from 'client/store/ui/repository' +import { useFileUploadContext } from 'client/components/FileUpload' + +type Returned = () => void + +export const useClosePanel = (): Returned => { + const { setFiles } = useFileUploadContext() + const dispatch = useAppDispatch() + return useCallback(() => { + setFiles(null) + dispatch(RepositoryActions.setRepositoryItem(undefined)) + }, [dispatch, setFiles]) +} diff --git a/src/client/pages/CountryHome/Repository/hooks/useColumns.tsx b/src/client/pages/CountryHome/Repository/hooks/useColumns.tsx index 709cc77110..04d0be47e1 100644 --- a/src/client/pages/CountryHome/Repository/hooks/useColumns.tsx +++ b/src/client/pages/CountryHome/Repository/hooks/useColumns.tsx @@ -18,7 +18,7 @@ export const useColumns = (): Array> => { key: 'link', }, { - component: () => , + component: ({ datum }) => , header: t('common.name'), key: 'name', }, diff --git a/src/client/pages/CountryHome/Repository/hooks/useOpenPanel.ts b/src/client/pages/CountryHome/Repository/hooks/useOpenPanel.ts new file mode 100644 index 0000000000..de43054492 --- /dev/null +++ b/src/client/pages/CountryHome/Repository/hooks/useOpenPanel.ts @@ -0,0 +1,18 @@ +import { useCallback } from 'react' + +import { RepositoryItem } from 'meta/cycleData' + +import { useAppDispatch } from 'client/store' +import { RepositoryActions } from 'client/store/ui/repository' + +const initialRepositoryItem: RepositoryItem = { + name: '', + link: '', + file: '', +} as unknown as RepositoryItem + +export const useOpenPanel = (repositoryItem?: RepositoryItem) => { + const _repositoryItem = repositoryItem ?? initialRepositoryItem + const dispatch = useAppDispatch() + return useCallback(() => dispatch(RepositoryActions.setRepositoryItem(_repositoryItem)), [_repositoryItem, dispatch]) +} diff --git a/src/client/pages/Section/Contacts/CreateContact/CreateContact.tsx b/src/client/pages/Section/Contacts/CreateContact/CreateContact.tsx index e08e297c15..0b98fbe2e7 100644 --- a/src/client/pages/Section/Contacts/CreateContact/CreateContact.tsx +++ b/src/client/pages/Section/Contacts/CreateContact/CreateContact.tsx @@ -14,7 +14,7 @@ const CreateContact: React.FC = () => {
) diff --git a/src/client/store/ui/repository/actions/index.ts b/src/client/store/ui/repository/actions/index.ts index 9714bc6932..ac43640a4b 100644 --- a/src/client/store/ui/repository/actions/index.ts +++ b/src/client/store/ui/repository/actions/index.ts @@ -1,5 +1,7 @@ -import { save } from 'client/store/ui/repository/actions/save' +import { upsertRepositoryItem } from 'client/store/ui/repository/actions/upsertRepositoryItem' +import { RepositorySlice } from 'client/store/ui/repository/slice' export const RepositoryActions = { - save, + upsertRepositoryItem, + ...RepositorySlice.actions, } diff --git a/src/client/store/ui/repository/actions/save.ts b/src/client/store/ui/repository/actions/save.ts deleted file mode 100644 index d95ebee997..0000000000 --- a/src/client/store/ui/repository/actions/save.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit' -import axios from 'axios' - -import { ApiEndPoint } from 'meta/api/endpoint' -import { CycleParams } from 'meta/api/request' - -import { RepositoryEdit } from 'client/pages/CountryHome/Repository/Panel/repositoryEdit' - -type Params = CycleParams & { - file: RepositoryEdit -} - -export const save = createAsyncThunk('repository/save', async (props) => { - const { assessmentName, cycleName, countryIso, file } = props - const formData = new FormData() - formData.append('name', file?.name || '') - formData.append('link', file?.link || '') - - if (file?.file) formData.append('file', file.file) - - const params = { countryIso, assessmentName, cycleName } - const config = { params } - await axios.post(ApiEndPoint.CycleData.Repository.one(), formData, config) -}) diff --git a/src/client/store/ui/repository/actions/upsertRepositoryItem.ts b/src/client/store/ui/repository/actions/upsertRepositoryItem.ts new file mode 100644 index 0000000000..0d35e9b637 --- /dev/null +++ b/src/client/store/ui/repository/actions/upsertRepositoryItem.ts @@ -0,0 +1,30 @@ +import { createAsyncThunk } from '@reduxjs/toolkit' +import axios from 'axios' + +import { ApiEndPoint } from 'meta/api/endpoint' +import { CycleParams } from 'meta/api/request' + +import { ThunkApiConfig } from 'client/store/types' +import { RepositorySelectors } from 'client/store/ui/repository/selectors' + +type Props = CycleParams & { + file?: File +} + +export const upsertRepositoryItem = createAsyncThunk( + 'repositoryItem/upsert', + async (props, { getState }) => { + const { file } = props + const repositoryItem = RepositorySelectors.getRepositoryItem(getState()) + const { assessmentName, cycleName, countryIso } = props + const formData = new FormData() + formData.append('name', repositoryItem?.name) + formData.append('link', repositoryItem?.link) + + if (file) formData.append('file', file) + + const params = { countryIso, assessmentName, cycleName } + const config = { params } + await axios.post(ApiEndPoint.CycleData.Repository.one(), formData, config) + } +) diff --git a/src/client/store/ui/repository/hooks/index.ts b/src/client/store/ui/repository/hooks/index.ts index 7bb987cc80..5c676f9737 100644 --- a/src/client/store/ui/repository/hooks/index.ts +++ b/src/client/store/ui/repository/hooks/index.ts @@ -4,3 +4,7 @@ import { RepositorySelectors } from 'client/store/ui/repository/selectors' export const useIsRepositoryLoading = () => { return useAppSelector(RepositorySelectors.isLoading) } + +export const useRepositoryItem = () => { + return useAppSelector(RepositorySelectors.getRepositoryItem) +} diff --git a/src/client/store/ui/repository/reducers/saveReducer.ts b/src/client/store/ui/repository/reducers/saveReducer.ts deleted file mode 100644 index 2640f80465..0000000000 --- a/src/client/store/ui/repository/reducers/saveReducer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ActionReducerMapBuilder } from '@reduxjs/toolkit' - -import { save } from 'client/store/ui/repository/actions/save' -import { RepositoryState } from 'client/store/ui/repository/stateType' - -export const saveReducer = (builder: ActionReducerMapBuilder) => { - builder.addCase(save.pending, (state) => { - state.loading = true - }) - builder.addCase(save.fulfilled, (state) => { - state.loading = false - }) - builder.addCase(save.rejected, (state) => { - state.loading = false - }) -} diff --git a/src/client/store/ui/repository/reducers/upsertRepositoryItemReducer.ts b/src/client/store/ui/repository/reducers/upsertRepositoryItemReducer.ts new file mode 100644 index 0000000000..078f6b88ec --- /dev/null +++ b/src/client/store/ui/repository/reducers/upsertRepositoryItemReducer.ts @@ -0,0 +1,17 @@ +import { ActionReducerMapBuilder } from '@reduxjs/toolkit' + +import { upsertRepositoryItem } from 'client/store/ui/repository/actions/upsertRepositoryItem' +import { RepositoryState } from 'client/store/ui/repository/state' + +export const upsertRepositoryItemReducer = (builder: ActionReducerMapBuilder) => { + builder.addCase(upsertRepositoryItem.pending, (state) => { + state.loading = true + }) + builder.addCase(upsertRepositoryItem.fulfilled, (state) => { + state.loading = false + state.repositoryItem = undefined + }) + builder.addCase(upsertRepositoryItem.rejected, (state) => { + state.loading = false + }) +} diff --git a/src/client/store/ui/repository/selectors/index.ts b/src/client/store/ui/repository/selectors/index.ts index 944c1252a2..f5b9cf98d1 100644 --- a/src/client/store/ui/repository/selectors/index.ts +++ b/src/client/store/ui/repository/selectors/index.ts @@ -5,7 +5,9 @@ import { RepositorySlice } from 'client/store/ui/repository/slice' const _getState = (state: RootState) => state.ui[RepositorySlice.name] const isLoading = createSelector(_getState, (repository) => repository.loading) +const getRepositoryItem = createSelector(_getState, (repository) => repository.repositoryItem) export const RepositorySelectors = { isLoading, + getRepositoryItem, } diff --git a/src/client/store/ui/repository/slice.ts b/src/client/store/ui/repository/slice.ts index 14db66418f..408b2ab56e 100644 --- a/src/client/store/ui/repository/slice.ts +++ b/src/client/store/ui/repository/slice.ts @@ -1,15 +1,20 @@ -import { createSlice, Reducer } from '@reduxjs/toolkit' +import { createSlice, PayloadAction, Reducer } from '@reduxjs/toolkit' -import { initialState, RepositoryState } from 'client/store/ui/repository/state' +import { RepositoryItem } from 'meta/cycleData' -import { saveReducer } from './reducers/saveReducer' +import { upsertRepositoryItemReducer } from 'client/store/ui/repository/reducers/upsertRepositoryItemReducer' +import { initialState, RepositoryState } from 'client/store/ui/repository/state' export const RepositorySlice = createSlice({ name: 'repository', initialState, - reducers: {}, + reducers: { + setRepositoryItem: (state: RepositoryState, action: PayloadAction) => { + state.repositoryItem = action.payload + }, + }, extraReducers: (builder) => { - saveReducer(builder) + upsertRepositoryItemReducer(builder) }, }) diff --git a/src/client/store/ui/repository/state.ts b/src/client/store/ui/repository/state.ts index 2fdefb1f26..997f6c16a6 100644 --- a/src/client/store/ui/repository/state.ts +++ b/src/client/store/ui/repository/state.ts @@ -1,5 +1,8 @@ +import { RepositoryItem } from 'meta/cycleData' + export type RepositoryState = { loading: boolean + repositoryItem?: RepositoryItem } export const initialState: RepositoryState = { diff --git a/src/i18n/resources/ar.js b/src/i18n/resources/ar.js index 3b230d5d56..13fa84b4b6 100644 --- a/src/i18n/resources/ar.js +++ b/src/i18n/resources/ar.js @@ -468,7 +468,6 @@ The FRA team delete: 'إلغاء', writeComment: 'كتابة تعليق...', commentingClosed: 'إغلاق التعليقات', - add: 'إضافة', cancel: 'إلغاء', loading: 'تحميل', }, diff --git a/src/i18n/resources/ar/common.js b/src/i18n/resources/ar/common.js index 37ac7137f2..194e95c333 100644 --- a/src/i18n/resources/ar/common.js +++ b/src/i18n/resources/ar/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: 'تم قبوله', + add: 'إضافة', apply: 'نفذ', cancel: 'إلغاء', clearTable: 'حذف بيانات الجدول', diff --git a/src/i18n/resources/en.js b/src/i18n/resources/en.js index 83f7a4ee9c..a778c458b0 100644 --- a/src/i18n/resources/en.js +++ b/src/i18n/resources/en.js @@ -454,7 +454,6 @@ The FRA team delete: 'Delete', writeComment: 'Write a comment…', commentingClosed: 'Commenting closed', - add: 'Add', cancel: 'Cancel', }, diff --git a/src/i18n/resources/en/common.js b/src/i18n/resources/en/common.js index 4395619fa4..fd49bbb344 100644 --- a/src/i18n/resources/en/common.js +++ b/src/i18n/resources/en/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: 'Accepted', + add: 'Add', apply: 'Apply', areYouSureYouWantToDeleteAllTableData: 'Are you sure you want to delete all data from the table?', cancel: 'Cancel', diff --git a/src/i18n/resources/es.js b/src/i18n/resources/es.js index 551c4e0168..5443cd4c9e 100644 --- a/src/i18n/resources/es.js +++ b/src/i18n/resources/es.js @@ -390,7 +390,6 @@ El equipo de FRA delete: 'Borrar', writeComment: 'Escriba un comentario…', commentingClosed: 'Se han desactivado los comentarios', - add: 'Añadir', cancel: 'Cancelar', loading: 'Cargando', }, diff --git a/src/i18n/resources/es/common.js b/src/i18n/resources/es/common.js index 0132e129a0..236baeefb8 100644 --- a/src/i18n/resources/es/common.js +++ b/src/i18n/resources/es/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: 'Aceptado', + add: 'Añadir', apply: 'Aplicar', cancel: 'Cancelar', clearTable: 'Despejar la tabla', diff --git a/src/i18n/resources/fr.js b/src/i18n/resources/fr.js index 20ee19cb65..b2d50bcf6c 100644 --- a/src/i18n/resources/fr.js +++ b/src/i18n/resources/fr.js @@ -385,7 +385,6 @@ L'équipe de FRA delete: 'Supprimer', writeComment: 'Écrire un commentaire…', commentingClosed: 'Période de commentaires terminée', - add: 'Ajouter', cancel: 'Effacer', loading: 'Chargement', }, diff --git a/src/i18n/resources/fr/common.js b/src/i18n/resources/fr/common.js index 8f2c690a0f..d40f6d80ac 100644 --- a/src/i18n/resources/fr/common.js +++ b/src/i18n/resources/fr/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: 'Accepté', + add: 'Ajouter', apply: 'Appliquer', cancel: 'Effacer', clearTable: 'Supprimer tableau', diff --git a/src/i18n/resources/ru.js b/src/i18n/resources/ru.js index 35eafeaa3c..1e3f0c846b 100644 --- a/src/i18n/resources/ru.js +++ b/src/i18n/resources/ru.js @@ -415,7 +415,6 @@ module.exports.translation = { delete: 'Удалить', writeComment: 'Написать комментарий…', commentingClosed: 'Комментирование закрыто', - add: 'Добавить', cancel: 'Отмена', loading: 'Загрузка', }, diff --git a/src/i18n/resources/ru/common.js b/src/i18n/resources/ru/common.js index da7c8fd6ca..38c1359cfd 100644 --- a/src/i18n/resources/ru/common.js +++ b/src/i18n/resources/ru/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: 'Принято', + add: 'Добавить', apply: 'Применить', areYouSureYouWantToDeleteAllTableData: 'Вы уверены, что хотите удалить все данные из таблицы?', cancel: 'Отмена', diff --git a/src/i18n/resources/zh.js b/src/i18n/resources/zh.js index 8fdcd3f3bc..31b2d484ce 100644 --- a/src/i18n/resources/zh.js +++ b/src/i18n/resources/zh.js @@ -436,7 +436,6 @@ FRA工作组 delete: '删除', writeComment: '写评论…', commentingClosed: '评论关闭', - add: '添加', cancel: '取消', loading: '正在加载', }, diff --git a/src/i18n/resources/zh/common.js b/src/i18n/resources/zh/common.js index 619c0e0ab3..a07337f0a7 100644 --- a/src/i18n/resources/zh/common.js +++ b/src/i18n/resources/zh/common.js @@ -1,5 +1,6 @@ module.exports = { accepted: '已接受', + add: '添加', apply: '应用', cancel: '取消', clearTable: '清除表格', diff --git a/src/server/repository/assessmentCycle/repository/create.ts b/src/server/repository/assessmentCycle/repository/create.ts index 2c323695d7..1675fd13a9 100644 --- a/src/server/repository/assessmentCycle/repository/create.ts +++ b/src/server/repository/assessmentCycle/repository/create.ts @@ -18,7 +18,7 @@ type Props = { export const create = async (props: Props, client: BaseProtocol = DB): Promise => { const { assessment, cycle, countryIso, fileUuid, link, name } = props - if (fileUuid && link) throw new Error('Cannot create both fileUuid and link') + if (fileUuid && link) throw new Error('Cannot create both file and link') if (!fileUuid && !link) throw new Error('No file or link provided') const schemaCycle = Schemas.getNameCycle(assessment, cycle)