Skip to content

Commit

Permalink
Member profile page hide some tab options (#2518)
Browse files Browse the repository at this point in the history
* fix: member profile page hide some tab options

* feat: integrate share profile setting

* feat: plans and worked views by settings

* feat: plans and worked views by settings

* fix: build issues
  • Loading branch information
GloireMutaliko21 authored May 19, 2024
1 parent 87858a9 commit 60a3d0f
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 59 deletions.
3 changes: 3 additions & 0 deletions apps/mobile/app/services/interfaces/IOrganizationTeam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface IOrganizationTeamCreate {
tags?: any[];
organizationId: string;
tenantId: string;
shareProfileView?: boolean;
public?: boolean;
imageId?: string | null;
image?: IImageAssets | null;
Expand All @@ -30,6 +31,7 @@ export interface IOrganizationTeam {
members: any[];
tags: any[];
id: string;
shareProfileView?: boolean;
createdAt: string;
updatedAt: string;
imageId?: string | null;
Expand All @@ -48,6 +50,7 @@ export interface IOrganizationTeamList {
members: OT_Member[];
managerIds?: string[];
memberIds?: string[];
shareProfileView?: boolean;
public?: boolean;
createdById: string;
createdBy: IUser;
Expand Down
18 changes: 18 additions & 0 deletions apps/web/app/hooks/features/useAuthenticateUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { useRecoilState } from 'recoil';

import { useQuery } from '../useQuery';
import { useIsMemberManager } from './useTeamMember';
import { useOrganizationTeams } from './useOrganizationTeams';
import { useUserProfilePage } from './useUserProfilePage';

export const useAuthenticateUser = (defaultUser?: IUser) => {
const [user, setUser] = useRecoilState(userState);
Expand Down Expand Up @@ -68,3 +70,19 @@ export const useAuthenticateUser = (defaultUser?: IUser) => {
refreshToken
};
};

/**
* A hook to check if the current user is a manager or whom the current profile belongs to
*
* @description We need, especially for the user profile page, to know if the current user can see some activities, or interact with data
* @returns a boolean that defines in the user is authorized
*/

export const useCanSeeActivityScreen = () => {
const { user } = useAuthenticateUser();
const { activeTeamManagers } = useOrganizationTeams();
const profile = useUserProfilePage();

const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id);
return profile.userProfile?.id === user?.id || isManagerConnectedUser != -1;
};
3 changes: 3 additions & 0 deletions apps/web/app/interfaces/IOrganizationTeam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface IOrganizationTeamCreate {
tags?: any[];
organizationId: string;
tenantId: string;
shareProfileView?: boolean;
public?: boolean;
imageId?: string | null;
image?: IImageAssets | null;
Expand Down Expand Up @@ -42,6 +43,7 @@ export interface IOrganizationTeam {
id: string;
createdAt: string;
updatedAt: string;
shareProfileView?: boolean;
imageId?: string | null;
image?: IImageAssets | null;
}
Expand All @@ -59,6 +61,7 @@ export interface IOrganizationTeamList {
updated?: boolean;
prefix: string;
members: OT_Member[];
shareProfileView?: boolean;
public?: boolean;
createdById: string;
createdBy: IUser;
Expand Down
56 changes: 55 additions & 1 deletion apps/web/lib/components/switch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useOrganizationTeams } from '@app/hooks';
import { useOrganizationEmployeeTeams } from '@app/hooks/features/useOrganizatioTeamsEmployee';
import { OT_Member } from '@app/interfaces';
import { OT_Member, RoleNameEnum } from '@app/interfaces';
import { Switch } from '@headlessui/react';
import { useCallback, useEffect, useState } from 'react';
import { Text } from './typography';
Expand Down Expand Up @@ -49,3 +49,57 @@ export default function TimeTrackingToggle({ activeManager }: { activeManager: O
</div>
);
}

export function ShareProfileViewsToggle() {
const t = useTranslations();
const { activeTeam, editOrganizationTeam } = useOrganizationTeams();
const [enabled, setEnabled] = useState<boolean | undefined>(activeTeam?.shareProfileView);

const handleChange = useCallback(async () => {
if (activeTeam && typeof enabled != 'undefined') {
await editOrganizationTeam({
...activeTeam,
shareProfileView: !enabled,
memberIds: activeTeam.members
.map((t) => t.employee.id)
.filter((value, index, array) => array.indexOf(value) === index),
managerIds: activeTeam.members
.filter(
(m) =>
m.role &&
(m.role.name === RoleNameEnum.MANAGER ||
m.role.name === RoleNameEnum.SUPER_ADMIN ||
m.role.name === RoleNameEnum.ADMIN)
)
.map((t) => t.employee.id)
.filter((value, index, array) => array.indexOf(value) === index)
});
setEnabled(!enabled);
}
}, [activeTeam, editOrganizationTeam, enabled]);

useEffect(() => {
setEnabled(activeTeam?.shareProfileView);
}, [activeTeam?.shareProfileView]);

return (
<div className="flex items-center gap-x-[10px]">
<Switch
checked={enabled}
onChange={() => {
handleChange();
}}
className={`${enabled ? 'bg-[#DBD3FA]' : 'bg-[#80808061]'}
relative inline-flex h-[38px] w-[74px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75`}
>
<span className="sr-only">{t('common.USE_SETTING')}</span>
<span
aria-hidden="true"
className={`${enabled ? 'translate-x-9 bg-[#3826A6]' : 'bg-white translate-x-1'}
pointer-events-none inline-block h-[30px] w-[30px] mt-[2.5px] transform rounded-full bg-[#3826A6] shadow-lg ring-0 transition duration-200 ease-in-out`}
/>
</Switch>
<Text className="text-gray-400 ">{enabled ? t('common.ACTIVATED') : t('common.DEACTIVATED')}</Text>
</div>
);
}
31 changes: 19 additions & 12 deletions apps/web/lib/features/task/daily-plan/future-tasks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@c
import { EmptyPlans, PlanHeader } from 'lib/features/user-profile-plans';
import { TaskCard } from '../task-card';
import { Button } from '@components/ui/button';
import { useDailyPlan } from '@app/hooks';
import { useCanSeeActivityScreen, useDailyPlan } from '@app/hooks';
import { ReloadIcon } from '@radix-ui/react-icons';

export function FutureTasks({ dayPlans, profile }: { dayPlans: IDailyPlan[]; profile: any }) {
Expand All @@ -16,6 +16,7 @@ export function FutureTasks({ dayPlans, profile }: { dayPlans: IDailyPlan[]; pro
return planDate.getTime() >= today.getTime();
});
const { deleteDailyPlan, deleteDailyPlanLoading } = useDailyPlan();
const canSeeActivity = useCanSeeActivityScreen();

return (
<div className="flex flex-col gap-6">
Expand Down Expand Up @@ -60,17 +61,23 @@ export function FutureTasks({ dayPlans, profile }: { dayPlans: IDailyPlan[]; pro
</ul>

{/* Delete Plan */}
<div className="flex justify-end">
<Button
disabled={deleteDailyPlanLoading}
onClick={() => deleteDailyPlan(plan.id ?? '')}
variant="destructive"
className="p-7 py-6 font-normal rounded-xl text-md"
>
{deleteDailyPlanLoading && <ReloadIcon className="animate-spin mr-2 h-4 w-4" />}
Delete this plan
</Button>
</div>
{canSeeActivity ? (
<div className="flex justify-end">
<Button
disabled={deleteDailyPlanLoading}
onClick={() => deleteDailyPlan(plan.id ?? '')}
variant="destructive"
className="p-7 py-6 font-normal rounded-xl text-md"
>
{deleteDailyPlanLoading && (
<ReloadIcon className="animate-spin mr-2 h-4 w-4" />
)}
Delete this plan
</Button>
</div>
) : (
<></>
)}
</AccordionContent>
</AccordionItem>
))}
Expand Down
37 changes: 26 additions & 11 deletions apps/web/lib/features/task/task-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { secondsToTime } from '@app/helpers';
import {
I_TeamMemberCardHook,
I_UserProfilePage,
useCanSeeActivityScreen,
useDailyPlan,
useModal,
useOrganizationEmployeeTeams,
Expand Down Expand Up @@ -476,6 +477,8 @@ function TaskCardMenu({
}
}, [memberInfo, task, viewType]);

const canSeeActivity = useCanSeeActivityScreen();

return (
<Popover>
<Popover.Button className="flex items-center border-none outline-none">
Expand Down Expand Up @@ -552,21 +555,33 @@ function TaskCardMenu({
)}

{viewType === 'dailyplan' && planMode === 'Outstanding' && (
<AddTaskToPlanComponent employee={profile?.member} task={task} />
<>
{canSeeActivity ? (
<AddTaskToPlanComponent employee={profile?.member} task={task} />
) : (
<></>
)}
</>
)}

{viewType === 'dailyplan' &&
(planMode === 'Today Tasks' || planMode === 'Future Tasks') && (
<div>
<Divider type="HORIZONTAL" />
<div className="mt-2">
<RemoveTaskFromPlan
member={profile?.member}
task={task}
plan={plan}
/>
</div>
</div>
<>
{canSeeActivity ? (
<div>
<Divider type="HORIZONTAL" />
<div className="mt-2">
<RemoveTaskFromPlan
member={profile?.member}
task={task}
plan={plan}
/>
</div>
</div>
) : (
<></>
)}
</>
)}
{/* <li>
<ConfirmDropdown
Expand Down
33 changes: 21 additions & 12 deletions apps/web/lib/features/task/task-filters.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

/* eslint-disable no-mixed-spaces-and-tabs */
import { I_UserProfilePage, useOutsideClick } from '@app/hooks';
import { I_UserProfilePage, useAuthenticateUser, useOrganizationTeams, useOutsideClick } from '@app/hooks';
import { IClassName, ITeamTask } from '@app/interfaces';
import { clsxm } from '@app/utils';
import { Transition } from '@headlessui/react';
Expand Down Expand Up @@ -33,10 +33,15 @@ type StatusFilter = { [x in IStatusType]: string[] };
*/
export function useTaskFilter(profile: I_UserProfilePage) {
const t = useTranslations();

const defaultValue =
typeof window !== 'undefined' ? (window.localStorage.getItem('task-tab') as ITab) || null : 'worked';

const { activeTeamManagers, activeTeam } = useOrganizationTeams();
const { user } = useAuthenticateUser();

const isManagerConnectedUser = activeTeamManagers.findIndex((member) => member.employee?.user?.id == user?.id);
const canSeeActivity = profile.userProfile?.id === user?.id || isManagerConnectedUser != -1;

const [tab, setTab] = useState<ITab>(defaultValue || 'worked');
const [filterType, setFilterType] = useState<FilterType>(undefined);

Expand Down Expand Up @@ -67,12 +72,6 @@ export function useTaskFilter(profile: I_UserProfilePage) {
});

const tabs: ITabs[] = [
{
tab: 'worked',
name: t('common.WORKED'),
description: t('task.tabFilter.WORKED_DESCRIPTION'),
count: profile.tasksGrouped.workedTasks.length
},
{
tab: 'assigned',
name: t('common.ASSIGNED'),
Expand All @@ -84,14 +83,24 @@ export function useTaskFilter(profile: I_UserProfilePage) {
name: t('common.UNASSIGNED'),
description: t('task.tabFilter.UNASSIGNED_DESCRIPTION'),
count: profile.tasksGrouped.unassignedTasks.length
},
{
}
];

// For tabs on profile page, display "Worked" and "Daily Plan" only for the logged in user or managers
if (activeTeam?.shareProfileView || canSeeActivity) {
tabs.push({
tab: 'dailyplan',
name: 'Daily Plan',
description: 'This tab shows all yours tasks planned',
count: profile.tasksGrouped.dailyplan?.length
}
];
});
tabs.unshift({
tab: 'worked',
name: t('common.WORKED'),
description: t('task.tabFilter.WORKED_DESCRIPTION'),
count: profile.tasksGrouped.workedTasks.length
});
}

useEffect(() => {
window.localStorage.setItem('task-tab', tab);
Expand Down
36 changes: 22 additions & 14 deletions apps/web/lib/features/user-profile-plans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState } from 'react';
import { useRecoilValue } from 'recoil';
import { useDailyPlan, useUserProfilePage } from '@app/hooks';
import { useCanSeeActivityScreen, useDailyPlan, useUserProfilePage } from '@app/hooks';
import { TaskCard } from './task/task-card';
import { IDailyPlan } from '@app/interfaces';
import { Container, NoData, ProgressBar, VerticalSeparator } from 'lib/components';
Expand Down Expand Up @@ -87,6 +87,8 @@ function AllPlans({

const { deleteDailyPlan, deleteDailyPlanLoading } = useDailyPlan();

const canSeeActivity = useCanSeeActivityScreen();

return (
<div className="flex flex-col gap-6">
{filteredPlans.length > 0 ? (
Expand Down Expand Up @@ -135,19 +137,25 @@ function AllPlans({

{/* Delete Plan */}
{currentTab === 'Today Tasks' && (
<div className="flex justify-end">
<Button
disabled={deleteDailyPlanLoading}
onClick={() => deleteDailyPlan(plan.id ?? '')}
variant="destructive"
className="p-7 py-6 font-normal rounded-xl text-md"
>
{deleteDailyPlanLoading && (
<ReloadIcon className="animate-spin mr-2 h-4 w-4" />
)}
Delete this plan
</Button>
</div>
<>
{canSeeActivity ? (
<div className="flex justify-end">
<Button
disabled={deleteDailyPlanLoading}
onClick={() => deleteDailyPlan(plan.id ?? '')}
variant="destructive"
className="p-7 py-6 font-normal rounded-xl text-md"
>
{deleteDailyPlanLoading && (
<ReloadIcon className="animate-spin mr-2 h-4 w-4" />
)}
Delete this plan
</Button>
</div>
) : (
<></>
)}
</>
)}
</AccordionContent>
</AccordionItem>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/lib/settings/integration-setting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ export const IntegrationSetting = () => {

{selectedRepo && (
<Button variant="ghost" className="min-w-0" onClick={handleRemoveRepo}>
<TrashIcon className='w-3.5' />
<TrashIcon className="w-3.5" />
</Button>
)}
</div>
Expand Down
Loading

0 comments on commit 60a3d0f

Please sign in to comment.