From 8032839e2933021f64a7ac0cd5a51360a337fc27 Mon Sep 17 00:00:00 2001 From: sathvika-ramagiri Date: Tue, 10 Jun 2025 13:00:07 +0530 Subject: [PATCH 1/2] Added To-Do list and removed username from sidebar ,added a user icon --- src/app/timely/_component/TimeSheet.tsx | 1502 +++++++---------------- src/app/timely/_component/TimelyApp.tsx | 243 ++-- src/server/api/routers/project.ts | 245 ++-- 3 files changed, 692 insertions(+), 1298 deletions(-) diff --git a/src/app/timely/_component/TimeSheet.tsx b/src/app/timely/_component/TimeSheet.tsx index 0994608..b14b12b 100644 --- a/src/app/timely/_component/TimeSheet.tsx +++ b/src/app/timely/_component/TimeSheet.tsx @@ -1,622 +1,10 @@ -<<<<<<< HEAD -"use client"; - -import { useEffect, useState } from "react"; -import { z } from "zod"; -import { useFieldArray, useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { api } from "@/trpc/react"; -import { Clock, Plus, Trash2, X } from "lucide-react"; - -// Define the form schema with Zod -const formSchema = z.object({ - entries: z.array( - z.object({ - projectId: z.string().optional(), - newProjectName: z.string().min(1, "Project name is required").optional(), - about: z.string().min(1, "Activity description is required"), - hoursWorked: z.coerce - .number() - .positive("Hours must be a positive number"), - remark: z.string().optional(), - }), - ), -}); - -type FormValues = z.infer; - -export default function TimesheetUI() { - const utils = api.useUtils(); - const { data: projects, isLoading: projectsLoading } = - api.project.getToday.useQuery(); - - // Sort activities by descending creation date (newest first) - const sortedProjects = projects?.map((project) => ({ - ...project, - activities: [...project.activities].sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ), - })); - - const [isAdding, setIsAdding] = useState(false); - const [isDarkMode, setIsDarkMode] = useState(false); - - const { - register, - handleSubmit, - control, - watch, - reset, - formState: { errors, isSubmitting }, - } = useForm({ - resolver: zodResolver(formSchema), - defaultValues: { - entries: [ - { - about: "", - hoursWorked: 1, - remark: "", - }, - ], - }, - }); - - useEffect(() => { - setIsDarkMode(true); - }, [isDarkMode]); - - const { fields, append, remove } = useFieldArray({ - control, - name: "entries", - }); - - const createProject = api.project.create.useMutation({ - onSuccess: async () => { - await utils.project.getAll.invalidate(); - }, - }); - - const createActivity = api.activity.create.useMutation({ - onSuccess: async () => { - await utils.project.getAll.invalidate(); - await utils.project.getToday.invalidate(); - setIsAdding(false); - }, - }); - - const deleteActivity = api.activity.delete.useMutation({ - onSuccess: async () => { - await utils.project.getAll.invalidate(); - await utils.project.getToday.invalidate(); - }, - }); - - const onSubmit = async (data: FormValues) => { - try { - for (const entry of data.entries) { - let projectId = entry.projectId; - - if (entry.projectId === "new" && entry.newProjectName) { - const newProject = await createProject.mutateAsync({ - name: entry.newProjectName, - }); - projectId = newProject.id; - } - - if (projectId) { - await createActivity.mutateAsync({ - projectId, - about: entry.about, - hoursWorked: entry.hoursWorked, - remark: entry.remark ?? undefined, - }); - } - } - - await utils.project.getToday.invalidate(); - const refreshedData = await utils.project.getToday.fetch(); - reset(); - } catch (error) { - console.error("Error submitting form:", error); - } - }; - - const addNewRow = () => { - append({ - about: "", - hoursWorked: 1, - remark: "", - }); - }; - - const handleDelete = async (activityId: string) => { - if (confirm("Are you sure you want to delete this activity?")) { - await deleteActivity.mutateAsync({ id: activityId }); - } - }; - - const formatDate = (date: Date) => { - return new Date(date).toLocaleDateString("en-US", { - year: "numeric", - month: "short", - day: "numeric", - }); - }; - - return ( -
- {/* Header */} -
-
-

- Track and manage your daily activities -

-
- -
- - {/* Add Entry Form */} - {isAdding && ( -
-

- New Time Entry -

-
-
- {fields.map((field, index) => { - const isCreatingNewProject = - watch(`entries.${index}.projectId`) === "new"; - return ( -
-
- {/* Project */} -
- - - {isCreatingNewProject && ( -
- - {errors.entries?.[index]?.newProjectName && ( -

- {errors.entries[index]?.newProjectName?.message} -

- )} -
- )} - {errors.entries?.[index]?.projectId && ( -

- {errors.entries[index]?.projectId?.message} -

- )} -
- - {/* Activity */} -
- - - {errors.entries?.[index]?.about && ( -

- {errors.entries[index]?.about?.message} -

- )} -
- - {/* Hours */} -
- - - {errors.entries?.[index]?.hoursWorked && ( -

- {errors.entries[index]?.hoursWorked?.message} -

- )} -
- - {/* Remarks */} -
-
- - -
- -
-
-
- ); - })} -
- -
- - -
-
-
- )} - - {/* Timesheet Records */} -
-
-

- Today's Activities -

- - {projectsLoading ? ( -
-
- Loading your timesheet data... -
-
- ) : !sortedProjects || sortedProjects.length === 0 ? ( -
-
-

No activities recorded today

-

- Add your first time entry to get started -

-
-
- ) : ( -
- - - - - - - - - - - - - {sortedProjects.flatMap((project) => - project.activities.map((activity) => ( - - - - - - - - - )), - )} - -
- Project - - Activity - - Hours - - Time - - Notes - - Actions -
-
- {project.name} -
-
-
- {activity.about} -
-
-
- {activity.hoursWorked}h -
-
-
- {new Date(activity.createdAt).toLocaleTimeString( - [], - { - hour: "2-digit", - minute: "2-digit", - }, - )} -
-
-
- {activity.remark ?? "—"} -
-
- -
-
- )} -
- - {/* Summary Section */} - {sortedProjects && sortedProjects.length > 0 && ( -
-

- Daily Summary -

-
-
-

- Projects Worked On -

-

- {projects?.length ?? 0} -

-
-
-

- Total Activities -

-

- {sortedProjects.reduce( - (acc, project) => acc + project.activities.length, - 0, - )} -

-
-
-

- Total Hours -

-

- {sortedProjects - .reduce( - (acc, project) => - acc + - project.activities.reduce( - (sum, activity) => sum + activity.hoursWorked, - 0, - ), - 0, - ) - .toFixed(2)} - h -

-
-
-
- )} -
-
-); -} -======= "use client"; - -import { api } from "@/trpc/react"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { Plus, Trash2, X } from "lucide-react"; import { useEffect, useState } from "react"; -import { useFieldArray, useForm } from "react-hook-form"; import { z } from "zod"; +import { useFieldArray, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { api } from "@/trpc/react"; +import { Clock, Plus, Trash2, X } from "lucide-react"; // Define the form schema with Zod const formSchema = z.object({ @@ -754,507 +142,467 @@ export default function TimesheetUI() { }); }; - return ( -
- {/* Header */} -
-
-

- Time Logger -

-

- Track and manage your daily activities -

-
- + return ( +
+ {/* Header */} +
+
+

+ Track and manage your daily activities +

+ +
- {/* Add Entry Form */} - {isAdding && ( -
-

- New Time Entry -

-
-
- {fields.map((field, index) => { - const isCreatingNewProject = - watch(`entries.${index}.projectId`) === "new"; - return ( -
-
- {/* Project */} -
- - - {isCreatingNewProject && ( -
- - {errors.entries?.[index]?.newProjectName && ( -

- {errors.entries[index]?.newProjectName?.message} -

- )} -
- )} - {errors.entries?.[index]?.projectId && ( -

- {errors.entries[index]?.projectId?.message} -

- )} -
+ {/* Add Entry Form */} + {isAdding && ( +
+

+ New Time Entry +

+ +
+ {fields.map((field, index) => { + const isCreatingNewProject = + watch(`entries.${index}.projectId`) === "new"; + return ( +
+
+ {/* Project */} +
+ + + {isCreatingNewProject && ( +
+ + {errors.entries?.[index]?.newProjectName && ( +

+ {errors.entries[index]?.newProjectName?.message} +

+ )} +
+ )} + {errors.entries?.[index]?.projectId && ( +

+ {errors.entries[index]?.projectId?.message} +

+ )} +
- {/* Activity */} -
- - - {errors.entries?.[index]?.about && ( -

- {errors.entries[index]?.about?.message} -

- )} -
+ {/* Activity */} +
+ + + {errors.entries?.[index]?.about && ( +

+ {errors.entries[index]?.about?.message} +

+ )} +
- {/* Hours */} -
+ {/* Hours */} +
+ + + {errors.entries?.[index]?.hoursWorked && ( +

+ {errors.entries[index]?.hoursWorked?.message} +

+ )} +
+ + {/* Remarks */} +
+
- {errors.entries?.[index]?.hoursWorked && ( -

- {errors.entries[index]?.hoursWorked?.message} -

- )}
+ +
+
+
+ ); + })} +
- {/* Remarks */} -
-
- - +
+ + +
+ +
+ )} + + {/* Timesheet Records */} +
+
+

+ Today's Activities +

+ + {projectsLoading ? ( +
+
+ Loading your timesheet data... +
+
+ ) : !sortedProjects || sortedProjects.length === 0 ? ( +
+
+

No activities recorded today

+

+ Add your first time entry to get started +

+
+
+ ) : ( +
+ + + + + + + + + + + + + {sortedProjects.flatMap((project) => + project.activities.map((activity) => ( + + + + + + + + + )), + )} + +
+ Project + + Activity + + Hours + + Time + + Notes + + Actions +
+
+ {project.name} +
+
+
+ {activity.about} +
+
+
+ {activity.hoursWorked}h +
+
+
+ {new Date(activity.createdAt).toLocaleTimeString( + [], + { + hour: "2-digit", + minute: "2-digit", + }, + )}
+
+
+ {activity.remark ?? "—"} +
+
- - - - ); - })} - +
+
+ )} +
-
- - -
- -
- )} - - {/* Timesheet Records */} -
-
-

- Today's Activities -

- - {projectsLoading ? ( -
-
+

- Loading your timesheet data... -

+ {projects?.length ?? 0} +

- ) : !sortedProjects || sortedProjects.length === 0 ? (
-
-

No activities recorded today

-

- Add your first time entry to get started -

-
-
- ) : ( -
- - - - - - - - - - - - - {sortedProjects.flatMap((project) => - project.activities.map((activity) => ( - - - - - - - - - )), - )} - -
- Project - - Activity - - Hours - - Time - - Notes - - Actions -
-
- {project.name} -
-
-
- {activity.about} -
-
-
- {activity.hoursWorked}h -
-
-
- {new Date(activity.createdAt).toLocaleTimeString( - [], - { - hour: "2-digit", - minute: "2-digit", - }, - )} -
-
-
- {activity.remark ?? "—"} -
-
- -
-
- )} -
- - {/* Summary Section */} - {sortedProjects && sortedProjects.length > 0 && ( -
-

- Daily Summary -

-
-
+

-

- Projects Worked On -

-

- {projects?.length ?? 0} -

-
-
acc + project.activities.length, + 0, + )} +

+
+
+

-

- Total Activities -

-

- {sortedProjects.reduce( - (acc, project) => acc + project.activities.length, - 0, - )} -

-
-
+

-

- Total Hours -

-

- {sortedProjects - .reduce( - (acc, project) => - acc + - project.activities.reduce( - (sum, activity) => sum + activity.hoursWorked, - 0, - ), - 0, - ) - .toFixed(2)} - h -

-
+ {sortedProjects + .reduce( + (acc, project) => + acc + + project.activities.reduce( + (sum, activity) => sum + activity.hoursWorked, + 0, + ), + 0, + ) + .toFixed(2)} + h +

- )} -
+
+ )}
- ); +
+); } ->>>>>>> upstream/main diff --git a/src/app/timely/_component/TimelyApp.tsx b/src/app/timely/_component/TimelyApp.tsx index 74d639e..38cd101 100644 --- a/src/app/timely/_component/TimelyApp.tsx +++ b/src/app/timely/_component/TimelyApp.tsx @@ -1,19 +1,19 @@ "use client"; -import { useMemo } from "react"; -import { Calendar, Clock, LogOut, PieChart, Moon, Sun } from "lucide-react"; import { useState } from "react"; +import { Calendar, LogOut, PieChart, Moon, Sun, Bell, Settings, CheckSquare } from "lucide-react"; import TimesheetUI from "./TimeSheet"; -import { Bell, Settings } from "lucide-react"; -import CalendarComponent from 'react-calendar'; +import CalendarComponent from "react-calendar"; type AppProps = { developer?: { name: string | null; email: string | null }; }; -// Main Timely App with enhanced premium layout export default function TimelyApp({ developer }: AppProps) { - const [activeView, setActiveView] = useState("daily"); // Options: "daily" or "weekly" + const [activeView, setActiveView] = useState("daily"); const [isDarkMode, setIsDarkMode] = useState(true); + const [calendarDate, setCalendarDate] = useState(new Date()); + const [tasks, setTasks] = useState<{ id: number; text: string; completed: boolean }[]>([]); + const [newTask, setNewTask] = useState(""); // Get current date information const currentDate = new Date(); @@ -23,6 +23,24 @@ export default function TimelyApp({ developer }: AppProps) { month: "long", day: "numeric", }); + const addTask = () => { + if (newTask.trim()) { + setTasks([...tasks, { id: Date.now(), text: newTask, completed: false }]); + setNewTask(""); + } + }; + + const deleteTask = (id: number) => { + setTasks(tasks.filter((task) => task.id !== id)); + }; + + const toggleTaskCompletion = (id: number) => { + setTasks( + tasks.map((task) => + task.id === id ? { ...task, completed: !task.completed } : task + ) + ); + }; return (
- - - - + + + +

@@ -80,41 +98,14 @@ export default function TimelyApp({ developer }: AppProps) { Calendar -

- - {/* User Profile & Logout */} -
-
-
- {developer?.name?.slice(0, 2).toUpperCase() || "NA"} -
-
-
{developer?.name || "User"}
-
- {developer?.email || "user@example.com"} -
-
-
- setActiveView("todo")} > - - Logout - -
+ + To-Do + +
@@ -146,7 +137,7 @@ export default function TimelyApp({ developer }: AppProps) { )} - {/* User Avatar with dropdown */} + {/* User Avatar with dropdown */}
+

@@ -174,46 +166,108 @@ export default function TimelyApp({ developer }: AppProps) {

- + {/* To-Do List */} + {activeView === "todo" && ( +
+

To-Do List

+
+ setNewTask(e.target.value)} + placeholder="Enter a new task" + className="flex-grow p-2 rounded-lg border border-gray-300 dark:border-gray-600 dark:bg-gray-800" + /> +
+
    + {tasks.map((task) => ( +
  • + + {task.text} + +
    + + +
    +
  • + ))} +
+
+ )} {/* Main Content Switch */} - {activeView === "calendar" ? ( -
-<} - nextLabel={>} - navigationLabel={({ label }) => ( - {label} - )} - formatShortWeekday={(locale, date) => - date.toLocaleDateString(locale, { weekday: 'short' }).toUpperCase() - } - tileClassName={({ date, view }) => { - if (view === "month") { - const isSunday = date.getDay() === 0; - const isToday = - date.getDate() === new Date().getDate() && - date.getMonth() === new Date().getMonth() && - date.getFullYear() === new Date().getFullYear(); - return [ - "text-base text-center", - isSunday ? "text-red-500 font-bold" : isDarkMode ? "text-gray-100" : "text-gray-700", - isToday ? "bg-indigo-600 text-white rounded-full font-bold" : "", - ].join(" "); - } - return ""; - }} - tileContent={({ date, view }) => null} -/> -
+ {activeView === "calendar" ? ( +
+
+ {calendarDate.toLocaleString("default", { month: "long" })} {calendarDate.getFullYear()} +
+ setCalendarDate(activeStartDate!)} + showNeighboringMonth={false} + prevLabel={<} + nextLabel={>} + navigationLabel={null} + formatShortWeekday={(locale, date) => + date.toLocaleDateString(locale, { weekday: 'short' }).charAt(0) + } + tileClassName={({ date, view }) => { + if (view === "month") { + const isSunday = date.getDay() === 0; + const isToday = + date.getDate() === new Date().getDate() && + date.getMonth() === new Date().getMonth() && + date.getFullYear() === new Date().getFullYear(); + return [ + "text-base text-center", + isSunday ? "text-red-500 font-bold" : isDarkMode ? "text-gray-100" : "text-gray-700", + isToday ? "bg-indigo-600 text-white rounded-full font-bold" : "", + ].join(" "); + } + return ""; + }} + tileContent={({ date, view }) => null} + /> +
) : activeView === "daily" ? (
- ) : ( + ) : activeView === "weekly" ? (
-

- Weekly Activity Summary -

+

Weekly Activity Summary

- {/* Placeholder for weekly view */}
-

- Weekly Reports Coming Soon -

+

Weekly Reports Coming Soon

- We're working on bringing you detailed weekly summaries - and charts. Stay tuned for this exciting new feature! + We're working on bringing you detailed weekly summaries and charts. Stay tuned for this exciting new feature!

- +
- )} - + ) : null} ); diff --git a/src/server/api/routers/project.ts b/src/server/api/routers/project.ts index ecb3418..4e2ad9b 100644 --- a/src/server/api/routers/project.ts +++ b/src/server/api/routers/project.ts @@ -1,122 +1,123 @@ -import { z } from "zod"; - -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; - -export const projectRouter = createTRPCRouter({ - create: protectedProcedure - .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ ctx, input }) => { - return ctx.db.project.create({ - data: { - name: input.name, - createdBy: { connect: { id: ctx.session.user.id } }, - }, - }); - }), - - getAll: protectedProcedure.query(async ({ ctx }) => { - // Get all projects, but include activities only if they belong to the current user - const projects = await ctx.db.project.findMany({ - orderBy: { createdAt: "desc" }, - include: { - activities: { - where: { - performedById: ctx.session.user.id, - }, - }, - }, - }); - - return projects; - }), - - getToday: protectedProcedure.query(async ({ ctx }) => { - // Create date objects for the start and end of today - const today = new Date(); - const startOfDay = new Date(today.setHours(0, 0, 0, 0)); - const endOfDay = new Date(today.setHours(23, 59, 59, 999)); - - // Get all projects, but include activities only if they belong to the current user and were created today - const projects = await ctx.db.project.findMany({ - orderBy: { createdAt: "desc" }, - include: { - activities: { - where: { - performedById: ctx.session.user.id, - createdAt: { - gte: startOfDay, - lte: endOfDay, - }, - }, - }, - }, - }); - - return projects; - }), - getById: protectedProcedure - .input(z.object({ id: z.string() })) - .query(async ({ ctx, input }) => { - return ctx.db.project.findUnique({ - where: { id: input.id }, - include: { activities: true }, - }); - }), - - update: protectedProcedure - .input( - z.object({ - id: z.string(), - name: z.string().min(1), - }), - ) - .mutation(async ({ ctx, input }) => { - try { - // Ensure the user owns this project - const project = await ctx.db.project.findUnique({ - where: { id: input.id }, - select: { createdById: true }, - }); - - if (!project || project.createdById !== ctx.session.user.id) { - throw new Error("Not authorized to update this project"); - } - - return ctx.db.project.update({ - where: { id: input.id }, - data: { name: input.name }, - }); - } catch (error) { - console.error("Error updating project:", error); - throw new Error("Failed to update project"); - } - }), - - delete: protectedProcedure - .input(z.object({ id: z.string() })) - .mutation(async ({ ctx, input }) => { - try { - // Ensure the user owns this project - const project = await ctx.db.project.findUnique({ - where: { id: input.id }, - select: { createdById: true }, - }); - - if (!project || project.createdById !== ctx.session.user.id) { - throw new Error("Not authorized to delete this project"); - } - - // Delete all associated activities first (if cascade delete is not set up) - await ctx.db.activity.deleteMany({ - where: { projectId: input.id }, - }); - - return ctx.db.project.delete({ - where: { id: input.id }, - }); - } catch (error) { - console.error("Error deleting project:", error); - throw new Error("Failed to delete project"); - } - }), -}); +import { z } from "zod"; + +import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; + +export const projectRouter = createTRPCRouter({ + create: protectedProcedure + .input(z.object({ name: z.string().min(1) })) + .mutation(async ({ ctx, input }) => { + return ctx.db.project.create({ + data: { + name: input.name, + createdBy: { connect: { id: ctx.session.user.id } }, + }, + }); + }), + + + getAll: protectedProcedure.query(async ({ ctx }) => { + // Get all projects, but include activities only if they belong to the current user + const projects = await ctx.db.project.findMany({ + orderBy: { createdAt: "desc" }, + include: { + activities: { + where: { + performedById: ctx.session.user.id, + }, + }, + }, + }); + + return projects; + }), + + getToday: protectedProcedure.query(async ({ ctx }) => { + // Create date objects for the start and end of today + const today = new Date(); + const startOfDay = new Date(today.setHours(0, 0, 0, 0)); + const endOfDay = new Date(today.setHours(23, 59, 59, 999)); + + // Get all projects, but include activities only if they belong to the current user and were created today + const projects = await ctx.db.project.findMany({ + orderBy: { createdAt: "desc" }, + include: { + activities: { + where: { + performedById: ctx.session.user.id, + createdAt: { + gte: startOfDay, + lte: endOfDay, + }, + }, + }, + }, + }); + + return projects; + }), + getById: protectedProcedure + .input(z.object({ id: z.string() })) + .query(async ({ ctx, input }) => { + return ctx.db.project.findUnique({ + where: { id: input.id }, + include: { activities: true }, + }); + }), + + update: protectedProcedure + .input( + z.object({ + id: z.string(), + name: z.string().min(1), + }), + ) + .mutation(async ({ ctx, input }) => { + try { + // Ensure the user owns this project + const project = await ctx.db.project.findUnique({ + where: { id: input.id }, + select: { createdById: true }, + }); + + if (!project || project.createdById !== ctx.session.user.id) { + throw new Error("Not authorized to update this project"); + } + + return ctx.db.project.update({ + where: { id: input.id }, + data: { name: input.name }, + }); + } catch (error) { + console.error("Error updating project:", error); + throw new Error("Failed to update project"); + } + }), + + delete: protectedProcedure + .input(z.object({ id: z.string() })) + .mutation(async ({ ctx, input }) => { + try { + // Ensure the user owns this project + const project = await ctx.db.project.findUnique({ + where: { id: input.id }, + select: { createdById: true }, + }); + + if (!project || project.createdById !== ctx.session.user.id) { + throw new Error("Not authorized to delete this project"); + } + + // Delete all associated activities first (if cascade delete is not set up) + await ctx.db.activity.deleteMany({ + where: { projectId: input.id }, + }); + + return ctx.db.project.delete({ + where: { id: input.id }, + }); + } catch (error) { + console.error("Error deleting project:", error); + throw new Error("Failed to delete project"); + } + }), +}); From f4d25b813754ab821fef74f8b41d5268c92640e3 Mon Sep 17 00:00:00 2001 From: sathvika-ramagiri Date: Fri, 13 Jun 2025 19:47:34 +0530 Subject: [PATCH 2/2] Added a Note feature --- src/app/timely/_component/TimelyApp.tsx | 203 +++++++++++++++++------- src/styles/globals.css | 37 ++++- 2 files changed, 179 insertions(+), 61 deletions(-) diff --git a/src/app/timely/_component/TimelyApp.tsx b/src/app/timely/_component/TimelyApp.tsx index 38cd101..a39746b 100644 --- a/src/app/timely/_component/TimelyApp.tsx +++ b/src/app/timely/_component/TimelyApp.tsx @@ -1,6 +1,6 @@ "use client"; import { useState } from "react"; -import { Calendar, LogOut, PieChart, Moon, Sun, Bell, Settings, CheckSquare } from "lucide-react"; +import { Calendar, LogOut, PieChart, Moon, Sun, Bell, Settings, FileText, CheckSquare } from "lucide-react"; import TimesheetUI from "./TimeSheet"; import CalendarComponent from "react-calendar"; @@ -14,7 +14,27 @@ export default function TimelyApp({ developer }: AppProps) { const [calendarDate, setCalendarDate] = useState(new Date()); const [tasks, setTasks] = useState<{ id: number; text: string; completed: boolean }[]>([]); const [newTask, setNewTask] = useState(""); + const [notes, setNotes] = useState<{ id: number; title: string; content: string; timestamp: string }[]>([]); + const [newNoteTitle, setNewNoteTitle] = useState(""); + const [newNoteContent, setNewNoteContent] = useState(""); + // Add Note + const addNote = () => { + if (newNoteTitle.trim() && newNoteContent.trim()) { + const timestamp = new Date().toLocaleString(); + setNotes([ + ...notes, + { id: Date.now(), title: newNoteTitle, content: newNoteContent, timestamp }, + ]); + setNewNoteTitle(""); + setNewNoteContent(""); + } + }; + + // Delete Note + const deleteNote = (id: number) => { + setNotes(notes.filter((note) => note.id !== id)); + }; // Get current date information const currentDate = new Date(); const formattedDate = currentDate.toLocaleDateString("en-US", { @@ -105,6 +125,13 @@ export default function TimelyApp({ developer }: AppProps) { To-Do + @@ -167,65 +194,125 @@ export default function TimelyApp({ developer }: AppProps) { {/* To-Do List */} - {activeView === "todo" && ( -
+

To-Do List

+
+ setNewTask(e.target.value)} + placeholder="Enter a new task" + className="todo-input" + /> + +
+
    + {tasks.map((task) => ( +
  • + + {task.text} + +
    +
    -
      - {tasks.map((task) => ( -
    • - - {task.text} - -
      - - -
      -
    • - ))} -
    -
- )} + {task.completed ? "Undo" : "Complete"} + + + + + ))} + + +)} + +{/* Notes Feature */} +{activeView === "notes" && ( +
+

Notes

+
+ setNewNoteTitle(e.target.value)} + placeholder="Enter note title" + className="notes-input" +/> +