project-dashboard

repository·main·Indexed 21 days ago

https://github.com/jason-uxui/project-dashboard

A project dashboard application for client management, project tracking, and data visualization. It includes utilities for managing client records, project details, and task flattening, as well as systems for sidebar navigation, URL-based filter synchronization, and view configuration options.

Tokens
5.4K
Snippets
23
Records
24
Agent score
76%

What's inside project-dashboard

  1. Understand the ProjectDetails data structure

    main

    The ProjectDetails type is the central data contract for a project's comprehensive view. It aggregates several sub-structures:

    • meta: Labels for priority, location, sprint, and sync status.
    • scope: Defines inScope and outOfScope arrays.
    • keyFeatures: Categorized features by priority (p0, p1, p2).
    • workstreams: Groups of WorkstreamTask objects.
    • timelineTasks: High-level tasks with startDate, endDate, and status.
    • backlog: Summary of project status, priority, and assigned picUsers (Person In Charge).
    • files & quickLinks: Project assets and documentation.
    • notes: Project-related notes, including support for audio data with AI summaries and transcripts.
  2. Configure view options for the project dashboard

    main

    The ViewOptions type defines how projects and tasks are displayed in the dashboard. You can control the layout type, task hierarchy, sorting, grouping, and visibility of specific project elements. Use the DEFAULT_VIEW_OPTIONS constant as a baseline when initializing custom view states.

    import { ViewOptions, DEFAULT_VIEW_OPTIONS } from '@/lib/view-options'
    
    const myCustomOptions: ViewOptions = {
      ...DEFAULT_VIEW_OPTIONS,
      viewType: 'board',
      groupBy: 'status',
      properties: ['title', 'status']
    }
  3. Flatten project tasks with getProjectTasks()

    main

    The getProjectTasks(details: ProjectDetails) function extracts all tasks from all workstreams within a project and flattens them into a single array of ProjectTask objects. Each returned task is enriched with context from the parent project and workstream, including projectId, projectName, workstreamId, and workstreamName.

    import { getProjectTasks, type ProjectDetails } from '@/lib/data/project-details';
    
    const tasks = getProjectTasks(projectDetailsInstance);
    // tasks is now a flat array of ProjectTask[]
  4. Get an avatar URL with getAvatarUrl()

    main

    The getAvatarUrl function generates a path to a user's profile image based on their name.

    • If a name is provided that matches specific hardcoded identifiers (e.g., "jason duong", "jason d", or "jd"), it returns the path to a specific profile image: /avatar-profile.jpg.
    • If no name is provided, or if the name does not match the hardcoded identifiers, it returns undefined.

    Note: In this project, users who do not match these identifiers typically fall back to displaying initials in the UI rather than an image path.

    import { getAvatarUrl } from '@/lib/assets/avatars'
    
    const url = getAvatarUrl("jason duong")
    // returns "/avatar-profile.jpg"
    
    const fallback = getAvatarUrl("Unknown User")
    // returns undefined
  5. Update or create a client using upsertClient()

    main

    The upsertClient(input: Client) function is a mock-only helper used to simulate create or edit operations in-memory. If a client with the provided id already exists, it merges the new properties into the existing record. If the id does not exist, it pushes the new client into the clients array.

    const updatedClient = upsertClient({
      id: "acme",
      name: "Acme Corp Updated",
      status: "active"
    });
  6. Convert URLSearchParams to FilterChips

    main

    Use paramsToChips to reconstruct an array of FilterChip objects from a URLSearchParams instance. This allows the UI to restore filter states from the URL on page load.

    The function maps specific URL parameter keys back to standardized FilterChip keys:

    • status -> Status
    • priority -> Priority
    • tags -> Tag
    • members -> Member

    Values in the URL are expected to be comma-separated strings.

    import { paramsToChips } from '@/lib/url/filters';
    
    const params = new URLSearchParams('status=active,pending&tags=urgent&members=jason');
    const chips = paramsToChips(params);
    /* 
    Resulting chips array:
    [
      { key: 'Status', value: 'active' },
      { key: 'Status', value: 'pending' },
      { key: 'Tag', value: 'urgent' },
      { key: 'Member', value: 'jason' }
    ]
    */
  7. Merge Tailwind CSS classes with cn()

    main

    Use the cn utility to conditionally join CSS class names and resolve Tailwind CSS class conflicts. It combines clsx for conditional logic and tailwind-merge to ensure that the last class provided wins when there are conflicting Tailwind definitions (e.g., merging p-4 and p-2 results in p-2).

    import { cn } from '@/lib/utils'
    
    // Example usage:
    const className = cn(
      'base-class', 
      isTrue && 'conditional-class', 
      'p-4 p-2' // Result will be 'base-class conditional-class p-2'
    )
  8. Retrieve project details with getProjectDetailsById()

    main

    Use getProjectDetailsById(id: string) to fetch the full metadata and structured data for a specific project. If the provided id does not match an existing project in the data source, the function returns a default ProjectDetails object with placeholder values (e.g., "Untitled project [id]").

    import { getProjectDetailsById } from '@/lib/data/project-details';
    
    const details = getProjectDetailsById('1');
    console.log(details.name);
  9. Convert FilterChips to URLSearchParams

    main

    Use chipsToParams to transform an array of FilterChip objects into a URLSearchParams instance. This is useful for synchronizing UI filter states with the browser URL.

    The function applies key normalization:

    • status* becomes status
    • priority* becomes priority
    • tag* becomes tags
    • member* or pic becomes members

    Multiple values for the same key are serialized as a comma-separated string (e.g., ?status=active,pending).

    import { chipsToParams } from '@/lib/url/filters';
    import type { FilterChip } from '@/lib/view-options';
    
    const chips: FilterChip[] = [
      { key: 'status', value: 'active' },
      { key: 'status', value: 'pending' },
      { key: 'tag', value: 'urgent' }
    ];
    
    const params = chipsToParams(chips);
    // Resulting URLSearchParams: status=active,pending&tags=urgent
  10. Get the number of projects for a client using getProjectCountForClient()

    main

    Use getProjectCountForClient(clientName: string) to return the total number of projects associated with a specific client name. This function filters the global projects data based on the provided clientName.

    const count = getProjectCountForClient("Acme Corp");