Skip to content

Commit 655660d

Browse files
author
Lasim
committed
feat: Refactor team management table by creating a dedicated component and enhancing search functionality
1 parent d83eb9c commit 655660d

File tree

4 files changed

+189
-279
lines changed

4 files changed

+189
-279
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,21 @@ export default {
77
loading: 'Loading teams...',
88
error: 'Error loading teams: {error}',
99
noResults: 'No teams found.',
10+
noDescription: 'No description',
11+
selected: 'Selected',
12+
switch: 'Switch',
13+
manage: 'Manage',
14+
noActions: 'No actions',
1015
search: {
1116
placeholder: 'Search teams...'
17+
},
18+
columns: {
19+
name: 'Team Name',
20+
description: 'Description',
21+
role: 'Your Role',
22+
created: 'Created',
23+
switch: 'Switch Team',
24+
actions: 'Actions'
1225
}
1326
},
1427
messages: {
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import { Button } from '@/components/ui/button'
5+
import { Badge } from '@/components/ui/badge'
6+
import { Settings, ArrowRightLeft } from 'lucide-vue-next'
7+
import type { TeamWithRole } from '@/services/teamService'
8+
9+
interface Props {
10+
teams: TeamWithRole[]
11+
selectedTeamId: string | null
12+
userPermissions: string[]
13+
onManageTeam: (teamId: string) => void
14+
onSwitchTeam: (teamId: string) => void
15+
}
16+
17+
const props = defineProps<Props>()
18+
const { t } = useI18n()
19+
20+
// Helper function to check if user can manage a specific team
21+
const canManageTeam = (team: TeamWithRole): boolean => {
22+
return props.userPermissions.includes('teams.edit') && team.role === 'team_admin'
23+
}
24+
25+
// Helper function to format date
26+
const formatDate = (date: Date | string): string => {
27+
const dateObj = typeof date === 'string' ? new Date(date) : date
28+
return dateObj.toLocaleDateString()
29+
}
30+
31+
// Helper function to get role display info
32+
const getRoleDisplay = (role: string) => {
33+
const isAdmin = role === 'team_admin'
34+
return {
35+
text: isAdmin ? 'Admin' : 'User',
36+
class: isAdmin
37+
? 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300'
38+
: 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300'
39+
}
40+
}
41+
</script>
42+
43+
<template>
44+
<div class="rounded-md border">
45+
<table class="w-full">
46+
<thead>
47+
<tr class="border-b bg-muted/50">
48+
<th class="h-12 px-4 text-left align-middle font-medium text-muted-foreground">
49+
{{ t('teams.table.columns.name') }}
50+
</th>
51+
<th class="h-12 px-4 text-left align-middle font-medium text-muted-foreground">
52+
{{ t('teams.table.columns.description') }}
53+
</th>
54+
<th class="h-12 px-4 text-left align-middle font-medium text-muted-foreground">
55+
{{ t('teams.table.columns.role') }}
56+
</th>
57+
<th class="h-12 px-4 text-left align-middle font-medium text-muted-foreground">
58+
{{ t('teams.table.columns.created') }}
59+
</th>
60+
<th class="h-12 px-4 text-left align-middle font-medium text-muted-foreground">
61+
{{ t('teams.table.columns.switch') }}
62+
</th>
63+
<th class="h-12 px-4 text-right align-middle font-medium text-muted-foreground">
64+
{{ t('teams.table.columns.actions') }}
65+
</th>
66+
</tr>
67+
</thead>
68+
<tbody>
69+
<tr
70+
v-for="team in teams"
71+
:key="team.id"
72+
class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"
73+
>
74+
<!-- Team Name -->
75+
<td class="p-4 align-middle">
76+
<div class="font-medium">{{ team.name }}</div>
77+
</td>
78+
79+
<!-- Description -->
80+
<td class="p-4 align-middle">
81+
<div class="text-muted-foreground">
82+
{{ team.description || t('teams.table.noDescription') }}
83+
</div>
84+
</td>
85+
86+
<!-- Role -->
87+
<td class="p-4 align-middle">
88+
<Badge
89+
:class="getRoleDisplay(team.role).class"
90+
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
91+
>
92+
{{ getRoleDisplay(team.role).text }}
93+
</Badge>
94+
</td>
95+
96+
<!-- Created Date -->
97+
<td class="p-4 align-middle">
98+
<div class="text-sm text-muted-foreground">
99+
{{ formatDate(team.created_at) }}
100+
</div>
101+
</td>
102+
103+
<!-- Switch Team -->
104+
<td class="p-4 align-middle">
105+
<div class="flex justify-start">
106+
<Button
107+
:variant="selectedTeamId === team.id ? 'default' : 'outline'"
108+
size="sm"
109+
class="h-8 px-3"
110+
:disabled="selectedTeamId === team.id"
111+
@click="() => {
112+
if (selectedTeamId !== team.id) {
113+
props.onSwitchTeam(team.id)
114+
}
115+
}"
116+
>
117+
<ArrowRightLeft class="h-4 w-4 mr-1" />
118+
{{ selectedTeamId === team.id ? t('teams.table.selected') : t('teams.table.switch') }}
119+
</Button>
120+
</div>
121+
</td>
122+
123+
<!-- Actions -->
124+
<td class="p-4 align-middle">
125+
<div class="flex justify-end">
126+
<Button
127+
v-if="canManageTeam(team)"
128+
variant="outline"
129+
size="sm"
130+
class="h-8 px-3"
131+
@click="() => props.onManageTeam(team.id)"
132+
>
133+
<Settings class="h-4 w-4 mr-1" />
134+
{{ t('teams.table.manage') }}
135+
</Button>
136+
<div
137+
v-else
138+
class="text-muted-foreground text-sm"
139+
>
140+
{{ t('teams.table.noActions') }}
141+
</div>
142+
</div>
143+
</td>
144+
</tr>
145+
</tbody>
146+
</table>
147+
</div>
148+
</template>

services/frontend/src/views/teams/columns.ts

Lines changed: 0 additions & 113 deletions
This file was deleted.

0 commit comments

Comments
 (0)