MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / OrgPage

Function OrgPage

packages/react/src/pages/org.tsx:163–497  ·  view source on GitHub ↗
(props: {
  domainsSection?: React.ReactNode;
  // Cloud injects the plan-upgrade call to action (a link to billing/plans).
  // When set and the org is at its seat limit, clicking "Invite member" opens
  // an upgrade prompt instead of the invite form. Self-host has no seat limit,
  // so it never reaches this and can omit it.
  upgradeAction?: React.ReactNode;
  // Cloud injects a destructive "delete organization" section here. It hangs
  // off the cloud-only `/auth/delete-organization` endpoint (WorkOS + billing
  // teardown), so self-host omits it. Rendered last, below members.
  dangerZoneSection?: React.ReactNode;
})

Source from the content-addressed store, hash-verified

161}
162
163export function OrgPage(props: {
164 domainsSection?: React.ReactNode;
165 // Cloud injects the plan-upgrade call to action (a link to billing/plans).
166 // When set and the org is at its seat limit, clicking "Invite member" opens
167 // an upgrade prompt instead of the invite form. Self-host has no seat limit,
168 // so it never reaches this and can omit it.
169 upgradeAction?: React.ReactNode;
170 // Cloud injects a destructive "delete organization" section here. It hangs
171 // off the cloud-only `/auth/delete-organization` endpoint (WorkOS + billing
172 // teardown), so self-host omits it. Rendered last, below members.
173 dangerZoneSection?: React.ReactNode;
174}) {
175 useExecutorDocumentTitle("Organization");
176 const auth = useAuth();
177 const organizationName =
178 auth.status === "authenticated" ? (auth.organization?.name ?? "Organization") : "Organization";
179 const membersResult = useAtomValue(orgMembersAtom);
180 const refreshMembers = useAtomRefresh(orgMembersAtom);
181 const rolesResult = useAtomValue(orgRolesAtom);
182 const doRemove = useAtomSet(removeMember, { mode: "promiseExit" });
183 const [removingMember, setRemovingMember] = useState<{ id: string; name: string } | null>(null);
184 const doUpdateRole = useAtomSet(updateMemberRole, { mode: "promiseExit" });
185 const doUpdateOrgName = useAtomSet(updateOrgName, { mode: "promiseExit" });
186 const [inviteOpen, setInviteOpen] = useState(false);
187 const [upgradeOpen, setUpgradeOpen] = useState(false);
188 const [editName, setEditName] = useState(organizationName);
189 const [savingName, setSavingName] = useState(false);
190 const [search, setSearch] = useState("");
191
192 const roles = AsyncResult.match(rolesResult, {
193 onInitial: () => [] as readonly RoleData[],
194 onFailure: () => [] as readonly RoleData[],
195 onSuccess: ({ value }) => value.roles,
196 });
197
198 const seats = AsyncResult.match(membersResult, {
199 onInitial: () => undefined,
200 onFailure: () => undefined,
201 onSuccess: ({ value }) => value.seats,
202 });
203 // At the plan's member-seat limit, "Invite member" opens an upgrade prompt
204 // (when cloud provided one) instead of the invite form, so the admin gets a
205 // clear next step rather than a refused invite.
206 const atSeatLimit = !!seats && !seats.unlimited && seats.used >= seats.granted;
207 const showUpgradeOnInvite = atSeatLimit && !!props.upgradeAction;
208
209 const handleRemove = async (membershipId: string, name: string) => {
210 setRemovingMember(null);
211 const exit = await doRemove({
212 params: { membershipId },
213 reactivityKeys: orgMemberWriteKeys,
214 });
215 trackEvent("org_member_removed", { success: Exit.isSuccess(exit) });
216 toast[Exit.isSuccess(exit) ? "success" : "error"](
217 Exit.isSuccess(exit) ? `Removed ${name}` : "Failed to remove member",
218 );
219 };
220

Callers

nothing calls this directly

Calls 9

useExecutorDocumentTitleFunction · 0.90
useAuthFunction · 0.90
isAsyncResultLoadingFunction · 0.90
handleSaveNameFunction · 0.85
memberInitialsFunction · 0.85
memberLabelFunction · 0.85
formatLastActiveFunction · 0.85
handleChangeRoleFunction · 0.85
handleRemoveFunction · 0.70

Tested by

no test coverage detected