Skip to content

Commit

Permalink
feat/#1662-kanban-board (#2138)
Browse files Browse the repository at this point in the history
* fix(Kanban): ui fixes and kanban drag and drop smoothness

* fix(Kanban): ui fixes and kanban drag and drop smoothness

* fix(DeepScan): fix the condition that is used for testing purpose

* fix: translations added + console remove + static data removed

* fix the consoles and static code

* fix the consoles and static code

* Update team-members-kanban-view.tsx

* Update page.tsx

* fix the scro unused word in class

* fix the overlapper unused word in class

* fix the overlapper unused word in class

---------

Co-authored-by: Ruslan K <[email protected]>
  • Loading branch information
Anishali2 and evereq authored Feb 2, 2024
1 parent 4d973a0 commit 5b8b6a0
Show file tree
Hide file tree
Showing 24 changed files with 344 additions and 263 deletions.
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"gtag",
"headlessui",
"heroicons",
"overlapper",
"Huhn",
"icnsutils",
"incididunt",
Expand Down
213 changes: 116 additions & 97 deletions apps/web/app/[locale]/kanban/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,148 +4,167 @@ import { KanbanTabs } from '@app/constants';
import { useOrganizationTeams } from '@app/hooks';
import { useKanban } from '@app/hooks/features/useKanban';
import KanbanBoardSkeleton from '@components/shared/skeleton/KanbanBoardSkeleton';
import VerticalLine from '@components/ui/svgs/vertificalline';
import { withAuthentication } from 'lib/app/authenticator';
import { Breadcrumb } from 'lib/components';
import { AddIcon } from 'lib/components/svgs';
import { Breadcrumb, Button, Dropdown, InputField } from 'lib/components';
import { AddIcon, SearchNormalIcon, Settings4Icon } from 'lib/components/svgs';
import { KanbanView } from 'lib/features/team-members-kanban-view';
import { MainLayout } from 'lib/layout';
import { useState } from 'react';
import { useTranslations } from 'next-intl';
import { useParams } from 'next/navigation';
import Skeleton from 'react-loading-skeleton';
import ImageOverlapper, { IImageOverlapper } from 'lib/components/image-overlapper';
import ImageComponent, { ImageOverlapperProps } from 'lib/components/image-overlapper';
import Separator from '@components/ui/separator';
import { clsxm } from '@app/utils';

const Kanban = () => {
const { data } = useKanban();
const { activeTeam } = useOrganizationTeams();
const t = useTranslations();
const params = useParams<{ locale: string }>();

const currentLocale = params ? params.locale : null;

const [activeTab, setActiveTab] = useState(KanbanTabs.TODAY);

const breadcrumbPath = [
{ title: JSON.parse(t('pages.home.BREADCRUMB')), href: '/' },
{ title: activeTeam?.name || '', href: '/' },
{ title: 'Kanban Board', href: `/${currentLocale}/kanban` }
{ title: t('pages.kanban.KANBAN_BOARD'), href: `/${currentLocale}/kanban` }
];

const activeTeamMembers = activeTeam?.members ? activeTeam.members : [];

const teamMembers: IImageOverlapper[] = [];
const teamMembers: ImageOverlapperProps[] = [];

activeTeamMembers.map((member: any)=> {
activeTeamMembers.map((member: any) => {
teamMembers.push({
id: member.employee.user.id,
url: member.employee.user.imageUrl,
alt: member.employee.user.firstName
})
});
});
const tabs = [
{ name: t('common.TODAY'), value: KanbanTabs.TODAY },
{ name: t('common.YESTERDAY'), value: KanbanTabs.YESTERDAY },
{ name: t('common.TOMORROW'), value: KanbanTabs.TOMORROW }
];
// eslint-disable-next-line react/no-unstable-nested-components
const Label = ({ active, selected }: { active: string; selected: string }) => (
<div
style={{
fontWeight: selected ? 'bold' : 'normal'
}}
className="text-left"
>
{active}
</div>
);

const sampleDropdownItem = (key: string) => {
const data = {
key: '1',
Label: Label,
selectedLabel: <strong>{key}</strong>,
itemTitle: key
// other properties can be added as needed
};
return data;
};
return (
<>
<MainLayout
showTimer={true}
>
<div className={'fixed flex flex-col bg-white dark:bg-dark--theme h-auto z-10 px-[32px] mx-[0px] w-full'}>
<MainLayout showTimer={true}>
<div className={' flex flex-col bg-white dark:bg-dark--theme h-auto z-10 px-[32px] mx-[0px] w-full'}>
<div className="flex flex-row items-center justify-between mt-[34px]">
<Breadcrumb paths={breadcrumbPath} className="text-sm" />
<div className="flex flex-row items-center gap-[12px]">
{activeTeamMembers.length > 0 ?
<p>08:00 ( UTC +04:30 )</p>
:
<Skeleton height={20} width={120} borderRadius={5} className="rounded-full dark:bg-[#353741]" />
}
<VerticalLine />
<ImageOverlapper images={teamMembers}/>
<VerticalLine />
</div>
<div className="flex justify-between items-center mt-10">
<h1 className="text-4xl font-semibold ">{t('pages.kanban.KANBAN_BOARD')}</h1>
<div className="flex w-fit items-center space-x-2">
<strong className="text-gray-400">08:00 ( UTC +04:30 )</strong>
<div className="mt-1">
<Separator />
</div>
<ImageComponent images={teamMembers} />
<div className="mt-1">
<Separator />
</div>
<button className="p-2 rounded-full border-2 border-[#0000001a] dark:border-white">
<AddIcon width={24} height={24} className={'dark:stroke-white'} />
</button>
</div>
</div>
<div className="relative flex flex-row justify-between items-center ">
<div className="relative flex flex-row justify-between items-center mt-10">
<div className="flex flex-row">
<div
onClick={() => {
setActiveTab(KanbanTabs.TODAY);
}}
className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${
activeTab === KanbanTabs.TODAY
? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white'
: 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]'
}`}
style={{
borderBottomWidth: '3px',
borderBottomStyle: 'solid'
}}
>
Today
</div>
<div
onClick={() => {
setActiveTab(KanbanTabs.YESTERDAY);
}}
className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${
activeTab === KanbanTabs.YESTERDAY
? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white'
: 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]'
}`}
style={{
borderBottomWidth: '3px',
borderBottomStyle: 'solid'
}}
{tabs.map((tab) => (
<div
key={tab.name}
onClick={() => setActiveTab(tab.value)}
className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${
activeTab === tab.value
? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white'
: 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]'
}`}
style={{
borderBottomWidth: '3px',
borderBottomStyle: 'solid'
}}
>
{tab.name}
</div>
))}
</div>
<div className="flex space-x-2">
<Dropdown
searchBar={false}
className="w-24"
buttonClassName={clsxm(
'py-0 font-medium h-11',
'bg-light--theme-light dark:bg-dark--theme-light dark:text-white font-normal'
)}
value={sampleDropdownItem('Epic') as any}
items={[sampleDropdownItem] as any}
/>
<Dropdown
searchBar={false}
className="w-24"
buttonClassName={clsxm(
'py-0 font-medium h-11',
'bg-light--theme-light dark:bg-dark--theme-light dark:text-white font-normal'
)}
value={sampleDropdownItem('Label') as any}
items={[sampleDropdownItem] as any}
/>
<button
className={clsxm(
'p-3 px-5 flex space-x-2 input-border rounded-xl items-center text-sm',
'h-[2.75rem]'
)}
>
Yesterday
<Settings4Icon className="dark:stroke-white" />
<span>{t('common.FILTER')}</span>
</button>
<div className="mt-1">
<Separator />
</div>
<div
onClick={() => {
setActiveTab(KanbanTabs.TOMORROW);
}}
className={`cursor-pointer pt-2.5 px-5 pb-[30px] text-base font-semibold ${
activeTab === KanbanTabs.TOMORROW
? 'border-b-[#3826A6] text-[#3826A6] dark:text-white dark:border-b-white'
: 'border-b-white dark:border-b-[#191A20] dark:text-white text-[#282048]'
}`}
style={{
borderBottomWidth: '3px',
borderBottomStyle: 'solid'
}}
>
Tomorrow
<div className="w-44">
<InputField
type="text"
placeholder={t('common.SEARCH')}
className="mb-0 h-10"
leadingNode={
<Button
variant="ghost"
className="p-0 m-0 ml-[0.9rem] min-w-0 absolute right-3"
type="submit"
>
<SearchNormalIcon className="w-[1rem] dark:stroke-[#ffffff] " />
</Button>
}
/>
</div>
</div>
<div></div>
</div>
</div>
<div className="mt-[15vh] z-0">
<div>
{/** TODO:fetch teamtask based on days */}
{/** Kanbanboard for today tasks */}
{activeTab === KanbanTabs.TODAY && (
<>
{Object.keys(data).length > 0 ? (
<KanbanView kanbanBoardTasks={data} />
) : (
<KanbanBoardSkeleton />
)}
</>
)}

{/** Kanbanboard for yesterday tasks */}
{activeTab === KanbanTabs.YESTERDAY && (
<>
{Object.keys(data).length > 0 ? (
<KanbanView kanbanBoardTasks={data} />
) : (
<KanbanBoardSkeleton />
)}
</>
)}

{/** Kanbanboard for tomorrow tasks */}
{activeTab === KanbanTabs.TOMORROW && (
{activeTab && ( // add filter for today, yesterday and tomorrow
<>
{Object.keys(data).length > 0 ? (
<KanbanView kanbanBoardTasks={data} />
Expand Down
16 changes: 11 additions & 5 deletions apps/web/app/hooks/features/useKanban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { useRecoilState } from 'recoil';
import { useEffect, useState } from 'react';
import { ITaskStatusItemList, ITeamTask } from '@app/interfaces';
import { useTeamTasks } from './useTeamTasks';
import { IKanban } from '@app/interfaces/IKanban';

export function useKanban() {
const [loading, setLoading] = useState<boolean>(true);

const [kanbanBoard, setKanbanBoard] = useRecoilState(kanbanBoardState);

const taskStatusHook = useTaskStatus();

const { tasks, tasksFetching, updateTask } = useTeamTasks();

/**
Expand Down Expand Up @@ -73,14 +71,22 @@ export function useKanban() {
});
};

const addNewTask = (task: ITeamTask, status: string) => {
const updatedBoard = {
...kanbanBoard,
[status]: [...kanbanBoard[status], task]
};
setKanbanBoard(() => updatedBoard);
};
return {
data: kanbanBoard,
data: kanbanBoard as IKanban,
isLoading: loading,
columns: taskStatusHook.taskStatus,
updateKanbanBoard: setKanbanBoard,
updateTaskStatus: updateTask,
toggleColumn,
isColumnCollapse,
reorderStatus
reorderStatus,
addNewTask
};
}
6 changes: 3 additions & 3 deletions apps/web/app/interfaces/IKanban.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ITeamTask } from "./ITask";
import { ITeamTask } from './ITask';

export interface IKanban {
[key: string]: ITeamTask[]
}
[key: string]: ITeamTask[];
}
6 changes: 4 additions & 2 deletions apps/web/app/stores/kanban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ import { atom } from "recoil";

export const kanbanBoardState = atom<IKanban>({
key: 'kanbanBoardState',
default: {}
})
default: {

}
})
Loading

0 comments on commit 5b8b6a0

Please sign in to comment.