Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,924 @@
# Profile Incomplete Configuration Reference
This document provides comprehensive documentation on the `profile_incomplete` configuration system, including how it's evaluated, enforced, and where it's used throughout the application.
## Table of Contents
1. [Overview](#overview)
2. [Configuration Structure](#configuration-structure)
3. [Evaluation Logic](#evaluation-logic)
4. [Enforcement Locations](#enforcement-locations)
5. [Related Profile States](#related-profile-states)
6. [Implementation Status](#implementation-status)
7. [Testing](#testing)
8. [Configuration Examples](#configuration-examples)
---
## Overview
The `profile_incomplete` configuration system provides a mechanism to identify and optionally hide profiles that lack sufficient information. This helps ensure that only profiles with adequate content appear in search results and other discovery features.
### Purpose
- Encourage users to complete their profiles with meaningful content
- Filter incomplete profiles from search results and messaging
- Maintain a quality threshold for publicly visible profiles
- Allow administrators to still view and manage incomplete profiles
---
## Configuration Structure
### Location
Configuration is defined in:
- `config/timebank-default.php.example` (lines 200-208)
- `config/timebank_cc.php.example` (lines 186-194)
- Active config loaded via `TIMEBANK_CONFIG` environment variable
### Settings
```php
'profile_incomplete' => [
// Visibility settings
'messenger_hidden' => true, // Not searchable in chat messenger
'profile_search_hidden' => true, // Hidden from main search bar
'profile_hidden' => true, // Profile page access control
'profile_labeled' => true, // Show "incomplete" label on profile
'show_warning_modal' => true, // Show warning modal when viewing own incomplete profile
// Completion criteria - fields
'check_fields' => [
'about', // Extended description field
'about_short', // Short description field
'motivation', // Motivation/why joining field
'cyclos_skills', // Skills/services offered field
],
'check_fields_min_total_length' => 100, // Min total characters across all fields
// Completion criteria - relations
'check_relations' => [
'tags', // Skill tags
'languages', // Spoken languages
'locations', // Geographic locations
],
],
```
### Completion Criteria
A profile is considered **COMPLETE** when **ALL THREE** of these conditions are met:
1. ✓ At least one field from `check_fields` has data
2. ✓ Total character length across all `check_fields``check_fields_min_total_length` (default: 100)
3. ✓ At least one relation from `check_relations` exists (tags, languages, OR locations)
If any condition fails, the profile is marked as **INCOMPLETE**.
---
## Evaluation Logic
### Primary Method: `hasIncompleteProfile()`
**Location:** `app/Traits/ProfileTrait.php:264-310`
**Usage:**
```php
$user = User::find($id);
$isIncomplete = $user->hasIncompleteProfile($user);
```
**Algorithm:**
```php
public function hasIncompleteProfile($model)
{
$config = timebank_config('profile_incomplete');
if (!$config) {
return false; // No config = assume complete
}
// 1. Check fields
$hasFieldData = false;
$totalFieldLength = 0;
foreach ($config['check_fields'] as $field) {
if (!empty($model->{$field})) {
$hasFieldData = true;
$totalFieldLength += strlen(trim($model->{$field}));
}
}
// 2. Check minimum length requirement
$meetsMinLength = $totalFieldLength >= $config['check_fields_min_total_length'];
// 3. Check relations
$hasRelationData = false;
foreach ($config['check_relations'] as $relation) {
if (!$model->relationLoaded($relation)) {
$model->load($relation);
}
if (!$model->{$relation}->isEmpty()) {
$hasRelationData = true;
break;
}
}
// Complete when ALL three conditions are met
$isComplete = $hasFieldData && $meetsMinLength && $hasRelationData;
// Return true if incomplete, false if complete
return !$isComplete;
}
```
**Performance Notes:**
- Lazy-loads relations only if not already loaded
- Exits early on first found relation (OR logic)
- No database queries if relations pre-loaded
---
## Enforcement Locations
### 1. Main Search Bar (ACTIVE)
**Location:** `app/Http/Livewire/MainSearchBar.php:676-684`
**When:** Processing profile search results
**Logic:**
```php
if (
timebank_config('profile_incomplete.profile_search_hidden')
&& method_exists($model, 'hasIncompleteProfile')
&& $model->hasIncompleteProfile($model)
) {
return []; // Exclude from search results
}
```
**Notes:**
- Only enforced for non-Admin/non-Bank users
- Organizations temporarily exempted (line 681-682) for debugging
- Filters out incomplete profiles before they reach the user
**Affected Models:**
- `App\Models\User`
- `App\Models\Organization` (currently exempted)
- `App\Models\Bank`
---
### 2. Browse by Tag Categories (ACTIVE)
**Location:** `app/Http/Livewire/MainBrowseTagCategories.php:523-564`
**Status:** ✓ FULLY IMPLEMENTED
**When:** Filtering profiles during category-based search results
**Implementation:**
```php
private function filterProfile($model, bool $canManageProfiles)
{
if ($canManageProfiles) {
return $model;
}
// Checks profile_inactive
// Checks profile_email_unverified
// Checks deleted_at
// Check incomplete profiles
if (
timebank_config('profile_incomplete.profile_search_hidden')
&& method_exists($model, 'hasIncompleteProfile')
&& $model->hasIncompleteProfile($model)
) {
return null;
}
return $model;
}
```
**Notes:**
- Only enforced for non-Admin/non-Bank users
- Consistent with MainSearchBar implementation
- Filters out incomplete profiles before they reach the user
**Affected Models:**
- `App\Models\User`
- `App\Models\Organization`
- `App\Models\Bank`
---
### 3. Profile Page Access (ACTIVE)
**Configuration:** `profile_incomplete.profile_hidden` and `profile_incomplete.profile_labeled`
**Behavior:**
- When `profile_hidden` is `true`, non-Admin/non-Bank users cannot view the profile page
- Returns "profile not found" view for unauthorized access
- Admins and Banks can always view incomplete profiles
**Current Status:** ✓ FULLY IMPLEMENTED
**Location:** `app/Http/Controllers/ProfileController.php:354-407`
The `getActiveStates()` method checks all profile states:
- `profile_inactive.profile_hidden`
- `profile_email_unverified.profile_hidden`
- `profile_incomplete.profile_hidden`
**Implementation:**
```php
private function getActiveStates($profile)
{
$inactive = false;
$hidden = false;
$inactiveLabel = false;
$inactiveSince = '';
$emailUnverifiedLabel = false;
$incompleteLabel = false;
$removedSince = '';
// ... existing inactive checks ...
// ... existing email_unverified checks ...
// Check incomplete profiles
if (method_exists($profile, 'hasIncompleteProfile') && $profile->hasIncompleteProfile($profile)) {
if (timebank_config('profile_incomplete.profile_hidden')) {
$hidden = true;
}
if (timebank_config('profile_incomplete.profile_labeled')) {
$incompleteLabel = true;
}
}
// ... existing deleted_at checks ...
return compact('inactive', 'hidden', 'inactiveLabel', 'inactiveSince',
'emailUnverifiedLabel', 'incompleteLabel', 'removedSince');
}
```
**How it Works:**
1. Called in `showUser()`, `showOrganization()`, and `showBank()` methods
2. Sets `$hidden = true` when profile is incomplete and config enabled
3. Admin override applied in calling methods (lines 88-95, 155-162, 224-231)
4. When `$hidden && !$canManageProfiles`, returns `profile.not_found` view
**Affected Models:**
- `App\Models\User`
- `App\Models\Organization`
- `App\Models\Bank`
---
### 4. Profile Labels (FULLY IMPLEMENTED)
**Configuration:** `profile_incomplete.profile_labeled`
**Expected Behavior:**
- When `true`, show an "Incomplete Profile" badge/label on the profile page
- Only visible to Admins/Banks who can view incomplete profiles
**Current Status:** ✓ FULLY IMPLEMENTED
**Backend Implementation:** ✓ COMPLETED
- `ProfileController.php:418-425` sets `$incompleteLabel` variable
- Value passed to views via `$states` array (lines 117, 194, 272)
- Available in views as `$incompleteLabel`
**Frontend Implementation:** ✓ COMPLETED
- `resources/views/profile/show.blade.php:18` passes variable to Livewire component
- `resources/views/livewire/profile/show.blade.php:35-49` displays label in top section (near name)
- `resources/views/livewire/profile/show.blade.php:263-267` displays label in activity info section
- Label uses `text-red-700` styling to match inactive/removed profile labels and email unverified labels
**Configuration:**
- Enabled in `config/timebank_cc.php:204` (`profile_labeled => true`)
- Enabled in `config/timebank-default.php:204` (`profile_labeled => true`)
---
### 5. Incomplete Profile Warning Modal (FULLY IMPLEMENTED)
**Configuration:** `profile_incomplete.show_warning_modal`
**Expected Behavior:**
- When `true`, show a modal dialog when user views their own incomplete profile
- Modal explains profile is hidden and provides guidance on completing it
- Only shown when viewing own profile (not when admins/banks view other incomplete profiles)
- Can be dismissed by clicking close button or clicking outside modal
**Current Status:** ✓ FULLY IMPLEMENTED
**Backend Implementation:** ✓ COMPLETED
- `ProfileController.php:115, 214, 315` sets `$showIncompleteWarning` variable based on config
- Checks `profile_incomplete.show_warning_modal` AND profile incompleteness
- Only triggered when viewing own profile
- Implemented in `showUser()`, `showOrganization()`, and `showBank()` methods
- Also implemented in `edit()` method (line 360) for edit pages
**Frontend Implementation:** ✓ COMPLETED
- `resources/views/profile/show.blade.php:24-92` contains modal markup
- `resources/views/profile-user/edit.blade.php:18-86` contains modal for edit pages
- Uses Alpine.js for show/hide functionality
- Includes backdrop with click-outside-to-close
- Displays SidePost content (type: `SiteContents\ProfileIncomplete`)
- Fallback title and description if SidePost not configured
**Modal Features:**
- Warning icon with attention-grabbing styling
- Dismissible with ESC key or close button
- Prevents body scrolling when open
- Smooth transitions (Alpine.js x-transition)
- Theme-aware styling (uses theme color classes)
**Configuration:**
- Enabled in `config/timebank_cc.php:208` (`show_warning_modal => true`)
- Works independently from `profile_hidden` setting
- Can show modal even if profile is accessible to others
---
### 6. Chat Messenger (NOT IMPLEMENTED)
**Configuration:** `profile_incomplete.messenger_hidden`
**Expected Behavior:**
- Incomplete profiles should not appear in messenger user search
- Cannot start new conversations with incomplete profiles
- Existing conversations remain accessible
**Current Status:** ❌ NOT IMPLEMENTED
**Package:** `namu/wirechat` (WireChat)
**Location to Implement:**
- Search participants functionality in WireChat
- May require custom override or event listener
**Implementation Approach:**
```php
// In a custom service provider or WireChat override
Event::listen(\Namu\WireChat\Events\SearchingParticipants::class, function ($event) {
if (!timebank_config('profile_incomplete.messenger_hidden')) {
return;
}
$event->query->where(function ($q) {
// Filter out incomplete profiles
$q->whereHas('user', function ($userQuery) {
// Add logic to check profile completeness
});
});
});
```
---
## Related Profile States
The application has three similar profile state systems:
### 1. Profile Inactive (`profile_inactive`)
**Configuration:**
```php
'profile_inactive' => [
're-activate_at_login' => true,
'messenger_hidden' => true,
'profile_search_hidden' => true,
'profile_hidden' => true,
'profile_labeled' => true,
],
```
**Evaluation:**
- Checked via `$profile->isActive()` method
- Based on `inactive_at` field (null or future = active, past = inactive)
**Enforcement:** ✓ FULLY IMPLEMENTED
- Main search bar: Filtered ✓ (`MainSearchBar.php:654-659`)
- Browse tags: Filtered ✓ (`MainBrowseTagCategories.php:530-536`)
- Profile page: Hidden/Labeled ✓ (`ProfileController.php:363-374`)
- Messenger: Hidden ✓ (assumed via WireChat)
---
### 2. Profile Email Unverified (`profile_email_unverified`)
**Configuration:**
```php
'profile_email_unverified' => [
'messenger_hidden' => true,
'profile_search_hidden' => true,
'profile_hidden' => false,
'profile_labeled' => false,
],
```
**Evaluation:**
- Checked via `$profile->isEmailVerified()` method
- Based on `email_verified_at` field (null or future = unverified)
**Enforcement:** ✓ FULLY IMPLEMENTED
- Main search bar: Filtered ✓ (`MainSearchBar.php:661-666`)
- Browse tags: Filtered ✓ (`MainBrowseTagCategories.php:538-544`)
- Profile page: Hidden/Labeled ✓ (`ProfileController.php:376-384`)
- Messenger: Hidden ✓ (assumed via WireChat)
---
### 3. Profile Incomplete (`profile_incomplete`)
**Configuration:** (as documented above)
**Evaluation:**
- Checked via `$profile->hasIncompleteProfile($profile)` method
- Based on field content and relations
**Enforcement:** ⚠️ PARTIALLY IMPLEMENTED
- Main search bar: Filtered ✓ (`MainSearchBar.php:676-684`)
- Browse tags: Filtered ✓ (`MainBrowseTagCategories.php:554-561`)
- Profile page: Hidden ✓ (`ProfileController.php:387-394`)
- Profile labels: NOT IMPLEMENTED ❌ (prepared but requires view updates)
- Messenger: NOT IMPLEMENTED ❌
---
## Implementation Status
### Summary Table
| Feature | Config Key | Main Search | Browse Tags | Profile Page | Labels | Warning Modal | Messenger |
|---------|-----------|-------------|-------------|--------------|--------|---------------|-----------|
| **Inactive** | `profile_inactive` | ✓ | ✓ | ✓ | ✓ | N/A | ✓ |
| **Email Unverified** | `profile_email_unverified` | ✓ | ✓ | ✓ | ✓ | N/A | ✓ |
| **Incomplete** | `profile_incomplete` | ✓ | ✓ | ✓ | ✓ | ✓ | ❌ |
### Priority Tasks
1. ~~**HIGH:** Implement incomplete profile filtering in `MainBrowseTagCategories`~~ ✓ COMPLETED
2. ~~**HIGH:** Implement profile page hiding/access control~~ ✓ COMPLETED
3. ~~**MEDIUM:** Implement incomplete profile labels on profile pages~~ ✓ COMPLETED
4. ~~**MEDIUM:** Implement incomplete profile warning modal~~ ✓ COMPLETED
5. **MEDIUM:** Implement messenger filtering
6. ~~**LOW:** Remove temporary Organization exemption in `MainSearchBar`~~ ✓ COMPLETED
---
## Testing
### Manual Testing Checklist
**Setup:**
1. Create test user with minimal profile data
2. Verify profile is incomplete: `$user->hasIncompleteProfile($user)` returns `true`
**Test Cases:**
#### Test 1: Field Content Requirements
```php
$user = User::factory()->create([
'about' => '',
'about_short' => '',
'motivation' => '',
'cyclos_skills' => '',
]);
// Add tags and locations
$user->tags()->attach([1, 2]);
$user->locations()->attach(1);
// Should be incomplete (no field data)
assertTrue($user->hasIncompleteProfile($user));
// Add 50 characters
$user->about = str_repeat('a', 50);
$user->save();
// Still incomplete (< 100 chars)
assertTrue($user->hasIncompleteProfile($user));
// Add 50 more characters
$user->about_short = str_repeat('b', 50);
$user->save();
// Now complete (100+ chars, has relations)
assertFalse($user->hasIncompleteProfile($user));
```
#### Test 2: Relation Requirements
```php
$user = User::factory()->create([
'about' => str_repeat('test ', 25), // 125 characters
]);
// No relations yet
// Should be incomplete (no relations)
assertTrue($user->hasIncompleteProfile($user));
// Add a tag
$user->tags()->attach(1);
// Now complete
assertFalse($user->hasIncompleteProfile($user));
```
#### Test 3: Search Filtering
```php
// Create incomplete user
$incompleteUser = User::factory()->create(['about' => '']);
// Search as regular user
actingAs($regularUser);
$results = app(MainSearchBar::class)->search($incompleteUser->name);
// Should NOT find incomplete user
assertEmpty($results);
// Search as admin
actingAs($admin);
$results = app(MainSearchBar::class)->search($incompleteUser->name);
// SHOULD find incomplete user (admins can see all)
assertNotEmpty($results);
```
#### Test 4: Profile Page Access
```php
$incompleteUser = User::factory()->create(['about' => '']);
// Test with profile_hidden = true
config(['timebank-cc.profile_incomplete.profile_hidden' => true]);
// Access as regular user
actingAs($regularUser);
$response = $this->get(route('profile.show', ['type' => 'user', 'id' => $incompleteUser->id]));
$response->assertViewIs('profile.not_found'); // Should be hidden
// Access as admin
actingAs($admin);
$response = $this->get(route('profile.show', ['type' => 'user', 'id' => $incompleteUser->id]));
$response->assertViewIs('profile.show'); // Should be visible
```
### Automated Test Suite
**Create:** `tests/Feature/ProfileIncompleteTest.php`
```php
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Models\Tag;
use App\Models\Locations\City;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ProfileIncompleteTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function profile_with_no_content_is_incomplete()
{
$user = User::factory()->create([
'about' => '',
'about_short' => '',
'motivation' => '',
'cyclos_skills' => '',
]);
$this->assertTrue($user->hasIncompleteProfile($user));
}
/** @test */
public function profile_with_content_but_no_relations_is_incomplete()
{
$user = User::factory()->create([
'about' => str_repeat('test ', 25), // 125 chars
]);
$this->assertTrue($user->hasIncompleteProfile($user));
}
/** @test */
public function profile_with_short_content_and_relations_is_incomplete()
{
$user = User::factory()->create([
'about' => 'Short text', // < 100 chars
]);
$user->tags()->attach(Tag::factory()->create()->tag_id);
$this->assertTrue($user->hasIncompleteProfile($user));
}
/** @test */
public function profile_with_sufficient_content_and_relations_is_complete()
{
$user = User::factory()->create([
'about' => str_repeat('test ', 25), // 125 chars
]);
$user->tags()->attach(Tag::factory()->create()->tag_id);
$this->assertFalse($user->hasIncompleteProfile($user));
}
/** @test */
public function incomplete_profiles_hidden_from_main_search()
{
$this->markTestIncomplete('Implement when search filtering is active');
}
/** @test */
public function admins_can_see_incomplete_profiles_in_search()
{
$this->markTestIncomplete('Implement when search filtering is active');
}
}
```
---
## Configuration Examples
### Example 1: Strict Requirements (Default)
Requires meaningful content across multiple fields and at least one relation.
```php
'profile_incomplete' => [
'messenger_hidden' => true,
'profile_search_hidden' => true,
'profile_hidden' => false,
'profile_labeled' => false,
'check_fields' => ['about', 'about_short', 'motivation', 'cyclos_skills'],
'check_fields_min_total_length' => 100,
'check_relations' => ['tags', 'languages', 'locations'],
],
```
**Use Case:** Quality-focused communities that want only well-documented profiles visible.
---
### Example 2: Minimal Requirements
Only requires basic information.
```php
'profile_incomplete' => [
'messenger_hidden' => false,
'profile_search_hidden' => true,
'profile_hidden' => false,
'profile_labeled' => true,
'check_fields' => ['about_short'],
'check_fields_min_total_length' => 20,
'check_relations' => ['locations'],
],
```
**Use Case:** Welcoming communities that want to encourage participation but still require location.
---
### Example 3: Skills-Focused Platform
Emphasizes skills/services offered.
```php
'profile_incomplete' => [
'messenger_hidden' => true,
'profile_search_hidden' => true,
'profile_hidden' => false,
'profile_labeled' => true,
'check_fields' => ['cyclos_skills', 'motivation'],
'check_fields_min_total_length' => 50,
'check_relations' => ['tags', 'locations'],
],
```
**Use Case:** Service exchange platforms where skills are the primary discovery method.
---
### Example 4: Disabled
Turns off incomplete profile filtering entirely.
```php
'profile_incomplete' => [
'messenger_hidden' => false,
'profile_search_hidden' => false,
'profile_hidden' => false,
'profile_labeled' => false,
'check_fields' => [],
'check_fields_min_total_length' => 0,
'check_relations' => [],
],
```
**Use Case:** Testing environments or very small communities where all profiles should be visible.
---
## Best Practices
### 1. Gradual Enforcement
Start with lenient settings and tighten over time as users complete profiles:
```php
// Week 1-2: Just label incomplete profiles
'profile_labeled' => true,
'profile_search_hidden' => false,
// Week 3-4: Hide from search but allow messenger
'profile_labeled' => true,
'profile_search_hidden' => true,
'messenger_hidden' => false,
// Week 5+: Full enforcement
'profile_labeled' => true,
'profile_search_hidden' => true,
'messenger_hidden' => true,
```
### 2. Clear User Communication
When enforcing incomplete profile restrictions:
- Show clear messages on why their profile is hidden
- Provide checklist of what's needed to complete profile
- Calculate and display completion percentage
- Send reminder emails to users with incomplete profiles
### 3. Admin Override
Always allow Admins and Banks to:
- View all profiles regardless of completion status
- Search for incomplete profiles
- Message incomplete profiles
This is already implemented in the permission checks.
### 4. Performance Optimization
When checking many profiles:
- Eager load relations to avoid N+1 queries
- Cache profile completion status
- Consider adding a `profile_completed_at` timestamp field
```php
// Efficient bulk checking
User::with(['tags', 'languages', 'locations'])
->get()
->filter(fn($user) => !$user->hasIncompleteProfile($user));
```
---
## Troubleshooting
### Issue: Profile shows as incomplete but appears complete
**Diagnosis:**
```php
$user = User::with(['tags', 'languages', 'locations'])->find($id);
dd([
'has_field_data' => !empty($user->about) || !empty($user->about_short),
'field_lengths' => [
'about' => strlen($user->about ?? ''),
'about_short' => strlen($user->about_short ?? ''),
'motivation' => strlen($user->motivation ?? ''),
'cyclos_skills' => strlen($user->cyclos_skills ?? ''),
],
'total_length' => strlen(trim($user->about ?? '')) + strlen(trim($user->about_short ?? '')),
'has_tags' => !$user->tags->isEmpty(),
'has_languages' => !$user->languages->isEmpty(),
'has_locations' => !$user->locations->isEmpty(),
]);
```
**Common Causes:**
- Whitespace-only content in fields (use `trim()`)
- Relations not eager-loaded (causing empty collection check to fail)
- Total character count just under 100 threshold
### Issue: Admin sees incomplete profiles in search
**This is correct behavior.** Admins should see all profiles.
**Verify with:**
```php
$canManageProfiles = $this->getCanManageProfiles();
// Returns true for Admin/Bank profiles
```
---
## Migration Guide
### Adding Completion Tracking
To track when profiles become complete:
**Migration:**
```php
Schema::table('users', function (Blueprint $table) {
$table->timestamp('profile_completed_at')->nullable()->after('email_verified_at');
});
```
**Model Method:**
```php
public function markAsComplete()
{
if (!$this->hasIncompleteProfile($this)) {
$this->profile_completed_at = now();
$this->save();
}
}
```
**Usage:**
```php
// After profile edit
$user->markAsComplete();
```
---
## See Also
- [SEARCH_REFERENCE.md](SEARCH_REFERENCE.md) - Main search implementation details
- [STYLE_GUIDE.md](STYLE_GUIDE.md) - UI patterns for profile badges/labels
- `config/timebank-default.php.example` - Full configuration reference
- `app/Traits/ProfileTrait.php` - Core profile methods
- `app/Traits/ActiveStatesTrait.php` - Active/inactive state management
---
## Changelog
### 2025-11-03 - Bank Profile Updates
- ✓ Added `cyclos_skills` column to banks table via migration
- ✓ Updated `showBank()` method to include `cyclos_skills` in select statement
- Banks now have skills field matching Users and Organizations
### 2025-11-03 - Search Improvements
- ✓ Removed temporary Organization exemption from incomplete profile filtering in `MainSearchBar`
- ✓ All profile types (Users, Organizations, Banks) now properly filtered when incomplete
- ✓ Fixed search dropdown showing empty border when no suggestions available
- Search behavior now consistent across all profile types
### 2025-11-03 - Warning Modal Implementation
- ✓ Added `show_warning_modal` configuration setting to `profile_incomplete`
- ✓ Implemented warning modal display when viewing own incomplete profile
- ✓ Modal appears on both profile view and edit pages
- ✓ Uses Alpine.js for smooth transitions and dismissal
- ✓ Integrates with SidePost content system for customizable messaging
- ✓ Modal checks `show_warning_modal` config (independent from `profile_hidden`)
### 2025-11-03 - Profile Visibility Refinements
- ✓ Updated incomplete label visibility logic for admins/banks vs regular users
- ✓ Regular users respect `profile_labeled` config setting
- ✓ Admins/Banks always see incomplete labels regardless of config
- ✓ Fixed profile access control to properly hide incomplete/inactive profiles
- ✓ Changed incomplete label styling to `text-red-700` (matching inactive/removed)
### 2025-01-31 - Bank Profile Access Fix
- ✓ Added `canViewIncompleteProfiles()` method to `ProfilePermissionTrait`
- ✓ Banks can now view incomplete profiles (checks profile type, not permissions)
- ✓ Maintains existing permission-based `getCanManageProfiles()` method
- ✓ Updated all three profile show methods to use new check
- No database migration needed - profile type check only
### 2025-01-31 - Profile Labels Implementation
- ✓ Enabled `profile_incomplete.profile_labeled` in both config files
- ✓ Enabled `profile_email_unverified.profile_labeled` in both config files
- Frontend labels already implemented in Livewire component (lines 35-49, 263-267)
- Incomplete profiles now show red (`text-red-700`) warning label to Admins/Banks
- Email unverified profiles now show red (`text-red-700`) warning label to Admins/Banks
- Labels appear in both top section (near name) and activity info section
### 2025-01-31 - Browse Categories & Profile Page Implementation
- ✓ Implemented incomplete profile filtering in `MainBrowseTagCategories`
- ✓ Implemented profile page access control in `ProfileController`
- ✓ Added `incompleteLabel` variable to profile state system
- Backend now fully ready for incomplete profile enforcement
### 2025-01-31 - Initial Documentation
- Documented current implementation status
- Identified missing enforcement locations
- Created testing guidelines
- Provided configuration examples
---
**Last Updated:** 2025-11-03
**Maintainer:** Development Team
**Status:** Mostly Implemented (Search ✓, Browse ✓, Profile Page Hidden ✓, Labels ✓, Warning Modal ✓ - Only Messenger Pending)