Files
ThreadNet-Web/src/components/views/elements/MiniAvatarUploader.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

118 lines
3.9 KiB
TypeScript
Raw Normal View History

/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
2024-09-09 14:57:16 +01:00
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import classNames from "classnames";
import { EventType } from "matrix-js-sdk/src/matrix";
import React, { useContext, useRef, useState, MouseEvent, ReactNode } from "react";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomContext from "../../../contexts/RoomContext";
import { useTimeout } from "../../../hooks/useTimeout";
import { TranslatedString } from "../../../languageHandler";
import { chromeFileInputFix } from "../../../utils/BrowserWorkarounds";
import AccessibleButton from "./AccessibleButton";
2021-04-26 14:10:09 -04:00
import Spinner from "./Spinner";
export const AVATAR_SIZE = "52px";
interface IProps {
hasAvatar: boolean;
noAvatarLabel?: TranslatedString;
hasAvatarLabel?: TranslatedString;
2021-07-12 09:10:27 +01:00
setAvatarUrl(url: string): Promise<unknown>;
isUserAvatar?: boolean;
onClick?(ev: MouseEvent<HTMLInputElement>): void;
children?: ReactNode;
}
const MiniAvatarUploader: React.FC<IProps> = ({
hasAvatar,
hasAvatarLabel,
noAvatarLabel,
setAvatarUrl,
isUserAvatar,
children,
onClick,
}) => {
const cli = useContext(MatrixClientContext);
const [busy, setBusy] = useState(false);
const [hover, setHover] = useState(false);
const [show, setShow] = useState(false);
useTimeout(() => {
setShow(true);
2020-11-10 10:00:55 +00:00
}, 3000); // show after 3 seconds
useTimeout(() => {
setShow(false);
2020-11-10 10:00:55 +00:00
}, 13000); // hide after being shown for 10 seconds
const uploadRef = useRef<HTMLInputElement>(null);
2020-11-10 10:00:55 +00:00
const label = hasAvatar || busy ? hasAvatarLabel : noAvatarLabel;
2021-06-29 13:11:58 +01:00
const { room } = useContext(RoomContext);
const canSetAvatar =
isUserAvatar || room?.currentState?.maySendStateEvent(EventType.RoomAvatar, cli.getSafeUserId());
2020-12-27 21:25:48 +00:00
if (!canSetAvatar) return <React.Fragment>{children}</React.Fragment>;
2020-12-27 21:13:01 +00:00
const visible = !!label && (hover || show);
return (
<React.Fragment>
<input
type="file"
ref={uploadRef}
className="mx_MiniAvatarUploader_input"
onClick={(ev) => {
chromeFileInputFix(ev);
onClick?.(ev);
}}
onChange={async (ev): Promise<void> => {
if (!ev.target.files?.length) return;
setBusy(true);
const file = ev.target.files[0];
2022-10-12 18:59:07 +01:00
const { content_uri: uri } = await cli.uploadContent(file);
await setAvatarUrl(uri);
setBusy(false);
}}
accept="image/*"
/>
<AccessibleButton
className={classNames("mx_MiniAvatarUploader", {
mx_MiniAvatarUploader_busy: busy,
mx_MiniAvatarUploader_hasAvatar: hasAvatar,
})}
disabled={busy}
onClick={() => {
uploadRef.current?.click();
}}
onMouseOver={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{children}
2021-04-26 14:10:09 -04:00
<div className="mx_MiniAvatarUploader_indicator">
2021-07-23 10:23:45 +01:00
{busy ? <Spinner w={20} h={20} /> : <div className="mx_MiniAvatarUploader_cameraIcon" />}
2021-04-26 14:10:09 -04:00
</div>
2020-12-27 21:13:01 +00:00
<div
className={classNames("mx_Tooltip", {
mx_Tooltip_visible: visible,
mx_Tooltip_invisible: !visible,
})}
>
<div className="mx_Tooltip_chevron" />
{label}
</div>
</AccessibleButton>
</React.Fragment>
);
};
export default MiniAvatarUploader;