Fix email invite/ allow non auth and table refresh issues (#5076)

# Description of Changes

- Show warning when email invite fails but user is created
  - Auto-refresh user/team tables after modifications
  - Fix invite email URLs to use frontend URL instead of backend
  - Support anonymous SMTP for local development
---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Anthony Stirling
2025-11-29 16:03:44 +00:00
committed by GitHub
parent 85d9b5b83d
commit 4ae79d92ae
7 changed files with 106 additions and 21 deletions

View File

@@ -27,9 +27,10 @@ import { useNavigate } from 'react-router-dom';
interface InviteMembersModalProps {
opened: boolean;
onClose: () => void;
onSuccess?: () => void;
}
export default function InviteMembersModal({ opened, onClose }: InviteMembersModalProps) {
export default function InviteMembersModal({ opened, onClose, onSuccess }: InviteMembersModalProps) {
const { t } = useTranslation();
const { config } = useAppConfig();
const navigate = useNavigate();
@@ -136,6 +137,7 @@ export default function InviteMembersModal({ opened, onClose }: InviteMembersMod
});
alert({ alertType: 'success', title: t('workspace.people.addMember.success') });
onClose();
onSuccess?.();
// Reset form
setInviteForm({
username: '',
@@ -168,11 +170,23 @@ export default function InviteMembersModal({ opened, onClose }: InviteMembersMod
});
if (response.successCount > 0) {
// Show success message
alert({
alertType: 'success',
title: t('workspace.people.emailInvite.success', { count: response.successCount, defaultValue: `Successfully invited ${response.successCount} user(s)` })
});
// Show warning if there were partial failures
if (response.failureCount > 0 && response.errors) {
alert({
alertType: 'warning',
title: t('workspace.people.emailInvite.partialFailure', 'Some invites failed'),
body: response.errors
});
}
onClose();
onSuccess?.();
setEmailInviteForm({
emails: '',
role: 'ROLE_USER',
@@ -208,6 +222,7 @@ export default function InviteMembersModal({ opened, onClose }: InviteMembersMod
sendEmail: inviteLinkForm.sendEmail,
});
setGeneratedInviteLink(response.inviteUrl);
onSuccess?.();
if (inviteLinkForm.sendEmail && inviteLinkForm.email) {
alert({ alertType: 'success', title: t('workspace.people.inviteLink.emailSent', 'Invite link generated and sent via email') });
}

View File

@@ -588,6 +588,7 @@ export default function PeopleSection() {
<InviteMembersModal
opened={inviteModalOpened}
onClose={() => setInviteModalOpened(false)}
onSuccess={fetchData}
/>
{/* Edit User Modal */}

View File

@@ -80,9 +80,9 @@ export default function TeamsSection() {
setProcessing(true);
await teamService.createTeam(newTeamName);
alert({ alertType: 'success', title: t('workspace.teams.createTeam.success') });
setCreateModalOpened(false);
setNewTeamName('');
fetchTeams();
setCreateModalOpened(false);
await fetchTeams();
} catch (error: any) {
console.error('Failed to create team:', error);
const errorMessage = error.response?.data?.message ||
@@ -105,10 +105,10 @@ export default function TeamsSection() {
setProcessing(true);
await teamService.renameTeam(selectedTeam.id, renameTeamName);
alert({ alertType: 'success', title: t('workspace.teams.renameTeam.success') });
setRenameModalOpened(false);
setSelectedTeam(null);
setRenameTeamName('');
fetchTeams();
setSelectedTeam(null);
setRenameModalOpened(false);
await fetchTeams();
} catch (error: any) {
console.error('Failed to rename team:', error);
const errorMessage = error.response?.data?.message ||
@@ -134,7 +134,7 @@ export default function TeamsSection() {
try {
await teamService.deleteTeam(team.id);
alert({ alertType: 'success', title: t('workspace.teams.deleteTeam.success') });
fetchTeams();
await fetchTeams();
} catch (error: any) {
console.error('Failed to delete team:', error);
const errorMessage = error.response?.data?.message ||
@@ -182,10 +182,10 @@ export default function TeamsSection() {
setProcessing(true);
await teamService.addUserToTeam(selectedTeam.id, parseInt(selectedUserId));
alert({ alertType: 'success', title: t('workspace.teams.addMemberToTeam.success') });
setAddMemberModalOpened(false);
setSelectedTeam(null);
setSelectedUserId('');
fetchTeams();
setSelectedTeam(null);
setAddMemberModalOpened(false);
await fetchTeams();
} catch (error) {
console.error('Failed to add member to team:', error);
alert({ alertType: 'error', title: t('workspace.teams.addMemberToTeam.error') });