Skip to content

Commit ae7fbef

Browse files
committed
feat(teams): enhance team deletion process with success messaging and improved error handling
1 parent 04ec27e commit ae7fbef

File tree

6 files changed

+70
-17
lines changed

6 files changed

+70
-17
lines changed

services/backend/src/middleware/roleMiddleware.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,33 @@ import { RoleService } from '../services/roleService';
99
*/
1010
export function requirePermission(permission: string) {
1111
return async (request: FastifyRequest, reply: FastifyReply) => {
12-
// Check if user is authenticated
13-
if (!request.user) {
14-
return reply.status(401).send({ error: 'Authentication required' });
15-
}
16-
17-
const roleService = new RoleService();
18-
1912
try {
13+
// Check if user is authenticated
14+
if (!request.user) {
15+
return reply.status(401).send({
16+
success: false,
17+
error: 'Authentication required'
18+
});
19+
}
20+
21+
const roleService = new RoleService();
22+
2023
const hasPermission = await roleService.userHasPermission(request.user.id, permission);
2124

2225
if (!hasPermission) {
2326
return reply.status(403).send({
27+
success: false,
2428
error: 'Insufficient permissions',
2529
required_permission: permission
2630
});
2731
}
2832
} catch (error) {
29-
request.log.error(error, 'Error checking user permissions');
30-
return reply.status(500).send({ error: 'Internal server error' });
33+
request.log.error(error, `Error checking user permissions for permission: ${permission}`);
34+
return reply.status(500).send({
35+
success: false,
36+
error: 'Internal server error',
37+
details: error instanceof Error ? error.message : 'Unknown error'
38+
});
3139
}
3240
};
3341
}

services/backend/src/routes/teams/index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,19 @@ export default async function teamsRoute(fastify: FastifyInstance) {
429429
});
430430
}
431431

432-
// Check if it's a default team
433-
const isDefaultTeam = await TeamService.isDefaultTeam(teamId, request.user.id);
432+
// Check if it's a default team with better error handling
433+
let isDefaultTeam = false;
434+
try {
435+
isDefaultTeam = await TeamService.isDefaultTeam(teamId, request.user.id);
436+
fastify.log.info(`Default team check for team ${teamId}: ${isDefaultTeam}`);
437+
} catch (defaultTeamError) {
438+
fastify.log.error(defaultTeamError, 'Error checking if team is default team');
439+
return reply.status(500).send({
440+
success: false,
441+
error: 'Failed to verify team deletion eligibility',
442+
});
443+
}
444+
434445
if (isDefaultTeam) {
435446
return reply.status(400).send({
436447
success: false,
@@ -457,6 +468,7 @@ export default async function teamsRoute(fastify: FastifyInstance) {
457468
return reply.status(500).send({
458469
success: false,
459470
error: 'Failed to delete team',
471+
details: error instanceof Error ? error.message : 'Unknown error'
460472
});
461473
}
462474
});

services/frontend/src/i18n/locales/en/teams.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export default {
1111
placeholder: 'Search teams...'
1212
}
1313
},
14+
messages: {
15+
deleteSuccess: 'Team "{teamName}" has been successfully deleted.'
16+
},
1417
pagination: {
1518
rowsSelected: '{selected} of {total} row(s) selected.',
1619
previous: 'Previous',

services/frontend/src/services/teamService.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,6 @@ export class TeamService {
275275

276276
const response = await fetch(`${apiUrl}/api/teams/${teamId}`, {
277277
method: 'DELETE',
278-
headers: {
279-
'Content-Type': 'application/json',
280-
},
281278
credentials: 'include',
282279
});
283280

services/frontend/src/views/Teams.vue

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ import AddTeamModal from '@/components/teams/AddTeamModal.vue'
2828
import { TeamService, type TeamWithRole } from '@/services/teamService'
2929
import { UserService } from '@/services/userService'
3030
import { createColumns } from './teams/columns'
31-
import { useRouter } from 'vue-router'
31+
import { useRouter, useRoute } from 'vue-router'
32+
import { Alert, AlertDescription } from '@/components/ui/alert'
33+
import { CheckCircle } from 'lucide-vue-next'
3234
3335
const { t } = useI18n()
3436
const router = useRouter()
37+
const route = useRoute()
3538
3639
// State
3740
const teams = ref<TeamWithRole[]>([])
@@ -44,6 +47,7 @@ const rowSelection = ref({})
4447
const showAddModal = ref(false)
4548
const canCreateTeams = ref(false)
4649
const userPermissions = ref<string[]>([])
50+
const deleteSuccessMessage = ref<string | null>(null)
4751
4852
// Handle manage team navigation
4953
const handleManageTeam = (teamId: string) => {
@@ -89,8 +93,27 @@ const handleTeamCreated = async () => {
8993
await TeamService.getUserTeams(true)
9094
}
9195
96+
// Check for delete success message from query params
97+
const checkDeleteSuccess = () => {
98+
const deletedTeamName = route.query.deleted as string
99+
if (deletedTeamName) {
100+
deleteSuccessMessage.value = t('teams.messages.deleteSuccess', { teamName: deletedTeamName })
101+
102+
// Clear the query parameter from URL
103+
router.replace({ path: '/teams' })
104+
105+
// Clear the message after 5 seconds
106+
setTimeout(() => {
107+
deleteSuccessMessage.value = null
108+
}, 5000)
109+
}
110+
}
111+
92112
// Load data on component mount
93113
onMounted(async () => {
114+
// Check for delete success message first
115+
checkDeleteSuccess()
116+
94117
await Promise.all([
95118
checkPermissions(),
96119
fetchTeams()
@@ -170,6 +193,12 @@ const filterValue = computed({
170193
</Button>
171194
</div>
172195

196+
<!-- Delete Success Message -->
197+
<Alert v-if="deleteSuccessMessage" class="border-green-200 bg-green-50 text-green-800">
198+
<CheckCircle class="h-4 w-4" />
199+
<AlertDescription>{{ deleteSuccessMessage }}</AlertDescription>
200+
</Alert>
201+
173202
<!-- Loading State -->
174203
<div v-if="isLoading" class="text-muted-foreground">
175204
{{ t('teams.table.loading') }}

services/frontend/src/views/teams/TeamManage.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,14 @@ const saveTeam = async () => {
170170
const deleteTeam = async () => {
171171
try {
172172
isDeleting.value = true
173+
const teamName = team.value?.name || 'Unknown Team'
173174
await TeamService.deleteTeam(teamId.value)
174175
175-
// Redirect to teams list
176-
router.push('/teams')
176+
// Redirect to teams list with success message
177+
router.push({
178+
path: '/teams',
179+
query: { deleted: teamName }
180+
})
177181
} catch (err) {
178182
error.value = err instanceof Error ? err.message : 'Failed to delete team'
179183
console.error('Error deleting team:', err)

0 commit comments

Comments
 (0)