@kelpie/ui 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/resources/attendances.d.ts +13 -0
- package/dist/api/resources/attendances.d.ts.map +1 -0
- package/dist/api/resources/attendances.js +34 -0
- package/dist/api/resources/attendances.js.map +1 -0
- package/dist/api/resources/eventAssociations.d.ts +12 -0
- package/dist/api/resources/eventAssociations.d.ts.map +1 -0
- package/dist/api/resources/eventAssociations.js +25 -0
- package/dist/api/resources/eventAssociations.js.map +1 -0
- package/dist/api/resources/events.d.ts +17 -0
- package/dist/api/resources/events.d.ts.map +1 -0
- package/dist/api/resources/events.js +40 -0
- package/dist/api/resources/events.js.map +1 -0
- package/dist/api/resources/handbookSeed.d.ts +11 -0
- package/dist/api/resources/handbookSeed.d.ts.map +1 -0
- package/dist/api/resources/handbookSeed.js +43 -0
- package/dist/api/resources/handbookSeed.js.map +1 -0
- package/dist/api/resources/moduleSettings.d.ts +10 -0
- package/dist/api/resources/moduleSettings.d.ts.map +1 -1
- package/dist/api/resources/moduleSettings.js +21 -0
- package/dist/api/resources/moduleSettings.js.map +1 -1
- package/dist/api/resources/planItems.d.ts +4 -4
- package/dist/api/resources/planItems.d.ts.map +1 -1
- package/dist/api/resources/planItems.js +1 -1
- package/dist/api/resources/planItems.js.map +1 -1
- package/dist/api/resources/publicConfig.js +3 -3
- package/dist/api/resources/sampleData.d.ts.map +1 -1
- package/dist/api/resources/sampleData.js +2 -0
- package/dist/api/resources/sampleData.js.map +1 -1
- package/dist/api/resources/session.d.ts +22 -1
- package/dist/api/resources/session.d.ts.map +1 -1
- package/dist/api/resources/session.js +43 -1
- package/dist/api/resources/session.js.map +1 -1
- package/dist/api/resources/workspace.d.ts.map +1 -1
- package/dist/api/resources/workspace.js +2 -3
- package/dist/api/resources/workspace.js.map +1 -1
- package/dist/app/KelpieApp.d.ts.map +1 -1
- package/dist/app/KelpieApp.js +5 -1
- package/dist/app/KelpieApp.js.map +1 -1
- package/dist/components/ActivitiesPanel.d.ts.map +1 -1
- package/dist/components/ActivitiesPanel.js +2 -0
- package/dist/components/ActivitiesPanel.js.map +1 -1
- package/dist/components/AddressesField.d.ts +23 -0
- package/dist/components/AddressesField.d.ts.map +1 -0
- package/dist/components/AddressesField.js +215 -0
- package/dist/components/AddressesField.js.map +1 -0
- package/dist/components/CountrySearch.d.ts +16 -0
- package/dist/components/CountrySearch.d.ts.map +1 -0
- package/dist/components/CountrySearch.js +30 -0
- package/dist/components/CountrySearch.js.map +1 -0
- package/dist/components/EnvironmentBanner.d.ts +0 -12
- package/dist/components/EnvironmentBanner.d.ts.map +1 -1
- package/dist/components/EnvironmentBanner.js +21 -6
- package/dist/components/EnvironmentBanner.js.map +1 -1
- package/dist/components/InlineEdit.d.ts +7 -1
- package/dist/components/InlineEdit.d.ts.map +1 -1
- package/dist/components/InlineEdit.js +8 -1
- package/dist/components/InlineEdit.js.map +1 -1
- package/dist/components/LinkedEventsPanel.d.ts +11 -0
- package/dist/components/LinkedEventsPanel.d.ts.map +1 -0
- package/dist/components/LinkedEventsPanel.js +18 -0
- package/dist/components/LinkedEventsPanel.js.map +1 -0
- package/dist/components/NotesPanel.d.ts +4 -6
- package/dist/components/NotesPanel.d.ts.map +1 -1
- package/dist/components/NotesPanel.js +39 -3
- package/dist/components/NotesPanel.js.map +1 -1
- package/dist/components/PlanAttention.d.ts.map +1 -1
- package/dist/components/PlanAttention.js +3 -2
- package/dist/components/PlanAttention.js.map +1 -1
- package/dist/components/PlanPanel.d.ts +3 -3
- package/dist/components/PlanPanel.d.ts.map +1 -1
- package/dist/components/Shell.d.ts.map +1 -1
- package/dist/components/Shell.js +8 -2
- package/dist/components/Shell.js.map +1 -1
- package/dist/components/SocialNetworkIcon.d.ts +17 -0
- package/dist/components/SocialNetworkIcon.d.ts.map +1 -0
- package/dist/components/SocialNetworkIcon.js +39 -0
- package/dist/components/SocialNetworkIcon.js.map +1 -0
- package/dist/components/SocialProfilesField.d.ts +8 -0
- package/dist/components/SocialProfilesField.d.ts.map +1 -1
- package/dist/components/SocialProfilesField.js +19 -5
- package/dist/components/SocialProfilesField.js.map +1 -1
- package/dist/components/TimezoneSearch.d.ts +21 -0
- package/dist/components/TimezoneSearch.d.ts.map +1 -0
- package/dist/components/TimezoneSearch.js +27 -0
- package/dist/components/TimezoneSearch.js.map +1 -0
- package/dist/components/WorkspaceSwitcher.d.ts +8 -0
- package/dist/components/WorkspaceSwitcher.d.ts.map +1 -0
- package/dist/components/WorkspaceSwitcher.js +67 -0
- package/dist/components/WorkspaceSwitcher.js.map +1 -0
- package/dist/components/environmentTone.d.ts +10 -0
- package/dist/components/environmentTone.d.ts.map +1 -0
- package/dist/components/environmentTone.js +35 -0
- package/dist/components/environmentTone.js.map +1 -0
- package/dist/index.d.ts +25 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/timezones.d.ts +17 -0
- package/dist/lib/timezones.d.ts.map +1 -0
- package/dist/lib/timezones.js +39 -0
- package/dist/lib/timezones.js.map +1 -0
- package/dist/pages/CompaniesPage.d.ts.map +1 -1
- package/dist/pages/CompaniesPage.js +12 -11
- package/dist/pages/CompaniesPage.js.map +1 -1
- package/dist/pages/CompanyDetail.d.ts.map +1 -1
- package/dist/pages/CompanyDetail.js +23 -12
- package/dist/pages/CompanyDetail.js.map +1 -1
- package/dist/pages/DealDetail.d.ts.map +1 -1
- package/dist/pages/DealDetail.js +5 -1
- package/dist/pages/DealDetail.js.map +1 -1
- package/dist/pages/DecisionsPage.d.ts.map +1 -1
- package/dist/pages/DecisionsPage.js +7 -0
- package/dist/pages/DecisionsPage.js.map +1 -1
- package/dist/pages/EnquiryDetail.d.ts.map +1 -1
- package/dist/pages/EnquiryDetail.js +5 -1
- package/dist/pages/EnquiryDetail.js.map +1 -1
- package/dist/pages/EventDetail.d.ts +2 -0
- package/dist/pages/EventDetail.d.ts.map +1 -0
- package/dist/pages/EventDetail.js +332 -0
- package/dist/pages/EventDetail.js.map +1 -0
- package/dist/pages/EventsPage.d.ts +2 -0
- package/dist/pages/EventsPage.d.ts.map +1 -0
- package/dist/pages/EventsPage.js +176 -0
- package/dist/pages/EventsPage.js.map +1 -0
- package/dist/pages/ListDetail.d.ts.map +1 -1
- package/dist/pages/ListDetail.js +17 -0
- package/dist/pages/ListDetail.js.map +1 -1
- package/dist/pages/OpportunityDetail.d.ts.map +1 -1
- package/dist/pages/OpportunityDetail.js +5 -1
- package/dist/pages/OpportunityDetail.js.map +1 -1
- package/dist/pages/PartnershipDetail.d.ts.map +1 -1
- package/dist/pages/PartnershipDetail.js +5 -1
- package/dist/pages/PartnershipDetail.js.map +1 -1
- package/dist/pages/PeoplePage.d.ts.map +1 -1
- package/dist/pages/PeoplePage.js +13 -5
- package/dist/pages/PeoplePage.js.map +1 -1
- package/dist/pages/PersonDetail.d.ts.map +1 -1
- package/dist/pages/PersonDetail.js +94 -28
- package/dist/pages/PersonDetail.js.map +1 -1
- package/dist/pages/PlanningPage.d.ts.map +1 -1
- package/dist/pages/PlanningPage.js +6 -3
- package/dist/pages/PlanningPage.js.map +1 -1
- package/dist/pages/RaiseDetail.d.ts.map +1 -1
- package/dist/pages/RaiseDetail.js +5 -1
- package/dist/pages/RaiseDetail.js.map +1 -1
- package/dist/pages/RoleDetail.d.ts.map +1 -1
- package/dist/pages/RoleDetail.js +4 -1
- package/dist/pages/RoleDetail.js.map +1 -1
- package/dist/pages/SearchPage.d.ts.map +1 -1
- package/dist/pages/SearchPage.js +2 -1
- package/dist/pages/SearchPage.js.map +1 -1
- package/dist/pages/account/PreferencesPage.d.ts.map +1 -1
- package/dist/pages/account/PreferencesPage.js +2 -28
- package/dist/pages/account/PreferencesPage.js.map +1 -1
- package/dist/pages/account/SecurityPage.js +2 -2
- package/dist/pages/account/SecurityPage.js.map +1 -1
- package/dist/pages/admin/DataPage.js +10 -9
- package/dist/pages/admin/DataPage.js.map +1 -1
- package/dist/pages/admin/FieldsPage.js +1 -1
- package/dist/pages/admin/FieldsPage.js.map +1 -1
- package/dist/pages/admin/ModulesPage.d.ts.map +1 -1
- package/dist/pages/admin/ModulesPage.js +1 -0
- package/dist/pages/admin/ModulesPage.js.map +1 -1
- package/dist/pages/admin/WorkspaceSettingsPage.d.ts +12 -0
- package/dist/pages/admin/WorkspaceSettingsPage.d.ts.map +1 -1
- package/dist/pages/admin/WorkspaceSettingsPage.js +2 -21
- package/dist/pages/admin/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/auth/AuthForm.d.ts +18 -0
- package/dist/pages/auth/AuthForm.d.ts.map +1 -1
- package/dist/pages/auth/AuthForm.js +17 -0
- package/dist/pages/auth/AuthForm.js.map +1 -1
- package/dist/pages/auth/AuthLayout.d.ts +5 -4
- package/dist/pages/auth/AuthLayout.d.ts.map +1 -1
- package/dist/pages/auth/AuthLayout.js +7 -5
- package/dist/pages/auth/AuthLayout.js.map +1 -1
- package/dist/pages/auth/AuthMethods.d.ts +12 -0
- package/dist/pages/auth/AuthMethods.d.ts.map +1 -0
- package/dist/pages/auth/AuthMethods.js +20 -0
- package/dist/pages/auth/AuthMethods.js.map +1 -0
- package/dist/pages/auth/RegionSwitcher.d.ts +10 -0
- package/dist/pages/auth/RegionSwitcher.d.ts.map +1 -0
- package/dist/pages/auth/RegionSwitcher.js +28 -0
- package/dist/pages/auth/RegionSwitcher.js.map +1 -0
- package/dist/pages/auth/SignInPage.d.ts +7 -0
- package/dist/pages/auth/SignInPage.d.ts.map +1 -1
- package/dist/pages/auth/SignInPage.js +5 -8
- package/dist/pages/auth/SignInPage.js.map +1 -1
- package/dist/pages/auth/SignUpPage.d.ts.map +1 -1
- package/dist/pages/auth/SignUpPage.js +9 -1
- package/dist/pages/auth/SignUpPage.js.map +1 -1
- package/dist/pages/auth/nextPath.d.ts +15 -0
- package/dist/pages/auth/nextPath.d.ts.map +1 -0
- package/dist/pages/auth/nextPath.js +17 -0
- package/dist/pages/auth/nextPath.js.map +1 -0
- package/dist/pages/auth/regionHref.d.ts +6 -0
- package/dist/pages/auth/regionHref.d.ts.map +1 -0
- package/dist/pages/auth/regionHref.js +8 -0
- package/dist/pages/auth/regionHref.js.map +1 -0
- package/dist/pages/dashboard/DashboardPage.d.ts +8 -0
- package/dist/pages/dashboard/DashboardPage.d.ts.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +5 -13
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/attention.d.ts +1 -8
- package/dist/pages/dashboard/attention.d.ts.map +1 -1
- package/dist/pages/dashboard/attention.js +21 -54
- package/dist/pages/dashboard/attention.js.map +1 -1
- package/dist/pages/dashboard/sections.d.ts.map +1 -1
- package/dist/pages/dashboard/sections.js +3 -2
- package/dist/pages/dashboard/sections.js.map +1 -1
- package/dist/pages/forms/FormActions.d.ts.map +1 -1
- package/dist/pages/forms/FormActions.js +7 -3
- package/dist/pages/forms/FormActions.js.map +1 -1
- package/dist/pages/onboarding/HandbookStepPage.d.ts +4 -8
- package/dist/pages/onboarding/HandbookStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/HandbookStepPage.js +13 -13
- package/dist/pages/onboarding/HandbookStepPage.js.map +1 -1
- package/dist/pages/onboarding/InvitesStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/InvitesStepPage.js +13 -7
- package/dist/pages/onboarding/InvitesStepPage.js.map +1 -1
- package/dist/pages/onboarding/ModulesStepPage.d.ts +11 -0
- package/dist/pages/onboarding/ModulesStepPage.d.ts.map +1 -0
- package/dist/pages/onboarding/ModulesStepPage.js +80 -0
- package/dist/pages/onboarding/ModulesStepPage.js.map +1 -0
- package/dist/pages/onboarding/OnboardingNav.d.ts +17 -0
- package/dist/pages/onboarding/OnboardingNav.d.ts.map +1 -0
- package/dist/pages/onboarding/OnboardingNav.js +37 -0
- package/dist/pages/onboarding/OnboardingNav.js.map +1 -0
- package/dist/pages/onboarding/OrganisationStepPage.d.ts +13 -0
- package/dist/pages/onboarding/OrganisationStepPage.d.ts.map +1 -0
- package/dist/pages/onboarding/OrganisationStepPage.js +59 -0
- package/dist/pages/onboarding/OrganisationStepPage.js.map +1 -0
- package/dist/pages/onboarding/WorkspaceStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/WorkspaceStepPage.js +25 -20
- package/dist/pages/onboarding/WorkspaceStepPage.js.map +1 -1
- package/dist/pages/onboarding/handbookTemplates.d.ts +19 -0
- package/dist/pages/onboarding/handbookTemplates.d.ts.map +1 -0
- package/dist/pages/onboarding/handbookTemplates.js +57 -0
- package/dist/pages/onboarding/handbookTemplates.js.map +1 -0
- package/dist/pages/onboarding/onboardingModules.d.ts +23 -0
- package/dist/pages/onboarding/onboardingModules.d.ts.map +1 -0
- package/dist/pages/onboarding/onboardingModules.js +153 -0
- package/dist/pages/onboarding/onboardingModules.js.map +1 -0
- package/dist/pages/onboarding/onboardingRerun.d.ts +21 -0
- package/dist/pages/onboarding/onboardingRerun.d.ts.map +1 -0
- package/dist/pages/onboarding/onboardingRerun.js +33 -0
- package/dist/pages/onboarding/onboardingRerun.js.map +1 -0
- package/dist/registry/context.d.ts +3 -1
- package/dist/registry/context.d.ts.map +1 -1
- package/dist/registry/context.js +4 -0
- package/dist/registry/context.js.map +1 -1
- package/dist/registry/contributions.d.ts +24 -0
- package/dist/registry/contributions.d.ts.map +1 -1
- package/dist/registry/contributions.js.map +1 -1
- package/dist/registry/registry.d.ts +4 -1
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +6 -0
- package/dist/registry/registry.js.map +1 -1
- package/package.json +4 -3
- package/src/api/resources/attendances.ts +54 -0
- package/src/api/resources/eventAssociations.ts +43 -0
- package/src/api/resources/events.ts +70 -0
- package/src/api/resources/handbookSeed.ts +63 -0
- package/src/api/resources/moduleSettings.ts +25 -0
- package/src/api/resources/planItems.ts +5 -5
- package/src/api/resources/publicConfig.ts +3 -3
- package/src/api/resources/sampleData.ts +2 -0
- package/src/api/resources/session.ts +59 -0
- package/src/api/resources/workspace.ts +2 -3
- package/src/app/KelpieApp.tsx +11 -3
- package/src/components/ActivitiesPanel.tsx +2 -0
- package/src/components/AddressesField.tsx +502 -0
- package/src/components/CountrySearch.tsx +71 -0
- package/src/components/EnvironmentBanner.tsx +23 -6
- package/src/components/InlineEdit.tsx +35 -1
- package/src/components/LinkedEventsPanel.tsx +50 -0
- package/src/components/NotesPanel.tsx +132 -15
- package/src/components/PlanAttention.tsx +5 -4
- package/src/components/PlanPanel.tsx +3 -3
- package/src/components/Shell.tsx +16 -1
- package/src/components/SocialNetworkIcon.tsx +88 -0
- package/src/components/SocialProfilesField.tsx +57 -10
- package/src/components/TimezoneSearch.tsx +67 -0
- package/src/components/WorkspaceSwitcher.tsx +136 -0
- package/src/components/environmentTone.ts +40 -0
- package/src/index.ts +49 -3
- package/src/lib/timezones.ts +43 -0
- package/src/pages/CompaniesPage.tsx +14 -13
- package/src/pages/CompanyDetail.tsx +59 -27
- package/src/pages/DealDetail.tsx +5 -0
- package/src/pages/DecisionsPage.tsx +7 -0
- package/src/pages/EnquiryDetail.tsx +7 -0
- package/src/pages/EventDetail.tsx +794 -0
- package/src/pages/EventsPage.tsx +382 -0
- package/src/pages/ListDetail.tsx +24 -0
- package/src/pages/OpportunityDetail.tsx +7 -0
- package/src/pages/PartnershipDetail.tsx +7 -0
- package/src/pages/PeoplePage.tsx +18 -5
- package/src/pages/PersonDetail.tsx +300 -100
- package/src/pages/PlanningPage.tsx +17 -14
- package/src/pages/RaiseDetail.tsx +5 -0
- package/src/pages/RoleDetail.tsx +8 -0
- package/src/pages/SearchPage.tsx +2 -1
- package/src/pages/account/PreferencesPage.tsx +2 -37
- package/src/pages/account/SecurityPage.tsx +6 -1
- package/src/pages/admin/DataPage.tsx +63 -21
- package/src/pages/admin/FieldsPage.tsx +1 -1
- package/src/pages/admin/ModulesPage.tsx +1 -0
- package/src/pages/admin/WorkspaceSettingsPage.tsx +10 -33
- package/src/pages/auth/AuthForm.tsx +38 -0
- package/src/pages/auth/AuthLayout.tsx +8 -4
- package/src/pages/auth/AuthMethods.tsx +29 -0
- package/src/pages/auth/RegionSwitcher.tsx +56 -0
- package/src/pages/auth/SignInPage.tsx +13 -14
- package/src/pages/auth/SignUpPage.tsx +32 -0
- package/src/pages/auth/nextPath.ts +17 -0
- package/src/pages/auth/regionHref.ts +10 -0
- package/src/pages/dashboard/DashboardPage.tsx +16 -48
- package/src/pages/dashboard/attention.ts +24 -78
- package/src/pages/dashboard/sections.tsx +8 -2
- package/src/pages/forms/FormActions.tsx +14 -8
- package/src/pages/onboarding/HandbookStepPage.tsx +21 -24
- package/src/pages/onboarding/InvitesStepPage.tsx +27 -19
- package/src/pages/onboarding/ModulesStepPage.tsx +145 -0
- package/src/pages/onboarding/OnboardingNav.tsx +97 -0
- package/src/pages/onboarding/OrganisationStepPage.tsx +130 -0
- package/src/pages/onboarding/WorkspaceStepPage.tsx +53 -38
- package/src/pages/onboarding/handbookTemplates.ts +77 -0
- package/src/pages/onboarding/onboardingModules.ts +202 -0
- package/src/pages/onboarding/onboardingRerun.ts +41 -0
- package/src/registry/context.ts +6 -0
- package/src/registry/contributions.ts +26 -0
- package/src/registry/registry.ts +12 -0
- package/src/styles.css +30 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react'
|
|
2
|
+
import { useNavigate } from 'react-router'
|
|
3
|
+
|
|
4
|
+
import { useAccountWorkspaces, useSession, useSwitchWorkspace } from '../api/resources/session.ts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Header control: the workspace this session is in, and a menu to move it.
|
|
8
|
+
*
|
|
9
|
+
* The list and the switch both live under `/v1/auth`, so a suspended current
|
|
10
|
+
* workspace still lets the reader see the other memberships and leave.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export function WorkspaceSwitcher(): React.JSX.Element | null {
|
|
14
|
+
const navigate = useNavigate()
|
|
15
|
+
const { session } = useSession()
|
|
16
|
+
const { workspaces, isLoading } = useAccountWorkspaces()
|
|
17
|
+
const switchWorkspace = useSwitchWorkspace()
|
|
18
|
+
const [open, setOpen] = useState(false)
|
|
19
|
+
const menuRef = useRef<HTMLDivElement>(null)
|
|
20
|
+
const currentId = session?.workspaceId ?? null
|
|
21
|
+
const current = workspaces.find((workspace) => workspace.id === currentId)
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!open) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function onPointerDown(event: MouseEvent): void {
|
|
29
|
+
if (menuRef.current?.contains(event.target as Node) !== true) {
|
|
30
|
+
setOpen(false)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function onKeyDown(event: KeyboardEvent): void {
|
|
35
|
+
if (event.key === 'Escape') {
|
|
36
|
+
setOpen(false)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
document.addEventListener('mousedown', onPointerDown)
|
|
41
|
+
document.addEventListener('keydown', onKeyDown)
|
|
42
|
+
|
|
43
|
+
return () => {
|
|
44
|
+
document.removeEventListener('mousedown', onPointerDown)
|
|
45
|
+
document.removeEventListener('keydown', onKeyDown)
|
|
46
|
+
}
|
|
47
|
+
}, [open])
|
|
48
|
+
|
|
49
|
+
if (isLoading && workspaces.length === 0) {
|
|
50
|
+
return (
|
|
51
|
+
<span className="max-w-[10rem] truncate px-2 py-1 text-[12px] text-ink-faint" aria-hidden>
|
|
52
|
+
Workspace
|
|
53
|
+
</span>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (workspaces.length === 0) {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const label = current?.name ?? 'Workspace'
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="relative" ref={menuRef}>
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
onClick={() => {
|
|
68
|
+
setOpen((value) => !value)
|
|
69
|
+
}}
|
|
70
|
+
aria-expanded={open}
|
|
71
|
+
aria-haspopup="menu"
|
|
72
|
+
aria-label="Switch workspace"
|
|
73
|
+
title={label}
|
|
74
|
+
className="inline-flex max-w-[12rem] items-center gap-1 rounded-md px-2 py-1 text-[12px] text-ink-muted transition hover:bg-surface-sunken hover:text-ink"
|
|
75
|
+
>
|
|
76
|
+
<span className="truncate">{label}</span>
|
|
77
|
+
<svg viewBox="0 0 12 12" aria-hidden className="h-2.5 w-2.5 shrink-0">
|
|
78
|
+
<path
|
|
79
|
+
d="M2.5 4.5 L6 8 L9.5 4.5"
|
|
80
|
+
fill="none"
|
|
81
|
+
stroke="currentColor"
|
|
82
|
+
strokeWidth="1.5"
|
|
83
|
+
strokeLinecap="round"
|
|
84
|
+
strokeLinejoin="round"
|
|
85
|
+
/>
|
|
86
|
+
</svg>
|
|
87
|
+
</button>
|
|
88
|
+
{open && (
|
|
89
|
+
<div
|
|
90
|
+
role="menu"
|
|
91
|
+
className="absolute right-0 z-20 mt-1.5 w-56 overflow-hidden rounded-md border border-border bg-surface-raised py-1"
|
|
92
|
+
>
|
|
93
|
+
{workspaces.map((workspace) => {
|
|
94
|
+
const isCurrent = workspace.id === currentId
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<button
|
|
98
|
+
key={workspace.id}
|
|
99
|
+
type="button"
|
|
100
|
+
role="menuitem"
|
|
101
|
+
aria-current={isCurrent ? 'true' : undefined}
|
|
102
|
+
disabled={switchWorkspace.isPending}
|
|
103
|
+
onClick={() => {
|
|
104
|
+
if (isCurrent) {
|
|
105
|
+
setOpen(false)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
switchWorkspace
|
|
110
|
+
.runAsync({ workspaceId: workspace.id })
|
|
111
|
+
.then(() => {
|
|
112
|
+
setOpen(false)
|
|
113
|
+
void navigate('/dashboard', { replace: true })
|
|
114
|
+
})
|
|
115
|
+
.catch(() => undefined)
|
|
116
|
+
}}
|
|
117
|
+
className="block w-full px-3 py-1.5 text-left hover:bg-surface-sunken disabled:opacity-60"
|
|
118
|
+
>
|
|
119
|
+
<div className="truncate text-[13px] text-ink">{workspace.name}</div>
|
|
120
|
+
<div className="truncate text-[11px] text-ink-faint capitalize">
|
|
121
|
+
{workspace.role}
|
|
122
|
+
{isCurrent ? ' · current' : ''}
|
|
123
|
+
</div>
|
|
124
|
+
</button>
|
|
125
|
+
)
|
|
126
|
+
})}
|
|
127
|
+
{switchWorkspace.error !== null && (
|
|
128
|
+
<p className="border-t border-border px-3 py-1.5 text-[12px] text-danger">
|
|
129
|
+
{switchWorkspace.error.message}
|
|
130
|
+
</p>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type EnvironmentTone = 'dev' | 'demo' | 'staging' | 'test' | 'cloud'
|
|
2
|
+
|
|
3
|
+
const NAMED_TONES: Readonly<Record<string, EnvironmentTone>> = {
|
|
4
|
+
development: 'dev',
|
|
5
|
+
dev: 'dev',
|
|
6
|
+
local: 'dev',
|
|
7
|
+
demo: 'demo',
|
|
8
|
+
staging: 'staging',
|
|
9
|
+
stage: 'staging',
|
|
10
|
+
preview: 'staging',
|
|
11
|
+
test: 'test',
|
|
12
|
+
cloud: 'cloud',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const TONES: readonly EnvironmentTone[] = ['dev', 'demo', 'staging', 'test', 'cloud']
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Picks a banner colour from a site name or runtime-mode fallback.
|
|
19
|
+
*
|
|
20
|
+
* Known names keep a stable colour so four tabs (dev, demo, cloud, staging)
|
|
21
|
+
* never collide. Anything else hashes onto the same five colours so an
|
|
22
|
+
* unknown name still looks different from local.
|
|
23
|
+
*/
|
|
24
|
+
export function environmentTone(label: string): EnvironmentTone {
|
|
25
|
+
const key = label.trim().toLowerCase()
|
|
26
|
+
const named = NAMED_TONES[key]
|
|
27
|
+
if (named !== undefined) {
|
|
28
|
+
return named
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return TONES[hashLabel(key) % TONES.length] ?? 'dev'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hashLabel(value: string): number {
|
|
35
|
+
let hash = 0
|
|
36
|
+
for (const char of value) {
|
|
37
|
+
hash = (hash * 31 + char.charCodeAt(0)) >>> 0
|
|
38
|
+
}
|
|
39
|
+
return hash
|
|
40
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -44,6 +44,26 @@ export {
|
|
|
44
44
|
} from './api/resources/people.ts'
|
|
45
45
|
export type { CreatePersonInput, PeopleFilters } from './api/resources/people.ts'
|
|
46
46
|
|
|
47
|
+
export {
|
|
48
|
+
useCreateEvent,
|
|
49
|
+
useDeleteEvent,
|
|
50
|
+
useEvent,
|
|
51
|
+
useEvents,
|
|
52
|
+
useUpdateEvent,
|
|
53
|
+
} from './api/resources/events.ts'
|
|
54
|
+
export type { EventFilters } from './api/resources/events.ts'
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
useAttendances,
|
|
58
|
+
useCreateAttendance,
|
|
59
|
+
useDeleteAttendance,
|
|
60
|
+
useUpdateAttendance,
|
|
61
|
+
} from './api/resources/attendances.ts'
|
|
62
|
+
export type { AttendanceFilters } from './api/resources/attendances.ts'
|
|
63
|
+
|
|
64
|
+
export { useEventAssociationsFor } from './api/resources/eventAssociations.ts'
|
|
65
|
+
export type { EventAssociationsResult } from './api/resources/eventAssociations.ts'
|
|
66
|
+
|
|
47
67
|
export {
|
|
48
68
|
useCreatePosition,
|
|
49
69
|
useDeletePosition,
|
|
@@ -73,6 +93,7 @@ export type { DecisionFilters } from './api/resources/decisions.ts'
|
|
|
73
93
|
|
|
74
94
|
export {
|
|
75
95
|
useAcceptInvite,
|
|
96
|
+
useAccountWorkspaces,
|
|
76
97
|
useConfirmPasswordReset,
|
|
77
98
|
useCreateWorkspace,
|
|
78
99
|
useLogIn,
|
|
@@ -80,8 +101,9 @@ export {
|
|
|
80
101
|
useRequestPasswordReset,
|
|
81
102
|
useSession,
|
|
82
103
|
useSignUp,
|
|
104
|
+
useSwitchWorkspace,
|
|
83
105
|
} from './api/resources/session.ts'
|
|
84
|
-
export type { SessionState } from './api/resources/session.ts'
|
|
106
|
+
export type { AccountWorkspacesState, SessionState } from './api/resources/session.ts'
|
|
85
107
|
|
|
86
108
|
export { fetchServiceHealth } from './api/health.ts'
|
|
87
109
|
export type { HealthRequestOptions, ServiceHealth } from './api/health.ts'
|
|
@@ -121,17 +143,37 @@ export type { AddButtonProps, SectionHeaderProps } from './components/SectionHea
|
|
|
121
143
|
export { Shell } from './components/Shell.tsx'
|
|
122
144
|
export { SidebarField } from './components/SidebarField.tsx'
|
|
123
145
|
export type { SidebarFieldProps } from './components/SidebarField.tsx'
|
|
124
|
-
export {
|
|
125
|
-
export type {
|
|
146
|
+
export { AddressSidebarLink, AddressesField } from './components/AddressesField.tsx'
|
|
147
|
+
export type { AddressSidebarLinkProps, AddressesFieldProps } from './components/AddressesField.tsx'
|
|
148
|
+
export { CountrySearch } from './components/CountrySearch.tsx'
|
|
149
|
+
export type { CountrySearchProps } from './components/CountrySearch.tsx'
|
|
150
|
+
export { SocialNetworkIcon, SocialNetworkName } from './components/SocialNetworkIcon.tsx'
|
|
151
|
+
export type {
|
|
152
|
+
SocialNetworkIconProps,
|
|
153
|
+
SocialNetworkNameProps,
|
|
154
|
+
} from './components/SocialNetworkIcon.tsx'
|
|
155
|
+
export { SocialProfileIcons, SocialProfilesField } from './components/SocialProfilesField.tsx'
|
|
156
|
+
export type {
|
|
157
|
+
SocialProfileIconsProps,
|
|
158
|
+
SocialProfilesFieldProps,
|
|
159
|
+
} from './components/SocialProfilesField.tsx'
|
|
126
160
|
export { SummaryBlock } from './components/SummaryBlock.tsx'
|
|
127
161
|
export type { SummaryBlockProps } from './components/SummaryBlock.tsx'
|
|
162
|
+
export { TimezoneSearch } from './components/TimezoneSearch.tsx'
|
|
163
|
+
export type { TimezoneSearchProps } from './components/TimezoneSearch.tsx'
|
|
128
164
|
|
|
129
165
|
export { CompaniesPage } from './pages/CompaniesPage.tsx'
|
|
130
166
|
export { CompanyDetail } from './pages/CompanyDetail.tsx'
|
|
131
167
|
export { DecisionsPage } from './pages/DecisionsPage.tsx'
|
|
168
|
+
export { EventDetail } from './pages/EventDetail.tsx'
|
|
169
|
+
export { EventsPage } from './pages/EventsPage.tsx'
|
|
132
170
|
export { PeoplePage } from './pages/PeoplePage.tsx'
|
|
133
171
|
export { PersonDetail } from './pages/PersonDetail.tsx'
|
|
134
172
|
export { PlanningPage } from './pages/PlanningPage.tsx'
|
|
173
|
+
// The controls a module contributing a sign-in method builds its button from,
|
|
174
|
+
// so it matches the form beside it without copying class names.
|
|
175
|
+
export { AuthDivider, AuthLinkButton } from './pages/auth/AuthForm.tsx'
|
|
176
|
+
export { safeNext } from './pages/auth/nextPath.ts'
|
|
135
177
|
export { ForgotPasswordPage } from './pages/auth/ForgotPasswordPage.tsx'
|
|
136
178
|
export { JoinPage } from './pages/auth/JoinPage.tsx'
|
|
137
179
|
export { ResetPasswordPage } from './pages/auth/ResetPasswordPage.tsx'
|
|
@@ -139,6 +181,7 @@ export { SignInPage } from './pages/auth/SignInPage.tsx'
|
|
|
139
181
|
export { SignUpPage } from './pages/auth/SignUpPage.tsx'
|
|
140
182
|
export { HandbookStepPage } from './pages/onboarding/HandbookStepPage.tsx'
|
|
141
183
|
export { InvitesStepPage } from './pages/onboarding/InvitesStepPage.tsx'
|
|
184
|
+
export { OrganisationStepPage } from './pages/onboarding/OrganisationStepPage.tsx'
|
|
142
185
|
export { WorkspaceStepPage } from './pages/onboarding/WorkspaceStepPage.tsx'
|
|
143
186
|
|
|
144
187
|
export {
|
|
@@ -165,6 +208,8 @@ export type { ThemePreference } from './lib/theme.ts'
|
|
|
165
208
|
|
|
166
209
|
export { EXTENSIBLE_RECORD_TYPES, NAV_SLOTS } from './registry/contributions.ts'
|
|
167
210
|
export type {
|
|
211
|
+
AuthMethod,
|
|
212
|
+
AuthMethodContext,
|
|
168
213
|
DashboardCard,
|
|
169
214
|
ExtensibleRecordType,
|
|
170
215
|
NavItem,
|
|
@@ -182,6 +227,7 @@ export { NO_UI_MODULES, UiModuleError, inSlotOrder, registerUiModules } from './
|
|
|
182
227
|
export type { UiExtensions, UiModule, UiModuleContext } from './registry/registry.ts'
|
|
183
228
|
|
|
184
229
|
export {
|
|
230
|
+
useAuthMethods,
|
|
185
231
|
useDashboardCards,
|
|
186
232
|
useModuleRoutes,
|
|
187
233
|
useNavItems,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IANA zone names this runtime can resolve, matching the server's
|
|
3
|
+
* `timezoneSchema`. UTC is always first: some engines omit it from
|
|
4
|
+
* `supportedValuesOf` even though `DateTimeFormat` accepts it.
|
|
5
|
+
*
|
|
6
|
+
* Falls back to the short list the mockup offered if `supportedValuesOf` is
|
|
7
|
+
* missing, for a browser old enough to lack it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const FALLBACK_TIMEZONES: readonly string[] = [
|
|
11
|
+
'UTC',
|
|
12
|
+
'Australia/Sydney',
|
|
13
|
+
'Australia/Melbourne',
|
|
14
|
+
'America/Los_Angeles',
|
|
15
|
+
'America/New_York',
|
|
16
|
+
'Europe/London',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
function readTimezones(): readonly string[] {
|
|
20
|
+
try {
|
|
21
|
+
const supported = Intl.supportedValuesOf('timeZone')
|
|
22
|
+
|
|
23
|
+
return ['UTC', ...supported.filter((zone) => zone !== 'UTC')]
|
|
24
|
+
} catch {
|
|
25
|
+
return FALLBACK_TIMEZONES
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const ALL_TIMEZONES: readonly string[] = readTimezones()
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The full list, with `current` prepended when a stored zone is not in it.
|
|
33
|
+
*
|
|
34
|
+
* A value the picker does not know must still render, rather than being
|
|
35
|
+
* rewritten to the first option on the next save.
|
|
36
|
+
*/
|
|
37
|
+
export function timezonesIncluding(current: string): readonly string[] {
|
|
38
|
+
if (current.length === 0 || ALL_TIMEZONES.includes(current)) {
|
|
39
|
+
return ALL_TIMEZONES
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return [current, ...ALL_TIMEZONES]
|
|
43
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatAddress, primaryAddress } from '@kelpie/schemas'
|
|
1
2
|
import type { Company, IcpFit } from '@kelpie/schemas'
|
|
2
3
|
import { useState } from 'react'
|
|
3
4
|
import { useNavigate } from 'react-router'
|
|
@@ -32,7 +33,7 @@ const ICP_TONES: Readonly<Record<IcpFit, ChipTone>> = {
|
|
|
32
33
|
unknown: 'neutral',
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const DEFAULT_VISIBLE_KEYS: readonly string[] = ['name', 'domain', '
|
|
36
|
+
const DEFAULT_VISIBLE_KEYS: readonly string[] = ['name', 'domain', 'type', 'updatedAt']
|
|
36
37
|
|
|
37
38
|
const SERVER_SORT_KEYS: readonly string[] = ['name', 'created_at', 'updated_at']
|
|
38
39
|
|
|
@@ -70,14 +71,6 @@ export function CompaniesPage(): React.JSX.Element {
|
|
|
70
71
|
<span className="font-mono text-[12px] text-ink-muted">{company.domain ?? '—'}</span>
|
|
71
72
|
),
|
|
72
73
|
},
|
|
73
|
-
{
|
|
74
|
-
key: 'website',
|
|
75
|
-
header: 'Website',
|
|
76
|
-
getSortValue: (company) => company.website,
|
|
77
|
-
render: (company) => (
|
|
78
|
-
<span className="font-mono text-[12px] text-ink-muted">{company.website ?? '—'}</span>
|
|
79
|
-
),
|
|
80
|
-
},
|
|
81
74
|
{
|
|
82
75
|
key: 'industry',
|
|
83
76
|
header: 'Industry',
|
|
@@ -85,10 +78,18 @@ export function CompaniesPage(): React.JSX.Element {
|
|
|
85
78
|
render: (company) => company.industry ?? '—',
|
|
86
79
|
},
|
|
87
80
|
{
|
|
88
|
-
key: '
|
|
89
|
-
header: '
|
|
90
|
-
getSortValue: (company) =>
|
|
91
|
-
|
|
81
|
+
key: 'addresses',
|
|
82
|
+
header: 'Address',
|
|
83
|
+
getSortValue: (company) => {
|
|
84
|
+
const address = primaryAddress(company.addresses)
|
|
85
|
+
|
|
86
|
+
return address === undefined ? null : formatAddress(address)
|
|
87
|
+
},
|
|
88
|
+
render: (company) => {
|
|
89
|
+
const address = primaryAddress(company.addresses)
|
|
90
|
+
|
|
91
|
+
return address === undefined ? '—' : formatAddress(address)
|
|
92
|
+
},
|
|
92
93
|
},
|
|
93
94
|
{
|
|
94
95
|
key: 'type',
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ACCOUNT_TYPES,
|
|
3
|
+
COMPANY_ADDRESS_KIND_LABELS,
|
|
4
|
+
COMPANY_ADDRESS_KINDS,
|
|
5
|
+
COMPANY_STAGES,
|
|
6
|
+
ICP_FITS,
|
|
7
|
+
SIZE_BANDS,
|
|
8
|
+
} from '@kelpie/schemas'
|
|
2
9
|
import type { AccountType, Company, CompanyInput, CompanyStage, IcpFit, SizeBand } from '@kelpie/schemas'
|
|
3
10
|
import { useState } from 'react'
|
|
4
11
|
import type { FormEvent } from 'react'
|
|
@@ -14,6 +21,7 @@ import {
|
|
|
14
21
|
import { useDeals } from '../api/resources/deals.ts'
|
|
15
22
|
import { useEnquiries } from '../api/resources/enquiries.ts'
|
|
16
23
|
import { useFormSubmissionsForRecord } from '../api/resources/forms.ts'
|
|
24
|
+
import { useModuleEnabled } from '../api/resources/moduleSettings.ts'
|
|
17
25
|
import { useOpportunities } from '../api/resources/opportunities.ts'
|
|
18
26
|
import { usePartnerships } from '../api/resources/partnerships.ts'
|
|
19
27
|
import { usePeople } from '../api/resources/people.ts'
|
|
@@ -24,6 +32,7 @@ import {
|
|
|
24
32
|
useUpdatePositionTitle,
|
|
25
33
|
} from '../api/resources/positions.ts'
|
|
26
34
|
import { useRaises } from '../api/resources/raises.ts'
|
|
35
|
+
import { AddressSidebarLink, AddressesField } from '../components/AddressesField.tsx'
|
|
27
36
|
import { ActivitiesPanel, LatestActivity } from '../components/ActivitiesPanel.tsx'
|
|
28
37
|
import { AgentTasks } from '../components/AgentTasks.tsx'
|
|
29
38
|
import { Chip } from '../components/Chip.tsx'
|
|
@@ -36,6 +45,7 @@ import { CustomFieldsPanel } from '../components/CustomFieldsPanel.tsx'
|
|
|
36
45
|
import { useHasCustomFields } from '../components/useHasCustomFields.ts'
|
|
37
46
|
import { InlineEdit } from '../components/InlineEdit.tsx'
|
|
38
47
|
import { ListsPanel } from '../components/ListsPanel.tsx'
|
|
48
|
+
import { LinkedEventsPanel } from '../components/LinkedEventsPanel.tsx'
|
|
39
49
|
import { NotesPanel } from '../components/NotesPanel.tsx'
|
|
40
50
|
import { RelatedPlanAttention } from '../components/PlanAttention.tsx'
|
|
41
51
|
import { ErrorPanel, LoadingPanel, NotFoundPanel } from '../components/QueryState.tsx'
|
|
@@ -51,9 +61,10 @@ import { toOptions, toTags } from './fields.ts'
|
|
|
51
61
|
/**
|
|
52
62
|
* One company.
|
|
53
63
|
*
|
|
54
|
-
* Overview, Activity, Notes, Decisions, Lists and People render
|
|
55
|
-
* tabs for Deals, Opportunities, Partnerships and Raises wait for
|
|
56
|
-
* endpoints. A UI module can add its own through the `company`
|
|
64
|
+
* Overview, Addresses, Activity, Notes, Decisions, Lists and People render
|
|
65
|
+
* today. The tabs for Deals, Opportunities, Partnerships and Raises wait for
|
|
66
|
+
* their endpoints. A UI module can add its own through the `company`
|
|
67
|
+
* record-tab slot.
|
|
57
68
|
*/
|
|
58
69
|
|
|
59
70
|
const STAGE_OPTIONS = toOptions(COMPANY_STAGES)
|
|
@@ -75,6 +86,7 @@ export function CompanyDetail(): React.JSX.Element {
|
|
|
75
86
|
const deleteCompany = useDeleteCompany()
|
|
76
87
|
const moduleTabs = inSlotOrder(useRecordTabs('company'))
|
|
77
88
|
const hasCustomFields = useHasCustomFields('company')
|
|
89
|
+
const eventsEnabled = useModuleEnabled('events')
|
|
78
90
|
const [activeTab, setActiveTab] = useState('overview')
|
|
79
91
|
const formSubmissions = useFormSubmissionsForRecord('company', id)
|
|
80
92
|
|
|
@@ -92,12 +104,14 @@ export function CompanyDetail(): React.JSX.Element {
|
|
|
92
104
|
|
|
93
105
|
const tabs: readonly RecordTabDescriptor<string>[] = [
|
|
94
106
|
{ id: 'overview', label: 'Overview' },
|
|
107
|
+
{ id: 'addresses', label: 'Addresses', count: record.addresses.length },
|
|
95
108
|
...(hasCustomFields ? [{ id: 'fields', label: 'Fields' }] : []),
|
|
96
109
|
{ id: 'activity', label: 'Activity' },
|
|
97
110
|
{ id: 'people', label: 'People' },
|
|
98
111
|
{ id: 'notes', label: 'Notes' },
|
|
99
112
|
{ id: 'decisions', label: 'Decisions' },
|
|
100
113
|
{ id: 'lists', label: 'Lists' },
|
|
114
|
+
...(eventsEnabled ? [{ id: 'events', label: 'Events' }] : []),
|
|
101
115
|
...(formSubmissions.records.length === 0
|
|
102
116
|
? []
|
|
103
117
|
: [{ id: 'forms', label: 'Forms', count: formSubmissions.records.length }]),
|
|
@@ -142,19 +156,28 @@ export function CompanyDetail(): React.JSX.Element {
|
|
|
142
156
|
ariaLabel="Company sections"
|
|
143
157
|
>
|
|
144
158
|
{active === 'overview' && <CompanyOverview company={record} />}
|
|
159
|
+
{active === 'addresses' && <CompanyAddresses company={record} />}
|
|
145
160
|
{active === 'fields' && <CompanyFields company={record} />}
|
|
146
161
|
{active === 'activity' && <ActivitiesPanel targetType="company" targetId={record.id} />}
|
|
147
162
|
{active === 'people' && <CompanyPeople company={record} />}
|
|
148
163
|
{active === 'notes' && <NotesPanel targetType="company" targetId={record.id} />}
|
|
149
164
|
{active === 'decisions' && <DecisionsPanel targetType="company" targetId={record.id} />}
|
|
150
165
|
{active === 'lists' && <ListsPanel targetType="company" targetId={record.id} />}
|
|
166
|
+
{active === 'events' && (
|
|
167
|
+
<LinkedEventsPanel targetType="company" targetId={record.id} />
|
|
168
|
+
)}
|
|
151
169
|
{active === 'forms' && <FormsPanel targetType="company" targetId={record.id} />}
|
|
152
170
|
{moduleTab?.render({ objectType: 'company', recordId: record.id })}
|
|
153
171
|
</RecordTabs>
|
|
154
172
|
</div>
|
|
155
173
|
|
|
156
174
|
<aside className="space-y-4 text-[12px] lg:sticky lg:top-6">
|
|
157
|
-
<CompanySidebar
|
|
175
|
+
<CompanySidebar
|
|
176
|
+
company={record}
|
|
177
|
+
onOpenAddresses={() => {
|
|
178
|
+
setActiveTab('addresses')
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
158
181
|
</aside>
|
|
159
182
|
</div>
|
|
160
183
|
</div>
|
|
@@ -189,6 +212,7 @@ function CompanyHeading({ company }: { readonly company: Company }): React.JSX.E
|
|
|
189
212
|
onChange={(domain) => {
|
|
190
213
|
patch({ domain: domain.length > 0 ? domain : null })
|
|
191
214
|
}}
|
|
215
|
+
visitable
|
|
192
216
|
displayClassName="text-[13px] font-mono text-ink-muted not-italic"
|
|
193
217
|
emptyLabel="Add domain…"
|
|
194
218
|
/>
|
|
@@ -239,7 +263,13 @@ function CompanyOverview({ company }: { readonly company: Company }): React.JSX.
|
|
|
239
263
|
)
|
|
240
264
|
}
|
|
241
265
|
|
|
242
|
-
function CompanySidebar({
|
|
266
|
+
function CompanySidebar({
|
|
267
|
+
company,
|
|
268
|
+
onOpenAddresses,
|
|
269
|
+
}: {
|
|
270
|
+
readonly company: Company
|
|
271
|
+
readonly onOpenAddresses: () => void
|
|
272
|
+
}): React.JSX.Element {
|
|
243
273
|
const { patch, error } = useCompanyPatch(company)
|
|
244
274
|
|
|
245
275
|
return (
|
|
@@ -309,27 +339,7 @@ function CompanySidebar({ company }: { readonly company: Company }): React.JSX.E
|
|
|
309
339
|
displayClassName="not-italic text-[12px]"
|
|
310
340
|
/>
|
|
311
341
|
</SidebarField>
|
|
312
|
-
<
|
|
313
|
-
<InlineEdit
|
|
314
|
-
value={company.hq ?? ''}
|
|
315
|
-
onChange={(hq) => {
|
|
316
|
-
patch({ hq: hq.length > 0 ? hq : null })
|
|
317
|
-
}}
|
|
318
|
-
displayClassName="not-italic normal-case text-[12px]"
|
|
319
|
-
emptyLabel="Add HQ…"
|
|
320
|
-
/>
|
|
321
|
-
</SidebarField>
|
|
322
|
-
<SidebarField label="Website">
|
|
323
|
-
<InlineEdit
|
|
324
|
-
value={company.website ?? ''}
|
|
325
|
-
onChange={(website) => {
|
|
326
|
-
patch({ website: website.length > 0 ? website : null })
|
|
327
|
-
}}
|
|
328
|
-
type="url"
|
|
329
|
-
displayClassName="not-italic normal-case text-[12px]"
|
|
330
|
-
emptyLabel="Add website…"
|
|
331
|
-
/>
|
|
332
|
-
</SidebarField>
|
|
342
|
+
<AddressSidebarLink addresses={company.addresses} onOpen={onOpenAddresses} />
|
|
333
343
|
<SidebarField label="Tech stack">
|
|
334
344
|
<InlineEdit
|
|
335
345
|
value={company.techStack.join(', ')}
|
|
@@ -376,6 +386,28 @@ function CompanySidebar({ company }: { readonly company: Company }): React.JSX.E
|
|
|
376
386
|
)
|
|
377
387
|
}
|
|
378
388
|
|
|
389
|
+
function CompanyAddresses({ company }: { readonly company: Company }): React.JSX.Element {
|
|
390
|
+
const { patch, error } = useCompanyPatch(company)
|
|
391
|
+
|
|
392
|
+
return (
|
|
393
|
+
<div className="max-w-lg space-y-4">
|
|
394
|
+
{error !== null && <ErrorPanel error={error} />}
|
|
395
|
+
<SectionHeader
|
|
396
|
+
title="Addresses"
|
|
397
|
+
description="One address per kind. Mark one as primary for lists and the sidebar."
|
|
398
|
+
/>
|
|
399
|
+
<AddressesField
|
|
400
|
+
value={company.addresses}
|
|
401
|
+
kinds={COMPANY_ADDRESS_KINDS}
|
|
402
|
+
kindLabels={COMPANY_ADDRESS_KIND_LABELS}
|
|
403
|
+
onChange={(addresses) => {
|
|
404
|
+
patch({ addresses })
|
|
405
|
+
}}
|
|
406
|
+
/>
|
|
407
|
+
</div>
|
|
408
|
+
)
|
|
409
|
+
}
|
|
410
|
+
|
|
379
411
|
function CompanyFields({ company }: { readonly company: Company }): React.JSX.Element {
|
|
380
412
|
const { patch, error } = useCompanyPatch(company)
|
|
381
413
|
return (
|
package/src/pages/DealDetail.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { useDeal, useDeleteDeal, useUpdateDeal } from '../api/resources/deals.ts'
|
|
14
14
|
import { useFormSubmissionsForRecord } from '../api/resources/forms.ts'
|
|
15
15
|
import { useMembers } from '../api/resources/members.ts'
|
|
16
|
+
import { useModuleEnabled } from '../api/resources/moduleSettings.ts'
|
|
16
17
|
import { usePeople } from '../api/resources/people.ts'
|
|
17
18
|
import { usePipelineStages } from '../api/resources/pipelineStages.ts'
|
|
18
19
|
import { useRecordPlanItems } from '../api/resources/planItems.ts'
|
|
@@ -29,6 +30,7 @@ import { CustomFieldsPanel } from '../components/CustomFieldsPanel.tsx'
|
|
|
29
30
|
import { useHasCustomFields } from '../components/useHasCustomFields.ts'
|
|
30
31
|
import { InlineEdit } from '../components/InlineEdit.tsx'
|
|
31
32
|
import { ListsPanel } from '../components/ListsPanel.tsx'
|
|
33
|
+
import { LinkedEventsPanel } from '../components/LinkedEventsPanel.tsx'
|
|
32
34
|
import { NotesPanel } from '../components/NotesPanel.tsx'
|
|
33
35
|
import { PlanAttention } from '../components/PlanAttention.tsx'
|
|
34
36
|
import { PlanPanel } from '../components/PlanPanel.tsx'
|
|
@@ -65,6 +67,7 @@ export function DealDetail(): React.JSX.Element {
|
|
|
65
67
|
const deleteDeal = useDeleteDeal()
|
|
66
68
|
const moduleTabs = inSlotOrder(useRecordTabs('deal'))
|
|
67
69
|
const hasCustomFields = useHasCustomFields('deal')
|
|
70
|
+
const eventsEnabled = useModuleEnabled('events')
|
|
68
71
|
const [activeTab, setActiveTab] = useState('overview')
|
|
69
72
|
const [showConvert, setShowConvert] = useState(false)
|
|
70
73
|
const formSubmissions = useFormSubmissionsForRecord('deal', id)
|
|
@@ -89,6 +92,7 @@ export function DealDetail(): React.JSX.Element {
|
|
|
89
92
|
{ id: 'notes', label: 'Notes' },
|
|
90
93
|
{ id: 'decisions', label: 'Decisions' },
|
|
91
94
|
{ id: 'lists', label: 'Lists' },
|
|
95
|
+
...(eventsEnabled ? [{ id: 'events', label: 'Events' }] : []),
|
|
92
96
|
...(formSubmissions.records.length === 0
|
|
93
97
|
? []
|
|
94
98
|
: [{ id: 'forms', label: 'Forms', count: formSubmissions.records.length }]),
|
|
@@ -164,6 +168,7 @@ export function DealDetail(): React.JSX.Element {
|
|
|
164
168
|
{active === 'notes' && <NotesPanel targetType="deal" targetId={record.id} />}
|
|
165
169
|
{active === 'decisions' && <DecisionsPanel targetType="deal" targetId={record.id} />}
|
|
166
170
|
{active === 'lists' && <ListsPanel targetType="deal" targetId={record.id} />}
|
|
171
|
+
{active === 'events' && <LinkedEventsPanel targetType="deal" targetId={record.id} />}
|
|
167
172
|
{active === 'forms' && <FormsPanel targetType="deal" targetId={record.id} />}
|
|
168
173
|
{moduleTab?.render({ objectType: 'deal', recordId: record.id })}
|
|
169
174
|
</RecordTabs>
|
|
@@ -6,6 +6,7 @@ import { useTimezone } from '../api/resources/account.ts'
|
|
|
6
6
|
import { useCompanies } from '../api/resources/companies.ts'
|
|
7
7
|
import { useDeals } from '../api/resources/deals.ts'
|
|
8
8
|
import { useDecisions } from '../api/resources/decisions.ts'
|
|
9
|
+
import { useEvents } from '../api/resources/events.ts'
|
|
9
10
|
import { useMembers } from '../api/resources/members.ts'
|
|
10
11
|
import { useOpportunities } from '../api/resources/opportunities.ts'
|
|
11
12
|
import { usePartnerships } from '../api/resources/partnerships.ts'
|
|
@@ -46,6 +47,8 @@ const TARGET_LABELS: Readonly<Record<RecordTargetType, string>> = {
|
|
|
46
47
|
raise: 'Raise',
|
|
47
48
|
enquiry: 'Enquiry',
|
|
48
49
|
candidate: 'Candidate',
|
|
50
|
+
event: 'Event',
|
|
51
|
+
attendance: 'Attendance',
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const TARGET_ROUTES: Readonly<Partial<Record<RecordTargetType, string>>> = {
|
|
@@ -56,6 +59,7 @@ const TARGET_ROUTES: Readonly<Partial<Record<RecordTargetType, string>>> = {
|
|
|
56
59
|
raise: '/fundraising',
|
|
57
60
|
partnership: '/partnerships',
|
|
58
61
|
enquiry: '/enquiries',
|
|
62
|
+
event: '/events',
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
interface TargetDirectory {
|
|
@@ -69,6 +73,7 @@ function useTargetDirectory(): TargetDirectory {
|
|
|
69
73
|
const opportunities = useOpportunities({ limit: MAX_PAGE })
|
|
70
74
|
const raises = useRaises({ limit: MAX_PAGE })
|
|
71
75
|
const partnerships = usePartnerships({ limit: MAX_PAGE })
|
|
76
|
+
const events = useEvents({ limit: MAX_PAGE })
|
|
72
77
|
|
|
73
78
|
const nameById = useMemo(
|
|
74
79
|
() =>
|
|
@@ -80,6 +85,7 @@ function useTargetDirectory(): TargetDirectory {
|
|
|
80
85
|
...opportunities.records,
|
|
81
86
|
...raises.records,
|
|
82
87
|
...partnerships.records,
|
|
88
|
+
...events.records,
|
|
83
89
|
].map((record) => [record.id, record.name]),
|
|
84
90
|
),
|
|
85
91
|
[
|
|
@@ -89,6 +95,7 @@ function useTargetDirectory(): TargetDirectory {
|
|
|
89
95
|
opportunities.records,
|
|
90
96
|
raises.records,
|
|
91
97
|
partnerships.records,
|
|
98
|
+
events.records,
|
|
92
99
|
],
|
|
93
100
|
)
|
|
94
101
|
|