diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx
index b24b4c81e..2152a1cf4 100644
--- a/apps/web/app/[locale]/profile/[memberId]/page.tsx
+++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx
@@ -23,6 +23,7 @@ import { AppsTab } from 'lib/features/activity/apps';
import { VisitedSitesTab } from 'lib/features/activity/visited-sites';
import { activityTypeState } from '@app/stores/activity-type';
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@components/ui/resizable';
+import { TableActionPopover } from 'lib/settings/table-action-popover';
// import { ActivityCalendar } from 'lib/features/activity/calendar';
export type FilterTab = 'Tasks' | 'Screenshots' | 'Apps' | 'Visited Sites';
@@ -197,17 +198,19 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId
function UserProfileDetail({ member }: { member?: OT_Member }) {
const user = useMemo(() => member?.employee.user, [member?.employee.user]);
+
const userName = `${user?.firstName || ''} ${user?.lastName || ''}`;
const imgUrl = user?.image?.thumbUrl || user?.image?.fullUrl || user?.imageUrl;
const imageUrl = useMemo(() => imgUrl, [imgUrl]);
const size = 100;
const { timerStatus } = useTimer();
+ // const isManager = activeTeamManagers.find((member) => member.employee.user?.id === member?.employee.user?.id);
const timerStatusValue: ITimerStatusEnum = useMemo(() => {
return getTimerStatusValue(timerStatus, member, false);
}, [timerStatus, member]);
-
return (
+
+
{imageUrl && isValidUrl(imageUrl) ? (
+
+
) : (
<>
+
{imgTitle(userName).charAt(0)}
+
)}
-
-
-
- {user?.firstName} {user?.lastName}
-
+
+
+
+ {user?.firstName} {user?.lastName}
+
+
+
{user?.email}
diff --git a/apps/web/app/api/employee/[id]/route.ts b/apps/web/app/api/employee/[id]/route.ts
new file mode 100644
index 000000000..6bead1db0
--- /dev/null
+++ b/apps/web/app/api/employee/[id]/route.ts
@@ -0,0 +1,24 @@
+import { IUpdateEmployee } from "@app/interfaces";
+import { authenticatedGuard } from "@app/services/server/guards/authenticated-guard-app";
+import { updateEmployees } from "@app/services/server/requests";
+import { NextResponse } from "next/server";
+
+export async function PUT(req: Request, { params }: { params: { id: string } }) {
+ const res = new NextResponse();
+ const { id } = params;
+ if (!id) {
+ return
+ }
+ const { $res, user, access_token } = await authenticatedGuard(req, res);
+ if (!user) return $res('Unauthorized');
+ const body = (await req.json()) as unknown as IUpdateEmployee;
+
+ const response = await updateEmployees(
+ {
+ bearer_token: access_token,
+ body,
+ id
+ }
+ );
+ return $res(response.data)
+}
diff --git a/apps/web/app/api/employee/working/route.ts b/apps/web/app/api/employee/working/route.ts
deleted file mode 100644
index 061206e17..000000000
--- a/apps/web/app/api/employee/working/route.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app';
-import { getOrganizationEmployees } from '@app/services/server/requests';
-import { NextResponse } from 'next/server';
-
-export async function GET(req: Request) {
- const res = new NextResponse();
- const { $res, user, access_token, tenantId, organizationId } = await authenticatedGuard(req, res);
-
- if (!user) {
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
- }
-
- const { data } = await getOrganizationEmployees(access_token, tenantId, organizationId);
-
- return $res(data);
-}
diff --git a/apps/web/app/hooks/features/useEmployee.ts b/apps/web/app/hooks/features/useEmployee.ts
index cf0cae1aa..916877137 100644
--- a/apps/web/app/hooks/features/useEmployee.ts
+++ b/apps/web/app/hooks/features/useEmployee.ts
@@ -1,10 +1,11 @@
-import { getWorkingEmployeesAPI } from '@app/services/client/api';
+import { getWorkingEmployeesAPI, updateEmployeeAPI } from '@app/services/client/api';
import { workingEmployeesEmailState, workingEmployeesState } from '@app/stores/employee';
import { useCallback, useEffect } from 'react';
import { useRecoilState } from 'recoil';
import { useQuery } from '../useQuery';
import { useAuthenticateUser } from './useAuthenticateUser';
+import { IUpdateEmployee } from '@app/interfaces';
export const useEmployee = () => {
const { user } = useAuthenticateUser();
@@ -39,3 +40,19 @@ export const useEmployee = () => {
workingEmployeesEmail
};
};
+
+
+export const useEmployeeUpdate = () => {
+ const { queryCall: employeeUpdateQuery, loading: isLoading } = useQuery(updateEmployeeAPI);
+
+ const updateEmployee = useCallback(({ id, data
+ }: { id: string, data: IUpdateEmployee }) => {
+ employeeUpdateQuery({ id, data })
+ .then((res) => res.data)
+ .catch((error) => {
+ console.log(error);
+ });
+ }, []);
+
+ return { updateEmployee, isLoading }
+}
diff --git a/apps/web/app/interfaces/IEmployee.ts b/apps/web/app/interfaces/IEmployee.ts
index 3844c9ff9..bed02d1c0 100644
--- a/apps/web/app/interfaces/IEmployee.ts
+++ b/apps/web/app/interfaces/IEmployee.ts
@@ -57,6 +57,7 @@ export interface IEmployee {
}
export type ICreateEmployee = Pick
;
+export type IUpdateEmployee = Pick
export interface IRole {
id?: string;
diff --git a/apps/web/app/services/client/api/employee.ts b/apps/web/app/services/client/api/employee.ts
index ca9f0529b..0d5f28362 100644
--- a/apps/web/app/services/client/api/employee.ts
+++ b/apps/web/app/services/client/api/employee.ts
@@ -1,6 +1,6 @@
import { GAUZY_API_BASE_SERVER_URL } from '@app/constants';
-import { IWorkingEmployee, PaginationResponse } from '@app/interfaces';
-import { get } from '../axios';
+import { IUpdateEmployee, IWorkingEmployee, PaginationResponse } from '@app/interfaces';
+import { get, put } from '../axios';
import qs from 'qs';
export async function getWorkingEmployeesAPI(tenantId: string, organizationId: string) {
@@ -15,3 +15,8 @@ export async function getWorkingEmployeesAPI(tenantId: string, organizationId: s
return get>(endpoint, { tenantId });
}
+
+
+export function updateEmployeeAPI({ id, data }: { id: string, data: IUpdateEmployee }) {
+ return put(`/employee/${id}`, data);
+}
diff --git a/apps/web/app/services/server/requests/employee.ts b/apps/web/app/services/server/requests/employee.ts
index 30e65f9f9..a9cbbf33c 100644
--- a/apps/web/app/services/server/requests/employee.ts
+++ b/apps/web/app/services/server/requests/employee.ts
@@ -1,5 +1,5 @@
import { PaginationResponse } from '@app/interfaces';
-import { ICreateEmployee, IEmployee, IWorkingEmployee } from '@app/interfaces/IEmployee';
+import { ICreateEmployee, IEmployee, IUpdateEmployee, IWorkingEmployee } from '@app/interfaces/IEmployee';
import { serverFetch } from '../fetch';
import qs from 'qs';
@@ -29,3 +29,13 @@ export function getOrganizationEmployees(bearer_token: string, tenantId: string,
tenantId
});
}
+
+export function updateEmployees({ bearer_token, id, body }: { bearer_token: string, id: string, body: IUpdateEmployee }) {
+ return serverFetch({
+ path: `/employee/${id}`,
+ method: 'PUT',
+ bearer_token,
+ body
+
+ })
+}
diff --git a/apps/web/app/stores/employee.ts b/apps/web/app/stores/employee.ts
index 8c9ee1f08..ecd867c97 100644
--- a/apps/web/app/stores/employee.ts
+++ b/apps/web/app/stores/employee.ts
@@ -1,4 +1,4 @@
-import { IWorkingEmployee } from '@app/interfaces';
+import { IUpdateEmployee, IWorkingEmployee } from '@app/interfaces';
import { atom } from 'recoil';
export const workingEmployeesState = atom({
@@ -10,3 +10,9 @@ export const workingEmployeesEmailState = atom({
key: 'workingEmployeesEmailState',
default: []
});
+
+
+export const employeeUpdateState = atom({
+ key: 'employeeUpdateState',
+ default: null!,
+})
diff --git a/apps/web/lib/components/avatar.tsx b/apps/web/lib/components/avatar.tsx
index 9f7c2fb0e..5992aac9d 100644
--- a/apps/web/lib/components/avatar.tsx
+++ b/apps/web/lib/components/avatar.tsx
@@ -61,8 +61,8 @@ export function Avatar({
height: size,
...(backgroundColor
? {
- backgroundColor
- }
+ backgroundColor
+ }
: {})
}}
>
diff --git a/apps/web/lib/settings/member-table.tsx b/apps/web/lib/settings/member-table.tsx
index 039cfd147..16ca75b60 100644
--- a/apps/web/lib/settings/member-table.tsx
+++ b/apps/web/lib/settings/member-table.tsx
@@ -28,7 +28,6 @@ export const MemberTable = ({ members }: { members: OT_Member[] }) => {
const handleEdit = (member: OT_Member) => {
setEditMember(member);
};
-
const handelNameChange = useCallback(
(event: ChangeEvent) => {
const name = event.target.value || '';
@@ -210,7 +209,7 @@ export const MemberTable = ({ members }: { members: OT_Member[] }) => {
-
+
|
))}
diff --git a/apps/web/lib/settings/table-action-popover.tsx b/apps/web/lib/settings/table-action-popover.tsx
index 12fcd3118..3cdab0e82 100644
--- a/apps/web/lib/settings/table-action-popover.tsx
+++ b/apps/web/lib/settings/table-action-popover.tsx
@@ -1,34 +1,41 @@
-import { useAuthenticateUser, useModal, useTMCardTaskEdit, useTeamMemberCard } from '@app/hooks';
+import { useAuthenticateUser, useModal, useOrganizationTeams, useTMCardTaskEdit, useTeamMemberCard } from '@app/hooks';
import { useRoles } from '@app/hooks/features/useRoles';
-import { OT_Member } from '@app/interfaces';
+import { OT_Member, RoleNameEnum } from '@app/interfaces';
import { Popover, Transition } from '@headlessui/react';
import { useDropdownAction } from 'lib/features/team/user-team-card/user-team-card-menu';
import { Fragment, useEffect } from 'react';
import { useTranslations } from 'next-intl';
import { ConfirmationModal } from './confirmation-modal';
import { ThreeCircleOutlineHorizontalIcon } from 'assets/svg';
+import { useEmployeeUpdate } from '@app/hooks/features/useEmployee';
type Props = {
member: OT_Member;
- handleEdit: (member: OT_Member) => void;
+ handleEdit?: (member: OT_Member) => void;
+ status?: 'settings' | 'profile'
};
-
-export const TableActionPopover = ({ member, handleEdit }: Props) => {
+/**
+ *
+ *
+ */
+export const TableActionPopover = ({ member, handleEdit, status }: Props) => {
// const [isOpen, setIsOpen] = useState(false);
-
const t = useTranslations();
const { user } = useAuthenticateUser();
+ const { activeTeamManagers } = useOrganizationTeams();
+
const memberInfo = useTeamMemberCard(member);
const taskEdition = useTMCardTaskEdit(memberInfo.memberTask);
const { onRemoveMember } = useDropdownAction({
edition: taskEdition,
memberInfo
});
+ const { isLoading, updateEmployee } = useEmployeeUpdate();
const { isOpen, openModal, closeModal } = useModal();
const isCurrentUser = user?.employee.id === memberInfo.member?.employeeId;
-
+ const isManager = activeTeamManagers.findIndex((member) => member.employee.user?.id === user?.id);
// const handleClick = () => {
// setIsOpen(!isOpen);
// };
@@ -45,19 +52,19 @@ export const TableActionPopover = ({ member, handleEdit }: Props) => {
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
-
+
{/* TODO Dynamic */}
{/* Edit */}
- {
- handleEdit(member);
+ handleEdit && handleEdit(member);
}}
>
{t('common.EDIT')}
-
+ }
{/* TODO Dynamic */}
{/* Change Role */}
@@ -67,6 +74,41 @@ export const TableActionPopover = ({ member, handleEdit }: Props) => {
*/}
+
Time tracking
+
{
+ updateEmployee({
+ data: {
+ isTrackingEnabled: !member.employee.isTrackingEnabled,
+ id: member.employee.id,
+ organizationId: member.employee.organizationId,
+ isActive: member.employee.isActive,
+ tenantId: member.employee.tenantId
+ },
+ id: member.employee.id
+ });
+ }}
+ style={
+ member.employee.isTrackingEnabled
+ ? { background: 'linear-gradient(to right, #ea31244d, #ea312479)' }
+ : { background: '#2ead805b' }
+ }
+ >
+
+
+ {!isLoading && renderTrackingIcon(member.employee.isTrackingEnabled)}
+
+ {isLoading ?
+
: null
+ }
+
+
+ }
{/* TODO Dynamic */}
{/* Need to integrate with API */}
@@ -80,21 +122,22 @@ export const TableActionPopover = ({ member, handleEdit }: Props) => {
*/}
{/* Delete */}
-