diff --git a/packages/app/src/__deprecated__/renderer/locales/default/en-US.json b/packages/app/src/__deprecated__/renderer/locales/default/en-US.json index e059041608..20516a48f6 100644 --- a/packages/app/src/__deprecated__/renderer/locales/default/en-US.json +++ b/packages/app/src/__deprecated__/renderer/locales/default/en-US.json @@ -32,6 +32,7 @@ "component.contactModalSuccessBody": "We will contact you as soon as the problem is resolved", "component.contactModalSuccessBodyWithoutEmail": "We will check the issue as soon as possible.", "component.contactModalSuccessTitle": "Message sent", + "component.contactModalTitle": "Mudita Center Support", "component.contactSupportModalActionButton": "Send", "component.contactSupportModalActionButtonProgress": "Sending", "component.contactSupportModalDescription": "Contact Mudita support team and we will do our best to help you resolve your issues.", @@ -153,6 +154,7 @@ "component.supportModalSuccessBody": "We will contact you as soon as the problem is resolved", "component.supportModalSuccessBodyWithoutEmail": "We will check the issue as soon as possible.", "component.supportModalSuccessTitle": "Message sent", + "component.supportModalTitle": "Mudita Center Support", "component.table.close": "Close", "component.textEditorCancelButton": "Reject changes", "component.textEditorSaveButton": "Save to phone", @@ -178,7 +180,7 @@ "component.updateDownloadedModalDescription": "Do you want to update app now or during next launch?", "component.updateDownloadedModalMessage": "Update is ready to install", "component.updateDownloadedModalWarning": "Note that update process will require app {osxPlatform, select, false {restart} true {quit}}.\nMake sure you saved all data you're currently working on.", - "component.updateErrorModalDescription": "Please download the latest Mudita Center version from {link}", + "component.updateErrorModalDescription": "Please restart the app or update it manually.", "component.updateErrorModalMessage": "Error", "component.updateForcedModalButton": "Download", "component.updateForcedModalCurrentVersion": "Your current version: v.{version}", @@ -418,12 +420,16 @@ "module.filesManager.duplicatedFilesUploadModalPendingFilesTextInfo": "Of the {uploadFilesCount} files you selected, {duplicatedFilesCount} {duplicatedFilesCount, plural, one {file} other {files}} with that name\nalready exist on your device. Change the name and try again.", "module.filesManager.duplicatedFilesUploadModalTextInfo": "The file with this name already exists on the device. Change the name and try again.", "module.filesManager.duplicatedFilesUploadModalTitle": "Upload files", + "module.filesManager.invalidFiledModalFilesInfo": "We found some files which wouldn't work on your device. To avoid problems we only uploaded the files that will work.", + "module.filesManager.invalidFiledModalHelpInfo": "To find out more about which files work on your device, visit our {link}.", + "module.filesManager.invalidFiledModalTitle": "File upload complete", + "module.filesManager.invalidFiledModalUploadInfo": "To avoid problems we only uploaded the files that will work.", "module.filesManager.panelSearchPlaceholder": "Search music files", + "module.filesManager.pendingUploadModalAbortButtonText": "Abort", "module.filesManager.pendingUploadModalActionButton": "Ok", "module.filesManager.pendingUploadModalHeader": "Files uploading", "module.filesManager.pendingUploadModalTextDetailsInfo": "The first {count, plural, one {file} other {# files}} will be uploaded to the device.", - "module.filesManager.pendingUploadModalTextInfo": "Mudita Center cannot load all files.\nThe number of selected files exceeds the limit.", - "module.filesManager.pendingUploadModalAbortButtonText": "Abort", + "module.filesManager.pendingUploadModalTextInfo": "Mudita Center cannot load all files.\\nThe number of selected files exceeds the limit.", "module.filesManager.pendingUploadModalTitle": "Upload files", "module.filesManager.selectionNumber": "{num, plural, =-1 {All Files} one {# File} other {# Files}} selected", "module.filesManager.tooManyFilesTooltipDescription": "The maximum number of files has been reached ({filesSlotsHarmonyMaxLimit} files)", @@ -789,11 +795,6 @@ "module.settings.aboutLicense": "License", "module.settings.aboutPrivacyPolicy": "Privacy Policy", "module.settings.aboutTermsOfService": "Terms of service", - "module.settings.checkForFailedAppUpdateTitle": "Mudita Center", - "module.settings.checkForFailedAppUpdateSubtitle": "Checking failed", - "module.settings.checkForFailedAppUpdateBody": "Opps, something went wrong. \nPlease check your internet connection", - "module.settings.loadingTitle": "Mudita Center", - "module.settings.loadingSubtitle": "Checking for update", "module.settings.audioConversion": "Audio Conversion", "module.settings.audioConversionAlwaysAskLabel": "Always ask", "module.settings.audioConversionConversionFormat": "Conversion format:", @@ -810,11 +811,15 @@ "module.settings.backupDescription": " ", "module.settings.backupLabel": "Backup Location", "module.settings.backupTetheringLabel": "Start tethering", - "module.settings.systemUpdateCheckFailed": "Checking for update failed", + "module.settings.checkForFailedAppUpdateBody": "Opps, something went wrong. \nPlease check your internet connection", + "module.settings.checkForFailedAppUpdateSubtitle": "Checking failed", + "module.settings.checkForFailedAppUpdateTitle": "Mudita Center", "module.settings.collectingData": "Send Mudita Center logs to Mudita", "module.settings.collectingDataTooltip": "Sending logs is completely voluntary. Mudita doesn’t collect nor store any sensitive data - find out more in Mudita Center Privacy Policy (https://mudita.com/legal/privacy-policy/mudita-center/)", "module.settings.connection": "General", "module.settings.description": " ", + "module.settings.loadingSubtitle": "Checking for update", + "module.settings.loadingTitle": "Mudita Center", "module.settings.notifications": "Notifications", "module.settings.notificationsDescription": "Select which notifications you want to receive while using Mudita Center:", "module.settings.notificationsIncomingCallsNotificationsLabel": "Incoming calls notifications", @@ -828,6 +833,7 @@ "module.settings.privacyPolicyModalHeader": "Read and accept the Privacy policy", "module.settings.privacyPolicyModalLink": "Read the Privacy Policy", "module.settings.privacyPolicyModalTitle": "Privacy Policy", + "module.settings.systemUpdateCheckFailed": "Checking for update failed", "module.settings.tetheringLabel": "Start tethering", "module.template.dropdownDelete": "Delete Template", "module.templates": "Templates", @@ -875,7 +881,6 @@ "module.templates.temporary": "New template", "module.templates.text": "Template...", "module.templates.tooLong": "The template is too long", - "module.templates.newLine": "The template contains new line character", "module.templates.unsavedTemplate": "unsaved", "module.templates.updatingModalErrorSubtitle": "Updating failed", "module.templates.updatingModalErrorTitle": "Updating Template", diff --git a/packages/app/src/__deprecated__/renderer/locales/default/pl-PL.json b/packages/app/src/__deprecated__/renderer/locales/default/pl-PL.json index 69ea9059b0..e9fe7cffa1 100644 --- a/packages/app/src/__deprecated__/renderer/locales/default/pl-PL.json +++ b/packages/app/src/__deprecated__/renderer/locales/default/pl-PL.json @@ -1,3 +1,3 @@ { "component.collectingDataModalBody": "I agree on sending anonymized data to Mudita" -} \ No newline at end of file +} diff --git a/packages/app/src/files-manager/actions/base.action.ts b/packages/app/src/files-manager/actions/base.action.ts index ddce07692f..78fba8e3f9 100644 --- a/packages/app/src/files-manager/actions/base.action.ts +++ b/packages/app/src/files-manager/actions/base.action.ts @@ -43,3 +43,7 @@ export const setDuplicatedFiles = createAction( FilesManagerEvent.SetDuplicatedFiles ) export const resetFiles = createAction(FilesManagerEvent.ResetFiles) + +export const setInvalidFiles = createAction( + FilesManagerEvent.SetInvalidFiles +) diff --git a/packages/app/src/files-manager/actions/upload-file.action.ts b/packages/app/src/files-manager/actions/upload-file.action.ts index b0aa57f431..24a11a86ed 100644 --- a/packages/app/src/files-manager/actions/upload-file.action.ts +++ b/packages/app/src/files-manager/actions/upload-file.action.ts @@ -16,6 +16,7 @@ import { uploadFilesRequest } from "App/files-manager/requests" import { getFiles } from "App/files-manager/actions/get-files.action" import { setDuplicatedFiles, + setInvalidFiles, setPendingFilesToUpload, setUploadBlocked, setUploadingFileCount, @@ -52,9 +53,9 @@ export const uploadFile = createAsyncThunk< return rejectWithValue("no files to upload") } - const allFilesSupported = checkFilesExtensions(filePaths) + const { validFiles, invalidFiles } = checkFilesExtensions(filePaths) - if (!allFilesSupported) { + if (!validFiles.length && invalidFiles.length) { dispatch(setUploadBlocked(false)) return rejectWithValue( new AppError( @@ -66,11 +67,11 @@ export const uploadFile = createAsyncThunk< const duplicatedFiles = getDuplicatedFiles( state.filesManager.files, - filePaths + validFiles ) if (duplicatedFiles.length > 0) { - const uniqueFiles = getUniqueFiles(state.filesManager.files, filePaths) + const uniqueFiles = getUniqueFiles(state.filesManager.files, validFiles) dispatch(setPendingFilesToUpload(uniqueFiles)) dispatch(setDuplicatedFiles(duplicatedFiles)) dispatch(setUploadBlocked(false)) @@ -96,17 +97,17 @@ export const uploadFile = createAsyncThunk< if ( state.device.deviceType === DeviceType.MuditaHarmony && - harmonyFreeFilesSlotsCount < filePaths.length + harmonyFreeFilesSlotsCount < validFiles.length ) { dispatch( - setPendingFilesToUpload(filePaths.slice(0, harmonyFreeFilesSlotsCount)) + setPendingFilesToUpload(validFiles.slice(0, harmonyFreeFilesSlotsCount)) ) dispatch(setUploadingState(State.Pending)) dispatch(setUploadBlocked(false)) return } - dispatch(setUploadingFileCount(filePaths.length)) + dispatch(setUploadingFileCount(validFiles.length)) dispatch(setUploadingState(State.Loading)) const directory = @@ -116,7 +117,7 @@ export const uploadFile = createAsyncThunk< const result = await uploadFilesRequest({ directory, - filePaths, + filePaths: validFiles, }) void dispatch(getFiles(directory)) @@ -128,6 +129,9 @@ export const uploadFile = createAsyncThunk< void dispatch(loadStorageInfoAction()) dispatch(setUploadingState(State.Loaded)) dispatch(setUploadBlocked(false)) + if (invalidFiles.length) { + dispatch(setInvalidFiles(invalidFiles)) + } return } diff --git a/packages/app/src/files-manager/components/files-manager/files-manager.component.tsx b/packages/app/src/files-manager/components/files-manager/files-manager.component.tsx index a4c736446d..d384839fc6 100644 --- a/packages/app/src/files-manager/components/files-manager/files-manager.component.tsx +++ b/packages/app/src/files-manager/components/files-manager/files-manager.component.tsx @@ -201,6 +201,7 @@ const FilesManager: FunctionComponent = ({ Array.from(fileInputRef.current?.files).map((file) => file.path) ) ) + fileInputRef.current.value = "" } } diff --git a/packages/app/src/files-manager/components/invalid-files-modal/invalid-files-modal.component.tsx b/packages/app/src/files-manager/components/invalid-files-modal/invalid-files-modal.component.tsx new file mode 100644 index 0000000000..79012e6626 --- /dev/null +++ b/packages/app/src/files-manager/components/invalid-files-modal/invalid-files-modal.component.tsx @@ -0,0 +1,97 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { defineMessages } from "react-intl" +import { FunctionComponent } from "App/__deprecated__/renderer/types/function-component.interface" +import { useDispatch, useSelector } from "react-redux" +import { getInvalidFiles } from "App/files-manager/selectors/get-invalid-files.selector" +import { + ModalContent, + ModalDialog, + RoundIconWrapper, +} from "App/ui/components/modal-dialog" +import React from "react" +import { ModalSize } from "App/__deprecated__/renderer/components/core/modal/modal.interface" +import { intl } from "App/__deprecated__/renderer/utils/intl" +import Icon from "App/__deprecated__/renderer/components/core/icon/icon.component" +import { IconType } from "App/__deprecated__/renderer/components/core/icon/icon-type" +import Text, { + TextDisplayStyle, +} from "App/__deprecated__/renderer/components/core/text/text.component" +import { resetUploadingState } from "App/files-manager/actions" +import styled from "styled-components" +import { + fontWeight, + textColor, +} from "App/__deprecated__/renderer/styles/theming/theme-getters" +import { ipcRenderer } from "electron-better-ipc" +import { HelpActions } from "App/__deprecated__/common/enums/help-actions.enum" + +const messages = defineMessages({ + title: { + id: "module.filesManager.invalidFiledModalTitle", + }, + filesInfo: { + id: "module.filesManager.invalidFiledModalFilesInfo", + }, + helpInfo: { + id: "module.filesManager.invalidFiledModalHelpInfo", + }, +}) + +const StyledLink = styled.a` + text-decoration: underline; + cursor: pointer; + font-size: 1.4rem; + font-weight: ${fontWeight("default")}; + color: ${textColor("action")}; +` +const StyledModalContent = styled(ModalContent)` + p { + text-align: left; + } +` + +export const InvalidFilesModal: FunctionComponent = ({ ...props }) => { + const invalidFiles = useSelector(getInvalidFiles) + const openHelpWindow = () => ipcRenderer.callMain(HelpActions.OpenWindow) + + const dispatch = useDispatch() + return ( + { + dispatch(resetUploadingState()) + }} + {...props} + > + + + + + + help pages + ), + }, + }} + /> + + + ) +} diff --git a/packages/app/src/files-manager/components/upload-files-modals/upload-files-modals.component.tsx b/packages/app/src/files-manager/components/upload-files-modals/upload-files-modals.component.tsx index cf6a8e0d0b..b5bcd78574 100644 --- a/packages/app/src/files-manager/components/upload-files-modals/upload-files-modals.component.tsx +++ b/packages/app/src/files-manager/components/upload-files-modals/upload-files-modals.component.tsx @@ -17,6 +17,7 @@ import PendingUploadModal from "App/files-manager/components/pending-upload-moda import DuplicatedFilesModal from "App/files-manager/components/duplicated-files-modal/duplicated-files-modal.component" import UnsupportedFileFormatModal from "App/files-manager/components/unsupported-file-format-modal/unsupported-file-format-modal.component" import UnsupportedFileSizeModal from "App/files-manager/components/unsupported-file-size-modal/unsupported-file-size-modal.component" +import { InvalidFilesModal } from "../invalid-files-modal/invalid-files-modal.component" const messages = defineMessages({ uploadingModalInfo: { id: "module.filesManager.uploadingModalInfo" }, @@ -100,6 +101,7 @@ export const UploadFilesModals: FunctionComponent = ({ + ) } diff --git a/packages/app/src/files-manager/constants/event.enum.ts b/packages/app/src/files-manager/constants/event.enum.ts index ce9eddfb5a..abdc6c1362 100644 --- a/packages/app/src/files-manager/constants/event.enum.ts +++ b/packages/app/src/files-manager/constants/event.enum.ts @@ -22,5 +22,6 @@ export enum FilesManagerEvent { AbortPendingUpload = "FILES_MANAGER_ABORT_PENDING_UPLOAD", ContinuePendingUpload = "FILES_MANAGER_CONTINUE_PENDING_UPLOAD", SetDuplicatedFiles = "FILES_MANAGER_SET_DUPLICATED_FILES", + SetInvalidFiles = "FILES_MANAGER_SET_INVALID_FILES", ResetFiles = "FILES_MANAGER_RESET_FILES", } diff --git a/packages/app/src/files-manager/helpers/check-files-extensions.helper.test.ts b/packages/app/src/files-manager/helpers/check-files-extensions.helper.test.ts index 67adbfa03a..5cb2803847 100644 --- a/packages/app/src/files-manager/helpers/check-files-extensions.helper.test.ts +++ b/packages/app/src/files-manager/helpers/check-files-extensions.helper.test.ts @@ -10,15 +10,25 @@ const supportedFiles = eligibleFormat.map((extension) => `file.${extension}`) describe("`checkFilesExtensions` helper", () => { test("all correct extensions", () => { - expect(checkFilesExtensions(supportedFiles)).toBeTruthy() + expect(checkFilesExtensions(supportedFiles)).toEqual({ + validFiles: supportedFiles, + invalidFiles: [], + }) }) test("empty files array", () => { - expect(checkFilesExtensions([])).toBeTruthy() + expect(checkFilesExtensions([])).toEqual({ + validFiles: [], + invalidFiles: [], + }) }) test("at least one unsupported extension", () => { - const unsupportedFiles = [...supportedFiles, "file.unsupported"] - expect(checkFilesExtensions(unsupportedFiles)).toBeFalsy() + const unsupportedFiles = ["file.unsupported"] + const allFiles = [...supportedFiles, ...unsupportedFiles] + expect(checkFilesExtensions(allFiles)).toEqual({ + validFiles: supportedFiles, + invalidFiles: unsupportedFiles, + }) }) }) diff --git a/packages/app/src/files-manager/helpers/check-files-extensions.helper.ts b/packages/app/src/files-manager/helpers/check-files-extensions.helper.ts index 1b035b3cfa..5f22969c43 100644 --- a/packages/app/src/files-manager/helpers/check-files-extensions.helper.ts +++ b/packages/app/src/files-manager/helpers/check-files-extensions.helper.ts @@ -5,10 +5,15 @@ import { eligibleFormat } from "App/files-manager/constants/eligible-format.constant" -export const checkFilesExtensions = (filesPaths: string[]): boolean => { - return filesPaths.every((filePath) => { - return eligibleFormat.includes( - (filePath.split(".").pop() ?? "").toLocaleLowerCase() - ) - }) +export const checkFilesExtensions = ( + filesPaths: string[] +): { validFiles: string[]; invalidFiles: string[] } => { + const isPathEligible = (path: string) => + eligibleFormat.includes((path.split(".").pop() ?? "").toLocaleLowerCase()) + const validFiles = filesPaths.filter((filePath) => isPathEligible(filePath)) + const invalidFiles = filesPaths.filter( + (filePath) => !isPathEligible(filePath) + ) + + return { validFiles, invalidFiles } } diff --git a/packages/app/src/files-manager/reducers/files-manager.interface.ts b/packages/app/src/files-manager/reducers/files-manager.interface.ts index 4c626c5824..958136e0db 100644 --- a/packages/app/src/files-manager/reducers/files-manager.interface.ts +++ b/packages/app/src/files-manager/reducers/files-manager.interface.ts @@ -19,4 +19,5 @@ export interface FilesManagerState { uploadBlocked: boolean uploadPendingFiles: string[] duplicatedFiles: string[] + invalidFiles: string[] } diff --git a/packages/app/src/files-manager/reducers/files-manager.reducer.ts b/packages/app/src/files-manager/reducers/files-manager.reducer.ts index a0110f61b7..c95ddf3b14 100644 --- a/packages/app/src/files-manager/reducers/files-manager.reducer.ts +++ b/packages/app/src/files-manager/reducers/files-manager.reducer.ts @@ -22,6 +22,7 @@ import { setDuplicatedFiles, resetUploadingStateAfterSuccess, resetFiles, + setInvalidFiles, } from "App/files-manager/actions" import { changeLocation } from "App/core/actions" import { FilesManagerState } from "App/files-manager/reducers/files-manager.interface" @@ -42,6 +43,7 @@ export const initialState: FilesManagerState = { error: null, uploadPendingFiles: [], duplicatedFiles: [], + invalidFiles: [], } export const filesManagerReducer = createReducer( @@ -173,6 +175,7 @@ export const filesManagerReducer = createReducer( uploadingFileCount: 0, uploadBlocked: false, duplicatedFiles: [], + invalidFiles: [], } }) .addCase(resetUploadingStateAfterSuccess, (state) => { @@ -203,6 +206,9 @@ export const filesManagerReducer = createReducer( .addCase(setDuplicatedFiles, (state, action) => { state.duplicatedFiles = action.payload }) + .addCase(setInvalidFiles, (state, action) => { + state.invalidFiles = action.payload + }) .addCase(resetFiles, (state, _) => { state.files = null }) diff --git a/packages/app/src/files-manager/selectors/get-invalid-files.selector.ts b/packages/app/src/files-manager/selectors/get-invalid-files.selector.ts new file mode 100644 index 0000000000..8439bc6a50 --- /dev/null +++ b/packages/app/src/files-manager/selectors/get-invalid-files.selector.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) Mudita sp. z o.o. All rights reserved. + * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md + */ + +import { createSelector } from "@reduxjs/toolkit" +import { getFilesManager } from "App/files-manager/selectors/get-files-manager.selector" + +export const getInvalidFiles = createSelector( + getFilesManager, + (filesManager): string[] => { + return filesManager.invalidFiles + } +)