profile picture

This commit is contained in:
hamid zarghami
2026-07-20 10:11:43 +03:30
parent bd65d28ea3
commit 94639858f2
11 changed files with 53 additions and 16 deletions
@@ -0,0 +1,16 @@
import { type FC } from "react";
import AvatarImage from "../../../assets/images/avatar_image.png";
type Props = {
src?: string | null;
alt?: string;
className?: string;
};
const UserAvatar: FC<Props> = ({ src, alt = "", className = "size-6" }) => (
<div className={`${className} rounded-full overflow-hidden shrink-0 bg-[#D0D0D0]`}>
<img src={src || AvatarImage} alt={alt} className="size-full object-cover" />
</div>
);
export default UserAvatar;
@@ -2,7 +2,7 @@ import { Add } from "iconsax-react";
import { type FC } from "react"; import { type FC } from "react";
import type DateObject from "react-date-object"; import type DateObject from "react-date-object";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import AvatarImage from "../../../../assets/images/avatar_image.png"; import UserAvatar from "../UserAvatar";
import { formatDateRange } from "./date/utils"; import { formatDateRange } from "./date/utils";
import type { TaskLabel } from "./labels/types"; import type { TaskLabel } from "./labels/types";
import type { TaskUser } from "./users/types"; import type { TaskUser } from "./users/types";
@@ -52,16 +52,7 @@ const TaskDetailMetadataPreview: FC<Props> = ({ selectedLabels, selectedUsers, s
<div className="text-xs font-medium mb-2">{t("taskmanager.users")}</div> <div className="text-xs font-medium mb-2">{t("taskmanager.users")}</div>
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
{selectedUsers.map((user) => ( {selectedUsers.map((user) => (
<div <UserAvatar key={user.id} src={user.avatar} alt={user.name} className="size-8" />
key={user.id}
className="size-8 rounded-full bg-[#D0D0D0] overflow-hidden shrink-0"
>
<img
src={user.avatar ?? AvatarImage}
alt={user.name}
className="size-full object-cover"
/>
</div>
))} ))}
<button <button
type="button" type="button"
@@ -91,19 +91,28 @@ const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, task
page.data?.users?.map((user: UserItemType) => ({ page.data?.users?.map((user: UserItemType) => ({
id: user.id, id: user.id,
name: `${user.firstName} ${user.lastName}`.trim(), name: `${user.firstName} ${user.lastName}`.trim(),
avatar: user.profilePic,
})) ?? [], })) ?? [],
) ?? []; ) ?? [];
const taskUsers: TaskUser[] = const taskUsers: TaskUser[] =
taskDetail?.users?.map((user) => ({ taskDetail?.users?.map((user) => ({
id: user.id, id: user.id,
name: `${user.firstName} ${user.lastName}`.trim(), name: `${user.firstName} ${user.lastName}`.trim(),
avatar: user.profilePic,
})) ?? []; })) ?? [];
const userMap = new Map<string, TaskUser>(apiUsers.map((user) => [user.id, user])); const userMap = new Map<string, TaskUser>(apiUsers.map((user) => [user.id, user]));
taskUsers.forEach((user) => { taskUsers.forEach((user) => {
if (!userMap.has(user.id)) { const existing = userMap.get(user.id);
userMap.set(user.id, user);
if (existing) {
if (!existing.avatar && user.avatar) {
userMap.set(user.id, { ...existing, avatar: user.avatar });
}
return;
} }
userMap.set(user.id, user);
}); });
return Array.from(userMap.values()); return Array.from(userMap.values());
@@ -115,6 +124,7 @@ const TaskDetailToolbar: FC<Props> = ({ activeTab, onTabChange, taskDetail, task
page.data?.users?.map((user: UserItemType) => ({ page.data?.users?.map((user: UserItemType) => ({
id: user.id, id: user.id,
name: `${user.firstName} ${user.lastName}`.trim(), name: `${user.firstName} ${user.lastName}`.trim(),
avatar: user.profilePic,
})) ?? [], })) ?? [],
) ?? [] ) ?? []
); );
@@ -1,6 +1,7 @@
import { type FC } from "react"; import { type FC } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Input from "../../../../../components/Input"; import Input from "../../../../../components/Input";
import UserAvatar from "../../UserAvatar";
import TaskDetailLabelCheckbox from "../labels/TaskDetailLabelCheckbox"; import TaskDetailLabelCheckbox from "../labels/TaskDetailLabelCheckbox";
import type { TaskUser } from "./types"; import type { TaskUser } from "./types";
@@ -71,7 +72,7 @@ const TaskDetailUsersList: FC<Props> = ({
onToggle={() => onToggle(user.id)} onToggle={() => onToggle(user.id)}
ariaLabel={user.name} ariaLabel={user.name}
/> />
<div className="size-6 rounded-full bg-gray-400 shrink-0"></div> <UserAvatar src={user.avatar} alt={user.name} />
<div className="text-[10px]">{user.name}</div> <div className="text-[10px]">{user.name}</div>
</div> </div>
); );
+1
View File
@@ -135,6 +135,7 @@ const UpdateProject: FC = () => {
project.users.map((user) => ({ project.users.map((user) => ({
id: user.id, id: user.id,
name: `${user.firstName} ${user.lastName}`, name: `${user.firstName} ${user.lastName}`,
profilePic: user.profilePic,
})), })),
); );
} else if (project.userIds?.length) { } else if (project.userIds?.length) {
@@ -8,10 +8,12 @@ import { UserItemType } from "../../../users/types/UserTypes";
import { useGetWorkspaces } from "../../workspace/hooks/useWorkspaceData"; import { useGetWorkspaces } from "../../workspace/hooks/useWorkspaceData";
import { WorkspaceItemType } from "../../workspace/types/WorkspaceTypes"; import { WorkspaceItemType } from "../../workspace/types/WorkspaceTypes";
import WorkspaceColorPicker from "../../workspace/components/WorkspaceColorPicker"; import WorkspaceColorPicker from "../../workspace/components/WorkspaceColorPicker";
import UserAvatar from "../../components/UserAvatar";
export type SelectedUser = { export type SelectedUser = {
id: string; id: string;
name: string; name: string;
profilePic?: string;
}; };
export const BACKGROUND_PRESETS = [ export const BACKGROUND_PRESETS = [
@@ -95,7 +97,11 @@ const CreateProjectSidebar: FC<Props> = ({
if (user) { if (user) {
onSelectedUsersChange([ onSelectedUsersChange([
...selectedUsers, ...selectedUsers,
{ id: user.id, name: `${user.firstName} ${user.lastName}` }, {
id: user.id,
name: `${user.firstName} ${user.lastName}`,
profilePic: user.profilePic,
},
]); ]);
} }
@@ -142,6 +148,7 @@ const CreateProjectSidebar: FC<Props> = ({
) : ( ) : (
selectedUsers.map((user) => ( selectedUsers.map((user) => (
<div key={user.id} className="bg-[#EBEEF5] flex gap-2 text-xs items-center px-2 py-2 rounded-lg"> <div key={user.id} className="bg-[#EBEEF5] flex gap-2 text-xs items-center px-2 py-2 rounded-lg">
<UserAvatar src={user.profilePic} alt={user.name} />
<div>{user.name}</div> <div>{user.name}</div>
<CloseCircle variant="Bold" className="size-4 cursor-pointer" color="red" onClick={() => handleRemoveUser(user.id)} /> <CloseCircle variant="Bold" className="size-4 cursor-pointer" color="red" onClick={() => handleRemoveUser(user.id)} />
</div> </div>
@@ -12,6 +12,7 @@ export type ProjectUserType = {
id: string; id: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
profilePic?: string;
}; };
export type CreateProjectType = { export type CreateProjectType = {
@@ -59,6 +59,7 @@ export type TaskUserType = {
id: string; id: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
profilePic?: string;
}; };
export type TaskChecklistItemType = { export type TaskChecklistItemType = {
@@ -89,6 +89,7 @@ const UpdateWorkspace: FC = () => {
workspace.users.map((user) => ({ workspace.users.map((user) => ({
id: user.id, id: user.id,
name: `${user.firstName} ${user.lastName}`, name: `${user.firstName} ${user.lastName}`,
profilePic: user.profilePic,
})), })),
); );
} else if (workspace.userIds?.length) { } else if (workspace.userIds?.length) {
@@ -6,10 +6,12 @@ import Select from "../../../../components/Select";
import { useGetUsers } from "../../../users/hooks/useUserData"; import { useGetUsers } from "../../../users/hooks/useUserData";
import { UserItemType } from "../../../users/types/UserTypes"; import { UserItemType } from "../../../users/types/UserTypes";
import WorkspaceColorPicker from "./WorkspaceColorPicker"; import WorkspaceColorPicker from "./WorkspaceColorPicker";
import UserAvatar from "../../components/UserAvatar";
export type SelectedUser = { export type SelectedUser = {
id: string; id: string;
name: string; name: string;
profilePic?: string;
}; };
type Props = { type Props = {
@@ -55,7 +57,11 @@ const CreateWorkspaceSidebar: FC<Props> = ({
if (user) { if (user) {
onSelectedUsersChange([ onSelectedUsersChange([
...selectedUsers, ...selectedUsers,
{ id: user.id, name: `${user.firstName} ${user.lastName}` }, {
id: user.id,
name: `${user.firstName} ${user.lastName}`,
profilePic: user.profilePic,
},
]); ]);
} }
@@ -107,6 +113,7 @@ const CreateWorkspaceSidebar: FC<Props> = ({
key={user.id} key={user.id}
className="bg-[#EBEEF5] flex gap-2 text-xs items-center px-2 py-2 rounded-lg" className="bg-[#EBEEF5] flex gap-2 text-xs items-center px-2 py-2 rounded-lg"
> >
<UserAvatar src={user.profilePic} alt={user.name} />
<div>{user.name}</div> <div>{user.name}</div>
<CloseCircle <CloseCircle
variant="Bold" variant="Bold"
@@ -18,6 +18,7 @@ export type WorkspaceUserType = {
id: string; id: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
profilePic?: string;
}; };
export type WorkspaceDetailType = WorkspaceItemType & { export type WorkspaceDetailType = WorkspaceItemType & {