Skip to content

Task Management System#12

Open
FlorRoth wants to merge 35 commits into
microboxlabs:trunkfrom
FlorRoth:dev
Open

Task Management System#12
FlorRoth wants to merge 35 commits into
microboxlabs:trunkfrom
FlorRoth:dev

Conversation

@FlorRoth

@FlorRoth FlorRoth commented Dec 17, 2024

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Introduced API routes for managing groups, user-group associations, user authentication, tasks, and comments.
    • Added components for task management, including task cards, modals for creation and deletion, and a sidebar for filtering tasks.
    • Implemented a notification system for user feedback on actions.
    • Created custom hooks for form handling and pagination management.
  • Bug Fixes

    • Improved error handling across various API endpoints and components.
  • Documentation

    • Updated metadata and component documentation for clarity.
  • Chores

    • Added new dependencies for enhanced functionality, including Axios, bcrypt, and jsonwebtoken.

@coderabbitai

coderabbitai Bot commented Dec 17, 2024

Copy link
Copy Markdown

Walkthrough

This pull request introduces a comprehensive task management system built with Next.js, featuring robust API routes, authentication, and context-based state management. The system includes endpoints for managing tasks, users, groups, and comments, with a focus on secure authentication, error handling, and modular component design. The implementation leverages modern React practices, including context providers, custom hooks, and server-side rendering capabilities.

Changes

File/Path Change Summary
app/api/... Added multiple API routes for tasks, users, groups, login, and comments with comprehensive CRUD operations and error handling
app/components/... Introduced UI components like CardTasks, Form, Modal, NavBar, and Pagination for interactive task management
app/contexts/... Created context providers for authentication, tasks, and user management
app/providers/... Implemented provider components with state management using useReducer
app/reducers/... Developed reducers for managing authentication, task, and user states
app/hooks/... Added custom hooks for form handling and pagination
package.json Added dependencies for Axios, bcrypt, and JWT

Sequence Diagram

sequenceDiagram
    participant User
    participant LoginPage
    participant AuthProvider
    participant API
    participant Database

    User->>LoginPage: Enter credentials
    LoginPage->>AuthProvider: Trigger login
    AuthProvider->>API: Send login request
    API->>Database: Verify credentials
    Database-->>API: Return user data
    API-->>AuthProvider: Return token and user info
    AuthProvider->>User: Authenticate and redirect
Loading

Poem

🐰 Hop, hop, hooray! A task system's here to play,
With routes that dance and contexts bright,
Reducers spinning data just right.
From login's leap to task's delight,
Our code hops on with pure might! 🚀

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 62

🧹 Nitpick comments (34)
nextjs-task-system/app/api/tasks/route.js (5)

5-5: Include 'Content-Type' Header in GET Response

To ensure the client correctly interprets the response as JSON, include the Content-Type: application/json header in the GET response.

Apply this diff to add the header:

-  return new Response(JSON.stringify(tasks), { status: 200 });
+  return new Response(JSON.stringify(tasks), {
+    status: 200,
+    headers: { 'Content-Type': 'application/json' },
+  });

15-15: Include 'Content-Type' Header in POST Response

Similarly, include the Content-Type: application/json header in the POST response to specify the content type.

Apply this diff:

-        return new Response(JSON.stringify({ id: result.lastInsertRowid }), { status: 201 });
+        return new Response(JSON.stringify({ id: result.lastInsertRowid }), {
+          status: 201,
+          headers: { 'Content-Type': 'application/json' },
+        });

17-18: Include 'Content-Type' Header in Error Responses

Ensure that error responses include the Content-Type: application/json header for consistency across all endpoints.

Apply this diff to both POST and PUT error responses:

-        return new Response(JSON.stringify({ error: error.message }), { status: 400 });
+        return new Response(JSON.stringify({ error: error.message }), {
+          status: 400,
+          headers: { 'Content-Type': 'application/json' },
+        });

Also applies to: 31-32


29-29: Use Appropriate Status Code for PUT Response

The PUT method responds with a status code of 201, which is typically used for resource creation. Since this endpoint updates an existing resource, consider using status code 200 for a successful update.

Apply this diff to adjust the status code:

-    return new Response(JSON.stringify({ id }), { status: 201 });
+    return new Response(JSON.stringify({ id }), {
+      status: 200,
+      headers: { 'Content-Type': 'application/json' },
+    });

37-38: Use Path Parameters Instead of Query Parameters for DELETE

Using query parameters to identify resources in DELETE requests is unconventional. Consider using path parameters to specify the task ID, which aligns with RESTful API best practices.

Apply this diff to modify the DELETE method:

-  const { searchParams } = new URL(request.url); 
-  const id = searchParams.get('id'); 
+  const { pathname } = new URL(request.url);
+  const id = pathname.split('/').pop();

Update the route definition to include the ID parameter, and adjust the client-side code to send requests to /api/tasks/{id}.

nextjs-task-system/app/providers/taskProvider.tsx (2)

127-127: Improve Type Safety by Defining Interfaces

The functions accept parameters typed as any, which undermines TypeScript's type safety. Define interfaces for task and comment data to enhance type checking and code maintainability.

Example:

interface TaskData {
  id?: number;
  title: string;
  description?: string;
  assigned_to?: string;
  assigned_to_id?: number;
  assigned_to_type?: string;
  due_date?: string;
  priority?: string;
  status?: string;
  statusNew?: string;
}

interface CommentData {
  task_id: number;
  user_id: number;
  comment: string;
}

Then update the function signatures:

- const addCommentTask = async (data: any) => {
+ const addCommentTask = async (data: CommentData) => {

- const createTask = async (data: any) => {
+ const createTask = async (data: TaskData) => {

- const updateTask = async (data: any) => {
+ const updateTask = async (data: TaskData) => {

- const deleteTask = async (id: number) => {
+ const deleteTask = async (id: number): Promise<void> => {

Also applies to: 159-159, 197-197, 236-236


184-186: Handle Errors More Graciously

Logging errors using console.log(error) can expose sensitive information in production environments. Consider using a logging library or handling errors to provide user-friendly messages without revealing internal details.

nextjs-task-system/app/components/card.tsx (2)

31-31: Avoid Using 'any' Type for State Variables

Using any for state variables can lead to type safety issues. Define proper types or interfaces for state variables like selectedTask, deletedTask, and editTask to leverage TypeScript's benefits.

Example:

interface Task {
  id: number;
  title: string;
  description?: string;
  // ...other properties
}

const [selectedTask, setSelectedTask] = useState<Task | null>(null);

229-246: Handle Empty User and Group Lists Gracefully

If there are no users or groups available, the "Assign Task" dropdown might be empty or cause errors. Ensure the UI handles these cases gracefully and informs the user appropriately.

nextjs-task-system/app/components/footer.tsx (1)

10-10: Consider using dynamic year calculation.

Instead of hardcoding the year, consider using new Date().getFullYear() for automatic updates.

-        <Footer.Copyright href="#" by="Task Management System™" year={2024} />
+        <Footer.Copyright href="#" by="Task Management System™" year={new Date().getFullYear()} />
nextjs-task-system/app/page.tsx (1)

3-3: Add TypeScript return type.

Explicitly define the return type for better type safety.

-export default function Home() {
+export default function Home(): JSX.Element {
nextjs-task-system/app/components/pagination.tsx (1)

5-11: Consider performance optimizations and improved type safety.

While the implementation is clean, consider these improvements:

  1. Memoize the component to prevent unnecessary re-renders
  2. Add validation for edge cases
  3. Use a separate type definition for props
+interface PaginationTaskProps {
+  currentPage: number;
+  totalPages: number;
+  onPageChange: (page: number) => void;
+}
+
-export function PaginationTask({ currentPage, totalPages, onPageChange }: { currentPage: number; totalPages: number; onPageChange: (page: number) => void }) {
+export const PaginationTask = React.memo(function PaginationTask({ 
+  currentPage, 
+  totalPages, 
+  onPageChange 
+}: PaginationTaskProps) {
+  if (totalPages < 1) return null;
+  
   return (
     <div className="flex overflow-x-auto sm:justify-center">
       <Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={onPageChange} />
     </div>
   );
-}
+});
+
+PaginationTask.displayName = 'PaginationTask';

Don't forget to add the React import:

+"use client";
+
+import React from 'react';
 import { Pagination } from "flowbite-react";
nextjs-task-system/app/hooks/useForm.ts (1)

19-24: Potential naming conflicts in return value

Spreading formState directly in the return object could cause naming conflicts with the other properties.

 return {
-    ...formState,
     formState,
     setFormState,
     onChangeInput,
 }
nextjs-task-system/app/api/groups/route.js (1)

1-17: Consider externalizing SQL queries

Move SQL queries to a separate constants file for better maintainability.

 import db from "../../db/database.js";
+import { SQL_QUERIES } from '../../constants/queries';
 
 export async function POST(request) {
   // ... input validation ...
   try {
-      const result =  db.prepare('INSERT INTO groups (name) VALUES (?)').run(name);
+      const result = db.prepare(SQL_QUERIES.INSERT_GROUP).run(name);
       return new Response(JSON.stringify({ id: result.lastInsertRowid }), { status: 201 });
   }
   // ... error handling ...
 }
 
 export async function GET() {
-  const groups = db.prepare('SELECT * FROM groups').all();
+  const groups = db.prepare(SQL_QUERIES.SELECT_ALL_GROUPS).all();
   return new Response(JSON.stringify(groups), { status: 200 });
 }
nextjs-task-system/app/hooks/usePaginate.ts (3)

1-1: Remove unused import

The useEffect import is not being used in this file.

-import { useEffect, useState } from 'react'
+import { useState } from 'react'

9-26: Optimize state updates to prevent potential race conditions

The current implementation updates multiple states separately, which could lead to race conditions. Consider using a single state update:

+interface PaginationData {
+  offset: number;
+  page: number;
+}

+const [paginationData, setPaginationData] = useState<PaginationData>({
+  offset: initialOffset,
+  page: initialPage
+});

 const onNext = () => {
-  setOffset(prev => prev + limit);
-  setPage(page + 1);
+  setPaginationData(prev => ({
+    offset: prev.offset + limit,
+    page: prev.page + 1
+  }));
 }

 const onPrev = () => {
-  setOffset(prev => {
-    if(prev <= initialOffset){
-      setPage(initialPage)
-      return initialOffset;
-    } else {
-      setPage(page-1);
-      return prev - limit;
-    }
+  setPaginationData(prev => {
+    if (prev.offset <= initialOffset) {
+      return {
+        offset: initialOffset,
+        page: initialPage
+      };
+    }
+    return {
+      offset: prev.offset - limit,
+      page: prev.page - 1
+    };
   });
 }

29-36: Add memoization for returned object

The returned object is recreated on every render. Consider using useMemo:

+import { useMemo } from 'react';

-return {
+return useMemo(() => ({
   offset,
   page,
   onNext,
   onPrev,
   setPage
-}
+}), [offset, page, onNext, onPrev, setPage]);
nextjs-task-system/app/layout.tsx (1)

27-36: Consider documenting provider dependencies.

The provider nesting order (Auth -> Task -> User) appears logical, but it would be helpful to document any dependencies between these providers to assist future maintenance.

Consider adding a comment explaining the provider hierarchy:

      <body className={inter.className}>
+       {/* Providers are nested in order of dependencies:
+        * 1. AuthProvider: Manages authentication state
+        * 2. TaskProvider: Depends on auth context for user-specific tasks
+        * 3. UserProvider: Depends on auth context for user data
+        */}
        <AuthProvider>
nextjs-task-system/app/api/tasks/user/route.js (1)

28-30: Improve error handling with specific error types.

The current error handling doesn't differentiate between different types of errors.

     } catch (error) {
+      const status = error.code === 'SQLITE_CONSTRAINT' ? 400 : 500;
+      const message = status === 400 ? 'Invalid request' : 'Internal server error';
-      return new Response(JSON.stringify({ error: error.message }), { status: 500 });
+      return new Response(JSON.stringify({ error: message }), { status });
     }
nextjs-task-system/app/api/users/route.js (1)

18-20: Use parameterized queries consistently.

While the current query uses parameterized inputs, it's good practice to document this security measure.

Add a comment explaining the security measure:

     const hashedPass = await bcrypt.hash(pass, 10);
+    // Using parameterized query to prevent SQL injection
     const result = db.prepare(
       'INSERT INTO users (username, email, pass, rol) VALUES (?, ?, ?, ?)'
     ).run(username, email, hashedPass, rol || 'regular');
nextjs-task-system/app/components/toast.tsx (1)

6-6: Consider using proper TypeScript interface for props

Define a dedicated interface for the component props to improve type safety and documentation.

+interface NotificationProps {
+  text: string;
+  successfullyAction: boolean;
+}
-export function Notification({ text, successfullyAction }: { text: string; successfullyAction: boolean }) {
+export function Notification({ text, successfullyAction }: NotificationProps) {
nextjs-task-system/app/login/layout.tsx (1)

33-37: Enhance loading state feedback

The loading spinner could provide more context to improve user experience.

-return <div className="text-center">
+return <div className="flex flex-col items-center justify-center min-h-screen">
+  <div className="text-center space-y-4">
     <Spinner aria-label="Center-aligned spinner example" />
+    <p className="text-gray-600">Verifying your session...</p>
+  </div>
 </div>;
nextjs-task-system/app/dashboard/layout.tsx (1)

35-39: Enhance loading state presentation.

The loading spinner should be centered both vertically and horizontally on the page, and potentially include a loading message for better user experience.

-    return <div className="text-center">
+    return <div className="flex items-center justify-center min-h-screen">
       <Spinner aria-label="Center-aligned spinner example" />
+      <span className="ml-2">Loading dashboard...</span>
     </div>;
nextjs-task-system/app/dashboard/tasks/page.tsx (1)

29-45: Improve layout structure and accessibility

The layout structure could be improved for better maintainability and accessibility.

-<div className="flex flex-col md:flex-row">
+<div className="flex flex-col md:flex-row" role="main">
   <aside className="w-full md:max-w-xs md:w-auto">
     <Dashboard handleFilterChange={handleFilterChange} />
   </aside>
-  <div className="flex-1 p-4">
+  <section className="flex-1 p-4" aria-label="Task Management">
     <div className="flex justify-end w-100">
       {hasAdminAccess(state.user?.rol) && (
         <Button 
           onClick={() => setOpenModal(true)}
           aria-label="Create New Task"
         >
           Create Task
         </Button>
       )}
     </div>
     <ModalForm openModal={openModal} setOpenModal={setOpenModal} task={null} />
-    <div className="">
+    <div className="task-list-container">
       <CardTasks filters={filters}/>
     </div>
-  </div>
+  </section>
 </div>
nextjs-task-system/app/components/navBar.tsx (1)

24-45: Add loading state and improve accessibility

The user dropdown should handle loading states and be more accessible.

-{state.user &&
+{state.user ? (
   <Dropdown
     arrowIcon={false}
     inline
+    aria-label="User menu"
     label={
       <div className="shadow-lg border-2 border-grey-darker border-solid rounded-full">
-        <Avatar rounded />
+        <Avatar 
+          rounded
+          alt={`${state.user.username}'s avatar`}
+        />
       </div>
     }
   >
     <Dropdown.Header>
       <span className="block text-sm">{state.user.username}</span>
       <span className="block truncate text-sm font-medium">
         {state.user.email}
       </span>
     </Dropdown.Header>
     <Dropdown.Item onClick={signOut}>Sign out</Dropdown.Item>
   </Dropdown>
+) : (
+  <div className="h-10 w-10 animate-pulse bg-gray-200 rounded-full" />
+)}
nextjs-task-system/app/components/modalDelete.tsx (1)

47-50: Enhance button accessibility and loading state

Add proper ARIA labels and disable buttons during deletion.

-<Button onClick={handleDeletedTask}>Accept</Button>
-<Button color="gray" onClick={handleClose}>
+<Button 
+  onClick={handleDeletedTask}
+  disabled={isDeleting}
+  aria-label="Confirm deletion"
+>
+  {isDeleting ? 'Deleting...' : 'Accept'}
+</Button>
+<Button 
+  color="gray" 
+  onClick={handleClose}
+  disabled={isDeleting}
+  aria-label="Cancel deletion"
+>
   Cancel
 </Button>
nextjs-task-system/app/components/modal.tsx (1)

58-61: Improve conditional rendering readability

The ternary operator in the onSubmit prop is hard to read. Consider simplifying it.

-                        <Form initialData={task ? task : {}}
-                            onSubmit={task ? (data) => handleSubmitEdit(data) 
-                                           : (data) => handleSubmitCreate(data)} />
+                        <Form 
+                            initialData={task ?? {}}
+                            onSubmit={(data) => handleSubmit(data, Boolean(task))}
+                        />
nextjs-task-system/app/login/page.tsx (3)

13-13: Remove commented code

Commented-out code should be removed rather than committed.

-    // const [showNotification, setShowNotification] = useState(false);

38-38: Update placeholder email

The placeholder email should reflect your application's domain rather than flowbite.com.

-                                    placeholder="name@flowbite.com"
+                                    placeholder="name@example.com"

35-42: Add client-side email validation

Consider adding proper email validation before submission.

                                 <TextInput
                                     id="email"
                                     type="email"
                                     placeholder="name@example.com"
                                     required
+                                    pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
+                                    title="Please enter a valid email address"
                                     value={email}
                                     onChange={(e) => setEmail(e.target.value)}
                                 />
nextjs-task-system/app/providers/authProvider.tsx (1)

85-85: Fix typo in success message

The success message contains a typo: "successfullyy" has an extra 'y'.

- message: "User Logged in successfullyy!"
+ message: "User Logged in successfully!"
nextjs-task-system/app/components/form.tsx (2)

81-85: Add proper type for user object and improve accessibility

The component uses any type for users and lacks proper ARIA labels.

- state.users.map((user: any) => (
+ state.users.map((user: User) => (
    <option 
      key={user.id} 
      value={`user:${user.id}`}
+     aria-label={`Assign to user ${user.username}`}
    >

99-108: Enhance date input validation and constraints

The date input lacks minimum date validation and proper date formatting.

 <input
   id="due_date"
   name="due_date"
   type="date"
   required
+  min={new Date().toISOString().split('T')[0]}
   value={formState.due_date || ""}
   onChange={onChangeInput}
+  onInvalid={(e) => {
+    const target = e.target as HTMLInputElement;
+    target.setCustomValidity('Please select a future date');
+  }}
+  onInput={(e) => {
+    const target = e.target as HTMLInputElement;
+    target.setCustomValidity('');
+  }}
   className="block w-full px-3 py-2 text-gray-700 border-1 border-inherit rounded-lg"
 />
nextjs-task-system/app/components/modalView.tsx (1)

13-37: Enhance type safety and reusability of color utility functions

Consider the following improvements:

  1. Use literal types for parameters
  2. Move these utilities to a separate file since they're also used in the sidebar component
  3. Consider using a constant map instead of switch statements
// utils/colors.ts
type Priority = 'low' | 'medium' | 'high';
type Status = 'pending' | 'in progress' | 'completed';
type Color = 'green' | 'yellow' | 'red' | 'blue' | 'gray';

const PRIORITY_COLORS: Record<Priority, Color> = {
  low: 'green',
  medium: 'yellow',
  high: 'red'
};

const STATUS_COLORS: Record<Status, Color> = {
  pending: 'yellow',
  'in progress': 'blue',
  completed: 'green'
};

export const getPriorityColor = (priority: Priority): Color => 
  PRIORITY_COLORS[priority] ?? 'gray';

export const getStatusColor = (status: Status): Color => 
  STATUS_COLORS[status] ?? 'gray';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 111e4dd and afa738f.

📒 Files selected for processing (38)
  • nextjs-task-system/app/api/groups/route.js (1 hunks)
  • nextjs-task-system/app/api/groups/user/route.js (1 hunks)
  • nextjs-task-system/app/api/login/route.js (1 hunks)
  • nextjs-task-system/app/api/tasks/comments/route.js (1 hunks)
  • nextjs-task-system/app/api/tasks/route.js (1 hunks)
  • nextjs-task-system/app/api/tasks/user/route.js (1 hunks)
  • nextjs-task-system/app/api/users/route.js (1 hunks)
  • nextjs-task-system/app/components/card.tsx (1 hunks)
  • nextjs-task-system/app/components/footer.tsx (1 hunks)
  • nextjs-task-system/app/components/form.tsx (1 hunks)
  • nextjs-task-system/app/components/modal.tsx (1 hunks)
  • nextjs-task-system/app/components/modalDelete.tsx (1 hunks)
  • nextjs-task-system/app/components/modalView.tsx (1 hunks)
  • nextjs-task-system/app/components/navBar.tsx (1 hunks)
  • nextjs-task-system/app/components/pagination.tsx (1 hunks)
  • nextjs-task-system/app/components/sidebar.tsx (1 hunks)
  • nextjs-task-system/app/components/toast.tsx (1 hunks)
  • nextjs-task-system/app/config/axiosApi.ts (1 hunks)
  • nextjs-task-system/app/contexts/authContexts.tsx (1 hunks)
  • nextjs-task-system/app/contexts/taskContexts.tsx (1 hunks)
  • nextjs-task-system/app/contexts/userContexts.tsx (1 hunks)
  • nextjs-task-system/app/dashboard/layout.tsx (1 hunks)
  • nextjs-task-system/app/dashboard/tasks/page.tsx (1 hunks)
  • nextjs-task-system/app/db/database.js (1 hunks)
  • nextjs-task-system/app/db/initDB.js (1 hunks)
  • nextjs-task-system/app/hooks/useForm.ts (1 hunks)
  • nextjs-task-system/app/hooks/usePaginate.ts (1 hunks)
  • nextjs-task-system/app/layout.tsx (2 hunks)
  • nextjs-task-system/app/login/layout.tsx (1 hunks)
  • nextjs-task-system/app/login/page.tsx (1 hunks)
  • nextjs-task-system/app/page.tsx (1 hunks)
  • nextjs-task-system/app/providers/authProvider.tsx (1 hunks)
  • nextjs-task-system/app/providers/taskProvider.tsx (1 hunks)
  • nextjs-task-system/app/providers/userProvider.tsx (1 hunks)
  • nextjs-task-system/app/reducers/authReducer.ts (1 hunks)
  • nextjs-task-system/app/reducers/taskReducer.ts (1 hunks)
  • nextjs-task-system/app/reducers/userReducer.ts (1 hunks)
  • nextjs-task-system/package.json (2 hunks)
✅ Files skipped from review due to trivial changes (5)
  • nextjs-task-system/app/contexts/authContexts.tsx
  • nextjs-task-system/app/contexts/taskContexts.tsx
  • nextjs-task-system/app/contexts/userContexts.tsx
  • nextjs-task-system/app/config/axiosApi.ts
  • nextjs-task-system/app/db/database.js
🧰 Additional context used
🪛 Gitleaks (8.21.2)
nextjs-task-system/app/api/login/route.js

5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

nextjs-task-system/app/api/users/route.js

5-5: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (3)
nextjs-task-system/app/components/footer.tsx (1)

6-14: LGTM! Clean and well-structured component.

The component follows React best practices and properly utilizes the flowbite-react Footer component.

nextjs-task-system/package.json (1)

5-5: ⚠️ Potential issue

Reconsider the use of "type": "module"

The "type": "module" configuration might cause issues with Next.js, as it uses a hybrid module system. Consider removing this field and using the default CommonJS format, or ensure all your imports/exports are properly configured for ESM.

nextjs-task-system/app/layout.tsx (1)

13-14: LGTM: Metadata updates align with the application purpose.

The title and description changes accurately reflect the task management system's purpose.

Comment on lines +36 to +38
} catch (error) {
return new Response(JSON.stringify({ error: token }), { status: 400 });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix Error Handling in Catch Block

In the catch block, you're returning an error response with token, but token is not defined in this scope, which will cause a ReferenceError.

Apply this diff to fix the error handling:

-    return new Response(JSON.stringify({ error: token }), { status: 400 });
+    return new Response(JSON.stringify({ error: error.message }), { status: 400 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error) {
return new Response(JSON.stringify({ error: token }), { status: 400 });
}
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), { status: 400 });
}

Comment on lines +14 to +18
if (!user) {
return new Response(JSON.stringify({ error: "User not found" }), {
status: 404,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid Revealing User Existence in Error Messages

Returning "User not found" exposes whether an email is registered in the system, which can be a security concern. Consider returning a generic error message to prevent user enumeration attacks.

Apply this diff to generalize the error message:

-      return new Response(JSON.stringify({ error: "User not found" }), {
-        status: 404,
-      });
+      return new Response(JSON.stringify({ error: "Invalid credentials" }), {
+        status: 401,
+      });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!user) {
return new Response(JSON.stringify({ error: "User not found" }), {
status: 404,
});
}
if (!user) {
return new Response(JSON.stringify({ error: "Invalid credentials" }), {
status: 401,
});
}

Comment on lines +5 to +6
const SECRET_KEY =
"e95c8b5289c1bb3ec29be04822a7b5ddfb912d71a884bc9633b889b0439565eb8f3400f7b91a9e023b1d2ed57ed7217c2a485bbe3287c9cbd2a83aafd39d21e8";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical Security Issue: Hardcoded Secret Key Exposed

The SECRET_KEY is hardcoded in the codebase, which poses a severe security risk. Secret keys should be stored securely using environment variables or a secrets management system to prevent unauthorized access.

Apply this diff to fix the issue:

-const SECRET_KEY =
-  "e95c8b5289c1bb3ec29be04822a7b5ddfb912d71a884bc9633b889b0439565eb8f3400f7b91a9e023b1d2ed57ed7217c2a485bbe3287c9cbd2a83aafd39d21e8";
+const SECRET_KEY = process.env.SECRET_KEY;

Ensure that the SECRET_KEY environment variable is securely set in your deployment environment.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const SECRET_KEY =
"e95c8b5289c1bb3ec29be04822a7b5ddfb912d71a884bc9633b889b0439565eb8f3400f7b91a9e023b1d2ed57ed7217c2a485bbe3287c9cbd2a83aafd39d21e8";
const SECRET_KEY = process.env.SECRET_KEY;
🧰 Tools
🪛 Gitleaks (8.21.2)

5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

}

export async function POST(request) {
const { title, description,assigned_to, assigned_to_id,assigned_to_type, due_date, priority } = await request.json();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add Input Validation for Request Data

Currently, there is no validation for the incoming request data in the POST and PUT methods. This can lead to database errors or unintended behavior if the data is malformed or missing. Consider adding input validation to ensure required fields are present and have the correct data types.

Also applies to: 22-22

Comment on lines +1 to +3
import db from "../../db/database.js";

export async function GET() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing Authentication Middleware

The API endpoints lack authentication checks, allowing unrestricted access to task data. This poses a security risk as unauthorized users can perform any actions. Consider implementing authentication middleware to protect these routes.

Comment on lines +71 to +82
const handleAddComment = async () => {
if (newComment.trim()) {
await addCommentTask({ task_id: task.id, user_id: stateUser.user.id, comment: newComment });
setNewComment("");
setComments(prev => [
...prev,
{ comment: newComment, user_id: stateUser.user.id, created_at: new Date() }
]);

await getCommentsTask(task.id);
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve comment handling logic and validation

Current implementation has several issues:

  1. Missing proper input validation
  2. Unnecessary double update of comments
  3. Missing error handling
  4. Potential race condition

Consider this refactor:

const handleAddComment = async () => {
  const trimmedComment = newComment.trim();
  if (!trimmedComment) return;
  
  if (trimmedComment.length > 1000) { // Add appropriate max length
    setError('Comment is too long');
    return;
  }

  setIsLoading(true);
  try {
    await addCommentTask({
      task_id: task.id,
      user_id: stateUser.user.id,
      comment: trimmedComment
    });
    setNewComment('');
    // Remove local comment addition and rely on global state update
    await getCommentsTask(task.id);
  } catch (err) {
    setError(err instanceof Error ? err.message : 'Failed to add comment');
  } finally {
    setIsLoading(false);
  }
};

Comment on lines +88 to +161
return (
<Modal show={openModal} onClose={handleClose}>
<Modal.Header className="h-10 p-2" ></Modal.Header>
<Modal.Body>
<div className="space-y-6">
<Card href="#" className="w-100">
<div className="flex w-100 justify-between">
<h5 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
{task?.title}
</h5>
<Badge
size="sm"
color={getStatusColor(task?.status)}
className="uppercase"
>
{task?.status}
</Badge>
</div>

<p className="font-normal text-gray-700 dark:text-gray-400">
{task?.description}
</p>
<p className="font-normal text-gray-700 dark:text-gray-400 flex gap-2">
Assigned To:
<Badge size="sm" color="info" className="uppercase">
{task?.assigned_to || 'Unassigned'}
</Badge>
</p>
<p className="font-normal text-gray-700 dark:text-gray-400">
Due Date: {task?.due_date}
</p>
<p className="font-normal text-gray-700 dark:text-gray-400 flex gap-2">
Priority:
<Badge
size="sm"
color={getPriorityColor(task?.priority)}
className="uppercase"
>
{task?.priority}
</Badge>
</p>
</Card>
<div className="mt-4">
<h5 className="text-xl font-bold">Comments</h5>
<div className="space-y-4">
{comments.map((comment: any, index: number) => (
<div key={index} className="border p-4 rounded-md">
<p className="font-medium">{comment.username}</p>
<p>{comment.comment}</p>
</div>
))}
</div>

<Textarea
value={newComment}
onChange={(e) => setNewComment(e.target.value)}
placeholder="Add a comment..."
rows={3}
className="mt-4"
/>
<Button
onClick={handleAddComment}
className="mt-2"
color="light"
size="sm"
>
Add Comment
</Button>
</div>

</div>
</Modal.Body>

</Modal>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance modal accessibility and user experience

Several accessibility and UX improvements needed:

  1. Add proper aria labels
  2. Improve keyboard navigation
  3. Add loading states to the comment button
  4. Add error messages display
 <Modal 
   show={openModal} 
   onClose={handleClose}
+  aria-labelledby="task-modal-title"
+  aria-describedby="task-modal-description"
 >
-  <Modal.Header className="h-10 p-2" ></Modal.Header>
+  <Modal.Header className="h-10 p-2">
+    <h2 id="task-modal-title" className="text-xl font-bold">Task Details</h2>
+  </Modal.Header>
   <Modal.Body>
     <div className="space-y-6">
       <Card href="#" className="w-100">
         {/* ... existing card content ... */}
       </Card>
+      {error && (
+        <div role="alert" className="text-red-600">
+          {error}
+        </div>
+      )}
       <div className="mt-4">
         {/* ... existing comments section ... */}
         <Button
           onClick={handleAddComment}
           className="mt-2"
           color="light"
           size="sm"
+          disabled={isLoading || !newComment.trim()}
         >
-          Add Comment
+          {isLoading ? 'Adding...' : 'Add Comment'}
         </Button>
       </div>
     </div>
   </Modal.Body>
 </Modal>

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +108 to +121
<label htmlFor="statusFilter" className="text-sm font-medium text-gray-700">
Priority
</label>
<select
id="statusFilter"
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 md:text-sm"
onChange={(e) => handleFilterChange('priority',e)}
>
<option value="">All Priorities</option>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix duplicate IDs and improve accessibility

There are several issues in the filter components:

  1. The priority filter uses the same ID as status filter
  2. Missing aria-labels
  3. Inconsistent naming
-<label htmlFor="statusFilter" className="text-sm font-medium text-gray-700">
+<label htmlFor="priorityFilter" className="text-sm font-medium text-gray-700">
   Priority
 </label>
 <select
-  id="statusFilter"
+  id="priorityFilter"
+  aria-label="Filter tasks by priority"
   className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 md:text-sm"
   onChange={(e) => handleFilterChange('priority',e)}
 >

Also, consider adding loading states and error messages to improve user experience:

{isLoading ? (
  <div>Loading filters...</div>
) : error ? (
  <div role="alert" className="text-red-600">{error}</div>
) : (
  // Filter components
)}

Comment on lines +9 to +12
export function Dashboard({ filters,handleFilterChange }: any) {
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { state, getUsers, getGroups, getGroupsByUser } = useContext(UserContexts);
const { state: stateUser } = useContext(AuthContexts);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add proper TypeScript interfaces for component props

Replace any types with proper interfaces:

type FilterType = 'user' | 'group' | 'status' | 'priority';
type FilterValue = string | number;

interface Filters {
  user?: FilterValue;
  group?: FilterValue;
  status?: FilterValue;
  priority?: FilterValue;
}

interface DashboardProps {
  filters: Filters;
  handleFilterChange: (type: FilterType, event: React.ChangeEvent<HTMLSelectElement>) => void;
}

export function Dashboard({ filters, handleFilterChange }: DashboardProps) {

Comment on lines +14 to +22
useEffect(() => {
if (stateUser.user.rol === "admin") {
getUsers();
getGroups();
}
else {
getGroupsByUser(stateUser.user.id);
}
}, []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve data fetching logic and error handling

The useEffect has several issues:

  1. Missing dependencies in dependency array
  2. Missing error handling
  3. Missing loading states
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
  const fetchData = async () => {
    try {
      setIsLoading(true);
      setError(null);
      if (stateUser.user.rol === "admin") {
        await Promise.all([getUsers(), getGroups()]);
      } else {
        await getGroupsByUser(stateUser.user.id);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to fetch data');
    } finally {
      setIsLoading(false);
    }
  };

  fetchData();
}, [stateUser.user.rol, stateUser.user.id, getUsers, getGroups, getGroupsByUser]);

@FlorRoth FlorRoth changed the title Dev Task Management System Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants