import React, { FormEventHandler, useCallback, useState } from 'react';
import {
Badge,
Box,
Button,
Checkbox,
Chip,
color,
config,
Icon,
Icons,
Input,
Spinner,
Text,
toRem,
} from 'folds';
import { MatrixError } from 'matrix-js-sdk';
import { SettingTile } from '../../../components/setting-tile';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../../room-settings/styles.css';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useRoom } from '../../../hooks/useRoom';
import {
useLocalAliases,
usePublishedAliases,
usePublishUnpublishAliases,
useSetMainAlias,
} from '../../../hooks/useRoomAliases';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { CutoutCard } from '../../../components/cutout-card';
import { replaceSpaceWithDash } from '../../../utils/common';
import { useAlive } from '../../../hooks/useAlive';
import { StateEvent } from '../../../../types/matrix/room';
import { RoomPermissionsAPI } from '../../../hooks/useRoomPermissions';
import { getMxIdServer } from '../../../utils/matrix';
type RoomPublishedAddressesProps = {
permissions: RoomPermissionsAPI;
};
export function RoomPublishedAddresses({ permissions }: RoomPublishedAddressesProps) {
const mx = useMatrixClient();
const room = useRoom();
const canEditCanonical = permissions.stateEvent(
StateEvent.RoomCanonicalAlias,
mx.getSafeUserId()
);
const [canonicalAlias, publishedAliases] = usePublishedAliases(room);
const setMainAlias = useSetMainAlias(room);
const [mainState, setMain] = useAsyncCallback(setMainAlias);
const loading = mainState.status === AsyncStatus.Loading;
return (
If access is Public, Published addresses will be used to join by anyone.
}
/>
{publishedAliases.length === 0 ? (
No Addresses
To publish an address, it needs to be set as a local address first
) : (
{publishedAliases.map((alias) => (
{alias === canonicalAlias ? {alias} : alias}
{alias === canonicalAlias && (
Main
)}
{canEditCanonical && (
{alias === canonicalAlias ? (
setMain(undefined)}
>
Unset Main
) : (
setMain(alias)}
>
Set Main
)}
)}
))}
{mainState.status === AsyncStatus.Error && (
{(mainState.error as MatrixError).message}
)}
)}
);
}
function LocalAddressInput({ addLocalAlias }: { addLocalAlias: (alias: string) => Promise }) {
const mx = useMatrixClient();
const userId = mx.getSafeUserId();
const server = getMxIdServer(userId);
const alive = useAlive();
const [addState, addAlias] = useAsyncCallback(addLocalAlias);
const adding = addState.status === AsyncStatus.Loading;
const handleSubmit: FormEventHandler = (evt) => {
if (adding) return;
evt.preventDefault();
const target = evt.target as HTMLFormElement | undefined;
const aliasInput = target?.aliasInput as HTMLInputElement | undefined;
if (!aliasInput) return;
const alias = replaceSpaceWithDash(aliasInput.value.trim());
if (!alias) return;
addAlias(`#${alias}:${server}`).then(() => {
if (alive()) {
aliasInput.value = '';
}
});
};
return (
#}
readOnly={adding}
after={
:{server}
}
/>
}
>
Save
{addState.status === AsyncStatus.Error && (
{(addState.error as MatrixError).httpStatus === 409
? 'Address is already in use!'
: (addState.error as MatrixError).message}
)}
);
}
function LocalAddressesList({
localAliases,
removeLocalAlias,
canEditCanonical,
}: {
localAliases: string[];
removeLocalAlias: (alias: string) => Promise;
canEditCanonical?: boolean;
}) {
const room = useRoom();
const alive = useAlive();
const [, publishedAliases] = usePublishedAliases(room);
const { publishAliases, unpublishAliases } = usePublishUnpublishAliases(room);
const [selectedAliases, setSelectedAliases] = useState([]);
const selectHasPublished = selectedAliases.find((alias) => publishedAliases.includes(alias));
const toggleSelect = (alias: string) => {
setSelectedAliases((aliases) => {
if (aliases.includes(alias)) {
return aliases.filter((a) => a !== alias);
}
const newAliases = [...aliases];
newAliases.push(alias);
return newAliases;
});
};
const clearSelected = () => {
if (alive()) {
setSelectedAliases([]);
}
};
const [deleteState, deleteAliases] = useAsyncCallback(
useCallback(
async (aliases: string[]) => {
for (let i = 0; i < aliases.length; i += 1) {
const alias = aliases[i];
// eslint-disable-next-line no-await-in-loop
await removeLocalAlias(alias);
}
},
[removeLocalAlias]
)
);
const [publishState, publish] = useAsyncCallback(publishAliases);
const [unpublishState, unpublish] = useAsyncCallback(unpublishAliases);
const handleDelete = () => {
deleteAliases(selectedAliases).then(clearSelected);
};
const handlePublish = () => {
publish(selectedAliases).then(clearSelected);
};
const handleUnpublish = () => {
unpublish(selectedAliases).then(clearSelected);
};
const loading =
deleteState.status === AsyncStatus.Loading ||
publishState.status === AsyncStatus.Loading ||
unpublishState.status === AsyncStatus.Loading;
let error: MatrixError | undefined;
if (deleteState.status === AsyncStatus.Error) error = deleteState.error as MatrixError;
if (publishState.status === AsyncStatus.Error) error = publishState.error as MatrixError;
if (unpublishState.status === AsyncStatus.Error) error = unpublishState.error as MatrixError;
return (
{selectedAliases.length > 0 && (
{selectedAliases.length} Selected
{canEditCanonical &&
(selectHasPublished ? (
)
}
>
Unpublish
) : (
)
}
>
Publish
))}
)
}
>
Delete
)}
{localAliases.map((alias) => {
const published = publishedAliases.includes(alias);
const selected = selectedAliases.includes(alias);
return (
toggleSelect(alias)}
size="50"
variant="Primary"
disabled={loading}
/>
{alias}
{published && (
Published
)}
);
})}
{error && (
{error.message}
)}
);
}
export function RoomLocalAddresses({ permissions }: { permissions: RoomPermissionsAPI }) {
const mx = useMatrixClient();
const room = useRoom();
const canEditCanonical = permissions.stateEvent(
StateEvent.RoomCanonicalAlias,
mx.getSafeUserId()
);
const [expand, setExpand] = useState(false);
const { localAliasesState, addLocalAlias, removeLocalAlias } = useLocalAliases(room.roomId);
return (
setExpand(!expand)}
size="300"
variant="Secondary"
fill="Soft"
outlined
radii="300"
before={
}
>
{expand ? 'Collapse' : 'Expand'}
}
/>
{expand && (
{localAliasesState.status === AsyncStatus.Loading && (
Loading...
)}
{localAliasesState.status === AsyncStatus.Success &&
(localAliasesState.data.length === 0 ? (
No Addresses
) : (
))}
{localAliasesState.status === AsyncStatus.Error && (
{localAliasesState.error.message}
)}
)}
{expand && }
);
}