e11f70b347
* refactor: optimize page loading and data fetching * fix: resolve recurring production runtime errors * feat: add MCP company and customer updates * fix: handle year-end tax adjustments * feat: harden annual report compliance * fix: expand invoice logo and font support * fix: sanitize API route error responses * fix: sanitize user-facing error messages * feat: persist onboarding and tax assessment notices * fix: reduce cloud backup audit churn * feat: refine invoice editor layout * fix: show saved tax adjustments in INK2 * fix: complete annual report API mappings * docs: record operational safeguards and decisions * fix: harden annual report review findings * fix: adjust column span for description based on VAT registration * New css class name
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import 'server-only'
|
|
|
|
import { cache } from 'react'
|
|
import { createClient } from '@/lib/supabase/server'
|
|
import { getActiveCompanyId } from '@/lib/company/context'
|
|
import { ensureSandboxAgentProfile } from '@/lib/sandbox/ensure-agent'
|
|
|
|
/**
|
|
* Request-local dashboard auth context. React cache shares the Supabase client
|
|
* and auth lookup between the dashboard layout and every nested server page.
|
|
*/
|
|
export const getDashboardAuthContext = cache(async () => {
|
|
const supabase = await createClient()
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser()
|
|
|
|
return { supabase, user }
|
|
})
|
|
|
|
/**
|
|
* Request-local active company resolution. Nested layouts and pages commonly
|
|
* need the same value, so resolving it once removes repeated preference and
|
|
* membership round trips without caching anything across requests.
|
|
*/
|
|
export const getDashboardCompanyId = cache(async () => {
|
|
const { supabase, user } = await getDashboardAuthContext()
|
|
return user ? getActiveCompanyId(supabase, user.id) : null
|
|
})
|
|
|
|
export const getDashboardSettings = cache(async () => {
|
|
const [{ supabase }, companyId] = await Promise.all([
|
|
getDashboardAuthContext(),
|
|
getDashboardCompanyId(),
|
|
])
|
|
if (!companyId) return { data: null, error: null }
|
|
|
|
return supabase
|
|
.from('company_settings')
|
|
.select('company_name, onboarding_complete, entity_type, pays_salaries, is_sandbox, dimensions_enabled, ore_rounding, initial_setup_path, initial_setup_completed_at, initial_setup_dismissed_at')
|
|
.eq('company_id', companyId)
|
|
.maybeSingle()
|
|
})
|
|
|
|
const getDashboardAgentProfile = cache(async () => {
|
|
const [{ supabase }, companyId] = await Promise.all([
|
|
getDashboardAuthContext(),
|
|
getDashboardCompanyId(),
|
|
])
|
|
if (!companyId) return { data: null, error: null }
|
|
|
|
return supabase
|
|
.from('agent_profiles')
|
|
.select('display_name, avatar_id, verified_at')
|
|
.eq('company_id', companyId)
|
|
.maybeSingle()
|
|
})
|
|
|
|
export const getResolvedDashboardAgentProfile = cache(async () => {
|
|
const [{ supabase }, companyId, settingsResult, profileResult] = await Promise.all([
|
|
getDashboardAuthContext(),
|
|
getDashboardCompanyId(),
|
|
getDashboardSettings(),
|
|
getDashboardAgentProfile(),
|
|
])
|
|
|
|
let profile = profileResult.data
|
|
if (companyId && settingsResult.data?.is_sandbox === true && !profile?.verified_at) {
|
|
await ensureSandboxAgentProfile(supabase, companyId)
|
|
const refreshed = await supabase
|
|
.from('agent_profiles')
|
|
.select('display_name, avatar_id, verified_at')
|
|
.eq('company_id', companyId)
|
|
.maybeSingle()
|
|
profile = refreshed.data ?? profile
|
|
}
|
|
|
|
return profile
|
|
})
|