@burdenoff/microfe-devportal 2026.625.2 → 2026.625.3
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/devportal/components/EmptyState.js +14 -8
- package/dist/devportal/components/EmptyState.js.map +1 -1
- package/dist/devportal/components/LoadingState.js.map +1 -1
- package/dist/devportal/components/PageLayout.js +39 -34
- package/dist/devportal/components/PageLayout.js.map +1 -1
- package/dist/devportal/components/StatCard.js +4 -3
- package/dist/devportal/components/StatCard.js.map +1 -1
- package/dist/devportal/components/StatusBadge.js +1 -1
- package/dist/devportal/components/StatusBadge.js.map +1 -1
- package/dist/devportal/pages/ApiKeysPage.js +1 -1
- package/dist/devportal/pages/ApiKeysPage.js.map +1 -1
- package/dist/devportal/pages/AppLogsPage.js +85 -85
- package/dist/devportal/pages/AppLogsPage.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +7 -7
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/DashboardPage.js +157 -151
- package/dist/devportal/pages/DashboardPage.js.map +1 -1
- package/dist/devportal/pages/DelegationsPage.js +2 -2
- package/dist/devportal/pages/DelegationsPage.js.map +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js +1 -1
- package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationMembersPage.js +225 -225
- package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
- package/dist/devportal/pages/OrganizationsPage.js +25 -25
- package/dist/devportal/pages/OrganizationsPage.js.map +1 -1
- package/dist/devportal/pages/WebhooksPage.js +1 -1
- package/dist/devportal/pages/WebhooksPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationMembersPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationMembersPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Users,\n Mail,\n Shield,\n UserMinus,\n RefreshCw,\n Loader2,\n AlertCircle,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { InputField, SelectField } from \"../components/FormField\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { DeveloperOrgRole } from \"../types\";\nimport { ORG_ROLE_LABELS } from \"../utils/constants\";\nimport { format } from \"date-fns\";\nimport {\n useGetOrganizationQuery,\n useGetOrganizationMembersQuery,\n useGetOrganizationInvitationsQuery,\n useInviteMemberMutation,\n useRemoveMemberMutation,\n useSuspendMemberMutation,\n useReactivateMemberMutation,\n useUpdateMemberRoleMutation,\n useTransferOwnershipMutation,\n useCancelInvitationMutation,\n useResendInvitationMutation,\n type OrgMemberFieldsFragment,\n type OrgInvitationFieldsFragment,\n} from \"../hooks\";\n\nexport const OrganizationMembersPage: FC = () => {\n const { orgId } = useParams<{ orgId: string }>();\n const { currentUser } = useDevportal();\n const { allowed: canInvite } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_INVITATION_CREATE,\n );\n const { allowed: canManageMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_UPDATE,\n );\n const { allowed: canRemoveMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_DELETE,\n );\n const { allowed: canActivateMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_ACTIVATE,\n );\n const { allowed: canDeactivateMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_DEACTIVATE,\n );\n const resolveMemberLabel = (member: {\n userId: string;\n email?: string | null;\n }): string => {\n if (member.email) return member.email;\n if (currentUser?.id === member.userId && currentUser.email)\n return currentUser.email;\n return member.userId;\n };\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [showInviteDialog, setShowInviteDialog] = useState(false);\n const [inviteEmail, setInviteEmail] = useState(\"\");\n const [inviteRole, setInviteRole] = useState<DeveloperOrgRole>(\"DEVELOPER\");\n const [inviteMessage, setInviteMessage] = useState(\"\");\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [selectedMemberIds, setSelectedMemberIds] = useState<Set<string>>(\n new Set(),\n );\n const [selectedInvitationIds, setSelectedInvitationIds] = useState<\n Set<string>\n >(new Set());\n const [showBulkRemoveMembersDialog, setShowBulkRemoveMembersDialog] =\n useState(false);\n const [showBulkCancelInvitationsDialog, setShowBulkCancelInvitationsDialog] =\n useState(false);\n const [transferOwnershipMember, setTransferOwnershipMember] =\n useState<OrgMemberFieldsFragment | null>(null);\n\n const { data: orgData } = useGetOrganizationQuery({\n variables: { id: orgId ?? \"\" },\n skip: !orgId,\n fetchPolicy: \"cache-first\",\n });\n useEffect(() => {\n const name = orgData?.developerOrganization?.name;\n if (!orgId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(orgId, name);\n return () => reg?.unregister(orgId);\n }, [orgId, orgData?.developerOrganization?.name]);\n\n // Queries\n const {\n data: membersData,\n loading: membersLoading,\n error: membersError,\n } = useGetOrganizationMembersQuery({\n variables: { organizationId: orgId! },\n skip: !orgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const {\n data: invitationsData,\n loading: invitationsLoading,\n error: invitationsError,\n } = useGetOrganizationInvitationsQuery({\n variables: { organizationId: orgId!, status: \"PENDING\" as never },\n skip: !orgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n // Mutations\n const [inviteMember, { loading: inviting }] = useInviteMemberMutation({\n refetchQueries: [\"GetOrganizationInvitations\"],\n });\n\n const [removeMember] = useRemoveMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [suspendMember] = useSuspendMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [reactivateMember] = useReactivateMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [updateMemberRole] = useUpdateMemberRoleMutation({\n refetchQueries: [\"GetOrganizationMembers\", \"GetOrganization\"],\n });\n\n const [transferOwnership] = useTransferOwnershipMutation({\n refetchQueries: [\"GetOrganizationMembers\", \"GetOrganization\"],\n });\n\n const [cancelInvitation] = useCancelInvitationMutation({\n refetchQueries: [\"GetOrganizationInvitations\"],\n });\n\n const [resendInvitation] = useResendInvitationMutation();\n\n // Derived data\n const members: OrgMemberFieldsFragment[] = useMemo(\n () =>\n membersData?.developerOrgMembers?.edges?.map(\n (e: { node: OrgMemberFieldsFragment }) => e.node,\n ) ?? [],\n [membersData?.developerOrgMembers?.edges],\n );\n\n const invitations: OrgInvitationFieldsFragment[] = useMemo(\n () =>\n invitationsData?.developerOrgInvitations?.edges?.map(\n (e: { node: OrgInvitationFieldsFragment }) => e.node,\n ) ?? [],\n [invitationsData?.developerOrgInvitations?.edges],\n );\n\n const membersCount = membersData?.developerOrgMembers?.totalCount ?? 0;\n const invitationsCount =\n invitationsData?.developerOrgInvitations?.totalCount ?? 0;\n\n const selectedMembers = useMemo(\n () => members.filter((member) => selectedMemberIds.has(member.id)),\n [members, selectedMemberIds],\n );\n const selectedInvitations = useMemo(\n () =>\n invitations.filter((invitation) =>\n selectedInvitationIds.has(invitation.id),\n ),\n [invitations, selectedInvitationIds],\n );\n\n const selectableMembers = members.filter((member) => member.role !== \"OWNER\");\n const allMembersSelected =\n selectableMembers.length > 0 &&\n selectableMembers.every((member) => selectedMemberIds.has(member.id));\n const partiallySelectedMembers =\n selectableMembers.some((member) => selectedMemberIds.has(member.id)) &&\n !allMembersSelected;\n\n const allInvitationsSelected =\n invitations.length > 0 &&\n invitations.every((invitation) => selectedInvitationIds.has(invitation.id));\n const partiallySelectedInvitations =\n invitations.some((invitation) =>\n selectedInvitationIds.has(invitation.id),\n ) && !allInvitationsSelected;\n\n const suspendableMembers = selectedMembers.filter(\n (member) => member.role !== \"OWNER\" && !member.isSuspended,\n );\n const reactivatableMembers = selectedMembers.filter(\n (member) => member.isSuspended,\n );\n const removableMembers = selectedMembers.filter(\n (member) => member.role !== \"OWNER\",\n );\n\n const handleInvite = async () => {\n if (!orgId || !inviteEmail.trim()) return;\n setActionError(null);\n\n try {\n await inviteMember({\n variables: {\n organizationId: orgId,\n input: {\n email: inviteEmail,\n role: inviteRole as never,\n message: inviteMessage || undefined,\n },\n },\n });\n setShowInviteDialog(false);\n setInviteEmail(\"\");\n setInviteRole(\"DEVELOPER\");\n setInviteMessage(\"\");\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToSendInvitation\", \"Failed to send invitation\"),\n );\n }\n };\n\n const handleRemoveMember = async (memberId: string) => {\n setActionError(null);\n try {\n await removeMember({ variables: { id: memberId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToRemoveMember\", \"Failed to remove member\"),\n );\n }\n };\n\n const handleSuspendMember = async (memberId: string, reason?: string) => {\n setActionError(null);\n try {\n await suspendMember({\n variables: { id: memberId, reason: reason || undefined },\n });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToSuspendMember\", \"Failed to suspend member\"),\n );\n }\n };\n\n const handleReactivateMember = async (memberId: string) => {\n setActionError(null);\n try {\n await reactivateMember({ variables: { id: memberId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToReactivateMember\",\n \"Failed to reactivate member\",\n ),\n );\n }\n };\n\n const handleUpdateMemberRole = async (\n memberId: string,\n role: DeveloperOrgRole,\n ) => {\n setActionError(null);\n try {\n await updateMemberRole({\n variables: {\n id: memberId,\n role: role as never,\n permissions: undefined,\n },\n });\n setActionSuccess(\n tr(\"devportal.memberRoleUpdated\", \"Member role updated successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToUpdateMemberRole\",\n \"Failed to update member role\",\n ),\n );\n }\n };\n\n const handleTransferOwnership = async () => {\n const member = transferOwnershipMember;\n if (!orgId || !member) return;\n setActionError(null);\n\n try {\n await transferOwnership({\n variables: { organizationId: orgId, newOwnerId: member.userId },\n });\n setTransferOwnershipMember(null);\n setActionSuccess(\n tr(\n \"devportal.organizationOwnershipTransferred\",\n \"Organization ownership transferred successfully\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToTransferOwnership\",\n \"Failed to transfer organization ownership\",\n ),\n );\n }\n };\n\n const handleCancelInvitation = async (invitationId: string) => {\n setActionError(null);\n try {\n await cancelInvitation({ variables: { id: invitationId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToCancelInvitation\",\n \"Failed to cancel invitation\",\n ),\n );\n }\n };\n\n const handleResendInvitation = async (invitationId: string) => {\n setActionError(null);\n try {\n await resendInvitation({ variables: { id: invitationId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToResendInvitation\",\n \"Failed to resend invitation\",\n ),\n );\n }\n };\n\n const clearSelections = () => {\n setSelectedMemberIds(new Set());\n setSelectedInvitationIds(new Set());\n };\n\n const toggleMemberSelection = (memberId: string, checked: boolean) => {\n setSelectedMemberIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(memberId);\n } else {\n next.delete(memberId);\n }\n return next;\n });\n };\n\n const toggleAllMembers = (checked: boolean) => {\n setSelectedMemberIds((prev) => {\n const next = new Set(prev);\n selectableMembers.forEach((member) => {\n if (checked) {\n next.add(member.id);\n } else {\n next.delete(member.id);\n }\n });\n return next;\n });\n };\n\n const toggleInvitationSelection = (\n invitationId: string,\n checked: boolean,\n ) => {\n setSelectedInvitationIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(invitationId);\n } else {\n next.delete(invitationId);\n }\n return next;\n });\n };\n\n const toggleAllInvitations = (checked: boolean) => {\n setSelectedInvitationIds((prev) => {\n const next = new Set(prev);\n invitations.forEach((invitation) => {\n if (checked) {\n next.add(invitation.id);\n } else {\n next.delete(invitation.id);\n }\n });\n return next;\n });\n };\n\n const handleBulkSuspendMembers = async () => {\n if (suspendableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n suspendableMembers.map((member) =>\n suspendMember({ variables: { id: member.id, reason: undefined } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.suspended\", \"Suspended\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkReactivateMembers = async () => {\n if (reactivatableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n reactivatableMembers.map((member) =>\n reactivateMember({ variables: { id: member.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.reactivated\", \"Reactivated\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkRemoveMembers = async () => {\n if (removableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n removableMembers.map((member) =>\n removeMember({ variables: { id: member.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.removed\", \"Removed\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setShowBulkRemoveMembersDialog(false);\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkResendInvitations = async () => {\n if (selectedInvitations.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n selectedInvitations.map((invitation) =>\n resendInvitation({ variables: { id: invitation.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.resent\", \"Resent\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.invitationLower\", \"invitation\") : tr(\"devportal.invitationsLower\", \"invitations\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedInvitationIds(new Set());\n };\n\n const handleBulkCancelInvitations = async () => {\n if (selectedInvitations.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n selectedInvitations.map((invitation) =>\n cancelInvitation({ variables: { id: invitation.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.cancelled\", \"Cancelled\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.invitationLower\", \"invitation\") : tr(\"devportal.invitationsLower\", \"invitations\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setShowBulkCancelInvitationsDialog(false);\n setSelectedInvitationIds(new Set());\n };\n\n const isLoading = membersLoading || invitationsLoading;\n const hasError = membersError || invitationsError;\n\n if (isLoading && !membersData && !invitationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n >\n <div className=\"flex items-center justify-center py-16\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (hasError && !membersData && !invitationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\"devportal.failedToLoadMembers\", \"Failed to load members\")}\n description={\n membersError?.message ||\n invitationsError?.message ||\n tr(\n \"devportal.anErrorOccurredWhileLoadingTeamData\",\n \"An error occurred while loading team data\",\n )\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.ORG_MEMBER_READ}>\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n actions={\n <button\n onClick={() => setShowInviteDialog(true)}\n disabled={!canInvite}\n aria-disabled={!canInvite}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n <Plus size={16} />\n {tr(\"devportal.inviteMember\", \"Invite Member\")}\n </button>\n }\n >\n {/* Action Error Banner */}\n {actionError && (\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionError}\n <button\n onClick={() => setActionError(null)}\n className=\"ml-auto text-status-error-text hover:text-status-error-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {actionSuccess && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 flex items-center gap-2 text-sm text-status-success-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionSuccess}\n <button\n onClick={() => setActionSuccess(null)}\n className=\"ml-auto text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {(selectedMemberIds.size > 0 || selectedInvitationIds.size > 0) && (\n <div className=\"flex flex-wrap items-center gap-3 rounded-card border border-border-seam bg-bg-surface p-4\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedMemberIds.size + selectedInvitationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n <button\n onClick={clearSelections}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearAllSelections\", \"Clear all selections\")}\n </button>\n </div>\n )}\n\n {/* Current Members */}\n <PageSection\n title={`${tr(\"devportal.members\", \"Members\")} (${membersCount})`}\n actions={\n members.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n onClick={handleBulkSuspendMembers}\n disabled={\n suspendableMembers.length === 0 || !canDeactivateMembers\n }\n aria-disabled={!canDeactivateMembers}\n className=\"rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.suspendSelected\", \"Suspend Selected\")}\n {suspendableMembers.length > 0\n ? ` (${suspendableMembers.length})`\n : \"\"}\n </button>\n <button\n onClick={handleBulkReactivateMembers}\n disabled={\n reactivatableMembers.length === 0 || !canActivateMembers\n }\n aria-disabled={!canActivateMembers}\n className=\"rounded-md border border-status-success-bg px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.reactivateSelected\", \"Reactivate Selected\")}\n {reactivatableMembers.length > 0\n ? ` (${reactivatableMembers.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setShowBulkRemoveMembersDialog(true)}\n disabled={removableMembers.length === 0 || !canRemoveMembers}\n aria-disabled={!canRemoveMembers}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.removeSelected\", \"Remove Selected\")}\n {removableMembers.length > 0\n ? ` (${removableMembers.length})`\n : \"\"}\n </button>\n </div>\n ) : null\n }\n >\n {members.length > 0 ? (\n <DataTable\n data={members}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allMembersSelected}\n indeterminate={partiallySelectedMembers}\n onChange={toggleAllMembers}\n ariaLabel={tr(\n \"devportal.selectAllMembers\",\n \"Select all members\",\n )}\n />\n ),\n className: \"w-12\",\n render: (member) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedMemberIds.has(member.id)}\n disabled={member.role === \"OWNER\"}\n onChange={(checked) =>\n toggleMemberSelection(member.id, checked)\n }\n ariaLabel={`Select member ${resolveMemberLabel(member)}`}\n />\n </div>\n ),\n },\n {\n key: \"email\",\n header: tr(\"devportal.memberColumn\", \"Member\"),\n render: (member) => {\n const label = resolveMemberLabel(member);\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-8 w-8 items-center justify-center rounded-full bg-action-primary-bg/10 text-primary text-sm font-medium\">\n {label.charAt(0).toUpperCase()}\n </div>\n <div>\n <p className=\"font-medium\">{label}</p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.joined\", \"Joined\")}{\" \"}\n {format(new Date(member.joinedAt), \"MMM d, yyyy\")}\n </p>\n </div>\n </div>\n );\n },\n },\n {\n key: \"role\",\n header: tr(\"devportal.roleColumn\", \"Role\"),\n render: (member) => (\n <div className=\"flex items-center gap-2\">\n <Shield size={14} className=\"text-text-secondary\" />\n {member.role === \"OWNER\" ? (\n <span>\n {ORG_ROLE_LABELS[member.role as DeveloperOrgRole] ??\n member.role}\n </span>\n ) : (\n <select\n value={member.role}\n onChange={(event) =>\n void handleUpdateMemberRole(\n member.id,\n event.target.value as DeveloperOrgRole,\n )\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-2 py-1 text-xs text-text-primary\"\n >\n {Object.entries(ORG_ROLE_LABELS)\n .filter(([value]) => value !== \"OWNER\")\n .map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n )}\n </div>\n ),\n },\n {\n key: \"status\",\n header: tr(\"devportal.statusColumn\", \"Status\"),\n render: (member) =>\n member.isSuspended ? (\n <StatusBadge status=\"SUSPENDED\" type=\"app\" />\n ) : member.isActive ? (\n <StatusBadge status=\"ACTIVE\" type=\"app\" />\n ) : (\n <StatusBadge status=\"INACTIVE\" type=\"app\" />\n ),\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-32\",\n render: (member) =>\n member.role !== \"OWNER\" && (\n <div className=\"flex gap-1\">\n {member.isSuspended ? (\n <button\n className=\"text-xs text-status-success-text hover:underline disabled:opacity-50\"\n disabled={!canActivateMembers}\n aria-disabled={!canActivateMembers}\n title={tr(\n \"devportal.reactivateMember\",\n \"Reactivate member\",\n )}\n onClick={() => handleReactivateMember(member.id)}\n >\n {tr(\"devportal.reactivate\", \"Reactivate\")}\n </button>\n ) : (\n <button\n className=\"text-xs text-status-warning-text hover:underline disabled:opacity-50\"\n disabled={!canDeactivateMembers}\n aria-disabled={!canDeactivateMembers}\n title={tr(\n \"devportal.suspendMember\",\n \"Suspend member\",\n )}\n onClick={() => handleSuspendMember(member.id)}\n >\n {tr(\"devportal.suspend\", \"Suspend\")}\n </button>\n )}\n <button\n className=\"text-xs text-status-error-text hover:underline disabled:opacity-50\"\n disabled={!canRemoveMembers}\n aria-disabled={!canRemoveMembers}\n title={tr(\"devportal.removeMember\", \"Remove member\")}\n onClick={() => handleRemoveMember(member.id)}\n >\n {tr(\"devportal.remove\", \"Remove\")}\n </button>\n <button\n className=\"text-xs text-primary hover:underline disabled:opacity-50\"\n disabled={!canManageMembers}\n aria-disabled={!canManageMembers}\n title={tr(\n \"devportal.transferOwnership\",\n \"Transfer ownership\",\n )}\n onClick={() => setTransferOwnershipMember(member)}\n >\n {tr(\"devportal.makeOwner\", \"Make Owner\")}\n </button>\n </div>\n ),\n },\n ]}\n />\n ) : (\n <EmptyState\n icon={<Users size={24} />}\n title={tr(\"devportal.noMembers\", \"No members\")}\n description={tr(\n \"devportal.inviteTeamMembersToCollaborate\",\n \"Invite team members to collaborate\",\n )}\n />\n )}\n </PageSection>\n\n {/* Pending Invitations */}\n {invitations.length > 0 && (\n <PageSection\n title={`${tr(\"devportal.pendingInvitations\", \"Pending Invitations\")} (${invitationsCount})`}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n onClick={handleBulkResendInvitations}\n disabled={selectedInvitations.length === 0}\n className=\"rounded-md border border-primary/30 px-3 py-2 text-sm font-medium text-primary hover:bg-action-primary-bg/5 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.resendSelected\", \"Resend Selected\")}\n {selectedInvitations.length > 0\n ? ` (${selectedInvitations.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setShowBulkCancelInvitationsDialog(true)}\n disabled={selectedInvitations.length === 0}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.cancelSelected\", \"Cancel Selected\")}\n {selectedInvitations.length > 0\n ? ` (${selectedInvitations.length})`\n : \"\"}\n </button>\n </div>\n }\n >\n <DataTable\n data={invitations}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allInvitationsSelected}\n indeterminate={partiallySelectedInvitations}\n onChange={toggleAllInvitations}\n ariaLabel={tr(\n \"devportal.selectAllInvitations\",\n \"Select all invitations\",\n )}\n />\n ),\n className: \"w-12\",\n render: (invitation) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedInvitationIds.has(invitation.id)}\n onChange={(checked) =>\n toggleInvitationSelection(invitation.id, checked)\n }\n ariaLabel={`Select invitation ${invitation.invitedEmail}`}\n />\n </div>\n ),\n },\n {\n key: \"invitedEmail\",\n header: tr(\"devportal.emailColumn\", \"Email\"),\n render: (inv) => (\n <div className=\"flex items-center gap-2\">\n <Mail size={16} className=\"text-text-secondary\" />\n {inv.invitedEmail}\n </div>\n ),\n },\n {\n key: \"role\",\n header: tr(\"devportal.invitedRoleColumn\", \"Invited Role\"),\n render: (inv) =>\n ORG_ROLE_LABELS[inv.role as DeveloperOrgRole] ?? inv.role,\n },\n {\n key: \"status\",\n header: tr(\"devportal.statusColumn\", \"Status\"),\n render: (inv) => (\n <StatusBadge status={inv.status} type=\"invitation\" />\n ),\n },\n {\n key: \"expiresAt\",\n header: tr(\"devportal.expiresColumn\", \"Expires\"),\n render: (inv) =>\n format(new Date(inv.expiresAt), \"MMM d, yyyy\"),\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-24\",\n render: (inv) => (\n <div className=\"flex gap-1\">\n <button\n className=\"rounded p-1 hover:bg-bg-sunken\"\n title={tr(\"devportal.resend\", \"Resend\")}\n onClick={() => handleResendInvitation(inv.id)}\n >\n <RefreshCw size={14} />\n </button>\n <button\n className=\"rounded p-1 hover:bg-bg-sunken text-status-error-text\"\n title={tr(\"devportal.cancel\", \"Cancel\")}\n onClick={() => handleCancelInvitation(inv.id)}\n >\n <UserMinus size={14} />\n </button>\n </div>\n ),\n },\n ]}\n />\n </PageSection>\n )}\n\n {/* Invite Dialog */}\n {showInviteDialog && (\n <ConfirmDialog\n open={showInviteDialog}\n onOpenChange={setShowInviteDialog}\n onConfirm={handleInvite}\n title={tr(\"devportal.inviteTeamMember\", \"Invite Team Member\")}\n confirmLabel={\n inviting\n ? tr(\"devportal.sendingDots\", \"Sending...\")\n : tr(\"devportal.sendInvitation\", \"Send Invitation\")\n }\n >\n <div className=\"space-y-4\">\n <InputField\n label={tr(\"devportal.emailAddress\", \"Email Address\")}\n type=\"email\"\n value={inviteEmail}\n onChange={(e) => setInviteEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n hint={tr(\n \"devportal.mustBeExistingVerifiedUser\",\n \"Must be an existing verified user\",\n )}\n required\n />\n <SelectField\n label={tr(\"devportal.roleColumn\", \"Role\")}\n value={inviteRole}\n onChange={(e) =>\n setInviteRole(e.target.value as DeveloperOrgRole)\n }\n options={[\n {\n value: \"ADMIN\",\n label: tr(\n \"devportal.adminFullAccess\",\n \"Admin - Full access\",\n ),\n },\n {\n value: \"DEVELOPER\",\n label: tr(\n \"devportal.developerCreateAndManageApps\",\n \"Developer - Create and manage apps\",\n ),\n },\n {\n value: \"VIEWER\",\n label: tr(\n \"devportal.viewerReadOnlyAccess\",\n \"Viewer - Read-only access\",\n ),\n },\n ]}\n required\n />\n </div>\n </ConfirmDialog>\n )}\n\n <ConfirmDialog\n open={showBulkRemoveMembersDialog}\n onOpenChange={setShowBulkRemoveMembersDialog}\n onConfirm={handleBulkRemoveMembers}\n title={tr(\n \"devportal.removeSelectedMembers\",\n \"Remove selected members\",\n )}\n description={`${tr(\"devportal.removeNSelectedMembers\", \"Remove\")} ${removableMembers.length} ${tr(\"devportal.selectedMembersFromOrg\", \"selected member(s) from this organization? This action cannot be undone.\")}`}\n confirmLabel={tr(\"devportal.removeMembers\", \"Remove Members\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={showBulkCancelInvitationsDialog}\n onOpenChange={setShowBulkCancelInvitationsDialog}\n onConfirm={handleBulkCancelInvitations}\n title={tr(\n \"devportal.cancelSelectedInvitations\",\n \"Cancel selected invitations\",\n )}\n description={`${tr(\"devportal.cancelNPendingInvitations\", \"Cancel\")} ${selectedInvitations.length} ${tr(\"devportal.pendingInvitationsQuestion\", \"pending invitation(s)?\")}`}\n confirmLabel={tr(\"devportal.cancelInvitations\", \"Cancel Invitations\")}\n cancelLabel={tr(\"devportal.keepInvitations\", \"Keep Invitations\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={transferOwnershipMember !== null}\n onOpenChange={(open) => {\n if (!open) setTransferOwnershipMember(null);\n }}\n onConfirm={handleTransferOwnership}\n title={tr(\"devportal.transferOwnership\", \"Transfer ownership\")}\n description={\n transferOwnershipMember\n ? tr(\n \"devportal.transferOwnershipConfirmation\",\n `Transfer organization ownership to ${resolveMemberLabel(transferOwnershipMember)}?`,\n )\n : undefined\n }\n confirmLabel={tr(\"devportal.makeOwner\", \"Make Owner\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OrganizationMembersPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationMembersPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Users,\n Mail,\n Shield,\n UserMinus,\n RefreshCw,\n Loader2,\n AlertCircle,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport { ConfirmDialog } from \"../components/ConfirmDialog\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { InputField, SelectField } from \"../components/FormField\";\nimport { SelectionCheckbox } from \"../components/SelectionCheckbox\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport { useDevportalPermission } from \"../hooks/usePermission\";\nimport type { DeveloperOrgRole } from \"../types\";\nimport { ORG_ROLE_LABELS } from \"../utils/constants\";\nimport { format } from \"date-fns\";\nimport {\n useGetOrganizationQuery,\n useGetOrganizationMembersQuery,\n useGetOrganizationInvitationsQuery,\n useInviteMemberMutation,\n useRemoveMemberMutation,\n useSuspendMemberMutation,\n useReactivateMemberMutation,\n useUpdateMemberRoleMutation,\n useTransferOwnershipMutation,\n useCancelInvitationMutation,\n useResendInvitationMutation,\n type OrgMemberFieldsFragment,\n type OrgInvitationFieldsFragment,\n} from \"../hooks\";\n\nexport const OrganizationMembersPage: FC = () => {\n const { orgId } = useParams<{ orgId: string }>();\n const { currentUser } = useDevportal();\n const { allowed: canInvite } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_INVITATION_CREATE,\n );\n const { allowed: canManageMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_UPDATE,\n );\n const { allowed: canRemoveMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_DELETE,\n );\n const { allowed: canActivateMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_ACTIVATE,\n );\n const { allowed: canDeactivateMembers } = useDevportalPermission(\n DEVPORTAL_PERMISSIONS.ORG_MEMBER_DEACTIVATE,\n );\n const resolveMemberLabel = (member: {\n userId: string;\n email?: string | null;\n }): string => {\n if (member.email) return member.email;\n if (currentUser?.id === member.userId && currentUser.email)\n return currentUser.email;\n return member.userId;\n };\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [showInviteDialog, setShowInviteDialog] = useState(false);\n const [inviteEmail, setInviteEmail] = useState(\"\");\n const [inviteRole, setInviteRole] = useState<DeveloperOrgRole>(\"DEVELOPER\");\n const [inviteMessage, setInviteMessage] = useState(\"\");\n const [actionError, setActionError] = useState<string | null>(null);\n const [actionSuccess, setActionSuccess] = useState<string | null>(null);\n const [selectedMemberIds, setSelectedMemberIds] = useState<Set<string>>(\n new Set(),\n );\n const [selectedInvitationIds, setSelectedInvitationIds] = useState<\n Set<string>\n >(new Set());\n const [showBulkRemoveMembersDialog, setShowBulkRemoveMembersDialog] =\n useState(false);\n const [showBulkCancelInvitationsDialog, setShowBulkCancelInvitationsDialog] =\n useState(false);\n const [transferOwnershipMember, setTransferOwnershipMember] =\n useState<OrgMemberFieldsFragment | null>(null);\n\n const { data: orgData } = useGetOrganizationQuery({\n variables: { id: orgId ?? \"\" },\n skip: !orgId,\n fetchPolicy: \"cache-first\",\n });\n useEffect(() => {\n const name = orgData?.developerOrganization?.name;\n if (!orgId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(orgId, name);\n return () => reg?.unregister(orgId);\n }, [orgId, orgData?.developerOrganization?.name]);\n\n // Queries\n const {\n data: membersData,\n loading: membersLoading,\n error: membersError,\n } = useGetOrganizationMembersQuery({\n variables: { organizationId: orgId! },\n skip: !orgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const {\n data: invitationsData,\n loading: invitationsLoading,\n error: invitationsError,\n } = useGetOrganizationInvitationsQuery({\n variables: { organizationId: orgId!, status: \"PENDING\" as never },\n skip: !orgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n // Mutations\n const [inviteMember, { loading: inviting }] = useInviteMemberMutation({\n refetchQueries: [\"GetOrganizationInvitations\"],\n });\n\n const [removeMember] = useRemoveMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [suspendMember] = useSuspendMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [reactivateMember] = useReactivateMemberMutation({\n refetchQueries: [\"GetOrganizationMembers\"],\n });\n\n const [updateMemberRole] = useUpdateMemberRoleMutation({\n refetchQueries: [\"GetOrganizationMembers\", \"GetOrganization\"],\n });\n\n const [transferOwnership] = useTransferOwnershipMutation({\n refetchQueries: [\"GetOrganizationMembers\", \"GetOrganization\"],\n });\n\n const [cancelInvitation] = useCancelInvitationMutation({\n refetchQueries: [\"GetOrganizationInvitations\"],\n });\n\n const [resendInvitation] = useResendInvitationMutation();\n\n // Derived data\n const members: OrgMemberFieldsFragment[] = useMemo(\n () =>\n membersData?.developerOrgMembers?.edges?.map(\n (e: { node: OrgMemberFieldsFragment }) => e.node,\n ) ?? [],\n [membersData?.developerOrgMembers?.edges],\n );\n\n const invitations: OrgInvitationFieldsFragment[] = useMemo(\n () =>\n invitationsData?.developerOrgInvitations?.edges?.map(\n (e: { node: OrgInvitationFieldsFragment }) => e.node,\n ) ?? [],\n [invitationsData?.developerOrgInvitations?.edges],\n );\n\n const membersCount = membersData?.developerOrgMembers?.totalCount ?? 0;\n const invitationsCount =\n invitationsData?.developerOrgInvitations?.totalCount ?? 0;\n\n const selectedMembers = useMemo(\n () => members.filter((member) => selectedMemberIds.has(member.id)),\n [members, selectedMemberIds],\n );\n const selectedInvitations = useMemo(\n () =>\n invitations.filter((invitation) =>\n selectedInvitationIds.has(invitation.id),\n ),\n [invitations, selectedInvitationIds],\n );\n\n const selectableMembers = members.filter((member) => member.role !== \"OWNER\");\n const allMembersSelected =\n selectableMembers.length > 0 &&\n selectableMembers.every((member) => selectedMemberIds.has(member.id));\n const partiallySelectedMembers =\n selectableMembers.some((member) => selectedMemberIds.has(member.id)) &&\n !allMembersSelected;\n\n const allInvitationsSelected =\n invitations.length > 0 &&\n invitations.every((invitation) => selectedInvitationIds.has(invitation.id));\n const partiallySelectedInvitations =\n invitations.some((invitation) =>\n selectedInvitationIds.has(invitation.id),\n ) && !allInvitationsSelected;\n\n const suspendableMembers = selectedMembers.filter(\n (member) => member.role !== \"OWNER\" && !member.isSuspended,\n );\n const reactivatableMembers = selectedMembers.filter(\n (member) => member.isSuspended,\n );\n const removableMembers = selectedMembers.filter(\n (member) => member.role !== \"OWNER\",\n );\n\n const handleInvite = async () => {\n if (!orgId || !inviteEmail.trim()) return;\n setActionError(null);\n\n try {\n await inviteMember({\n variables: {\n organizationId: orgId,\n input: {\n email: inviteEmail,\n role: inviteRole as never,\n message: inviteMessage || undefined,\n },\n },\n });\n setShowInviteDialog(false);\n setInviteEmail(\"\");\n setInviteRole(\"DEVELOPER\");\n setInviteMessage(\"\");\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToSendInvitation\", \"Failed to send invitation\"),\n );\n }\n };\n\n const handleRemoveMember = async (memberId: string) => {\n setActionError(null);\n try {\n await removeMember({ variables: { id: memberId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToRemoveMember\", \"Failed to remove member\"),\n );\n }\n };\n\n const handleSuspendMember = async (memberId: string, reason?: string) => {\n setActionError(null);\n try {\n await suspendMember({\n variables: { id: memberId, reason: reason || undefined },\n });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.failedToSuspendMember\", \"Failed to suspend member\"),\n );\n }\n };\n\n const handleReactivateMember = async (memberId: string) => {\n setActionError(null);\n try {\n await reactivateMember({ variables: { id: memberId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToReactivateMember\",\n \"Failed to reactivate member\",\n ),\n );\n }\n };\n\n const handleUpdateMemberRole = async (\n memberId: string,\n role: DeveloperOrgRole,\n ) => {\n setActionError(null);\n try {\n await updateMemberRole({\n variables: {\n id: memberId,\n role: role as never,\n permissions: undefined,\n },\n });\n setActionSuccess(\n tr(\"devportal.memberRoleUpdated\", \"Member role updated successfully\"),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToUpdateMemberRole\",\n \"Failed to update member role\",\n ),\n );\n }\n };\n\n const handleTransferOwnership = async () => {\n const member = transferOwnershipMember;\n if (!orgId || !member) return;\n setActionError(null);\n\n try {\n await transferOwnership({\n variables: { organizationId: orgId, newOwnerId: member.userId },\n });\n setTransferOwnershipMember(null);\n setActionSuccess(\n tr(\n \"devportal.organizationOwnershipTransferred\",\n \"Organization ownership transferred successfully\",\n ),\n );\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToTransferOwnership\",\n \"Failed to transfer organization ownership\",\n ),\n );\n }\n };\n\n const handleCancelInvitation = async (invitationId: string) => {\n setActionError(null);\n try {\n await cancelInvitation({ variables: { id: invitationId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToCancelInvitation\",\n \"Failed to cancel invitation\",\n ),\n );\n }\n };\n\n const handleResendInvitation = async (invitationId: string) => {\n setActionError(null);\n try {\n await resendInvitation({ variables: { id: invitationId } });\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr(\n \"devportal.failedToResendInvitation\",\n \"Failed to resend invitation\",\n ),\n );\n }\n };\n\n const clearSelections = () => {\n setSelectedMemberIds(new Set());\n setSelectedInvitationIds(new Set());\n };\n\n const toggleMemberSelection = (memberId: string, checked: boolean) => {\n setSelectedMemberIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(memberId);\n } else {\n next.delete(memberId);\n }\n return next;\n });\n };\n\n const toggleAllMembers = (checked: boolean) => {\n setSelectedMemberIds((prev) => {\n const next = new Set(prev);\n selectableMembers.forEach((member) => {\n if (checked) {\n next.add(member.id);\n } else {\n next.delete(member.id);\n }\n });\n return next;\n });\n };\n\n const toggleInvitationSelection = (\n invitationId: string,\n checked: boolean,\n ) => {\n setSelectedInvitationIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(invitationId);\n } else {\n next.delete(invitationId);\n }\n return next;\n });\n };\n\n const toggleAllInvitations = (checked: boolean) => {\n setSelectedInvitationIds((prev) => {\n const next = new Set(prev);\n invitations.forEach((invitation) => {\n if (checked) {\n next.add(invitation.id);\n } else {\n next.delete(invitation.id);\n }\n });\n return next;\n });\n };\n\n const handleBulkSuspendMembers = async () => {\n if (suspendableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n suspendableMembers.map((member) =>\n suspendMember({ variables: { id: member.id, reason: undefined } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.suspended\", \"Suspended\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkReactivateMembers = async () => {\n if (reactivatableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n reactivatableMembers.map((member) =>\n reactivateMember({ variables: { id: member.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.reactivated\", \"Reactivated\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkRemoveMembers = async () => {\n if (removableMembers.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n removableMembers.map((member) =>\n removeMember({ variables: { id: member.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.removed\", \"Removed\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.memberLower\", \"member\") : tr(\"devportal.membersLower\", \"members\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setShowBulkRemoveMembersDialog(false);\n setSelectedMemberIds(new Set());\n };\n\n const handleBulkResendInvitations = async () => {\n if (selectedInvitations.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n selectedInvitations.map((invitation) =>\n resendInvitation({ variables: { id: invitation.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.resent\", \"Resent\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.invitationLower\", \"invitation\") : tr(\"devportal.invitationsLower\", \"invitations\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setSelectedInvitationIds(new Set());\n };\n\n const handleBulkCancelInvitations = async () => {\n if (selectedInvitations.length === 0) return;\n setActionError(null);\n const results = await Promise.allSettled(\n selectedInvitations.map((invitation) =>\n cancelInvitation({ variables: { id: invitation.id } }),\n ),\n );\n const succeeded = results.filter(\n (result) => result.status === \"fulfilled\",\n ).length;\n const failed = results.length - succeeded;\n setActionSuccess(\n `${tr(\"devportal.cancelled\", \"Cancelled\")} ${succeeded} ${succeeded === 1 ? tr(\"devportal.invitationLower\", \"invitation\") : tr(\"devportal.invitationsLower\", \"invitations\")}${\n failed > 0 ? ` • ${failed} ${tr(\"devportal.failed\", \"failed\")}` : \"\"\n }`,\n );\n setShowBulkCancelInvitationsDialog(false);\n setSelectedInvitationIds(new Set());\n };\n\n const isLoading = membersLoading || invitationsLoading;\n const hasError = membersError || invitationsError;\n\n if (isLoading && !membersData && !invitationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n >\n <div className=\"flex items-center justify-center py-16\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n </PageLayout>\n );\n }\n\n if (hasError && !membersData && !invitationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\"devportal.failedToLoadMembers\", \"Failed to load members\")}\n description={\n membersError?.message ||\n invitationsError?.message ||\n tr(\n \"devportal.anErrorOccurredWhileLoadingTeamData\",\n \"An error occurred while loading team data\",\n )\n }\n />\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.ORG_MEMBER_READ}>\n <PageLayout\n title={tr(\"devportal.teamMembers\", \"Team Members\")}\n description={tr(\n \"devportal.manageYourOrganizationsTeam\",\n \"Manage your organization's team\",\n )}\n backLink={`/organizations/${orgId}`}\n backLabel={tr(\"devportal.backToOrganization\", \"Back to Organization\")}\n actions={\n <button\n onClick={() => setShowInviteDialog(true)}\n disabled={!canInvite}\n aria-disabled={!canInvite}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n <Plus size={16} />\n {tr(\"devportal.inviteMember\", \"Invite Member\")}\n </button>\n }\n >\n {/* Action Error Banner */}\n {actionError && (\n <div className=\"rounded-lg border border-border-subtle bg-status-error-bg-subtle p-3 flex items-center gap-2 text-sm text-status-error-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionError}\n <button\n onClick={() => setActionError(null)}\n className=\"ml-auto text-status-error-text hover:text-status-error-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {actionSuccess && (\n <div className=\"rounded-lg border border-border-subtle bg-status-success-bg-subtle p-3 flex items-center gap-2 text-sm text-status-success-text\">\n <AlertCircle size={16} className=\"flex-shrink-0\" />\n {actionSuccess}\n <button\n onClick={() => setActionSuccess(null)}\n className=\"ml-auto text-status-success-text hover:text-status-success-text\"\n >\n {tr(\"devportal.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {(selectedMemberIds.size > 0 || selectedInvitationIds.size > 0) && (\n <div className=\"flex flex-wrap items-center gap-3 rounded-card border border-border-seam bg-bg-surface p-4\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedMemberIds.size + selectedInvitationIds.size}{\" \"}\n {tr(\"devportal.selected\", \"selected\")}\n </span>\n <button\n onClick={clearSelections}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr(\"devportal.clearAllSelections\", \"Clear all selections\")}\n </button>\n </div>\n )}\n\n {/* Current Members */}\n <PageSection\n title={`${tr(\"devportal.members\", \"Members\")} (${membersCount})`}\n actions={\n members.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n onClick={handleBulkSuspendMembers}\n disabled={\n suspendableMembers.length === 0 || !canDeactivateMembers\n }\n aria-disabled={!canDeactivateMembers}\n className=\"rounded-md border border-status-warning-bg px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.suspendSelected\", \"Suspend Selected\")}\n {suspendableMembers.length > 0\n ? ` (${suspendableMembers.length})`\n : \"\"}\n </button>\n <button\n onClick={handleBulkReactivateMembers}\n disabled={\n reactivatableMembers.length === 0 || !canActivateMembers\n }\n aria-disabled={!canActivateMembers}\n className=\"rounded-md border border-status-success-bg px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.reactivateSelected\", \"Reactivate Selected\")}\n {reactivatableMembers.length > 0\n ? ` (${reactivatableMembers.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setShowBulkRemoveMembersDialog(true)}\n disabled={removableMembers.length === 0 || !canRemoveMembers}\n aria-disabled={!canRemoveMembers}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.removeSelected\", \"Remove Selected\")}\n {removableMembers.length > 0\n ? ` (${removableMembers.length})`\n : \"\"}\n </button>\n </div>\n ) : null\n }\n >\n {members.length > 0 ? (\n <DataTable\n data={members}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allMembersSelected}\n indeterminate={partiallySelectedMembers}\n onChange={toggleAllMembers}\n ariaLabel={tr(\n \"devportal.selectAllMembers\",\n \"Select all members\",\n )}\n />\n ),\n className: \"w-12\",\n render: (member) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedMemberIds.has(member.id)}\n disabled={member.role === \"OWNER\"}\n onChange={(checked) =>\n toggleMemberSelection(member.id, checked)\n }\n ariaLabel={`Select member ${resolveMemberLabel(member)}`}\n />\n </div>\n ),\n },\n {\n key: \"email\",\n header: tr(\"devportal.memberColumn\", \"Member\"),\n render: (member) => {\n const label = resolveMemberLabel(member);\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-8 w-8 items-center justify-center rounded-full bg-action-primary-bg/10 text-primary text-sm font-medium\">\n {label.charAt(0).toUpperCase()}\n </div>\n <div>\n <p className=\"font-medium\">{label}</p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"devportal.joined\", \"Joined\")}{\" \"}\n {format(new Date(member.joinedAt), \"MMM d, yyyy\")}\n </p>\n </div>\n </div>\n );\n },\n },\n {\n key: \"role\",\n header: tr(\"devportal.roleColumn\", \"Role\"),\n render: (member) => (\n <div className=\"flex items-center gap-2\">\n <Shield size={14} className=\"text-text-secondary\" />\n {member.role === \"OWNER\" ? (\n <span>\n {ORG_ROLE_LABELS[member.role as DeveloperOrgRole] ??\n member.role}\n </span>\n ) : (\n <select\n value={member.role}\n onChange={(event) =>\n void handleUpdateMemberRole(\n member.id,\n event.target.value as DeveloperOrgRole,\n )\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-2 py-1 text-xs text-text-primary\"\n >\n {Object.entries(ORG_ROLE_LABELS)\n .filter(([value]) => value !== \"OWNER\")\n .map(([value, label]) => (\n <option key={value} value={value}>\n {label}\n </option>\n ))}\n </select>\n )}\n </div>\n ),\n },\n {\n key: \"status\",\n header: tr(\"devportal.statusColumn\", \"Status\"),\n render: (member) =>\n member.isSuspended ? (\n <StatusBadge status=\"SUSPENDED\" type=\"app\" />\n ) : member.isActive ? (\n <StatusBadge status=\"ACTIVE\" type=\"app\" />\n ) : (\n <StatusBadge status=\"INACTIVE\" type=\"app\" />\n ),\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-32\",\n render: (member) =>\n member.role !== \"OWNER\" && (\n <div className=\"flex gap-1\">\n {member.isSuspended ? (\n <button\n className=\"text-xs text-status-success-text hover:underline disabled:opacity-50\"\n disabled={!canActivateMembers}\n aria-disabled={!canActivateMembers}\n title={tr(\n \"devportal.reactivateMember\",\n \"Reactivate member\",\n )}\n onClick={() => handleReactivateMember(member.id)}\n >\n {tr(\"devportal.reactivate\", \"Reactivate\")}\n </button>\n ) : (\n <button\n className=\"text-xs text-status-warning-text hover:underline disabled:opacity-50\"\n disabled={!canDeactivateMembers}\n aria-disabled={!canDeactivateMembers}\n title={tr(\n \"devportal.suspendMember\",\n \"Suspend member\",\n )}\n onClick={() => handleSuspendMember(member.id)}\n >\n {tr(\"devportal.suspend\", \"Suspend\")}\n </button>\n )}\n <button\n className=\"text-xs text-status-error-text hover:underline disabled:opacity-50\"\n disabled={!canRemoveMembers}\n aria-disabled={!canRemoveMembers}\n title={tr(\"devportal.removeMember\", \"Remove member\")}\n onClick={() => handleRemoveMember(member.id)}\n >\n {tr(\"devportal.remove\", \"Remove\")}\n </button>\n <button\n className=\"text-xs text-primary hover:underline disabled:opacity-50\"\n disabled={!canManageMembers}\n aria-disabled={!canManageMembers}\n title={tr(\n \"devportal.transferOwnership\",\n \"Transfer ownership\",\n )}\n onClick={() => setTransferOwnershipMember(member)}\n >\n {tr(\"devportal.makeOwner\", \"Make Owner\")}\n </button>\n </div>\n ),\n },\n ]}\n />\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\"devportal.noMembers\", \"No members\")}\n description={tr(\n \"devportal.inviteTeamMembersToCollaborate\",\n \"Invite team members to collaborate\",\n )}\n />\n )}\n </PageSection>\n\n {/* Pending Invitations */}\n {invitations.length > 0 && (\n <PageSection\n title={`${tr(\"devportal.pendingInvitations\", \"Pending Invitations\")} (${invitationsCount})`}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n onClick={handleBulkResendInvitations}\n disabled={selectedInvitations.length === 0}\n className=\"rounded-md border border-primary/30 px-3 py-2 text-sm font-medium text-primary hover:bg-action-primary-bg/5 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.resendSelected\", \"Resend Selected\")}\n {selectedInvitations.length > 0\n ? ` (${selectedInvitations.length})`\n : \"\"}\n </button>\n <button\n onClick={() => setShowBulkCancelInvitationsDialog(true)}\n disabled={selectedInvitations.length === 0}\n className=\"rounded-md border border-status-error-bg px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr(\"devportal.cancelSelected\", \"Cancel Selected\")}\n {selectedInvitations.length > 0\n ? ` (${selectedInvitations.length})`\n : \"\"}\n </button>\n </div>\n }\n >\n <DataTable\n data={invitations}\n keyField=\"id\"\n columns={[\n {\n key: \"select\",\n header: (\n <SelectionCheckbox\n checked={allInvitationsSelected}\n indeterminate={partiallySelectedInvitations}\n onChange={toggleAllInvitations}\n ariaLabel={tr(\n \"devportal.selectAllInvitations\",\n \"Select all invitations\",\n )}\n />\n ),\n className: \"w-12\",\n render: (invitation) => (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedInvitationIds.has(invitation.id)}\n onChange={(checked) =>\n toggleInvitationSelection(invitation.id, checked)\n }\n ariaLabel={`Select invitation ${invitation.invitedEmail}`}\n />\n </div>\n ),\n },\n {\n key: \"invitedEmail\",\n header: tr(\"devportal.emailColumn\", \"Email\"),\n render: (inv) => (\n <div className=\"flex items-center gap-2\">\n <Mail size={16} className=\"text-text-secondary\" />\n {inv.invitedEmail}\n </div>\n ),\n },\n {\n key: \"role\",\n header: tr(\"devportal.invitedRoleColumn\", \"Invited Role\"),\n render: (inv) =>\n ORG_ROLE_LABELS[inv.role as DeveloperOrgRole] ?? inv.role,\n },\n {\n key: \"status\",\n header: tr(\"devportal.statusColumn\", \"Status\"),\n render: (inv) => (\n <StatusBadge status={inv.status} type=\"invitation\" />\n ),\n },\n {\n key: \"expiresAt\",\n header: tr(\"devportal.expiresColumn\", \"Expires\"),\n render: (inv) =>\n format(new Date(inv.expiresAt), \"MMM d, yyyy\"),\n },\n {\n key: \"actions\",\n header: \"\",\n className: \"w-24\",\n render: (inv) => (\n <div className=\"flex gap-1\">\n <button\n className=\"rounded p-1 hover:bg-bg-sunken\"\n title={tr(\"devportal.resend\", \"Resend\")}\n onClick={() => handleResendInvitation(inv.id)}\n >\n <RefreshCw size={14} />\n </button>\n <button\n className=\"rounded p-1 hover:bg-bg-sunken text-status-error-text\"\n title={tr(\"devportal.cancel\", \"Cancel\")}\n onClick={() => handleCancelInvitation(inv.id)}\n >\n <UserMinus size={14} />\n </button>\n </div>\n ),\n },\n ]}\n />\n </PageSection>\n )}\n\n {/* Invite Dialog */}\n {showInviteDialog && (\n <ConfirmDialog\n open={showInviteDialog}\n onOpenChange={setShowInviteDialog}\n onConfirm={handleInvite}\n title={tr(\"devportal.inviteTeamMember\", \"Invite Team Member\")}\n confirmLabel={\n inviting\n ? tr(\"devportal.sendingDots\", \"Sending...\")\n : tr(\"devportal.sendInvitation\", \"Send Invitation\")\n }\n >\n <div className=\"space-y-4\">\n <InputField\n label={tr(\"devportal.emailAddress\", \"Email Address\")}\n type=\"email\"\n value={inviteEmail}\n onChange={(e) => setInviteEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n hint={tr(\n \"devportal.mustBeExistingVerifiedUser\",\n \"Must be an existing verified user\",\n )}\n required\n />\n <SelectField\n label={tr(\"devportal.roleColumn\", \"Role\")}\n value={inviteRole}\n onChange={(e) =>\n setInviteRole(e.target.value as DeveloperOrgRole)\n }\n options={[\n {\n value: \"ADMIN\",\n label: tr(\n \"devportal.adminFullAccess\",\n \"Admin - Full access\",\n ),\n },\n {\n value: \"DEVELOPER\",\n label: tr(\n \"devportal.developerCreateAndManageApps\",\n \"Developer - Create and manage apps\",\n ),\n },\n {\n value: \"VIEWER\",\n label: tr(\n \"devportal.viewerReadOnlyAccess\",\n \"Viewer - Read-only access\",\n ),\n },\n ]}\n required\n />\n </div>\n </ConfirmDialog>\n )}\n\n <ConfirmDialog\n open={showBulkRemoveMembersDialog}\n onOpenChange={setShowBulkRemoveMembersDialog}\n onConfirm={handleBulkRemoveMembers}\n title={tr(\n \"devportal.removeSelectedMembers\",\n \"Remove selected members\",\n )}\n description={`${tr(\"devportal.removeNSelectedMembers\", \"Remove\")} ${removableMembers.length} ${tr(\"devportal.selectedMembersFromOrg\", \"selected member(s) from this organization? This action cannot be undone.\")}`}\n confirmLabel={tr(\"devportal.removeMembers\", \"Remove Members\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={showBulkCancelInvitationsDialog}\n onOpenChange={setShowBulkCancelInvitationsDialog}\n onConfirm={handleBulkCancelInvitations}\n title={tr(\n \"devportal.cancelSelectedInvitations\",\n \"Cancel selected invitations\",\n )}\n description={`${tr(\"devportal.cancelNPendingInvitations\", \"Cancel\")} ${selectedInvitations.length} ${tr(\"devportal.pendingInvitationsQuestion\", \"pending invitation(s)?\")}`}\n confirmLabel={tr(\"devportal.cancelInvitations\", \"Cancel Invitations\")}\n cancelLabel={tr(\"devportal.keepInvitations\", \"Keep Invitations\")}\n variant=\"danger\"\n />\n\n <ConfirmDialog\n open={transferOwnershipMember !== null}\n onOpenChange={(open) => {\n if (!open) setTransferOwnershipMember(null);\n }}\n onConfirm={handleTransferOwnership}\n title={tr(\"devportal.transferOwnership\", \"Transfer ownership\")}\n description={\n transferOwnershipMember\n ? tr(\n \"devportal.transferOwnershipConfirmation\",\n `Transfer organization ownership to ${resolveMemberLabel(transferOwnershipMember)}?`,\n )\n : undefined\n }\n confirmLabel={tr(\"devportal.makeOwner\", \"Make Owner\")}\n cancelLabel={tr(\"devportal.cancel\", \"Cancel\")}\n variant=\"warning\"\n />\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
|
|
@@ -13,68 +13,68 @@ import { AlertCircle as u, AppWindow as d, Building2 as f, CheckCircle as p, Dol
|
|
|
13
13
|
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
14
14
|
//#region src/devportal/pages/OrganizationsPage.tsx
|
|
15
15
|
var b = () => {
|
|
16
|
-
let { navigate: a, basePath: o } = e(), { t: d } = l(),
|
|
16
|
+
let { navigate: a, basePath: o } = e(), { t: d } = l(), f = (e, t) => {
|
|
17
17
|
let n = d(e);
|
|
18
18
|
return n === e ? t : n;
|
|
19
|
-
}, { data:
|
|
19
|
+
}, { data: p, loading: m, error: _, refetch: b } = n({ fetchPolicy: "cache-and-network" }), S = p?.myDeveloperOrganizations ?? [], C = (e) => {
|
|
20
20
|
a?.(`${o}${e}`);
|
|
21
21
|
};
|
|
22
|
-
return
|
|
23
|
-
title:
|
|
24
|
-
description:
|
|
22
|
+
return m && !p ? /* @__PURE__ */ v(i, {
|
|
23
|
+
title: f("devportal.developerOrganizations", "Developer Organizations"),
|
|
24
|
+
description: f("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
25
25
|
children: /* @__PURE__ */ y("div", {
|
|
26
26
|
className: "flex items-center justify-center py-12",
|
|
27
27
|
children: [/* @__PURE__ */ v(h, { className: "h-8 w-8 animate-spin text-text-secondary" }), /* @__PURE__ */ v("span", {
|
|
28
28
|
className: "ml-2 text-text-secondary",
|
|
29
|
-
children:
|
|
29
|
+
children: f("devportal.loadingOrganizations", "Loading organizations...")
|
|
30
30
|
})]
|
|
31
31
|
})
|
|
32
|
-
}) :
|
|
33
|
-
title:
|
|
34
|
-
description:
|
|
32
|
+
}) : _ ? /* @__PURE__ */ v(i, {
|
|
33
|
+
title: f("devportal.developerOrganizations", "Developer Organizations"),
|
|
34
|
+
description: f("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
35
35
|
children: /* @__PURE__ */ y("div", {
|
|
36
36
|
className: "rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center",
|
|
37
37
|
children: [
|
|
38
38
|
/* @__PURE__ */ v(u, { className: "mx-auto h-8 w-8 text-status-error-text" }),
|
|
39
39
|
/* @__PURE__ */ v("h3", {
|
|
40
40
|
className: "mt-2 font-medium text-status-error-text",
|
|
41
|
-
children:
|
|
41
|
+
children: f("devportal.failedToLoadOrganizations", "Failed to load organizations")
|
|
42
42
|
}),
|
|
43
43
|
/* @__PURE__ */ v("p", {
|
|
44
44
|
className: "mt-1 text-sm text-text-secondary",
|
|
45
|
-
children: r(
|
|
45
|
+
children: r(_)
|
|
46
46
|
}),
|
|
47
47
|
/* @__PURE__ */ v("button", {
|
|
48
|
-
onClick: () =>
|
|
48
|
+
onClick: () => b(),
|
|
49
49
|
className: "mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
50
|
-
children:
|
|
50
|
+
children: f("devportal.tryAgain", "Try Again")
|
|
51
51
|
})
|
|
52
52
|
]
|
|
53
53
|
})
|
|
54
54
|
}) : /* @__PURE__ */ v(s, {
|
|
55
55
|
permission: c.ORG_READ,
|
|
56
56
|
children: /* @__PURE__ */ v(i, {
|
|
57
|
-
title:
|
|
58
|
-
description:
|
|
57
|
+
title: f("devportal.developerOrganizations", "Developer Organizations"),
|
|
58
|
+
description: f("devportal.manageYourDevTeams", "Manage your development teams"),
|
|
59
59
|
actions: /* @__PURE__ */ y("button", {
|
|
60
|
-
onClick: () =>
|
|
60
|
+
onClick: () => C("/organizations/new"),
|
|
61
61
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors",
|
|
62
|
-
children: [/* @__PURE__ */ v(g, { size: 16 }),
|
|
62
|
+
children: [/* @__PURE__ */ v(g, { size: 16 }), f("devportal.createOrganization", "Create Organization")]
|
|
63
63
|
}),
|
|
64
|
-
children:
|
|
64
|
+
children: S.length > 0 ? /* @__PURE__ */ v("div", {
|
|
65
65
|
className: "grid gap-6",
|
|
66
|
-
children:
|
|
66
|
+
children: S.map((e) => /* @__PURE__ */ v(x, {
|
|
67
67
|
org: e,
|
|
68
|
-
onClick: () =>
|
|
68
|
+
onClick: () => C(`/organizations/${e.id}`)
|
|
69
69
|
}, e.id))
|
|
70
70
|
}) : /* @__PURE__ */ v(t, {
|
|
71
|
-
|
|
72
|
-
title:
|
|
73
|
-
description:
|
|
71
|
+
illustration: "empty-people",
|
|
72
|
+
title: f("devportal.noOrganizationsYet", "No organizations yet"),
|
|
73
|
+
description: f("devportal.createOrgToCollaborate", "Create an organization to collaborate with your team and manage apps together"),
|
|
74
74
|
action: /* @__PURE__ */ y("button", {
|
|
75
|
-
onClick: () =>
|
|
75
|
+
onClick: () => C("/organizations/new"),
|
|
76
76
|
className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90",
|
|
77
|
-
children: [/* @__PURE__ */ v(g, { size: 16 }),
|
|
77
|
+
children: [/* @__PURE__ */ v(g, { size: 16 }), f("devportal.createOrganization", "Create Organization")]
|
|
78
78
|
})
|
|
79
79
|
})
|
|
80
80
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n DollarSign,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations = data?.myDeveloperOrganizations ?? [];\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.ORG_READ}>\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Building2 size={32} />}\n title={tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")}\n description={tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} /> Certified\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>{org.members?.length || 0} members</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps} apps\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <DollarSign size={16} className=\"text-text-secondary\" />\n <span>${(org.totalRevenue || 0).toLocaleString()}</span>\n </div>\n </div>\n </div>\n\n {/* Stats bar */}\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Total Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Active Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">API Calls</p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Rating</p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating ? `${org.averageRating.toFixed(1)} ★` : \"N/A\"}\n </p>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OrganizationsPage.js","names":[],"sources":["../../../src/devportal/pages/OrganizationsPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n Plus,\n Building2,\n Users,\n AppWindow,\n DollarSign,\n CheckCircle,\n AlertCircle,\n Loader2,\n} from \"lucide-react\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatusBadge, VerifiedBadge } from \"../components/StatusBadge\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n useGetMyOrganizationsQuery,\n getErrorMessage,\n type OrganizationFieldsFragment,\n} from \"../hooks\";\n\n/**\n * Organizations listing page\n *\n * Displays all developer organizations the current user is a member of.\n * Uses GraphQL to fetch real data from the DevPortal backend.\n */\nexport const OrganizationsPage: FC = () => {\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n // Fetch organizations from GraphQL API\n const { data, loading, error, refetch } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations = data?.myDeveloperOrganizations ?? [];\n\n const handleNavigate = (path: string) => {\n navigate?.(`${basePath}${path}`);\n };\n\n // Loading state\n if (loading && !data) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n <span className=\"ml-2 text-text-secondary\">\n {tr(\"devportal.loadingOrganizations\", \"Loading organizations...\")}\n </span>\n </div>\n </PageLayout>\n );\n }\n\n // Error state\n if (error) {\n return (\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n >\n <div className=\"rounded-lg border border-status-error-border/50 bg-status-error-bg/10 p-6 text-center\">\n <AlertCircle className=\"mx-auto h-8 w-8 text-status-error-text\" />\n <h3 className=\"mt-2 font-medium text-status-error-text\">\n {tr(\n \"devportal.failedToLoadOrganizations\",\n \"Failed to load organizations\",\n )}\n </h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {getErrorMessage(error)}\n </p>\n <button\n onClick={() => refetch()}\n className=\"mt-4 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n {tr(\"devportal.tryAgain\", \"Try Again\")}\n </button>\n </div>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.ORG_READ}>\n <PageLayout\n title={tr(\n \"devportal.developerOrganizations\",\n \"Developer Organizations\",\n )}\n description={tr(\n \"devportal.manageYourDevTeams\",\n \"Manage your development teams\",\n )}\n actions={\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n >\n {organizations.length > 0 ? (\n <div className=\"grid gap-6\">\n {organizations.map((org: OrganizationFieldsFragment) => (\n <OrganizationCard\n key={org.id}\n org={org as DeveloperOrganization}\n onClick={() => handleNavigate(`/organizations/${org.id}`)}\n />\n ))}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-people\"\n title={tr(\"devportal.noOrganizationsYet\", \"No organizations yet\")}\n description={tr(\n \"devportal.createOrgToCollaborate\",\n \"Create an organization to collaborate with your team and manage apps together\",\n )}\n action={\n <button\n onClick={() => handleNavigate(\"/organizations/new\")}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90\"\n >\n <Plus size={16} />\n {tr(\"devportal.createOrganization\", \"Create Organization\")}\n </button>\n }\n />\n )}\n </PageLayout>\n </PermissionGuard>\n );\n};\n\n// Organization card component\nconst OrganizationCard: FC<{\n org: DeveloperOrganization;\n onClick: () => void;\n}> = ({ org, onClick }) => {\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onClick();\n }\n }}\n className=\"cursor-pointer rounded-card border border-border-seam bg-bg-surface p-6 shadow-[var(--shadow-pop)] transition-[box-shadow,border-color] hover:shadow-[var(--shadow-pop-hover)] hover:border-border-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Left side - Info */}\n <div className=\"flex items-start gap-4\">\n {org.logoUrl ? (\n <img\n src={org.logoUrl}\n alt={org.name}\n className=\"h-16 w-16 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={32} />\n </div>\n )}\n <div>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <h3 className=\"text-lg font-semibold\">{org.name}</h3>\n {org.isVerified && <VerifiedBadge verified />}\n {org.isCertified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n <CheckCircle size={12} /> Certified\n </span>\n )}\n </div>\n {org.description && (\n <p className=\"mt-1 text-sm text-text-secondary\">\n {org.description}\n </p>\n )}\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <StatusBadge status={org.tier} type=\"tier\" />\n {org.partnerTier && (\n <StatusBadge status={org.partnerTier} type=\"partner\" />\n )}\n </div>\n </div>\n </div>\n\n {/* Right side - Stats */}\n <div className=\"flex flex-wrap gap-6 text-sm\">\n <div className=\"flex items-center gap-2\">\n <Users size={16} className=\"text-text-secondary\" />\n <span>{org.members?.length || 0} members</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AppWindow size={16} className=\"text-text-secondary\" />\n <span>\n {org.publishedApps} / {org.totalApps} apps\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <DollarSign size={16} className=\"text-text-secondary\" />\n <span>${(org.totalRevenue || 0).toLocaleString()}</span>\n </div>\n </div>\n </div>\n\n {/* Stats bar */}\n <div className=\"mt-4 grid grid-cols-2 gap-4 rounded-lg bg-bg-sunken/50 p-4 sm:grid-cols-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Total Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.totalInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Active Installs</p>\n <p className=\"text-lg font-semibold\">\n {(org.activeInstalls || 0).toLocaleString()}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">API Calls</p>\n <p className=\"text-lg font-semibold\">\n {org.totalApiCalls\n ? `${(parseInt(org.totalApiCalls) / 1000000).toFixed(1)}M`\n : \"0\"}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Avg Rating</p>\n <p className=\"text-lg font-semibold\">\n {org.averageRating ? `${org.averageRating.toFixed(1)} ★` : \"N/A\"}\n </p>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -454,7 +454,7 @@ var M = () => {
|
|
|
454
454
|
keyField: "id",
|
|
455
455
|
onRowClick: (e) => Z(`/apps/${M}/webhooks/${e.id}`)
|
|
456
456
|
}) : /* @__PURE__ */ D(n, {
|
|
457
|
-
|
|
457
|
+
illustration: "empty-notifications",
|
|
458
458
|
title: P("devportal.noWebhooksFound", "No webhooks found"),
|
|
459
459
|
description: I || R ? P("devportal.tryAdjustingFilters", "Try adjusting your filters") : P("devportal.createFirstWebhook", "Create your first webhook to receive real-time event notifications"),
|
|
460
460
|
action: !I && !R ? /* @__PURE__ */ O("button", {
|