Delete features (#218)
* Implement company and account deletion features - Add event types for company and account deletion to CoreEvent. - Enhance Supabase middleware to handle company context resolution and cookie management for archived companies. - Create API routes for deleting accounts and companies, including necessary validations and event emissions. - Implement tests for account and company deletion endpoints to ensure proper functionality and error handling. - Add retention notice component to inform users about bookkeeping data retention during destructive actions. - Create database migrations to support soft deletion of companies and anonymization of user accounts, ensuring compliance with retention laws. * feat: enhance account deletion process and update user notifications * Add service client for onboarding completion check and update escape hatch visibility * Enhance invite flow and email handling for company members * Refactor company context and RLS policies for active company isolation - Update `switchCompany` to remove unnecessary revalidation as client handles navigation. - Revise `getActiveCompanyId` to prioritize `user_preferences` and validate against non-archived memberships. - Modify `setActiveCompany` to ensure `user_preferences` is the authoritative source while maintaining cookie compatibility. - Enhance middleware to resolve active company using `user_preferences` and fallback to first non-archived membership. - Introduce new API route `/api/company/current` to fetch the active company ID for cross-tab synchronization. - Implement `CompanyTabSync` component for real-time active company enforcement across tabs. - Create migration for RLS policies to enforce single-active-company isolation using `current_active_company_id()`. * feat: implement viewer role enforcement for write permissions - Added `useCanWrite` hook to determine if the current user has write permissions based on their role in the active company. - Updated various components (JournalEntryForm, CustomerForm, DeadlineForm, etc.) to disable write actions and show a lock icon with a tooltip for users without write permissions. - Introduced `requireWritePermission` function to enforce write permissions at the API level, returning a 403 response for viewers. - Created tests to verify the behavior of the viewer role and write permissions. - Added database migration to enforce read-only access for viewers at the database level.
This commit is contained in:
@@ -21,6 +21,8 @@ import {
|
||||
} from '@/components/ui/select'
|
||||
import { Deadline, DeadlineType, DeadlinePriority } from '@/types'
|
||||
import { formatDateISO, DEADLINE_TYPE_LABELS, PRIORITY_LABELS } from '@/lib/calendar/utils'
|
||||
import { useCanWrite } from '@/lib/hooks/use-can-write'
|
||||
import { Lock } from 'lucide-react'
|
||||
|
||||
interface DeadlineFormProps {
|
||||
open: boolean
|
||||
@@ -41,6 +43,7 @@ export function DeadlineForm({
|
||||
initialDate,
|
||||
customers,
|
||||
}: DeadlineFormProps) {
|
||||
const { canWrite } = useCanWrite()
|
||||
const [confirmDelete, setConfirmDelete] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [formData, setFormData] = useState({
|
||||
@@ -300,7 +303,12 @@ export function DeadlineForm({
|
||||
>
|
||||
Avbryt
|
||||
</Button>
|
||||
<Button type="submit" disabled={isLoading || !formData.title}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isLoading || !formData.title || !canWrite}
|
||||
title={!canWrite ? 'Du har endast läsbehörighet i detta företag' : undefined}
|
||||
>
|
||||
{!canWrite && <Lock className="mr-2 h-4 w-4" />}
|
||||
{isLoading ? 'Sparar...' : initialData?.id ? 'Spara' : 'Skapa'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,8 @@ import { DeadlineCard } from './DeadlineCard'
|
||||
import { DeadlineFilters } from './DeadlineFilters'
|
||||
import { DeadlineForm } from './DeadlineForm'
|
||||
import { isDeadlineOverdue } from '@/lib/calendar/utils'
|
||||
import { Plus } from 'lucide-react'
|
||||
import { Plus, Lock } from 'lucide-react'
|
||||
import { useCanWrite } from '@/lib/hooks/use-can-write'
|
||||
|
||||
interface DeadlineListProps {
|
||||
deadlines: Deadline[]
|
||||
@@ -26,6 +27,7 @@ export function DeadlineList({
|
||||
onDeadlineEdit,
|
||||
onDeadlineDelete,
|
||||
}: DeadlineListProps) {
|
||||
const { canWrite } = useCanWrite()
|
||||
const [statusFilter, setStatusFilter] = useState<'all' | 'pending' | 'completed'>('pending')
|
||||
const [typeFilter, setTypeFilter] = useState<DeadlineType | 'all'>('all')
|
||||
const [showForm, setShowForm] = useState(false)
|
||||
@@ -105,8 +107,16 @@ export function DeadlineList({
|
||||
onTypeChange={setTypeFilter}
|
||||
onReset={handleResetFilters}
|
||||
/>
|
||||
<Button onClick={() => setShowForm(true)}>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
<Button
|
||||
onClick={() => setShowForm(true)}
|
||||
disabled={!canWrite}
|
||||
title={!canWrite ? 'Du har endast läsbehörighet i detta företag' : undefined}
|
||||
>
|
||||
{canWrite ? (
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Lock className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Ny deadline
|
||||
</Button>
|
||||
</div>
|
||||
@@ -124,8 +134,14 @@ export function DeadlineList({
|
||||
size="sm"
|
||||
className="mt-4"
|
||||
onClick={() => setShowForm(true)}
|
||||
disabled={!canWrite}
|
||||
title={!canWrite ? 'Du har endast läsbehörighet i detta företag' : undefined}
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5 mr-1.5" />
|
||||
{canWrite ? (
|
||||
<Plus className="h-3.5 w-3.5 mr-1.5" />
|
||||
) : (
|
||||
<Lock className="h-3.5 w-3.5 mr-1.5" />
|
||||
)}
|
||||
Skapa en deadline
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user