Skip to content

Commit

Permalink
[Fix]: Display statistical data on the progress of each task (#2803)
Browse files Browse the repository at this point in the history
* fix daily plan statistics displays

* fix daily plan statistics displays

* fix: Responsive on popover time estimation

---------

Co-authored-by: cedric karungu <[email protected]>
  • Loading branch information
Innocent-Akim and Cedric921 authored Aug 1, 2024
1 parent e4e342b commit 6cd2d96
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 88 deletions.
108 changes: 55 additions & 53 deletions apps/web/lib/features/daily-plan/daily-plan-compare-estimate-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { TaskEstimateInput } from '../team/user-team-card/task-estimate';
import { useDailyPlan, useTeamMemberCard, useTimer, useTMCardTaskEdit } from '@app/hooks';
import { dailyPlanCompareEstimated } from '@app/helpers/daily-plan-estimated';
import { secondsToTime } from '@app/helpers';
import { ScrollArea } from '@components/ui/scroll-bar';
import { DAILY_PLAN_ESTIMATE_HOURS_MODAL_DATE } from '@app/constants';

export interface IDailyPlanCompareEstimated {
Expand Down Expand Up @@ -51,59 +52,60 @@ export function DailyPlanCompareEstimatedModal({
}
};

return (
<Modal isOpen={open} closeModal={closeModal}>
<div className="w-[98%] md:w-[550px] relative">
<Card className="w-full h-[620px] flex flex-col justify-start bg-gray-50" shadow="custom">
<div className="flex flex-col items-center justify-between">
<DailyPlanCompareHeader />
</div>
<div className="flex items-start flex-col justify-start w-full px-2">
<TimePicker
defaultValue={{
hours: hour,
meridiem: 'AM',
minute: minute
}}
onChange={(value) => setTimes(value)}
/>
<DailyPlanWorkTimeInput />
</div>
<div className="flex h-full w-full p-2">
{todayPlan.map((plan, i) => {
return (
<div key={i}>
{plan.tasks?.map((data, index) => {
return (
<div key={index} className="p-1">
<DailyPlanTask key={index} task={data} profile={profile} />
</div>
);
})}
</div>
);
})}
</div>
<div className="flex flex-col">
<div className="flex items-center pb-2 text-red-500 text-[12px]">
{!difference && !estimated?.every(Boolean) && (
<>
<PiWarningCircleFill className="text-[14px]" />
<span>Please correct planned work hours or re-estimate task(s)</span>
</>
)}
</div>
<DailyPlanCompareActionButton
loading={updateDailyPlanLoading}
closeModal={closeModal}
onClick={onClick}
disabled={updateDailyPlanLoading && (parseInt(times.hours) > 0 ? false : true)}
/>
</div>
</Card>
</div>
</Modal>
);
return (
<Modal isOpen={open} closeModal={closeModal}>
<div className='w-[98%] md:w-[550px] relative'>
<Card className="w-full h-[620px] flex flex-col justify-start bg-gray-50" shadow='custom'>
<div className='flex flex-col items-center justify-between'>
<DailyPlanCompareHeader />
</div>
<div className='flex items-start flex-col justify-start w-full px-2'>
<TimePicker
defaultValue={{
hours: hour,
meridiem: 'AM',
minute: minute,
}}
onChange={(value) => setTimes(value)}
/>
<DailyPlanWorkTimeInput />
</div>
<ScrollArea className='flex h-full w-full p-2 flex-col'>
{todayPlan.map((plan, i) => {
return <div key={i}>
{plan.tasks?.map((data, index) => {
return <div key={index} className='p-1'>
<DailyPlanTask
key={index}
task={data}
profile={profile}
/>
</div>
})}
</div>
})}
</ScrollArea>
<div className='flex flex-col'>
<div className='flex items-center pb-2 text-red-500 text-[12px]'>
{!difference && !estimated?.every(Boolean) && (
<>
<PiWarningCircleFill className='text-[14px]' />
<span>Please correct planned work hours or re-estimate task(s)</span>
</>
)
}
</div>
<DailyPlanCompareActionButton
loading={updateDailyPlanLoading}
closeModal={closeModal}
onClick={onClick}
disabled={updateDailyPlanLoading && (parseInt(times.hours) > 0 ? false : true)}
/>
</div>
</Card>
</div>
</Modal>
)
}
export function DailyPlanTask({ task, profile }: { task?: ITeamTask; profile: any }) {
const taskEdition = useTMCardTaskEdit(task);
Expand Down
70 changes: 35 additions & 35 deletions apps/web/lib/features/user-profile-plans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useCanSeeActivityScreen, useDailyPlan, useUserProfilePage } from '@app/hooks';
import { TaskCard } from './task/task-card';
import { IDailyPlan } from '@app/interfaces';
import { IDailyPlan, ITeamTask } from '@app/interfaces';
import { AlertPopup, Container, HorizontalSeparator, NoData, ProgressBar, VerticalSeparator } from 'lib/components';
import { clsxm } from '@app/utils';
import { dataDailyPlanState } from '@app/stores';
Expand Down Expand Up @@ -45,9 +45,12 @@ export function UserProfilePlans() {
const [currentTab, setCurrentTab] = useState<FilterTabs>(defaultTab || 'Today Tasks');
const [currentOutstanding, setCurrentOutstanding] = useState<FilterOutstanding>(defaultOutstanding || 'ALL');

const [currentDataDailyPlan, setCurrentDataDailyPlan] = useRecoilState(dataDailyPlanState);

const [currentDataDailyPlan, setCurrentDataDailyPlan] = useRecoilState(dataDailyPlanState)
const { setDate, date } = useDateRange(currentTab);



const screenOutstanding = {
ALL: <OutstandingAll profile={profile} />,
DATE: <OutstandingFilterDate profile={profile} />
Expand All @@ -63,21 +66,24 @@ export function UserProfilePlans() {
const [filterPastPlanData, setFilteredPastPlanData] = useState<IDailyPlan[]>(pastPlans);
const [filterAllPlanData, setFilterAllPlanData] = useState<IDailyPlan[]>(sortedPlans);


useEffect(() => {
window.localStorage.setItem('daily-plan-tab', currentTab);
if (!currentDataDailyPlan) return;
if (currentTab === 'All Tasks') {
setCurrentDataDailyPlan(sortedPlans);
setFilterAllPlanData(filterDailyPlan(date as any, sortedPlans));
setCurrentDataDailyPlan(sortedPlans)
setFilterAllPlanData(filterDailyPlan(date as any, sortedPlans))
} else if (currentTab === 'Past Tasks') {
setCurrentDataDailyPlan(pastPlans);
setFilteredPastPlanData(filterDailyPlan(date as any, pastPlans));
setCurrentDataDailyPlan(pastPlans)
setFilteredPastPlanData(filterDailyPlan(date as any, pastPlans))
} else if (currentTab === 'Future Tasks') {
setCurrentDataDailyPlan(futurePlans);
setFilterFuturePlanData(filterDailyPlan(date as any, futurePlans));
setCurrentDataDailyPlan(futurePlans)
setFilterFuturePlanData(filterDailyPlan(date as any, futurePlans))
}

}, [currentTab, setCurrentDataDailyPlan, setDate, date]);


useEffect(() => {
window.localStorage.setItem('outstanding', currentOutstanding);
}, [currentOutstanding]);
Expand All @@ -99,8 +105,8 @@ export function UserProfilePlans() {
currentTab == filter && 'text-blue-600 dark:text-white font-medium'
)}
onClick={() => {
setDate(undefined);
setCurrentTab(filter as FilterTabs);
setDate(undefined)
setCurrentTab(filter as FilterTabs)
}}
>
{filter}
Expand All @@ -115,6 +121,7 @@ export function UserProfilePlans() {
{filter === 'Past Tasks' && filterPastPlanData?.length}
{filter === 'All Tasks' && filterAllPlanData?.length}
{filter === 'Outstanding' && outstandingPlans.length}

</span>
</div>
</div>
Expand Down Expand Up @@ -177,8 +184,8 @@ function AllPlans({ profile, currentTab = 'All Tasks' }: { profile: any; current

const [plans, setPlans] = useState<IDailyPlan[]>(filteredPlans);
useEffect(() => {
setPlans(filterDailyPlan(date as any, filteredPlans));
}, [date, setDate]);
setPlans(filterDailyPlan(date as any, filteredPlans))
}, [date, setDate])
return (
<div className="flex flex-col gap-6">
{Array.isArray(plans) && plans?.length > 0 ? (
Expand Down Expand Up @@ -254,7 +261,7 @@ function AllPlans({ profile, currentTab = 'All Tasks' }: { profile: any; current
: undefined
}
plan={plan}
className="shadow-[0px_0px_15px_0px_#e2e8f0]"
className='shadow-[0px_0px_15px_0px_#e2e8f0]'
/>
</div>
)}
Expand Down Expand Up @@ -344,32 +351,26 @@ export function PlanHeader({ plan, planMode }: { plan: IDailyPlan; planMode: Fil
const [editTime, setEditTime] = useState<boolean>(false);
const [time, setTime] = useState<number>(0);
const { updateDailyPlan, updateDailyPlanLoading } = useDailyPlan();

// Get all tasks's estimations time
const times =
plan.tasks?.map((task) => task?.estimate).filter((time): time is number => typeof time === 'number') ?? [];

let estimatedTime = 0;
if (times.length > 0) estimatedTime = times.reduce((acc, cur) => acc + cur, 0) ?? 0;
// Helper function to sum times
const sumTimes = (tasks: ITeamTask[], key: any) => tasks?.map((task: any) =>
task[key]).filter((time): time is number => typeof time === 'number')
.reduce((acc, cur) => acc + cur, 0) ?? 0;

// Get all tasks's worked time
const workedTimes =
plan.tasks?.map((task) => task.totalWorkedTime).filter((time): time is number => typeof time === 'number') ??
[];
let totalWorkTime = 0;
if (workedTimes.length > 0) totalWorkTime = workedTimes.reduce((acc, cur) => acc + cur, 0) ?? 0;
// Get all tasks' estimation and worked times
const estimatedTime = sumTimes(plan.tasks!, 'estimate');
const totalWorkTime = sumTimes(plan.tasks!, 'totalWorkedTime');

// Get completed tasks from a plan
const completedTasks = plan.tasks?.filter((task) => task.status === 'completed' && task.status).length ?? 0;
// Get completed and ready tasks from a plan
const completedTasks = plan.tasks?.filter(task => task.status === 'completed').length ?? 0;
const readyTasks = plan.tasks?.filter(task => task.status === 'ready').length ?? 0;

// Get ready tasks from a plan
const readyTasks = plan.tasks?.filter((task) => task.status === 'ready').length ?? 0;

// Total tasks for plan
// Total tasks for the plan
const totalTasks = plan.tasks?.length ?? 0;

// Completion percent
const completionPercent = ((completedTasks * 100) / totalTasks).toFixed(2);
const completionPercent = totalTasks > 0 ? ((completedTasks * 100) / totalTasks).toFixed(0) : '0.0';


return (
<div
Expand Down Expand Up @@ -442,7 +443,7 @@ export function PlanHeader({ plan, planMode }: { plan: IDailyPlan; planMode: Fil
<div>
<div className="flex items-center gap-2">
<span className="font-medium">Completed tasks: </span>
<span className="font-medium">{completedTasks}</span>
<span className="font-medium">{`${completedTasks}/${totalTasks}`}</span>
</div>
<div className="flex items-center gap-2">
<span className="font-medium">Ready: </span>
Expand Down Expand Up @@ -486,8 +487,7 @@ export function EmptyPlans({ planMode }: { planMode?: FilterTabs }) {
<div className="xl:mt-20">
<NoData
text={`No task planned ${planMode === 'Today Tasks' ? 'today' : ''}`}
component={<ReaderIcon className="w-14 h-14" />}
/>
component={<ReaderIcon className="w-14 h-14" />} />
</div>
);
}

0 comments on commit 6cd2d96

Please sign in to comment.