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} } /> {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 && } ); }