Skip to content

[SSF-206] Add empty state components for dashboard#181

Open
jxuistrying wants to merge 9 commits into
mainfrom
jx/SSF-206-empty-state-components
Open

[SSF-206] Add empty state components for dashboard#181
jxuistrying wants to merge 9 commits into
mainfrom
jx/SSF-206-empty-state-components

Conversation

@jxuistrying

Copy link
Copy Markdown

ℹ️ Issue

Closes #206

📝 Description

I implemented SectionEmptyState and PageEmptyState components to update the ui when there isn't any data to display to users.

  1. Created SectionEmptyState component for section-level empty states
  2. Created PageEmptyState for page-level empty states
  3. Updated Admin dashboard to show empty state for pending actions, recent orders and recent donations sections
  4. Updated Volunteer dashboard to show empty state
  5. Updated Pantry dashboard to show empty state

✔️ Verification

Tested empty state by setting conditionals that check if a section is empty to true

Dashboard empty state
image

Section empty state
image

🏕️ (Optional) Future Work / Notes

I had trouble testing Pantry dashboard specifically if(!pantry) { return null } in apps/frontend/src/containers/pantryDashboard.tsx made it so that the empty state message doesnt show so I added an error message for when there isn't data to display which seems to fix the empty state message not showing but I don't think that error message is needed.

@jxuistrying jxuistrying changed the title Add empty state components for dashboard [SSF-206]Add empty state components for dashboard May 24, 2026
@jxuistrying jxuistrying changed the title [SSF-206]Add empty state components for dashboard [SSF-206] Add empty state components for dashboard May 24, 2026
@jiang-h-y jiang-h-y self-requested a review May 24, 2026 17:06
@Yurika-Kan Yurika-Kan self-assigned this May 25, 2026
Comment thread apps/frontend/src/containers/adminDashboard.tsx
</Box>
{isPageEmpty ? (
<PageEmptyState
subtitle="You have no orders or applications to review at this time."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Not sure if this is strictly necessary, but it might be good to pass in the entity to PageEmptyState and SectionEmptyState instead of hard coding the entire subtitle.

e.g. You have no {entity} at this time.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

im liking the sound of dis

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

gotchu I added {entity} so that the content can be passed in

@Yurika-Kan Yurika-Kan self-requested a review May 29, 2026 06:24

@Yurika-Kan Yurika-Kan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

awesome job implementing this! tested pages & overall a great first pr ><

commented on matching the figma, edge cases, and frontend styling!

take a look at apps/frontend/src/theme.ts for our repo design system

  • specifically we use <Text textStyle="p2 (...etc)"> and <Heading textStyle="h1 (...etc)"> instead of hardcoding fontSize, fontWeight, fontFamily
  • we also have color tokens there to use instead of hardcoding hex numbers
  • we have our font tokens there wired so we also don't have to hardcode those

can you update the styling to follow our conventions? ik seems tomato tomato but routing all styling through one source makes the app easier to maintain, extend, and look at :)

Comment thread apps/frontend/src/components/PageEmptyState.tsx Outdated
Comment thread apps/frontend/src/components/SectionEmptyState.tsx Outdated
Comment thread apps/frontend/src/components/pageEmptyState.tsx
Comment thread apps/frontend/src/components/PageEmptyState.tsx Outdated
Comment thread apps/frontend/src/containers/volunteerDashboard.tsx Outdated
Comment thread apps/frontend/src/components/PageEmptyState.tsx Outdated
Comment thread apps/frontend/src/components/PageEmptyState.tsx Outdated
Comment thread apps/frontend/src/components/PageEmptyState.tsx Outdated
Comment thread apps/frontend/src/containers/pantryDashboard.tsx Outdated
Comment thread apps/frontend/src/containers/adminDashboard.tsx Outdated
@Yurika-Kan

Yurika-Kan commented May 31, 2026

Copy link
Copy Markdown
Collaborator

@jxuistrying btw - justin's FM dashboard pr has been merged! if you could add the empty state for FM dashboards, that would be so so great!

Comment thread apps/frontend/src/containers/adminDashboard.tsx Outdated
Comment thread apps/frontend/src/containers/adminDashboard.tsx
Comment thread apps/frontend/src/containers/volunteerDashboard.tsx
Comment thread apps/frontend/src/containers/pantryDashboard.tsx
Comment thread apps/frontend/src/containers/foodManufacturerDashboard.tsx
@jxuistrying jxuistrying requested a review from Yurika-Kan June 14, 2026 17:50

@Yurika-Kan Yurika-Kan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i noticed a same fail-fast issue with using Promise.all so i suggested two fixes!

/>
)}

{Object.values(DonationStatus).map((status) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can we add the same loading fix to this file as well?

instead of directly rendering empty state when it could be loading..

useEffect(() => {
const fetchDashboardData = async () => {
try {
const [user, applications, allOrders, allDonations] = await Promise.all(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

consider Promise.allSettled instead of Promise.all here~

Promise.all -
all the calls are bundled into one block, so if any single endpoint fails, the entire dashboard renders empty + a generic error, even if the other endpoints succeeded

Promise.allSettled -
lets each section render independently, so a failure in one call will not affect another

@Yurika-Kan Yurika-Kan Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

OR actually consider...

so the problem is that promise.all is fail fast, so if any one endpoint rejects we skip all the set calls, even for sections that succeeded. this results in:

  • one flaky call emptying the whole dashboard
  • after the catch, loading is false but the arrays are still empty [], so isPageEmpty is true & we render empty state error showing that you have no orders" which defeats the empty-state feature

i suggest keeping the per section functions (each with its own try/catch) and just coordinating them for the loading flag:

useEffect(() => {
  const load = async () => {
    try {
      await Promise.all([fetchMe(), fetchPendingApplications(), fetchRecentOrders(), fetchRecentDonations()]);
    } finally {
      setLoading(false);
    }
  };
  load();
}, [setAlertMessage]);

each function catches its own error, so Promise.all never rejects. successful sections render, only the failed one is empty (with a specific message), isPageEmpty stays truthful!

const pantryData = await ApiClient.getPantry(pantryId);
const pantryId = await ApiClient.getCurrentUserPantryId();
const [pantryData, pantryFoodRequests, pantryOrders] =
await Promise.all([

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

keep per-section catches, wrap in awaited Promise.all for the loading flag (see admin comment). the leading getXId/getMe call is a prerequisite, so let that one throw, then Promise.all the rest

@jxuistrying jxuistrying requested a review from Yurika-Kan June 21, 2026 05:33

@Yurika-Kan Yurika-Kan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

please make the changes to pantry name & resolve merge conflicts before merging into main!

thanks for this justin! this is looking quite awesome. nice pr!

}, [setAlertMessage]);

if (!pantry) return null;
if (loading || !pantry) return null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can you remove the !pantry?

if only fetchPantry fails, pantry stays null (hitting !pantry) and the whole page renders null rather than the other sections

@@ -77,51 +101,85 @@ const PantryDashboard: React.FC = () => {
Welcome, {pantry.pantryName}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

to support a case of !pantry:

make this pantry?.pantryName

type={DashboardCardType.FOOD_REQUEST}
title={`Request #${fr.requestId}`}
date={fr.requestedAt}
subtitle={pantry.pantryName}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

and this to pantry?.pantryName

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.

3 participants