Skip to content

Conversation

@nick-livefront
Copy link
Collaborator

@nick-livefront nick-livefront commented Oct 13, 2025

🎟️ Tracking

PM-24535

📔 Objective

Add steps for the user to upgrade to if they do not have access to premium:

  • Show premium badge in the more options menu
  • Show premium badge in left-hand filter menu
  • When the user does not have archived items and is not a premium user, clicking on the archive feature should show the upgrade modal.
  • When the user has archived items and is not a premium user the filter should allow them to view their archived items with a callout.

📸 Screenshots

No Premium Lost premium with archived items
no-premium.mov
lost-premium.mov

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

Comment on lines 50 to 55
premiumOptions?: {
/** When true, the premium badge will show on the filter for non-premium users. */
showPremiumBadge?: true;
/** Action to be called instead of applying the filter. */
blockFilterAction?: () => Promise<void>;
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried to make this somewhat reusable if it were to ever apply to other filters, but I'm not supper happy with the configuration options here. I'm open to ideas!

Copy link
Member

Choose a reason for hiding this comment

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

The only piece I'm hung up on is the name showPremiumBadge implies that the badge will always show, even though its only shown for non-premium. Maybe showBadgeForNonPremium though that is now pretty verbose.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Verbose but does eliminate any confusion which is important.

Updated! 84d3c01

@github-actions
Copy link
Contributor

github-actions bot commented Oct 13, 2025

Logo
Checkmarx One – Scan Summary & Details2cf0f874-d33d-4197-a9b5-1cc99f72e130

Great job! No new security vulnerabilities introduced in this pull request

@nick-livefront nick-livefront force-pushed the vault/pm-24535/web-premium-archive branch from 1c1f901 to 759126f Compare October 13, 2025 16:50
@claude
Copy link

claude bot commented Oct 13, 2025

Claude finished @nick-livefront's task —— View job


Code Review Complete

I've reviewed this PR implementing the premium upgrade path for the archive feature. Here are my findings:

Summary

This PR successfully implements premium upgrade paths for the archive feature, showing appropriate badges and prompts for non-premium users. The implementation generally follows established patterns and addresses previous review feedback well.


Findings

Finding 1: PR description quality is excellent - clear objectives, comprehensive screenshots/videos, and proper Jira tracking.

Finding 2: Observable pattern implementation follows ADR-0003 correctly with hasArchiveFlagEnabled$ being a direct observable property (apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts:261).

Finding 3: The refactoring mentioned in the last commit (a55201e) using combineLatest in addArchiveFilter properly handles multiple async operations (apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts:432-439).

Finding 4: Good use of Angular signals for archiveEnabled input in vault-cipher-row.component.ts:106, following the modernization pattern while maintaining RxJS for service-level state.

Finding 5: Premium badge implementation is properly abstracted through premiumOptions configuration (apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts:50-59).

Finding 6: Tailwind CSS classes properly use tw- prefix throughout (vault-filter-section.component.html:87, vault-cipher-row.component.html:215).

⚠️ Finding 7: Test coverage is concerningly low at 14.28% for patch coverage. While I understand this may be due to the nature of UI-heavy changes, consider adding:

  • Unit tests for showArchiveButton and showUnArchiveButton computed properties in vault-cipher-row.component.ts:147-164
  • Tests for the premium badge interaction flows
  • Tests for addArchiveFilter logic in vault-filter.component.ts:431-472

💭 Finding 8: The premiumOptions.blockFilterAction pattern (vault-filter-section.component.ts:99-102) is clever for intercepting filter actions. However, the naming blockFilterAction could be clearer - perhaps overrideFilterAction or interceptFilterAction would better indicate it's not just blocking but providing alternative behavior?

💭 Finding 9: In vault-cipher-row.component.ts:193-197, the logic for hiding attachments when archived AND non-premium is good, but the comment could be more explicit about the business rule: "Users who lose premium should still access attachments on their archived items."

♻️ Finding 10: The showBadgeForNonPremium naming (vault-filter-section.type.ts:52) is verbose but clear after the refactoring from previous reviews. This is acceptable given the clarity requirement.

🎨 Finding 11: Consider extracting the premium check logic that's repeated in multiple places. For example, vault-cipher-row.component.ts has several guards like CipherViewLikeUtils.isArchived(this.cipher) && !this.userCanArchive. A helper method like isArchivedButNoAccess() would improve readability.

💭 Finding 12: The service implementation in default-cipher-archive.service.ts:60-78 exposes multiple related observables (hasArchiveFlagEnabled$, userHasPremium$, showSubscriptionEndedMessaging$). While this provides flexibility, there's potential for consumers to use these inconsistently. The current usage appears correct, but documenting the intended use cases for each would help maintainability.


Positive Observations

👍 Great job addressing previous review feedback, especially:

  • Refactoring to use combineLatest for cleaner async handling
  • Using Observable with async pipe for archiveEnabled$
  • Clear separation of concerns between feature flag checks and premium status

👍 The video demonstrations in the PR description clearly show both user flows (no premium vs lost premium with archived items).

👍 Comprehensive i18n string additions with clear, user-friendly messaging (messages.json additions).


Recommendations

  1. Increase test coverage - Add unit tests for the new premium-gated features
  2. Document edge cases - Add inline comments explaining business rules for archived items when users lose premium
  3. Consider refactoring - Extract repeated premium access checks into helper methods

Conclusion

This is solid work that implements the premium upgrade path thoughtfully. The main concern is test coverage, which should be addressed before merging. The code quality is good, follows established patterns, and the previous review feedback has been well incorporated.

@codecov
Copy link

codecov bot commented Oct 13, 2025

Codecov Report

❌ Patch coverage is 14.58333% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.20%. Comparing base (9ee4fd0) to head (b914a54).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
.../vault-filter/components/vault-filter.component.ts 0.00% 10 Missing ⚠️
.../src/app/vault/individual-vault/vault.component.ts 0.00% 10 Missing ⚠️
...mponents/vault-items/vault-cipher-row.component.ts 0.00% 6 Missing ⚠️
...hared/components/vault-filter-section.component.ts 0.00% 4 Missing ⚠️
.../vault-filter/components/vault-filter.component.ts 0.00% 4 Missing ⚠️
...ault/popup/settings/vault-settings-v2.component.ts 0.00% 3 Missing ⚠️
...collections/vault-filter/vault-filter.component.ts 0.00% 1 Missing ⚠️
...vault/components/vault-items/vault-items.module.ts 0.00% 1 Missing ⚠️
...ault/components/vault-items/vault-items.stories.ts 0.00% 1 Missing ⚠️
.../vault-filter/shared/vault-filter-shared.module.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #16854      +/-   ##
==========================================
- Coverage   41.20%   41.20%   -0.01%     
==========================================
  Files        3543     3543              
  Lines      101912   101941      +29     
  Branches    15282    15287       +5     
==========================================
+ Hits        41991    42002      +11     
- Misses      58155    58174      +19     
+ Partials     1766     1765       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@jrmccannon jrmccannon left a comment

Choose a reason for hiding this comment

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

Looks good. Just a few small suggestions and a question.

Base automatically changed from PM-19152-web-archive to main October 14, 2025 21:41
@nick-livefront nick-livefront marked this pull request as draft October 14, 2025 21:41
@nick-livefront nick-livefront force-pushed the vault/pm-24535/web-premium-archive branch from 27635f1 to abb1e9d Compare October 15, 2025 19:34
@nick-livefront nick-livefront marked this pull request as ready for review October 15, 2025 19:36
@nick-livefront
Copy link
Collaborator Author

@jrmccannon @shane-melton I had to rebase as the base branch was squashed in, ready for review now!

jrmccannon
jrmccannon previously approved these changes Oct 16, 2025
shane-melton
shane-melton previously approved these changes Oct 16, 2025
Copy link
Member

@shane-melton shane-melton left a comment

Choose a reason for hiding this comment

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

Looks good to me! Just one non-blocking comment regarding the name of the premiumOptions.

Comment on lines 50 to 55
premiumOptions?: {
/** When true, the premium badge will show on the filter for non-premium users. */
showPremiumBadge?: true;
/** Action to be called instead of applying the filter. */
blockFilterAction?: () => Promise<void>;
};
Copy link
Member

Choose a reason for hiding this comment

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

The only piece I'm hung up on is the name showPremiumBadge implies that the badge will always show, even though its only shown for non-premium. Maybe showBadgeForNonPremium though that is now pretty verbose.

@sonarqubecloud
Copy link

jrmccannon
jrmccannon previously approved these changes Oct 17, 2025
shane-melton
shane-melton previously approved these changes Oct 18, 2025
@nick-livefront
Copy link
Collaborator Author

Archive has been put on a temporary hold - I'm moving this to a draft for the time being.

@nick-livefront nick-livefront marked this pull request as draft October 29, 2025 15:32
@nick-livefront nick-livefront marked this pull request as ready for review November 19, 2025 19:24
@nick-livefront
Copy link
Collaborator Author

nick-livefront commented Nov 19, 2025

@jrmccannon @shane-melton This is back ready for review now that Archive has a path forward. No functionality changes since your last review, only coming up to date with main and other archive work.

I actually refactored a change I don't know why I changed regarding the feature flag observable - a55201e

Copy link
Contributor

@jrmccannon jrmccannon left a comment

Choose a reason for hiding this comment

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

Looks good from AC perspective

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.

4 participants