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:
| Status | Meaning | Effect |
|---|---|---|
| Active | Company is operational | Full access for all users |
| Inactive | Company is suspended | Access restricted |
Status Effects
When a company is deactivated:
| Component | Effect |
|---|---|
| Company Managers | Cannot login |
| Staff Members | Cannot login |
| Data | Preserved but inaccessible |
| Schedules | Frozen, no new entries |
| Reports | Cannot be generated |
| API Access | Blocked 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
| Scenario | Action |
|---|---|
| New company setup complete | Activate to enable access |
| Subscription renewed | Reactivate after payment |
| Issue resolved | Restore access after fix |
| Trial period started | Enable 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:
| Component | Before | After |
|---|---|---|
| Login | Blocked | Enabled |
| Dashboard | Inaccessible | Full access |
| Scheduling | Frozen | Operational |
| Time Tracking | Disabled | Enabled |
| Reports | Blocked | Available |
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
| Scenario | Priority | Duration |
|---|---|---|
| Non-payment | High | Until resolved |
| Contract ended | High | Permanent |
| Security incident | Critical | Until resolved |
| Requested by company | Medium | As requested |
| Compliance issue | High | Until resolved |
Deactivation Considerations
Before deactivating, consider:
- Active Staff - Users will lose access immediately
- Scheduled Shifts - Future shifts remain but are inaccessible
- Pending Requests - Leave requests become frozen
- Time Entries - Current week entries may be affected
- 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
| Indicator | Colour | Meaning |
|---|---|---|
| Active | 🟢 Green | Company operational |
| Inactive | 🔴 Red | Company 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 Role | Can Login | Can 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
| Event | Logged Data |
|---|---|
| Activation | Timestamp, admin ID, reason |
| Deactivation | Timestamp, 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
- Notify Company Manager - Give advance warning when possible
- Document Reason - Record why company is being deactivated
- Review Active Data - Check for pending operations
- Consider Timing - Avoid mid-shift deactivation
- Prepare Communication - Draft user notification
After Reactivation
- Notify Company Manager - Confirm access restored
- Verify Access - Test login functionality
- Check Data Integrity - Ensure no data corruption
- Review Pending Items - Process frozen requests
- Update Records - Document reactivation
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Toggle failed | Network error | Retry operation |
| Users still blocked | Cache delay | Wait 5 minutes or clear cache |
| Status not updating | Database error | Check Supabase logs |
| Forbidden error | Not System Admin | Verify role permissions |
Error Messages
| Error | Meaning | Action |
|---|---|---|
| "Invalid request data" | Missing active field | Include { active: boolean } |
| "Forbidden" | Not authorised | Login as System Admin |
| "Company not found" | Invalid company ID | Verify company exists |
| "Database error" | Server issue | Contact support |
Related Documentation
- Creating Companies - Create new companies
- Editing Companies - Update details
- Company Deletion - Remove companies
- Viewing Users - User management
Source Files:
src/app/api/companies/[companyId]/toggle-status/route.ts- Status toggle APIsrc/lib/db/company.ts- Database operationssrc/lib/validation/company.schemas.ts- Validation schemassrc/types/database.types.ts- Database type definitions