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

Function OrgPage

packages/react/src/pages/org.tsx:136–429  ·  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;
})

Source from the content-addressed store, hash-verified

134}
135
136export function OrgPage(props: {
137 domainsSection?: React.ReactNode;
138 // Cloud injects the plan-upgrade call to action (a link to billing/plans).
139 // When set and the org is at its seat limit, clicking "Invite member" opens
140 // an upgrade prompt instead of the invite form. Self-host has no seat limit,
141 // so it never reaches this and can omit it.
142 upgradeAction?: React.ReactNode;
143}) {
144 useExecutorDocumentTitle("Organization");
145 const auth = useAuth();
146 const organizationName =
147 auth.status === "authenticated" ? (auth.organization?.name ?? "Organization") : "Organization";
148 const membersResult = useAtomValue(orgMembersAtom);
149 const refreshMembers = useAtomRefresh(orgMembersAtom);
150 const rolesResult = useAtomValue(orgRolesAtom);
151 const doRemove = useAtomSet(removeMember, { mode: "promiseExit" });
152 const doUpdateRole = useAtomSet(updateMemberRole, { mode: "promiseExit" });
153 const doUpdateOrgName = useAtomSet(updateOrgName, { mode: "promiseExit" });
154 const [inviteOpen, setInviteOpen] = useState(false);
155 const [upgradeOpen, setUpgradeOpen] = useState(false);
156 const [editName, setEditName] = useState(organizationName);
157 const [savingName, setSavingName] = useState(false);
158 const [search, setSearch] = useState("");
159
160 const roles = AsyncResult.match(rolesResult, {
161 onInitial: () => [] as readonly RoleData[],
162 onFailure: () => [] as readonly RoleData[],
163 onSuccess: ({ value }) => value.roles,
164 });
165
166 const seats = AsyncResult.match(membersResult, {
167 onInitial: () => undefined,
168 onFailure: () => undefined,
169 onSuccess: ({ value }) => value.seats,
170 });
171 // At the plan's member-seat limit, "Invite member" opens an upgrade prompt
172 // (when cloud provided one) instead of the invite form, so the admin gets a
173 // clear next step rather than a refused invite.
174 const atSeatLimit = !!seats && !seats.unlimited && seats.used >= seats.granted;
175 const showUpgradeOnInvite = atSeatLimit && !!props.upgradeAction;
176
177 const handleRemove = async (membershipId: string, name: string) => {
178 const exit = await doRemove({
179 params: { membershipId },
180 reactivityKeys: orgMemberWriteKeys,
181 });
182 trackEvent("org_member_removed", { success: Exit.isSuccess(exit) });
183 toast[Exit.isSuccess(exit) ? "success" : "error"](
184 Exit.isSuccess(exit) ? `Removed ${name}` : "Failed to remove member",
185 );
186 };
187
188 const handleChangeRole = async (membershipId: string, roleSlug: string, roleName: string) => {
189 const exit = await doUpdateRole({
190 params: { membershipId },
191 payload: { roleSlug },
192 reactivityKeys: orgMemberWriteKeys,
193 });

Callers

nothing calls this directly

Calls 7

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

Tested by

no test coverage detected