Adjusting role actions
This commit is contained in:
+106
-19
@@ -1621,6 +1621,7 @@ function App() {
|
||||
const [editingMedicationId, setEditingMedicationId] = useState('');
|
||||
const [deletingMedicationId, setDeletingMedicationId] = useState('');
|
||||
const [savingMedicationAdministrationId, setSavingMedicationAdministrationId] = useState('');
|
||||
const [updatingWorkspaceMemberId, setUpdatingWorkspaceMemberId] = useState('');
|
||||
const [removingWorkspaceMemberId, setRemovingWorkspaceMemberId] = useState('');
|
||||
const [expandedSettingsSection, setExpandedSettingsSection] = useState<SettingsSection | null>(null);
|
||||
|
||||
@@ -1628,6 +1629,11 @@ function App() {
|
||||
() => birds.find((bird) => bird.id === selectedBirdId) ?? null,
|
||||
[birds, selectedBirdId],
|
||||
);
|
||||
const isBillingOwner = Boolean(
|
||||
authSession?.user.email &&
|
||||
workspace?.billingEmail &&
|
||||
authSession.user.email.trim().toLowerCase() === workspace.billingEmail.trim().toLowerCase(),
|
||||
);
|
||||
const selectedBirdAdoptionTransferCode = selectedBird ? adoptionTransferCodes[selectedBird.id] ?? '' : '';
|
||||
const editingBird = useMemo(
|
||||
() => birds.find((bird) => bird.id === editingBirdId) ?? null,
|
||||
@@ -4712,7 +4718,15 @@ function App() {
|
||||
email: data.member.inviteEmail,
|
||||
};
|
||||
|
||||
setWorkspaceMembers((current) => [...current, nextMember]);
|
||||
setWorkspaceMembers((current) => {
|
||||
const existingIndex = current.findIndex((member) => member.id === nextMember.id);
|
||||
|
||||
if (existingIndex === -1) {
|
||||
return [...current, nextMember];
|
||||
}
|
||||
|
||||
return current.map((member) => (member.id === nextMember.id ? nextMember : member));
|
||||
});
|
||||
setWorkspaceMemberForm(emptyWorkspaceMemberForm);
|
||||
} catch (memberError) {
|
||||
setError(memberError instanceof Error ? memberError.message : 'Unable to add rescue team member.');
|
||||
@@ -4721,6 +4735,40 @@ function App() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateWorkspaceMemberRole = async (memberId: string, role: WorkspaceRole) => {
|
||||
setError('');
|
||||
setUpdatingWorkspaceMemberId(memberId);
|
||||
|
||||
try {
|
||||
const response = await apiFetch(`/workspace/members/${memberId}`, authToken, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ role }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(await readErrorMessage(response, 'Unable to update collaborator role.'));
|
||||
}
|
||||
|
||||
const data = (await readJsonSafely<{ member?: WorkspaceMember }>(response)) ?? {};
|
||||
|
||||
if (!data.member) {
|
||||
throw new Error('Unable to update collaborator role.');
|
||||
}
|
||||
|
||||
const updatedMember = {
|
||||
...data.member,
|
||||
email: data.member.inviteEmail,
|
||||
};
|
||||
|
||||
setWorkspaceMembers((current) => current.map((member) => (member.id === memberId ? updatedMember : member)));
|
||||
} catch (memberError) {
|
||||
setError(memberError instanceof Error ? memberError.message : 'Unable to update collaborator role.');
|
||||
} finally {
|
||||
setUpdatingWorkspaceMemberId('');
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveWorkspaceMember = async (memberId: string) => {
|
||||
setError('');
|
||||
setRemovingWorkspaceMemberId(memberId);
|
||||
@@ -7352,7 +7400,6 @@ function App() {
|
||||
})
|
||||
}
|
||||
>
|
||||
<option value="owner">Owner</option>
|
||||
<option value="assistant">Assistant</option>
|
||||
<option value="caregiver">Caregiver</option>
|
||||
<option value="viewer">Viewer</option>
|
||||
@@ -7365,23 +7412,63 @@ function App() {
|
||||
|
||||
<div className="recent-list">
|
||||
{workspaceMembers.length ? (
|
||||
workspaceMembers.map((member) => (
|
||||
<article key={member.id} className="vet-visit-card">
|
||||
<strong>{member.name}</strong>
|
||||
<span>
|
||||
{formatWorkspaceRole(member.role)} • {member.email || member.inviteEmail}
|
||||
</span>
|
||||
<small>{member.acceptedAt ? 'Active access' : 'Invitation pending'}</small>
|
||||
<button
|
||||
className="secondary-button"
|
||||
onClick={() => handleRemoveWorkspaceMember(member.id)}
|
||||
type="button"
|
||||
disabled={removingWorkspaceMemberId === member.id || member.role === 'owner'}
|
||||
>
|
||||
{member.role === 'owner' ? 'Owner' : removingWorkspaceMemberId === member.id ? 'Removing...' : 'Remove'}
|
||||
</button>
|
||||
</article>
|
||||
))
|
||||
workspaceMembers.map((member) => {
|
||||
const memberEmail = member.email || member.inviteEmail || '';
|
||||
const memberIsBillingOwner = Boolean(
|
||||
workspace?.billingEmail &&
|
||||
memberEmail.trim().toLowerCase() === workspace.billingEmail.trim().toLowerCase(),
|
||||
);
|
||||
const canRemoveOwner = member.role === 'owner' && isBillingOwner && member.id !== activeMembership?.id;
|
||||
const canChangeOwnerRole =
|
||||
member.role === 'owner' &&
|
||||
activeMembership?.role === 'owner' &&
|
||||
member.id !== activeMembership.id &&
|
||||
(isBillingOwner || !memberIsBillingOwner);
|
||||
const canRemoveMember = member.role !== 'owner' || canRemoveOwner;
|
||||
|
||||
return (
|
||||
<article key={member.id} className="vet-visit-card">
|
||||
<strong>{member.name}</strong>
|
||||
<span>
|
||||
{formatWorkspaceRole(member.role)} • {member.email || member.inviteEmail}
|
||||
</span>
|
||||
<small>{member.acceptedAt ? 'Active access' : 'Invitation pending'}</small>
|
||||
<label>
|
||||
Role
|
||||
<select
|
||||
value={member.role}
|
||||
onChange={(event) => handleUpdateWorkspaceMemberRole(member.id, event.target.value as WorkspaceRole)}
|
||||
disabled={
|
||||
(member.role === 'owner' && !canChangeOwnerRole) ||
|
||||
updatingWorkspaceMemberId === member.id ||
|
||||
removingWorkspaceMemberId === member.id
|
||||
}
|
||||
>
|
||||
{member.role === 'owner' ? <option value="owner">Owner</option> : null}
|
||||
<option value="assistant">Assistant</option>
|
||||
<option value="caregiver">Caregiver</option>
|
||||
<option value="viewer">Viewer</option>
|
||||
</select>
|
||||
</label>
|
||||
<button
|
||||
className="danger-button"
|
||||
onClick={() => handleRemoveWorkspaceMember(member.id)}
|
||||
type="button"
|
||||
disabled={
|
||||
removingWorkspaceMemberId === member.id ||
|
||||
updatingWorkspaceMemberId === member.id ||
|
||||
!canRemoveMember
|
||||
}
|
||||
>
|
||||
{removingWorkspaceMemberId === member.id
|
||||
? 'Removing...'
|
||||
: canRemoveMember
|
||||
? 'Remove access'
|
||||
: 'Owner'}
|
||||
</button>
|
||||
</article>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<article className="vet-visit-card empty-card">
|
||||
<strong>No collaborators yet</strong>
|
||||
|
||||
Reference in New Issue
Block a user