#179-suspensions #188

Merged
Ajdj100 merged 13 commits from #179-suspensions into main 2026-02-12 08:32:04 -06:00
Showing only changes of commit cf880ed124 - Show all commits

View File

@@ -1,152 +1,157 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch } from "vue";
import { useRouter } from 'vue-router';
import {
Ellipsis, Search, Trash2, UserX,
X,
} from "lucide-vue-next";
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination'
import { ref, computed, onMounted, watch } from "vue";
import { useRouter } from 'vue-router';
import {
Ellipsis, Search, Trash2, UserX,
X,
} from "lucide-vue-next";
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination'
// API & Types
import { getMembersFiltered } from "@/api/member";
import { getUnits } from "@/api/units";
import type { Member } from "@shared/types/member";
import { MemberState } from "@shared/types/member";
import type { Unit } from "@shared/types/units";
import type { pagination as PaginationType } from "@shared/types/pagination";
// API & Types
import { getMembersFiltered } from "@/api/member";
import { getUnits } from "@/api/units";
import type { Member } from "@shared/types/member";
import { MemberState } from "@shared/types/member";
import type { Unit } from "@shared/types/units";
import type { pagination as PaginationType } from "@shared/types/pagination";
// UI Components
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Button } from "@/components/ui/button";
import Badge from "@/components/ui/badge/Badge.vue";
import Input from "@/components/ui/input/Input.vue";
import Spinner from "@/components/ui/spinner/Spinner.vue";
import DischargeMember from "@/components/members/DischargeMember.vue";
import MemberCard from "@/components/members/MemberCard.vue";
// UI Components
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Button } from "@/components/ui/button";
import Badge from "@/components/ui/badge/Badge.vue";
import Input from "@/components/ui/input/Input.vue";
import Spinner from "@/components/ui/spinner/Spinner.vue";
import DischargeMember from "@/components/members/DischargeMember.vue";
import MemberCard from "@/components/members/MemberCard.vue";
// --- State ---
const router = useRouter();
const members = ref<Member[]>([]);
const units = ref<Unit[]>([]);
const isLoaded = ref(false);
const pagination = ref<PaginationType>({
page: 1,
pageSize: 15,
total: 0,
totalPages: 0,
});
// --- State ---
const router = useRouter();
const members = ref<Member[]>([]);
const units = ref<Unit[]>([]);
const isLoaded = ref(false);
const pagination = ref<PaginationType>({
page: 1,
pageSize: 15,
total: 0,
totalPages: 0,
});
const filters = ref<{ search: string; status: "all" | MemberState; unitId: string }>({
search: "",
status: MemberState.Member,
unitId: "all"
});
// Pagination State
const pageNum = ref(1);
const pageSize = ref(15);
const pageSizeOptions = [10, 15, 30];
const MEMBER_STATUSES = Object.values(MemberState);
// --- Methods ---
const fetchMembers = async () => {
isLoaded.value = false;
try {
const result = await getMembersFiltered({
page: pageNum.value,
pageSize: pageSize.value,
search: filters.value.search || undefined,
status: filters.value.status,
unitId: filters.value.unitId,
});
members.value = result.data;
pagination.value = result.pagination;
} catch (error) {
console.error('Failed to fetch members:', error);
members.value = [];
} finally {
isLoaded.value = true;
}
};
const fetchUnits = async () => {
try {
units.value = await getUnits();
} catch (error) {
console.error('Failed to fetch units:', error);
}
};
const navigateToMember = (id: string | number) => router.push(`/member/${id}`);
const setPage = (num: number) => {
pageNum.value = num;
};
const setPageSize = (size: number) => {
pageSize.value = size;
pageNum.value = 1;
};
// --- Computed ---
const paginatedMembers = computed(() => members.value);
const totalItems = computed(() => pagination.value.total);
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
// Watch pagination (Immediate)
watch([pageNum, pageSize], () => {
if (debounceTimer) clearTimeout(debounceTimer);
fetchMembers();
});
// Watch filters (Debounced)
watch(filters, () => {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
fetchMembers();
}, 300);
}, { deep: true });
function clearFilters() {
filters.value = {
const filters = ref<{ search: string; status: "all" | MemberState; unitId: string }>({
search: "",
status: "all",
status: MemberState.Member,
unitId: "all"
});
// Pagination State
const pageNum = ref(1);
const pageSize = ref(15);
const pageSizeOptions = [10, 15, 30];
const MEMBER_STATUSES = Object.entries(MemberState)
.filter(([key, value]) => isNaN(Number(key)))
.map(([label, id]) => ({
label,
id: id as number // Casting back to number for your SQL logic
}));
// --- Methods ---
const fetchMembers = async () => {
isLoaded.value = false;
try {
const result = await getMembersFiltered({
page: pageNum.value,
pageSize: pageSize.value,
search: filters.value.search || undefined,
status: filters.value.status,
unitId: filters.value.unitId,
});
members.value = result.data;
pagination.value = result.pagination;
} catch (error) {
console.error('Failed to fetch members:', error);
members.value = [];
} finally {
isLoaded.value = true;
}
};
const fetchUnits = async () => {
try {
units.value = await getUnits();
} catch (error) {
console.error('Failed to fetch units:', error);
}
};
const navigateToMember = (id: string | number) => router.push(`/member/${id}`);
const setPage = (num: number) => {
pageNum.value = num;
};
const setPageSize = (size: number) => {
pageSize.value = size;
pageNum.value = 1;
};
// --- Computed ---
const paginatedMembers = computed(() => members.value);
const totalItems = computed(() => pagination.value.total);
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
// Watch pagination (Immediate)
watch([pageNum, pageSize], () => {
if (debounceTimer) clearTimeout(debounceTimer);
fetchMembers();
});
// Watch filters (Debounced)
watch(filters, () => {
if (debounceTimer) clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
fetchMembers();
}, 300);
}, { deep: true });
function clearFilters() {
filters.value = {
search: "",
status: "all",
unitId: "all"
}
}
}
onMounted(() => {
fetchUnits();
fetchMembers();
});
onMounted(() => {
fetchUnits();
fetchMembers();
});
//discharge form logic
const isDischargeOpen = ref(false)
const targetMember = ref(null)
//discharge form logic
const isDischargeOpen = ref(false)
const targetMember = ref(null)
function openDischargeModal(member: Member) {
targetMember.value = member
isDischargeOpen.value = true
}
function openDischargeModal(member: Member) {
targetMember.value = member
isDischargeOpen.value = true
}
function suspendMember(member: Member) {
function suspendMember(member: Member) {
}
}
function handleDischargeSuccess(data) {
fetchMembers();
}
function handleDischargeSuccess(data) {
fetchMembers();
}
</script>
<template>
@@ -171,8 +176,8 @@ function handleDischargeSuccess(data) {
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Statuses</SelectItem>
<SelectItem v-for="s in MEMBER_STATUSES" :key="s" :value="s">
<span class="capitalize">{{ s }}</span>
<SelectItem v-for="s in MEMBER_STATUSES" :key="s.id" :value="s.id">
<span class="capitalize">{{ s.label }}</span>
</SelectItem>
</SelectContent>
</Select>