46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
/**
|
|
* Zdjecie profilowe uzytkownika - jedno miejsce dla calej aplikacji.
|
|
*
|
|
* Uzytkownik ustawia zdjecie raz w /konto/ustawienia, a backend dokleja je do profilu
|
|
* (/api/auth/me, profil publiczny, karta sprzedajacego przy ogloszeniu). Gdy zdjecia nie ma,
|
|
* rysujemy inicjaly na zielonym tle - ten sam wyglad co awatar w prawym gornym rogu naglowka.
|
|
*
|
|
* Rozmiar i pozycje nadaje klasa z miejsca uzycia (np. .account-trigger-avatar), a wspolna
|
|
* klasa .avatar odpowiada za ksztalt, kolor tla i wpasowanie zdjecia w kolo.
|
|
*/
|
|
|
|
type AvatarProps = {
|
|
/** Nazwa uzytkownika - zrodlo inicjalow i tekstu alternatywnego zdjecia. */
|
|
name: string;
|
|
/** Zdjecie jako data URL. Puste albo null oznacza, ze uzytkownik zadnego nie ustawil. */
|
|
image?: string | null;
|
|
/** Klasa miejsca uzycia, ktora nadaje rozmiar. */
|
|
className?: string;
|
|
/** Sama pierwsza litera imienia zamiast dwoch inicjalow - tak wyglada karta sprzedajacego. */
|
|
singleLetter?: boolean;
|
|
};
|
|
|
|
/** Inicjaly z nazwy: "Jan Kowalski" -> "JK", "joanna" -> "JO", pusta nazwa -> "??". */
|
|
export function initialsFrom(name: string): string {
|
|
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
if (parts.length === 0) {
|
|
return '??';
|
|
}
|
|
if (parts.length === 1) {
|
|
return parts[0].slice(0, 2).toUpperCase();
|
|
}
|
|
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
}
|
|
|
|
export function Avatar({ name, image, className, singleLetter }: AvatarProps) {
|
|
const trimmed = image?.trim();
|
|
const letters = singleLetter ? (name.trim()[0] ?? '?').toUpperCase() : initialsFrom(name);
|
|
return (
|
|
<span className={className ? `avatar ${className}` : 'avatar'}>
|
|
{trimmed
|
|
? <img src={trimmed} alt={`Zdjęcie profilowe: ${name}`} />
|
|
: letters}
|
|
</span>
|
|
);
|
|
}
|