Skip to content

Commit

Permalink
feature / add teams - crude
Browse files Browse the repository at this point in the history
  • Loading branch information
psiddharthdesign committed Jul 31, 2024
1 parent 18ade66 commit bb0fa5e
Show file tree
Hide file tree
Showing 37 changed files with 2,491 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Suspense } from 'react';

import { DesktopSidebarFallback } from '@/components/SidebarComponents/SidebarFallback';
import { SwitcherAndToggle } from '@/components/SidebarComponents/SidebarLogo';
import { Activity, FileText, GitCompare, Home, Layers, MessageCircle, Settings, Shield } from 'lucide-react';
import { Activity, FileText, GitCompare, Home, Layers, MessageCircle, Settings, Shield, Users } from 'lucide-react';

async function OrganizationSidebarInternal({
organizationId,
Expand Down Expand Up @@ -41,6 +41,11 @@ async function OrganizationSidebarInternal({
href={`/org/${organizationId}/projects`}
icon={<Layers className="size-4 text-foreground" />}
/>
<SidebarLink
label="Teams"
href={`/org/${organizationId}/teams`}
icon={<Users className="size-4 text-foreground" />}
/>
<SidebarLink
label="Activity"
href={`/org/${organizationId}/activity`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DesktopSidebarFallback } from '@/components/SidebarComponents/SidebarFa
import { SwitcherAndToggle } from '@/components/SidebarComponents/SidebarLogo';
import { fetchSlimOrganizations, getOrganizationSlugByOrganizationId } from '@/data/user/organizations';
import { organizationParamSchema } from '@/utils/zod-schemas/params';
import { Activity, FileText, GitCompare, Home, Layers, MessageCircle, Settings, Shield } from 'lucide-react';
import { Activity, FileText, GitCompare, Home, Layers, MessageCircle, Settings, Shield, Users } from 'lucide-react';

async function OrganizationSidebarInternal({
organizationId,
Expand Down Expand Up @@ -41,6 +41,11 @@ async function OrganizationSidebarInternal({
href={`/org/${organizationId}/projects`}
icon={<Layers className="size-4 text-foreground" />}
/>
<SidebarLink
label="Teams"
href={`/org/${organizationId}/teams`}
icon={<Users className="size-4 text-foreground" />}
/>
<SidebarLink
label="Activity"
href={`/org/${organizationId}/activity`}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Card } from '@/components/ui/card'
import { Skeleton } from '@/components/ui/skeleton'

type Props = {
quantity: number
}

const TeamsLoadingFallback = ({ quantity }: Props) => {
return (
<div className='flex w-full gap-4 p-4 overflow-x-auto mt-6'>
{[...Array(quantity)].map((_, i) => (
<Card className="flex flex-col items-start p-4 bg-card min-h-32 rounded-lg shadow w-72" key={`${i}skeleton`}>
<Skeleton className="h-6 w-24 mb-2" />
<Skeleton className="h-6 w-36 mb-1" />
<Skeleton className="h-4 w-16" />
</Card>
))}
</div>
)
}

export default TeamsLoadingFallback
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ProjectsCardList } from "@/components/Projects/ProjectsCardList";
import { Search } from "@/components/Search";
import { TeamsCardList } from "@/components/Teams/TeamsCardList";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { getOrganizationTitle } from "@/data/user/organizations";
import { getProjects } from "@/data/user/projects";
import { getTeams } from "@/data/user/teams";
import {
organizationParamSchema,
projectsfilterSchema
Expand All @@ -16,6 +18,7 @@ import type { z } from "zod";
import { DashboardClientWrapper } from "./DashboardClientWrapper";
import { DashboardLoadingFallback } from "./DashboardLoadingFallback";
import ProjectsLoadingFallback from "./ProjectsLoadingFallback";
import TeamsLoadingFallback from "./TeamsLoadingFallback";

async function Projects({
organizationId,
Expand All @@ -26,10 +29,26 @@ async function Projects({
}) {
const projects = await getProjects({
organizationId,
teamId: null,
...filters,
});
return <ProjectsCardList projects={projects} />;
}
async function Teams({
organizationId,
filters,
}: {
organizationId: string;
filters: z.infer<typeof projectsfilterSchema>;
}) {
const teams = await getTeams({
organizationId,
...filters,
});
return <TeamsCardList teams={teams} />;
}



export type DashboardProps = {
params: { organizationId: string };
Expand Down Expand Up @@ -81,6 +100,35 @@ async function Dashboard({ params, searchParams }: DashboardProps) {
</Suspense>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-6">
<CardTitle>Recent Teams</CardTitle>
<div className="flex items-center space-x-4">
<Search className="w-[200px]" placeholder="Search teams" />
<Button variant="secondary" size="sm" asChild>
<Link href={`/org/${organizationId}/teams`}>
<Layers className="mr-2 h-4 w-4" />
View all teams
</Link>
</Button>
</div>
</CardHeader>
<CardContent>
<Suspense fallback={<TeamsLoadingFallback quantity={3} />}>
<Teams
organizationId={organizationId}
filters={validatedSearchParams}
/>
{validatedSearchParams.query && (
<p className="mt-4 text-sm text-muted-foreground">
Searching for{" "}
<span className="font-medium">{validatedSearchParams.query}</span>
</p>
)}
</Suspense>
</CardContent>

</Card>
</DashboardClientWrapper>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CreateProjectForm from "@/components/CreateProjectForm";
import { getOrganizationRepos } from "@/data/user/repos";
import { getTeamsInOrganization } from "@/data/user/teams";
import { organizationParamSchema } from "@/utils/zod-schemas/params";
import type { Metadata } from "next";

Expand All @@ -14,11 +15,16 @@ export default async function CreateProjectPage({
params: unknown;
}) {
const { organizationId } = organizationParamSchema.parse(params);
const repositories = await getOrganizationRepos(organizationId);
const [repositories, fullTeams] = await Promise.all([
getOrganizationRepos(organizationId),
getTeamsInOrganization(organizationId)
]);

const teams = fullTeams.map(({ id, name }) => ({ id, name }));

return (
<div className="w-full mt-1">
<CreateProjectForm organizationId={organizationId} repositories={repositories} />
<CreateProjectForm organizationId={organizationId} repositories={repositories} teams={teams} />
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { T } from "@/components/ui/Typography";
import { Button } from "@/components/ui/button";
import { getProjects, getProjectsTotalCount } from "@/data/user/projects";
import {
organizationParamSchema,
projectsfilterSchema
projectsfilterSchema,
teamParamSchema
} from "@/utils/zod-schemas/params";
import { Plus } from "lucide-react";
import type { Metadata } from "next";
Expand All @@ -15,13 +15,14 @@ import { Suspense } from "react";
import type { DashboardProps } from "../page";
import { OrganizationProjectsTable } from "./OrganizationProjectsTable";

async function ProjectsTableWithPagination({
export async function ProjectsTableWithPagination({
organizationId,
teamId,
searchParams,
}: { organizationId: string; searchParams: unknown }) {
}: { organizationId: string; teamId: number | null; searchParams: unknown }) {
const filters = projectsfilterSchema.parse(searchParams);
const [projects, totalPages] = await Promise.all([
getProjects({ ...filters, organizationId }),
getProjects({ ...filters, organizationId, teamId }),
getProjectsTotalCount({ ...filters, organizationId }),
]);

Expand All @@ -42,7 +43,7 @@ export default async function Page({
params,
searchParams,
}: DashboardProps) {
const { organizationId } = organizationParamSchema.parse(params);
const { organizationId, teamId } = teamParamSchema.parse(params);
const filters = projectsfilterSchema.parse(searchParams);

return (
Expand Down Expand Up @@ -78,6 +79,7 @@ export default async function Page({
>
<ProjectsTableWithPagination
organizationId={organizationId}
teamId={teamId ?? null}
searchParams={searchParams}
/>
</Suspense>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use client";
import { T } from '@/components/ui/Typography';
import { Card } from '@/components/ui/card';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import type { Tables } from '@/lib/database.types';
import {
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
type ColumnDef,
type SortingState,
} from '@tanstack/react-table';
import moment from 'moment';
import Link from 'next/link';
import { useState } from 'react';

type Team = Tables<'teams'>;

type Props = {
teams: Team[];
};

export function OrganizationTeamsTable({ teams }: Props) {
const columns: ColumnDef<Team>[] = [
{
accessorKey: 'name',
header: 'Name',
cell: ({ row }) => (
<Link href={`/org/${row.original.organization_id}/team/${row.original.id}`} className='hover:underline'>
{row.getValue('name')}
</Link>
),
},
{
accessorKey: 'created_at',
header: 'Created At',
cell: ({ row }) => {
const date = moment(row.getValue('created_at') as string);
return date.format('MMM DD YYYY, HH:mm [hrs]');
},
},
{
accessorKey: 'by',
header: 'By',
cell: ({ row }) => row.getValue('by') || 'unknown',
},
];

const [sorting, setSorting] = useState<SortingState>([]);
const table = useReactTable({
data: teams,
columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onSortingChange: setSorting,
state: {
sorting,
},
});

if (teams.length === 0) {
return (
<Card>
<div className='flex justify-center w-full items-center h-[180px]'>
<T.Subtle>No teams found</T.Subtle>
</div>
</Card>
);
}

return (
<div className="w-full">
<Card className="p-4">
<Table>
<TableHeader>
{table.getHeaderGroups().map(headerGroup => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map(header => (
<TableHead key={header.id} className="text-left font-normal text-sm text-muted-foreground">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map(row => (
<TableRow key={row.id} className="hover:bg-muted/50">
{row.getVisibleCells().map(cell => (
<TableCell key={cell.id} className="py-2">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</Card>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Pagination } from "@/components/Pagination";
import { getTeams, getTeamsTotalCount } from "@/data/user/teams";
import { projectsfilterSchema } from "@/utils/zod-schemas/params";
import { OrganizationTeamsTable } from "./OrganizationTeamsTable";

export async function TeamsTableWithPagination({
organizationId,
searchParams,
}: { organizationId: string; searchParams: unknown }) {
const filters = projectsfilterSchema.parse(searchParams);
const [teams, totalPages] = await Promise.all([
getTeams({ ...filters, organizationId }),
getTeamsTotalCount({ ...filters, organizationId }),
]);

return (
<>
<OrganizationTeamsTable teams={teams} />
<Pagination totalPages={totalPages} />
</>
);
}
Loading

0 comments on commit bb0fa5e

Please sign in to comment.