diff --git a/packages/client/src/pages/Sdk/index.js b/packages/client/src/pages/Sdk/index.js
index e81b42c7ad..07fb3a124b 100644
--- a/packages/client/src/pages/Sdk/index.js
+++ b/packages/client/src/pages/Sdk/index.js
@@ -4,7 +4,7 @@ import { useParams } from "react-router-dom";
import { Button } from "@docspace/shared/components/button";
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
import AppLoader from "@docspace/common/components/AppLoader";
-import RoomSelector from "../../components/RoomSelector";
+import RoomSelector from "@docspace/shared/selectors/Room";
import FilesSelector from "../../components/FilesSelector";
import {
frameCallEvent,
diff --git a/packages/common/components/Loaders/SelectorSearchLoader/index.js b/packages/common/components/Loaders/SelectorSearchLoader/index.js
deleted file mode 100644
index 0f7a745504..0000000000
--- a/packages/common/components/Loaders/SelectorSearchLoader/index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from "react";
-import { RectangleSkeleton } from "@docspace/shared/skeletons";
-
-const SelectorSearchLoader = ({
- id,
- className,
- style,
-
- ...rest
-}) => {
- return (
-
- );
-};
-
-export default SelectorSearchLoader;
diff --git a/packages/common/components/Loaders/index.js b/packages/common/components/Loaders/index.js
index ead69ed05c..dcff41b516 100644
--- a/packages/common/components/Loaders/index.js
+++ b/packages/common/components/Loaders/index.js
@@ -1,4 +1,3 @@
-
import Header from "./HeaderLoader";
import SectionHeader from "./SectionHeaderLoader";
import ArticleHeader from "./ArticleHeaderLoader";
@@ -38,8 +37,6 @@ import PaymentsLoader from "./PaymentsLoader";
import SelectorBreadCrumbsLoader from "./SelectorBreadCrumbsLoader";
import PaymentsStandaloneLoader from "./PaymentsStandaloneLoader";
-import SelectorSearchLoader from "./SelectorSearchLoader";
-import SelectorRowLoader from "./SelectorRowLoader";
import InfoPanelViewLoader from "./InfoPanelBodyLoader/InfoPanelViewLoader";
import InfoPanelHeaderLoader from "./InfoPanelHeaderLoader";
@@ -52,7 +49,6 @@ import SettingsDSConnect from "./SettingsLoader/SettingsDSConnectLoader";
import EmptyContainerLoader from "./EmptyContainerLoader/EmptyContainerLoader";
export default {
-
Header,
SectionHeader,
ArticleHeader,
@@ -91,8 +87,6 @@ export default {
SelectorBreadCrumbsLoader,
PaymentsStandaloneLoader,
- SelectorSearchLoader,
- SelectorRowLoader,
InfoPanelHeaderLoader,
InfoPanelViewLoader,
diff --git a/packages/shared/api/files/types.ts b/packages/shared/api/files/types.ts
index 31dc78ab97..54efdf0b3c 100644
--- a/packages/shared/api/files/types.ts
+++ b/packages/shared/api/files/types.ts
@@ -1,4 +1,4 @@
-import { TUser } from "types";
+import { TCreatedBy, TPathParts, TUser } from "../../types";
import {
EmployeeActivationStatus,
EmployeeStatus,
@@ -9,14 +9,6 @@ import {
ShareAccessRights,
} from "../../enums";
-export type TCreatedBy = {
- avatarSmall: string;
- displayName: string;
- hasAvatar: boolean;
- id: string;
- profileUrl: string;
-};
-
export type TFileViewAccessibility = {
CanConvert: boolean;
CoAuhtoring: boolean;
@@ -148,12 +140,6 @@ export type TFolder = {
export type TGetFolderPath = TFolder[];
-export type TPathParts = {
- id: number;
- title: string;
- roomType?: RoomsType;
-};
-
export type TGetFolder = {
files: TFile[];
folders: TFolder[];
diff --git a/packages/shared/api/rooms/index.js b/packages/shared/api/rooms/index.ts
similarity index 93%
rename from packages/shared/api/rooms/index.js
rename to packages/shared/api/rooms/index.ts
index cd5c3bab7b..e0ac66b382 100644
--- a/packages/shared/api/rooms/index.js
+++ b/packages/shared/api/rooms/index.ts
@@ -1,3 +1,5 @@
+import { AxiosRequestConfig } from "axios";
+
import { FolderType } from "../../enums";
import { request } from "../client";
import {
@@ -6,8 +8,9 @@ import {
toUrlParams,
} from "../../utils/common";
import RoomsFilter from "./filter";
+import { TGetRooms } from "./types";
-export function getRooms(filter, signal) {
+export async function getRooms(filter: RoomsFilter, signal?: AbortSignal) {
let params;
if (filter) {
@@ -16,24 +19,24 @@ export function getRooms(filter, signal) {
params = `?${filter.toApiUrlParams()}`;
}
- const options = {
+ const options: AxiosRequestConfig = {
method: "get",
url: `/files/rooms${params}`,
signal,
};
- return request(options).then((res) => {
- res.files = decodeDisplayName(res.files);
- res.folders = decodeDisplayName(res.folders);
+ const res = (await request(options)) as TGetRooms;
- if (res.current.rootFolderType === FolderType.Archive) {
- res.folders.forEach((room) => {
- room.isArchive = true;
- });
- }
+ res.files = decodeDisplayName(res.files);
+ res.folders = decodeDisplayName(res.folders);
- return res;
- });
+ if (res.current.rootFolderType === FolderType.Archive) {
+ res.folders.forEach((room) => {
+ room.isArchive = true;
+ });
+ }
+
+ return res;
}
export function getRoomInfo(id) {
diff --git a/packages/shared/api/rooms/types.ts b/packages/shared/api/rooms/types.ts
new file mode 100644
index 0000000000..9b6c19304a
--- /dev/null
+++ b/packages/shared/api/rooms/types.ts
@@ -0,0 +1,66 @@
+import { TFile, TFolder } from "../files/types";
+import { FolderType, RoomsType, ShareAccessRights } from "../../enums";
+import { TCreatedBy, TPathParts } from "../../types";
+
+export type TLogo = {
+ original: string;
+ large: string;
+ medium: string;
+ small: string;
+ color?: string;
+};
+
+export type TRoomSecurity = {
+ Read: boolean;
+ Create: boolean;
+ Delete: boolean;
+ EditRoom: boolean;
+ Rename: boolean;
+ CopyTo: boolean;
+ Copy: boolean;
+ MoveTo: boolean;
+ Move: boolean;
+ Pin: boolean;
+ Mute: boolean;
+ EditAccess: boolean;
+ Duplicate: boolean;
+ Download: boolean;
+ CopySharedLink: boolean;
+};
+
+export type TRoom = {
+ parentId: number;
+ filesCount: number;
+ foldersCount: number;
+ new: number;
+ mute: boolean;
+ tags: string[];
+ logo: TLogo;
+ pinned: boolean;
+ roomType: RoomsType;
+ private: boolean;
+ inRoom: boolean;
+ id: number;
+ rootFolderId: number;
+ canShare: boolean;
+ title: string;
+ access: ShareAccessRights;
+ shared: boolean;
+ created: Date;
+ createdBy: TCreatedBy;
+ updated: Date;
+ rootFolderType: FolderType;
+ updatedBy: TCreatedBy;
+ isArchive?: boolean;
+};
+
+export type TGetRooms = {
+ files: TFile[];
+ folders: TRoom[];
+ current: TFolder;
+ pathParts: TPathParts[];
+ startIndex: number;
+ count: number;
+ total: number;
+ new: number;
+};
diff --git a/packages/shared/selectors/Room/RoomSelector.types.ts b/packages/shared/selectors/Room/RoomSelector.types.ts
new file mode 100644
index 0000000000..c8e2cee7bd
--- /dev/null
+++ b/packages/shared/selectors/Room/RoomSelector.types.ts
@@ -0,0 +1,16 @@
+import { SelectorProps } from "../../components/selector";
+import { TLogo } from "../../api/rooms/types";
+import { RoomsType } from "../../enums";
+
+export interface RoomSelectorProps extends SelectorProps {
+ excludeItems: number[];
+}
+
+export type TItem = {
+ id: number;
+ label: string;
+ icon: string;
+ color: string | undefined;
+ logo: TLogo;
+ roomType: RoomsType;
+};
diff --git a/packages/shared/selectors/Room/RoomSelector.utils.ts b/packages/shared/selectors/Room/RoomSelector.utils.ts
new file mode 100644
index 0000000000..4498ce181a
--- /dev/null
+++ b/packages/shared/selectors/Room/RoomSelector.utils.ts
@@ -0,0 +1,14 @@
+import { TRoom } from "../../api/rooms/types";
+
+export const convertToItems = (folders: TRoom[]) => {
+ const items = folders.map((folder) => {
+ const { id, title, roomType, logo } = folder;
+
+ const icon = logo.medium;
+ const color = logo.color;
+
+ return { id, label: title, icon, color, logo, roomType };
+ });
+
+ return items;
+};
diff --git a/packages/client/src/components/RoomSelector/index.js b/packages/shared/selectors/Room/index.tsx
similarity index 56%
rename from packages/client/src/components/RoomSelector/index.js
rename to packages/shared/selectors/Room/index.tsx
index ac4679bd04..d78131ca1d 100644
--- a/packages/client/src/components/RoomSelector/index.js
+++ b/packages/shared/selectors/Room/index.tsx
@@ -1,61 +1,26 @@
-import EmptyScreenCorporateSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate.svg?url";
-import React from "react";
-import { withTranslation } from "react-i18next";
+import React from "react";
+import { useTranslation } from "react-i18next";
-import api from "@docspace/shared/api";
-import RoomsFilter from "@docspace/shared/api/rooms/filter";
-import { RoomsType } from "@docspace/shared/enums";
-import { iconSize32 } from "@docspace/shared/utils/image-helpers";
+import EmptyScreenCorporateSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate.svg?url";
-import Loaders from "@docspace/common/components/Loaders";
+import { Selector } from "../../components/selector";
+import { RowLoader, SearchLoader } from "../../skeletons/selector";
+import api from "../../api";
+import RoomsFilter from "../../api/rooms/filter";
-import { Selector } from "@docspace/shared/components/selector";
+import { TTranslation } from "../../types";
-const pageCount = 100;
+import { RoomSelectorProps, TItem } from "./RoomSelector.types";
+import { convertToItems } from "./RoomSelector.utils";
-const getRoomLogo = (roomType) => {
- let path = "";
- switch (roomType) {
- case RoomsType.CustomRoom:
- path = "custom.svg";
- break;
- case RoomsType.FillingFormsRoom:
- path = "filling.form.svg";
- break;
- case RoomsType.EditingRoom:
- path = "editing.svg";
- break;
- case RoomsType.ReadOnlyRoom:
- path = "view.only.svg";
- break;
- case RoomsType.ReviewRoom:
- path = "review.svg";
- break;
- }
-
- return iconSize32.get(path);
-};
-
-const convertToItems = (folders) => {
- const items = folders.map((folder) => {
- const { id, title, roomType, logo } = folder;
-
- const icon = logo.medium ? logo.medium : getRoomLogo(roomType);
- const color = logo.color;
-
- return { id, label: title, icon, color, logo, roomType };
- });
-
- return items;
-};
+const PAGE_COUNT = 100;
const RoomSelector = ({
- t,
id,
className,
style,
- excludeItems,
+ excludeItems = [],
headerLabel,
onBackClick,
@@ -91,7 +56,9 @@ const RoomSelector = ({
searchEmptyScreenImage,
searchEmptyScreenHeader,
searchEmptyScreenDescription,
-}) => {
+}: RoomSelectorProps) => {
+ const { t }: { t: TTranslation } = useTranslation(["RoomSelector", "Common"]);
+
const [isFirstLoad, setIsFirstLoad] = React.useState(true);
const [searchValue, setSearchValue] = React.useState("");
const [hasNextPage, setHasNextPage] = React.useState(false);
@@ -99,22 +66,22 @@ const RoomSelector = ({
const [total, setTotal] = React.useState(0);
- const [items, setItems] = React.useState([]);
+ const [items, setItems] = React.useState([]);
const onSearchAction = React.useCallback(
- (value) => {
- onSearch && onSearch(value);
+ (value: string) => {
+ onSearch?.(value);
setSearchValue(() => {
setIsFirstLoad(true);
return value;
});
},
- [onSearch]
+ [onSearch],
);
const onClearSearchAction = React.useCallback(() => {
- onClearSearch && onClearSearch();
+ onClearSearch?.();
setSearchValue(() => {
setIsFirstLoad(true);
@@ -123,50 +90,51 @@ const RoomSelector = ({
}, [onClearSearch]);
const onLoadNextPage = React.useCallback(
- (startIndex) => {
+ async (startIndex: number) => {
setIsNextPageLoading(true);
- const page = startIndex / pageCount;
+ const page = startIndex / PAGE_COUNT;
const filter = RoomsFilter.getDefault();
filter.page = page;
- filter.pageCount = pageCount;
+ filter.pageCount = PAGE_COUNT;
- filter.filterValue = searchValue ? searchValue : null;
+ filter.filterValue = searchValue || null;
- api.rooms
- .getRooms(filter)
- .then(({ folders, total, count }) => {
- const rooms = convertToItems(folders);
+ const {
+ folders,
+ total: totalCount,
+ count,
+ } = await api.rooms.getRooms(filter);
- const itemList = rooms.filter((x) => !excludeItems.includes(x.id));
+ const rooms = convertToItems(folders);
- setHasNextPage(count === pageCount);
+ const itemList = rooms.filter((x) => !excludeItems.includes(x.id));
- if (isFirstLoad) {
- setTotal(total);
- setItems(itemList);
- } else {
- setItems((value) => [...value, ...itemList]);
- }
- })
- .finally(() => {
- if (isFirstLoad) {
- setTimeout(() => {
- setIsFirstLoad(false);
- }, 500);
- }
+ setHasNextPage(count === PAGE_COUNT);
- setIsNextPageLoading(false);
- });
+ if (isFirstLoad) {
+ setTotal(totalCount);
+ setItems(itemList);
+ } else {
+ setItems((value) => [...value, ...itemList]);
+ }
+
+ if (isFirstLoad) {
+ setTimeout(() => {
+ setIsFirstLoad(false);
+ }, 500);
+ }
+
+ setIsNextPageLoading(false);
},
- [isFirstLoad, excludeItems, searchValue]
+ [isFirstLoad, excludeItems, searchValue],
);
React.useEffect(() => {
onLoadNextPage(0);
- }, [searchValue]);
+ }, [onLoadNextPage, searchValue]);
return (
}
+ searchLoader={}
rowLoader={
- `
width: 100%;
height: 48px;
min-height: 48px;
@@ -52,7 +52,18 @@ const Divider = styled.div`
border-bottom: ${(props) => props.theme.selector.border};
`;
-const SelectorRowLoader = ({
+interface RowLoaderProps extends RectangleSkeletonProps {
+ id?: string;
+ className?: string;
+ style?: React.CSSProperties;
+ isMultiSelect?: boolean;
+ isContainer?: boolean;
+ isUser?: boolean;
+ withAllSelect?: boolean;
+ count?: number;
+}
+
+const RowLoader = ({
id,
className,
style,
@@ -62,30 +73,21 @@ const SelectorRowLoader = ({
withAllSelect,
count = 5,
...rest
-}) => {
- const getRowItem = (key) => {
+}: RowLoaderProps) => {
+ const getRowItem = (key: number) => {
return (
-
-
+
+
{isMultiSelect && (
-
+
)}
);
@@ -93,7 +95,7 @@ const SelectorRowLoader = ({
const getRowItems = () => {
const rows = [];
- for (let i = 0; i < count; i++) {
+ for (let i = 0; i < count; i += 1) {
rows.push(getRowItem(i));
}
@@ -111,8 +113,8 @@ const SelectorRowLoader = ({
{getRowItems()}
) : (
- getRowItem()
+ getRowItem(0)
);
};
-export default SelectorRowLoader;
+export default RowLoader;
diff --git a/packages/shared/skeletons/selector/Search.tsx b/packages/shared/skeletons/selector/Search.tsx
new file mode 100644
index 0000000000..f7231ae2cf
--- /dev/null
+++ b/packages/shared/skeletons/selector/Search.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import { RectangleSkeleton, RectangleSkeletonProps } from "../rectangle";
+
+interface SearchLoaderProps extends RectangleSkeletonProps {
+ id?: string;
+ className?: string;
+ style?: React.CSSProperties;
+}
+
+const SearchLoader = ({
+ id,
+ className,
+ style,
+
+ ...rest
+}: SearchLoaderProps) => {
+ return (
+
+ );
+};
+
+export default SearchLoader;
diff --git a/packages/shared/skeletons/selector/index.ts b/packages/shared/skeletons/selector/index.ts
new file mode 100644
index 0000000000..6c69ab3fe5
--- /dev/null
+++ b/packages/shared/skeletons/selector/index.ts
@@ -0,0 +1,4 @@
+import RowLoader from "./Row";
+import SearchLoader from "./Search";
+
+export { SearchLoader, RowLoader };
diff --git a/packages/shared/tsconfig.eslint.json b/packages/shared/tsconfig.eslint.json
index aca7a0a144..276328ff40 100644
--- a/packages/shared/tsconfig.eslint.json
+++ b/packages/shared/tsconfig.eslint.json
@@ -14,6 +14,7 @@
"hooks",
"api",
"sw",
+ "selectors",
// add all files in which you see
// the "parserOptions.project" error
".eslintrc.cjs",
diff --git a/packages/shared/types/index.ts b/packages/shared/types/index.ts
index 7b3aaaa4db..80ad8a7466 100644
--- a/packages/shared/types/index.ts
+++ b/packages/shared/types/index.ts
@@ -1,3 +1,4 @@
+import { RoomsType } from "../enums";
import { TTheme } from "../themes";
export type TDirectionX = "left" | "right";
@@ -9,6 +10,20 @@ export type TTranslation = (key: string) => string;
export type { TUser } from "./user";
+export type TPathParts = {
+ id: number;
+ title: string;
+ roomType?: RoomsType;
+};
+
+export type TCreatedBy = {
+ avatarSmall: string;
+ displayName: string;
+ hasAvatar: boolean;
+ id: string;
+ profileUrl: string;
+};
+
export type TI18n = {
language: string;
changeLanguage: (l: string) => string;
diff --git a/packages/shared/utils/common.ts b/packages/shared/utils/common.ts
index e905b2e28b..535e8d8027 100644
--- a/packages/shared/utils/common.ts
+++ b/packages/shared/utils/common.ts
@@ -28,6 +28,7 @@ import { FolderType, RoomsType, ThemeKeys } from "../enums";
import { LANGUAGE, RTL_LANGUAGES } from "../constants";
import { TUser, TI18n } from "../types";
import { TFolder, TFile, TGetFolder } from "../api/files/types";
+import { TRoom } from "../api/rooms/types";
import TopLoaderService from "../components/top-loading-indicator";
import { Encoder } from "./encoder";
@@ -594,7 +595,9 @@ export const getFolderClassNameByType = (folderType: FolderType) => {
}
};
-export const decodeDisplayName = (items: T[]) => {
+export const decodeDisplayName = (
+ items: T[],
+) => {
return items.map((item) => {
if (!item) return item;