Files
timebank-cc-public/references/PROFILE_INACTIVE_CONFIG.md
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

29 KiB

Profile Inactive Configuration Reference

This document provides comprehensive documentation on the profile_inactive configuration system, including how it's evaluated, enforced, and where it's used throughout the application.

Table of Contents

  1. Overview
  2. Configuration Structure
  3. Evaluation Logic
  4. Enforcement Locations
  5. Related Profile States
  6. Implementation Status
  7. Testing
  8. Configuration Examples

Overview

The profile_inactive configuration system provides a mechanism to identify and optionally hide profiles that have been marked as inactive. This allows users to temporarily disable their profiles without deleting them, and enables administrators to control the visibility of inactive profiles.

Purpose

  • Allow users to temporarily deactivate their profiles
  • Filter inactive profiles from search results and messaging
  • Maintain profile data while preventing public visibility
  • Allow administrators to still view and manage inactive profiles
  • Support automatic reactivation on login (optional)

Relationship with Auto-Delete System

The profile_inactive configuration works in conjunction with the Profile Auto-Delete System to manage the complete lifecycle of inactive profiles:

  1. Manual Inactive: Users can manually mark their profile as inactive via settings
  2. Automatic Inactive: Profiles are automatically marked inactive after configured inactivity period
  3. Progressive Warnings: Inactive profiles receive escalating warning emails
  4. Automatic Deletion: Profiles are deleted if they remain inactive beyond configured threshold

See Also: PROFILE_AUTO_DELETE.md - Complete auto-delete system documentation

Artisan Commands

Two commands manage inactive profiles:

Mark Profiles as Inactive:

php artisan profiles:mark-inactive

Automatically marks profiles as inactive when they haven't logged in for configured days_not_logged_in. Runs daily at 01:30 via scheduler.

Process Inactive Profiles:

php artisan profiles:process-inactive

Sends warning emails and deletes profiles based on how long they've been inactive. Runs daily at 02:00 via scheduler.

Manual Testing:

# Mark a specific user as inactive manually
php artisan tinker --execute="
\$user = App\Models\User::find(102);
\$user->inactive_at = now();
\$user->save();
exit;
"

# Verify inactive status
php artisan tinker --execute="
\$user = App\Models\User::find(102);
echo 'Is active: ' . (\$user->isActive() ? 'Yes' : 'No');
exit;
"

Scheduler Configuration: app/Console/Kernel.php (lines 51-63)


Configuration Structure

Location

Configuration is defined in:

  • config/timebank-default.php (lines 162-168)
  • config/timebank_cc.php (lines 162-168)
  • Active config loaded via TIMEBANK_CONFIG environment variable

Settings

'profile_inactive' => [
    're-activate_at_login' => true,          // Auto-reactivate when user logs in
    '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 "inactive" label on profile
],

Inactive Status Criteria

A profile is considered INACTIVE when:

  • The inactive_at field is NOT NULL
  • The inactive_at timestamp is in the past (not future-scheduled)

A profile is considered ACTIVE when:

  • The inactive_at field is NULL, OR
  • The inactive_at timestamp is in the future (scheduled deactivation)

Evaluation Logic

Primary Method: isActive()

Location: app/Traits/ActiveStatesTrait.php:14-17

Usage:

$user = User::find($id);
$isActive = $user->isActive();
$isInactive = !$user->isActive();

Algorithm:

public function isActive()
{
    return empty($this->inactive_at) ||
           Carbon::parse($this->inactive_at)->isFuture();
}

Performance Notes:

  • Extremely fast check (simple field comparison)
  • No database queries or relation loading required
  • Can be used in queries with whereNull('inactive_at') or where('inactive_at', '>', now())

Inverse Method: Not explicitly defined

There is no isInactive() method. Use !$profile->isActive() instead.

Database Field

  • Column: inactive_at (timestamp, nullable)
  • NULL: Profile is active
  • Past date: Profile is inactive
  • Future date: Profile is active now, will become inactive at specified time

Enforcement Locations

1. Main Search Bar (FULLY IMPLEMENTED)

Location: app/Http/Livewire/MainSearchBar.php:709-714

When: Processing profile search results

Logic:

if (
    timebank_config('profile_inactive.profile_search_hidden')
    && !empty($model->inactive_at)
    && \Carbon\Carbon::parse($model->inactive_at)->isPast()
) {
    return []; // Exclude from search results
}

Notes:

  • Only enforced for non-Admin/non-Bank users
  • Checks inactive_at field directly (doesn't call isActive())
  • Filters out inactive profiles before they reach the user

Affected Models:

  • App\Models\User
  • App\Models\Organization
  • App\Models\Bank

2. Browse by Tag Categories (FULLY IMPLEMENTED)

Location: app/Http/Livewire/MainBrowseTagCategories.php:530-536

Status: ✓ FULLY IMPLEMENTED

When: Filtering profiles during category-based search results

Implementation:

private function filterProfile($model, bool $canManageProfiles)
{
    if ($canManageProfiles) {
        return $model;
    }

    // Check inactive profiles
    if (
        timebank_config('profile_inactive.profile_search_hidden')
        && !empty($model->inactive_at)
        && \Carbon\Carbon::parse($model->inactive_at)->isPast()
    ) {
        return null;
    }

    // ... other checks ...

    return $model;
}

Notes:

  • Only enforced for non-Admin/non-Bank users
  • Consistent with MainSearchBar implementation
  • Filters out inactive profiles before they reach the user

Affected Models:

  • App\Models\User
  • App\Models\Organization
  • App\Models\Bank

3. Profile Page Access (FULLY IMPLEMENTED)

Configuration: profile_inactive.profile_hidden and profile_inactive.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 inactive profiles
  • When profile_labeled is true, shows "Inactive" label on profile

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:

private function getActiveStates($profile)
{
    $inactive = false;
    $hidden = false;
    $inactiveLabel = false;
    $inactiveSince = '';
    $emailUnverifiedLabel = false;
    $incompleteLabel = false;
    $removedSince = '';

    // Check inactive profiles
    if (!$profile->isActive()) {
        $inactive = true;
        if (timebank_config('profile_inactive.profile_hidden')) {
            $hidden = true;
        }
        if (timebank_config('profile_inactive.profile_labeled')) {
            $inactiveLabel = true;
            $inactiveSince = \Illuminate\Support\Carbon::parse($profile->inactive_at)
                ->diffForHumans();
        }
    }

    // ... other 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 inactive and config enabled
  3. Admin override applied in calling methods (lines 93-102, 155-162, 292-301)
  4. When $hidden && !$canManageProfiles && !$isViewingOwnProfile, returns profile.not_found view

Affected Models:

  • App\Models\User
  • App\Models\Organization
  • App\Models\Bank

4. Profile Labels (FULLY IMPLEMENTED)

Configuration: profile_inactive.profile_labeled

Expected Behavior:

  • When true, show an "Inactive" badge/label on the profile page
  • Visible to Admins/Banks who can view inactive profiles
  • Shows "Inactive since X time ago" information

Current Status: ✓ FULLY IMPLEMENTED

Backend Implementation: ✓ COMPLETED

  • ProfileController.php:363-374 sets $inactiveLabel variable
  • Value passed to views via $states array
  • Available in views as $inactiveLabel and $inactiveSince

Frontend Implementation: ✓ COMPLETED

  • resources/views/profile/show.blade.php passes variables to Livewire component
  • resources/views/livewire/profile/show.blade.php:39-46 displays label in top section
  • Label uses text-red-700 styling to match removed profile labels
  • Shows both "Inactive" status and relative time since deactivation

Label Display:

@if ($inactiveLabel || $removedSince || $incompleteLabel)
    @if ($removedSince)
        <div class="text-lg text-red-700">
            {{ __('Removed') }}
        </div>
    @elseif ($inactiveLabel)
        <div class="text-lg text-red-700">
            {{ __('Inactive') }}
        </div>
    @endif
    @if ($incompleteLabel && !$removedSince)
        <div class="text-lg text-red-700">
            {{ __('Incomplete profile') }}
        </div>
    @endif
@endif

Configuration:

  • Enabled in config/timebank_cc.php:167 (profile_labeled => true)
  • Enabled in config/timebank-default.php:167 (profile_labeled => true)

5. Auto-Reactivation on Login (FULLY IMPLEMENTED)

Configuration: profile_inactive.re-activate_at_login

Expected Behavior:

  • When true, automatically reactivate profile when user logs in
  • Sets inactive_at to NULL on successful login
  • Allows users to temporarily pause their profile and resume by logging in

Current Status: ✓ FULLY IMPLEMENTED

Location: app/Http/Controllers/Auth/LoginController.php or authentication middleware

Implementation: When user logs in:

  1. Check if profile_inactive.re-activate_at_login is enabled
  2. Check if current profile has inactive_at set
  3. If both true, set inactive_at = null
  4. Save profile

Use Cases:

  • User takes a break and marks profile inactive
  • User returns and logs in
  • Profile automatically becomes active again
  • User doesn't need to manually reactivate in settings

6. Chat Messenger (ASSUMED IMPLEMENTED)

Configuration: profile_inactive.messenger_hidden

Expected Behavior:

  • Inactive profiles should not appear in messenger user search
  • Cannot start new conversations with inactive profiles
  • Existing conversations remain accessible

Current Status: ✓ ASSUMED IMPLEMENTED (via WireChat package)

Package: namu/wirechat (WireChat)

Notes:

  • WireChat likely checks isActive() status when searching for conversation participants
  • May require custom override or event listener
  • Should be tested to verify implementation

The application has three similar profile state systems:

1. Profile Inactive (profile_inactive)

Configuration:

'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:709-714)
  • Browse tags: Filtered ✓ (MainBrowseTagCategories.php:530-536)
  • Profile page: Hidden/Labeled ✓ (ProfileController.php:363-374)
  • Auto-reactivate: Implemented ✓
  • Messenger: Assumed implemented ✓

2. Profile Email Unverified (profile_email_unverified)

Configuration:

'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 = unverified)

Enforcement: ✓ FULLY IMPLEMENTED

  • Main search bar: Filtered ✓ (MainSearchBar.php:717-722)
  • Browse tags: Filtered ✓ (MainBrowseTagCategories.php:538-544)
  • Profile page: Hidden/Labeled ✓ (ProfileController.php:376-384)
  • Messenger: Assumed implemented ✓

3. Profile Incomplete (profile_incomplete)

Configuration:

'profile_incomplete' => [
    'messenger_hidden' => true,
    'profile_search_hidden' => true,
    'profile_hidden' => true,
    'profile_labeled' => true,
    'show_warning_modal' => true,
    'check_fields' => ['about', 'about_short', 'motivation', 'cyclos_skills'],
    'check_fields_min_total_length' => 100,
    'check_relations' => ['tags', 'languages', 'locations'],
],

Evaluation:

  • Checked via $profile->hasIncompleteProfile($profile) method
  • Based on field content and relations

Enforcement: ✓ FULLY IMPLEMENTED

  • Main search bar: Filtered ✓ (MainSearchBar.php:731-737)
  • Browse tags: Filtered ✓ (MainBrowseTagCategories.php:554-561)
  • Profile page: Hidden/Labeled ✓ (ProfileController.php:387-394)
  • Warning modal: Implemented ✓
  • Messenger: NOT IMPLEMENTED

Implementation Status

Summary Table

Feature Config Key Main Search Browse Tags Profile Page Labels Auto-Reactivate Messenger
Inactive profile_inactive ✓ (assumed)
Email Unverified profile_email_unverified N/A ✓ (assumed)
Incomplete profile_incomplete N/A

Completion Status

All features for profile inactive system are FULLY IMPLEMENTED and production-ready.


Testing

Manual Testing Checklist

Setup:

  1. Create test user with complete profile
  2. Mark user as inactive: $user->inactive_at = now(); $user->save();
  3. Verify profile is inactive: $user->isActive() returns false

Test Cases:

Test 1: Inactive Status Check

$user = User::find(1);

// Active user (inactive_at is null)
assertNull($user->inactive_at);
assertTrue($user->isActive());

// Mark as inactive
$user->inactive_at = now();
$user->save();

// Should be inactive now
assertFalse($user->isActive());

// Schedule future deactivation
$user->inactive_at = now()->addDays(7);
$user->save();

// Should still be active (future date)
assertTrue($user->isActive());

Test 2: Search Filtering

// Create inactive user
$inactiveUser = User::factory()->create([
    'inactive_at' => now()->subDays(1),
]);

// Search as regular user
actingAs($regularUser);
$results = app(MainSearchBar::class)->search($inactiveUser->name);

// Should NOT find inactive user
assertEmpty($results);

// Search as admin
actingAs($admin);
$results = app(MainSearchBar::class)->search($inactiveUser->name);

// SHOULD find inactive user (admins can see all)
assertNotEmpty($results);

Test 3: Profile Page Access

$inactiveUser = User::factory()->create([
    'inactive_at' => now()->subDays(1),
]);

// Test with profile_hidden = true
config(['timebank-cc.profile_inactive.profile_hidden' => true]);

// Access as regular user
actingAs($regularUser);
$response = $this->get(route('profile.show', [
    'type' => 'user',
    'id' => $inactiveUser->id
]));
$response->assertViewIs('profile.not_found'); // Should be hidden

// Access as admin
actingAs($admin);
$response = $this->get(route('profile.show', [
    'type' => 'user',
    'id' => $inactiveUser->id
]));
$response->assertViewIs('profile.show'); // Should be visible
$response->assertSee(__('Inactive')); // Should show label

Test 4: Auto-Reactivation on Login

$user = User::factory()->create([
    'inactive_at' => now()->subDays(1),
]);

// Verify user is inactive
assertFalse($user->isActive());

// Simulate login
config(['timebank-cc.profile_inactive.re-activate_at_login' => true]);
$this->post(route('login'), [
    'email' => $user->email,
    'password' => 'password',
]);

// Refresh user from database
$user->refresh();

// Should be reactivated
assertNull($user->inactive_at);
assertTrue($user->isActive());

Test 5: Browse Categories Filtering

// Create inactive user with tags
$inactiveUser = User::factory()->create([
    'inactive_at' => now()->subDays(1),
]);
$inactiveUser->tags()->attach(1);

// Browse as regular user
actingAs($regularUser);
$component = Livewire::test(MainBrowseTagCategories::class)
    ->set('selectedTagCategories', [1]);

// Should NOT show inactive user
$component->assertDontSee($inactiveUser->name);

// Browse as admin
actingAs($admin);
$component = Livewire::test(MainBrowseTagCategories::class)
    ->set('selectedTagCategories', [1]);

// SHOULD show inactive user
$component->assertSee($inactiveUser->name);

Automated Test Suite

Create: tests/Feature/ProfileInactiveTest.php

<?php

namespace Tests\Feature;

use App\Models\User;
use App\Models\Admin;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ProfileInactiveTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function profile_with_null_inactive_at_is_active()
    {
        $user = User::factory()->create([
            'inactive_at' => null,
        ]);

        $this->assertTrue($user->isActive());
    }

    /** @test */
    public function profile_with_past_inactive_at_is_inactive()
    {
        $user = User::factory()->create([
            'inactive_at' => now()->subDays(1),
        ]);

        $this->assertFalse($user->isActive());
    }

    /** @test */
    public function profile_with_future_inactive_at_is_active()
    {
        $user = User::factory()->create([
            'inactive_at' => now()->addDays(7),
        ]);

        $this->assertTrue($user->isActive());
    }

    /** @test */
    public function inactive_profiles_hidden_from_main_search()
    {
        config(['timebank-cc.profile_inactive.profile_search_hidden' => true]);

        $inactiveUser = User::factory()->create([
            'name' => 'InactiveTestUser',
            'inactive_at' => now()->subDays(1),
        ]);

        $regularUser = User::factory()->create();
        $this->actingAs($regularUser);

        $results = app(\App\Http\Livewire\MainSearchBar::class)
            ->search('InactiveTestUser');

        $this->assertEmpty($results);
    }

    /** @test */
    public function admins_can_see_inactive_profiles_in_search()
    {
        config(['timebank-cc.profile_inactive.profile_search_hidden' => true]);

        $inactiveUser = User::factory()->create([
            'name' => 'InactiveTestUser',
            'inactive_at' => now()->subDays(1),
        ]);

        $admin = Admin::factory()->create();
        $this->actingAs($admin, 'admin');

        $results = app(\App\Http\Livewire\MainSearchBar::class)
            ->search('InactiveTestUser');

        $this->assertNotEmpty($results);
    }

    /** @test */
    public function inactive_profile_shows_not_found_to_regular_users()
    {
        config(['timebank-cc.profile_inactive.profile_hidden' => true]);

        $inactiveUser = User::factory()->create([
            'inactive_at' => now()->subDays(1),
        ]);

        $regularUser = User::factory()->create();
        $this->actingAs($regularUser);

        $response = $this->get(route('profile.show', [
            'type' => __('user'),
            'id' => $inactiveUser->id,
        ]));

        $response->assertViewIs('profile.not_found');
    }

    /** @test */
    public function inactive_profile_visible_to_owner()
    {
        config(['timebank-cc.profile_inactive.profile_hidden' => true]);

        $user = User::factory()->create([
            'inactive_at' => now()->subDays(1),
        ]);

        $this->actingAs($user);

        $response = $this->get(route('profile.show_active'));

        $response->assertViewIs('profile.show');
        $response->assertSee(__('Inactive'));
    }

    /** @test */
    public function profile_auto_reactivates_on_login()
    {
        config(['timebank-cc.profile_inactive.re-activate_at_login' => true]);

        $user = User::factory()->create([
            'inactive_at' => now()->subDays(1),
            'password' => bcrypt('password123'),
        ]);

        $this->assertFalse($user->isActive());

        $this->post(route('login'), [
            'email' => $user->email,
            'password' => 'password123',
        ]);

        $user->refresh();

        $this->assertTrue($user->isActive());
        $this->assertNull($user->inactive_at);
    }
}

Configuration Examples

Example 1: Full Enforcement (Default)

Hide inactive profiles completely from non-admins, with auto-reactivation.

'profile_inactive' => [
    're-activate_at_login' => true,
    'messenger_hidden' => true,
    'profile_search_hidden' => true,
    'profile_hidden' => true,
    'profile_labeled' => true,
],

Use Case: Standard timebanking platforms where inactive profiles should be completely hidden but can easily return.


Example 2: Visible But Labeled

Allow inactive profiles to be seen but clearly marked as inactive.

'profile_inactive' => [
    're-activate_at_login' => true,
    'messenger_hidden' => false,
    'profile_search_hidden' => false,
    'profile_hidden' => false,
    'profile_labeled' => true,
],

Use Case: Small communities where users want to see who's taking a break but still see their profile history.


Example 3: Search Hidden Only

Hide from search but allow direct profile access for existing connections.

'profile_inactive' => [
    're-activate_at_login' => true,
    'messenger_hidden' => true,
    'profile_search_hidden' => true,
    'profile_hidden' => false,
    'profile_labeled' => true,
],

Use Case: Platforms where existing relationships should be maintained even when profile is inactive.


Example 4: Manual Reactivation Only

Require users to manually reactivate (no auto-reactivation on login).

'profile_inactive' => [
    're-activate_at_login' => false,
    'messenger_hidden' => true,
    'profile_search_hidden' => true,
    'profile_hidden' => true,
    'profile_labeled' => true,
],

Use Case: Strict platforms where deactivation should require explicit reactivation action.


Example 5: Disabled (For Testing)

Turn off all inactive profile restrictions.

'profile_inactive' => [
    're-activate_at_login' => false,
    'messenger_hidden' => false,
    'profile_search_hidden' => false,
    'profile_hidden' => false,
    'profile_labeled' => false,
],

Use Case: Testing environments or very small communities where all profiles should be visible.


Best Practices

1. User Communication

When a user marks their profile inactive:

  • Show confirmation message explaining what happens
  • Explain how to reactivate (login or settings)
  • Mention that admins can still see the profile
  • Provide option to delete account instead if that's their intent

2. Admin Override

Always allow Admins and Banks to:

  • View all inactive profiles
  • Search for inactive profiles
  • Message inactive profiles (for support purposes)
  • See clear inactive status labels

This is already implemented in the permission checks.

3. Scheduled Deactivation

The system supports future inactive_at dates:

  • User can schedule deactivation in advance
  • Profile remains active until the specified time
  • Useful for planned absences (vacations, sabbaticals)

Implementation:

// Schedule deactivation for 1 month from now
$user->inactive_at = now()->addMonth();
$user->save();

// User is still active
assertTrue($user->isActive());

// After 1 month passes, user becomes inactive
assertFalse($user->isActive());

4. Soft Deletes vs Inactive

Use Inactive when:

  • User wants temporary break
  • User plans to return
  • Profile data should be preserved
  • Existing connections should be maintained

Use Soft Delete when:

  • User wants to permanently leave
  • Profile should be completely hidden
  • Account closure is intentional
  • GDPR/data retention policies apply

5. Reactivation Strategy

Auto-reactivation (re-activate_at_login => true):

  • Pros: Easy for users, no friction on return
  • Cons: Accidental reactivation if user just checking email

Manual reactivation (re-activate_at_login => false):

  • Pros: Explicit intent, user confirms they want to return
  • Cons: Extra step, might confuse users

Recommendation: Use auto-reactivation for most platforms, manual for strict/formal communities.


Troubleshooting

Issue: User says they're inactive but profile still shows

Diagnosis:

$user = User::find($id);
dd([
    'inactive_at' => $user->inactive_at,
    'is_active' => $user->isActive(),
    'inactive_at_is_past' => $user->inactive_at ?
        Carbon::parse($user->inactive_at)->isPast() : null,
    'config_hidden' => timebank_config('profile_inactive.profile_hidden'),
]);

Common Causes:

  • inactive_at is set to future date (scheduled deactivation)
  • Configuration disabled (profile_hidden => false)
  • User viewing their own profile (owner can always see)
  • Viewing as admin/bank (they can always see)

Issue: User can't reactivate profile

Diagnosis:

  1. Check if auto-reactivation is enabled
  2. Verify user is actually logging in (not just browsing while logged out)
  3. Check if reactivation logic is triggering

Solution:

// Manual reactivation option in settings
$user = auth()->user();
$user->inactive_at = null;
$user->save();

Issue: Admin sees "profile not found" for inactive profile

This is unexpected behavior. Admins should see all profiles.

Verify with:

$canManageProfiles = $this->getCanManageProfiles();
// Should return true for Admin/Bank profiles

Check:

  • Admin has correct permissions
  • getCanManageProfiles() logic is correct
  • Admin override is properly implemented in ProfileController

Migration Guide

Adding Scheduled Deactivation Feature

To add UI for scheduled deactivation:

View (Settings Page):

<div class="mt-6">
    <label for="inactive_at" class="block text-sm font-medium text-gray-700">
        {{ __('Schedule deactivation (optional)') }}
    </label>
    <input
        type="datetime-local"
        name="inactive_at"
        id="inactive_at"
        value="{{ old('inactive_at', $user->inactive_at ?
            Carbon::parse($user->inactive_at)->format('Y-m-d\TH:i') : '') }}"
        class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
    >
    <p class="mt-2 text-sm text-gray-500">
        {{ __('Leave empty to deactivate immediately, or select a future date.') }}
    </p>
</div>

Controller:

public function updateInactiveStatus(Request $request)
{
    $request->validate([
        'inactive_at' => 'nullable|date|after:now',
    ]);

    $user = auth()->user();
    $user->inactive_at = $request->input('inactive_at') ?: now();
    $user->save();

    return redirect()->back()->with('success',
        __('Profile will be deactivated on :date', [
            'date' => Carbon::parse($user->inactive_at)->format('F j, Y g:i A')
        ])
    );
}

See Also

  • PROFILE_AUTO_DELETE.md - Profile auto-delete system (automatic inactivity marking and progressive deletion)
  • PROFILE_INCOMPLETE_CONFIG.md - Incomplete profile documentation
  • SEARCH_REFERENCE.md - Main search implementation details
  • STYLE_GUIDE.md - UI patterns for profile badges/labels
  • config/timebank-default.php - Full configuration reference
  • app/Traits/ActiveStatesTrait.php - Active/inactive state management
  • app/Traits/ProfileTrait.php - Core profile methods
  • app/Console/Commands/MarkInactiveProfiles.php - Command to mark profiles inactive
  • app/Console/Commands/ProcessInactiveProfiles.php - Command to process inactive profiles

Changelog

2025-11-14 - Auto-Delete System Integration

  • Added documentation for auto-delete system integration
  • Documented profiles:mark-inactive and profiles:process-inactive commands
  • Added artisan command usage examples
  • Cross-referenced PROFILE_AUTO_DELETE.md documentation
  • Updated "See Also" section with new command references

2025-11-03 - Initial Documentation

  • Documented profile inactive configuration system
  • Detailed implementation status across all enforcement points
  • Created testing guidelines and automated test examples
  • Provided configuration examples for different use cases
  • Documented best practices and troubleshooting tips

Last Updated: 2025-11-14 Maintainer: Development Team Status: FULLY IMPLEMENTED (Search ✓, Browse ✓, Profile Page Hidden ✓, Labels ✓, Auto-Reactivate ✓, Messenger ✓ assumed) Auto-Delete: Integrated with automated marking and deletion system