Skip to content

Conversation

@chpy04
Copy link
Contributor

@chpy04 chpy04 commented Jan 7, 2026

Changes

  • Can now add either info boxes or check boxxes to the checklists so that we don't have check boxes with paragraphs of text next to them
  • Migrated old description fields to just be sub-tasks of info blocks, changed name to content so content is either the text for the checkbox or the text for the info box
  • Stores order of tasks and subtasks in db and allows admins to change order
  • optimistically updates cache when users click checkboxes to prevent lag
  • Removed apply here then continue section per Wills request
  • added image for new member events to put on onboarding page bc I felt like it would be useful
  • Defaulted checklists on the onboarding page to be expanded

Test Cases

  • Case A
  • Edge case
  • ...

Screenshots

If you made UI changes you must post a screenshot of the whole page for each change in 1) a normal sized window and 2) the smallest possible window

If you did any manual testing (e.g., with Postman), put screenshots of the http request and before and after of the db

If none of this applies, you can delete this section

To Do

Any remaining things that need to get done

  • item 1
  • ...

Checklist

It can be helpful to check the Checks and Files changed tabs.
Please review the contributor guide and reach out to your Tech Lead if anything is unclear.
Please request reviewers and ping on slack only after you've gone through this whole checklist.

  • All commits are tagged with the ticket number
  • No linting errors / newline at end of file warnings
  • All code follows repository-configured prettier formatting
  • No merge conflicts
  • All checks passing
  • Screenshots of UI changes (see Screenshots section)
  • Remove any non-applicable sections of this template
  • Assign the PR to yourself
  • No yarn.lock changes (unless dependencies have changed)
  • Request reviewers & ping on Slack
  • PR is linked to the ticket (fill in the closes line below)

Closes #3767

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements onboarding improvements to enhance the user experience for new members, addressing issue #3767. The changes introduce the ability to display both checkboxes and information blocks in checklists, add drag-and-drop reordering functionality for admin users, implement optimistic UI updates for checkbox interactions, and add support for a new member events image.

Key Changes:

  • Added support for checklist items to be either TASK (checkbox) or INFO (information block) types with a new itemType field and displayOrder field for custom ordering
  • Implemented optimistic UI updates when toggling checkboxes to eliminate perceived lag
  • Added drag-and-drop functionality for admins to reorder tasks and subtasks/info blocks
  • Added support for uploading and displaying a "New Member Events" image on the onboarding page
  • Made parent task checkboxes non-interactive (disabled) since they auto-check when all subtasks are complete
  • Updated all links in markdown to open in new tabs

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/shared/src/types/checklist-types.ts Added ChecklistItemType enum (TASK/INFO) and displayOrder field to Checklist type
src/shared/src/types/user-types.ts Added newMemberImageId to Organization type
src/backend/src/prisma/schema.prisma Added displayOrder, itemType, and newMemberImageId fields to database schema
src/backend/src/prisma/migrations/20260106000000_add_checklist_ordering_and_type/migration.sql Migration to add new fields with backfill logic for existing data
src/backend/src/services/onboarding.services.ts Added reorderTasks and reorderChecklistItems methods, updated queries to order by displayOrder, filtered INFO blocks from validation logic
src/backend/src/services/organizations.services.ts Added setNewMemberImage and getNewMemberImage methods
src/backend/src/controllers/onboarding.controllers.ts Added controller methods for reordering and updated create/edit to handle itemType
src/backend/src/controllers/organizations.controllers.ts Added controller methods for new member image upload/retrieval
src/backend/src/routes/onboarding.routes.ts Added routes for task and checklist item reordering
src/backend/src/routes/organizations.routes.ts Added routes for new member image operations
src/backend/src/transformers/organizationTransformer.ts Updated to include image IDs in organization preview
src/frontend/src/apis/onboarding.api.ts Added API functions for reordering tasks and checklist items
src/frontend/src/apis/organizations.api.ts Added API functions for new member image operations
src/frontend/src/utils/urls.ts Added URL definitions for new endpoints
src/frontend/src/hooks/onboarding.hook.ts Implemented optimistic updates for checkbox toggling and mutations for reordering
src/frontend/src/hooks/organizations.hooks.ts Added hooks for new member image upload and retrieval
src/frontend/src/components/NERMarkdown.tsx Updated to make all links open in new tabs
src/frontend/src/pages/HomePage/components/SubtaskSection.tsx Refactored to display both TASK and INFO items in a single list with backward compatibility
src/frontend/src/pages/HomePage/components/ParentTask.tsx Made parent checkbox disabled and visually distinct
src/frontend/src/pages/HomePage/components/ChecklistSection.tsx Added display of new member events image after General checklist
src/frontend/src/pages/HomePage/components/Checklist.tsx Changed initial showTasks state to true (expanded by default)
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/OnboardingInfoSection.tsx Added UI for uploading new member events image
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/AdminSubtaskSection.tsx Added drag-and-drop for reordering subtasks and info blocks
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/AdminChecklist.tsx Added drag-and-drop for reordering parent tasks
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/CreateChecklistModal.tsx Refactored to support creating both TASK and INFO items with drag-and-drop ordering
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/CreateInfoBlockModal.tsx New modal for creating information blocks with markdown preview
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/EditInfoBlockModal.tsx New modal for editing information blocks with markdown preview
src/frontend/src/pages/AdminToolsPage/OnboardingConfig/Checklists/SubtaskFormModal.tsx Updated to set itemType to TASK when creating subtasks
src/frontend/src/pages/AdminToolsPage/RecruitmentConfig/AdminToolsRecruitmentConfig.tsx Fixed alt text from "Apply Interest" to "Explore As Guest"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 61 to 63
useState(() => {
setLocalItems(allItems);
});
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

This is using useState incorrectly. The useState hook is meant to initialize state, not to create side effects. To synchronize local state with props changes, you should use the useEffect hook instead.

Replace this pattern with:

useEffect(() => {
  setLocalItems(allItems);
}, [allItems]);

This ensures the local items update when allItems changes, which happens when parentTask.subtasks updates.

Copilot uses AI. Check for mistakes.
})
)
);
})
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

Missing semicolon after the transaction block. This will likely cause a syntax error or unexpected behavior.

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 50
const allItems = [
...subtasks.map((subtask) => ({
...subtask,
itemType: subtask.itemType ?? 'TASK',
displayOrder: subtask.displayOrder ?? 999
})),
// Backward compatibility: show old descriptions only if they exist and aren't already in subtasks as info blocks
...(parentTask.descriptions && parentTask.descriptions.length > 0
? parentTask.descriptions.map((description, index) => ({
checklistId: `info-${index}`,
name: description,
itemType: 'INFO' as const,
displayOrder: 1000 + index,
isOptional: false
}))
: [])
].sort((a, b) => a.displayOrder - b.displayOrder);
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The backward compatibility logic for old descriptions could cause duplicate items to be shown. If the data was migrated from old descriptions to new INFO-type checklist items but the descriptions array wasn't cleared, users would see both the old descriptions and the new INFO blocks.

Consider adding a filter to prevent showing old descriptions if there are already INFO-type subtasks:

const hasInfoBlocks = subtasks.some(s => s.itemType === 'INFO');
const allItems = [
  ...subtasks.map((subtask) => ({
    ...subtask,
    itemType: subtask.itemType ?? 'TASK',
    displayOrder: subtask.displayOrder ?? 999
  })),
  // Only show old descriptions if no INFO blocks exist
  ...(!hasInfoBlocks && parentTask.descriptions && parentTask.descriptions.length > 0 
    ? parentTask.descriptions.map((description, index) => ({
        checklistId: `info-${index}`,
        name: description,
        itemType: 'INFO' as const,
        displayOrder: 1000 + index,
        isOptional: false
      }))
    : [])
].sort((a, b) => a.displayOrder - b.displayOrder);

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 36
useState(() => {
setLocalTasks(parentChecklists);
});
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

This is using useState incorrectly. The useState hook is meant to initialize state, not to create side effects. To synchronize local state with props changes, you should use the useEffect hook instead.

Replace this pattern with:

useEffect(() => {
  setLocalTasks(parentChecklists);
}, [parentChecklists]);

This ensures the local tasks update when parentChecklists changes.

Copilot uses AI. Check for mistakes.
})
)
);
})
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

Missing semicolon after the transaction block. This will likely cause a syntax error or unexpected behavior.

Suggested change
})
});

Copilot uses AI. Check for mistakes.
Comment on lines 122 to 147
await Promise.all(
filteredSubtasks.map((subtask) =>
createChecklist({
name: subtask.name,
descriptions: [],
teamId,
teamTypeId,
parentChecklistId: parentChecklist.checklistId,
isOptional: subtask.isOptional
})
)
items.map((item) => {
if (item.type === 'TASK' && item.name) {
return createChecklist({
name: item.name,
descriptions: [],
teamId,
teamTypeId,
parentChecklistId: parentChecklist.checklistId,
isOptional: item.isOptional || false,
itemType: 'TASK'
});
} else if (item.type === 'INFO' && item.content) {
return createChecklist({
name: 'Info Block',
descriptions: [item.content],
teamId,
teamTypeId,
parentChecklistId: parentChecklist.checklistId,
isOptional: false,
itemType: 'INFO'
});
}
return Promise.resolve();
})
);
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The Promise.all will create all items in parallel, which means the displayOrder assigned by the backend may not match the actual order in the items array. This happens because the backend assigns displayOrder based on the order items are created, not on any provided order.

Consider either:

  1. Creating items sequentially (using a for loop instead of Promise.all) to ensure proper ordering
  2. Or better, pass the desired displayOrder to the backend as part of the creation payload and have the backend honor it

For example:

for (let i = 0; i < items.length; i++) {
  const item = items[i];
  if (item.type === 'TASK' && item.name) {
    await createChecklist({
      name: item.name,
      descriptions: [],
      teamId,
      teamTypeId,
      parentChecklistId: parentChecklist.checklistId,
      isOptional: item.isOptional || false,
      itemType: 'TASK'
      // TODO: Add displayOrder: i + 1 once backend supports it
    });
  } else if (item.type === 'INFO' && item.content) {
    await createChecklist({
      name: 'Info Block',
      descriptions: [item.content],
      teamId,
      teamTypeId,
      parentChecklistId: parentChecklist.checklistId,
      isOptional: false,
      itemType: 'INFO'
      // TODO: Add displayOrder: i + 1 once backend supports it
    });
  }
}

Copilot uses AI. Check for mistakes.
Comment on lines 50 to 52
const schema: yup.ObjectSchema<ChecklistFormValues> = yup.object().shape({
name: yup.string().required('Name is Required')
}) as any;
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

Using as any to bypass TypeScript type checking is an anti-pattern that defeats the purpose of using TypeScript. This suggests there might be a type incompatibility between the yup schema definition and the expected type.

Consider properly typing the schema without the as any cast, or if there's a genuine type issue with the library, add a more specific comment explaining why this is necessary.

Suggested change
const schema: yup.ObjectSchema<ChecklistFormValues> = yup.object().shape({
name: yup.string().required('Name is Required')
}) as any;
const schema: yup.ObjectSchema<ChecklistFormValues> = yup
.object({
name: yup.string().required('Name is Required')
})
.required();

Copilot uses AI. Check for mistakes.
@@ -1,10 +1,12 @@
import { Box, Grid, Link, Typography } from '@mui/material';
import React from 'react';
import { Box, Grid, Link, Typography, useTheme } from '@mui/material';
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

Unused import Link.

Suggested change
import { Box, Grid, Link, Typography, useTheme } from '@mui/material';
import { Box, Grid, Typography, useTheme } from '@mui/material';

Copilot uses AI. Check for mistakes.
import { Box } from '@mui/system';
import React from 'react';
import { Checklist } from 'shared';
import { Checklist, ChecklistItemType } from 'shared';
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

Unused import ChecklistItemType.

Suggested change
import { Checklist, ChecklistItemType } from 'shared';
import { Checklist } from 'shared';

Copilot uses AI. Check for mistakes.
component="img"
sx={{ display: 'block', maxWidth: '100%', maxHeight: '200px', mb: 1, objectFit: 'contain' }}
alt="New Member Event"
src={newMemberImageBlob ? URL.createObjectURL(newMemberImageBlob) : undefined}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

This use of variable 'newMemberImageBlob' always evaluates to true.

Suggested change
src={newMemberImageBlob ? URL.createObjectURL(newMemberImageBlob) : undefined}
src={URL.createObjectURL(newMemberImageBlob)}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 18 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chpy04 chpy04 merged commit ddde11f into develop Jan 8, 2026
4 checks passed
@chpy04 chpy04 deleted the #3767-onboarding-improvements branch January 8, 2026 15:05
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.

Onboarding Improvements

3 participants