You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx

125 lines
3.0 KiB
TypeScript

import React from 'react';
import { getInitials } from '../../util/getInitials';
interface Props {
diameter: number;
name: string;
pubkey?: string;
colors: Array<string>;
borderColor: string;
}
interface State {
sha512Seed?: string;
}
export class AvatarPlaceHolder extends React.PureComponent<Props, State> {
public constructor(props: Props) {
super(props);
this.state = {
sha512Seed: undefined,
};
}
public componentDidMount() {
const { pubkey } = this.props;
if (pubkey) {
void this.sha512(pubkey).then((sha512Seed: string) => {
this.setState({ sha512Seed });
});
}
}
public componentDidUpdate(prevProps: Props, prevState: State) {
const { pubkey, name } = this.props;
if (pubkey === prevProps.pubkey && name === prevProps.name) {
return;
}
if (pubkey) {
void this.sha512(pubkey).then((sha512Seed: string) => {
this.setState({ sha512Seed });
});
}
}
public render() {
const { borderColor, colors, diameter, name } = this.props;
const diameterWithoutBorder = diameter - 2;
const viewBox = `0 0 ${diameter} ${diameter}`;
const r = diameter / 2;
const rWithoutBorder = diameterWithoutBorder / 2;
if (!this.state.sha512Seed) {
// return grey circle
return (
<svg viewBox={viewBox}>
<g id="UrTavla">
<circle
cx={r}
cy={r}
r={rWithoutBorder}
fill="#d2d2d3"
shapeRendering="geometricPrecision"
stroke={borderColor}
strokeWidth="1"
/>
</g>
</svg>
);
}
const initial = getInitials(name)?.toLocaleUpperCase() || '0';
const fontSize = diameter * 0.5;
// Generate the seed simulate the .hashCode as Java
const hash = parseInt(this.state.sha512Seed.substring(0, 12), 16) || 0;
const bgColorIndex = hash % colors.length;
const bgColor = colors[bgColorIndex];
return (
<svg viewBox={viewBox}>
<g id="UrTavla">
<circle
cx={r}
cy={r}
r={rWithoutBorder}
fill={bgColor}
shapeRendering="geometricPrecision"
stroke={borderColor}
strokeWidth="1"
/>
<text
fontSize={fontSize}
x="50%"
y="50%"
fill="white"
textAnchor="middle"
stroke="white"
strokeWidth={1}
alignmentBaseline="central"
>
{initial}
</text>
</g>
</svg>
);
}
private async sha512(str: string) {
// tslint:disable-next-line: await-promise
const buf = await crypto.subtle.digest(
'SHA-512',
new TextEncoder().encode(str)
);
// tslint:disable: prefer-template restrict-plus-operands
return Array.prototype.map
.call(new Uint8Array(buf), (x: any) => ('00' + x.toString(16)).slice(-2))
.join('');
}
}