Skip to content

Commit

Permalink
Use only text for Avatar (#9951)
Browse files Browse the repository at this point in the history
  • Loading branch information
gigincg authored Jan 14, 2025
1 parent 111ebf5 commit 27fef8d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 143 deletions.
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

130 changes: 59 additions & 71 deletions src/components/Common/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import React from "react";

import { cn } from "@/lib/utils";

const colors: string[] = [
"#E6F3FF", // Light Blue
"#FFF0E6", // Light Peach
"#E6FFE6", // Light Green
"#FFE6E6", // Light Pink
"#F0E6FF", // Light Purple
"#FFFFE6", // Light Yellow
"#E6FFFF", // Light Cyan
"#FFE6F3", // Light Rose
"#F3FFE6", // Light Lime
"#E6E6FF", // Light Lavender
"#FFE6FF", // Light Magenta
"#E6FFF0", // Light Mint
// Subtle, professional color combinations that blend well with the UI
const colorPairs: Array<[string, string]> = [
["#E3F2FD", "#1565C0"], // Subtle Blue
["#E8F5E9", "#2E7D32"], // Subtle Green
["#FFF3E0", "#E65100"], // Subtle Orange
["#F3E5F5", "#6A1B9A"], // Subtle Purple
["#E1F5FE", "#0277BD"], // Subtle Light Blue
["#E0F2F1", "#00695C"], // Subtle Teal
["#FBE9E7", "#D84315"], // Subtle Deep Orange
["#F3E5F5", "#6A1B9A"], // Subtle Purple
["#E8EAF6", "#283593"], // Subtle Indigo
["#FFF8E1", "#FF8F00"], // Subtle Amber
["#FCE4EC", "#C2185B"], // Subtle Pink
["#EFEBE9", "#4E342E"], // Subtle Brown
];

const stringToInt = (name: string): number => {
const aux = (sum: number, remains: string): number => {
if (remains === "") return sum;
const firstCharacter = remains.slice(0, 1);
const newRemains = remains.slice(1);
return aux(sum + firstCharacter.charCodeAt(0), newRemains);
};

return Math.floor(aux(0, name));
const stringToIndex = (name: string): number => {
return name.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
};

const toColor = (name: string): [string, string] => {
const index = stringToInt(name) % colors.length;
const backgroundColor = colors[index];
return [backgroundColor, "#333333"]; // Using dark gray for text
const getColorPair = (name: string): [string, string] => {
const index = stringToIndex(name) % colorPairs.length;
return colorPairs[index];
};

const initials = (name: string): string => {
Expand All @@ -40,73 +34,67 @@ const initials = (name: string): string => {
.slice(0, 2)
.map((word) => word.slice(0, 1))
.join("")
.toUpperCase(); // Ensure initials are uppercase
.toUpperCase();
};

interface AvatarProps {
colors?: [string, string];
name?: string;
name: string;
imageUrl?: string;
className?: string;
icon?: React.ReactNode;
}

const Avatar: React.FC<AvatarProps> = ({
colors: propColors,
name,
imageUrl,
className,
icon,
}) => {
const [bgColor] = propColors || (name ? toColor(name) : toColor(""));
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
AvatarProps
>(({ colors: propColors, name, imageUrl, className }, ref) => {
const avatarText = name.match(/[a-zA-Z]+/g)?.join(" ");

const [bgColor, textColor] =
propColors ||
(avatarText ? getColorPair(avatarText) : getColorPair("user"));

return (
<div
title={name}
className={cn(
`flex aspect-square w-full items-center justify-center overflow-hidden border border-black/10`,
className,
)}
<AvatarPrimitive.Root
ref={ref}
className={cn("w-full h-full", className)}
style={{
background: bgColor,
borderRadius: "calc(100% / 15)",
}}
>
{imageUrl ? (
<img
<AvatarPrimitive.Image
src={imageUrl}
alt={name}
className="aspect-square h-full w-full object-cover"
/>
) : icon ? (
<div className="flex items-center justify-center w-full h-full">
{icon}
</div>
) : (
// Render initials SVG
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
viewBox="0 0 100 100"
className="aspect-square h-full w-full object-cover"
>
<text
fill="black"
fillOpacity="0.1"
fontSize="40"
fontWeight="900"
x="50"
y="54"
textAnchor="middle"
dominantBaseline="middle"
alignmentBaseline="middle"
<AvatarPrimitive.Fallback className="flex h-full w-full select-none items-center justify-center text-center">
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
viewBox="0 0 100 100"
className="aspect-square h-full w-full object-cover"
>
{name ? initials(name) : null}
</text>
</svg>
<text
fill={textColor}
fillOpacity="0.5"
fontSize="50"
fontWeight="900"
x="50"
y="54"
textAnchor="middle"
dominantBaseline="middle"
alignmentBaseline="middle"
>
{avatarText ? initials(avatarText) : null}
</text>
</svg>
</AvatarPrimitive.Fallback>
)}
</div>
</AvatarPrimitive.Root>
);
};
});

export { Avatar };
export type { AvatarProps };
20 changes: 5 additions & 15 deletions src/components/Common/LoginHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";

import CareIcon from "@/CAREUI/icons/CareIcon";

import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
Expand All @@ -13,6 +12,8 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

import { Avatar } from "@/components/Common/Avatar";

import { usePatientSignOut } from "@/hooks/usePatientSignOut";

import { LocalStorageKeys } from "@/common/constants";
Expand All @@ -33,31 +34,20 @@ export const LoginHeader = () => {
dayjs(tokenData.createdAt).isAfter(dayjs().subtract(14, "minutes"));

if (isLoggedIn) {
const phoneNumber = tokenData.phoneNumber?.replace("+91", "") || "";
const initials = phoneNumber.slice(-2);

return (
<header className="w-full">
<div className="flex justify-end items-center gap-2">
<Button
variant="ghost"
className="text-sm font-medium hover:bg-gray-100 rounded-full px-6"
className="text-sm font-medium hover:bg-gray-100 px-6"
onClick={() => navigate("/patient/home")}
>
{t("dashboard")}
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full p-0 hover:bg-gray-100 border-gray-400 border-2"
>
<Avatar className="h-8 w-8">
<AvatarFallback className="bg-primary-50 text-primary-600 text-xs">
{initials}
</AvatarFallback>
</Avatar>
<Button variant="ghost" size="icon">
<Avatar name={"User"} className="w-7 h-7 rounded-full" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
Expand Down
4 changes: 2 additions & 2 deletions src/components/Facility/FacilityHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export const FacilityHome = ({ facilityId }: Props) => {
}
};

if (isLoading) {
if (isLoading || !facilityData) {
return <Loading />;
}

Expand Down Expand Up @@ -210,7 +210,7 @@ export const FacilityHome = ({ facilityId }: Props) => {
<div className="flex-1">
<div className="flex items-center gap-4">
<Avatar
name={facilityData?.name}
name={facilityData.name}
className="h-12 w-12 shrink-0 rounded-xl border-2 border-white/10 shadow-xl"
/>
<div>
Expand Down
48 changes: 0 additions & 48 deletions src/components/ui/avatar.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const buttonVariants = cva(
secondary:
"bg-gray-100 text-gray-900 shadow-sm hover:bg-gray-100/80 dark:bg-gray-800 dark:text-gray-50 dark:hover:bg-gray-800/80",
ghost:
"underline hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-50",
"hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-50",
link: "text-gray-900 underline-offset-4 hover:underline dark:text-gray-50",
outline_primary:
"border border-primary-700 text-primary-700 bg-white shadow-sm hover:bg-primary-700 hover:text-white dark:border-primary-700 dark:bg-primary-700 dark:text-white",
Expand Down
6 changes: 3 additions & 3 deletions src/components/ui/sidebar/patient-switcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function PatientSwitcher({ className }: PatientSwitcherProps) {

const patientUserContext = usePatientContext();

if (!patientUserContext) {
if (!patientUserContext || !patientUserContext.selectedPatient) {
return null;
}

Expand Down Expand Up @@ -67,7 +67,7 @@ export function PatientSwitcher({ className }: PatientSwitcherProps) {
{open && (
<div className="flex flex-row justify-between items-center gap-2 w-full text-primary-800">
<Avatar
name={patientUserContext.selectedPatient?.name}
name={patientUserContext.selectedPatient?.name || "User"}
className="h-4 w-4"
/>
<div className="flex flex-row items-center justify-between w-full gap-2">
Expand All @@ -83,7 +83,7 @@ export function PatientSwitcher({ className }: PatientSwitcherProps) {
{!open && (
<div className="flex flex-row items-center -ml-1.5">
<Avatar
name={patientUserContext.selectedPatient?.name}
name={patientUserContext.selectedPatient?.name || "User"}
className="h-4 w-4"
/>
</div>
Expand Down

0 comments on commit 27fef8d

Please sign in to comment.