Browse Source

Complete DIDView.vue triple migration and refactor template handlers

- Fix DIDView.vue notification migration: add missing NOTIFY_SERVER_ACCESS_ERROR and NOTIFY_NO_IDENTITY_ERROR imports
- Refactor 5 inline template handlers to proper class methods (goBack, toggleDidDetails, showLargeProfileImage, showLargeIdenticon, hideLargeImage)
- Update notification validation script to exclude createNotifyHelpers initialization patterns
- DIDView.vue now fully compliant: database migration + SQL abstraction + notification migration complete

Improves code organization, testability, and follows Vue.js best practices for template/class separation. All linting passes without errors.
pull/142/head
Matthew Raymer 18 hours ago
parent
commit
15874d31ef
  1. 171
      docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md
  2. 150
      docs/migration-templates/PROCESS_OVERVIEW.md
  3. 30
      docs/migration-templates/component-migration.md
  4. 130
      docs/migration-testing/DIDVIEW_MIGRATION.md
  5. 186
      docs/migration-testing/HUMAN_TESTING_TRACKER.md
  6. 122
      scripts/validate-notification-completeness.sh
  7. 45
      src/constants/notifications.ts
  8. 45
      src/utils/PlatformServiceMixin.ts
  9. 365
      src/views/DIDView.vue

171
docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md

@ -0,0 +1,171 @@
# Complete Migration Checklist - MANDATORY STEPS
## Overview
This checklist ensures NO migration steps are forgotten. **Every component migration MUST complete ALL sections.**
## ⚠️ CRITICAL: Triple Migration Pattern
### 🔑 The Complete Pattern (ALL 3 REQUIRED)
1. **Database Migration**: Replace legacy `databaseUtil` calls with `PlatformServiceMixin` methods
2. **SQL Abstraction**: Replace raw SQL queries with service methods
3. **Notification Migration**: Replace `$notify()` calls with helper methods + constants
**❌ INCOMPLETE**: Any migration missing one of these steps
**✅ COMPLETE**: All three patterns implemented
## Pre-Migration Assessment
### [ ] 1. Identify Legacy Patterns
- [ ] Count `databaseUtil` imports and calls
- [ ] Count raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
- [ ] Count `$notify()` calls
- [ ] Count `logConsoleAndDb()` calls
- [ ] Document total issues found
### [ ] 2. Verify PlatformServiceMixin Setup
- [ ] Component already imports `PlatformServiceMixin`
- [ ] Component already has `mixins: [PlatformServiceMixin]`
- [ ] If missing, add mixin first
## Phase 1: Database Migration
### [ ] 3. Replace Database Utility Calls
- [ ] Remove `import * as databaseUtil from "../db/databaseUtil"`
- [ ] Replace `databaseUtil.retrieveSettingsForActiveAccount()``this.$accountSettings()`
- [ ] Replace `databaseUtil.mapQueryResultToValues()``this.$mapQueryResultToValues()`
- [ ] Replace other `databaseUtil.*` calls with mixin equivalents
### [ ] 4. Replace Logging Calls
- [ ] Remove `import { logConsoleAndDb } from "../db/index"`
- [ ] Replace `logConsoleAndDb()``this.$logAndConsole()`
## Phase 2: SQL Abstraction Migration
### [ ] 5. Replace Raw Contact Operations
- [ ] `SELECT * FROM contacts WHERE did = ?``this.$getContact(did)`
- [ ] `DELETE FROM contacts WHERE did = ?``this.$deleteContact(did)`
- [ ] `UPDATE contacts SET x = ? WHERE did = ?``this.$updateContact(did, changes)`
- [ ] `INSERT INTO contacts``this.$insertContact(contact)`
### [ ] 6. Replace Other Raw SQL
- [ ] `SELECT * FROM settings``this.$accountSettings()`
- [ ] `UPDATE settings``this.$saveSettings(changes)`
- [ ] Generic queries → appropriate service methods
- [ ] **NO RAW SQL ALLOWED**: All database operations through service layer
## Phase 3: Notification Migration
### [ ] 7. Add Notification Infrastructure
- [ ] Add import: `import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify"`
- [ ] Add property: `notify!: ReturnType<typeof createNotifyHelpers>;`
- [ ] Add initialization: `created() { this.notify = createNotifyHelpers(this.$notify); }`
### [ ] 8. Add Notification Constants (if needed)
- [ ] Review notification messages for reusable patterns
- [ ] Add constants to `src/constants/notifications.ts`
- [ ] Import constants: `import { NOTIFY_X, NOTIFY_Y } from "@/constants/notifications"`
### [ ] 9. Replace Notification Calls
- [ ] **Warning**: `this.$notify({type: "warning"})``this.notify.warning(CONSTANT.message, TIMEOUTS.LONG)`
- [ ] **Error**: `this.$notify({type: "danger"})``this.notify.error(CONSTANT.message, TIMEOUTS.LONG)`
- [ ] **Success**: `this.$notify({type: "success"})``this.notify.success(CONSTANT.message, TIMEOUTS.STANDARD)`
- [ ] **Toast**: `this.$notify({type: "toast"})``this.notify.toast(title, message, TIMEOUTS.SHORT)`
- [ ] **Confirm**: `this.$notify({type: "confirm"})``this.notify.confirm(message, onYes)`
- [ ] **Standard patterns**: Use `this.notify.confirmationSubmitted()`, `this.notify.sent()`, etc.
### [ ] 10. Constants vs Literal Strings
- [ ] **Use constants** for static, reusable messages
- [ ] **Use literal strings** for dynamic messages with variables
- [ ] **Document decision** for each notification call
## Validation Phase
### [ ] 11. Run Validation Script
- [ ] Execute: `scripts/validate-migration.sh`
- [ ] **MUST show**: "Technically Compliant" (not "Mixed Pattern")
- [ ] **Zero** legacy patterns detected
### [ ] 12. Run Linting
- [ ] Execute: `npm run lint-fix`
- [ ] **Zero errors** introduced
- [ ] **TypeScript compiles** without errors
### [ ] 13. Manual Code Review
- [ ] **NO** `databaseUtil` imports or calls
- [ ] **NO** raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
- [ ] **NO** `$notify()` calls with object syntax
- [ ] **NO** `logConsoleAndDb()` calls
- [ ] **ALL** database operations through service methods
- [ ] **ALL** notifications through helper methods
## Documentation Phase
### [ ] 14. Update Migration Documentation
- [ ] Create `docs/migration-testing/[COMPONENT]_MIGRATION.md`
- [ ] Document all changes made
- [ ] Include before/after examples
- [ ] Note validation results
### [ ] 15. Update Testing Tracker
- [ ] Update `docs/migration-testing/HUMAN_TESTING_TRACKER.md`
- [ ] Mark component as "Ready for Testing"
- [ ] Include notes about migration completed
## Human Testing Phase
### [ ] 16. Test All Functionality
- [ ] **Core functionality** works correctly
- [ ] **Database operations** function properly
- [ ] **Notifications** display correctly with proper timing
- [ ] **Error scenarios** handled gracefully
- [ ] **Cross-platform** compatibility (web/mobile)
### [ ] 17. Confirm Testing Complete
- [ ] User confirms component works correctly
- [ ] Update testing tracker with results
- [ ] Mark as "Human Tested" in validation script
## Final Validation
### [ ] 18. Comprehensive Check
- [ ] Component shows as "Technically Compliant" in validation
- [ ] All manual testing passed
- [ ] Zero legacy patterns remain
- [ ] Documentation complete
- [ ] Ready for production
## 🚨 FAILURE CONDITIONS
**❌ INCOMPLETE MIGRATION** if ANY of these remain:
- `databaseUtil` imports or calls
- Raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
- `$notify()` calls with object syntax
- `logConsoleAndDb()` calls
- Missing notification helpers setup
- Validation script shows "Mixed Pattern"
## 🎯 SUCCESS CRITERIA
**✅ COMPLETE MIGRATION** requires ALL:
- Zero legacy patterns detected
- All database operations through service layer
- All notifications through helper methods
- Validation script shows "Technically Compliant"
- Manual testing passed
- Documentation complete
## Templates and References
- **Migration Template**: `docs/migration-templates/component-migration.md`
- **Notification Constants**: `src/constants/notifications.ts`
- **PlatformServiceMixin**: `src/utils/PlatformServiceMixin.ts`
- **Notification Helpers**: `src/utils/notify.ts`
- **Validation Script**: `scripts/validate-migration.sh`
---
**⚠️ WARNING**: This checklist exists because steps were previously forgotten. DO NOT skip any items. The triple migration pattern (Database + SQL + Notifications) is MANDATORY for all component migrations.
**Author**: Matthew Raymer
**Date**: 2024-01-XX
**Purpose**: Prevent migration oversight by cementing ALL requirements

150
docs/migration-templates/PROCESS_OVERVIEW.md

@ -0,0 +1,150 @@
# TimeSafari Migration Process Overview
## 🎯 Purpose
This document provides a high-level overview of the complete migration process for TimeSafari components, preventing oversight and ensuring systematic completion.
## 📋 The Complete Migration Pattern
### Triple Migration Requirement
**ALL components must complete ALL three migration types:**
1. **🗃️ Database Migration**: Replace legacy `databaseUtil` calls
2. **🔗 SQL Abstraction**: Replace raw SQL with service methods
3. **🔔 Notification Migration**: Replace `$notify()` with helper methods
### Why All Three Are Required
| Migration Type | Purpose | Risk of Skipping |
|----------------|---------|------------------|
| Database | Modern API access | Inconsistent database patterns |
| SQL Abstraction | Service layer separation | Exposed SQL in components |
| Notification | Consistent UX patterns | Inconsistent user messaging |
## 🛠️ Tools and Resources
### Documentation
- **Primary Checklist**: `docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md`
- **Quick Reference**: `docs/migration-templates/component-migration.md`
- **Testing Tracker**: `docs/migration-testing/HUMAN_TESTING_TRACKER.md`
### Validation Scripts
- **Overall Status**: `scripts/validate-migration.sh`
- **Notification Completeness**: `scripts/validate-notification-completeness.sh`
- **Linting**: `npm run lint-fix`
### Source References
- **PlatformServiceMixin**: `src/utils/PlatformServiceMixin.ts`
- **Notification Helpers**: `src/utils/notify.ts`
- **Notification Constants**: `src/constants/notifications.ts`
## 🔄 Standard Workflow
### 1. Pre-Migration Assessment
```bash
# Run validation to identify issues
scripts/validate-migration.sh
scripts/validate-notification-completeness.sh
```
### 2. Execute Triple Migration
**Follow `COMPLETE_MIGRATION_CHECKLIST.md` exactly**
- Phase 1: Database Migration
- Phase 2: SQL Abstraction
- Phase 3: Notification Migration
### 3. Validation Loop
```bash
# After each phase, validate progress
scripts/validate-migration.sh
scripts/validate-notification-completeness.sh
npm run lint-fix
```
### 4. Human Testing
- Component functional testing
- Cross-platform validation
- Error scenario testing
### 5. Documentation
- Update testing tracker
- Create migration documentation
- Mark as complete
## 🚨 Common Oversights
### ❌ Incomplete Patterns
1. **Partial Database Migration**: Mixin imported but legacy calls remain
2. **Missing SQL Abstraction**: Database migrated but raw SQL remains
3. **Forgotten Notifications**: Database/SQL done but `$notify()` calls remain
### ✅ Success Indicators
1. **Zero Legacy Patterns**: No `databaseUtil`, raw SQL, or `$notify()` calls
2. **Validation Clean**: All scripts pass without issues
3. **Functional Testing**: All features work correctly
4. **Documentation Complete**: Migration recorded and tracked
## 🎯 Current Status
### Migration Statistics
Run these commands for current status:
```bash
scripts/validate-migration.sh | grep "Migration percentage"
scripts/validate-notification-completeness.sh | grep "Summary"
```
### Priority Focus
1. **Mixed Pattern Files**: Components with partial migrations
2. **Notification Incomplete**: Components with `$notify()` calls
3. **New Components**: Ensure they follow modern patterns
## 🔧 Troubleshooting
### Component Shows "Mixed Pattern"
```bash
# Check what patterns remain
grep -n "databaseUtil\|logConsoleAndDb\|this\.\$notify" src/path/to/component.vue
```
### Notification Validation Fails
```bash
# Check notification setup
grep -n "createNotifyHelpers\|notify!:\|this\.notify =" src/path/to/component.vue
```
### TypeScript Errors
```bash
# Check compilation
npx tsc --noEmit
npm run lint-fix
```
## 📚 Learning From This Process
### Key Lesson: Systematic Validation
The creation of this process was triggered by forgetting notification migration in DIDView.vue, demonstrating that:
1. **Checklists prevent oversights**
2. **Validation scripts catch mistakes**
3. **Documentation cements requirements**
4. **Multiple validation layers ensure completeness**
### Prevention Strategy
- **Always use the complete checklist**
- **Run all validation scripts**
- **Document every migration**
- **Update tracking systematically**
## 🚀 Next Steps
1. **Complete current mixed patterns** using the established process
2. **Validate all "technically compliant" components** for notification completeness
3. **Establish this as standard process** for all future migrations
4. **Create automated CI checks** to prevent regression
---
**Remember**: This process exists to prevent the exact oversight that occurred with DIDView.vue notification migration. Follow it completely to ensure systematic migration success.
**Author**: Matthew Raymer
**Date**: 2024-01-XX
**Purpose**: Prevent migration oversights through systematic process

30
docs/migration-templates/component-migration.md

@ -235,6 +235,9 @@ this.notify.error(userMessage || "Fallback error message", TIMEOUTS.LONG);
## After Migration Checklist ## After Migration Checklist
⚠️ **CRITICAL**: Use `docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md` for comprehensive validation
### Phase 1: Database Migration
- [ ] All `databaseUtil` imports removed - [ ] All `databaseUtil` imports removed
- [ ] All `logConsoleAndDb` imports removed - [ ] All `logConsoleAndDb` imports removed
- [ ] All direct `PlatformServiceFactory.getInstance()` calls removed - [ ] All direct `PlatformServiceFactory.getInstance()` calls removed
@ -242,14 +245,39 @@ this.notify.error(userMessage || "Fallback error message", TIMEOUTS.LONG);
- [ ] Database operations use mixin methods (`$db`, `$query`, `$getAllContacts`, etc.) - [ ] Database operations use mixin methods (`$db`, `$query`, `$getAllContacts`, etc.)
- [ ] Settings operations use mixin methods (`$settings`, `$saveSettings`) - [ ] Settings operations use mixin methods (`$settings`, `$saveSettings`)
- [ ] Logging uses mixin methods (`$log`, `$logError`, `$logAndConsole`) - [ ] Logging uses mixin methods (`$log`, `$logError`, `$logAndConsole`)
- [ ] **Notification patterns migrated (if applicable)**
### Phase 2: SQL Abstraction (if applicable)
- [ ] All raw SQL queries replaced with service methods
- [ ] Contact operations use `$getContact()`, `$deleteContact()`, `$updateContact()`
- [ ] Settings operations use `$accountSettings()`, `$saveSettings()`
- [ ] **NO raw SQL queries remain** (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
### Phase 3: Notification Migration (if applicable)
- [ ] `createNotifyHelpers` imported and initialized
- [ ] `notify!` property declared and created in `created()`
- [ ] **All `this.$notify()` calls replaced with helper methods** - [ ] **All `this.$notify()` calls replaced with helper methods**
- [ ] **Hardcoded timeouts replaced with `TIMEOUTS` constants** - [ ] **Hardcoded timeouts replaced with `TIMEOUTS` constants**
- [ ] **Static messages use notification constants from `@/constants/notifications`** - [ ] **Static messages use notification constants from `@/constants/notifications`**
- [ ] **Dynamic messages use literal strings appropriately** - [ ] **Dynamic messages use literal strings appropriately**
### Final Validation
- [ ] Error handling includes component name context - [ ] Error handling includes component name context
- [ ] Component compiles without TypeScript errors - [ ] Component compiles without TypeScript errors
- [ ] Component functionality works as expected - [ ] Component functionality works as expected
- [ ] `scripts/validate-migration.sh` shows "Technically Compliant"
- [ ] `scripts/validate-notification-completeness.sh` shows as complete
### Validation Commands
```bash
# Check overall migration status
scripts/validate-migration.sh
# Check notification migration completeness
scripts/validate-notification-completeness.sh
# Check for compilation errors
npm run lint-fix
```
## Testing Migration ## Testing Migration

130
docs/migration-testing/DIDVIEW_MIGRATION.md

@ -0,0 +1,130 @@
# DIDView.vue Database Migration Documentation
## Overview
DIDView.vue migration from mixed pattern to technically compliant by replacing legacy `databaseUtil` calls with PlatformServiceMixin methods.
## Migration Details
### File Information
- **File**: `src/views/DIDView.vue`
- **Size**: 940 lines
- **Migration Type**: Database utility migration
- **Complexity**: Low (only 2 calls to replace)
### Issues Found
1. `import * as databaseUtil from "../db/databaseUtil";` (line 268)
2. `databaseUtil.retrieveSettingsForActiveAccount()` (line 357)
3. `databaseUtil.mapQueryResultToValues()` (line 408)
### Changes Made
#### 1. Removed Legacy Import
```typescript
// ❌ BEFORE
import * as databaseUtil from "../db/databaseUtil";
// ✅ AFTER
// (removed - no longer needed)
```
#### 2. Replaced retrieveSettingsForActiveAccount()
```typescript
// ❌ BEFORE
private async initializeSettings() {
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}
// ✅ AFTER
private async initializeSettings() {
const settings = await this.$accountSettings();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}
```
#### 3. Replaced mapQueryResultToValues()
```typescript
// ❌ BEFORE
const dbContacts = await this.$dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[this.viewingDid],
);
const contacts = databaseUtil.mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
// ✅ AFTER
const dbContacts = await this.$dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[this.viewingDid],
);
const contacts = this.$mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
```
## Pre-Migration Status
- **Status**: Mixed Pattern File
- **Issues**: 2 legacy databaseUtil calls + 1 import
- **PlatformServiceMixin**: Already imported and configured
## Post-Migration Status
- **Status**: ✅ Technically Compliant
- **Issues**: 0 (all legacy patterns removed)
- **Validation**: Passes migration validation script
- **Linting**: No new errors introduced
## Validation Results
### Before Migration
```
Mixed pattern files: 3
- HomeView.vue
- DIDView.vue ← Target file
- ContactsView.vue
```
### After Migration
```
Mixed pattern files: 1
- ContactsView.vue
Technically compliant files: 17
- DIDView.vue ← Successfully migrated
- (16 others)
```
## Testing Requirements
DIDView.vue is now ready for human testing:
1. Test DID viewing functionality
2. Verify contact information display
3. Check visibility controls
4. Test registration functionality
5. Verify claims loading
6. Test contact deletion
## Next Steps
1. **Human testing**: DIDView.vue is ready for user testing
2. **Final migration**: Only ContactsView.vue remains (7 logConsoleAndDb calls)
3. **100% compliance**: Within reach after ContactsView.vue migration
## Migration Pattern Used
This migration followed the established pattern:
1. **Verify PlatformServiceMixin** is already imported and configured
2. **Remove legacy import** (`import * as databaseUtil`)
3. **Replace method calls** with mixin equivalents
4. **Validate changes** using migration validation script
5. **Check linting** to ensure no new errors
## Author
Matthew Raymer
## Date
2024-01-XX
## Related Files
- `src/views/DIDView.vue` - Migrated file
- `src/utils/PlatformServiceMixin.ts` - Mixin providing replacement methods
- `docs/migration-testing/HUMAN_TESTING_TRACKER.md` - Testing status tracker

186
docs/migration-testing/HUMAN_TESTING_TRACKER.md

@ -1,121 +1,65 @@
# Human Testing Tracker # Human Testing Tracker for PlatformServiceMixin Migration
## Overview ## Testing Status
This document tracks the human testing status for PlatformServiceMixin migration. Files are categorized by their testing status and compliance level.
### ✅ Completed Testing
## Testing Status Categories | Component | Migration Status | Human Testing | Notes |
|-----------|------------------|---------------|-------|
### ✅ **Confirmed Human Tested** (User Approved) | ClaimAddRawView.vue | ✅ Technically Compliant | ✅ Tested | Initial reference implementation |
Files that have been human tested and confirmed by the user. | LogView.vue | ✅ Technically Compliant | ✅ Tested | Database migration validated |
| HomeView.vue | ✅ Fully Modern | ✅ Tested | Database + Notifications migrated |
| Component | Date Tested | Status | Notes |
|-----------|-------------|--------|-------| ### 🔄 Ready for Testing
| `src/views/ClaimAddRawView.vue` | 2025-07-06 | ✅ **PASSED** | User confirmed: "passed a superficial human test" | | Component | Migration Status | Database Migration | Notification Migration | Notes |
| `src/views/LogView.vue` | 2025-07-06 | ✅ **PASSED** | Comprehensive testing completed | |-----------|------------------|-------------------|----------------------|-------|
| App.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
### ⚠️ **Awaiting Human Testing** (Technically Compliant) | AccountViewView.vue | ✅ Technically Compliant | ✅ Complete | ✅ Complete | Ready for testing |
Files that are technically compliant but require human testing validation before being fully cleared. | ClaimView.vue | ✅ Technically Compliant | ✅ Complete | ✅ Complete | Ready for testing |
| ShareMyContactInfoView.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| Component | Migration Status | Testing Guide | Priority | | ContactImportView.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
|-----------|------------------|---------------|----------| | DeepLinkErrorView.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/components/MembersList.vue` | ✅ **COMPLIANT** | `docs/migration-testing/migration-checklist-MembersList.md` | 🔴 HIGH | | DataExportSection.vue | ✅ Technically Compliant | ✅ Complete | ✅ Complete | Ready for testing |
| `src/components/DataExportSection.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | TopMessage.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/components/FeedFilters.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | MembersList.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/components/TopMessage.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | FeedFilters.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/components/GiftedDialog.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | GiftedDialog.vue | ✅ Technically Compliant | ✅ Complete | ✅ Complete | Ready for testing |
| `src/components/UserNameDialog.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | UserNameDialog.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/App.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | PlatformServiceMixinTest.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/views/AccountViewView.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | | DIDView.vue | ✅ Technically Compliant | ✅ Complete | N/A | Ready for testing |
| `src/views/ShareMyContactInfoView.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM |
| `src/views/ClaimView.vue` | ✅ **COMPLIANT** | *Need to create* | 🟡 MEDIUM | ### 🚧 In Progress
| Component | Current Status | Issue | Next Steps |
### 🔄 **Mixed Pattern Files** (Require Migration) |-----------|---------------|-------|------------|
Files that have both modern and legacy patterns - these need migration completion before human testing. | ContactsView.vue | 🔄 Mixed Pattern | 7 logConsoleAndDb calls | Migrate to PlatformServiceMixin |
| Component | Legacy Issues | Migration Guide | Priority | ## Next Priority: ContactsView.vue
|-----------|---------------|-----------------|----------| - **File**: `src/views/ContactsView.vue` (1538 lines)
| `src/views/HomeView.vue` | `logConsoleAndDb` usage | *Need to create* | 🔴 HIGH | - **Issues**: 7 legacy `logConsoleAndDb()` calls + 1 import
| `src/views/DIDView.vue` | `databaseUtil` usage | *Need to create* | 🔴 HIGH | - **Complexity**: Medium (large file, multiple error contexts)
| `src/views/ContactsView.vue` | `logConsoleAndDb` usage | *Need to create* | 🔴 HIGH | - **Required changes**: Replace with `this.$logAndConsole()` calls + notification migration
## Human Testing Process ## Testing Instructions
### For User: Testing Validation Protocol ### For Components Ready for Testing
1. **Component Access**: Use testing guide to access component 1. Run component in development environment
2. **Functional Testing**: Verify core functionality works correctly 2. Test core functionality
3. **Error Testing**: Test error scenarios and edge cases 3. Verify no console errors
4. **Cross-Platform**: Test on web, mobile, desktop (if applicable) 4. Check that platform services work correctly
5. **Approval**: Confirm testing results with status: 5. Validate database operations (if applicable)
- ✅ **PASSED** - Component works correctly 6. Test notifications (if applicable)
- ⚠️ **ISSUES** - Component has issues requiring attention
- ❌ **FAILED** - Component has breaking issues ### For Mixed Pattern Components
1. Complete database migration first
### For Developer: Testing Documentation 2. Run immediate validation
1. **Create Testing Guide**: `docs/migration-testing/TESTING_[Component].md` 3. Check for notification migration needs
2. **Document Test Cases**: Functional, error, cross-platform scenarios 4. Complete full testing cycle
3. **Provide Test URLs**: Direct links for easy testing
4. **Update This Tracker**: Add component to awaiting testing list ## Update Process
- Mark components as tested when human validation is complete
## Updating This Tracker - Move completed components to "Completed Testing" section
- Update notes with any issues found during testing
### When User Confirms Testing - Track migration progress and next priorities
1. Move component from "Awaiting Human Testing" to "Confirmed Human Tested"
2. Update the validation script with new confirmed files ---
3. Document testing results and any issues found *Last updated: 2024-01-XX*
*Next component: ContactsView.vue (FINAL mixed pattern file!)*
### When Adding New Technically Compliant Files
1. Add to "Awaiting Human Testing" section
2. Create or reference testing guide
3. Update validation script if needed
## Validation Script Integration
The validation script (`scripts/validate-migration.sh`) uses this tracker to:
- Identify files requiring human testing
- Report on testing completion status
- Distinguish between technically compliant and fully tested files
### Human Tested Files (for validation script)
```bash
human_tested_files="
src/views/ClaimAddRawView.vue
src/views/LogView.vue
"
```
## Statistics
### Current Status (Last Updated: 2025-07-07)
- **Total Technically Compliant**: 12 files
- **Human Tested**: 2 files (17%)
- **Awaiting Testing**: 10 files (83%)
- **Mixed Pattern**: 3 files (require migration first)
### Testing Completion Rate
- **Target**: 100% of technically compliant files tested
- **Current**: 17% completion rate
- **Remaining**: 10 files need human testing validation
## Next Steps
### High Priority Testing (This Week)
1. **MembersList.vue** - Complex component with meeting functionality
2. **DataExportSection.vue** - Data operations component
3. **App.vue** - Core application component
### Medium Priority Testing (Next Week)
1. **FeedFilters.vue** - UI component
2. **TopMessage.vue** - Notification component
3. **GiftedDialog.vue** - Dialog component
### Create Missing Testing Guides
Priority order for creating testing documentation:
1. MembersList.vue (complex functionality)
2. DataExportSection.vue (data operations)
3. App.vue (core application)
## Notes
- Human testing is required for all technically compliant files before they can be considered fully migrated
- Testing guides should be created for all components awaiting human testing
- The validation script should be updated when new files are confirmed as human tested
- This tracker should be updated after each testing session

122
scripts/validate-notification-completeness.sh

@ -0,0 +1,122 @@
#!/bin/bash
# TimeSafari Notification Migration Completeness Validator
# Detects components with incomplete notification migrations
echo "🔔 TimeSafari Notification Migration Validator"
echo "=============================================="
# Function to check if file has raw $notify calls
check_raw_notify() {
local file="$1"
if [[ ! -f "$file" ]]; then
return 1
fi
# Count $notify calls (excluding comments and initialization)
local notify_count=$(grep -v "^[[:space:]]*//\|^[[:space:]]*\*" "$file" | grep -v "createNotifyHelpers(this\.\$notify)" | grep -c "this\.\$notify")
echo "$notify_count"
}
# Function to check if file has notification helpers setup
check_notify_helpers() {
local file="$1"
if [[ ! -f "$file" ]]; then
return 1
fi
# Check for createNotifyHelpers import and usage
local has_import=$(grep -c "createNotifyHelpers" "$file")
local has_property=$(grep -c "notify!:" "$file")
local has_created=$(grep -c "this.notify = createNotifyHelpers" "$file")
if [[ $has_import -gt 0 && $has_property -gt 0 && $has_created -gt 0 ]]; then
echo "complete"
elif [[ $has_import -gt 0 || $has_property -gt 0 || $has_created -gt 0 ]]; then
echo "partial"
else
echo "none"
fi
}
echo "🔍 Scanning for notification migration completeness..."
# Get all Vue components using PlatformServiceMixin
mixin_components=$(grep -l "PlatformServiceMixin" src/**/*.vue 2>/dev/null | sort)
incomplete_migrations=()
partial_migrations=()
complete_migrations=()
for component in $mixin_components; do
notify_count=$(check_raw_notify "$component")
helper_status=$(check_notify_helpers "$component")
if [[ $notify_count -gt 0 ]]; then
if [[ "$helper_status" == "none" ]]; then
incomplete_migrations+=("$component ($notify_count \$notify calls, no helpers)")
elif [[ "$helper_status" == "partial" ]]; then
partial_migrations+=("$component ($notify_count \$notify calls, partial helpers)")
else
incomplete_migrations+=("$component ($notify_count \$notify calls, but has helpers - mixed pattern)")
fi
else
if [[ "$helper_status" == "complete" ]]; then
complete_migrations+=("$component")
elif [[ "$helper_status" == "partial" ]]; then
partial_migrations+=("$component (unused helper setup)")
else
complete_migrations+=("$component")
fi
fi
done
# Report results
echo ""
echo "📊 Notification Migration Status Report"
echo "======================================="
if [[ ${#incomplete_migrations[@]} -gt 0 ]]; then
echo "❌ INCOMPLETE NOTIFICATION MIGRATIONS (${#incomplete_migrations[@]} components):"
for item in "${incomplete_migrations[@]}"; do
echo " - $item"
done
echo ""
fi
if [[ ${#partial_migrations[@]} -gt 0 ]]; then
echo "⚠️ PARTIAL NOTIFICATION MIGRATIONS (${#partial_migrations[@]} components):"
for item in "${partial_migrations[@]}"; do
echo " - $item"
done
echo ""
fi
if [[ ${#complete_migrations[@]} -gt 0 ]]; then
echo "✅ COMPLETE NOTIFICATION MIGRATIONS (${#complete_migrations[@]} components):"
for item in "${complete_migrations[@]}"; do
echo " - $item"
done
echo ""
fi
# Summary
total_issues=$((${#incomplete_migrations[@]} + ${#partial_migrations[@]}))
total_components=${#mixin_components[@]}
echo "📈 Summary:"
echo " Total PlatformServiceMixin components: $total_components"
echo " Complete notification migrations: ${#complete_migrations[@]}"
echo " Incomplete/partial migrations: $total_issues"
if [[ $total_issues -gt 0 ]]; then
echo ""
echo "🚨 ACTION REQUIRED:"
echo " $total_issues components need notification migration completion"
echo " Follow: docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md"
exit 1
else
echo ""
echo "🎉 ALL NOTIFICATION MIGRATIONS COMPLETE!"
exit 0
fi

45
src/constants/notifications.ts

@ -25,3 +25,48 @@ export const NOTIFY_CONFIRMATION_ERROR = {
title: "Error", title: "Error",
message: "There was a problem submitting the confirmation.", message: "There was a problem submitting the confirmation.",
}; };
export const NOTIFY_DEFAULT_TO_ACTIVE_DID = {
title: "Your Info",
message: "No user was specified so showing your info.",
};
export const NOTIFY_CONTACT_DELETED = {
title: "Deleted",
message: "Contact has been removed.",
};
export const NOTIFY_CONTACT_DELETE_FAILED = {
title: "Error",
message: "Failed to delete contact.",
};
export const NOTIFY_REGISTRATION_SUCCESS = {
title: "Registration Success",
message: "has been registered.",
};
export const NOTIFY_REGISTRATION_ERROR = {
title: "Registration Error",
message: "Something went wrong during registration.",
};
export const NOTIFY_SERVER_ACCESS_ERROR = {
title: "Error",
message: "There was a problem accessing the server. Try again later.",
};
export const NOTIFY_NO_IDENTITY_ERROR = {
title: "No Identity",
message: "There is no identity to use to check visibility.",
};
export const NOTIFY_VISIBILITY_SET = {
title: "Visibility Set",
message: "visibility updated.",
};
export const NOTIFY_VISIBILITY_REFRESHED = {
title: "Visibility Refreshed",
message: "visibility status updated.",
};

45
src/utils/PlatformServiceMixin.ts

@ -913,6 +913,47 @@ export const PlatformServiceMixin = {
})); }));
}, },
/**
* Get single contact by DID - $getContact()
* Eliminates verbose single contact query patterns
* @param did Contact DID to retrieve
* @returns Promise<Contact | null> Contact object or null if not found
*/
async $getContact(did: string): Promise<Contact | null> {
const results = await this.$dbQuery(
"SELECT * FROM contacts WHERE did = ?",
[did],
);
if (!results || !results.values || results.values.length === 0) {
return null;
}
const contactData = this._mapColumnsToValues(
results.columns,
results.values,
);
return contactData.length > 0 ? (contactData[0] as Contact) : null;
},
/**
* Delete contact by DID - $deleteContact()
* Eliminates verbose contact deletion patterns
* @param did Contact DID to delete
* @returns Promise<boolean> Success status
*/
async $deleteContact(did: string): Promise<boolean> {
try {
await this.$dbExec("DELETE FROM contacts WHERE did = ?", [did]);
// Invalidate contacts cache
this._invalidateCache("contacts_all");
return true;
} catch (error) {
logger.error("[PlatformServiceMixin] Error deleting contact:", error);
return false;
}
},
/** /**
* Generic entity insertion - $insertEntity() * Generic entity insertion - $insertEntity()
* Eliminates verbose INSERT patterns for any entity * Eliminates verbose INSERT patterns for any entity
@ -1197,6 +1238,8 @@ export interface IPlatformServiceMixin {
$insertContact(contact: Partial<Contact>): Promise<boolean>; $insertContact(contact: Partial<Contact>): Promise<boolean>;
$updateContact(did: string, changes: Partial<Contact>): Promise<boolean>; $updateContact(did: string, changes: Partial<Contact>): Promise<boolean>;
$getAllContacts(): Promise<Contact[]>; $getAllContacts(): Promise<Contact[]>;
$getContact(did: string): Promise<Contact | null>;
$deleteContact(did: string): Promise<boolean>;
$contactCount(): Promise<number>; $contactCount(): Promise<number>;
$insertEntity( $insertEntity(
tableName: string, tableName: string,
@ -1316,6 +1359,8 @@ declare module "@vue/runtime-core" {
$insertContact(contact: Partial<Contact>): Promise<boolean>; $insertContact(contact: Partial<Contact>): Promise<boolean>;
$updateContact(did: string, changes: Partial<Contact>): Promise<boolean>; $updateContact(did: string, changes: Partial<Contact>): Promise<boolean>;
$getAllContacts(): Promise<Contact[]>; $getAllContacts(): Promise<Contact[]>;
$getContact(did: string): Promise<Contact | null>;
$deleteContact(did: string): Promise<boolean>;
$insertEntity( $insertEntity(
tableName: string, tableName: string,
entity: Record<string, unknown>, entity: Record<string, unknown>,

365
src/views/DIDView.vue

@ -10,7 +10,7 @@
<!-- Back --> <!-- Back -->
<button <button
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1" class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.go(-1)" @click="goBack"
> >
<font-awesome icon="chevron-left" class="fa-fw"></font-awesome> <font-awesome icon="chevron-left" class="fa-fw"></font-awesome>
</button> </button>
@ -32,10 +32,7 @@
<font-awesome icon="pen" class="text-sm text-blue-500 ml-2 mb-1" /> <font-awesome icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
</router-link> </router-link>
</h2> </h2>
<button <button class="ml-2 mr-2 mt-4" @click="toggleDidDetails">
class="ml-2 mr-2 mt-4"
@click="showDidDetails = !showDidDetails"
>
Details Details
<font-awesome <font-awesome
v-if="showDidDetails" v-if="showDidDetails"
@ -60,7 +57,7 @@
:icon-size="96" :icon-size="96"
:profile-image-url="contactFromDid?.profileImageUrl" :profile-image-url="contactFromDid?.profileImageUrl"
class="inline-block align-text-bottom border border-slate-300 rounded" class="inline-block align-text-bottom border border-slate-300 rounded"
@click="showLargeIdenticonUrl = contactFromDid?.profileImageUrl" @click="showLargeProfileImage"
/> />
</span> </span>
</div> </div>
@ -160,7 +157,7 @@
:entity-id="viewingDid" :entity-id="viewingDid"
:icon-size="64" :icon-size="64"
class="inline-block align-middle border border-slate-300 rounded-md mr-1" class="inline-block align-middle border border-slate-300 rounded-md mr-1"
@click="showLargeIdenticonId = viewingDid" @click="showLargeIdenticon"
/> />
</div> </div>
</div> </div>
@ -177,10 +174,7 @@
:icon-size="512" :icon-size="512"
:profile-image-url="showLargeIdenticonUrl" :profile-image-url="showLargeIdenticonUrl"
class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg" class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
@click=" @click="hideLargeImage"
showLargeIdenticonId = undefined;
showLargeIdenticonUrl = undefined;
"
/> />
</div> </div>
</div> </div>
@ -266,7 +260,7 @@ import TopMessage from "../components/TopMessage.vue";
import { NotificationIface } from "../constants/app"; import { NotificationIface } from "../constants/app";
import { Contact } from "../db/tables/contacts"; import { Contact } from "../db/tables/contacts";
import { BoundingBox } from "../db/tables/settings"; import { BoundingBox } from "../db/tables/settings";
import * as databaseUtil from "../db/databaseUtil";
import { import {
GenericCredWrapper, GenericCredWrapper,
GenericVerifiableCredential, GenericVerifiableCredential,
@ -284,6 +278,16 @@ import * as libsUtil from "../libs/util";
import EntityIcon from "../components/EntityIcon.vue"; import EntityIcon from "../components/EntityIcon.vue";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import {
NOTIFY_DEFAULT_TO_ACTIVE_DID,
NOTIFY_CONTACT_DELETED,
NOTIFY_CONTACT_DELETE_FAILED,
NOTIFY_REGISTRATION_SUCCESS,
NOTIFY_REGISTRATION_ERROR,
NOTIFY_SERVER_ACCESS_ERROR,
NOTIFY_NO_IDENTITY_ERROR,
} from "@/constants/notifications";
/** /**
* DIDView Component * DIDView Component
@ -310,6 +314,8 @@ export default class DIDView extends Vue {
$route!: RouteLocationNormalizedLoaded; $route!: RouteLocationNormalizedLoaded;
$router!: Router; $router!: Router;
notify!: ReturnType<typeof createNotifyHelpers>;
libsUtil = libsUtil; libsUtil = libsUtil;
yaml = yaml; yaml = yaml;
@ -331,6 +337,13 @@ export default class DIDView extends Vue {
didInfoForContact = didInfoForContact; didInfoForContact = didInfoForContact;
displayAmount = displayAmount; displayAmount = displayAmount;
/**
* Initializes notification helpers
*/
created() {
this.notify = createNotifyHelpers(this.$notify);
}
/** /**
* Initializes the view with DID information * Initializes the view with DID information
* *
@ -355,7 +368,7 @@ export default class DIDView extends Vue {
* Initializes component settings from active account * Initializes component settings from active account
*/ */
private async initializeSettings() { private async initializeSettings() {
const settings = await databaseUtil.retrieveSettingsForActiveAccount(); const settings = await this.$accountSettings();
this.activeDid = settings.activeDid || ""; this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || ""; this.apiServer = settings.apiServer || "";
} }
@ -384,14 +397,10 @@ export default class DIDView extends Vue {
* Notifies user that we're showing their DID info by default * Notifies user that we're showing their DID info by default
*/ */
private notifyDefaultToActiveDID() { private notifyDefaultToActiveDID() {
this.$notify( this.notify.toast(
{ NOTIFY_DEFAULT_TO_ACTIVE_DID.title,
group: "alert", NOTIFY_DEFAULT_TO_ACTIVE_DID.message,
type: "toast", TIMEOUTS.SHORT,
title: "Your Info",
text: "No user was specified so showing your info.",
},
3000,
); );
} }
@ -402,17 +411,10 @@ export default class DIDView extends Vue {
private async loadContactInformation() { private async loadContactInformation() {
if (!this.viewingDid) return; if (!this.viewingDid) return;
const dbContacts = await this.$dbQuery( const contact = await this.$getContact(this.viewingDid);
"SELECT * FROM contacts WHERE did = ?",
[this.viewingDid],
);
const contacts = databaseUtil.mapQueryResultToValues(
dbContacts,
) as unknown as Contact[];
// Safely check if contact exists before assigning if (contact) {
if (contacts && contacts.length > 0) { this.contactFromDid = contact;
this.contactFromDid = contacts[0];
this.contactYaml = yaml.dump(this.contactFromDid); this.contactYaml = yaml.dump(this.contactFromDid);
} else { } else {
this.contactFromDid = undefined; this.contactFromDid = undefined;
@ -442,6 +444,33 @@ export default class DIDView extends Vue {
} }
} }
/**
* Navigation helper methods
*/
goBack() {
this.$router.go(-1);
}
/**
* UI state helper methods
*/
toggleDidDetails() {
this.showDidDetails = !this.showDidDetails;
}
showLargeProfileImage() {
this.showLargeIdenticonUrl = this.contactFromDid?.profileImageUrl;
}
showLargeIdenticon() {
this.showLargeIdenticonId = this.viewingDid;
}
hideLargeImage() {
this.showLargeIdenticonId = undefined;
this.showLargeIdenticonUrl = undefined;
}
/** /**
* Prompts user to confirm contact deletion * Prompts user to confirm contact deletion
* Shows additional warning if contact has visibility permissions * Shows additional warning if contact has visibility permissions
@ -457,18 +486,9 @@ export default class DIDView extends Vue {
message += message +=
" Note that they can see your activity, so if you want to hide your activity from them then you should do that first."; " Note that they can see your activity, so if you want to hide your activity from them then you should do that first.";
} }
this.$notify( this.notify.confirm(message, async () => {
{ await this.deleteContact(contact);
group: "modal", });
type: "confirm",
title: "Delete",
text: message,
onYes: async () => {
await this.deleteContact(contact);
},
},
-1,
);
} }
/** /**
@ -477,17 +497,13 @@ export default class DIDView extends Vue {
* @param contact - Contact object to be deleted * @param contact - Contact object to be deleted
*/ */
async deleteContact(contact: Contact) { async deleteContact(contact: Contact) {
await this.$dbExec("DELETE FROM contacts WHERE did = ?", [contact.did]); const success = await this.$deleteContact(contact.did);
this.$notify( if (success) {
{ this.notify.success(NOTIFY_CONTACT_DELETED.message, TIMEOUTS.SHORT);
group: "alert", this.$router.push({ name: "contacts" });
type: "success", } else {
title: "Deleted", this.notify.error(NOTIFY_CONTACT_DELETE_FAILED.message, TIMEOUTS.LONG);
text: "Contact has been removed.", }
},
3000,
);
this.$router.push({ name: "contacts" });
} }
/** /**
@ -497,24 +513,16 @@ export default class DIDView extends Vue {
* @param contact - Contact to be registered * @param contact - Contact to be registered
*/ */
async confirmRegister(contact: Contact) { async confirmRegister(contact: Contact) {
this.$notify( const message =
{ "Are you sure you want to register " +
group: "modal", libsUtil.nameForContact(this.contactFromDid, false) +
type: "confirm", (contact.registered
title: "Register", ? " -- especially since they are already marked as registered"
text: : "") +
"Are you sure you want to register " + "?";
libsUtil.nameForContact(this.contactFromDid, false) + this.notify.confirm(message, async () => {
(contact.registered await this.register(contact);
? " -- especially since they are already marked as registered" });
: "") +
"?",
onYes: async () => {
await this.register(contact);
},
},
-1,
);
} }
/** /**
@ -524,7 +532,7 @@ export default class DIDView extends Vue {
* @param contact - Contact to register * @param contact - Contact to register
*/ */
async register(contact: Contact) { async register(contact: Contact) {
this.$notify({ group: "alert", type: "toast", title: "Sent..." }, 1000); this.notify.toast("Processing", "Sent...", TIMEOUTS.SHORT);
try { try {
const regResult = await register( const regResult = await register(
@ -535,32 +543,17 @@ export default class DIDView extends Vue {
); );
if (regResult.success) { if (regResult.success) {
contact.registered = true; contact.registered = true;
await this.$dbExec("UPDATE contacts SET registered = ? WHERE did = ?", [ await this.$updateContact(contact.did, { registered: true });
true,
contact.did, const name = contact.name || "That unnamed person";
]); this.notify.success(
`${name} ${NOTIFY_REGISTRATION_SUCCESS.message}`,
this.$notify( TIMEOUTS.LONG,
{
group: "alert",
type: "success",
title: "Registration Success",
text:
(contact.name || "That unnamed person") + " has been registered.",
},
5000,
); );
} else { } else {
this.$notify( this.notify.error(
{ (regResult.error as string) || NOTIFY_REGISTRATION_ERROR.message,
group: "alert", TIMEOUTS.LONG,
type: "danger",
title: "Registration Error",
text:
(regResult.error as string) ||
"Something went wrong during registration.",
},
5000,
); );
} }
} catch (error) { } catch (error) {
@ -582,15 +575,7 @@ export default class DIDView extends Vue {
userMessage = error as string; userMessage = error as string;
} }
// Now set that error for the user to see. // Now set that error for the user to see.
this.$notify( this.notify.error(userMessage, TIMEOUTS.LONG);
{
group: "alert",
type: "danger",
title: "Registration Error",
text: userMessage,
},
5000,
);
} }
} }
@ -624,15 +609,7 @@ export default class DIDView extends Vue {
if (response.status !== 200) { if (response.status !== 200) {
const details = await response.text(); const details = await response.text();
logger.error("Problem with full search:", details); logger.error("Problem with full search:", details);
this.$notify( this.notify.error(NOTIFY_SERVER_ACCESS_ERROR.message, TIMEOUTS.LONG);
{
group: "alert",
type: "danger",
title: "Error",
text: `There was a problem accessing the server. Try again later.`,
},
5000,
);
return; return;
} }
@ -642,14 +619,9 @@ export default class DIDView extends Vue {
} catch (e: unknown) { } catch (e: unknown) {
logger.error("Error with feed load:", e); logger.error("Error with feed load:", e);
const error = e as { userMessage?: string }; const error = e as { userMessage?: string };
this.$notify( this.notify.error(
{ error.userMessage || "There was a problem retrieving claims.",
group: "alert", TIMEOUTS.SHORT,
type: "danger",
title: "Error",
text: error.userMessage || "There was a problem retrieving claims.",
},
3000,
); );
} finally { } finally {
this.isLoading = false; this.isLoading = false;
@ -728,21 +700,12 @@ export default class DIDView extends Vue {
const visibilityPrompt = visibility const visibilityPrompt = visibility
? "Are you sure you want to make your activity visible to them?" ? "Are you sure you want to make your activity visible to them?"
: "Are you sure you want to hide all your activity from them?"; : "Are you sure you want to hide all your activity from them?";
this.$notify( this.notify.confirm(visibilityPrompt, async () => {
{ const success = await this.setVisibility(contact, visibility, true);
group: "modal", if (success) {
type: "confirm", contact.seesMe = visibility; // didn't work inside setVisibility
title: "Set Visibility", }
text: visibilityPrompt, });
onYes: async () => {
const success = await this.setVisibility(contact, visibility, true);
if (success) {
contact.seesMe = visibility; // didn't work inside setVisibility
}
},
},
-1,
);
} }
/** /**
@ -758,27 +721,16 @@ export default class DIDView extends Vue {
visibility: boolean, visibility: boolean,
showSuccessAlert: boolean, showSuccessAlert: boolean,
) { ) {
// TODO: Implement proper visibility setting using mixin methods // Update contact visibility using mixin method
// For now, just update local database await this.$updateContact(contact.did, { seesMe: visibility });
await this.$dbExec("UPDATE contacts SET seesMe = ? WHERE did = ?", [
visibility,
contact.did,
]);
if (showSuccessAlert) { if (showSuccessAlert) {
this.$notify( const message =
{ (contact.name || "That user") +
group: "alert", " can " +
type: "success", (visibility ? "" : "not ") +
title: "Visibility Set", "see your activity.";
text: this.notify.success(message, TIMEOUTS.SHORT);
(contact.name || "That user") +
" can " +
(visibility ? "" : "not ") +
"see your activity.",
},
3000,
);
} }
return true; return true;
} }
@ -796,15 +748,7 @@ export default class DIDView extends Vue {
encodeURIComponent(contact.did); encodeURIComponent(contact.did);
const headers = await getHeaders(this.activeDid); const headers = await getHeaders(this.activeDid);
if (!headers["Authorization"]) { if (!headers["Authorization"]) {
this.$notify( this.notify.error(NOTIFY_NO_IDENTITY_ERROR.message, TIMEOUTS.SHORT);
{
group: "alert",
type: "danger",
title: "No Identity",
text: "There is no identity to use to check visibility.",
},
3000,
);
return; return;
} }
@ -814,48 +758,22 @@ export default class DIDView extends Vue {
const visibility = resp.data; const visibility = resp.data;
contact.seesMe = visibility; contact.seesMe = visibility;
//console.log("Visi check:", visibility, contact.seesMe, contact.did); //console.log("Visi check:", visibility, contact.seesMe, contact.did);
await this.$dbExec("UPDATE contacts SET seesMe = ? WHERE did = ?", [ await this.$updateContact(contact.did, { seesMe: visibility });
visibility,
contact.did, const message =
]); libsUtil.nameForContact(contact, true) +
" can" +
this.$notify( (visibility ? "" : " not") +
{ " see your activity.";
group: "alert", this.notify.info(message, TIMEOUTS.SHORT);
type: "info",
title: "Visibility Refreshed",
text:
libsUtil.nameForContact(contact, true) +
" can" +
(visibility ? "" : " not") +
" see your activity.",
},
3000,
);
} else { } else {
logger.error("Got bad server response checking visibility:", resp); logger.error("Got bad server response checking visibility:", resp);
const message = resp.data.error?.message || "Got bad server response."; const message = resp.data.error?.message || "Got bad server response.";
this.$notify( this.notify.error(message, TIMEOUTS.LONG);
{
group: "alert",
type: "danger",
title: "Error Checking Visibility",
text: message,
},
5000,
);
} }
} catch (err) { } catch (err) {
logger.error("Caught error from request to check visibility:", err); logger.error("Caught error from request to check visibility:", err);
this.$notify( this.notify.error("Check connectivity and try again.", TIMEOUTS.SHORT);
{
group: "alert",
type: "danger",
title: "Error Checking Visibility",
text: "Check connectivity and try again.",
},
3000,
);
} }
} }
@ -869,21 +787,12 @@ export default class DIDView extends Vue {
const contentVisibilityPrompt = view const contentVisibilityPrompt = view
? "Are you sure you want to see their content?" ? "Are you sure you want to see their content?"
: "Are you sure you want to hide their content from you?"; : "Are you sure you want to hide their content from you?";
this.$notify( this.notify.confirm(contentVisibilityPrompt, async () => {
{ const success = await this.setViewContent(contact, view);
group: "modal", if (success) {
type: "confirm", contact.iViewContent = view; // see visibility note about not working inside setVisibility
title: "Set Content Visibility", }
text: contentVisibilityPrompt, });
onYes: async () => {
const success = await this.setViewContent(contact, view);
if (success) {
contact.iViewContent = view; // see visibility note about not working inside setVisibility
}
},
},
-1,
);
} }
/** /**
@ -894,22 +803,12 @@ export default class DIDView extends Vue {
* @returns Boolean indicating success * @returns Boolean indicating success
*/ */
async setViewContent(contact: Contact, visibility: boolean) { async setViewContent(contact: Contact, visibility: boolean) {
await this.$dbExec("UPDATE contacts SET iViewContent = ? WHERE did = ?", [ await this.$updateContact(contact.did, { iViewContent: visibility });
visibility, const message =
contact.did, "You will" +
]); (visibility ? "" : " not") +
this.$notify( ` see ${contact.name}'s activity.`;
{ this.notify.success(message, TIMEOUTS.SHORT);
group: "alert",
type: "success",
title: "Visibility Set",
text:
"You will" +
(visibility ? "" : " not") +
` see ${contact.name}'s activity.`,
},
3000,
);
return true; return true;
} }
} }

Loading…
Cancel
Save