Skip to content

Conversation

@bbarni2020
Copy link
Collaborator

Screenshot 2025-12-29 at 13 08 16

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 adds a visual progress bar component to the project details page that displays the current status of a project through a multi-step progress indicator. The component shows different visualizations for rejected projects versus active projects progressing through various stages.

Key changes:

  • Added project metadata display (creation date, update date, and time spent)
  • Implemented a multi-step progress bar showing project status through 5 stages: Submitted → On print queue → Being printed → Printed → Payout
  • Added special visualization for rejected projects with a red-themed progress bar

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

Comment on lines +77 to +152
<div class="h-2 bg-gradient-to-r from-primary-400 to-primary-600 transition-all duration-300" style="width: calc((({[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status)}) / 4) * 100%)"></div>
</div>
{#each [
{ key: 'submitted', label: 'Submitted', color: 'bg-indigo-400' },
{ key: 't1_approved', label: 'On print queue', color: 'bg-yellow-400' },
{ key: 'printing', label: 'Being printed', color: 'bg-emerald-400' },
{ key: 'printed', label: 'Printed', color: 'bg-blue-400' },
{ key: 'finalized', label: 'Payout', color: 'bg-green-200' }
] as step, i (step.key)}
<div class="flex-1 flex flex-col items-center min-w-0 relative z-10" style="position: absolute; left: calc(5% + (90% * {i} / 4)); top: 50%; transform: translate(-50%, -50%);">
<div
class="w-7 h-7 rounded-full border-4 shadow-md transition-all duration-300"
class:bg-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:bg-gray-200={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:border-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:border-gray-300={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:{step.color}={true}
style="box-shadow: 0 2px 8px 0 rgba(0,0,0,0.07);"
></div>
</div>
{/each}
</div>
<div class="relative w-full mt-3" style="height: 22px;">
{#each [
{ key: 'submitted', label: 'Submitted' },
{ key: 't1_approved', label: 'On print queue' },
{ key: 'printing', label: 'Being printed' },
{ key: 'printed', label: 'Printed' },
{ key: 'finalized', label: 'Payout' }
] as step, i (step.key)}
<div class="absolute w-max max-w-[20%] text-center left-0" style="left: calc(5% + (90% * {i} / 4)); transform: translate(-50%, 0);">
<span class="text-xs font-semibold whitespace-nowrap"
class:text-primary-700={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:text-gray-400={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The same array ['submitted', 't1_approved', 'printing', 'printed', 'finalized'] is repeated multiple times throughout the code. This creates significant code duplication and makes maintenance difficult. Consider extracting this array into a constant at the component level to improve maintainability and reduce the risk of inconsistencies.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

<div class="absolute left-0 top-0 h-4 rounded-full bg-gradient-to-r from-red-500 to-red-400 animate-pulse" style="width: 22%"></div>
</div>
<span class="ml-2 text-red-700 font-bold text-base tracking-wide flex items-center gap-1 whitespace-nowrap">
<svg width="18" height="18" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#f87171"/><path d="M12 7v5m0 4h.01" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The rejected status icon SVG is missing accessible text for screen readers. Consider adding an aria-label or title element to describe the icon's meaning for users who rely on assistive technologies.

Suggested change
<svg width="18" height="18" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#f87171"/><path d="M12 7v5m0 4h.01" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
<svg width="18" height="18" fill="none" viewBox="0 0 24 24" role="img" aria-label="Rejected status"><circle cx="12" cy="12" r="10" fill="#f87171"/><path d="M12 7v5m0 4h.01" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>

Copilot uses AI. Check for mistakes.
{#if data.project.status === 'rejected' || data.project.status === 'rejected_locked'}
<div class="flex items-center gap-3 w-full">
<div class="flex-1 h-4 rounded-full bg-gradient-to-r from-red-200 to-red-100 relative overflow-hidden w-full">
<div class="absolute left-0 top-0 h-4 rounded-full bg-gradient-to-r from-red-500 to-red-400 animate-pulse" style="width: 22%"></div>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The rejected status progress bar shows a hardcoded width of 22% which appears to be an arbitrary magic number. This value should either be documented with a comment explaining its significance or extracted as a named constant to improve code clarity.

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +123
{ key: 'submitted', label: 'Submitted', color: 'bg-indigo-400' },
{ key: 't1_approved', label: 'On print queue', color: 'bg-yellow-400' },
{ key: 'printing', label: 'Being printed', color: 'bg-emerald-400' },
{ key: 'printed', label: 'Printed', color: 'bg-blue-400' },
{ key: 'finalized', label: 'Payout', color: 'bg-green-200' }
] as step, i (step.key)}
<div class="flex-1 flex flex-col items-center min-w-0 relative z-10" style="position: absolute; left: calc(5% + (90% * {i} / 4)); top: 50%; transform: translate(-50%, -50%);">
<div
class="w-7 h-7 rounded-full border-4 shadow-md transition-all duration-300"
class:bg-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:bg-gray-200={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:border-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:border-gray-300={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:{step.color}={true}
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The step color property defined in the loop (line 86-90) is not being used effectively. Line 123 sets the color with class:{step.color}={true}, but since the circles are already conditionally styled with bg-primary-500 or bg-gray-200 based on the status progression, the step.color classes (bg-indigo-400, bg-yellow-400, etc.) will be overridden and have no visible effect. This creates confusion about the intended styling.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +83
<div class="h-2 bg-gradient-to-r from-primary-400 to-primary-600 transition-all duration-300" style="width: calc((({[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status)}) / 4) * 100%)"></div>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The progress bar width calculation uses a hardcoded divisor of 4, which assumes there are always 5 steps (0-indexed). If the status list changes in the future, this calculation will break. Consider using a dynamic calculation based on the actual array length minus 1, such as (index / (steps.length - 1)) * 100%.

Copilot uses AI. Check for mistakes.
{ key: 'printed', label: 'Printed', color: 'bg-blue-400' },
{ key: 'finalized', label: 'Payout', color: 'bg-green-200' }
] as step, i (step.key)}
<div class="flex-1 flex flex-col items-center min-w-0 relative z-10" style="position: absolute; left: calc(5% + (90% * {i} / 4)); top: 50%; transform: translate(-50%, -50%);">
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The hardcoded divisor of 4 in the positioning calculation assumes there are always 5 steps. This creates the same maintainability issue as the progress bar width calculation. If steps are added or removed, the positioning will be incorrect.

Copilot uses AI. Check for mistakes.
{ key: 'printed', label: 'Printed' },
{ key: 'finalized', label: 'Payout' }
] as step, i (step.key)}
<div class="absolute w-max max-w-[20%] text-center left-0" style="left: calc(5% + (90% * {i} / 4)); transform: translate(-50%, 0);">
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The same hardcoded divisor of 4 is used here for label positioning, which will break if the number of steps changes. This should be calculated dynamically based on the array length.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +160
<div class="mb-8 w-full px-0 sm:px-2 md:px-4 lg:px-8 xl:px-16 py-6">
{#key data.project.status}
{#if data.project.status === 'rejected' || data.project.status === 'rejected_locked'}
<div class="flex items-center gap-3 w-full">
<div class="flex-1 h-4 rounded-full bg-gradient-to-r from-red-200 to-red-100 relative overflow-hidden w-full">
<div class="absolute left-0 top-0 h-4 rounded-full bg-gradient-to-r from-red-500 to-red-400 animate-pulse" style="width: 22%"></div>
</div>
<span class="ml-2 text-red-700 font-bold text-base tracking-wide flex items-center gap-1 whitespace-nowrap">
<svg width="18" height="18" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#f87171"/><path d="M12 7v5m0 4h.01" stroke="#fff" stroke-width="2" stroke-linecap="round"/></svg>
Rejected
</span>
</div>
{:else}
<div class="w-full flex flex-col items-stretch">
<div class="relative w-full flex items-center" style="height: 44px;">
<div class="absolute z-0 top-1/2 -translate-y-1/2 left-[5%] right-[5%] h-2 bg-gray-200 rounded-full overflow-hidden">
<div class="h-2 bg-gradient-to-r from-primary-400 to-primary-600 transition-all duration-300" style="width: calc((({[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status)}) / 4) * 100%)"></div>
</div>
{#each [
{ key: 'submitted', label: 'Submitted', color: 'bg-indigo-400' },
{ key: 't1_approved', label: 'On print queue', color: 'bg-yellow-400' },
{ key: 'printing', label: 'Being printed', color: 'bg-emerald-400' },
{ key: 'printed', label: 'Printed', color: 'bg-blue-400' },
{ key: 'finalized', label: 'Payout', color: 'bg-green-200' }
] as step, i (step.key)}
<div class="flex-1 flex flex-col items-center min-w-0 relative z-10" style="position: absolute; left: calc(5% + (90% * {i} / 4)); top: 50%; transform: translate(-50%, -50%);">
<div
class="w-7 h-7 rounded-full border-4 shadow-md transition-all duration-300"
class:bg-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:bg-gray-200={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:border-primary-500={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:border-gray-300={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
class:{step.color}={true}
style="box-shadow: 0 2px 8px 0 rgba(0,0,0,0.07);"
></div>
</div>
{/each}
</div>
<div class="relative w-full mt-3" style="height: 22px;">
{#each [
{ key: 'submitted', label: 'Submitted' },
{ key: 't1_approved', label: 'On print queue' },
{ key: 'printing', label: 'Being printed' },
{ key: 'printed', label: 'Printed' },
{ key: 'finalized', label: 'Payout' }
] as step, i (step.key)}
<div class="absolute w-max max-w-[20%] text-center left-0" style="left: calc(5% + (90% * {i} / 4)); transform: translate(-50%, 0);">
<span class="text-xs font-semibold whitespace-nowrap"
class:text-primary-700={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) >= i}
class:text-gray-400={[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status) < i}
>{step.label}</span>
</div>
{/each}
</div>
</div>
{/if}
{/key}
</div>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The progress indicator circles lack proper ARIA attributes for screen reader users. Consider adding role="progressbar", aria-valuenow, aria-valuemin, aria-valuemax, and aria-label attributes to make the progress bar accessible to users with disabilities.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +83
<div class="h-2 bg-gradient-to-r from-primary-400 to-primary-600 transition-all duration-300" style="width: calc((({[
'submitted',
't1_approved',
'printing',
'printed',
'finalized'
].indexOf(data.project.status)}) / 4) * 100%)"></div>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

The progress calculation using indexOf() will return -1 if the project status is not in the expected list, resulting in a negative width value. While this may not crash the UI, it could lead to unexpected visual behavior. Consider adding validation to handle unexpected status values gracefully.

Copilot uses AI. Check for mistakes.
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.

2 participants