Skip to content

Commit

Permalink
dark mode, show project for the selected team
Browse files Browse the repository at this point in the history
  • Loading branch information
CREDO23 committed Feb 15, 2025
1 parent 5a3f28e commit 4f5c2bb
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 137 deletions.
27 changes: 27 additions & 0 deletions apps/web/app/[locale]/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client';

import { MainLayout } from '@/lib/layout';
import { useOrganizationTeams } from '@/app/hooks';
import { withAuthentication } from '@/lib/app/authenticator';

function Page() {
const { isTrackingEnabled } = useOrganizationTeams();
return (
<MainLayout
showTimer={isTrackingEnabled}
className="!p-0 pb-1 !overflow-hidden w-full"
childrenClassName="w-full h-full"
mainHeaderSlot={
<div className="flex flex-col p-4 dark:bg-dark--theme">
<div className="flex flex-col items-start justify-between gap-3">
<div className="flex items-center justify-center h-10 gap-8">
<h3 className=" text-3xl font-medium">Project</h3>
</div>
</div>
</div>
}
></MainLayout>
);
}

export default withAuthentication(Page, { displayName: 'ProjectPage' });
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import moment from 'moment';
import { ArrowUpDown } from 'lucide-react';
import { Button } from '@components/ui/button';
import AvatarStack from '@components/shared/avatar-stack';
import { SpinnerLoader } from '@/lib/components';

export type ProjectTableDataType = {
project: {
Expand All @@ -48,13 +49,14 @@ export type ProjectTableDataType = {
* @component
* @param {Object} props - The component props.
* @param {ProjectTableDataType[]} props.data - Array of data objects projects information.
* @param {boolean} props.loading - Whether to show loading indicator when loading projects data.
*
* @returns {JSX.Element} A table showing projects information.
*
*/

export function DataTableProject(props: { data: ProjectTableDataType[] }) {
const { data } = props;
export function DataTableProject(props: { data: ProjectTableDataType[]; loading: boolean }) {
const { data, loading } = props;
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]);
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({});
Expand Down Expand Up @@ -183,10 +185,12 @@ export function DataTableProject(props: { data: ProjectTableDataType[] }) {
header: () => <div>{t('common.MEMBERS')}</div>,
cell: ({ row }) => {
const members =
row.original?.members?.map((el) => ({
imageUrl: el?.employee?.user?.imageUrl,
name: el?.employee?.fullName
})) || [];
row.original?.members
?.filter((el) => !el.isManager)
?.map((el) => ({
imageUrl: el?.employee?.user?.imageUrl,
name: el?.employee?.fullName
})) || [];

return members?.length > 0 ? <AvatarStack avatars={members} /> : null;
}
Expand Down Expand Up @@ -239,9 +243,17 @@ export function DataTableProject(props: { data: ProjectTableDataType[] }) {
}
});

React.useEffect(() => {
console.log(loading);
}, [loading]);

return (
<div className="w-full">
{table?.getRowModel()?.rows.length ? (
{loading ? (
<div className="w-full flex justify-center items-center">
<SpinnerLoader />
</div>
) : table?.getRowModel()?.rows.length ? (
<div className="rounded-md">
<Table>
<TableHeader>
Expand All @@ -259,7 +271,6 @@ export function DataTableProject(props: { data: ProjectTableDataType[] }) {
</TableRow>
))}
</TableHeader>

<TableBody>
{table?.getRowModel()?.rows.length ? (
table?.getRowModel().rows.map((row) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ export default function GridItem(props: IGridItemProps) {

const members = useMemo(
() =>
data?.members?.map((el) => ({
imageUrl: el?.employee?.user?.imageUrl,
name: el?.employee?.fullName
})) || [],
data?.members
?.filter((el) => !el.isManager)
?.map((el) => ({
imageUrl: el?.employee?.user?.imageUrl,
name: el?.employee?.fullName
})) || [],
[data?.members]
);

Expand Down Expand Up @@ -83,12 +85,16 @@ export default function GridItem(props: IGridItemProps) {

<div className="w-full items-center flex gap-6">
<p className=" font-medium">{t('common.STATUS')}</p>
<div
style={{ backgroundColor: statusColorsMap.get(data?.status) ?? '#e5e7eb' }}
className="rounded px-4 py-1"
>
{data?.status ?? '-'}
</div>
{data?.status ? (
<div
style={{ backgroundColor: statusColorsMap.get(data?.status) ?? 'transparent' }}
className="rounded px-4 py-1"
>
{data?.status}
</div>
) : (
'-'
)}
</div>

<div className="w-full flex items-center gap-10">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import { MainLayout } from '@/lib/layout';
import { useOrganizationProjects, useOrganizationTeams } from '@/app/hooks';
import { withAuthentication } from '@/lib/app/authenticator';
import { useEffect, useMemo, useState } from 'react';
import { useMemo, useState } from 'react';
import { Grid, List, ListFilterPlus, Plus, Search, Settings2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button, InputField, Paginate } from '@/lib/components';
import { Button, InputField, Paginate, SpinnerLoader } from '@/lib/components';
import { usePagination } from '@/app/hooks/features/usePagination';
import { IProject } from '@/app/interfaces';
import { ExportModeSelect } from '@components/shared/export-mode-select';
Expand All @@ -21,6 +21,7 @@ import { useTranslations } from 'next-intl';
type TViewMode = 'GRID' | 'LIST';

function PageComponent() {
const t = useTranslations();
const { isTrackingEnabled } = useOrganizationTeams();
const lastSelectedView = useMemo(() => {
try {
Expand All @@ -31,34 +32,51 @@ function PageComponent() {
}
}, []);
const [selectedView, setSelectedView] = useState<TViewMode>(lastSelectedView ?? 'LIST');
const { getOrganizationProjects, organizationProjects } = useOrganizationProjects();
const { organizationProjects, getOrganizationProjectsLoading } = useOrganizationProjects();
const [dateRange] = useState<DateRange>({
from: startOfMonth(new Date()),
to: endOfMonth(new Date())
});
const { activeTeam } = useOrganizationTeams();
const activeTeamProjects = useMemo(() => activeTeam?.projects?.map((el) => el.id) ?? [], [activeTeam?.projects]);
const viewItems: { title: string; name: TViewMode; icon: any }[] = useMemo(
() => [
{
title: 'List view',
title: t('pages.projects.views.LIST_VIEW'),
name: 'LIST',
icon: List
},
{
title: 'Grid view',
title: t('pages.projects.views.GRID_VIEW'),
name: 'GRID',
icon: Grid
}
],
[]
[t]
);
const t = useTranslations();

const { total, onPageChange, itemsPerPage, itemOffset, endOffset, setItemsPerPage, currentItems } =
usePagination<IProject>(organizationProjects);
usePagination<IProject>(organizationProjects ?? []);

useEffect(() => {
getOrganizationProjects();
}, [getOrganizationProjects]);
const filteredProjects = useMemo(
() =>
currentItems
?.filter((el) => activeTeamProjects.includes(el.id))
?.map((el) => ({
project: {
name: el.name,
imageUrl: el.imageUrl,
color: el.color
},
status: el.status,
startDate: el.startDate,
endDate: el.endDate,
members: el.members,
managers: el.members,
teams: el.teams
})),
[currentItems, activeTeamProjects]
);

return (
<MainLayout
Expand All @@ -69,7 +87,7 @@ function PageComponent() {
<div className="flex flex-col p-4 dark:bg-dark--theme">
<div className="flex flex-col items-start justify-between gap-3">
<div className="flex items-center justify-center h-10 gap-8">
<h3 className=" text-3xl font-medium">Projects</h3>
<h3 className=" text-3xl font-medium">{t('pages.projects.projectTitle.PLURAL')}</h3>
</div>
<div className=" h-14 flex items-center justify-between w-full">
<div className="w-[20rem] h-full flex items-end justify-center">
Expand Down Expand Up @@ -101,7 +119,7 @@ function PageComponent() {

<div className="h-full flex items-end">
<Button variant="grey" className=" text-primary font-medium">
<Plus size={15} /> <span>Create New Project</span>
<Plus size={15} /> <span>{t('pages.projects.CREATE_NEW_PROJECT')}</span>
</Button>
</div>
</div>
Expand All @@ -110,60 +128,50 @@ function PageComponent() {
}
>
<div className="flex flex-col p-4 w-full h-full gap-6 dark:bg-dark--theme mt-6">
<div className="border rounded-lg bg-white p-3 space-y-6">
<div className="border bg-light--theme-light dark:bg-transparent rounded-lg p-3 space-y-6">
<div className=" rounded flex items-center justify-between font-light">
<div className="w-80 flex border h-[2.2rem] items-center px-4 rounded-lg">
<div className="w-80 flex border dark:border-white h-[2.2rem] items-center px-4 rounded-lg">
<Search size={15} className=" text-slate-300" />{' '}
<InputField placeholder="Search ..." className=" h-full border-none" noWrapper />
<InputField
placeholder="Search ..."
className=" h-full border-none bg-transparent dark:bg-transparent"
noWrapper
/>
</div>
<div className="flex gap-3">
<DatePickerWithRange
defaultValue={dateRange}
onChange={() => {
/* TODO: Implement date range handling */
}}
className="bg-transparent dark:bg-transparent dark:border-white"
/>
<Button
type="button"
className=" border-gray-200 hover:bg-slate-100 text-sm min-w-fit text-black h-[2.2rem] font-light"
className=" border-gray-200 !border hover:bg-slate-100 dark:border text-sm min-w-fit text-black h-[2.2rem] font-light hover:dark:bg-transparent"
variant="outline"
>
<ListFilterPlus size={15} /> <span>{t('common.FILTER')}</span>
</Button>
<ExportModeSelect
className="hover:bg-slate-100"
className="hover:bg-slate-100 bg-transparent dark:bg-transparent dark:border-white hover:dark:bg-transparent "
onChange={() => {
/* TODO: Implement export handling */
}}
/>
<Button
type="button"
className=" border-gray-200 text-sm hover:bg-slate-100 min-w-fit text-black h-[2.2rem] font-light"
className=" border-gray-200 text-sm hover:bg-slate-100 min-w-fit text-black h-[2.2rem] font-light hover:dark:bg-transparent"
variant="outline"
>
<Settings2 size={15} /> <span>{t('common.VIEW')}</span>
</Button>
</div>
</div>
{selectedView === 'LIST' ? (
<div className="w-full">
<DataTableProject
data={currentItems.map((el) => ({
project: {
name: el.name,
imageUrl: el.imageUrl,
color: el.color
},

status: el.status,
startDate: el.startDate,
endDate: el.endDate,
members: el.members,
managers: el.members,
teams: el.teams
}))}
/>
<div className=" bg-white dark:bg-dark--theme px-4 py-4 flex">
<div key="list" className="w-full">
<DataTableProject loading={getOrganizationProjectsLoading} data={filteredProjects} />
<div className=" dark:bg-dark--theme px-4 py-4 flex">
<Paginate
total={total}
onPageChange={onPageChange}
Expand All @@ -177,25 +185,14 @@ function PageComponent() {
</div>
</div>
) : selectedView === 'GRID' ? (
<div className=" w-full flex-wrap flex gap-3">
{currentItems
.map((el) => ({
project: {
name: el.name,
imageUrl: el.imageUrl,
color: el.color
},

status: el.status,
startDate: el.startDate,
endDate: el.endDate,
members: el.members,
managers: el.members,
teams: el.teams
}))
.map((el) => (
<GridItem key={el.project.name} data={el} />
))}
<div key="grid" className=" w-full flex-wrap flex gap-3">
{getOrganizationProjectsLoading ? (
<div className="w-full flex items-center justify-center">
<SpinnerLoader />
</div>
) : (
filteredProjects.map((el) => <GridItem key={el.project.name} data={el} />)
)}
</div>
) : null}
</div>
Expand All @@ -204,4 +201,4 @@ function PageComponent() {
);
}

export default withAuthentication(PageComponent, { displayName: 'ProjectPage' });
export default withAuthentication(PageComponent, { displayName: 'ProjectsPage' });
File renamed without changes.
Loading

0 comments on commit 4f5c2bb

Please sign in to comment.