Add quick deactivate member functionality and update routes and UI
Implemented a new quickDeactivateMember function in MemberService to handle member deactivation. Updated member routes to include a new endpoint for quick deactivation. Enhanced the MembersView component to support quick deactivation actions with updated UI elements, improving user experience for managing member statuses.
This commit is contained in:
@@ -124,6 +124,18 @@ const quickUpdateMemberFormHandedOver = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
const quickDeactivateMember = async (req, res) => {
|
||||
try {
|
||||
const { clubId, memberId } = req.params;
|
||||
const { authcode: userToken } = req.headers;
|
||||
const result = await MemberService.quickDeactivateMember(userToken, clubId, memberId);
|
||||
res.status(result.status).json(result.response);
|
||||
} catch (error) {
|
||||
console.error('[quickDeactivateMember] - Error:', error);
|
||||
res.status(500).json({ error: 'Failed to deactivate member' });
|
||||
}
|
||||
};
|
||||
|
||||
const transferMembers = async (req, res) => {
|
||||
try {
|
||||
const { id: clubId } = req.params;
|
||||
@@ -156,4 +168,4 @@ const transferMembers = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage, transferMembers, quickUpdateTestMembership, quickUpdateMemberFormHandedOver };
|
||||
export { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage, transferMembers, quickUpdateTestMembership, quickUpdateMemberFormHandedOver, quickDeactivateMember };
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage, transferMembers, quickUpdateTestMembership, quickUpdateMemberFormHandedOver } from '../controllers/memberController.js';
|
||||
import { getClubMembers, getWaitingApprovals, setClubMembers, uploadMemberImage, getMemberImage, updateRatingsFromMyTischtennis, rotateMemberImage, transferMembers, quickUpdateTestMembership, quickUpdateMemberFormHandedOver, quickDeactivateMember } from '../controllers/memberController.js';
|
||||
import express from 'express';
|
||||
import { authenticate } from '../middleware/authMiddleware.js';
|
||||
import { authorize } from '../middleware/authorizationMiddleware.js';
|
||||
@@ -19,5 +19,6 @@ router.post('/rotate-image/:clubId/:memberId', authenticate, authorize('members'
|
||||
router.post('/transfer/:id', authenticate, authorize('members', 'write'), transferMembers);
|
||||
router.post('/quick-update-test-membership/:clubId/:memberId', authenticate, authorize('members', 'write'), quickUpdateTestMembership);
|
||||
router.post('/quick-update-member-form/:clubId/:memberId', authenticate, authorize('members', 'write'), quickUpdateMemberFormHandedOver);
|
||||
router.post('/quick-deactivate/:clubId/:memberId', authenticate, authorize('members', 'write'), quickDeactivateMember);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -544,6 +544,31 @@ class MemberService {
|
||||
return { status: 500, response: { error: 'Failed to update member form status' } };
|
||||
}
|
||||
}
|
||||
|
||||
async quickDeactivateMember(userToken, clubId, memberId) {
|
||||
try {
|
||||
await checkAccess(userToken, clubId);
|
||||
const member = await Member.findOne({ where: { id: memberId, clubId: clubId } });
|
||||
if (!member) {
|
||||
return { status: 404, response: { error: 'Member not found in this club' } };
|
||||
}
|
||||
|
||||
if (!member.active) {
|
||||
return { status: 400, response: { error: 'Member is already inactive' } };
|
||||
}
|
||||
|
||||
member.active = false;
|
||||
await member.save();
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
response: { success: true, message: 'Mitglied deaktiviert' }
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[quickDeactivateMember] - Error:', error);
|
||||
return { status: 500, response: { error: 'Failed to deactivate member' } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new MemberService();
|
||||
@@ -161,15 +161,22 @@
|
||||
<span v-else>-</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons-row">
|
||||
<button v-if="member.testMembership" @click.stop="quickRemoveTestMembership(member)" class="btn-quick-action" title="Keine Testmitgliedschaft mehr">
|
||||
Keine Testmitgliedschaft
|
||||
</button>
|
||||
<button v-if="!member.memberFormHandedOver" @click.stop="quickMarkFormHandedOver(member)" class="btn-quick-action" title="Mitgliedsformular ausgehändigt">
|
||||
Formular ausgehändigt
|
||||
</button>
|
||||
<button @click.stop="openNotesModal(member)">Notizen</button>
|
||||
<button @click.stop="openActivitiesModal(member)" class="btn-activities">Übungen</button>
|
||||
<div class="action-icons-row">
|
||||
<span v-if="member.testMembership" @click.stop="quickRemoveTestMembership(member)" class="action-icon" title="Keine Testmitgliedschaft mehr">
|
||||
✅
|
||||
</span>
|
||||
<span v-if="member.testMembership && !member.memberFormHandedOver" @click.stop="quickMarkFormHandedOver(member)" class="action-icon" title="Mitgliedsformular ausgehändigt">
|
||||
📄
|
||||
</span>
|
||||
<span v-if="member.active" @click.stop="quickDeactivateMember(member)" class="action-icon action-icon-deactivate" title="Mitglied deaktivieren">
|
||||
⛔
|
||||
</span>
|
||||
<span @click.stop="openNotesModal(member)" class="action-icon" title="Notizen">
|
||||
📝
|
||||
</span>
|
||||
<span @click.stop="openActivitiesModal(member)" class="action-icon" title="Übungen">
|
||||
🏃
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -496,6 +503,26 @@ export default {
|
||||
this.showInfo('Fehler', errorMessage, '', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async quickDeactivateMember(member) {
|
||||
if (!confirm(`Möchten Sie "${member.firstName} ${member.lastName}" wirklich deaktivieren?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiClient.post(`/clubmembers/quick-deactivate/${this.currentClub}/${member.id}`);
|
||||
if (response.data.success) {
|
||||
member.active = false;
|
||||
this.showInfo('Erfolg', response.data.message || 'Mitglied deaktiviert', '', 'success');
|
||||
} else {
|
||||
this.showInfo('Fehler', response.data.error || 'Fehler beim Deaktivieren des Mitglieds', '', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Deaktivieren des Mitglieds:', error);
|
||||
const errorMessage = error.response?.data?.error || error.message || 'Fehler beim Deaktivieren des Mitglieds';
|
||||
this.showInfo('Fehler', errorMessage, '', 'error');
|
||||
}
|
||||
},
|
||||
toggleNewMember() {
|
||||
this.memberFormIsOpen = !this.memberFormIsOpen;
|
||||
},
|
||||
@@ -1272,28 +1299,32 @@ table td {
|
||||
background-color: #138496;
|
||||
}
|
||||
|
||||
.action-buttons-row {
|
||||
.action-icons-row {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-quick-action {
|
||||
background-color: #ffc107;
|
||||
color: #000;
|
||||
border: none;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 4px;
|
||||
.action-icon {
|
||||
font-size: 1.2em;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s ease;
|
||||
white-space: nowrap;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.btn-quick-action:hover {
|
||||
background-color: #e0a800;
|
||||
.action-icon:hover {
|
||||
transform: scale(1.2);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-icon-deactivate {
|
||||
filter: grayscale(0.3);
|
||||
}
|
||||
|
||||
.action-icon-deactivate:hover {
|
||||
filter: grayscale(0);
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
|
||||
Reference in New Issue
Block a user