DEV Community

Cover image for Day 94 of #100DaysOfCode — DevCollab: Dashboard, Profiles, and the Final Pages
M Saad Ahmad
M Saad Ahmad

Posted on

Day 94 of #100DaysOfCode — DevCollab: Dashboard, Profiles, and the Final Pages

Four days of backend. Four days of frontend building. Today was the last building day: the dashboard, public profiles, edit profile, and sent requests. After today, every planned page exists. The entire app is navigable directly in the browser without using Postman or the admin panel.


The Dashboard

The dashboard is the page users land on after logging in, and it needed to answer one question clearly: What's happening with my projects right now?

I split it into two sections. The top section shows the user's own projects; a list of cards with the project title, status badge, whether it's open or closed, and two action links: one to view incoming requests for that project, one to edit it. Below each project card is the count of pending requests, shown as a link. Clicking it scrolls to or filters the requests section below.

The second section shows all incoming collaboration requests across all the user's projects grouped by project. Each request shows the requester's username, their skills as small tags, a preview of their message, and two buttons: accept and reject. Clicking either calls the update request status API, updates the UI immediately without a full page reload, and shows the new status. I wanted this interaction to feel instant, not a redirect, just the button state changing and the badge updating in place.

The stats row at the top, total projects, total requests received, and accepted collaborators, gives a quick snapshot without having to count manually. These numbers are computed from the data already fetched for the two sections, not from separate API calls.

The dashboard is a protected page. Unauthenticated users get redirected to the login.


The RequestCard Component

The dashboard's request section uses a RequestCard component that I extracted because request cards appear both on the dashboard and potentially on individual project pages. The card shows the requester's avatar if they have one, their username as a link to their public profile, their skills as tags, the project title it belongs to, the message they wrote, and the accept and reject buttons.

The accept and reject buttons have three visual states: default, loading while the API call is in flight, and a disabled state after one has been clicked. Once a request is accepted or rejected, the buttons disappear, and a status badge takes their place. This prevents the owner from changing their mind through the UI if they want to change a status, they'd have to use the API directly, which is fine for now.


The Public Profile Page

The public profile page is accessible to anyone logged in or not. It shows everything a developer has chosen to share about themselves: their avatar, username, bio, location, skills as tags, GitHub link, LinkedIn link, and website link. Below the profile info is a grid of their active open projects.

The projects section on a profile page reuses the ProjectCard component from day 92. No new component is needed; the same card that appears on the browse page appears here. That reuse is the payoff for building ProjectCard as a standalone component on day 92 rather than inline on the browse page.

The page handles the case where the username in the URL doesn't exist, the API returns a 404, and the page shows a clean "User not found" message with a link back to the browse page.

One intentional design decision: the profile page doesn't show the user's sent collaboration requests or any private information. Only what the user has explicitly put in their public profile. The skills and bio are the user's own words; the projects are already public. Nothing private surfaces here.


The Edit Profile Page

The edit profile page is where users set up their presence on DevCollab. First impressions on the platform come from this page; a well-filled profile gets more collaboration requests.

The form has seven fields: bio, skills, location, GitHub URL, LinkedIn URL, website URL, and avatar upload. The skills field is a plain text input with a hint showing the comma-separated format. On submit, the page calls the update profile API with a PATCH request.

Avatar upload required special handling. The API endpoint accepts multipart form data for avatar uploads, not JSON. The profile update with text fields uses JSON. I handled this by separating the two text fields update via PATCH with JSON, and avatar updates via a separate POST to the avatar endpoint with FormData. The user sees one form, but under the hood, the two updates happen separately if an avatar is selected.

The form pre-fills with the current user's profile data fetched on mount. Fields the user hasn't filled in yet show as empty. On successful save, the page redirects to the user's public profile so they can see exactly what others will see.


The Sent Requests Page

The sent requests page is the requester's mirror of the dashboard. Where the dashboard shows incoming requests to the owner, this page shows outgoing requests from the requester.

Each row shows the project title as a link to the detail page, the project owner's username, the date the request was sent, the message the user wrote, and the current status as a colored badge: grey for pending, blue for reviewed, green for accepted, red for rejected.

The page is sorted by most recent first. Old rejected requests stay visible; removing them would hide useful information. A developer who got rejected from a project might want to know that when they're evaluating whether to apply to something similar.

The empty state on this page is important. A new user who has registered but hasn't applied anywhere yet lands here and sees "You haven't sent any collaboration requests yet" with a link to browse projects. It guides them toward the next action rather than showing a blank table.


The Users Service

All four pages today use profile data from the API. Rather than making direct API calls from each page, I wrote services/users.js first, a dedicated file with functions for getting the current user's profile, updating it, uploading an avatar, and fetching any public profile by username. The same principle as the projects and request services, API logic in service files, and pages focused on rendering.


Completing the Navigation

With all pages existing today, I also finished wiring up the navigation links that were previously pointing to pages that didn't exist yet.

The Navbar's Dashboard link now actually leads somewhere meaningful. The profile username in the Navbar links to the current user's public profile. The "Post Project" button in the Navbar links to the create project page. Every link in the app now resolves to a real page.

I also added a breadcrumb-style back link on the edit profile, edit project, and apply pages so users can navigate back without using the browser back button. Small detail, noticeably better experience.


Where Things Stand After Day 94

Every page is built. Every user flow works end-to-end through the browser. The complete journey register, fill in profile, post a project, another user browses and applies, the owner accepts from their dashboard, both sides see the updated status, works without touching anything outside the browser.

What's missing is polish. The pages work, but they don't all look their best. Some loading states are basic, some empty states are minimal, and some error messages are raw API text rather than friendly messages. That's what the next two days are for.

Thanks for reading. Feel free to share your thoughts!

Top comments (0)