Apply strictNullChecks to src/components/views/location/* (#10249

* strict fixes

* accessiblebutton without onClick explicit

* strict fix for UserMenu BaseAvatar
This commit is contained in:
Kerry 2023-02-28 21:55:59 +13:00 committed by GitHub
parent 6de8d85f7e
commit dd6fc124d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 46 additions and 31 deletions

View file

@ -432,7 +432,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
public render(): React.ReactNode {
const avatarSize = 32; // should match border-radius of the avatar
const userId = MatrixClientPeg.get().getUserId();
const userId = MatrixClientPeg.get().getSafeUserId();
const displayName = OwnProfileStore.instance.displayName || userId;
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);

View file

@ -32,7 +32,7 @@ import { toPx } from "../../../utils/units";
import { _t } from "../../../languageHandler";
interface IProps {
name: string; // The name (first initial used as default)
name?: string; // The name (first initial used as default)
idName?: string; // ID for generating hash colours
title?: string; // onHover title text
url?: string; // highest priority of them all, shortcut to set in urls[0]

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ReactElement, SyntheticEvent, useContext } from "react";
import React, { ReactNode, SyntheticEvent, useContext } from "react";
import classNames from "classnames";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { IEventRelation } from "matrix-js-sdk/src/models/event";
@ -41,9 +41,9 @@ export const LocationButton: React.FC<IProps> = ({ roomId, sender, menuPosition,
overflowMenuCloser?.();
};
let contextMenu: ReactElement;
let contextMenu: ReactNode = null;
if (menuDisplayed) {
const position = menuPosition ?? aboveLeftOf(button.current.getBoundingClientRect());
const position = menuPosition ?? (button.current && aboveLeftOf(button.current.getBoundingClientRect())) ?? {};
contextMenu = (
<LocationShareMenu

View file

@ -52,9 +52,9 @@ const isSharingOwnLocation = (shareType: LocationShareType): boolean =>
class LocationPicker extends React.Component<ILocationPickerProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private map?: maplibregl.Map = null;
private geolocate?: maplibregl.GeolocateControl = null;
private marker?: maplibregl.Marker = null;
private map?: maplibregl.Map;
private geolocate?: maplibregl.GeolocateControl;
private marker?: maplibregl.Marker;
public constructor(props: ILocationPickerProps) {
super(props);
@ -100,7 +100,7 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
});
this.map.on("load", () => {
this.geolocate.trigger();
this.geolocate?.trigger();
});
this.geolocate.on("error", this.onGeolocateError);
@ -120,7 +120,7 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
} catch (e) {
logger.error("Failed to render map", e);
const errorType =
e?.message === LocationShareError.MapStyleUrlNotConfigured
(e as Error)?.message === LocationShareError.MapStyleUrlNotConfigured
? LocationShareError.MapStyleUrlNotConfigured
: LocationShareError.Default;
this.setState({ error: errorType });
@ -141,7 +141,7 @@ class LocationPicker extends React.Component<ILocationPickerProps, IState> {
offset: [0, -1],
})
.setLngLat(new maplibregl.LngLat(0, 0))
.addTo(this.map);
.addTo(this.map!);
};
private updateStyleUrl = (clientWellKnown: IClientWellKnown): void => {

View file

@ -64,14 +64,15 @@ const LocationShareMenu: React.FC<Props> = ({ menuPosition, onFinished, sender,
);
const displayName = OwnProfileStore.instance.displayName;
const userId = matrixClient.getSafeUserId();
const onLocationSubmit =
shareType === LocationShareType.Live
? shareLiveLocation(matrixClient, roomId, displayName, openMenu)
: shareLocation(matrixClient, roomId, shareType, relation, openMenu);
? shareLiveLocation(matrixClient, roomId, displayName || userId, openMenu)
: shareLocation(matrixClient, roomId, shareType ?? LocationShareType.Own, relation, openMenu);
const onLiveShareEnableSubmit = (): void => {
SettingsStore.setValue("feature_location_share_live", undefined, SettingLevel.DEVICE, true);
SettingsStore.setValue("feature_location_share_live", null, SettingLevel.DEVICE, true);
};
const shouldAdvertiseLiveLabsFlag = shareType === LocationShareType.Live && !isLiveShareEnabled;

View file

@ -31,7 +31,7 @@ interface IProps extends IDialogProps {
}
interface IState {
error: Error;
error?: Error;
}
/**
@ -58,7 +58,7 @@ export default class LocationViewDialog extends React.Component<IProps, IState>
const { mxEvent } = this.props;
// only pass member to marker when should render avatar marker
const markerRoomMember = isSelfLocation(mxEvent.getContent()) ? mxEvent.sender : undefined;
const markerRoomMember = (isSelfLocation(mxEvent.getContent()) && mxEvent.sender) || undefined;
const geoUri = locationEventGeoUri(mxEvent);
return (
<BaseDialog className="mx_LocationViewDialog" onFinished={this.props.onFinished} fixedWidth={false}>

View file

@ -70,6 +70,9 @@ const useMapWithStyle = ({
if (map && centerGeoUri) {
try {
const coords = parseGeoUri(centerGeoUri);
if (!coords) {
throw new Error("Invalid geo URI");
}
map.setCenter({ lon: coords.longitude, lat: coords.latitude });
} catch (_error) {
logger.error("Could not set map center");

View file

@ -20,7 +20,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { _t } from "../../../languageHandler";
import { OwnProfileStore } from "../../../stores/OwnProfileStore";
import BaseAvatar from "../avatars/BaseAvatar";
import AccessibleButton from "../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import Heading from "../typography/Heading";
import { Icon as LocationIcon } from "../../../../res/img/element-icons/location.svg";
import { LocationShareType } from "./shareLocation";
@ -28,11 +28,11 @@ import StyledLiveBeaconIcon from "../beacon/StyledLiveBeaconIcon";
const UserAvatar: React.FC = () => {
const matrixClient = useContext(MatrixClientContext);
const userId = matrixClient.getUserId();
const displayName = OwnProfileStore.instance.displayName;
const userId = matrixClient.getSafeUserId();
const displayName = OwnProfileStore.instance.displayName ?? undefined;
// 40 - 2px border
const avatarSize = 36;
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize) ?? undefined;
return (
<div className={`mx_ShareType_option-icon ${LocationShareType.Own}`}>
@ -49,9 +49,13 @@ const UserAvatar: React.FC = () => {
);
};
type ShareTypeOptionProps = HTMLAttributes<Element> & { label: string; shareType: LocationShareType };
type ShareTypeOptionProps = HTMLAttributes<Element> & {
label: string;
shareType: LocationShareType;
onClick?: ((e: ButtonEvent) => void | Promise<void>) | null;
};
const ShareTypeOption: React.FC<ShareTypeOptionProps> = ({ onClick, label, shareType, ...rest }) => (
<AccessibleButton element="button" className="mx_ShareType_option" onClick={onClick} {...rest}>
<AccessibleButton element="button" className="mx_ShareType_option" onClick={onClick ?? null} {...rest}>
{shareType === LocationShareType.Own && <UserAvatar />}
{shareType === LocationShareType.Pin && (
<LocationIcon className={`mx_ShareType_option-icon ${LocationShareType.Pin}`} />

View file

@ -33,9 +33,11 @@ const useMapMarker = (
return;
}
const coords = parseGeoUri(geoUri);
if (coords) {
const newMarker = createMarker(coords, element);
newMarker.addTo(map);
setMarker(newMarker);
}
},
[marker, geoUri, map],
);
@ -43,8 +45,10 @@ const useMapMarker = (
useEffect(() => {
if (marker) {
const coords = parseGeoUri(geoUri);
if (coords) {
marker.setLngLat({ lon: coords.longitude, lat: coords.latitude });
}
}
}, [marker, geoUri]);
useEffect(

View file

@ -15,6 +15,7 @@ limitations under the License.
*/
import { MatrixClient } from "matrix-js-sdk/src/client";
import { IContent } from "matrix-js-sdk/src/matrix";
import { MatrixError } from "matrix-js-sdk/src/http-api";
import { makeLocationContent, makeBeaconInfoContent } from "matrix-js-sdk/src/content-helpers";
import { logger } from "matrix-js-sdk/src/logger";
@ -94,7 +95,7 @@ const getDefaultErrorParams = (
return { modalParams, errorMessage };
};
const handleShareError = (error: Error, openMenu: () => void, shareType: LocationShareType): void => {
const handleShareError = (error: unknown, openMenu: () => void, shareType: LocationShareType): void => {
const { modalParams, errorMessage } =
(error as MatrixError).errcode === "M_FORBIDDEN"
? getPermissionsErrorParams(shareType)
@ -135,9 +136,9 @@ export const shareLocation =
async ({ uri, timestamp }): Promise<void> => {
if (!uri) return;
try {
const threadId = relation?.rel_type === THREAD_RELATION_TYPE.name ? relation.event_id : null;
const threadId = (relation?.rel_type === THREAD_RELATION_TYPE.name && relation?.event_id) || null;
const assetType = shareType === LocationShareType.Pin ? LocationAssetType.Pin : LocationAssetType.Self;
const content = makeLocationContent(undefined, uri, timestamp, undefined, assetType);
const content = makeLocationContent(undefined, uri, timestamp, undefined, assetType) as IContent;
await doMaybeLocalRoomAction(
roomId,
(actualRoomId: string) => client.sendMessage(actualRoomId, threadId, content),

View file

@ -33,6 +33,7 @@ import { LocationShareType } from "../../../../src/components/views/location/sha
import {
flushPromisesWithFakeTimers,
getMockClientWithEventEmitter,
mockClientMethodsUser,
setupAsyncStoreWithClient,
} from "../../../test-utils";
import Modal from "../../../../src/Modal";
@ -74,7 +75,7 @@ jest.mock("../../../../src/Modal", () => ({
describe("<LocationShareMenu />", () => {
const userId = "@ernie:server.org";
const mockClient = getMockClientWithEventEmitter({
getUserId: jest.fn().mockReturnValue(userId),
...mockClientMethodsUser(userId),
getClientWellKnown: jest.fn().mockResolvedValue({
map_style_url: "maps.com",
}),
@ -334,7 +335,7 @@ describe("<LocationShareMenu />", () => {
expect(SettingsStore.setValue).toHaveBeenCalledWith(
"feature_location_share_live",
undefined,
null,
SettingLevel.DEVICE,
true,
);

View file

@ -48,6 +48,7 @@ jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({
describe("<SpacePanel />", () => {
const mockClient = {
getUserId: jest.fn().mockReturnValue("@test:test"),
getSafeUserId: jest.fn().mockReturnValue("@test:test"),
isGuest: jest.fn(),
getAccountData: jest.fn(),
} as unknown as MatrixClient;