Skip to main content

Company Status

This guide covers how to manage company status, including activating and deactivating companies and understanding the effects on users and data.


Overview​

What is Company Status?​

Company status controls whether a company is operational on the platform:

StatusMeaningEffect
ActiveCompany is operationalFull access for all users
InactiveCompany is suspendedAccess restricted

Status Effects​

When a company is deactivated:

ComponentEffect
Company ManagersCannot login
Staff MembersCannot login
DataPreserved but inaccessible
SchedulesFrozen, no new entries
ReportsCannot be generated
API AccessBlocked for company users

Toggle Status API​

Endpoint​

Endpoint: POST /api/companies/[companyId]/toggle-status

// Source: src/app/api/companies/[companyId]/toggle-status/route.ts:19-51
export async function POST(request: NextRequest, { params }: RouteParams) {
try {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()

if (!user) {
return ApiResponses.unauthorized()
}

// Check if user is system admin
if (getAuthRole(user) !== 'SYSTEM_ADMIN') {
return ApiResponses.forbidden('Forbidden - System Admin access required')
}

const body = await request.json()
const validationResult = toggleStatusSchema.safeParse(body)

if (!validationResult.success) {
return ApiResponses.badRequest('Invalid request data', validationResult.error.flatten().fieldErrors)
}

// Update company status
const result = await companyDB.updateCompany(
params.companyId,
{ is_active: validationResult.data.active }
)

return ApiResponses.success(result.data, { timing: result.timing.duration })

} catch (error) {
return handleApiError(error)
}
}

Validation Schema​

// Source: src/app/api/companies/[companyId]/toggle-status/route.ts:15-17
const toggleStatusSchema = z.object({
active: z.boolean()
})

Request Format​

// Toggle company status
const toggleCompanyStatus = async (companyId: string, active: boolean) => {
const response = await fetch(`/api/companies/${companyId}/toggle-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ active })
})

return response.json()
}

// Deactivate company
await toggleCompanyStatus('company-uuid', false)

// Activate company
await toggleCompanyStatus('company-uuid', true)

Response Format​

// Successful toggle response
{
success: true,
data: {
id: "company-uuid",
name: "Example Practice",
is_active: false, // or true
updated_at: "2025-01-14T10:30:00Z"
},
timing: "45ms"
}

Activating Companies​

When to Activate​

ScenarioAction
New company setup completeActivate to enable access
Subscription renewedReactivate after payment
Issue resolvedRestore access after fix
Trial period startedEnable for evaluation

Activation Process​

1. Navigate to company details
2. Review company status
3. Click "Activate Company"
4. Confirm activation
5. Company and users gain access

Activation Effects​

When a company is activated:

ComponentBeforeAfter
LoginBlockedEnabled
DashboardInaccessibleFull access
SchedulingFrozenOperational
Time TrackingDisabledEnabled
ReportsBlockedAvailable

API Example​

// Activate company
const activateCompany = async (companyId: string) => {
const response = await fetch(`/api/companies/${companyId}/toggle-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ active: true })
})

if (!response.ok) {
throw new Error('Failed to activate company')
}

return response.json()
}

Deactivating Companies​

When to Deactivate​

ScenarioPriorityDuration
Non-paymentHighUntil resolved
Contract endedHighPermanent
Security incidentCriticalUntil resolved
Requested by companyMediumAs requested
Compliance issueHighUntil resolved

Deactivation Considerations​

Before deactivating, consider:

  1. Active Staff - Users will lose access immediately
  2. Scheduled Shifts - Future shifts remain but are inaccessible
  3. Pending Requests - Leave requests become frozen
  4. Time Entries - Current week entries may be affected
  5. Data Retention - All data is preserved
Impact on Operations

Deactivating a company immediately affects all users. Consider notifying the Company Manager before deactivation when possible.

Deactivation Process​

1. Navigate to company details
2. Review active users and data
3. Click "Deactivate Company"
4. Enter reason for deactivation
5. Confirm deactivation
6. Notification sent to managers

API Example​

// Deactivate company
const deactivateCompany = async (companyId: string) => {
const response = await fetch(`/api/companies/${companyId}/toggle-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ active: false })
})

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

return response.json()
}

Status Check​

Viewing Company Status​

// Check company status
const getCompanyStatus = async (companyId: string) => {
const response = await fetch(`/api/companies/${companyId}`)
const { data } = await response.json()

return {
id: data.id,
name: data.name,
isActive: data.isActive,
updatedAt: data.updatedAt
}
}

Status Indicators​

IndicatorColourMeaning
Active🟢 GreenCompany operational
Inactive🔴 RedCompany suspended

Status Display Component​

// Company status badge
const CompanyStatusBadge = ({ isActive }: { isActive: boolean }) => (
<span className={`
px-2 py-1 rounded text-sm font-medium
${isActive
? 'bg-green-500/20 text-green-300'
: 'bg-red-500/20 text-red-300'
}
`}>
{isActive ? 'Active' : 'Inactive'}
</span>
)

Access Control​

User Impact​

When company is inactive:

User RoleCan LoginCan Access Data
System Admin✅ Yes✅ Yes (admin view)
Company Manager❌ No❌ No
Staff❌ No❌ No

Login Behaviour​

// Login check for inactive company
const checkCompanyAccess = async (user: User) => {
if (user.role === 'SYSTEM_ADMIN') {
return true // System admins always have access
}

const { data: company } = await supabase
.from('companies')
.select('is_active')
.eq('id', user.company_id)
.single()

if (!company?.is_active) {
throw new Error('Your company account has been suspended. Please contact support.')
}

return true
}

Error Messages​

// Error shown to users of inactive company
{
error: "Account Suspended",
message: "Your company account has been suspended. Please contact your administrator for assistance.",
code: "COMPANY_INACTIVE"
}

Bulk Status Operations​

Update Multiple Companies​

// Source: src/lib/validation/company.schemas.ts:191-199
export const bulkUpdateCompanySchema = z.object({
company_ids: z.array(uuidSchema).min(1, 'At least one company ID is required'),
updates: z.object({
is_active: z.boolean().optional(),
industry_template_id: uuidSchema.optional()
}).refine(data => Object.keys(data).length > 0, {
message: 'At least one field must be provided for update'
})
})

Bulk Toggle Example​

// Deactivate multiple companies
const bulkDeactivate = async (companyIds: string[]) => {
const results = await Promise.all(
companyIds.map(id =>
fetch(`/api/companies/${id}/toggle-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ active: false })
})
)
)

return results
}

Status History​

Tracking Changes​

EventLogged Data
ActivationTimestamp, admin ID, reason
DeactivationTimestamp, admin ID, reason

Activity Log Entry​

// Status change activity log
{
action: 'company_status_changed',
company_id: 'company-uuid',
created_by: 'admin-uuid',
details: {
previous_status: true,
new_status: false,
reason: 'Non-payment'
},
created_at: '2025-01-14T10:30:00Z'
}

Viewing Status History​

// Get company status history
const getStatusHistory = async (companyId: string) => {
const { data } = await supabase
.from('company_manager_activity_logs')
.select('*')
.eq('company_id', companyId)
.eq('action', 'company_status_changed')
.order('created_at', { ascending: false })

return data
}

UI Components​

Status Toggle Button​

// Company status toggle
const StatusToggle = ({ company, onToggle }) => {
const [loading, setLoading] = useState(false)

const handleToggle = async () => {
setLoading(true)

try {
await onToggle(!company.isActive)
} finally {
setLoading(false)
}
}

return (
<button
onClick={handleToggle}
disabled={loading}
className={`
px-4 py-2 rounded font-medium
${company.isActive
? 'bg-red-500/20 text-red-300 hover:bg-red-500/30'
: 'bg-green-500/20 text-green-300 hover:bg-green-500/30'
}
`}
>
{loading
? 'Updating...'
: company.isActive ? 'Deactivate' : 'Activate'
}
</button>
)
}

Confirmation Modal​

// Deactivation confirmation modal
const DeactivateConfirmModal = ({ company, onConfirm, onCancel }) => (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="card-glass p-6 max-w-md w-full mx-4">
<h2 className="text-xl font-semibold text-red-400 mb-4">
Deactivate Company
</h2>

<p className="text-secondary-text mb-4">
Are you sure you want to deactivate <strong>{company.name}</strong>?
</p>

<div className="bg-red-500/10 border border-red-500/20 rounded p-3 mb-4">
<p className="text-sm text-red-300">
This will immediately block access for all company users.
</p>
</div>

<div className="flex gap-3">
<button onClick={onCancel} className="form-button secondary flex-1">
Cancel
</button>
<button onClick={onConfirm} className="form-button danger flex-1">
Deactivate
</button>
</div>
</div>
</div>
)

Best Practices​

Before Deactivation​

  1. Notify Company Manager - Give advance warning when possible
  2. Document Reason - Record why company is being deactivated
  3. Review Active Data - Check for pending operations
  4. Consider Timing - Avoid mid-shift deactivation
  5. Prepare Communication - Draft user notification

After Reactivation​

  1. Notify Company Manager - Confirm access restored
  2. Verify Access - Test login functionality
  3. Check Data Integrity - Ensure no data corruption
  4. Review Pending Items - Process frozen requests
  5. Update Records - Document reactivation

Troubleshooting​

Common Issues​

IssueCauseSolution
Toggle failedNetwork errorRetry operation
Users still blockedCache delayWait 5 minutes or clear cache
Status not updatingDatabase errorCheck Supabase logs
Forbidden errorNot System AdminVerify role permissions

Error Messages​

ErrorMeaningAction
"Invalid request data"Missing active fieldInclude { active: boolean }
"Forbidden"Not authorisedLogin as System Admin
"Company not found"Invalid company IDVerify company exists
"Database error"Server issueContact support


Source Files:

  • src/app/api/companies/[companyId]/toggle-status/route.ts - Status toggle API
  • src/lib/db/company.ts - Database operations
  • src/lib/validation/company.schemas.ts - Validation schemas
  • src/types/database.types.ts - Database type definitions