I’m having trouble with
When I tried to create wix event with category, I can create event only but it doesn’t add selected category with that event.
Working in
Wix Editor
What I’m trying to do
I am trying to create a event with categories created in Wix Events category dashboard. In the UI I shows existing list of category using getCategory API.
What I’ve tried so far
import { eventCategories, createEvent, updateEventCategory } from "backend/events.web.js";
import wixLocation from 'wix-location';
import wixUsers from 'wix-users';
import { authentication, currentMember } from "wix-members-frontend";
function isSupportedFile(fileName, mimeType, fileSize) {
const supportedExtensions = ['jpg', 'jpeg', 'png'];
const maxSize = 15 * 1024 * 1024;
const extension = fileName.split('.').pop().toLowerCase();
return supportedExtensions.includes(extension) && fileSize <= maxSize;
}
$w.onReady(async function () {
const isLoggedIn = authentication.loggedIn();
if (!isLoggedIn) {
wixLocation.to('/customer-portal');
return;
}
$w('#toastText').hide();
$w('#toastBox').hide();
$w('#logout').onClick(async () => {
$w('#toastText').hide();
$w('#toastBox').hide();
await wixUsers.logout()
wixLocation.to('/customer-portal')
});
const requestCategory = await eventCategories();
const categoryItems = requestCategory._items;
const dropdownOptions = categoryItems.map(item => ({
label: item.name,
value: item._id
}));
categoryItems.forEach(element => {
console.log("Category: ", element.name);
console.log("ID", element._id);
});
$w('#eventCategory').options = dropdownOptions;
if (dropdownOptions.length > 0) {
$w('#eventCategory').value = dropdownOptions[0].value;
}
const countryMap = {
"India": "IN",
"United States": "US",
"United Kingdom": "GB",
"Australia": "AU",
"IN": "IN",
"US": "US",
"GB": "GB",
"AU": "AU"
};
let uploadedImageUrl = null;
$w('#toastText').hide();
$w('#toastBox').hide();
// Function to toggle field visibility based on radio button selection
function toggleFields(selectedValue) {
console.log('Selected radio button value:', selectedValue);
// Hide all fields initially
$w('#physicalLocationInput').hide();
$w('#onlineLocationInput').hide();
$w('#locationTBD').hide();
// Show relevant fields based on selected value
if (selectedValue === 'Radio button1') {
$w('#physicalLocationInput').show();
console.log('Showing physicalLocationInput');
} else if (selectedValue === 'Radio button2') {
$w('#onlineLocationInput').show();
console.log('Showing onlineLocationInput');
} else if (selectedValue === 'Radio button3') {
$w('#locationTBD').show();
console.log('Showing input6');
} else {
console.warn('Unknown radio button value:', selectedValue);
}
}
// Set default radio button and trigger field visibility
$w('#radioGroup2').value = 'Radio button1'; // Default to Radio button1
toggleFields('Radio button1'); // Initialize field visibility
// Handle radio button change
$w('#radioGroup2').onChange(() => {
const selectedValue = $w('#radioGroup2').value;
toggleFields(selectedValue);
});
$w('#imageUpload').onChange(async () => {
if ($w('#imageUpload').value.length === 0) return;
const file = $w('#imageUpload').value[0];
const fileName = file.name;
const fileSize = file.size;
console.log('Is Supported::', isSupportedFile(fileName, fileSize));
if (!isSupportedFile(fileName, fileSize)) {
showToast('Only JPG and PNG images are allowed.','error');
await $w('#imageUpload').reset();
uploadedImageUrl = null;
return;
}
try {
const uploadResponse = await $w('#imageUpload').startUpload();
uploadedImageUrl = uploadResponse.url;
console.log('Uploaded image URL:', uploadedImageUrl);
} catch (error) {
console.error('Image upload error:', error);
showToast('Failed to upload image','error');
}
});
function getMimeType(fileName) {
const extension = fileName.split('.').pop().toLowerCase();
const mimeTypes = {
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
gif: 'image/gif',
bmp: 'image/bmp',
};
return mimeTypes[extension] || 'image/jpeg';
}
function isSupportedFile(fileName, fileSize) {
const supportedExtensions = ['jpg', 'jpeg', 'png'];
const maxSize = 25 * 1024 * 1024;
const extension = fileName.split('.').pop().toLowerCase();
return supportedExtensions.includes(extension) && fileSize <= maxSize;
}
// Helper function to safely get and trim string values
function safeTrim(value, defaultValue = '') {
return typeof value === 'string' ? value.trim() : defaultValue;
}
// Helper function to reset the form
function resetForm() {
// Reset text inputs
$w('#eventNameInput').value = '';
$w('#onlineLocationInput').value = '';
$w('#input6').value = '';
$w('#conferenceLinkInput').value = '';
$w('#shortTeaserInput').value = '';
// Reset dropdowns to defaults
$w('#dropdownCurrency').value = 'GBP';
$w('#inputTicketLimit').value = '30';
$w('#eventCategory').value = $w('#eventCategory').options[0]?.value || '';
$w('#timezoneDropdown').value = 'America/Chicago';
// Reset date/time pickers
$w('#startDatePicker').value = null;
$w('#endDatePicker').value = null;
$w('#startTimePicker').value = null;
$w('#endTimePicker').value = null;
// Reset image upload
// $w('#imageUpload').value = [];
uploadedImageUrl = null;
console.log('Image upload field reset:', $w('#imageUpload').value);
$w('#imageUpload').reset();
// Reset physical location input
$w('#physicalLocationInput').value = null; // Explicitly reset address input
console.log('Physical location input reset:', $w('#physicalLocationInput').value);
// Maintain visibility based on current radio button selection
toggleFields($w('#radioGroup2').value);
}
// === Toast Notification System ===
function showToast(message, type = 'success') {
const isError = type === 'error';
const color = isError ? '#FF3B30' : '#28A745';
const icon = isError ? '❌' : '✅';
const backgroundColor = isError ? '#ffe6e6' : '#e6ffed';
if ($w('#toastBox').timeoutId) clearTimeout($w('#toastBox').timeoutId);
// Update text
$w('#toastText').text = `${icon} ${message}`;
$w('#toastText').style.color = color;
$w('#toastText').style.fontSize = '16px';
$w('#toastText').style.fontWeight = '600';
$w('#toastText').show();
// Style box
$w('#toastBox').style.backgroundColor = backgroundColor;
$w('#toastBox').style.border = `1px solid ${color}`;
$w('#toastBox').style.borderRadius = '12px';
$w('#toastBox').style.boxShadow = '0px 4px 12px rgba(0,0,0,0.2)';
$w('#toastBox').style.padding = '10px 18px';
// Scroll to toast
$w('#toastBox').scrollTo();
// Show and hide logic
$w('#toastBox').show('slide', { direction: 'bottom', duration: 300 });
$w('#toastBox').timeoutId = setTimeout(() => {
$w('#toastBox').hide('slide', { direction: 'bottom', duration: 300 });
}, 4000);
}
$w('#createEventBtn').onClick(async () => {
// Validate required fields before showing loader
const eventName = safeTrim($w('#eventNameInput').value);
const selectedLocationRaw = $w('#radioGroup2').value;
const addressInput = $w('#physicalLocationInput').value;
const onlineLink = safeTrim($w('#onlineLocationInput').value);
const otherLocation = safeTrim($w('#locationTBD').value);
const startDate = $w('#startDatePicker').value;
const endDate = $w('#endDatePicker').value;
const startTime = $w('#startTimePicker').value;
const endTime = $w('#endTimePicker').value;
const result2 = addressInput.formatted.split(",");
const streetname = result2[0];
// console.log("===== Result2", streetname);
console.log('Raw inputs:', {
eventName,
physicalLocation: addressInput,
onlineLocation: onlineLink,
otherLocation,
selectedLocationType: selectedLocationRaw,
imageUpload: $w('#imageUpload').value,
uploadedImageUrl
});
// Validate event name
if (!eventName) {
showToast('Event name is required','error');
return;
}
const valueMap = {
'Radio button1': 'Physical location',
'Radio button2': 'Online',
'Radio button3': 'To be decided (TBD)'
};
const selectedLocationType = valueMap[selectedLocationRaw];
//Location object
let locationData = {};
if (selectedLocationType === 'Physical location') {
if (!addressInput || !addressInput.formatted || addressInput.formatted.trim() === '') {
showToast('Physical Location is required', 'error');
return;
}
const { city, country, streetAddress, postalCode, subdivision } = addressInput;
const countryCode = countryMap[country] || countryMap[country?.toUpperCase()] || 'IN';
// Street Name
const result2 = addressInput.formatted.split(",");
const streetname = result2[0];
console.log("===== Result2", streetname);
const streetName = streetname;
const streetNumber = safeTrim(streetAddress?.number) || '';
const validPostalCode = safeTrim(postalCode) && postalCode !== 'undefined' ? postalCode : '000000';
locationData = {
type: 'VENUE',
address: {
country: countryCode,
city: safeTrim(city),
streetAddress: {
name: streetName,
number: streetNumber
},
postalCode: validPostalCode,
subdivision: safeTrim(subdivision) || ''
}
};
}
else if (selectedLocationType === 'Online') {
if (onlineLink || onlineLink.trim() !== '') {
showToast('Physical location type is required', 'error');
return;
}
locationData = {
type: 'ONLINE',
conferenceLink: safeTrim($w('#conferenceLinkInput').value)
};
}
else if (selectedLocationType === 'To be decided (TBD)') {
if (otherLocation || otherLocation.trim() !== '') {
showToast('Physical location type is required', 'error');
return;
}
locationData = {
type: 'UNKNOWN_LOCATION',
locationTbd: true,
name: otherLocation || 'To be decided'
};
} else {
showToast('Invalid location type selected','error');
return;
}
// Validate date and time fields
if (!startDate || !endDate && !startTime || !endTime) {
showToast('Date and time fields are required','error');
return;
}
// Check if end date is before start date
if (endDate < startDate) {
showToast('End date cannot be before start date', 'error');
return;
}
if (!startDate || !endDate) {
showToast('Date fields are required', 'error');
return;
}
if (!startTime || !endTime) {
showToast('Time fields are required', 'error');
return;
}
// If all validations pass, show the loader
const createBtn = $w('#createEventBtn');
const originalText = createBtn.label;
createBtn.label = '⏳ Creating event...';
createBtn.disable();
try {
const startTimeParsed = parseTimeValue(startTime);
const endTimeParsed = parseTimeValue(endTime);
function parseTimeValue(timeVal) {
if (!timeVal) return null;
if (timeVal instanceof Date) {
return { hours: timeVal.getHours(), minutes: timeVal.getMinutes() };
}
if (typeof timeVal === 'string') {
const match = timeVal.match(/(\d{1,2}):(\d{2})\s*(AM|PM)?/i);
if (!match) return null;
let hours = parseInt(match[1], 10);
const minutes = parseInt(match[2], 10);
const ampm = match[3]?.toUpperCase();
if (ampm === 'PM' && hours < 12) hours += 12;
if (ampm === 'AM' && hours === 12) hours = 0;
return { hours, minutes };
}
return null;
}
const startDateTime = new Date(startDate);
startDateTime.setHours(startTimeParsed.hours, startTimeParsed.minutes, 0, 0);
const endDateTime = new Date(endDate);
endDateTime.setHours(endTimeParsed.hours, endTimeParsed.minutes, 0, 0);
const descriptionText = safeTrim($w('#conferenceLinkInput').value) ?
`${safeTrim($w('#conferenceLinkInput').value).replace(/<[^>]+>/g, '')}` :
'';
const category = $w('#eventCategory').value
const eventData = {
event: {
title: eventName,
location: locationData,
dateAndTimeSettings: {
startDate: startDateTime.toISOString(),
endDate: endDateTime.toISOString(),
// timeZoneId: $w('#timezoneDropdown').value || 'Asia/Kolkata'
timeZoneId: 'America/Chicago'
},
description: descriptionText,
languageCode: 'en',
registration: {
initialType: 'TICKETING',
tickets: {
items: [{
name: 'General Admission',
price: {
amount: '0',
currency: safeTrim($w('#dropdownCurrency').value, 'GBP')
},
taxSettings: { type: 'INCLUDED_IN_PRICE' },
limitPerOrder: Number(safeTrim($w('#inputTicketLimit').value, '30')) || 30
}]
}
},
mainImage: uploadedImageUrl || undefined
},
draft: true,
categories: [category]
};
console.log('Sending eventData to backend:', JSON.stringify(eventData, null, 2));
const result = await createEvent(eventData);
console.log('Event Created Result: ', result);
console.log('EventID:::', [result.data._id]);
console.log('Category Selected', category);
const categoryUpdated = await updateEventCategory(category, [result.data._id]);
console.log('Category Updated Successfully::', categoryUpdated);
if (result.success) {
showToast('Event created successfully!', 'success');
resetForm();
} else {
console.log('Result:::', result);
showToast(result.error || 'Failed to create event','error');
}
} catch (error) {
console.log('Result:::', error);
showToast(error.message || 'An unexpected error occurred','error');
} finally {
// Restore button state
createBtn.label = originalText;
createBtn.enable();
}
});
});
import { wixEventsV2, categories } from "wix-events.v2";
import { webMethod, Permissions } from "wix-web-module";
import { elevate } from "wix-auth";
const elevatedQueryCategories = elevate(categories.queryCategories);
const elevatedCreateEvent = elevate(wixEventsV2.createEvent);
const elevatedCategoryUpdate = elevate(categories.assignEvents);
export const eventCategories = webMethod(
Permissions.SiteMember,
async () => {
try {
const items = await elevatedQueryCategories().find();
return items;
} catch (error) {
return error;
}
},
);
export const updateEventCategory = webMethod(
Permissions.SiteMember,
async (categoryId, eventId) => {
try {
const result = await elevatedCategoryUpdate(categoryId, eventId)
return { status: true, data: result }
} catch (error) {
return error;
}
}
);
const countryMap = {
'India': 'IN',
'United States': 'US',
'United Kingdom': 'GB',
'Australia': 'AU',
'IN': 'IN',
'US': 'US',
'GB': 'GB',
'AU': 'AU'
};
export const createEvent = webMethod(
Permissions.Anyone,
async (event, options) => {
try {
const e = event.event || event;
// Normalize initialType
const allowedInitialTypes = ['PUBLIC', 'TICKETING', 'PRIVATE'];
const initialType = allowedInitialTypes.includes(e.registration?.initialType?.toUpperCase()) ?
e.registration.initialType.toUpperCase() :
'TICKETING';
// Validate required fields
if (!e.title) {
throw new Error('Event title is required');
}
if (!e.dateAndTimeSettings?.startDate || !e.dateAndTimeSettings?.endDate) {
throw new Error('Start and end dates are required');
}
if (!e.location?.type) {
throw new Error('Location type is required');
}
let locationData = {};
// Handle different location types
if (e.location.type === 'VENUE') {
if (!e.location?.address?.city) {
throw new Error('City is required for VENUE');
}
if (!e.location?.address?.country) {
throw new Error('Country is required for VENUE');
}
if (!e.location?.address?.streetAddress?.name) {
throw new Error('Street name is required for VENUE');
}
if (!e.location?.address?.postalCode) {
throw new Error('Postal code is required for VENUE');
}
const countryCode = countryMap[e.location?.address?.country] ||
e.location?.address?.country || 'IN';
locationData = {
type: 'VENUE',
address: {
country: countryCode.toUpperCase(),
city: e.location?.address?.city || '',
streetAddress: {
name: e.location?.address?.streetAddress?.name || '',
number: e.location?.address?.streetAddress?.number || ''
},
postalCode: e.location?.address?.postalCode || '000000',
subdivision: e.location?.address?.subdivision || '',
latitude: e.location?.address?.latitude || undefined,
longitude: e.location?.address?.longitude || undefined
}
};
} else if (e.location.type === 'ONLINE') {
if (!e.location?.onlineDetails?.conferencingLink) {
throw new Error('Conferencing link is required for ONLINE');
}
locationData = {
type: 'ONLINE',
onlineDetails: {
conferencingLink: e.location.onlineDetails.conferencingLink
}
};
} else if (e.location.type === 'TBD') {
locationData = {
type: 'VENUE',
address: {
country: 'IN',
city: 'To be decided',
streetAddress: {
name: e.location.name || 'To be decided',
number: ''
},
postalCode: '000000',
subdivision: ''
}
};
} else {
throw new Error('Invalid location type');
}
const eventInfo = {
title: e.title,
language: e.languageCode || 'en',
description: e.description ? { nodes: [{ type: 'PARAGRAPH', nodes: [{ type: 'TEXT', textData: { text: e.description } }] }] } : undefined,
mainImage: e.mainImage || undefined, // Handle empty or undefined mainImage
location: locationData,
dateAndTimeSettings: {
dateAndTimeTbd: e.location.type === 'TBD',
startDate: e.dateAndTimeSettings.startDate,
endDate: e.dateAndTimeSettings.endDate,
showTimeZone: true,
timeZoneId: e.dateAndTimeSettings?.timeZoneId || 'Asia/Kolkata',
},
registration: {
initialType,
tickets: {
items: e.registration?.tickets?.items?.map(item => ({
name: item.name || 'General Admission',
price: {
amount: item.price?.amount || '0',
currency: item.price?.currency || 'GBP'
},
taxSettings: {
type: item.taxSettings?.type || 'INCLUDED_IN_PRICE'
},
limitPerOrder: Number(item.limitPerOrder) || 30
})) || [{
name: 'General Admission',
price: {
amount: '0',
currency: 'GBP'
},
taxSettings: {
type: 'INCLUDED_IN_PRICE'
},
limitPerOrder: 30
}]
}
},
draft: e.draft !== undefined ? e.draft : true
};
const result = await elevatedCreateEvent(eventInfo, { draft: true });
return { success: true, message: "Event Created Successfully, Wait for Admin Approval", data: result };
} catch (error) {
return { success: false, message: `Event failed to create, Try again Later: ${error};` };
}
},
);