• 
      
    adminjs
    1
    // src/api/admin.js
    2
    // File này chứa các hàm API dùng cho quản trị viên (admin) để quản lý các bài đăng (listing)
    3
    4
    import axios from './axios.js'; // Import instance axios đã được cấu hình sẵn (baseURL, interceptor, v.v.)
    5
    6
    /**
    7
     * Lấy danh sách các bài đăng đang chờ duyệt
    8
     * params: gồm page, size, sortBy, sortDirection
    9
     */
    10
    export const getPendingListings = async (params = {}) => {
    11
        // Giải nén giá trị mặc định cho các tham số nếu người dùng không truyền vào
    12
        const {
    13
            page = 0,
    14
            size = 10,
    15
        } = params;
    16
    17
        try {
    18
            // Gửi request GET đến endpoint admin/post-request (API backend dùng để lấy danh sách cần duyệt)
    19
            const response = await axios.get('/admin/post-request', {
    20
                params: { page, size } // Truyền query parameters vào axios
    21
            });
    22
    23
            // Lấy dữ liệu từ response, nếu không có thì dùng object rỗng
    24
            const data = response.data || {};
    25
    26
            // Backend thường trả về object chứa các thuộc tính: content, totalElements, totalPages, size, number
    27
            const content = data.content || data.data || []; // danh sách item thực tế
    28
            const totalElements = data.totalElements ?? (data.length || 0); // tổng số phần tử
    29
            const totalPages = data.totalPages ?? 1; // tổng số trang
    30
            const pageSize = data.size ?? size; // kích thước trang hiện tại
    31
            const pageNumber = data.number ?? page; // trang hiện tại
    32
    33
            // Chuyển đổi từng item trong danh sách thành object chuẩn để hiển thị trên UI
    34
            const mapped = (Array.isArray(content) ? content : []).map(item => {
    35
                const id = item.requestId; // ID của yêu cầu duyệt
    36
                const listingId = item.listingId; // ID của bài đăng gốc
    37
                const title = item.title ?? '—'; // tiêu đề bài đăng
    38
                const price = typeof item.price === 'number'
    39
                    ? item.price
    40
                    : (item.price ? Number(item.price) : null); // chuyển giá sang số
    41
                const thumbnail = item.thumbnailUrl || null; // ảnh thumbnail
    42
                const status = item.status ; // trạng thái bài đăng
    43
                return { id, listingId, title, price, thumbnail, status, raw: item }; // trả về object chuẩn
    44
            });
    45
    46
            // Trả về dữ liệu đã được chuẩn hóa
    47
            return {
    48
                content: mapped,
    49
                totalElements,
    50
                totalPages,
    51
                size: pageSize,
    52
                number: pageNumber
    53
            };
    54
        } catch (error) {
    55
            // Nếu gọi API chính thất bại, log lỗi
    56
            console.error('Admin API failed:', error);
    57
    58
            try {
    59
                // Gọi dự phòng đến 2 endpoint lấy EV và battery listings
    60
                const [evResponse, batteryResponse] = await Promise.all([
    61
                    axios.get('/evCart', { params: { page, size } }),
    62
                    axios.get('/batteryCart', { params: { page, size } })
    63
                ]);
    64
    65
                // Lấy dữ liệu từ 2 response
    66
                const evListings = evResponse.data.content || evResponse.data || [];
    67
                const batteryListings = batteryResponse.data.content || batteryResponse.data || [];
    68
                const allListings = [...evListings, ...batteryListings]; // Gộp lại
    69
    70
                // Tạm thời hiển thị tất cả listing để debug
    71
                const filteredListings = allListings.filter(listing => true);
    72
    73
                // Chuyển đổi từng listing về dạng chuẩn để hiển thị
    74
                const mapped = filteredListings.map(item => ({
    75
                    id: item.listingId,
    76
                    title: item.title ?? '—',
    77
                    price: typeof item.price === 'number'
    78
                        ? item.price
    79
                        : (item.price ? Number(item.price) : null),
    80
                    thumbnail: item.thumbnailUrl || null,
    81
                    status: item.status,
    82
                    raw: item
    83
                }));
    84
    85
                // Trả về kết quả dự phòng
    86
                return {
    87
                    content: mapped,
    88
                    totalElements: mapped.length,
    89
                    totalPages: Math.ceil(mapped.length / size),
    90
                    size: size,
    91
                    number: page
    92
                };
    93
            } catch (fallbackError) {
    94
                console.error('Fallback API also failed:', fallbackError);
    95
                throw error; // Ném lỗi gốc ra ngoài
    96
            }
    97
        }
    98
    };
    99
    100
    // Approve (chấp thuận) một bài đăng
    101
    export const approveListing = async (listingId, approvalNote = '') => {
    102
        try {
    103
            // Gọi endpoint approve-request/{id} để phê duyệt bài đăng
    104
            const response = await axios.get(`/admin/approve-request/${listingId}`);
    105
            return response.data;
    106
        } catch (error) {
    107
            console.error('Error approving listing:', error);
    108
            throw error;
    109
        }
    110
    };
    111
    112
    // Reject (từ chối) một bài đăng
    113
    export const rejectListing = async (listingId, rejectionReason) => {
    114
        // Kiểm tra lý do từ chối có tồn tại hay không
    115
        if (!rejectionReason?.trim()) {
    116
            throw new Error('Rejection reason is required');
    117
        }
    118
    119
        try {
    120
            // Gọi endpoint reject-request/{id}?reason=...
    121
            const response = await axios.get(`/admin/reject-request/${listingId}`, {
    122
                params: { reason: rejectionReason }
    123
            });
    124
            return response.data;
    125
        } catch (error) {
    126
            console.error('Error rejecting listing:', error);
    127
            throw error;
    128
        }
    129
    };
    130
    131
    // Lấy chi tiết bài đăng (kể cả ở trạng thái PENDING)
    132
    export const getListingDetail = async (listingId) => {
    133
        try {
    134
            // Gọi endpoint admin riêng để xem chi tiết bài đăng
    135
            const response = await axios.get(`/admin/listing-detail/${listingId}`);
    136
            return response.data;
    137
        } catch (error) {
    138
            console.error('Error fetching listing detail:', error);
    139
            throw error;
    140
        }
    141
    };
    142
    143
    // Lấy thống kê tổng quan cho trang dashboard admin
    144
    export const getAdminStats = async () => {
    145
        try {
    146
            // Gọi endpoint thống kê
    147
            const response = await axios.get('/api/admin/stats');
    148
            return response.data;
    149
        } catch (error) {
    150
            console.error('Error fetching admin stats:', error);
    151
            throw error;
    152
        }
    153
    };
    154
    155
    // Lấy lịch sử xét duyệt (approve/reject)
    156
    export const getApprovalHistory = async (params = {}) => {
    157
        const {
    158
            page = 0,
    159
            size = 10,
    160
            status = null
    161
        } = params;
    162
    163
        try {
    164
            // Hiện chưa có endpoint riêng cho lịch sử, nên tạm dùng /admin/post-request
    165
            const response = await axios.get('/admin/post-request', {
    166
                params: { page, size }
    167
            });
    168
            return response.data;
    169
        } catch (error) {
    170
            console.error('Error fetching approval history:', error);
    171
            throw error;
    172
        }
    173
    };