teqo-backup/src/lib/campaignQuickActionMount.ts
Francisco Solla 0d483a08db feat(campaign): C142 UI respects advisor permission profile somente_leitura
- Pure helpers: advisorEditingScope, rowEditingAllowed in campaignAdvisorProfile.ts
- gate: 'writable' in requireCampaignPageActor for route-level enforcement
- Shared cells accept readOnly prop: CampaignInlineEditableCell, MunicipalityRelationEditor, PhonesFieldEditor, DemandDescriptionEditor, etc.
- Municipality pages compute editingScope via resolveMunicipalityWriteScope and thread it to list/detail/edit surfaces
- Home actions, FAB mount rule, quick actions registry accept editingScope parameter
- Demands, activities, supporters, organizations create buttons gated
- E2E spec: campaignPermissionProfile.e2e.spec.ts covering 3 profiles
- Unit tests: campaignAdvisorProfile, accessShared, campaignComponents updated
- gate:fast passed (tsc, lint, format, knip, cycles, unit)
2026-08-21 23:01:35 -03:00

46 lines
2.1 KiB
TypeScript

import { CAMPAIGN_ACTIONS_HOME } from '@/lib/campaignActionRoutes'
import type { AdvisorEditingScope } from '@/lib/campaignAdvisorProfile'
import { isAdvisorsPath } from '@/lib/campaignAdvisorQuickActions'
import { CAMPAIGN_CONTACTS_HOME, CAMPAIGN_HOME, LEADER_CONTACTS_HOME } from '@/lib/campaignPaths'
import { isActivityTourComposerPath, isListPath } from '@/lib/campaignQuickActionPaths'
import {
isStaffCampaignRole,
isUnrestrictedCampaignRole,
type CampaignRole,
} from '@/lib/campaignRoles'
/** Same exact-match rule as the sidebar nav. */
export const isCampaignHomePath = (pathname: string): boolean => isListPath(pathname, CAMPAIGN_HOME)
export const isCampaignActionsPath = (pathname: string): boolean =>
pathname === CAMPAIGN_ACTIONS_HOME || pathname.startsWith(`${CAMPAIGN_ACTIONS_HOME}/`)
export const isLeaderContactsPath = (pathname: string): boolean =>
pathname === LEADER_CONTACTS_HOME || pathname.startsWith(`${LEADER_CONTACTS_HOME}/`)
/** C139 — the staff contacts page owns a create FAB of its own, so the
* quick-actions drawer stays out of it. */
export const isContactsPath = (pathname: string): boolean =>
pathname === CAMPAIGN_CONTACTS_HOME || pathname.startsWith(`${CAMPAIGN_CONTACTS_HOME}/`)
/**
* Whether the quick-actions FAB should mount on this navigation (all viewports).
* C142 — advisors with `somente_leitura` never see the FAB on staff surfaces
* (every action is a write destination).
*/
export const shouldMountQuickActionsFab = (
pathname: string,
role: CampaignRole,
editingScope: AdvisorEditingScope = 'tudo',
): boolean => {
if (isCampaignHomePath(pathname)) return false
if (isCampaignActionsPath(pathname)) return false
// B84: E13 compositor already exposes primary CTAs — skip competing drawer chrome.
if (isActivityTourComposerPath(pathname)) return false
if (role === 'leader') return isLeaderContactsPath(pathname)
if (isContactsPath(pathname)) return false
if (isAdvisorsPath(pathname)) return isUnrestrictedCampaignRole(role)
if (!isStaffCampaignRole(role)) return false
// C142 — `somente_leitura` advisors see no write actions in the drawer.
return editingScope !== 'none'
}