Skip to main content

Deactivating Staff

This guide covers the staff deactivation process, including soft deletion, impact on scheduling, data retention, and reactivation procedures.


Understanding Deactivation

Soft Delete Approach

Shyfts uses soft deletion for staff members rather than permanent deletion. This means:

  1. Data Preserved - All staff records remain in the database
  2. Historical Integrity - Past shifts and reports stay accurate
  3. Audit Trail - Employment history is maintained
  4. Reversible - Staff can be reactivated if needed

Deactivation vs Deletion

ActionEffectReversible
DeactivateSets is_active = false✅ Yes
DeleteRemoves record entirely❌ No

Shyfts only supports deactivation to maintain data integrity.


Deactivation Process

From Staff List

  1. Navigate to DashboardStaff Management
  2. Find the staff member to deactivate
  3. Click the Delete/Deactivate button (trash icon)
  4. Confirm the action in the dialog
// Source: src/components/staff/StaffList.tsx:58-82
const handleDelete = async (staffId: string) => {
if (!confirm('Are you sure you want to deactivate this staff member?')) {
return;
}

try {
setDeletingId(staffId);
const response = await fetch(`/api/staff/${staffId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ is_active: false }),
});

if (!response.ok) {
throw new Error('Failed to deactivate staff member');
}

await loadStaff();
} catch (err) {
console.error('Error deactivating staff:', err);
alert('Failed to deactivate staff member');
} finally {
setDeletingId(null);
}
};

Confirmation Dialog

The system displays a confirmation dialog before deactivation:

// Source: src/components/staff/StaffList.tsx:59
if (!confirm('Are you sure you want to deactivate this staff member?')) {
return;
}
Confirmation Required

Deactivation requires explicit confirmation. This prevents accidental removal of staff members from the active roster.


API Endpoint

Deactivate Staff

Endpoint: PATCH /api/staff/[id]

Request Body:

{
"is_active": false
}

Response:

{
"success": true,
"data": {
"id": "staff-uuid",
"first_name": "John",
"last_name": "Smith",
"is_active": false,
"updated_at": "2025-01-13T10:30:00Z"
}
}

Database Update

The deactivation updates the staff table:

UPDATE staff
SET is_active = false,
updated_at = NOW()
WHERE id = 'staff-uuid';

Impact of Deactivation

Immediate Effects

AreaImpact
Staff ListStaff member hidden from active list
SchedulingCannot be assigned to new shifts
DropdownsRemoved from staff selection options
LoginAccount access may be revoked

Preserved Data

Data TypeStatus
Historical ShiftsPreserved and visible
Leave RecordsMaintained for reporting
DocumentsRetained in storage
Time RecordsKept for payroll/audit
Profile DataUnchanged

Calendar Impact

Deactivated staff:

  • Future shifts - Should be reassigned or cancelled
  • Past shifts - Remain visible in historical views
  • Reports - Continue to appear in historical reports

Staff List Filtering

Active/Inactive Filter

The staff list can filter by status:

// Source: src/components/staff/CompanyStaffManagement.tsx:202-203
(filterStatus === 'active' && member.isActive) ||
(filterStatus === 'inactive' && !member.isActive)

Status Display

// Source: src/components/staff/CompanyStaffManagement.tsx:413
{staff.filter(s => s.isActive).length}

Filter Options

FilterShows
AllActive and inactive staff
ActiveOnly is_active = true
InactiveOnly is_active = false

Before Deactivation

Pre-Deactivation Checklist

Before deactivating a staff member, ensure:

  1. Future Shifts Reassigned

    • Check for upcoming shifts
    • Reassign or cancel as needed
  2. Leave Requests Resolved

    • Approve or reject pending requests
    • Cancel approved future leave
  3. Outstanding Time Records

    • Review any pending timesheet submissions
    • Approve completed time records
  4. Documents Collected

    • Ensure all company property returned
    • Collect any required exit documentation
  5. Access Revoked

    • Deactivation will prevent login
    • Consider timing of access removal

Finding Future Shifts

SELECT s.*, r.name as room_name
FROM shifts s
JOIN rooms r ON s.room_id = r.id
WHERE s.staff_id = 'staff-uuid'
AND s.start_time > NOW()
AND s.status = 'SCHEDULED'
ORDER BY s.start_time;

Offboarding Workflow

  1. Notify HR/Management

    • Document reason for departure
    • Set last working day
  2. Review Scheduled Work

    • Check calendar for future shifts
    • Arrange coverage or reassignment
  3. Process Final Pay

    • Review outstanding timesheets
    • Calculate final payment
  4. Collect Company Property

    • Keys, badges, equipment
    • Company documents
  5. Document Return

    • Obtain signed acknowledgments
    • File exit documentation
  6. Deactivate Account

    • Set is_active = false
    • Timing: after last working day
  7. Communicate Departure

    • Inform relevant team members
    • Update schedules as needed

Reactivating Staff

When to Reactivate

Staff can be reactivated when:

  • Employee returns from extended leave
  • Rehiring a former employee
  • Accidental deactivation
  • Seasonal staff returning

Reactivation Process

  1. Navigate to Staff Management
  2. Filter to show Inactive staff
  3. Find the staff member
  4. Click Edit Profile
  5. Change status to Active
  6. Save changes

Reactivation API

Endpoint: PATCH /api/staff/[id]

Request Body:

{
"is_active": true
}

Post-Reactivation

After reactivating:

  1. Update Role - Verify role assignment is current
  2. Check Credentials - Ensure login access is restored
  3. Review Availability - Update availability schedule
  4. Assign Shifts - Begin scheduling as needed

Bulk Deactivation

Multiple Staff Deactivation

For bulk operations (e.g., seasonal staff):

const deactivateMultiple = async (staffIds: string[]) => {
const promises = staffIds.map(id =>
fetch(`/api/staff/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ is_active: false })
})
);

await Promise.all(promises);
};

Bulk Reactivation

Similarly for reactivation:

const reactivateMultiple = async (staffIds: string[]) => {
const promises = staffIds.map(id =>
fetch(`/api/staff/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ is_active: true })
})
);

await Promise.all(promises);
};

Data Retention

Retention Policy

Deactivated staff data is retained according to legal requirements:

Data TypeRetention Period
Employment records6 years after departure
Payroll/tax records6 years
Disciplinary recordsDuration of warning + 12 months
Training records3 years
Medical records40 years (occupational health)

Permanent Deletion

If permanent deletion is required (e.g., GDPR request):

  1. Verify eligibility - Check legal retention requirements
  2. Document request - Record the deletion request
  3. Remove from database - Delete staff record
  4. Clear storage - Remove associated documents
  5. Audit log - Record deletion in audit trail
GDPR Compliance

Permanent deletion should only be performed when legally required and after verification that retention periods have been met.


Access Control

Login Status

When a staff member is deactivated:

ScenarioAccess
Active sessionMay continue until logout
New login attemptShould be prevented
Password resetShould be blocked

Immediate Lockout

For immediate access revocation, consider:

  1. Force logout - Invalidate active sessions
  2. Password reset - Change password to random value
  3. Account lock - Set account lock flag

Reporting

Including Inactive Staff

Reports can include or exclude inactive staff:

// Include all staff
const allStaff = await supabase
.from('staff')
.select('*')
.eq('company_id', companyId);

// Active only (default)
const activeStaff = await supabase
.from('staff')
.select('*')
.eq('company_id', companyId)
.eq('is_active', true);

// Inactive only
const inactiveStaff = await supabase
.from('staff')
.select('*')
.eq('company_id', companyId)
.eq('is_active', false);

Historical Reports

For historical accuracy, reports typically include all staff who were active during the reporting period, regardless of current status.


Best Practices

Deactivation Timing

ScenarioRecommended Timing
ResignationLast working day
TerminationEffective immediately
RetirementLast working day
Leave of absenceStart of leave (if extended)
Seasonal endEnd of season

Communication

  1. Internal - Inform relevant team members
  2. Scheduling - Update future rotas promptly
  3. Handover - Ensure knowledge transfer
  4. Documentation - Record departure details

Compliance

  1. Follow company policy - Adhere to HR procedures
  2. Document reasons - Maintain departure records
  3. Exit interviews - Conduct when appropriate
  4. Reference requests - Prepare for future references

Troubleshooting

Common Issues

IssueSolution
Cannot find inactive staffChange filter to "All" or "Inactive"
Deactivation failedCheck network connection, verify permissions
Staff still showing in dropdownsRefresh page, clear cache
Future shifts not cancelledManually cancel or reassign shifts

Error Messages

ErrorCauseSolution
"Failed to deactivate"API errorCheck console for details
"Permission denied"Insufficient rightsContact administrator
"Staff not found"Invalid IDRefresh staff list


Source Files:

  • src/components/staff/StaffList.tsx - Deactivation handler
  • src/components/staff/CompanyStaffManagement.tsx - Status filtering
  • src/app/api/staff/[id]/route.ts - Staff update API
  • src/types/database.types.ts - Staff type definitions