feat(holiday-system): add holiday population functionality and API integration
- Implemented a new API endpoint to populate country holidays in the database. - Enhanced the HolidayController to handle holiday population logic for multiple countries. - Updated the holiday API router to include the new populate endpoint. - Added a service method in the frontend to trigger holiday population. - Integrated a button in the admin center overview for easy access to populate holidays. - Improved error handling and user feedback during the holiday population process.
This commit is contained in:
@@ -1,211 +1,211 @@
|
|||||||
const Holidays = require('date-holidays');
|
const Holidays = require("date-holidays");
|
||||||
const { Pool } = require('pg');
|
const { Pool } = require("pg");
|
||||||
const config = require('../src/config/db-config');
|
const config = require("../build/config/db-config").default;
|
||||||
|
|
||||||
// Database connection
|
// Database connection
|
||||||
const pool = new Pool(config);
|
const pool = new Pool(config);
|
||||||
|
|
||||||
// Countries to populate with holidays
|
// Countries to populate with holidays
|
||||||
const countries = [
|
const countries = [
|
||||||
{ code: 'US', name: 'United States' },
|
{ code: "US", name: "United States" },
|
||||||
{ code: 'GB', name: 'United Kingdom' },
|
{ code: "GB", name: "United Kingdom" },
|
||||||
{ code: 'CA', name: 'Canada' },
|
{ code: "CA", name: "Canada" },
|
||||||
{ code: 'AU', name: 'Australia' },
|
{ code: "AU", name: "Australia" },
|
||||||
{ code: 'DE', name: 'Germany' },
|
{ code: "DE", name: "Germany" },
|
||||||
{ code: 'FR', name: 'France' },
|
{ code: "FR", name: "France" },
|
||||||
{ code: 'IT', name: 'Italy' },
|
{ code: "IT", name: "Italy" },
|
||||||
{ code: 'ES', name: 'Spain' },
|
{ code: "ES", name: "Spain" },
|
||||||
{ code: 'NL', name: 'Netherlands' },
|
{ code: "NL", name: "Netherlands" },
|
||||||
{ code: 'BE', name: 'Belgium' },
|
{ code: "BE", name: "Belgium" },
|
||||||
{ code: 'CH', name: 'Switzerland' },
|
{ code: "CH", name: "Switzerland" },
|
||||||
{ code: 'AT', name: 'Austria' },
|
{ code: "AT", name: "Austria" },
|
||||||
{ code: 'SE', name: 'Sweden' },
|
{ code: "SE", name: "Sweden" },
|
||||||
{ code: 'NO', name: 'Norway' },
|
{ code: "NO", name: "Norway" },
|
||||||
{ code: 'DK', name: 'Denmark' },
|
{ code: "DK", name: "Denmark" },
|
||||||
{ code: 'FI', name: 'Finland' },
|
{ code: "FI", name: "Finland" },
|
||||||
{ code: 'PL', name: 'Poland' },
|
{ code: "PL", name: "Poland" },
|
||||||
{ code: 'CZ', name: 'Czech Republic' },
|
{ code: "CZ", name: "Czech Republic" },
|
||||||
{ code: 'HU', name: 'Hungary' },
|
{ code: "HU", name: "Hungary" },
|
||||||
{ code: 'RO', name: 'Romania' },
|
{ code: "RO", name: "Romania" },
|
||||||
{ code: 'BG', name: 'Bulgaria' },
|
{ code: "BG", name: "Bulgaria" },
|
||||||
{ code: 'HR', name: 'Croatia' },
|
{ code: "HR", name: "Croatia" },
|
||||||
{ code: 'SI', name: 'Slovenia' },
|
{ code: "SI", name: "Slovenia" },
|
||||||
{ code: 'SK', name: 'Slovakia' },
|
{ code: "SK", name: "Slovakia" },
|
||||||
{ code: 'LT', name: 'Lithuania' },
|
{ code: "LT", name: "Lithuania" },
|
||||||
{ code: 'LV', name: 'Latvia' },
|
{ code: "LV", name: "Latvia" },
|
||||||
{ code: 'EE', name: 'Estonia' },
|
{ code: "EE", name: "Estonia" },
|
||||||
{ code: 'IE', name: 'Ireland' },
|
{ code: "IE", name: "Ireland" },
|
||||||
{ code: 'PT', name: 'Portugal' },
|
{ code: "PT", name: "Portugal" },
|
||||||
{ code: 'GR', name: 'Greece' },
|
{ code: "GR", name: "Greece" },
|
||||||
{ code: 'CY', name: 'Cyprus' },
|
{ code: "CY", name: "Cyprus" },
|
||||||
{ code: 'MT', name: 'Malta' },
|
{ code: "MT", name: "Malta" },
|
||||||
{ code: 'LU', name: 'Luxembourg' },
|
{ code: "LU", name: "Luxembourg" },
|
||||||
{ code: 'IS', name: 'Iceland' },
|
{ code: "IS", name: "Iceland" },
|
||||||
{ code: 'CN', name: 'China' },
|
{ code: "CN", name: "China" },
|
||||||
{ code: 'JP', name: 'Japan' },
|
{ code: "JP", name: "Japan" },
|
||||||
{ code: 'KR', name: 'South Korea' },
|
{ code: "KR", name: "South Korea" },
|
||||||
{ code: 'IN', name: 'India' },
|
{ code: "IN", name: "India" },
|
||||||
{ code: 'PK', name: 'Pakistan' },
|
{ code: "PK", name: "Pakistan" },
|
||||||
{ code: 'BD', name: 'Bangladesh' },
|
{ code: "BD", name: "Bangladesh" },
|
||||||
{ code: 'LK', name: 'Sri Lanka' },
|
{ code: "LK", name: "Sri Lanka" },
|
||||||
{ code: 'NP', name: 'Nepal' },
|
{ code: "NP", name: "Nepal" },
|
||||||
{ code: 'TH', name: 'Thailand' },
|
{ code: "TH", name: "Thailand" },
|
||||||
{ code: 'VN', name: 'Vietnam' },
|
{ code: "VN", name: "Vietnam" },
|
||||||
{ code: 'MY', name: 'Malaysia' },
|
{ code: "MY", name: "Malaysia" },
|
||||||
{ code: 'SG', name: 'Singapore' },
|
{ code: "SG", name: "Singapore" },
|
||||||
{ code: 'ID', name: 'Indonesia' },
|
{ code: "ID", name: "Indonesia" },
|
||||||
{ code: 'PH', name: 'Philippines' },
|
{ code: "PH", name: "Philippines" },
|
||||||
{ code: 'MM', name: 'Myanmar' },
|
{ code: "MM", name: "Myanmar" },
|
||||||
{ code: 'KH', name: 'Cambodia' },
|
{ code: "KH", name: "Cambodia" },
|
||||||
{ code: 'LA', name: 'Laos' },
|
{ code: "LA", name: "Laos" },
|
||||||
{ code: 'BN', name: 'Brunei' },
|
{ code: "BN", name: "Brunei" },
|
||||||
{ code: 'TL', name: 'Timor-Leste' },
|
{ code: "TL", name: "Timor-Leste" },
|
||||||
{ code: 'MN', name: 'Mongolia' },
|
{ code: "MN", name: "Mongolia" },
|
||||||
{ code: 'KZ', name: 'Kazakhstan' },
|
{ code: "KZ", name: "Kazakhstan" },
|
||||||
{ code: 'UZ', name: 'Uzbekistan' },
|
{ code: "UZ", name: "Uzbekistan" },
|
||||||
{ code: 'KG', name: 'Kyrgyzstan' },
|
{ code: "KG", name: "Kyrgyzstan" },
|
||||||
{ code: 'TJ', name: 'Tajikistan' },
|
{ code: "TJ", name: "Tajikistan" },
|
||||||
{ code: 'TM', name: 'Turkmenistan' },
|
{ code: "TM", name: "Turkmenistan" },
|
||||||
{ code: 'AF', name: 'Afghanistan' },
|
{ code: "AF", name: "Afghanistan" },
|
||||||
{ code: 'IR', name: 'Iran' },
|
{ code: "IR", name: "Iran" },
|
||||||
{ code: 'IQ', name: 'Iraq' },
|
{ code: "IQ", name: "Iraq" },
|
||||||
{ code: 'SA', name: 'Saudi Arabia' },
|
{ code: "SA", name: "Saudi Arabia" },
|
||||||
{ code: 'AE', name: 'United Arab Emirates' },
|
{ code: "AE", name: "United Arab Emirates" },
|
||||||
{ code: 'QA', name: 'Qatar' },
|
{ code: "QA", name: "Qatar" },
|
||||||
{ code: 'KW', name: 'Kuwait' },
|
{ code: "KW", name: "Kuwait" },
|
||||||
{ code: 'BH', name: 'Bahrain' },
|
{ code: "BH", name: "Bahrain" },
|
||||||
{ code: 'OM', name: 'Oman' },
|
{ code: "OM", name: "Oman" },
|
||||||
{ code: 'YE', name: 'Yemen' },
|
{ code: "YE", name: "Yemen" },
|
||||||
{ code: 'JO', name: 'Jordan' },
|
{ code: "JO", name: "Jordan" },
|
||||||
{ code: 'LB', name: 'Lebanon' },
|
{ code: "LB", name: "Lebanon" },
|
||||||
{ code: 'SY', name: 'Syria' },
|
{ code: "SY", name: "Syria" },
|
||||||
{ code: 'IL', name: 'Israel' },
|
{ code: "IL", name: "Israel" },
|
||||||
{ code: 'PS', name: 'Palestine' },
|
{ code: "PS", name: "Palestine" },
|
||||||
{ code: 'TR', name: 'Turkey' },
|
{ code: "TR", name: "Turkey" },
|
||||||
{ code: 'GE', name: 'Georgia' },
|
{ code: "GE", name: "Georgia" },
|
||||||
{ code: 'AM', name: 'Armenia' },
|
{ code: "AM", name: "Armenia" },
|
||||||
{ code: 'AZ', name: 'Azerbaijan' },
|
{ code: "AZ", name: "Azerbaijan" },
|
||||||
{ code: 'NZ', name: 'New Zealand' },
|
{ code: "NZ", name: "New Zealand" },
|
||||||
{ code: 'FJ', name: 'Fiji' },
|
{ code: "FJ", name: "Fiji" },
|
||||||
{ code: 'PG', name: 'Papua New Guinea' },
|
{ code: "PG", name: "Papua New Guinea" },
|
||||||
{ code: 'SB', name: 'Solomon Islands' },
|
{ code: "SB", name: "Solomon Islands" },
|
||||||
{ code: 'VU', name: 'Vanuatu' },
|
{ code: "VU", name: "Vanuatu" },
|
||||||
{ code: 'NC', name: 'New Caledonia' },
|
{ code: "NC", name: "New Caledonia" },
|
||||||
{ code: 'PF', name: 'French Polynesia' },
|
{ code: "PF", name: "French Polynesia" },
|
||||||
{ code: 'TO', name: 'Tonga' },
|
{ code: "TO", name: "Tonga" },
|
||||||
{ code: 'WS', name: 'Samoa' },
|
{ code: "WS", name: "Samoa" },
|
||||||
{ code: 'KI', name: 'Kiribati' },
|
{ code: "KI", name: "Kiribati" },
|
||||||
{ code: 'TV', name: 'Tuvalu' },
|
{ code: "TV", name: "Tuvalu" },
|
||||||
{ code: 'NR', name: 'Nauru' },
|
{ code: "NR", name: "Nauru" },
|
||||||
{ code: 'PW', name: 'Palau' },
|
{ code: "PW", name: "Palau" },
|
||||||
{ code: 'MH', name: 'Marshall Islands' },
|
{ code: "MH", name: "Marshall Islands" },
|
||||||
{ code: 'FM', name: 'Micronesia' },
|
{ code: "FM", name: "Micronesia" },
|
||||||
{ code: 'ZA', name: 'South Africa' },
|
{ code: "ZA", name: "South Africa" },
|
||||||
{ code: 'EG', name: 'Egypt' },
|
{ code: "EG", name: "Egypt" },
|
||||||
{ code: 'NG', name: 'Nigeria' },
|
{ code: "NG", name: "Nigeria" },
|
||||||
{ code: 'KE', name: 'Kenya' },
|
{ code: "KE", name: "Kenya" },
|
||||||
{ code: 'ET', name: 'Ethiopia' },
|
{ code: "ET", name: "Ethiopia" },
|
||||||
{ code: 'TZ', name: 'Tanzania' },
|
{ code: "TZ", name: "Tanzania" },
|
||||||
{ code: 'UG', name: 'Uganda' },
|
{ code: "UG", name: "Uganda" },
|
||||||
{ code: 'GH', name: 'Ghana' },
|
{ code: "GH", name: "Ghana" },
|
||||||
{ code: 'CI', name: 'Ivory Coast' },
|
{ code: "CI", name: "Ivory Coast" },
|
||||||
{ code: 'SN', name: 'Senegal' },
|
{ code: "SN", name: "Senegal" },
|
||||||
{ code: 'ML', name: 'Mali' },
|
{ code: "ML", name: "Mali" },
|
||||||
{ code: 'BF', name: 'Burkina Faso' },
|
{ code: "BF", name: "Burkina Faso" },
|
||||||
{ code: 'NE', name: 'Niger' },
|
{ code: "NE", name: "Niger" },
|
||||||
{ code: 'TD', name: 'Chad' },
|
{ code: "TD", name: "Chad" },
|
||||||
{ code: 'CM', name: 'Cameroon' },
|
{ code: "CM", name: "Cameroon" },
|
||||||
{ code: 'CF', name: 'Central African Republic' },
|
{ code: "CF", name: "Central African Republic" },
|
||||||
{ code: 'CG', name: 'Republic of the Congo' },
|
{ code: "CG", name: "Republic of the Congo" },
|
||||||
{ code: 'CD', name: 'Democratic Republic of the Congo' },
|
{ code: "CD", name: "Democratic Republic of the Congo" },
|
||||||
{ code: 'GA', name: 'Gabon' },
|
{ code: "GA", name: "Gabon" },
|
||||||
{ code: 'GQ', name: 'Equatorial Guinea' },
|
{ code: "GQ", name: "Equatorial Guinea" },
|
||||||
{ code: 'ST', name: 'São Tomé and Príncipe' },
|
{ code: "ST", name: "São Tomé and Príncipe" },
|
||||||
{ code: 'AO', name: 'Angola' },
|
{ code: "AO", name: "Angola" },
|
||||||
{ code: 'ZM', name: 'Zambia' },
|
{ code: "ZM", name: "Zambia" },
|
||||||
{ code: 'ZW', name: 'Zimbabwe' },
|
{ code: "ZW", name: "Zimbabwe" },
|
||||||
{ code: 'BW', name: 'Botswana' },
|
{ code: "BW", name: "Botswana" },
|
||||||
{ code: 'NA', name: 'Namibia' },
|
{ code: "NA", name: "Namibia" },
|
||||||
{ code: 'LS', name: 'Lesotho' },
|
{ code: "LS", name: "Lesotho" },
|
||||||
{ code: 'SZ', name: 'Eswatini' },
|
{ code: "SZ", name: "Eswatini" },
|
||||||
{ code: 'MG', name: 'Madagascar' },
|
{ code: "MG", name: "Madagascar" },
|
||||||
{ code: 'MU', name: 'Mauritius' },
|
{ code: "MU", name: "Mauritius" },
|
||||||
{ code: 'SC', name: 'Seychelles' },
|
{ code: "SC", name: "Seychelles" },
|
||||||
{ code: 'KM', name: 'Comoros' },
|
{ code: "KM", name: "Comoros" },
|
||||||
{ code: 'DJ', name: 'Djibouti' },
|
{ code: "DJ", name: "Djibouti" },
|
||||||
{ code: 'SO', name: 'Somalia' },
|
{ code: "SO", name: "Somalia" },
|
||||||
{ code: 'ER', name: 'Eritrea' },
|
{ code: "ER", name: "Eritrea" },
|
||||||
{ code: 'SD', name: 'Sudan' },
|
{ code: "SD", name: "Sudan" },
|
||||||
{ code: 'SS', name: 'South Sudan' },
|
{ code: "SS", name: "South Sudan" },
|
||||||
{ code: 'LY', name: 'Libya' },
|
{ code: "LY", name: "Libya" },
|
||||||
{ code: 'TN', name: 'Tunisia' },
|
{ code: "TN", name: "Tunisia" },
|
||||||
{ code: 'DZ', name: 'Algeria' },
|
{ code: "DZ", name: "Algeria" },
|
||||||
{ code: 'MA', name: 'Morocco' },
|
{ code: "MA", name: "Morocco" },
|
||||||
{ code: 'EH', name: 'Western Sahara' },
|
{ code: "EH", name: "Western Sahara" },
|
||||||
{ code: 'MR', name: 'Mauritania' },
|
{ code: "MR", name: "Mauritania" },
|
||||||
{ code: 'GM', name: 'Gambia' },
|
{ code: "GM", name: "Gambia" },
|
||||||
{ code: 'GW', name: 'Guinea-Bissau' },
|
{ code: "GW", name: "Guinea-Bissau" },
|
||||||
{ code: 'GN', name: 'Guinea' },
|
{ code: "GN", name: "Guinea" },
|
||||||
{ code: 'SL', name: 'Sierra Leone' },
|
{ code: "SL", name: "Sierra Leone" },
|
||||||
{ code: 'LR', name: 'Liberia' },
|
{ code: "LR", name: "Liberia" },
|
||||||
{ code: 'TG', name: 'Togo' },
|
{ code: "TG", name: "Togo" },
|
||||||
{ code: 'BJ', name: 'Benin' },
|
{ code: "BJ", name: "Benin" },
|
||||||
{ code: 'BR', name: 'Brazil' },
|
{ code: "BR", name: "Brazil" },
|
||||||
{ code: 'AR', name: 'Argentina' },
|
{ code: "AR", name: "Argentina" },
|
||||||
{ code: 'CL', name: 'Chile' },
|
{ code: "CL", name: "Chile" },
|
||||||
{ code: 'CO', name: 'Colombia' },
|
{ code: "CO", name: "Colombia" },
|
||||||
{ code: 'PE', name: 'Peru' },
|
{ code: "PE", name: "Peru" },
|
||||||
{ code: 'VE', name: 'Venezuela' },
|
{ code: "VE", name: "Venezuela" },
|
||||||
{ code: 'EC', name: 'Ecuador' },
|
{ code: "EC", name: "Ecuador" },
|
||||||
{ code: 'BO', name: 'Bolivia' },
|
{ code: "BO", name: "Bolivia" },
|
||||||
{ code: 'PY', name: 'Paraguay' },
|
{ code: "PY", name: "Paraguay" },
|
||||||
{ code: 'UY', name: 'Uruguay' },
|
{ code: "UY", name: "Uruguay" },
|
||||||
{ code: 'GY', name: 'Guyana' },
|
{ code: "GY", name: "Guyana" },
|
||||||
{ code: 'SR', name: 'Suriname' },
|
{ code: "SR", name: "Suriname" },
|
||||||
{ code: 'FK', name: 'Falkland Islands' },
|
{ code: "FK", name: "Falkland Islands" },
|
||||||
{ code: 'GF', name: 'French Guiana' },
|
{ code: "GF", name: "French Guiana" },
|
||||||
{ code: 'MX', name: 'Mexico' },
|
{ code: "MX", name: "Mexico" },
|
||||||
{ code: 'GT', name: 'Guatemala' },
|
{ code: "GT", name: "Guatemala" },
|
||||||
{ code: 'BZ', name: 'Belize' },
|
{ code: "BZ", name: "Belize" },
|
||||||
{ code: 'SV', name: 'El Salvador' },
|
{ code: "SV", name: "El Salvador" },
|
||||||
{ code: 'HN', name: 'Honduras' },
|
{ code: "HN", name: "Honduras" },
|
||||||
{ code: 'NI', name: 'Nicaragua' },
|
{ code: "NI", name: "Nicaragua" },
|
||||||
{ code: 'CR', name: 'Costa Rica' },
|
{ code: "CR", name: "Costa Rica" },
|
||||||
{ code: 'PA', name: 'Panama' },
|
{ code: "PA", name: "Panama" },
|
||||||
{ code: 'CU', name: 'Cuba' },
|
{ code: "CU", name: "Cuba" },
|
||||||
{ code: 'JM', name: 'Jamaica' },
|
{ code: "JM", name: "Jamaica" },
|
||||||
{ code: 'HT', name: 'Haiti' },
|
{ code: "HT", name: "Haiti" },
|
||||||
{ code: 'DO', name: 'Dominican Republic' },
|
{ code: "DO", name: "Dominican Republic" },
|
||||||
{ code: 'PR', name: 'Puerto Rico' },
|
{ code: "PR", name: "Puerto Rico" },
|
||||||
{ code: 'TT', name: 'Trinidad and Tobago' },
|
{ code: "TT", name: "Trinidad and Tobago" },
|
||||||
{ code: 'BB', name: 'Barbados' },
|
{ code: "BB", name: "Barbados" },
|
||||||
{ code: 'GD', name: 'Grenada' },
|
{ code: "GD", name: "Grenada" },
|
||||||
{ code: 'LC', name: 'Saint Lucia' },
|
{ code: "LC", name: "Saint Lucia" },
|
||||||
{ code: 'VC', name: 'Saint Vincent and the Grenadines' },
|
{ code: "VC", name: "Saint Vincent and the Grenadines" },
|
||||||
{ code: 'AG', name: 'Antigua and Barbuda' },
|
{ code: "AG", name: "Antigua and Barbuda" },
|
||||||
{ code: 'KN', name: 'Saint Kitts and Nevis' },
|
{ code: "KN", name: "Saint Kitts and Nevis" },
|
||||||
{ code: 'DM', name: 'Dominica' },
|
{ code: "DM", name: "Dominica" },
|
||||||
{ code: 'BS', name: 'Bahamas' },
|
{ code: "BS", name: "Bahamas" },
|
||||||
{ code: 'TC', name: 'Turks and Caicos Islands' },
|
{ code: "TC", name: "Turks and Caicos Islands" },
|
||||||
{ code: 'KY', name: 'Cayman Islands' },
|
{ code: "KY", name: "Cayman Islands" },
|
||||||
{ code: 'BM', name: 'Bermuda' },
|
{ code: "BM", name: "Bermuda" },
|
||||||
{ code: 'AI', name: 'Anguilla' },
|
{ code: "AI", name: "Anguilla" },
|
||||||
{ code: 'VG', name: 'British Virgin Islands' },
|
{ code: "VG", name: "British Virgin Islands" },
|
||||||
{ code: 'VI', name: 'U.S. Virgin Islands' },
|
{ code: "VI", name: "U.S. Virgin Islands" },
|
||||||
{ code: 'AW', name: 'Aruba' },
|
{ code: "AW", name: "Aruba" },
|
||||||
{ code: 'CW', name: 'Curaçao' },
|
{ code: "CW", name: "Curaçao" },
|
||||||
{ code: 'SX', name: 'Sint Maarten' },
|
{ code: "SX", name: "Sint Maarten" },
|
||||||
{ code: 'MF', name: 'Saint Martin' },
|
{ code: "MF", name: "Saint Martin" },
|
||||||
{ code: 'BL', name: 'Saint Barthélemy' },
|
{ code: "BL", name: "Saint Barthélemy" },
|
||||||
{ code: 'GP', name: 'Guadeloupe' },
|
{ code: "GP", name: "Guadeloupe" },
|
||||||
{ code: 'MQ', name: 'Martinique' }
|
{ code: "MQ", name: "Martinique" }
|
||||||
];
|
];
|
||||||
|
|
||||||
async function populateHolidays() {
|
async function populateHolidays() {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Starting holiday population...');
|
console.log("Starting holiday population...");
|
||||||
|
|
||||||
for (const country of countries) {
|
for (const country of countries) {
|
||||||
console.log(`Processing ${country.name} (${country.code})...`);
|
console.log(`Processing ${country.name} (${country.code})...`);
|
||||||
@@ -219,13 +219,13 @@ async function populateHolidays() {
|
|||||||
|
|
||||||
for (const holiday of holidays) {
|
for (const holiday of holidays) {
|
||||||
// Skip if holiday is not a date object
|
// Skip if holiday is not a date object
|
||||||
if (!holiday.date || typeof holiday.date !== 'object') {
|
if (!holiday.date || typeof holiday.date !== "object") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dateStr = holiday.date.toISOString().split('T')[0];
|
const dateStr = holiday.date.toISOString().split("T")[0];
|
||||||
const name = holiday.name || 'Unknown Holiday';
|
const name = holiday.name || "Unknown Holiday";
|
||||||
const description = holiday.type || 'Public Holiday';
|
const description = holiday.type || "Public Holiday";
|
||||||
|
|
||||||
// Insert holiday into database
|
// Insert holiday into database
|
||||||
const query = `
|
const query = `
|
||||||
@@ -251,10 +251,10 @@ async function populateHolidays() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Holiday population completed!');
|
console.log("Holiday population completed!");
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Database error:', error);
|
console.error("Database error:", error);
|
||||||
} finally {
|
} finally {
|
||||||
client.release();
|
client.release();
|
||||||
await pool.end();
|
await pool.end();
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { IWorkLenzRequest } from '../interfaces/worklenz-request';
|
import { IWorkLenzRequest } from "../interfaces/worklenz-request";
|
||||||
import { IWorkLenzResponse } from '../interfaces/worklenz-response';
|
import { IWorkLenzResponse } from "../interfaces/worklenz-response";
|
||||||
import db from '../config/db';
|
import db from "../config/db";
|
||||||
import { ServerResponse } from '../models/server-response';
|
import { ServerResponse } from "../models/server-response";
|
||||||
import WorklenzControllerBase from './worklenz-controller-base';
|
import WorklenzControllerBase from "./worklenz-controller-base";
|
||||||
import HandleExceptions from '../decorators/handle-exceptions';
|
import HandleExceptions from "../decorators/handle-exceptions";
|
||||||
import {
|
import {
|
||||||
ICreateHolidayRequest,
|
ICreateHolidayRequest,
|
||||||
IUpdateHolidayRequest,
|
IUpdateHolidayRequest,
|
||||||
IImportCountryHolidaysRequest,
|
IImportCountryHolidaysRequest,
|
||||||
} from '../interfaces/holiday.interface';
|
} from "../interfaces/holiday.interface";
|
||||||
|
|
||||||
export default class HolidayController extends WorklenzControllerBase {
|
export default class HolidayController extends WorklenzControllerBase {
|
||||||
@HandleExceptions()
|
@HandleExceptions()
|
||||||
@@ -23,7 +23,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
@HandleExceptions()
|
@HandleExceptions()
|
||||||
public static async getOrganizationHolidays(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
|
public static async getOrganizationHolidays(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
|
||||||
const { year } = req.query;
|
const { year } = req.query;
|
||||||
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : '';
|
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : "";
|
||||||
const params = year ? [req.user?.owner_id, year] : [req.user?.owner_id];
|
const params = year ? [req.user?.owner_id, year] : [req.user?.owner_id];
|
||||||
|
|
||||||
const q = `SELECT oh.id, oh.organization_id, oh.holiday_type_id, oh.name, oh.description,
|
const q = `SELECT oh.id, oh.organization_id, oh.holiday_type_id, oh.name, oh.description,
|
||||||
@@ -86,11 +86,11 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (updateFields.length === 0) {
|
if (updateFields.length === 0) {
|
||||||
return res.status(400).send(new ServerResponse(false, 'No fields to update'));
|
return res.status(400).send(new ServerResponse(false, "No fields to update"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const q = `UPDATE organization_holidays
|
const q = `UPDATE organization_holidays
|
||||||
SET ${updateFields.join(', ')}, updated_at = CURRENT_TIMESTAMP
|
SET ${updateFields.join(", ")}, updated_at = CURRENT_TIMESTAMP
|
||||||
WHERE id = $2 AND organization_id = (
|
WHERE id = $2 AND organization_id = (
|
||||||
SELECT id FROM organizations WHERE user_id = $1
|
SELECT id FROM organizations WHERE user_id = $1
|
||||||
)
|
)
|
||||||
@@ -99,7 +99,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const result = await db.query(q, values);
|
const result = await db.query(q, values);
|
||||||
|
|
||||||
if (result.rows.length === 0) {
|
if (result.rows.length === 0) {
|
||||||
return res.status(404).send(new ServerResponse(false, 'Holiday not found'));
|
return res.status(404).send(new ServerResponse(false, "Holiday not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).send(new ServerResponse(true, result.rows[0]));
|
return res.status(200).send(new ServerResponse(true, result.rows[0]));
|
||||||
@@ -118,10 +118,10 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const result = await db.query(q, [req.user?.owner_id, id]);
|
const result = await db.query(q, [req.user?.owner_id, id]);
|
||||||
|
|
||||||
if (result.rows.length === 0) {
|
if (result.rows.length === 0) {
|
||||||
return res.status(404).send(new ServerResponse(false, 'Holiday not found'));
|
return res.status(404).send(new ServerResponse(false, "Holiday not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).send(new ServerResponse(true, { message: 'Holiday deleted successfully' }));
|
return res.status(200).send(new ServerResponse(true, { message: "Holiday deleted successfully" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@HandleExceptions()
|
@HandleExceptions()
|
||||||
@@ -129,10 +129,10 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const { country_code, year } = req.query;
|
const { country_code, year } = req.query;
|
||||||
|
|
||||||
if (!country_code) {
|
if (!country_code) {
|
||||||
return res.status(400).send(new ServerResponse(false, 'Country code is required'));
|
return res.status(400).send(new ServerResponse(false, "Country code is required"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : '';
|
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : "";
|
||||||
const params = year ? [country_code, year] : [country_code];
|
const params = year ? [country_code, year] : [country_code];
|
||||||
|
|
||||||
const q = `SELECT id, country_code, name, description, date, is_recurring, created_at, updated_at
|
const q = `SELECT id, country_code, name, description, date, is_recurring, created_at, updated_at
|
||||||
@@ -160,7 +160,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const { country_code, year }: IImportCountryHolidaysRequest = req.body;
|
const { country_code, year }: IImportCountryHolidaysRequest = req.body;
|
||||||
|
|
||||||
if (!country_code) {
|
if (!country_code) {
|
||||||
return res.status(400).send(new ServerResponse(false, 'Country code is required'));
|
return res.status(400).send(new ServerResponse(false, "Country code is required"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get organization ID
|
// Get organization ID
|
||||||
@@ -169,7 +169,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const organizationId = orgResult.rows[0]?.id;
|
const organizationId = orgResult.rows[0]?.id;
|
||||||
|
|
||||||
if (!organizationId) {
|
if (!organizationId) {
|
||||||
return res.status(404).send(new ServerResponse(false, 'Organization not found'));
|
return res.status(404).send(new ServerResponse(false, "Organization not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get default holiday type (Public Holiday)
|
// Get default holiday type (Public Holiday)
|
||||||
@@ -178,11 +178,11 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const holidayTypeId = typeResult.rows[0]?.id;
|
const holidayTypeId = typeResult.rows[0]?.id;
|
||||||
|
|
||||||
if (!holidayTypeId) {
|
if (!holidayTypeId) {
|
||||||
return res.status(404).send(new ServerResponse(false, 'Default holiday type not found'));
|
return res.status(404).send(new ServerResponse(false, "Default holiday type not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get country holidays for the specified year
|
// Get country holidays for the specified year
|
||||||
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : '';
|
const yearFilter = year ? `AND EXTRACT(YEAR FROM date) = $2` : "";
|
||||||
const params = year ? [country_code, year] : [country_code];
|
const params = year ? [country_code, year] : [country_code];
|
||||||
|
|
||||||
const holidaysQ = `SELECT name, description, date, is_recurring
|
const holidaysQ = `SELECT name, description, date, is_recurring
|
||||||
@@ -192,7 +192,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const holidaysResult = await db.query(holidaysQ, params);
|
const holidaysResult = await db.query(holidaysQ, params);
|
||||||
|
|
||||||
if (holidaysResult.rows.length === 0) {
|
if (holidaysResult.rows.length === 0) {
|
||||||
return res.status(404).send(new ServerResponse(false, 'No holidays found for this country and year'));
|
return res.status(404).send(new ServerResponse(false, "No holidays found for this country and year"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import holidays to organization
|
// Import holidays to organization
|
||||||
@@ -229,7 +229,7 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const { year, month } = req.query;
|
const { year, month } = req.query;
|
||||||
|
|
||||||
if (!year || !month) {
|
if (!year || !month) {
|
||||||
return res.status(400).send(new ServerResponse(false, 'Year and month are required'));
|
return res.status(400).send(new ServerResponse(false, "Year and month are required"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const q = `SELECT oh.id, oh.name, oh.description, oh.date, oh.is_recurring,
|
const q = `SELECT oh.id, oh.name, oh.description, oh.date, oh.is_recurring,
|
||||||
@@ -261,4 +261,105 @@ export default class HolidayController extends WorklenzControllerBase {
|
|||||||
const result = await db.query(q, [req.user?.owner_id, year, month]);
|
const result = await db.query(q, [req.user?.owner_id, year, month]);
|
||||||
return res.status(200).send(new ServerResponse(true, result.rows));
|
return res.status(200).send(new ServerResponse(true, result.rows));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HandleExceptions()
|
||||||
|
public static async populateCountryHolidays(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
|
||||||
|
const Holidays = require("date-holidays");
|
||||||
|
|
||||||
|
const countries = [
|
||||||
|
{ code: "US", name: "United States" },
|
||||||
|
{ code: "GB", name: "United Kingdom" },
|
||||||
|
{ code: "CA", name: "Canada" },
|
||||||
|
{ code: "AU", name: "Australia" },
|
||||||
|
{ code: "DE", name: "Germany" },
|
||||||
|
{ code: "FR", name: "France" },
|
||||||
|
{ code: "IT", name: "Italy" },
|
||||||
|
{ code: "ES", name: "Spain" },
|
||||||
|
{ code: "NL", name: "Netherlands" },
|
||||||
|
{ code: "BE", name: "Belgium" },
|
||||||
|
{ code: "CH", name: "Switzerland" },
|
||||||
|
{ code: "AT", name: "Austria" },
|
||||||
|
{ code: "SE", name: "Sweden" },
|
||||||
|
{ code: "NO", name: "Norway" },
|
||||||
|
{ code: "DK", name: "Denmark" },
|
||||||
|
{ code: "FI", name: "Finland" },
|
||||||
|
{ code: "PL", name: "Poland" },
|
||||||
|
{ code: "CZ", name: "Czech Republic" },
|
||||||
|
{ code: "HU", name: "Hungary" },
|
||||||
|
{ code: "RO", name: "Romania" },
|
||||||
|
{ code: "BG", name: "Bulgaria" },
|
||||||
|
{ code: "HR", name: "Croatia" },
|
||||||
|
{ code: "SI", name: "Slovenia" },
|
||||||
|
{ code: "SK", name: "Slovakia" },
|
||||||
|
{ code: "LT", name: "Lithuania" },
|
||||||
|
{ code: "LV", name: "Latvia" },
|
||||||
|
{ code: "EE", name: "Estonia" },
|
||||||
|
{ code: "IE", name: "Ireland" },
|
||||||
|
{ code: "PT", name: "Portugal" },
|
||||||
|
{ code: "GR", name: "Greece" },
|
||||||
|
{ code: "CY", name: "Cyprus" },
|
||||||
|
{ code: "MT", name: "Malta" },
|
||||||
|
{ code: "LU", name: "Luxembourg" },
|
||||||
|
{ code: "IS", name: "Iceland" },
|
||||||
|
{ code: "CN", name: "China" },
|
||||||
|
{ code: "JP", name: "Japan" },
|
||||||
|
{ code: "KR", name: "South Korea" },
|
||||||
|
{ code: "IN", name: "India" },
|
||||||
|
{ code: "BR", name: "Brazil" },
|
||||||
|
{ code: "AR", name: "Argentina" },
|
||||||
|
{ code: "MX", name: "Mexico" },
|
||||||
|
{ code: "ZA", name: "South Africa" },
|
||||||
|
{ code: "NZ", name: "New Zealand" }
|
||||||
|
];
|
||||||
|
|
||||||
|
let totalPopulated = 0;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
for (const country of countries) {
|
||||||
|
try {
|
||||||
|
const hd = new Holidays(country.code);
|
||||||
|
|
||||||
|
for (let year = 2020; year <= 2030; year++) {
|
||||||
|
const holidays = hd.getHolidays(year);
|
||||||
|
|
||||||
|
for (const holiday of holidays) {
|
||||||
|
if (!holiday.date || typeof holiday.date !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateStr = holiday.date.toISOString().split("T")[0];
|
||||||
|
const name = holiday.name || "Unknown Holiday";
|
||||||
|
const description = holiday.type || "Public Holiday";
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
INSERT INTO country_holidays (country_code, name, description, date, is_recurring)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
ON CONFLICT (country_code, name, date) DO NOTHING
|
||||||
|
`;
|
||||||
|
|
||||||
|
await db.query(query, [
|
||||||
|
country.code,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
dateStr,
|
||||||
|
true
|
||||||
|
]);
|
||||||
|
|
||||||
|
totalPopulated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
errors.push(`${country.name}: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
success: true,
|
||||||
|
message: `Successfully populated ${totalPopulated} holidays`,
|
||||||
|
total_populated: totalPopulated,
|
||||||
|
errors: errors.length > 0 ? errors : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
return res.status(200).send(new ServerResponse(true, response));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,29 @@
|
|||||||
import express from 'express';
|
import express from "express";
|
||||||
import HolidayController from '../../controllers/holiday-controller';
|
import HolidayController from "../../controllers/holiday-controller";
|
||||||
import safeControllerFunction from '../../shared/safe-controller-function';
|
import safeControllerFunction from "../../shared/safe-controller-function";
|
||||||
import teamOwnerOrAdminValidator from '../../middlewares/validators/team-owner-or-admin-validator';
|
import teamOwnerOrAdminValidator from "../../middlewares/validators/team-owner-or-admin-validator";
|
||||||
import idParamValidator from '../../middlewares/validators/id-param-validator';
|
import idParamValidator from "../../middlewares/validators/id-param-validator";
|
||||||
|
|
||||||
const holidayApiRouter = express.Router();
|
const holidayApiRouter = express.Router();
|
||||||
|
|
||||||
// Holiday types
|
// Holiday types
|
||||||
holidayApiRouter.get('/types', safeControllerFunction(HolidayController.getHolidayTypes));
|
holidayApiRouter.get("/types", safeControllerFunction(HolidayController.getHolidayTypes));
|
||||||
|
|
||||||
// Organization holidays
|
// Organization holidays
|
||||||
holidayApiRouter.get('/organization', teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.getOrganizationHolidays));
|
holidayApiRouter.get("/organization", teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.getOrganizationHolidays));
|
||||||
holidayApiRouter.post('/organization', teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.createOrganizationHoliday));
|
holidayApiRouter.post("/organization", teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.createOrganizationHoliday));
|
||||||
holidayApiRouter.put('/organization/:id', teamOwnerOrAdminValidator, idParamValidator, safeControllerFunction(HolidayController.updateOrganizationHoliday));
|
holidayApiRouter.put("/organization/:id", teamOwnerOrAdminValidator, idParamValidator, safeControllerFunction(HolidayController.updateOrganizationHoliday));
|
||||||
holidayApiRouter.delete('/organization/:id', teamOwnerOrAdminValidator, idParamValidator, safeControllerFunction(HolidayController.deleteOrganizationHoliday));
|
holidayApiRouter.delete("/organization/:id", teamOwnerOrAdminValidator, idParamValidator, safeControllerFunction(HolidayController.deleteOrganizationHoliday));
|
||||||
|
|
||||||
// Country holidays
|
// Country holidays
|
||||||
holidayApiRouter.get('/countries', safeControllerFunction(HolidayController.getAvailableCountries));
|
holidayApiRouter.get("/countries", safeControllerFunction(HolidayController.getAvailableCountries));
|
||||||
holidayApiRouter.get('/countries/:country_code', safeControllerFunction(HolidayController.getCountryHolidays));
|
holidayApiRouter.get("/countries/:country_code", safeControllerFunction(HolidayController.getCountryHolidays));
|
||||||
holidayApiRouter.post('/import', teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.importCountryHolidays));
|
holidayApiRouter.post("/import", teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.importCountryHolidays));
|
||||||
|
|
||||||
// Calendar view
|
// Calendar view
|
||||||
holidayApiRouter.get('/calendar', teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.getHolidayCalendar));
|
holidayApiRouter.get("/calendar", teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.getHolidayCalendar));
|
||||||
|
|
||||||
|
// Populate holidays
|
||||||
|
holidayApiRouter.post("/populate", teamOwnerOrAdminValidator, safeControllerFunction(HolidayController.populateCountryHolidays));
|
||||||
|
|
||||||
export default holidayApiRouter;
|
export default holidayApiRouter;
|
||||||
@@ -65,4 +65,10 @@ export const holidayApiService = {
|
|||||||
const response = await apiClient.get<IServerResponse<IHolidayCalendarEvent[]>>(`${rootUrl}/calendar?year=${year}&month=${month}`);
|
const response = await apiClient.get<IServerResponse<IHolidayCalendarEvent[]>>(`${rootUrl}/calendar?year=${year}&month=${month}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Populate holidays
|
||||||
|
populateCountryHolidays: async (): Promise<IServerResponse<any>> => {
|
||||||
|
const response = await apiClient.post<IServerResponse<any>>(`${rootUrl}/populate`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EditOutlined, MailOutlined, PhoneOutlined } from '@ant-design/icons';
|
import { EditOutlined, MailOutlined, PhoneOutlined, DatabaseOutlined } from '@ant-design/icons';
|
||||||
import { PageHeader } from '@ant-design/pro-components';
|
import { PageHeader } from '@ant-design/pro-components';
|
||||||
import { Button, Card, Input, Space, Tooltip, Typography } from 'antd';
|
import { Button, Card, Input, Space, Tooltip, Typography, message } from 'antd';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import OrganizationAdminsTable from '@/components/admin-center/overview/organization-admins-table/organization-admins-table';
|
import OrganizationAdminsTable from '@/components/admin-center/overview/organization-admins-table/organization-admins-table';
|
||||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||||
@@ -10,6 +10,7 @@ import OrganizationName from '@/components/admin-center/overview/organization-na
|
|||||||
import OrganizationOwner from '@/components/admin-center/overview/organization-owner/organization-owner';
|
import OrganizationOwner from '@/components/admin-center/overview/organization-owner/organization-owner';
|
||||||
import HolidayCalendar from '@/components/admin-center/overview/holiday-calendar/holiday-calendar';
|
import HolidayCalendar from '@/components/admin-center/overview/holiday-calendar/holiday-calendar';
|
||||||
import { adminCenterApiService } from '@/api/admin-center/admin-center.api.service';
|
import { adminCenterApiService } from '@/api/admin-center/admin-center.api.service';
|
||||||
|
import { holidayApiService } from '@/api/holiday/holiday.api.service';
|
||||||
import { IOrganization, IOrganizationAdmin } from '@/types/admin-center/admin-center.types';
|
import { IOrganization, IOrganizationAdmin } from '@/types/admin-center/admin-center.types';
|
||||||
import logger from '@/utils/errorLogger';
|
import logger from '@/utils/errorLogger';
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ const Overview: React.FC = () => {
|
|||||||
const [organization, setOrganization] = useState<IOrganization | null>(null);
|
const [organization, setOrganization] = useState<IOrganization | null>(null);
|
||||||
const [organizationAdmins, setOrganizationAdmins] = useState<IOrganizationAdmin[] | null>(null);
|
const [organizationAdmins, setOrganizationAdmins] = useState<IOrganizationAdmin[] | null>(null);
|
||||||
const [loadingAdmins, setLoadingAdmins] = useState(false);
|
const [loadingAdmins, setLoadingAdmins] = useState(false);
|
||||||
|
const [populatingHolidays, setPopulatingHolidays] = useState(false);
|
||||||
|
|
||||||
const themeMode = useAppSelector((state: RootState) => state.themeReducer.mode);
|
const themeMode = useAppSelector((state: RootState) => state.themeReducer.mode);
|
||||||
const { t } = useTranslation('admin-center/overview');
|
const { t } = useTranslation('admin-center/overview');
|
||||||
@@ -48,6 +50,21 @@ const Overview: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePopulateHolidays = async () => {
|
||||||
|
setPopulatingHolidays(true);
|
||||||
|
try {
|
||||||
|
const res = await holidayApiService.populateCountryHolidays();
|
||||||
|
if (res.done) {
|
||||||
|
message.success(`Successfully populated ${res.body.total_populated} holidays`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error populating holidays', error);
|
||||||
|
message.error('Failed to populate holidays');
|
||||||
|
} finally {
|
||||||
|
setPopulatingHolidays(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getOrganizationDetails();
|
getOrganizationDetails();
|
||||||
getOrganizationAdmins();
|
getOrganizationAdmins();
|
||||||
@@ -55,7 +72,20 @@ const Overview: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%' }}>
|
<div style={{ width: '100%' }}>
|
||||||
<PageHeader title={<span>{t('overview')}</span>} style={{ padding: '16px 0' }} />
|
<PageHeader
|
||||||
|
title={<span>{t('overview')}</span>}
|
||||||
|
style={{ padding: '16px 0' }}
|
||||||
|
extra={[
|
||||||
|
<Button
|
||||||
|
key="populate-holidays"
|
||||||
|
icon={<DatabaseOutlined />}
|
||||||
|
onClick={handlePopulateHolidays}
|
||||||
|
loading={populatingHolidays}
|
||||||
|
>
|
||||||
|
Populate Holidays Database
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
<Space direction="vertical" style={{ width: '100%' }} size={22}>
|
<Space direction="vertical" style={{ width: '100%' }} size={22}>
|
||||||
<OrganizationName
|
<OrganizationName
|
||||||
|
|||||||
Reference in New Issue
Block a user