Integrate Wedding Guest List with real API and improve UX
🔗 API Integration: - Add weddingGuestService.js with full CRUD operations - Connect to /api/WeddingGuests endpoint using REACT_APP_API_BASE_URL - Implement proper error handling and fallback mechanisms - Add detailed debug logging for troubleshooting 🎯 Features Added: - Real-time API calls for guests, statistics, and units - Automatic fallback to mock data if API fails - Export Excel functionality - Delete confirmation with API integration - Search and filter with API parameters 🎨 UX Improvements: - Default 'Tất cả trạng thái' and 'Tất cả đơn vị' options - Beautiful icons for filter options (📋 🏢 ✅ ❌ ⏳) - User-friendly error messages and warnings - Loading states with spinners - Success/error notifications 🔧 Technical Enhancements: - Axios client with interceptors for auth and error handling - Proper pagination handling - Status mapping between API and UI - Environment variable configuration - Mock data structure matching API format 🚀 Production Ready: - Complete API integration with backend - Fallback mechanisms for reliability - Professional error handling - Responsive design maintained
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_BASE_URL = process.env.REACT_APP_API_BASE_URL;
|
||||
|
||||
// Create axios instance with base configuration
|
||||
const apiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Add request interceptor for authentication if needed
|
||||
apiClient.interceptors.request.use(
|
||||
(config) => {
|
||||
// Add auth token if available
|
||||
const token = localStorage.getItem('authToken');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Add response interceptor for error handling
|
||||
apiClient.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
console.error('API Error:', error);
|
||||
|
||||
// Handle common errors
|
||||
if (error.response?.status === 401) {
|
||||
// Unauthorized - redirect to login
|
||||
localStorage.removeItem('authToken');
|
||||
window.location.href = '/signin';
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Wedding Guest API Service
|
||||
export const weddingGuestService = {
|
||||
// Get all wedding guests with pagination and filters
|
||||
async getWeddingGuests(params = {}) {
|
||||
try {
|
||||
console.log('🔍 API Call - Wedding Guests:', {
|
||||
baseURL: API_BASE_URL,
|
||||
endpoint: '/WeddingGuests',
|
||||
params: params
|
||||
});
|
||||
|
||||
const response = await apiClient.get('/WeddingGuests', { params });
|
||||
|
||||
console.log('✅ API Response - Wedding Guests:', {
|
||||
status: response.status,
|
||||
data: response.data
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Success'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('❌ Error fetching wedding guests:', {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
data: error.response?.data,
|
||||
config: {
|
||||
url: error.config?.url,
|
||||
method: error.config?.method,
|
||||
baseURL: error.config?.baseURL
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to fetch wedding guests'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Get wedding guest by ID
|
||||
async getWeddingGuestById(id) {
|
||||
try {
|
||||
const response = await apiClient.get(`/WeddingGuests/${id}`);
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Success'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching wedding guest:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to fetch wedding guest'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Create new wedding guest
|
||||
async createWeddingGuest(guestData) {
|
||||
try {
|
||||
const response = await apiClient.post('/WeddingGuests', guestData);
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Wedding guest created successfully'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error creating wedding guest:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to create wedding guest'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Update wedding guest
|
||||
async updateWeddingGuest(id, guestData) {
|
||||
try {
|
||||
const response = await apiClient.put(`/WeddingGuests/${id}`, guestData);
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Wedding guest updated successfully'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error updating wedding guest:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to update wedding guest'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Delete wedding guest
|
||||
async deleteWeddingGuest(id) {
|
||||
try {
|
||||
const response = await apiClient.delete(`/WeddingGuests/${id}`);
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Wedding guest deleted successfully'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error deleting wedding guest:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to delete wedding guest'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Update wedding guest status only
|
||||
async updateWeddingGuestStatus(id, status) {
|
||||
try {
|
||||
const response = await apiClient.put(`/WeddingGuests/${id}/status`, { status });
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Status updated successfully'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error updating guest status:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to update status'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Get wedding guest statistics
|
||||
async getWeddingGuestStatistics() {
|
||||
try {
|
||||
const response = await apiClient.get('/WeddingGuests/statistics');
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Success'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching statistics:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to fetch statistics'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Get available units for filter dropdown
|
||||
async getUnits() {
|
||||
try {
|
||||
const response = await apiClient.get('/WeddingGuests/units');
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data || response.data,
|
||||
message: response.data.message || 'Success'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching units:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: [],
|
||||
message: error.response?.data?.message || error.message || 'Failed to fetch units'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Export wedding guest list
|
||||
async exportWeddingGuests(format = 'excel') {
|
||||
try {
|
||||
const response = await apiClient.get('/WeddingGuests/export', {
|
||||
params: { format },
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
// Create download link
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', `wedding-guests.${format === 'excel' ? 'xlsx' : 'csv'}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: null,
|
||||
message: 'Export completed successfully'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error exporting wedding guests:', error);
|
||||
return {
|
||||
success: false,
|
||||
data: null,
|
||||
message: error.response?.data?.message || error.message || 'Failed to export wedding guests'
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default weddingGuestService;
|
||||
Reference in New Issue
Block a user