Skip to content

Commit d2f6acc

Browse files
committed
[IMP][REF] tasks table and calendar
1 parent abd6856 commit d2f6acc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+11886
-1107
lines changed

Diff for: bun.lockb

3.21 KB
Binary file not shown.

Diff for: package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@radix-ui/react-avatar": "^1.1.2",
3333
"@radix-ui/react-checkbox": "^1.1.3",
3434
"@radix-ui/react-collapsible": "^1.1.2",
35+
"@radix-ui/react-context-menu": "^2.2.4",
3536
"@radix-ui/react-dialog": "^1.1.4",
3637
"@radix-ui/react-dropdown-menu": "^2.1.4",
3738
"@radix-ui/react-icons": "^1.3.2",
@@ -46,6 +47,8 @@
4647
"@radix-ui/react-switch": "^1.1.2",
4748
"@radix-ui/react-tabs": "^1.1.2",
4849
"@radix-ui/react-toast": "^1.2.4",
50+
"@radix-ui/react-toggle": "^1.1.1",
51+
"@radix-ui/react-toggle-group": "^1.1.1",
4952
"@radix-ui/react-tooltip": "^1.1.6",
5053
"@t3-oss/env-nextjs": "^0.11.1",
5154
"@tanstack/react-query": "^5.60.5",
@@ -55,6 +58,7 @@
5558
"@trpc/react-query": "^11.0.0-rc.638",
5659
"@trpc/server": "^11.0.0-rc.638",
5760
"@types/bcryptjs": "^2.4.6",
61+
"@uidotdev/usehooks": "^2.4.1",
5862
"@uploadthing/react": "^7.1.3",
5963
"bcryptjs": "^2.4.3",
6064
"better-auth": "^1.1.3",
@@ -65,6 +69,7 @@
6569
"drizzle-orm": "^0.38.2",
6670
"drizzle-zod": "^0.6.1",
6771
"framer-motion": "^11.15.0",
72+
"lodash.throttle": "^4.1.1",
6873
"lucide-react": "^0.469.0",
6974
"next": "15.1.2",
7075
"next-auth": "4.24.11",
@@ -84,7 +89,8 @@
8489
"trpc": "^0.11.3",
8590
"uploadthing": "^7.4.1",
8691
"vaul": "^1.1.2",
87-
"zod": "^3.24.1"
92+
"zod": "^3.24.1",
93+
"zustand": "^5.0.2"
8894
},
8995
"devDependencies": {
9096
"@types/node": "^22.10.2",

Diff for: src/app/(auth)/_components/login.form.tsx

+8-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { Button } from "@/components/ui/button";
44
import { Input } from "@/components/ui/input";
5-
import { Icons } from "@/components/icons";
5+
// Removed unused import
66
import { useState, useEffect } from "react";
77
import { useForm } from "react-hook-form";
88
import { z } from "zod";
@@ -20,8 +20,9 @@ import { AlertCircle } from "lucide-react";
2020
import ProvidersComponent from "./providers";
2121
import { signIn, useSession } from "@/lib/api/auth/auth-client";
2222
import { useSearchParams } from "next/navigation";
23-
import { se } from "date-fns/locale";
23+
// Removed unused import
2424
import LoadingIcon from "@/components/loading-icon";
25+
import { api } from "@/trpc/react";
2526

2627
const loginSchema = z.object({
2728
email: z.string().email(),
@@ -63,7 +64,7 @@ export function LoginForm() {
6364
async function onSubmit(input: LoginScheme) {
6465
setIsLoading(true);
6566
setError(null);
66-
const { data, error } = await signIn.email(
67+
const { error } = await signIn.email(
6768
{
6869
email: input.email,
6970
password: input.password,
@@ -99,7 +100,8 @@ export function LoginForm() {
99100
<FormControl>
100101
<Input
101102
placeholder="[email protected]"
102-
{...field}
103+
value={field.value || ""}
104+
onChange={field.onChange}
103105
/>
104106
</FormControl>
105107
<FormMessage />
@@ -116,7 +118,8 @@ export function LoginForm() {
116118
<Input
117119
type="password"
118120
placeholder="••••••••"
119-
{...field}
121+
value={field.value || ""}
122+
onChange={field.onChange}
120123
/>
121124
</FormControl>
122125
<FormMessage />

Diff for: src/app/(auth)/_components/providers.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Icons } from "@/components/icons";
33
import { Button } from "@/components/ui/button";
44
import { signIn, signUp } from "@/lib/api/auth/auth-client";
5+
import { api } from "@/trpc/react";
56

67
const ProvidersComponent = () => {
78
return (

Diff for: src/app/(dashboard)/analytics/components/title.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"use client";
2+
3+
import { useWorkspace } from "@/hooks/use-workspace";
4+
5+
export const PageTitle = () => {
6+
const { currentWorkspace } = useWorkspace();
7+
return (
8+
<h2 className="text-2xl font-bold tracking-tight">
9+
<span className="font-normal">Analytics for:</span>{" "}
10+
{currentWorkspace?.name} 📊
11+
<p className="text-sm text-muted-foreground font-thin">
12+
Get comprehensive insights into your workspace performance with
13+
real-time analytics, project progress tracking, and team productivity
14+
metrics at a glance.
15+
</p>
16+
</h2>
17+
);
18+
};

Diff for: src/app/(dashboard)/analytics/page.tsx

+3-12
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import TimeSpentChart from "./components/TimeSpentChart";
1010
import { api } from "@/trpc/server";
1111
import { TaskDistributionChart } from "./components/TaskDistributionChart";
1212
import PageContainer from "@/components/layout/page-container";
13+
import { a } from "node_modules/better-auth/dist/auth-CfxMSdnJ";
14+
import { PageTitle } from "./components/title";
1315

1416
export default async function AnalyticsPage() {
1517
const [
16-
currentWorkspace,
1718
projectCompletionData,
1819
memberProductivityData,
1920
upcomingDeadlinesData,
2021
taskPriorityData,
2122
taskDistributionData,
2223
timeSpentData,
2324
] = await Promise.all([
24-
api.workspaces.getCurrent(),
2525
api.analytics.getProjectCompletion(),
2626
api.analytics.getMemberProductivity(),
2727
api.analytics.getUpcomingDeadlines(),
@@ -34,17 +34,8 @@ export default async function AnalyticsPage() {
3434
<PageContainer>
3535
<div className="flex flex-col space-y-4">
3636
<Suspense fallback={<Skeleton className="h-8 w-[300px]" />}>
37-
<h2 className="text-2xl font-bold tracking-tight">
38-
<span className="font-normal">Analytics for:</span>{" "}
39-
{currentWorkspace?.name} 📊
40-
<p className="text-sm text-muted-foreground font-thin">
41-
Get comprehensive insights into your workspace performance with
42-
real-time analytics, project progress tracking, and team
43-
productivity metrics at a glance.
44-
</p>
45-
</h2>
37+
<PageTitle />
4638
</Suspense>
47-
4839
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
4940
<Suspense fallback={<ChartSkeleton />}>
5041
<ProjectCompletionChart data={projectCompletionData} />

Diff for: src/app/(dashboard)/projects/[projectId]/_components/members/members-table.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const MembersTable: React.FC<MembersTableProps> = ({
112112
};
113113

114114
return (
115-
<div className="space-y-4">
115+
<div className="space-y-4 mb-2">
116116
<div className="flex flex-col sm:flex-row justify-between gap-4">
117117
<div className="flex items-center gap-2 flex-1">
118118
<Search className="h-4 w-4 text-muted-foreground" />

Diff for: src/app/(dashboard)/projects/[projectId]/_components/project-settings-dialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
SelectTrigger,
3434
SelectValue,
3535
} from "@/components/ui/select";
36-
import { Loader2, Settings } from "lucide-react";
36+
import { Settings } from "lucide-react";
3737
import { api } from "@/trpc/react";
3838
import { toast } from "sonner";
3939
import DeleteEntityDialog from "@/components/delete-entity-confirmation-dialog";
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
1-
const CalendarProjectsTask = () => {
2-
return <>Calendar</>;
1+
"use client";
2+
import Calendar from "@/components/calendar/calendar";
3+
import { CalendarEvent, Mode } from "@/components/calendar/calendar-types";
4+
import { api } from "@/trpc/react";
5+
import { useParams } from "next/navigation";
6+
import { useState } from "react";
7+
import { TasksProps } from "./projects-tasks";
8+
9+
const CalendarProjectsTask = ({ tasks }: { tasks: TasksProps }) => {
10+
const { projectId } = useParams<{ projectId: string }>();
11+
12+
const [mode, setMode] = useState<Mode>("month");
13+
const [date, setDate] = useState<Date>(new Date());
14+
15+
const { data } = api.tasks.listCalendar.useQuery({
16+
projectId: projectId,
17+
mode: mode,
18+
from: date,
19+
to: date,
20+
});
21+
const [events, setEvents] = useState<CalendarEvent[]>(data || []);
22+
23+
return (
24+
<Calendar
25+
events={events}
26+
setEvents={setEvents}
27+
mode={mode}
28+
setMode={setMode}
29+
date={date}
30+
setDate={setDate}
31+
/>
32+
);
333
};
434

535
export default CalendarProjectsTask;

Diff for: src/app/(dashboard)/projects/[projectId]/_components/tasks/create-task-sheet.tsx

+22-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ import SelectMultipleMembersDropdown from "@/components/select-multiple-members-
3737
import SelectOrCreateLabel from "@/components/select-or-create-label";
3838
import SelectSingleMemberDropdown from "@/components/select-single-member-dropdown";
3939
import LoadingIcon from "@/components/loading-icon";
40+
import { CalendarDateRangePicker } from "@/components/ui/calendar-date-range-picker";
41+
import { DateRange } from "react-day-picker";
42+
import { addDays } from "date-fns";
4043

4144
interface UpdateTaskSheetProps
4245
extends React.ComponentPropsWithRef<typeof Sheet> {}
@@ -51,12 +54,20 @@ export function CreateTaskSheet({ ...props }: UpdateTaskSheetProps) {
5154
const [assignee, setAssignee] = React.useState<string | null>();
5255
const [reviewer, setReviewer] = React.useState<string>();
5356
const [labels, setLabels] = React.useState<LabelType[]>([]);
57+
const [date, setDate] = React.useState<DateRange | undefined>({
58+
from: addDays(new Date(), -30),
59+
to: new Date(),
60+
});
5461

5562
const [isUpdatePending, startUpdateTransition] = React.useTransition();
5663

5764
async function onSubmit(input: NewTask) {
5865
startUpdateTransition(async () => {
59-
const newTodo = await createTaskMutation.mutateAsync(input);
66+
const newTodo = await createTaskMutation.mutateAsync({
67+
assigneeId: assignee,
68+
reviewerId: reviewer,
69+
...input,
70+
});
6071
form.reset();
6172
props.onOpenChange?.(false);
6273
if (newTodo) {
@@ -133,13 +144,22 @@ export function CreateTaskSheet({ ...props }: UpdateTaskSheetProps) {
133144
</FormItem>
134145
)}
135146
/>
147+
<FormLabel>From - To</FormLabel>
148+
<CalendarDateRangePicker
149+
date={date}
150+
setDate={setDate}
151+
/>
136152
<SelectOrCreateLabel
137153
onLabelSelect={(labels) => setLabels(labels)}
138154
/>
139155
<SelectSingleMemberDropdown
140-
title="Select Assignee"
156+
title="Assignee"
141157
onMemberChange={(member) => setAssignee(member?.id)}
142158
/>
159+
<SelectSingleMemberDropdown
160+
title="Select Reviewer"
161+
onMemberChange={(member) => setReviewer(member?.id)}
162+
/>
143163
<SheetFooter className="gap-2 pt-2 sm:space-x-0">
144164
<SheetClose asChild>
145165
<Button

Diff for: src/app/(dashboard)/projects/[projectId]/_components/tasks/projects-tasks.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import { useState } from "react";
1010
import { addDays } from "date-fns";
1111
import { DateRange } from "react-day-picker";
1212
import { CreateTaskSheet } from "./create-task-sheet";
13+
import { RouterOutputs } from "@/trpc/react";
1314

14-
const ProjectTasks = () => {
15+
export type TasksProps = NonNullable<
16+
Awaited<RouterOutputs["projects"]["get"]>
17+
>["tasks"];
18+
19+
const ProjectTasks = ({ tasks }: { tasks: TasksProps }) => {
1520
const [date, setDate] = useState<DateRange | undefined>({
1621
from: addDays(new Date(), -30),
1722
to: new Date(),
@@ -20,14 +25,13 @@ const ProjectTasks = () => {
2025
<>
2126
<Tabs defaultValue="table">
2227
<div className="flex justify-between w-full">
23-
<TabsList className="grid grid-cols-3 w-56">
28+
<TabsList className="grid grid-cols-3 w-56">
2429
<TabsTrigger value="table">Table</TabsTrigger>
2530
<TabsTrigger value="kanban">Kanban</TabsTrigger>
2631
<TabsTrigger value="calendar">Calendar</TabsTrigger>
2732
</TabsList>
2833
<div className="flex gap-x-2">
2934
<CalendarDateRangePicker
30-
className="w-56 "
3135
date={date}
3236
setDate={setDate}
3337
/>
@@ -36,13 +40,13 @@ const ProjectTasks = () => {
3640
</div>
3741

3842
<TabsContent value="table">
39-
<TableProjectsTask />
43+
<TableProjectsTask tasks={tasks} />
4044
</TabsContent>
4145
<TabsContent value="kanban">
4246
<KanbanProjectsTask />
4347
</TabsContent>
4448
<TabsContent value="calendar">
45-
<CalendarProjectsTask />
49+
<CalendarProjectsTask tasks={tasks} />
4650
</TabsContent>
4751
</Tabs>
4852
</>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
const TableProjectsTask = () => {
2-
return <>table</>;
3-
};
1+
import { TasksProps } from "./projects-tasks";
2+
import { TaskTable } from "./table/TaskTable";
3+
import { columns } from "./table/TaskTableColumns";
44

5-
export default TableProjectsTask;
5+
export default function TasksPage({ tasks }: { tasks: TasksProps }) {
6+
return (
7+
<div className="mx-auto py-10">
8+
<TaskTable
9+
data={tasks}
10+
columns={columns}
11+
/>
12+
</div>
13+
);
14+
}

0 commit comments

Comments
 (0)