aktuazalizacja profilow,prefernecji,bezpiecznestwa

This commit is contained in:
2026-08-13 16:18:46 +02:00
parent fbb7ab2d90
commit 571ec05d76
22 changed files with 1339 additions and 151 deletions
+45
View File
@@ -0,0 +1,45 @@
/**
* 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>
);
}