diff --git a/packages/client/public/locales/en/EmptyView.json b/packages/client/public/locales/en/EmptyView.json index c45227d261..e40265d495 100644 --- a/packages/client/public/locales/en/EmptyView.json +++ b/packages/client/public/locales/en/EmptyView.json @@ -35,5 +35,10 @@ "UploadFromPortalDescription": "Upload any type files from Documents or Rooms", "UploadFromPortalTitle": "Upload from {{productName}}", "UploadPDFFormOptionDescription": "Select a ready PDF form available in {{productName}} and upload it to the room.", - "UserEmptyDescription": "Files and folders uploaded by admins will appeared here." + "UserEmptyDescription": "Files and folders uploaded by admins will appeared here.", + "InviteRootRoomDescription": "Send an invitation to add new members to your {{productName}}", + "MigrationDataTitle": "Migration Data", + "MigrationDataDescription": "Import data to your {{productName}} from ONLYOFFICE Workspace, Google Workspace, or Nextcloud.", + "EmptyRootRoomUserTitle": "There are no rooms here yet", + "EmptyRootRoomUserDescription": "The shared room will appear here." } diff --git a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.helpers.tsx b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.helpers.tsx index e9c5472b12..4299ec8638 100644 --- a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.helpers.tsx +++ b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.helpers.tsx @@ -2,6 +2,7 @@ import React from "react"; import { P, match } from "ts-pattern"; import { + EmployeeType, FilesSelectorFilterTypes, FilterType, FolderType, @@ -13,6 +14,7 @@ import CreateNewFormIcon from "PUBLIC_DIR/images/emptyview/create.new.form.svg"; import CreateNewSpreadsheetIcon from "PUBLIC_DIR/images/emptyview/create.new.spreadsheet.svg"; import CreateNewPresentation from "PUBLIC_DIR/images/emptyview/create.new.presentation.svg"; import CreateRoom from "PUBLIC_DIR/images/emptyview/create.room.svg"; +import InviteUserFormIcon from "PUBLIC_DIR/images/emptyview/invite.user.svg"; import SharedIcon from "PUBLIC_DIR/images/emptyview/share.svg"; @@ -57,7 +59,7 @@ export const getDescription = ( ): string => { const isNotAdmin = isUser(access); - if (isRootEmptyPage) return getRootDesctiption(t, rootFolderType); + if (isRootEmptyPage) return getRootDesctiption(t, access, rootFolderType); if (isFolder) return getFolderDescription( @@ -85,7 +87,7 @@ export const getTitle = ( ): string => { const isNotAdmin = isUser(access); - if (isRootEmptyPage) return getRootTitle(t, rootFolderType); + if (isRootEmptyPage) return getRootTitle(t, access, rootFolderType); if (isFolder) return getFolderTitle( @@ -232,6 +234,28 @@ export const getOptions = ( disabled: false, }; + const inviteRootRoom = { + title: t("EmptyView:InviteNewUsers"), + description: t("EmptyView:InviteRootRoomDescription", { + productName: t("Common:ProductName"), + }), + icon: , + key: "invite-root-room", + onClick: () => actions.inviteRootUser(EmployeeType.Guest), + disabled: false, + }; + + const migrationData = { + title: t("EmptyView:MigrationDataTitle"), + description: t("EmptyView:MigrationDataDescription", { + productName: t("Common:ProductName"), + }), + icon: , + key: "migration-data", + onClick: () => actions.navigate("/portal-settings/data-import"), + disabled: false, + }; + const createFile: EmptyViewItemType = { title: t("EmptyView:CreateNewFileTitle"), description: t("EmptyView:CreateNewFileDescription"), @@ -276,13 +300,13 @@ export const getOptions = ( if (isArchiveFolderRoot) return []; if (isRootEmptyPage) { - switch (rootFolderType) { - case FolderType.Rooms: - return [createRoom]; - - default: - return []; - } + return match([rootFolderType, access]) + .with([FolderType.Rooms, ShareAccessRights.None], () => [ + createRoom, + inviteRootRoom, + migrationData, + ]) + .otherwise(() => []); } if (isFolder) { diff --git a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.tsx b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.tsx index cbd340c6cb..0014a5a2f0 100644 --- a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.tsx +++ b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.tsx @@ -2,6 +2,7 @@ import { useTheme } from "styled-components"; import { inject, observer } from "mobx-react"; import { useTranslation } from "react-i18next"; import React, { useMemo, useCallback } from "react"; +import { useNavigate } from "react-router-dom"; import { Events, @@ -47,7 +48,10 @@ const EmptyViewContainer = observer( onCreateAndCopySharedLink, setSelectFileFormRoomDialogVisible, setInviteUsersWarningDialogVisible, + inviteUser: inviteRootUser, }: EmptyViewContainerProps) => { + const navigate = useNavigate(); + const { t } = useTranslation([ "EmptyView", "Files", @@ -189,6 +193,8 @@ const EmptyViewContainer = observer( createAndCopySharedLink, openInfoPanel, onCreateRoom, + inviteRootUser, + navigate, }, ), [ @@ -209,6 +215,8 @@ const EmptyViewContainer = observer( onCreate, openInfoPanel, onCreateRoom, + inviteRootUser, + navigate, ], ); @@ -237,7 +245,7 @@ const InjectedEmptyViewContainer = inject< infoPanelStore, currentTariffStatusStore, }): InjectedEmptyViewContainerProps => { - const { onClickInviteUsers, onCreateAndCopySharedLink } = + const { onClickInviteUsers, onCreateAndCopySharedLink, inviteUser } = contextOptionsStore; const { isGracePeriod } = currentTariffStatusStore; @@ -270,6 +278,7 @@ const InjectedEmptyViewContainer = inject< setInviteUsersWarningDialogVisible, setVisibleInfoPanel, setViewInfoPanel, + inviteUser, }; }, )(EmptyViewContainer as React.FC); diff --git a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.types.ts b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.types.ts index ce91603022..fc06c07dc6 100644 --- a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.types.ts +++ b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.types.ts @@ -1,5 +1,5 @@ -import type { TFolderSecurity } from "@docspace/shared/api/files/types"; -import type { TRoomSecurity } from "@docspace/shared/api/rooms/types"; +import type { NavigateFunction } from "react-router-dom"; + import type { FilesSelectorFilterTypes, FilterType, @@ -41,27 +41,34 @@ export interface OutEmptyViewContainerProps { isRootEmptyPage: boolean; } -export interface InjectedEmptyViewContainerProps { - access: Nullable; - security: Nullable; - selectedFolder?: ReturnType< +export interface InjectedEmptyViewContainerProps + extends Pick< + TStore["contextOptionsStore"], + "inviteUser" | "onCreateAndCopySharedLink" | "onClickInviteUsers" + >, + Pick< + TStore["dialogsStore"], + | "setSelectFileFormRoomDialogVisible" + | "setInviteUsersWarningDialogVisible" + >, + Pick< + TStore["selectedFolderStore"], + "access" | "security" | "rootFolderType" + > { + selectedFolder: ReturnType< TStore["selectedFolderStore"]["getSelectedFolder"] >; isGracePeriod: boolean; isVisibleInfoPanel: boolean; - rootFolderType: Nullable; - onClickInviteUsers: (folderId: string | number, roomType: RoomsType) => void; - onCreateAndCopySharedLink: TStore["contextOptionsStore"]["onCreateAndCopySharedLink"]; - setSelectFileFormRoomDialogVisible: TStore["dialogsStore"]["setSelectFileFormRoomDialogVisible"]; setVisibleInfoPanel: (arg: boolean) => void; setViewInfoPanel: TStore["infoPanelStore"]["setView"]; - setInviteUsersWarningDialogVisible: TStore["dialogsStore"]["setInviteUsersWarningDialogVisible"]; } export type EmptyViewContainerProps = OutEmptyViewContainerProps & InjectedEmptyViewContainerProps; export type OptionActions = { + navigate: NavigateFunction; inviteUser: VoidFunction; onCreate: (extension: ExtensiontionType, withoutDialog?: boolean) => void; uploadFromDocspace: ( @@ -72,4 +79,5 @@ export type OptionActions = { createAndCopySharedLink: VoidFunction; openInfoPanel: VoidFunction; onCreateRoom: VoidFunction; + inviteRootUser: TStore["contextOptionsStore"]["inviteUser"]; }; diff --git a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.utils.tsx b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.utils.tsx index 90f64e798d..a5e41978ff 100644 --- a/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.utils.tsx +++ b/packages/client/src/components/EmptyContainer/sub-components/EmptyViewContainer/EmptyViewContainer.utils.tsx @@ -34,6 +34,9 @@ import CreateNewFormIcon from "PUBLIC_DIR/images/emptyview/create.new.form.svg"; import EmptyRoomsRootDarkIcon from "PUBLIC_DIR/images/emptyview/empty.rooms.root.dark.svg"; import EmptyRoomsRootLightIcon from "PUBLIC_DIR/images/emptyview/empty.rooms.root.light.svg"; +import EmptyRoomsRootUserDarkIcon from "PUBLIC_DIR/images/emptyview/empty.rooms.root.user.dark.svg"; +import EmptyRoomsRootUserLightIcon from "PUBLIC_DIR/images/emptyview/empty.rooms.root.user.light.svg"; + import EmptyFormRoomDarkIcon from "PUBLIC_DIR/images/emptyview/empty.form.room.dark.svg"; import EmptyFormRoomLightIcon from "PUBLIC_DIR/images/emptyview/empty.form.room.light.svg"; @@ -88,6 +91,8 @@ import type { } from "./EmptyViewContainer.types"; export const isUser = (access: AccessType) => { + console.log({ access }); + return ( access !== ShareAccessRights.None && access !== ShareAccessRights.RoomManager && @@ -155,14 +160,20 @@ export const getRoomDescription = ( export const getRootDesctiption = ( t: TTranslation, + access: AccessType, rootFolderType: Nullable, ) => { - return match([rootFolderType]) - .with([FolderType.Rooms], () => t("Files:RoomEmptyContainerDescription")) - .with([FolderType.USER], () => t("Test")) - .with([FolderType.Recent], () => t("Test")) - .with([FolderType.Archive], () => t("Test")) - .with([FolderType.TRASH], () => t("Test")) + return match([rootFolderType, access]) + .with([FolderType.Rooms, ShareAccessRights.None], () => + t("Files:RoomEmptyContainerDescription"), + ) + .with([FolderType.Rooms, ShareAccessRights.DenyAccess], () => + t("EmptyView:EmptyRootRoomUserDescription"), + ) + .with([FolderType.USER, P._], () => t("Test")) + .with([FolderType.Recent, P._], () => t("Test")) + .with([FolderType.Archive, P._], () => t("Test")) + .with([FolderType.TRASH, P._], () => t("Test")) .otherwise(() => ""); }; @@ -234,18 +245,22 @@ export const getRoomTitle = ( export const getRootTitle = ( t: TTranslation, + access: AccessType, rootFolderType: Nullable, ) => { - return match([rootFolderType]) - .with([FolderType.Rooms], () => + return match([rootFolderType, access]) + .with([FolderType.Rooms, ShareAccessRights.None], () => t("Files:EmptyRootRoomHeader", { productName: t("Common:ProductName"), }), ) - .with([FolderType.USER], () => t("Test")) - .with([FolderType.Recent], () => t("Test")) - .with([FolderType.Archive], () => t("Test")) - .with([FolderType.TRASH], () => t("Test")) + .with([FolderType.Rooms, ShareAccessRights.DenyAccess], () => + t("EmptyView:EmptyRootRoomUserTitle"), + ) + .with([FolderType.USER, P._], () => t("Test")) + .with([FolderType.Recent, P._], () => t("Test")) + .with([FolderType.Archive, P._], () => t("Test")) + .with([FolderType.TRASH, P._], () => t("Test")) .otherwise(() => ""); }; @@ -363,9 +378,16 @@ export const getRootIcom = ( isBaseTheme: boolean, ) => { return match([rootFolderType, access]) - .with([FolderType.Rooms, P._], () => + .with([FolderType.Rooms, ShareAccessRights.None], () => isBaseTheme ? : , ) + .with([FolderType.Rooms, ShareAccessRights.DenyAccess], () => + isBaseTheme ? ( + + ) : ( + + ), + ) .with([FolderType.USER, P._], () =>
) .with([FolderType.Recent, P._], () =>
) .with([FolderType.Archive, P._], () =>
) diff --git a/packages/client/src/store/ContextOptionsStore.js b/packages/client/src/store/ContextOptionsStore.js index 9d0ddf6fd1..506fa444ff 100644 --- a/packages/client/src/store/ContextOptionsStore.js +++ b/packages/client/src/store/ContextOptionsStore.js @@ -2098,12 +2098,14 @@ class ContextOptionsStore { return newOptions; }; - onInvite = (e) => { + /** + * @param {EmployeeType} userType + * @returns {void} + */ + inviteUser = (userType) => { const { setInviteUsersWarningDialogVisible, setInvitePanelOptions } = this.dialogsStore; - const type = e.item["data-type"]; - if (this.currentTariffStatusStore.isGracePeriod) { setInviteUsersWarningDialogVisible(true); return; @@ -2113,10 +2115,15 @@ class ContextOptionsStore { visible: true, roomId: -1, hideSelector: true, - defaultAccess: type, + defaultAccess: userType, }); }; + onInvite = (e) => { + const type = e.item["data-type"]; + this.inviteUser(type); + }; + onInviteAgain = (t) => { resendInvitesAgain() .then(() => diff --git a/public/images/emptyview/create.room.svg b/public/images/emptyview/create.room.svg index b3cce21756..c1af7175d7 100644 --- a/public/images/emptyview/create.room.svg +++ b/public/images/emptyview/create.room.svg @@ -1,4 +1,4 @@ - - + + diff --git a/public/images/emptyview/empty.migration.svg b/public/images/emptyview/empty.migration.svg new file mode 100644 index 0000000000..f9ab05f0ea --- /dev/null +++ b/public/images/emptyview/empty.migration.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/emptyview/empty.rooms.root.user.dark.svg b/public/images/emptyview/empty.rooms.root.user.dark.svg new file mode 100644 index 0000000000..6e73101b5d --- /dev/null +++ b/public/images/emptyview/empty.rooms.root.user.dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/public/images/emptyview/empty.rooms.root.user.light.svg b/public/images/emptyview/empty.rooms.root.user.light.svg new file mode 100644 index 0000000000..50e314c93d --- /dev/null +++ b/public/images/emptyview/empty.rooms.root.user.light.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +