Wave A (Interest+EOI form quick wins): - Auto-select yacht after inline-create from interest form - EOI generate dialog: "View EOI" action toast - Interest form berth picker: formatBerthRange compact label - Remove "Generate EOI" button from Documents tab (clean removal) - Interest auto-assign: only sales_agent/sales_manager auto-claim ownership on create (explicit role check via user_port_roles join) - LinkedBerthRowItem dims: drop "D" suffix + "L × W" format - ExternalEoiUploadDialog: prefillSignatories prop threaded from active EOI signers - EOI signature progress on Overview milestone card footer Wave B (a11y + i18n sweeps): - aria-live on supplemental-info error state - text-[10px] -> text-xs in client-pipeline-summary - Currency formatter: locale default removed (Intl uses runtime) - en-US/en-GB hardcoded toLocaleString swept across 13 components Wave C (Primary berth always in EOI bundle): - Service guard strengthened on update path - Migration 0083 backfills historical primary rows Wave D (Onboarding super_admin discoverability): - /api/v1/admin/onboarding/status endpoint + shared service - Topbar OnboardingBanner (super_admin, session-dismissible) - OnboardingTile dashboard widget (rail group, self-hides at 100%) - Celebration toast + invalidate of shared status on last tick Wave E (Branded post-completion email idempotency): - Verified handleDocumentCompleted already owns the email fan-out - Added regression test for the polling path + idempotency Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
'use client';
|
|
|
|
import { useQuery } from '@tanstack/react-query';
|
|
|
|
import { apiFetch } from '@/lib/api/client';
|
|
|
|
export interface OnboardingStatusStep {
|
|
id: string;
|
|
href: string;
|
|
label: string;
|
|
description: string;
|
|
done: boolean;
|
|
auto: boolean;
|
|
}
|
|
|
|
export interface OnboardingStatusPayload {
|
|
steps: OnboardingStatusStep[];
|
|
completed: number;
|
|
total: number;
|
|
percent: number;
|
|
isComplete: boolean;
|
|
nextStep: { id: string; label: string; href: string } | null;
|
|
}
|
|
|
|
/**
|
|
* Shared onboarding-status query. Drives the topbar banner, dashboard tile,
|
|
* and the admin checklist summary. Cached for 60s so all three surfaces
|
|
* share a single fetch on first paint.
|
|
*
|
|
* Pass `enabled=false` to skip the network call (e.g. when the current
|
|
* user isn't a super_admin and the surface won't render anyway).
|
|
*/
|
|
export function useOnboardingStatus(opts: { enabled?: boolean } = {}) {
|
|
return useQuery<OnboardingStatusPayload>({
|
|
queryKey: ['admin', 'onboarding-status'],
|
|
queryFn: () =>
|
|
apiFetch<{ data: OnboardingStatusPayload }>('/api/v1/admin/onboarding/status').then(
|
|
(r) => r.data,
|
|
),
|
|
staleTime: 60_000,
|
|
enabled: opts.enabled ?? true,
|
|
retry: false,
|
|
});
|
|
}
|