Skip to content

Design#114

Open
ChitkulLakshya wants to merge 5 commits intomainfrom
design
Open

Design#114
ChitkulLakshya wants to merge 5 commits intomainfrom
design

Conversation

@ChitkulLakshya
Copy link
Copy Markdown
Collaborator

Description

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing functionality)
  • Documentation update
  • Refactor (no functional changes)
  • CI/CD changes

Related Issues

Screenshots (if applicable)

Testing

  • Tested on Windows
  • Tested on macOS
  • Tested on Linux
  • Unit tests added/updated
  • Manual testing completed

Checklist

  • Code follows project coding standards
  • Self-review of code performed
  • Comments added for complex logic
  • Documentation updated (if applicable)
  • All tests pass locally
  • No new warnings or errors introduced

Route mobile users through a new src/mobile/pages structure and add a mobile-first home page while preserving existing desktop pages.

Made-with: Cursor
Render a real mobile activity log experience with live session/task data and replace the bottom Profile tab with Settings for better navigation consistency.

Made-with: Cursor
Improve mobile UX by adding a dedicated dashboard layout, closing drawer on navigation, refining activity summaries/member drilldown, and adding missing dialog metadata to remove accessibility warnings.

Made-with: Cursor
fix(mobile): polish nav, dashboard, and accessibility
Copilot AI review requested due to automatic review settings April 21, 2026 08:02
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
zync Ready Ready Preview, Comment Apr 21, 2026 8:02am

Copy link
Copy Markdown

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

Adds mobile-specific routing and UI updates to support a refreshed “design” experience across desktop and mobile, including new mobile dashboard/activity views and a new app-wide dashboard backdrop.

Changes:

  • Introduces mobile route variants (incl. a mobile landing page) and switches routes based on useIsMobile.
  • Adds new mobile dashboard + activity log views and wires activity/session fetching into MobileView.
  • Updates desktop layout styling (transparent main panel + full-viewport gradient backdrop) and improves accessibility in several dialogs.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/App.tsx Routes now choose mobile vs desktop components using useIsMobile; adds lazy imports for mobile pages.
src/mobile/pages/IndexMobile.tsx New mobile landing page with feature cards and primary CTAs.
src/mobile/pages/LoginMobile.tsx Mobile wrapper component for Login page.
src/mobile/pages/SignupMobile.tsx Mobile wrapper component for Signup page.
src/mobile/pages/DashboardMobile.tsx Mobile wrapper component for Dashboard page.
src/mobile/pages/NewProjectMobile.tsx Mobile wrapper component for NewProject page.
src/mobile/pages/ProjectDetailsMobile.tsx Mobile wrapper component for ProjectDetails page.
src/mobile/pages/PrivacyPolicyMobile.tsx Mobile wrapper component for PrivacyPolicy page.
src/mobile/pages/PrivacyMobile.tsx Mobile wrapper component for Privacy page.
src/mobile/pages/TermsMobile.tsx Mobile wrapper component for Terms page.
src/mobile/pages/WelcomeToZyncMobile.tsx Mobile wrapper component for WelcomeToZync page.
src/mobile/pages/NotFoundMobile.tsx Mobile wrapper component for NotFound page.
src/components/views/MobileView.tsx Uses new mobile dashboard/activity views; adds activity/session/team data fetching and log actions.
src/components/views/mobile/MobileDashboardView.tsx New compact dashboard view for mobile with GitHub stats + contribution graph + task counts.
src/components/views/mobile/MobileActivityLogView.tsx New mobile activity summary + team member activity + recent activity list with delete/clear.
src/components/layout/MobileLayout.tsx Updates nav items and improves drawer accessibility/close behavior.
src/components/views/DesktopView.tsx Adds fixed “dashboard-backdrop” layer and makes main panel transparent to show it.
src/index.css Defines the new .dashboard-backdrop gradient (dark + light variants).
src/components/views/DesignView.tsx Makes Design view background transparent to align with new backdrop.
src/components/views/SettingsView.tsx Makes the settings tabs horizontally scrollable on smaller screens.
src/components/views/ActivityLogView.tsx Extracts time formatting helpers and reuses them in the UI.
src/components/ui/command.tsx Adds a screen-reader-only dialog header/description for the command menu.
src/components/ProfilePhotoCropper.tsx Adds a screen-reader-only dialog description for the cropper modal.
src/lib/firebase.ts Removes a DEV-only console info message for App Check being skipped.

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

Comment on lines +321 to +334
activityLogs.slice(0, 20).map((log, index) => {
const start = new Date(log.startTime);
const title = log.title || log.eventType || "Activity session";
const logKey =
log._id ||
`${log.startTime || "no-start"}-${log.eventType || title}-${log.userId || "no-user"}-${index}`;
return (
<div key={logKey} className="rounded-lg border border-border/60 p-3 flex items-start gap-2">
<Clock3 className="h-4 w-4 text-primary mt-0.5" />
<div className="min-w-0 flex-1">
<p className="text-sm font-medium truncate">{title}</p>
<p className="text-[11px] text-muted-foreground">
{formatDistanceToNow(start, { addSuffix: true })}
</p>
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

formatDistanceToNow(new Date(log.startTime)) will throw a RangeError if log.startTime is missing or not a valid date string/number. Add a guard (e.g., validate start.getTime()), and render a safe fallback label when the timestamp is invalid.

Copilot uses AI. Check for mistakes.
Comment on lines +337 to +345
<Button
size="icon"
variant="ghost"
className="h-7 w-7 text-destructive"
onClick={() => onDeleteLog(log._id)}
>
<Trash2 className="h-3.5 w-3.5" />
</Button>
)}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The delete action is an icon-only button with no accessible name. Add an aria-label (and/or title) so screen readers can announce the control (e.g., “Delete activity log entry”).

Copilot uses AI. Check for mistakes.
Comment thread src/App.tsx
Comment on lines 24 to +90
@@ -32,6 +44,7 @@ const AppContent = () => {
useUserSync();
useSyncData(); // Trigger local-first data fetch and Dexie sync on login/app load
const location = useLocation();
const isMobile = useIsMobile();


const getPageKey = (pathname: string) => {
@@ -55,33 +68,33 @@ const AppContent = () => {
>
<Suspense fallback={<div className="h-full w-full flex items-center justify-center text-sm text-muted-foreground">Loading…</div>}>
<Routes location={location}>
<Route path="/" element={<Index />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/welcome" element={<WelcomeToZync />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/dashboard/workspace" element={<Dashboard />} />
<Route path="/dashboard/workspace/project/:id" element={<Dashboard />} />
<Route path="/dashboard/projects" element={<Dashboard />} />
<Route path="/dashboard/calendar" element={<Dashboard />} />
<Route path="/dashboard/design" element={<Dashboard />} />
<Route path="/dashboard/tasks" element={<Dashboard />} />
<Route path="/dashboard/notes" element={<Dashboard />} />
<Route path="/dashboard/files" element={<Dashboard />} />
<Route path="/dashboard/activity" element={<Dashboard />} />
<Route path="/dashboard/people" element={<Dashboard />} />
<Route path="/dashboard/meet" element={<Dashboard />} />
<Route path="/dashboard/settings" element={<Dashboard />} />
<Route path="/dashboard/chat" element={<Dashboard />} />
<Route path="/dashboard/new-project" element={<Dashboard />} />
<Route path="/new-project" element={<NewProject />} />
<Route path="/projects/:id" element={<ProjectDetails />} />
<Route path="/" element={isMobile ? <IndexMobile /> : <Index />} />
<Route path="/login" element={isMobile ? <LoginMobile /> : <Login />} />
<Route path="/signup" element={isMobile ? <SignupMobile /> : <Signup />} />
<Route path="/welcome" element={isMobile ? <WelcomeToZyncMobile /> : <WelcomeToZync />} />
<Route path="/dashboard" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/workspace" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/workspace/project/:id" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/projects" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/calendar" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/design" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/tasks" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/notes" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/files" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/activity" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/people" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/meet" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/settings" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/chat" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/dashboard/new-project" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
<Route path="/new-project" element={isMobile ? <NewProjectMobile /> : <NewProject />} />
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

Several of the new *Mobile route components are simple passthrough wrappers around the existing pages (e.g. DashboardMobile just renders pages/Dashboard, and pages/Dashboard already branches on useIsMobile). This adds an extra lazy-loaded chunk and a second mobile check without changing behavior. Consider routing directly to the page and letting it handle responsive rendering, or make the mobile route components contain actual mobile-specific logic to justify the extra indirection.

Copilot uses AI. Check for mistakes.
Comment thread src/App.tsx
Comment on lines 46 to +75
@@ -55,33 +68,33 @@ const AppContent = () => {
>
<Suspense fallback={<div className="h-full w-full flex items-center justify-center text-sm text-muted-foreground">Loading…</div>}>
<Routes location={location}>
<Route path="/" element={<Index />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/welcome" element={<WelcomeToZync />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/dashboard/workspace" element={<Dashboard />} />
<Route path="/dashboard/workspace/project/:id" element={<Dashboard />} />
<Route path="/dashboard/projects" element={<Dashboard />} />
<Route path="/dashboard/calendar" element={<Dashboard />} />
<Route path="/dashboard/design" element={<Dashboard />} />
<Route path="/dashboard/tasks" element={<Dashboard />} />
<Route path="/dashboard/notes" element={<Dashboard />} />
<Route path="/dashboard/files" element={<Dashboard />} />
<Route path="/dashboard/activity" element={<Dashboard />} />
<Route path="/dashboard/people" element={<Dashboard />} />
<Route path="/dashboard/meet" element={<Dashboard />} />
<Route path="/dashboard/settings" element={<Dashboard />} />
<Route path="/dashboard/chat" element={<Dashboard />} />
<Route path="/dashboard/new-project" element={<Dashboard />} />
<Route path="/new-project" element={<NewProject />} />
<Route path="/projects/:id" element={<ProjectDetails />} />
<Route path="/" element={isMobile ? <IndexMobile /> : <Index />} />
<Route path="/login" element={isMobile ? <LoginMobile /> : <Login />} />
<Route path="/signup" element={isMobile ? <SignupMobile /> : <Signup />} />
<Route path="/welcome" element={isMobile ? <WelcomeToZyncMobile /> : <WelcomeToZync />} />
<Route path="/dashboard" element={isMobile ? <DashboardMobile /> : <Dashboard />} />
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

useIsMobile() currently returns false on the initial render (the hook initializes state to undefined and returns !!isMobile), so mobile users will briefly render the desktop routes before the effect runs. Consider delaying route rendering until the mobile breakpoint is resolved (e.g., return undefined from the hook and show a loading shell), or initialize the hook state from window.innerWidth to avoid a desktop->mobile flicker and unnecessary chunk loads.

Copilot uses AI. Check for mistakes.
navigate("/login");
const parsed = JSON.parse(storedSession);
if (parsed?.startTime) {
setSessionStartTime(new Date(parsed.startTime));
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

storedSession.startTime is parsed into a Date without validating it. If it’s missing/invalid, sessionStartTime.getTime() becomes NaN and the timer will render NaN:NaN:NaN. Validate the parsed date (e.g., check !Number.isNaN(date.getTime())) before calling setSessionStartTime.

Suggested change
setSessionStartTime(new Date(parsed.startTime));
const parsedStartTime = new Date(parsed.startTime);
if (!Number.isNaN(parsedStartTime.getTime())) {
setSessionStartTime(parsedStartTime);
}

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +123
const buildActivityLogTasks = (projects: any[]) => {
return projects.flatMap((project: any) =>
(project.steps || []).flatMap((step: any) =>
(step.tasks || []).map((task: any) => ({
...task,
projectId: project._id || project.id,
projectName: project.name,
githubRepoName: project.githubRepoName,
githubRepoOwner: project.githubRepoOwner,
githubRepo: project.githubRepo,
repoIds: project.githubRepoIds,
projectOwnerId: project.ownerUid || project.ownerId,
}))
)
);
};

const filterCommitCapableTasks = (tasks: any[], userId: string) => {
return tasks.filter((task: any) => {
const assignedTo = task?.assignedTo;
const assignedUserIds = Array.isArray(task?.assignedUserIds) ? task.assignedUserIds : [];
const hasRepoLink = Boolean(
task?.githubRepoOwner ||
task?.githubRepoName ||
task?.githubRepo ||
(Array.isArray(task?.repoIds) && task.repoIds.length > 0)
);
const hasCommitCode = Boolean(task?.commitCode);

return hasRepoLink && hasCommitCode && (assignedTo === userId || assignedUserIds.includes(userId));
});
};

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

buildActivityLogTasks / filterCommitCapableTasks appear to duplicate the same logic in src/components/views/DesktopView.tsx (e.g. around DesktopView.tsx:295-326). To avoid divergence/bugs over time, consider extracting these helpers into a shared utility module and reusing it from both desktop and mobile views.

Suggested change
const buildActivityLogTasks = (projects: any[]) => {
return projects.flatMap((project: any) =>
(project.steps || []).flatMap((step: any) =>
(step.tasks || []).map((task: any) => ({
...task,
projectId: project._id || project.id,
projectName: project.name,
githubRepoName: project.githubRepoName,
githubRepoOwner: project.githubRepoOwner,
githubRepo: project.githubRepo,
repoIds: project.githubRepoIds,
projectOwnerId: project.ownerUid || project.ownerId,
}))
)
);
};
const filterCommitCapableTasks = (tasks: any[], userId: string) => {
return tasks.filter((task: any) => {
const assignedTo = task?.assignedTo;
const assignedUserIds = Array.isArray(task?.assignedUserIds) ? task.assignedUserIds : [];
const hasRepoLink = Boolean(
task?.githubRepoOwner ||
task?.githubRepoName ||
task?.githubRepo ||
(Array.isArray(task?.repoIds) && task.repoIds.length > 0)
);
const hasCommitCode = Boolean(task?.commitCode);
return hasRepoLink && hasCommitCode && (assignedTo === userId || assignedUserIds.includes(userId));
});
};
const getProjectTaskMetadata = (project: any) => ({
projectId: project._id || project.id,
projectName: project.name,
githubRepoName: project.githubRepoName,
githubRepoOwner: project.githubRepoOwner,
githubRepo: project.githubRepo,
repoIds: project.githubRepoIds,
projectOwnerId: project.ownerUid || project.ownerId,
});
const flattenProjectTasks = (projects: any[]) => {
return projects.flatMap((project: any) =>
(project.steps || []).flatMap((step: any) =>
(step.tasks || []).map((task: any) => ({
...task,
...getProjectTaskMetadata(project),
}))
)
);
};
const hasTaskRepoLink = (task: any) => {
return Boolean(
task?.githubRepoOwner ||
task?.githubRepoName ||
task?.githubRepo ||
(Array.isArray(task?.repoIds) && task.repoIds.length > 0)
);
};
const isCommitCapableTaskForUser = (task: any, userId: string) => {
const assignedTo = task?.assignedTo;
const assignedUserIds = Array.isArray(task?.assignedUserIds) ? task.assignedUserIds : [];
const hasCommitCode = Boolean(task?.commitCode);
return hasTaskRepoLink(task) && hasCommitCode && (assignedTo === userId || assignedUserIds.includes(userId));
};
const buildActivityLogTasks = (projects: any[]) => {
return flattenProjectTasks(projects);
};
const filterCommitCapableTasks = (tasks: any[], userId: string) => {
return tasks.filter((task: any) => isCommitCapableTaskForUser(task, userId));
};

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants