137 lines
3.8 KiB
TypeScript
137 lines
3.8 KiB
TypeScript
import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react';
|
|
import { MatrixClient } from 'matrix-js-sdk';
|
|
import { AccountDataEvent } from '../../types/matrix/accountData';
|
|
import { useMatrixClient } from './useMatrixClient';
|
|
import { getAccountData, isSpace } from '../utils/room';
|
|
import { Membership } from '../../types/matrix/room';
|
|
import { useAccountDataCallback } from './useAccountDataCallback';
|
|
|
|
export type ISidebarFolder = {
|
|
name?: string;
|
|
id: string;
|
|
content: string[];
|
|
};
|
|
export type TSidebarItem = string | ISidebarFolder;
|
|
export type SidebarItems = Array<TSidebarItem>;
|
|
|
|
export type InVojoSpacesContent = {
|
|
shortcut?: string[];
|
|
sidebar?: SidebarItems;
|
|
};
|
|
|
|
export const parseSidebar = (
|
|
mx: MatrixClient,
|
|
orphanSpaces: string[],
|
|
content?: InVojoSpacesContent
|
|
) => {
|
|
const sidebar = content?.sidebar ?? content?.shortcut ?? [];
|
|
const orphans = new Set(orphanSpaces);
|
|
|
|
const items: SidebarItems = [];
|
|
|
|
const safeToAdd = (spaceId: string): boolean => {
|
|
if (typeof spaceId !== 'string') return false;
|
|
const space = mx.getRoom(spaceId);
|
|
if (space?.getMyMembership() !== Membership.Join) return false;
|
|
return isSpace(space);
|
|
};
|
|
|
|
sidebar.forEach((item) => {
|
|
if (typeof item === 'string') {
|
|
if (safeToAdd(item) && !items.includes(item)) {
|
|
orphans.delete(item);
|
|
items.push(item);
|
|
}
|
|
return;
|
|
}
|
|
if (
|
|
typeof item === 'object' &&
|
|
typeof item.id === 'string' &&
|
|
Array.isArray(item.content) &&
|
|
!items.find((i) => (typeof i === 'string' ? false : i.id === item.id))
|
|
) {
|
|
const safeContent = item.content.filter(safeToAdd);
|
|
safeContent.forEach((i) => orphans.delete(i));
|
|
items.push({
|
|
...item,
|
|
content: Array.from(new Set(safeContent)),
|
|
});
|
|
}
|
|
});
|
|
|
|
orphans.forEach((spaceId) => items.push(spaceId));
|
|
return items;
|
|
};
|
|
|
|
const LEGACY_CINNY_SPACES = 'in.cinny.spaces';
|
|
|
|
const getSpacesContent = (mx: MatrixClient): InVojoSpacesContent | undefined =>
|
|
getAccountData(mx, AccountDataEvent.VojoSpaces)?.getContent<InVojoSpacesContent>() ??
|
|
getAccountData(mx, LEGACY_CINNY_SPACES as AccountDataEvent)?.getContent<InVojoSpacesContent>();
|
|
|
|
export const useSidebarItems = (
|
|
orphanSpaces: string[]
|
|
): [SidebarItems, Dispatch<SetStateAction<SidebarItems>>] => {
|
|
const mx = useMatrixClient();
|
|
|
|
const [sidebarItems, setSidebarItems] = useState(() =>
|
|
parseSidebar(mx, orphanSpaces, getSpacesContent(mx))
|
|
);
|
|
|
|
useEffect(() => {
|
|
setSidebarItems(parseSidebar(mx, orphanSpaces, getSpacesContent(mx)));
|
|
}, [mx, orphanSpaces]);
|
|
|
|
useAccountDataCallback(
|
|
mx,
|
|
useCallback(
|
|
(mEvent) => {
|
|
if (
|
|
mEvent.getType() === AccountDataEvent.VojoSpaces ||
|
|
mEvent.getType() === LEGACY_CINNY_SPACES
|
|
) {
|
|
setSidebarItems(parseSidebar(mx, orphanSpaces, mEvent.getContent<InVojoSpacesContent>()));
|
|
}
|
|
},
|
|
[mx, orphanSpaces]
|
|
)
|
|
);
|
|
|
|
return [sidebarItems, setSidebarItems];
|
|
};
|
|
|
|
export const sidebarItemWithout = (items: SidebarItems, roomId: string) => {
|
|
const newItems: SidebarItems = items
|
|
.map((item) => {
|
|
if (typeof item === 'string') {
|
|
if (item === roomId) return null;
|
|
return item;
|
|
}
|
|
if (item.content.includes(roomId)) {
|
|
const newContent = item.content.filter((id) => id !== roomId);
|
|
if (newContent.length === 0) return null;
|
|
return {
|
|
...item,
|
|
content: newContent,
|
|
};
|
|
}
|
|
return item;
|
|
})
|
|
.filter((item) => item !== null) as SidebarItems;
|
|
|
|
return newItems;
|
|
};
|
|
|
|
export const makeVojoSpacesContent = (
|
|
mx: MatrixClient,
|
|
items: SidebarItems
|
|
): InVojoSpacesContent => {
|
|
const currentInSpaces = getSpacesContent(mx) ?? {};
|
|
|
|
const newSpacesContent: InVojoSpacesContent = {
|
|
...currentInSpaces,
|
|
sidebar: items,
|
|
};
|
|
|
|
return newSpacesContent;
|
|
};
|