From b19c800673eeefa3b379385bf178bfd5ea9af9fc Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 7 Aug 2025 18:41:00 -0300 Subject: [PATCH 1/4] actions for hootsuite #17712 Actions - Create Media Upload Job - Get Media Upload Status - Schedule Message --- .../create-media-upload-job.mjs | 77 + .../get-media-upload-status.mjs | 26 + .../schedule-message/schedule-message.mjs | 339 +++ components/hootsuite/common/constants.mjs | 2702 +++++++++++++++++ components/hootsuite/common/utils.mjs | 24 + components/hootsuite/hootsuite.app.mjs | 67 +- components/hootsuite/package.json | 4 +- .../new-post-created/new-post-created.mjs | 10 +- 8 files changed, 3224 insertions(+), 25 deletions(-) create mode 100644 components/hootsuite/actions/create-media-upload-job/create-media-upload-job.mjs create mode 100644 components/hootsuite/actions/get-media-upload-status/get-media-upload-status.mjs create mode 100644 components/hootsuite/actions/schedule-message/schedule-message.mjs create mode 100644 components/hootsuite/common/constants.mjs create mode 100644 components/hootsuite/common/utils.mjs diff --git a/components/hootsuite/actions/create-media-upload-job/create-media-upload-job.mjs b/components/hootsuite/actions/create-media-upload-job/create-media-upload-job.mjs new file mode 100644 index 0000000000000..1b2d40f580455 --- /dev/null +++ b/components/hootsuite/actions/create-media-upload-job/create-media-upload-job.mjs @@ -0,0 +1,77 @@ +import { getFileStreamAndMetadata } from "@pipedream/platform"; +import hootsuite from "../../hootsuite.app.mjs"; + +export default { + key: "hootsuite-create-media-upload-job", + name: "Create Media Upload Job", + description: "Creates a new Media Upload Job on your Hootsuite account. [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/createMedia)", + version: "0.0.1", + type: "action", + props: { + hootsuite, + file: { + type: "string", + label: "File Path or URL", + description: "The path or URL to the image file.", + }, + syncDir: { + type: "dir", + accessMode: "read", + sync: true, + }, + }, + methods: { + initializeUpload(opts = {}) { + return this.hootsuite._makeRequest({ + method: "POST", + path: "/media", + ...opts, + }); + }, + streamToBuffer(stream) { + return new Promise((resolve, reject) => { + const chunks = []; + stream.on("data", (chunk) => chunks.push(chunk)); + stream.on("end", () => resolve(Buffer.concat(chunks))); + stream.on("error", reject); + }); + }, + uploadImage(url, fileBinary, headers) { + return this.hootsuite._makeRequest({ + url, + method: "PUT", + maxBodyLength: Infinity, + data: Buffer.from(fileBinary, "binary"), + noHeaders: true, + headers, + }); + }, + }, + async run({ $ }) { + const { + stream, metadata, + } = await getFileStreamAndMetadata(this.file); + + const { + data: { + uploadUrl, id, + }, + } = await this.initializeUpload({ + data: { + sizeBytes: metadata.size, + mimeType: metadata.contentType, + }, + }); + + const fileBinary = await this.streamToBuffer(stream); + + await this.uploadImage(uploadUrl, fileBinary, { + "Content-Type": metadata.contentType, + }); + + $.export("$summary", `Successfully created media upload job with ID: ${id}`); + return { + fileId: id, + }; + }, +}; diff --git a/components/hootsuite/actions/get-media-upload-status/get-media-upload-status.mjs b/components/hootsuite/actions/get-media-upload-status/get-media-upload-status.mjs new file mode 100644 index 0000000000000..a4913f48c9d7c --- /dev/null +++ b/components/hootsuite/actions/get-media-upload-status/get-media-upload-status.mjs @@ -0,0 +1,26 @@ +import hootsuite from "../../hootsuite.app.mjs"; + +export default { + key: "hootsuite-get-media-upload-status", + name: "Get Media Upload Status", + description: "Gets the status of a Media Upload Job on your Hootsuite account. [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/getMedia)", + version: "0.0.1", + type: "action", + props: { + hootsuite, + fileId: { + type: "string", + label: "File ID", + description: "The ID of the file to get the status of.", + }, + }, + async run({ $ }) { + const response = await this.hootsuite.getMediaUploadStatus({ + $, + fileId: this.fileId, + }); + + $.export("$summary", `Successfully got media upload status for file ID: ${this.fileId}`); + return response; + }, +}; diff --git a/components/hootsuite/actions/schedule-message/schedule-message.mjs b/components/hootsuite/actions/schedule-message/schedule-message.mjs new file mode 100644 index 0000000000000..b5b6eb0ed48c2 --- /dev/null +++ b/components/hootsuite/actions/schedule-message/schedule-message.mjs @@ -0,0 +1,339 @@ +import { + COMPANY_SIZE_OPTIONS, + GEOGRAPHY_OPTIONS, + INDUSTRY_OPTIONS, + JOB_FUNCTION_OPTIONS, + SENIORITY_OPTIONS, + STAFF_COUNT_RANGE_OPTIONS, +} from "../../common/constants.mjs"; +import { parseObject } from "../../common/utils.mjs"; +import hootsuite from "../../hootsuite.app.mjs"; + +export default { + key: "hootsuite-schedule-message", + name: "Schedule Message", + description: "Schedules a message on your Hootsuite account. [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/scheduleMessage)", + version: "0.0.1", + type: "action", + props: { + hootsuite, + text: { + type: "string", + label: "Text", + description: "The message text to publish.", + }, + socialProfileIds: { + propDefinition: [ + hootsuite, + "socialProfileIds", + ], + }, + scheduledSendTime: { + type: "string", + label: "Scheduled Send Time", + description: "The time the message is scheduled to be sent in UTC time, (ISO-8601)[https://en.wikipedia.org/wiki/ISO_8601] format. Missing or different timezones will not be accepted, to ensure there is no ambiguity about scheduled time. Dates must end with 'Z' to be accepted.", + optional: true, + }, + webhookUrls: { + type: "string[]", + label: "Webhook URLs", + description: "The webhook URL(s) to call to when the message's state changes.", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "The Hootsuite message tags to apply to the message. To set tags the social profile must belong to an organization. Tags are case sensitive. Limited permission members can only use the existing tags for organization and cannot create new ones. See more about message tags at the Hootsuite Help Center. Not supported by Pinterest.", + optional: true, + }, + targetingFecabookPageAgeMin: { + type: "integer", + label: "Targeting Facebook Page - Age Min", + description: "Minimum age to target the message at.", + options: [ + 13, + 17, + 18, + 19, + 21, + ], + optional: true, + }, + targetingFecabookPageEducation: { + type: "string", + label: "Targeting Facebook Page - Education", + description: "The education level of the Facebook page to target.", + options: [ + "highSchool", + "college", + "collegeGrad", + ], + optional: true, + }, + targetingFecabookPageInterestIn: { + type: "string[]", + label: "Targeting Facebook Page - Interests", + description: "Interested in preferences to target the message at.", + options: [ + "male", + "female", + ], + optional: true, + }, + targetingFecabookPageRelationshipStatus: { + type: "string", + label: "Targeting Facebook Page - Relationship Status", + description: "Relationship status to target the message at.", + options: [ + "single", + "relationship", + "married", + "engaged", + ], + optional: true, + }, + targetingFecabookPageCountry: { + type: "string[]", + label: "Targeting Facebook Page - Country", + description: "Country to target the message at. 2-digit ISO 3166 format code as provided by Facebook.", + optional: true, + }, + targetingFecabookPageRegions: { + type: "string[]", + label: "Targeting Facebook Page - Regions", + description: "Region to target the message at. Note that regions can only be specified when there is exactly one country targeted. Limit 200.", + optional: true, + }, + targetingFecabookPageCities: { + type: "string[]", + label: "Targeting Facebook Page - Cities", + description: "City to target the message at. Note that cities can only be specified when there is exactly one country targeted. Limit 250.", + optional: true, + }, + targetingFecabookPageZips: { + type: "string[]", + label: "Targeting Facebook Page - Zip", + description: "Zip/Postal Code to target the message at. Limit 50,000.", + optional: true, + }, + targetingLinkedInCompanySize: { + type: "string[]", + label: "Targeting LinkedIn Company - Size", + description: "Company size to target the message at.", + options: COMPANY_SIZE_OPTIONS, + optional: true, + }, + targetingLinkedInCompanyGeography: { + type: "string[]", + label: "Targeting LinkedIn Company - Geography", + description: "Geography to target the message at.", + options: GEOGRAPHY_OPTIONS, + optional: true, + }, + targetingLinkedInCompanyIndustry: { + type: "string[]", + label: "Targeting LinkedIn Company - Industry", + description: "Industry to target the message at.", + options: INDUSTRY_OPTIONS, + optional: true, + }, + targetingLinkedInCompanyJobFunction: { + type: "string[]", + label: "Targeting LinkedIn Company - Job Function", + description: "Job function to target the message at.", + options: JOB_FUNCTION_OPTIONS, + optional: true, + }, + targetingLinkedInCompanySeniority: { + type: "string[]", + label: "Targeting LinkedIn Company - Seniority", + description: "Seniority to target the message at.", + options: SENIORITY_OPTIONS, + optional: true, + }, + targetingLinkedInV2CompanyLocations: { + type: "string[]", + label: "Targeting LinkedIn V2 Company - Locations", + description: "Locations to target the message at, expected format of urn:li:geo:{CODE}. (Geo Locations reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo], (Geo Typeahead Locations reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo-typeahead?tabs=http]", + optional: true, + }, + targetingLinkedInV2CompanyStaffCountRange: { + type: "string[]", + label: "Targeting LinkedIn V2 Company - Staff Count Range", + description: "Staff count to target the message at, expected format of SIZE_{VALUES}. (Staff count codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/company-size-codes]", + options: STAFF_COUNT_RANGE_OPTIONS, + optional: true, + }, + targetingLinkedInV2CompanySeniorities: { + type: "string[]", + label: "Targeting LinkedIn V2 Company - Seniorities", + description: "Seniorities to target the message at, expected format of urn:li:seniority:{CODE}. (Seniorities codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/seniority-codes]", + optional: true, + }, + targetingLinkedInV2CompanyIndustries: { + type: "string[]", + label: "Targeting LinkedIn V2 Company - Industries", + description: "Industries to target the message at, expected format of urn:li:industry:{CODE}. (Industries codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/industry-codes-v2]", + optional: true, + }, + targetingLinkedInV2CompanyInterfaceLocations: { + type: "string[]", + label: "Targeting LinkedIn V2 Company - Interface Locations", + description: "Languages to target the message at, expected format of {\"country\":\"COUNTRY\",\"language\":\"language\"}. (Language codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/language-codes] Languages can be interpreted as this format: language_COUNTRY, replace in request as necessary.", + optional: true, + }, + privacyFacebookVisibility: { + type: "string", + label: "Privacy Facebook Visibility", + description: "Facebook visibility rule.", + options: [ + "everyone", + "friends", + "friendsOfFriends", + ], + optional: true, + }, + privacyLinkedInVisibility: { + type: "string", + label: "Privacy LinkedIn Visibility", + description: "LinkedIn visibility rule.", + options: [ + "anyone", + "connectionsOnly", + ], + optional: true, + }, + latitude: { + type: "string", + label: "Latitude", + description: "The latitude in decimal degrees. Must be between -90 to 90.", + optional: true, + }, + longitude: { + type: "string", + label: "Longitude", + description: "The longitude in decimal degrees. Must be between -180 to 180.", + optional: true, + }, + emailNotification: { + type: "boolean", + label: "Email Notification", + description: "A flag to determine whether email notifications are sent when the message is published.", + optional: true, + }, + mediaUrls: { + type: "string[]", + label: "Media URLs", + description: "The ow.ly media to attach to the message", + optional: true, + }, + media: { + type: "string[]", + label: "Media", + description: "The media id(s) returned at `Create Media Upload Job` action to attach to the message", + optional: true, + }, + }, + async run({ $ }) { + const facebookPage = {}; + + if (this.targetingFecabookPageAgeMin) { + facebookPage.ageMin = this.targetingFecabookPageAgeMin; + } + if (this.targetingFecabookPageEducation) { + facebookPage.education = parseObject(this.targetingFecabookPageEducation); + } + if (this.targetingFecabookPageInterestIn) { + facebookPage.interestIn = parseObject(this.targetingFecabookPageInterestIn); + } + if (this.targetingFecabookPageRelationshipStatus) { + facebookPage.relationshipStatus = parseObject(this.targetingFecabookPageRelationshipStatus); + } + if (this.targetingFecabookPageCountry) { + facebookPage.countries = parseObject(this.targetingFecabookPageCountry)?.map((country) => ({ + v: country, + })); + } + if (this.targetingFecabookPageRegions) { + facebookPage.regions = parseObject(this.targetingFecabookPageRegions)?.map((region) => ({ + v: region, + })); + } + if (this.targetingFecabookPageCities) { + facebookPage.cities = parseObject(this.targetingFecabookPageCities)?.map((city) => ({ + v: city, + })); + } + if (this.targetingFecabookPageZips) { + facebookPage.zips = parseObject(this.targetingFecabookPageZips)?.map((zip) => ({ + v: zip, + })); + } + + const response = await this.hootsuite.scheduleMessage({ + $, + data: { + text: this.text, + socialProfileIds: parseObject(this.socialProfileIds), + scheduledSendTime: this.scheduledSendTime, + webhookUrls: parseObject(this.webhookUrls), + tags: parseObject(this.tags), + targeting: { + ...(Object.keys(facebookPage).length > 0 + ? { + facebookPage, + } + : {}), + linkedInCompany: { + companySize: parseObject(this.targetingLinkedInCompanySize), + geography: parseObject(this.targetingLinkedInCompanyGeography), + industry: parseObject(this.targetingLinkedInCompanyIndustry), + jobFunction: parseObject(this.targetingLinkedInCompanyJobFunction), + seniority: parseObject(this.targetingLinkedInCompanySeniority), + }, + linkedInV2Company: { + locations: parseObject(this.targetingLinkedInV2CompanyLocations), + staffCountRange: parseObject(this.targetingLinkedInV2CompanyStaffCountRange), + seniorities: parseObject(this.targetingLinkedInV2CompanySeniorities), + industries: parseObject(this.targetingLinkedInV2CompanyIndustries), + interfaceLocations: parseObject(this.targetingLinkedInV2CompanyInterfaceLocations), + }, + }, + privacy: (this.privacyFacebookVisibility || this.privacyLinkedInVisibility) && { + ...(this.privacyFacebookVisibility + ? { + facebook: { + visibility: [ + this.privacyFacebookVisibility, + ], + }, + } + : {}), + ...(this.privacyLinkedInVisibility + ? { + linkedIn: { + visibility: [ + this.privacyLinkedInVisibility, + ], + }, + } + : {}), + }, + location: { + latitude: this.latitude, + longitude: this.longitude, + }, + emailNotification: this.emailNotification, + mediaUrls: parseObject(this.mediaUrls)?.map((mediaUrl) => ({ + url: mediaUrl, + })), + media: parseObject(this.media)?.map((media) => ({ + id: media, + })), + }, + }); + + $.export("$summary", `Successfully scheduled message with ID: ${response.data[0].id}`); + return response; + }, +}; diff --git a/components/hootsuite/common/constants.mjs b/components/hootsuite/common/constants.mjs new file mode 100644 index 0000000000000..120103c44b485 --- /dev/null +++ b/components/hootsuite/common/constants.mjs @@ -0,0 +1,2702 @@ +export const COMPANY_SIZE_OPTIONS = [ + { + label: "self", + value: "self", + }, + { + label: "1-10", + value: "1 to 10 employees", + }, + { + label: "11-50", + value: "11 to 50 employees", + }, + { + label: "51-200", + value: "51 to 200 employees", + }, + { + label: "201-500", + value: "201 to 500 employees", + }, + { + label: "501-1000", + value: "501 to 1000 employees", + }, + { + label: "1001-5000", + value: "1001 to 5000 employees", + }, + { + label: "5001-10000", + value: "5001 to 10000 employees", + }, + { + label: "10001", + value: "10001+ employees", + }, +]; + +export const GEOGRAPHY_OPTIONS = [ + { + label: "Africa", + value: "af", + }, + { + label: "Cameroon", + value: "af.cm", + }, + { + label: "Algeria", + value: "af.dz", + }, + { + label: "Egypt", + value: "af.eg", + }, + { + label: "Ghana", + value: "af.gh", + }, + { + label: "Kenya", + value: "af.ke", + }, + { + label: "Morocco", + value: "af.ma", + }, + { + label: "Nigeria", + value: "af.ng", + }, + { + label: "Tunisia", + value: "af.tn", + }, + { + label: "Tanzania", + value: "af.tz", + }, + { + label: "Uganda", + value: "af.ug", + }, + { + label: "South Africa", + value: "af.za", + }, + { + label: "Zimbabwe", + value: "af.zw", + }, + { + label: "Antarctica", + value: "aq", + }, + { + label: "Asia", + value: "as", + }, + { + label: "Bangladesh", + value: "as.bd", + }, + { + label: "China", + value: "as.cn", + }, + { + label: "Shanghai City, China", + value: "as.cn.*.8909", + }, + { + label: "Shenzhen, Guangdong, China", + value: "as.cn.*.8910", + }, + { + label: "Beijing City, China", + value: "as.cn.*.8911", + }, + { + label: "Guangzhou, Guangdong, China", + value: "as.cn.*.8919", + }, + { + label: "Hong Kong", + value: "as.hk", + }, + { + label: "Indonesia", + value: "as.id", + }, + { + label: "Greater Jakarta Area, Indonesia", + value: "as.id.*.8594", + }, + { + label: "India", + value: "as.in", + }, + { + label: "Andaman & Nicobar Islands", + value: "as.in.an", + }, + { + label: "Andhra Pradesh", + value: "as.in.ap", + }, + { + label: "Hyderabad Area, India", + value: "as.in.ap.6508", + }, + { + label: "Arunachal Pradesh", + value: "as.in.ar", + }, + { + label: "Assam", + value: "as.in.as", + }, + { + label: "Bihar", + value: "as.in.br", + }, + { + label: "Chattisgarh", + value: "as.in.cg", + }, + { + label: "Chandigarh", + value: "as.in.ch", + }, + { + label: "Daman & Diu", + value: "as.in.dd", + }, + { + label: "Delhi", + value: "as.in.dl", + }, + { + label: "New Delhi Area, India", + value: "as.in.dl.7151", + }, + { + label: "Dadra & Nagar Haveli", + value: "as.in.dn", + }, + { + label: "Goa", + value: "as.in.ga", + }, + { + label: "Vadodara Area, India", + value: "as.in.gj.6552", + }, + { + label: "Ahmedabad Area, India", + value: "as.in.gj.7065", + }, + { + label: "Himachal Pradesh", + value: "as.in.hp", + }, + { + label: "Haryana", + value: "as.in.hr", + }, + { + label: "Daman & Diu", + value: "as.in.dd", + }, + { + label: "Delhi", + value: "as.in.dl", + }, + { + label: "New Delhi Area, India", + value: "as.in.dl.7151", + }, + { + label: "Dadra & Nagar Haveli", + value: "as.in.dn", + }, + { + label: "Goa", + value: "as.in.ga", + }, + { + label: "Gujarat", + value: "as.in.gj", + }, + { + label: "Vadodara Area, India", + value: "as.in.gj.6552", + }, + { + label: "Ahmedabad Area, India", + value: "as.in.gj.7065", + }, + { + label: "Himachal Pradesh", + value: "as.in.hp", + }, + { + label: "Haryana", + value: "as.in.hr", + }, + { + label: "Gurgaon, India", + value: "as.in.hr.7391", + }, + { + label: "Jharkhand", + value: "as.in.jh", + }, + { + label: "Jammu & Kashmir", + value: "as.in.jk", + }, + { + label: "Karnataka", + value: "as.in.ka", + }, + { + label: "Bengaluru Area, India", + value: "as.in.ka.7127", + }, + { + label: "Kerala", + value: "as.in.kl", + }, + { + label: "Cochin Area, India", + value: "as.in.kl.6477", + }, + { + label: "Lakshadweep", + value: "as.in.ld", + }, + { + label: "Maharashtra", + value: "as.in.mh", + }, + { + label: "Nagpur Area, India", + value: "as.in.mh.6751", + }, + { + label: "Mumbai Area, India", + value: "as.in.mh.7150", + }, + { + label: "Pune Area, India", + value: "as.in.mh.7350", + }, + { + label: "Meghalaya", + value: "as.in.mn", + }, + { + label: "Madhya Pradesh", + value: "as.in.mp", + }, + { + label: "Indore Area, India", + value: "as.in.mp.7382", + }, + { + label: "Mizoram", + value: "as.in.mz", + }, + { + label: "Nagaland", + value: "as.in.nl", + }, + { + label: "Orissa", + value: "as.in.or", + }, + { + label: "Punjab", + value: "as.in.pb", + }, + { + label: "Chandigarh Area, India", + value: "as.in.pb.6879", + }, + { + label: "Pondicherry", + value: "as.in.py", + }, + { + label: "Rajasthan", + value: "as.in.rj", + }, + { + label: "Jaipur Area, India", + value: "as.in.rj.7287", + }, + { + label: "Sikkim", + value: "as.in.sk", + }, + { + label: "Tamil Nadu", + value: "as.in.tn", + }, + { + label: "Coimbatore Area, India", + value: "as.in.tn.6472", + }, + { + label: "Chennai Area, India", + value: "as.in.tn.6891", + }, + { + label: "Tripura", + value: "as.in.tr", + }, + { + label: "Uttarakhand", + value: "as.in.ul", + }, + { + label: "Uttar Pradesh", + value: "as.in.up", + }, + { + label: "Lucknow Area, India", + value: "as.in.up.7093", + }, + { + label: "Noida Area, India", + value: "as.in.up.7392", + }, + { + label: "West Bengal", + value: "as.in.wb", + }, + { + label: "Kolkata Area, India", + value: "as.in.wb.7003", + }, + { + label: "Japan", + value: "as.jp", + }, + { + label: "Korea", + value: "as.kr", + }, + { + label: "Gangnam-gu, Seoul, Korea", + value: "as.kr.*.7700", + }, + { + label: "Sri Lanka", + value: "as.lk", + }, + { + label: "Malaysia", + value: "as.my", + }, + { + label: "Selangor, Malaysia", + value: "as.my.*.7945", + }, + { + label: "Kuala Lumpur, Malaysia", + value: "as.my.*.7960", + }, + { + label: "Nepal", + value: "as.np", + }, + { + label: "Philippines", + value: "as.ph", + }, + { + label: "Singapore", + value: "as.sg", + }, + { + label: "Thailand", + value: "as.th", + }, + { + label: "Taiwan", + value: "as.tw", + }, + { + label: "Vietnam", + value: "as.vn", + }, + { + label: "Europe", + value: "eu", + }, + { + label: "Austria", + value: "eu.at", + }, + { + label: "Belgium", + value: "eu.be", + }, + { + label: "Antwerp Area, Belgium", + value: "eu.be.*.4918", + }, + { + label: "Brussels Area, Belgium", + value: "eu.be.*.4920", + }, + { + label: "Bulgaria", + value: "eu.bg", + }, + { + label: "Switzerland", + value: "eu.ch", + }, + { + label: "Geneva Area, Switzerland", + value: "eu.ch.*.4930", + }, + { + label: "Zürich Area, Switzerland", + value: "eu.ch.*.4938", + }, + { + label: "Czech Republic", + value: "eu.cz", + }, + { + label: "Germany", + value: "eu.de", + }, + { + label: "Cologne Area, Germany", + value: "eu.de.*.4953", + }, + { + label: "Frankfurt Am Main Area, Germany", + value: "eu.de.*.4966", + }, + { + label: "Munich Area, Germany", + value: "eu.de.*.5000", + }, + { + label: "Denmark", + value: "eu.dk", + }, + { + label: "Copenhagen Area, Denmark", + value: "eu.dk.*.5038", + }, + { + label: "Odense Area, Denmark", + value: "eu.dk.*.5041", + }, + { + label: "Ålborg Area, Denmark", + value: "eu.dk.*.5044", + }, + { + label: "Århus Area, Denmark", + value: "eu.dk.*.5045", + }, + { + label: "Spain", + value: "eu.es", + }, + { + label: "Barcelona Area, Spain", + value: "eu.es.*.5064", + }, + { + label: "Madrid Area, Spain", + value: "eu.es.*.5113", + }, + { + label: "Finland", + value: "eu.fi", + }, + { + label: "France", + value: "eu.fr", + }, + { + label: "Lille Area, France", + value: "eu.fr.*.5205", + }, + { + label: "Lyon Area, France", + value: "eu.fr.*.5210", + }, + { + label: "Marseille Area, France", + value: "eu.fr.*.5211", + }, + { + label: "Nice Area, France", + value: "eu.fr.*.5221", + }, + { + label: "Paris Area, France", + value: "eu.fr.*.5227", + }, + { + label: "Toulouse Area, France", + value: "eu.fr.*.5249", + }, + { + label: "United Kingdom", + value: "eu.gb", + }, + { + label: "Birmingham, United Kingdom", + value: "eu.gb.*.4544", + }, + { + label: "Brighton, United Kingdom", + value: "eu.gb.*.4550", + }, + { + label: "Bristol, United Kingdom", + value: "eu.gb.*.4552", + }, + { + label: "Cambridge, United Kingdom", + value: "eu.gb.*.4555", + }, + { + label: "Chelmsford, United Kingdom", + value: "eu.gb.*.4558", + }, + { + label: "Coventry, United Kingdom", + value: "eu.gb.*.4562", + }, + { + label: "London, United Kingdom", + value: "eu.gb.*.4573", + }, + { + label: "Edinburgh, United Kingdom", + value: "eu.gb.*.4574", + }, + { + label: "Edinburgh, United Kingdom", + value: "eu.gb.*.4579", + }, + { + label: "Glasgow, United Kingdom", + value: "eu.gb.*.4580", + }, + { + label: "Gloucester, United Kingdom", + value: "eu.gb.*.4582", + }, + { + label: "Guildford, United Kingdom", + value: "eu.gb.*.4582", + }, + { + label: "Harrow, United Kingdom", + value: "eu.gb.*.4583", + }, + { + label: "Hemel Hempstead, United Kingdom", + value: "eu.gb.*.4586", + }, + { + label: "Hemel Hempstead, United Kingdom", + value: "eu.gb.*.4586", + }, + { + label: "Kingston upon Thames, United Kingdom", + value: "eu.gb.*.4597", + }, + { + label: "Kingston upon Thames, United Kingdom", + value: "eu.gb.*.4603", + }, + { + label: "Leicester, United Kingdom", + value: "eu.gb.*.4606", + }, + { + label: "Leeds, United Kingdom", + value: "eu.gb.*.4608", + }, + { + label: "Manchester, United Kingdom", + value: "eu.gb.*.4610", + }, + { + label: "Milton Keynes, United Kingdom", + value: "eu.gb.*.4612", + }, + { + label: "Newcastle upon Tyne, United Kingdom", + value: "eu.gb.*.4613", + }, + { + label: "Nottingham, United Kingdom", + value: "eu.gb.*.4614", + }, + { + label: "Northampton, United Kingdom", + value: "eu.gb.*.4618", + }, + { + label: "Portsmouth, United Kingdom", + value: "eu.gb.*.4623", + }, + { + label: "Reading, United Kingdom", + value: "eu.gb.*.4625", + }, + { + label: "Redhill, United Kingdom", + value: "eu.gb.*.4626", + }, + { + label: "Sheffield, United Kingdom", + value: "eu.gb.*.4628", + }, + { + label: "Slough, United Kingdom", + value: "eu.gb.*.4632", + }, + { + label: "Southampton, United Kingdom", + value: "eu.gb.*.4635", + }, + { + label: "Tonbridge, United Kingdom", + value: "eu.gb.*.4644", + }, + { + label: "Twickenham, United Kingdom", + value: "eu.gb.*.4648", + }, + { + label: "Greece", + value: "eu.gr", + }, + { + label: "Croatia", + value: "eu.hr", + }, + { + label: "Hungary", + value: "eu.hu", + }, + { + label: "Ireland", + value: "eu.ie", + }, + { + label: "Italy", + value: "eu.it", + }, + { + label: "Bologna Area, Italy", + value: "eu.it.*.5587", + }, + { + label: "Milan Area, Italy", + value: "eu.it.*.5616", + }, + { + label: "Rome Area, Italy", + value: "eu.it.*.5636", + }, + { + label: "Turin Area, Italy", + value: "eu.it.*.5652", + }, + { + label: "Venice Area, Italy", + value: "eu.it.*.5657", + }, + { + label: "Lithuania", + value: "eu.lt", + }, + { + label: "Netherlands", + value: "eu.nl", + }, + { + label: "Almere Stad Area, Netherlands", + value: "eu.nl.*.5663", + }, + { + label: "Amsterdam Area, Netherlands", + value: "eu.nl.*.5664", + }, + { + label: "Apeldoorn Area, Netherlands", + value: "eu.nl.*.5665", + }, + { + label: "Eindhoven Area, Netherlands", + value: "eu.nl.*.5668", + }, + { + label: "Enschede Area, Netherlands", + value: "eu.nl.*.5669", + }, + { + label: "Groningen Area, Netherlands", + value: "eu.nl.*.5673", + }, + { + label: "Nijmegen Area, Netherlands", + value: "eu.nl.*.5681", + }, + { + label: "The Hague Area, Netherlands", + value: "eu.nl.*.5688", + }, + { + label: "Utrecht Area, Netherlands", + value: "eu.nl.*.5690", + }, + { + label: "Breda Area, Netherlands", + value: "eu.nl.*.5906", + }, + { + label: "Tilburg Area, Netherlands", + value: "eu.nl.*.5907", + }, + { + label: "Rotterdam Area, Netherlands", + value: "eu.nl.*.5908", + }, + { + label: "Maastricht Area, Netherlands", + value: "eu.nl.*.7417", + }, + { + label: "Norway", + value: "eu.no", + }, + { + label: "Poland", + value: "eu.pl", + }, + { + label: "Portugal", + value: "eu.pt", + }, + { + label: "Romania", + value: "eu.ro", + }, + { + label: "Serbia", + value: "eu.rs", + }, + { + label: "Russian Federation", + value: "eu.ru", + }, + { + label: "Sweden", + value: "eu.se", + }, + { + label: "Slovak Republic", + value: "eu.sk", + }, + { + label: "Turkey", + value: "eu.tr", + }, + { + label: "Istanbul, Turkey", + value: "eu.tr.*.7585", + }, + { + label: "Ukraine", + value: "eu.ua", + }, + { + label: "Latin America", + value: "la", + }, + { + label: "Argentina", + value: "la.ar", + }, + { + label: "Bolivia", + value: "la.bo", + }, + { + label: "Brazil", + value: "la.br", + }, + { + label: "Acre", + value: "la.br.ac", + }, + { + label: "Alagoas", + value: "la.br.al", + }, + { + label: "Amazonas", + value: "la.br.am", + }, + { + label: "Amapá", + value: "la.br.ap", + }, + { + label: "Bahia", + value: "la.br.ba", + }, + { + label: "Ceará", + value: "la.br.ce", + }, + { + label: "Distrito Federal", + value: "la.br.df", + }, + { + label: "Espírito Santo", + value: "la.br.es", + }, + { + label: "Goiás", + value: "la.br.go", + }, + { + label: "Maranhão", + value: "la.br.ma", + }, + { + label: "Minas Gerais", + value: "la.br.mg", + }, + { + label: "Belo Horizonte Area, Brazil", + value: "la.br.mg.6156", + }, + { + label: "Mato Grosso do Sul", + value: "la.br.ms", + }, + { + label: "Mato Grosso", + value: "la.br.mt", + }, + { + label: "Pará", + value: "la.br.pa", + }, + { + label: "Paraíba", + value: "la.br.pb", + }, + { + label: "Pernambuco", + value: "la.br.pe", + }, + { + label: "Piauí", + value: "la.br.pi", + }, + { + label: "Paraná", + value: "la.br.pr", + }, + { + label: "Curitiba Area, Brazil", + value: "la.br.pr.6399", + }, + { + label: "Rio de Janeiro", + value: "la.br.rj", + }, + { + label: "Rio de Janeiro Area, Brazil", + value: "la.br.rj.6034", + }, + { + label: "Rio Grande do Norte", + value: "la.br.rn", + }, + { + label: "Rondônia", + value: "la.br.ro", + }, + { + label: "Roraima", + value: "la.br.rr", + }, + { + label: "Rio Grande do Sul", + value: "la.br.rs", + }, + { + label: "Porto Alegre Area, Brazil", + value: "la.br.rs.6467", + }, + { + label: "Santa Catarina", + value: "la.br.sc", + }, + { + label: "Sergipe", + value: "la.br.se", + }, + { + label: "São Paulo", + value: "la.br.sp", + }, + { + label: "Campinas Area, Brazil", + value: "la.br.sp.6104", + }, + { + label: "São Paulo Area, Brazil", + value: "la.br.sp.6368", + }, + { + label: "Tocantins", + value: "la.br.to", + }, + { + label: "Chile", + value: "la.cl", + }, + { + label: "Colombia", + value: "la.co", + }, + { + label: "Costa Rica", + value: "la.cr", + }, + { + label: "Dominican Republic", + value: "la.do", + }, + { + label: "Ecuador", + value: "la.ec", + }, + { + label: "Guatemala", + value: "la.gt", + }, + { + label: "Mexico", + value: "la.mx", + }, + { + label: "Mexico City Area, Mexico", + value: "la.mx.*.5921", + }, + { + label: "Naucalpan de Juárez Area, Mexico", + value: "la.mx.*.5955", + }, + { + label: "Panama", + value: "la.pa", + }, + { + label: "Peru", + value: "la.pe", + }, + { + label: "Puerto Rico", + value: "la.pr", + }, + { + label: "Trinidad and Tobago", + value: "la.tt", + }, + { + label: "Uruguay", + value: "la.uy", + }, + { + label: "Venezuela", + value: "la.ve", + }, + { + label: "Middle East", + value: "me", + }, + { + label: "United Arab Emirates", + value: "me.ae", + }, + { + label: "Bahrain", + value: "me.bh", + }, + { + label: "Israel", + value: "me.il", + }, + { + label: "Jordan", + value: "me.jo", + }, + { + label: "Kuwait", + value: "me.kw", + }, + { + label: "Pakistan", + value: "me.pk", + }, + { + label: "Qatar", + value: "me.qa", + }, + { + label: "Saudi Arabia", + value: "me.sa", + }, + { + label: "North America", + value: "na", + }, + { + label: "Canada", + value: "na.ca", + }, + { + label: "Alberta", + value: "na.ca.ab", + }, + { + label: "Edmonton, Canada Area", + value: "na.ca.ab.4872", + }, + { + label: "Calgary, Canada Area", + value: "na.ca.ab.4882", + }, + { + label: "British Columbia", + value: "na.ca.bc", + }, + { + label: "British Columbia, Canada", + value: "na.ca.bc.4873", + }, + { + label: "Vancouver, Canada Area", + value: "na.ca.bc.4880", + }, + { + label: "Manitoba", + value: "na.ca.mb", + }, + { + label: "New Brunswick", + value: "na.ca.nb", + }, + { + label: "Newfoundland And Labrador", + value: "na.ca.nl", + }, + { + label: "Nova Scotia", + value: "na.ca.ns", + }, + { + label: "Halifax, Canada Area", + value: "na.ca.ns.4874", + }, + { + label: "Northwest Territories", + value: "na.ca.nt", + }, + { + label: "Nunavut", + value: "na.ca.nu", + }, + { + label: "Ontario", + value: "na.ca.on", + }, + { + label: "Ontario, Canada", + value: "na.ca.on.4864", + }, + { + label: "Kitchener, Canada Area", + value: "na.ca.on.4865", + }, + { + label: "London, Canada Area", + value: "na.ca.on.4869", + }, + { + label: "Toronto, Canada Area", + value: "na.ca.on.4876", + }, + { + label: "Ottawa, Canada Area", + value: "na.ca.on.4884", + }, + { + label: "Prince Edward Island", + value: "na.ca.pe", + }, + { + label: "Quebec", + value: "na.ca.qc", + }, + { + label: "Montreal, Canada Area", + value: "na.ca.qc.4863", + }, + { + label: "Winnipeg, Canada Area", + value: "na.ca.qc.4866", + }, + { + label: "Quebec, Canada", + value: "na.ca.qc.4875", + }, + { + label: "Saskatchewan", + value: "na.ca.sk", + }, + { + label: "Yukon", + value: "na.ca.yt", + }, + { + label: "United States", + value: "na.us", + }, + { + label: "Alaska", + value: "na.us.ak", + }, + { + label: "Anchorage, Alaska Area", + value: "na.us.ak.38", + }, + { + label: "Alabama", + value: "na.us.al", + }, + { + label: "Birmingham, Alabama Area", + value: "na.us.al.100", + }, + { + label: "Huntsville, Alabama Area", + value: "na.us.al.344", + }, + { + label: "Mobile, Alabama Area", + value: "na.us.al.516", + }, + { + label: "Arkansas", + value: "na.us.ar", + }, + { + label: "Fayetteville, Arkansas Area", + value: "na.us.ar.258", + }, + { + label: "Little Rock, Arkansas Area", + value: "na.us.ar.440", + }, + { + label: "Arizona", + value: "na.us.az", + }, + { + label: "Phoenix, Arizona Area", + value: "na.us.az.620", + }, + { + label: "Tucson, Arizona Area", + value: "na.us.az.852", + }, + { + label: "California", + value: "na.us.ca", + }, + { + label: "Fresno, California Area", + value: "na.us.ca.284", + }, + { + label: "Greater Los Angeles Area", + value: "na.us.ca.49", + }, + { + label: "Orange County, California Area", + value: "na.us.ca.51", + }, + { + label: "Salinas, California Area", + value: "na.us.ca.712", + }, + { + label: "Greater San Diego Area", + value: "na.us.ca.732", + }, + { + label: "Santa Barbara, California Area", + value: "na.us.ca.748", + }, + { + label: "Stockton, California Area", + value: "na.us.ca.812", + }, + { + label: "Sacramento, California Area", + value: "na.us.ca.82", + }, + { + label: "San Francisco Bay Area", + value: "na.us.ca.84", + }, + { + label: "Colorado", + value: "na.us.co", + }, + { + label: "Colorado Springs, Colorado Area", + value: "na.us.co.172", + }, + { + label: "Fort Collins, Colorado Area", + value: "na.us.co.267", + }, + { + label: "Greater Denver Area", + value: "na.us.co.34", + }, + { + label: "Connecticut", + value: "na.us.ct", + }, + { + label: "Hartford, Connecticut Area", + value: "na.us.ct.327", + }, + { + label: "New London/Norwich, Connecticut Area", + value: "na.us.ct.552", + }, + { + label: "District Of Columbia", + value: "na.us.dc", + }, + { + label: "Washington D.C. Metro Area", + value: "na.us.dc.97", + }, + { + label: "Delaware", + value: "na.us.de", + }, + { + label: "Florida", + value: "na.us.fl", + }, + { + label: "Daytona Beach, Florida Area", + value: "na.us.fl.202", + }, + { + label: "Fort Myers, Florida Area", + value: "na.us.fl.270", + }, + { + label: "Fort Pierce, Florida Area", + value: "na.us.fl.271", + }, + { + label: "Gainesville, Florida Area", + value: "na.us.fl.290", + }, + { + label: "Jacksonville, Florida Area", + value: "na.us.fl.359", + }, + { + label: "Lakeland, Florida Area", + value: "na.us.fl.398", + }, + { + label: "Melbourne, Florida Area", + value: "na.us.fl.490", + }, + { + label: "Miami/Fort Lauderdale Area", + value: "na.us.fl.56", + }, + { + label: "Orlando, Florida Area", + value: "na.us.fl.596", + }, + { + label: "Sarasota, Florida Area", + value: "na.us.fl.751", + }, + { + label: "Tallahassee, Florida Area", + value: "na.us.fl.824", + }, + { + label: "Tampa/St. Petersburg, Florida Area", + value: "na.us.fl.828", + }, + { + label: "West Palm Beach, Florida Area", + value: "na.us.fl.896", + }, + { + label: "Georgia", + value: "na.us.ga", + }, + { + label: "Greater Atlanta Area", + value: "na.us.ga.52", + }, + { + label: "Augusta, Georgia Area", + value: "na.us.ga.60", + }, + { + label: "Savannah, Georgia Area", + value: "na.us.ga.752", + }, + { + label: "Hawaii", + value: "na.us.hi", + }, + { + label: "Hawaiian Islands", + value: "na.us.hi.332", + }, + { + label: "Iowa", + value: "na.us.ia", + }, + { + label: "Davenport, Iowa Area", + value: "na.us.ia.196", + }, + { + label: "Des Moines, Iowa Area", + value: "na.us.ia.212", + }, + { + label: "Idaho", + value: "na.us.id", + }, + { + label: "Boise, Idaho Area", + value: "na.us.id.108", + }, + { + label: "Illinois", + value: "na.us.il", + }, + { + label: "Greater Chicago Area", + value: "na.us.il.14", + }, + { + label: "Urbana-Champaign, Illinois Area", + value: "na.us.il.140", + }, + { + label: "Peoria, Illinois Area", + value: "na.us.il.612", + }, + { + label: "Rockford, Illinois Area", + value: "na.us.il.688", + }, + { + label: "Indiana", + value: "na.us.in", + }, + { + label: "Evansville, Indiana Area", + value: "na.us.in.244", + }, + { + label: "Fort Wayne, Indiana Area", + value: "na.us.in.276", + }, + { + label: "Indianapolis, Indiana Area", + value: "na.us.in.348", + }, + { + label: "Kansas", + value: "na.us.ks", + }, + { + label: "Wichita, Kansas Area", + value: "na.us.ks.904", + }, + { + label: "Kentucky", + value: "na.us.ky", + }, + { + label: "Lexington, Kentucky Area", + value: "na.us.ky.428", + }, + { + label: "Louisville, Kentucky Area", + value: "na.us.ky.452", + }, + { + label: "Louisiana", + value: "na.us.la", + }, + { + label: "Greater New Orleans Area", + value: "na.us.la.556", + }, + { + label: "Baton Rouge, Louisiana Area", + value: "na.us.la.76", + }, + { + label: "Massachusetts", + value: "na.us.ma", + }, + { + label: "Greater Boston Area", + value: "na.us.ma.7", + }, + { + label: "Springfield, Massachusetts Area", + value: "na.us.ma.800", + }, + { + label: "Maryland", + value: "na.us.md", + }, + { + label: "Baltimore, Maryland Area", + value: "na.us.md.7416", + }, + { + label: "Maine", + value: "na.us.me", + }, + { + label: "Portland, Maine Area", + value: "na.us.me.640", + }, + { + label: "Michigan", + value: "na.us.mi", + }, + { + label: "Greater Grand Rapids, Michigan Area", + value: "na.us.mi.300", + }, + { + label: "Greater Detroit Area", + value: "na.us.mi.35", + }, + { + label: "Kalamazoo, Michigan Area", + value: "na.us.mi.372", + }, + { + label: "Lansing, Michigan Area", + value: "na.us.mi.404", + }, + { + label: "Saginaw, Michigan Area", + value: "na.us.mi.696", + }, + { + label: "Minnesota", + value: "na.us.mn", + }, + { + label: "Greater Minneapolis-St. Paul Area", + value: "na.us.mn.512", + }, + { + label: "Missouri", + value: "na.us.mo", + }, + { + label: "Columbia, Missouri Area", + value: "na.us.mo.174", + }, + { + label: "Kansas City, Missouri Area", + value: "na.us.mo.376", + }, + { + label: "Greater St. Louis Area", + value: "na.us.mo.704", + }, + { + label: "Springfield, Missouri Area", + value: "na.us.mo.792", + }, + { + label: "Mississippi", + value: "na.us.ms", + }, + { + label: "Jackson, Mississippi Area", + value: "na.us.ms.356", + }, + { + label: "Montana", + value: "na.us.mt", + }, + { + label: "North Carolina", + value: "na.us.nc", + }, + { + label: "Charlotte, North Carolina Area", + value: "na.us.nc.152", + }, + { + label: "Greensboro/Winston-Salem, North Carolina Area", + value: "na.us.nc.312", + }, + { + label: "Asheville, North Carolina Area", + value: "na.us.nc.48", + }, + { + label: "Raleigh-Durham, North Carolina Area", + value: "na.us.nc.664", + }, + { + label: "Wilmington, North Carolina Area", + value: "na.us.nc.920", + }, + { + label: "North Dakota", + value: "na.us.nd", + }, + { + label: "Lincoln, Nebraska Area", + value: "na.us.ne.436", + }, + { + label: "Greater Omaha Area", + value: "na.us.ne.592", + }, + { + label: "New Hampshire", + value: "na.us.nh", + }, + { + label: "New Jersey", + value: "na.us.nj", + }, + { + label: "New Mexico", + value: "na.us.nm", + }, + { + label: "Albuquerque, New Mexico Area", + value: "na.us.nm.20", + }, + { + label: "Nevada", + value: "na.us.nv", + }, + { + label: "Las Vegas, Nevada Area", + value: "na.us.nv.412", + }, + { + label: "Reno, Nevada Area", + value: "na.us.nv.672", + }, + { + label: "New York", + value: "na.us.ny", + }, + { + label: "Buffalo/Niagara, New York Area", + value: "na.us.ny.128", + }, + { + label: "Albany, New York Area", + value: "na.us.ny.16", + }, + { + label: "Rochester, New York Area", + value: "na.us.ny.684", + }, + { + label: "Greater New York City Area", + value: "na.us.ny.70", + }, + { + label: "Syracuse, New York Area", + value: "na.us.ny.816", + }, + { + label: "Ithaca, New York Area", + value: "na.us.ny.96", + }, + { + label: "Ohio", + value: "na.us.oh", + }, + { + label: "Columbus, Ohio Area", + value: "na.us.oh.184", + }, + { + label: "Dayton, Ohio Area", + value: "na.us.oh.200", + }, + { + label: "Dayton, Ohio Area", + value: "na.us.oh.200", + }, + { + label: "Cincinnati Area", + value: "na.us.oh.21", + }, + { + label: "Cleveland/Akron, Ohio Area", + value: "na.us.oh.28", + }, + { + label: "Toledo, Ohio Area", + value: "na.us.oh.840", + }, + { + label: "Oklahoma", + value: "na.us.ok", + }, + { + label: "Oklahoma City, Oklahoma Area", + value: "na.us.ok.588", + }, + { + label: "Tulsa, Oklahoma Area", + value: "na.us.ok.856", + }, + { + label: "Oregon", + value: "na.us.or", + }, + { + label: "Eugene, Oregon Area", + value: "na.us.or.240", + }, + { + label: "Portland, Oregon Area", + value: "na.us.or.79", + }, + { + label: "Pennsylvania", + value: "na.us.pa", + }, + { + label: "Allentown, Pennsylvania Area", + value: "na.us.pa.24", + }, + { + label: "Harrisburg, Pennsylvania Area", + value: "na.us.pa.324", + }, + { + label: "Lancaster, Pennsylvania Area", + value: "na.us.pa.400", + }, + { + label: "Greater Pittsburgh Area", + value: "na.us.pa.628", + }, + { + label: "Scranton, Pennsylvania Area", + value: "na.us.pa.756", + }, + { + label: "Greater Philadelphia Area", + value: "na.us.pa.77", + }, + { + label: "Rhode Island", + value: "na.us.ri", + }, + { + label: "Providence, Rhode Island Area", + value: "na.us.ri.648", + }, + { + label: "South Carolina", + value: "na.us.sc", + }, + { + label: "Charleston, South Carolina Area", + value: "na.us.sc.144", + }, + { + label: "Columbia, South Carolina Area", + value: "na.us.sc.176", + }, + { + label: "Greenville, South Carolina Area", + value: "na.us.sc.316", + }, + { + label: "South Dakota", + value: "na.us.sd", + }, + { + label: "Sioux Falls, South Dakota Area", + value: "na.us.sd.776", + }, + { + label: "Tennessee", + value: "na.us.tn", + }, + { + label: "Chattanooga, Tennessee Area", + value: "na.us.tn.156", + }, + { + label: "Johnson City, Tennessee Area", + value: "na.us.tn.366", + }, + { + label: "Knoxville, Tennessee Area", + value: "na.us.tn.384", + }, + { + label: "Greater Memphis Area", + value: "na.us.tn.492", + }, + { + label: "Greater Nashville Area", + value: "na.us.tn.536", + }, + { + label: "Texas", + value: "na.us.tx", + }, + { + label: "El Paso, Texas Area", + value: "na.us.tx.232", + }, + { + label: "Dallas/Fort Worth Area", + value: "na.us.tx.31", + }, + { + label: "Houston, Texas Area", + value: "na.us.tx.42", + }, + { + label: "Austin, Texas Area", + value: "na.us.tx.64", + }, + { + label: "San Antonio, Texas Area", + value: "na.us.tx.724", + }, + { + label: "Utah", + value: "na.us.ut", + }, + { + label: "Provo, Utah Area", + value: "na.us.ut.652", + }, + { + label: "Greater Salt Lake City Area", + value: "na.us.ut.716", + }, + { + label: "Virginia", + value: "na.us.va", + }, + { + label: "Charlottesville, Virginia Area", + value: "na.us.va.154", + }, + { + label: "Norfolk, Virginia Area", + value: "na.us.va.572", + }, + { + label: "Richmond, Virginia Area", + value: "na.us.va.676", + }, + { + label: "Roanoke, Virginia Area", + value: "na.us.va.680", + }, + { + label: "Vermont", + value: "na.us.vt", + }, + { + label: "Burlington, Vermont Area", + value: "na.us.vt.130", + }, + { + label: "Washington", + value: "na.us.wa", + }, + { + label: "Spokane, Washington Area", + value: "na.us.wa.784", + }, + { + label: "Greater Seattle Area", + value: "na.us.wa.91", + }, + { + label: "Wisconsin", + value: "na.us.wi", + }, + { + label: "Green Bay, Wisconsin Area", + value: "na.us.wi.308", + }, + { + label: "Oshkosh, Wisconsin Area", + value: "na.us.wi.46", + }, + { + label: "Madison, Wisconsin Area", + value: "na.us.wi.472", + }, + { + label: "Greater Milwaukee Area", + value: "na.us.wi.63", + }, + { + label: "West Virginia", + value: "na.us.wv", + }, + { + label: "Wyoming", + value: "na.us.wy", + }, + { + label: "Oceania", + value: "oc", + }, + { + label: "Australia", + value: "oc.au", + }, + { + label: "Adelaide Area, Australia", + value: "oc.au.*.4886", + }, + { + label: "Canberra Area, Australia", + value: "oc.au.*.4893", + }, + { + label: "Melbourne Area, Australia", + value: "oc.au.*.4900", + }, + { + label: "Perth Area, Australia", + value: "oc.au.*.4905", + }, + { + label: "Brisbane Area, Australia", + value: "oc.au.*.4909", + }, + { + label: "Sydney Area, Australia", + value: "oc.au.*.4910", + }, + { + label: "New Zealand", + value: "oc.nz", + }, +]; + +export const INDUSTRY_OPTIONS = [ + { + label: "Agriculture - Farming", + value: "63", + }, + { + label: "Agriculture - Ranching", + value: "64", + }, + { + label: "Agriculture - Dairy", + value: "65", + }, + { + label: "Agriculture - Fishery", + value: "66", + }, + { + label: "Arts - Motion Pictures and Film", + value: "35", + }, + { + label: "Arts - Museums and Institutions", + value: "37", + }, + { + label: "Arts - Fine Art", + value: "38", + }, + { + label: "Arts - Performing Arts", + value: "39", + }, + { + label: "Arts - Design", + value: "99", + }, + { + label: "Arts - Arts and Crafts", + value: "111", + }, + { + label: "Arts - Music", + value: "115", + }, + { + label: "Arts - Photography", + value: "136", + }, + { + label: "Arts - Graphic Design", + value: "140", + }, + { + label: "Construction - Construction", + value: "48", + }, + { + label: "Construction - Building Materials", + value: "49", + }, + { + label: "Construction - Architecture & Planning", + value: "50", + }, + { + label: "Construction - Civil Engineering", + value: "51", + }, + { + label: "Consumer Goods - Cosmetics", + value: "18", + }, + { + label: "Consumer Goods - Apparel & Fashion", + value: "19", + }, + { + label: "Consumer Goods - Sporting Goods", + value: "20", + }, + { + label: "Consumer Goods - Tobacco", + value: "21", + }, + { + label: "Consumer Goods - Supermarkets", + value: "22", + }, + { + label: "Consumer Goods - Food Production", + value: "23", + }, + { + label: "Consumer Goods - Consumer Electronics", + value: "24", + }, + { + label: "Consumer Goods - Consumer Goods", + value: "25", + }, + { + label: "Consumer Goods - Furniture", + value: "26", + }, + { + label: "Consumer Goods - Retail", + value: "27", + }, + { + label: "Consumer Goods - Wholesale", + value: "133", + }, + { + label: "Consumer Goods - Import and Export", + value: "134", + }, + { + label: "Consumer Goods - Wine and Spirits", + value: "142", + }, + { + label: "Consumer Goods - Luxury Goods & Jewelry", + value: "143", + }, + { + label: "Corporate - Management Consulting", + value: "11", + }, + { + label: "Corporate - Marketing and Advertising", + value: "80", + }, + { + label: "Corporate - Market Research", + value: "97", + }, + { + label: "Corporate - Public Relations and Communications", + value: "98", + }, + { + label: "Corporate - Staffing and Recruiting", + value: "104", + }, + { + label: "Corporate - Professional Training & Coaching", + value: "105", + }, + { + label: "Corporate - Security and Investigations", + value: "121", + }, + { + label: "Corporate - Facilities Services", + value: "122", + }, + { + label: "Corporate - Outsourcing/Offshoring", + value: "123", + }, + { + label: "Corporate - Human Resources", + value: "137", + }, + { + label: "Corporate - Business Supplies and Equipment", + value: "138", + }, + { + label: "Educational - Primary/Secondary Education", + value: "67", + }, + { + label: "Educational - Higher Education", + value: "68", + }, + { + label: "Educational - Education Management", + value: "69", + }, + { + label: "Educational - Research", + value: "70", + }, + { + label: "Educational - E-Learning", + value: "132", + }, + { + label: "Finance - Banking", + value: "41", + }, + { + label: "Finance - Insurance", + value: "42", + }, + { + label: "Finance - Financial Services", + value: "43", + }, + { + label: "Finance - Real Estate", + value: "44", + }, + { + label: "Finance - Investment Banking", + value: "45", + }, + { + label: "Finance - Investment Management", + value: "46", + }, + { + label: "Finance - Accounting", + value: "47", + }, + { + label: "Finance - Venture Capital & Private Equity", + value: "106", + }, + { + label: "Finance - Commercial Real Estate", + value: "128", + }, + { + label: "Finance - Capital Markets", + value: "129", + }, + { + label: "Government - Military", + value: "71", + }, + { + label: "Government - Legislative Office", + value: "72", + }, + { + label: "Government - Judiciary", + value: "73", + }, + { + label: "Government - International Affairs", + value: "74", + }, + { + label: "Government - Government Administration", + value: "75", + }, + { + label: "Government - Executive Office", + value: "76", + }, + { + label: "Government - Law Enforcement", + value: "77", + }, + { + label: "Government - Public Safety", + value: "78", + }, + { + label: "Government - Public Policy", + value: "79", + }, + { + label: "Government - Political Organization", + value: "107", + }, + { + label: "Government - Government Relations", + value: "148", + }, + { + label: "High Tech - Defense & Space", + value: "1", + }, + { + label: "High Tech - Computer Hardware", + value: "3", + }, + { + label: "High Tech - Computer Software", + value: "4", + }, + { + label: "High Tech - Computer Networking", + value: "5", + }, + { + label: "High Tech - Internet", + value: "6", + }, + { + label: "High Tech - Semiconductors", + value: "7", + }, + { + label: "High Tech - Telecommunications", + value: "8", + }, + { + label: "High Tech - Information Technology and Services", + value: "96", + }, + { + label: "High Tech - Nanotechnology", + value: "114", + }, + { + label: "High Tech - Computer & Network Security", + value: "118", + }, + { + label: "High Tech - Wireless", + value: "119", + }, + { + label: "Legal - Law Practice", + value: "9", + }, + { + label: "Legal - Legal Services", + value: "10", + }, + { + label: "Legal - Alternative Dispute Resolution", + value: "120", + }, + { + label: "Manufacturing - Aviation & Aerospace", + value: "52", + }, + { + label: "Manufacturing - Automotive", + value: "53", + }, + { + label: "Manufacturing - Chemicals", + value: "54", + }, + { + label: "Manufacturing - Machinery", + value: "55", + }, + { + label: "Manufacturing - Mining & Metals", + value: "56", + }, + { + label: "Manufacturing - Oil & Energy", + value: "57", + }, + { + label: "Manufacturing - Shipbuilding", + value: "58", + }, + { + label: "Manufacturing - Utilities", + value: "59", + }, + { + label: "Manufacturing - Textiles", + value: "60", + }, + { + label: "Manufacturing - Paper & Forest Products", + value: "61", + }, + { + label: "Manufacturing - Railroad Manufacture", + value: "62", + }, + { + label: "Manufacturing - Electrical/Electronic Manufacturing", + value: "112", + }, + { + label: "Manufacturing - Plastics", + value: "117", + }, + { + label: "Manufacturing - Mechanical or Industrial Engineering", + value: "135", + }, + { + label: "Manufacturing - Renewables & Environment", + value: "144", + }, + { + label: "Manufacturing - Glass, Ceramics & Concrete", + value: "145", + }, + { + label: "Manufacturing - Packaging and Containers", + value: "146", + }, + { + label: "Manufacturing - Industrial Automation", + value: "147", + }, + { + label: "Media - Broadcast Media", + value: "36", + }, + { + label: "Media - Newspapers", + value: "81", + }, + { + label: "Media - Publishing", + value: "82", + }, + { + label: "Media - Printing", + value: "83", + }, + { + label: "Media - Writing and Editing", + value: "103", + }, + { + label: "Media - Online Media", + value: "113", + }, + { + label: "Media - Media Production", + value: "126", + }, + { + label: "Media - Animation", + value: "127", + }, + { + label: "Medical - Biotechnology", + value: "12", + }, + { + label: "Medical - Medical Practice", + value: "13", + }, + { + label: "Medical - Hospital & Health Care", + value: "14", + }, + { + label: "Medical - Pharmaceuticals", + value: "15", + }, + { + label: "Medical - Veterinary", + value: "16", + }, + { + label: "Medical - Medical Devices", + value: "17", + }, + { + label: "Medical - Health, Wellness and Fitness", + value: "124", + }, + { + label: "Medical - Alternative Medicine", + value: "125", + }, + { + label: "Medical - Mental Health Care", + value: "139", + }, + { + label: "Non-profit - Consumer Services", + value: "91", + }, + { + label: "Non-profit - Non-profit Organization Management", + value: "100", + }, + { + label: "Non-profit - Fund-Raising", + value: "101", + }, + { + label: "Non-profit - Program Development", + value: "102", + }, + { + label: "Non-profit - Think Tanks", + value: "130", + }, + { + label: "Non-profit - Philanthropy", + value: "131", + }, + { + label: "Non-profit - International Trade and Development", + value: "141", + }, + { + label: "Recreational - Entertainment", + value: "28", + }, + { + label: "Recreational - Gambling & Casinos", + value: "29", + }, + { + label: "Recreational - Leisure, Travel & Tourism", + value: "30", + }, + { + label: "Recreational - Hospitality", + value: "31", + }, + { + label: "Recreational - Restaurants", + value: "32", + }, + { + label: "Recreational - Sports", + value: "33", + }, + { + label: "Recreational - Food & Beverages", + value: "34", + }, + { + label: "Recreational - Recreational Facilities and Services", + value: "40", + }, + { + label: "Recreational - Computer Games", + value: "109", + }, + { + label: "Recreational - Events Services", + value: "110", + }, + { + label: "Service - Information Services", + value: "84", + }, + { + label: "Service - Libraries", + value: "85", + }, + { + label: "Service - Environmental Services", + value: "86", + }, + { + label: "Service - Individual & Family Services", + value: "88", + }, + { + label: "Service - Religious Institutions", + value: "89", + }, + { + label: "Service - Civic & Social Organization", + value: "90", + }, + { + label: "Service - Translation and Localization", + value: "108", + }, + { + label: "Transportation - Package/Freight Delivery", + value: "87", + }, + { + label: "Transportation - Transportation/Trucking/Railroad", + value: "92", + }, + { + label: "Transportation - Warehousing", + value: "93", + }, + { + label: "Transportation - Airlines/Aviation", + value: "94", + }, + { + label: "Transportation - Maritime", + value: "95", + }, + { + label: "Transportation - Logistics and Supply Chain", + value: "116", + }, +]; + +export const JOB_FUNCTION_OPTIONS = [ + { + label: "Research", + value: "acad", + }, + { + label: "Accounting", + value: "acct", + }, + { + label: "Administrative", + value: "admn", + }, + { + label: "Business Development", + value: "bd", + }, + { + label: "Purchasing", + value: "buy", + }, + { + label: "Consulting", + value: "cnsl", + }, + { + label: "Arts and Design", + value: "cre", + }, + { + label: "Community and Social Services", + value: "css", + }, + { + label: "Education", + value: "edu", + }, + { + label: "Engineering", + value: "eng", + }, + { + label: "Entrepreneurship", + value: "ent", + }, + { + label: "Finance", + value: "finc", + }, + { + label: "Human Resources", + value: "hr", + }, + { + label: "Information Technology", + value: "it", + }, + { + label: "Legal", + value: "lgl", + }, + { + label: "Healthcare Services", + value: "med", + }, + { + label: "Marketing", + value: "mktg", + }, + { + label: "Military and Protective Services", + value: "mps", + }, + { + label: "Operations", + value: "ops", + }, + { + label: "Program and Project Management", + value: "ppm", + }, + { + label: "Media and Communication", + value: "pr", + }, + { + label: "Product Management", + value: "prod", + }, + { + label: "Quality Assurance", + value: "qa", + }, + { + label: "Real Estate", + value: "re", + }, + { + label: "Sales", + value: "sale", + }, + { + label: "Support", + value: "supp", + }, +]; + +export const SENIORITY_OPTIONS = [ + { + label: "Chief X Officer", + value: "c", + }, + { + label: "Director", + value: "d", + }, + { + label: "Entry", + value: "en", + }, + { + label: "Senior", + value: "ic", + }, + { + label: "Manager", + value: "m", + }, + { + label: "Owner", + value: "o", + }, + { + label: "Partner", + value: "p", + }, + { + label: "Training", + value: "tr", + }, + { + label: "Unpaid", + value: "up", + }, + { + label: "Vice President", + value: "vp", + }, +]; + +export const STAFF_COUNT_RANGE_OPTIONS = [ + "SIZE_1", + "SIZE_2_TO_10", + "SIZE_11_TO_50", + "SIZE_51_TO_200", + "SIZE_201_TO_500", + "SIZE_501_TO_1000", + "SIZE_1001_TO_5000", + "SIZE_5001_TO_10000", + "SIZE_10001_OR_MORE", +]; diff --git a/components/hootsuite/common/utils.mjs b/components/hootsuite/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/hootsuite/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/hootsuite/hootsuite.app.mjs b/components/hootsuite/hootsuite.app.mjs index 731c5c46bafcf..a279c0d8f0f1d 100644 --- a/components/hootsuite/hootsuite.app.mjs +++ b/components/hootsuite/hootsuite.app.mjs @@ -3,29 +3,66 @@ import { axios } from "@pipedream/platform"; export default { type: "app", app: "hootsuite", - propDefinitions: {}, + propDefinitions: { + socialProfileIds: { + type: "string[]", + label: "Social Profile IDs", + description: "The social profiles that the message will be posted to.", + async options() { + const { data } = await this.listSocialProfiles(); + return data.map(({ + id: value, socialNetworkUsername: label, + }) => ({ + label, + value, + })); + }, + }, + }, methods: { - _oauthAccessToken() { - return this.$auth.oauth_access_token; + _baseUrl() { + return "https://platform.hootsuite.com/v1"; }, - _apiUrl() { - return "https://platform.hootsuite.com"; + _headers() { + return { + Authorization: `Bearer ${this.$auth.oauth_access_token}`, + }; }, - async _makeRequest({ - $ = this, path, ...args + _makeRequest({ + $ = this, path, noHeaders = false, ...opts }) { return axios($, { - url: `${this._apiUrl()}${path}`, - headers: { - Authorization: `Bearer ${this._oauthAccessToken()}`, - }, - ...args, + url: this._baseUrl() + path, + headers: noHeaders + ? {} + : this._headers(), + ...opts, + }); + }, + listSocialProfiles() { + return this._makeRequest({ + path: "/socialProfiles", + }); + }, + getMediaUploadStatus({ + fileId, ...opts + }) { + return this._makeRequest({ + path: `/media/${fileId}`, + ...opts, + }); + }, + scheduleMessage(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/messages", + ...opts, }); }, - async getPosts({ ...args } = {}) { + getPosts(opts = {}) { return this._makeRequest({ - path: "/v1/messages", - ...args, + path: "/messages", + ...opts, }); }, }, diff --git a/components/hootsuite/package.json b/components/hootsuite/package.json index 235b76acd10d9..a8d7b4029b121 100644 --- a/components/hootsuite/package.json +++ b/components/hootsuite/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/hootsuite", - "version": "0.1.0", + "version": "0.2.0", "description": "Pipedream Hootsuite Components", "main": "hootsuite.app.mjs", "keywords": [ @@ -13,7 +13,7 @@ "access": "public" }, "dependencies": { - "@pipedream/platform": "^1.5.1", + "@pipedream/platform": "^3.1.0", "dayjs": "^1.11.7" } } diff --git a/components/hootsuite/sources/new-post-created/new-post-created.mjs b/components/hootsuite/sources/new-post-created/new-post-created.mjs index a2d3ff3725398..ed93aede9061b 100644 --- a/components/hootsuite/sources/new-post-created/new-post-created.mjs +++ b/components/hootsuite/sources/new-post-created/new-post-created.mjs @@ -1,11 +1,11 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; import dayjs from "dayjs"; import hootsuite from "../../hootsuite.app.mjs"; import constants from "../common/constants.mjs"; -import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; export default { name: "New Post Created", - version: "0.0.1", + version: "0.0.2", key: "hootsuite-new-post-created", description: "Emit new event on each new created post. [See docs here](https://platform.hootsuite.com/docs/api/index.html#operation/retrieveMessages).", type: "source", @@ -72,12 +72,6 @@ export default { }, }); - console.log({ - startTime: dayjs(lastSyncTimestamp).subtract(24, "hour") - .toISOString(), - endTime: dayjs().toISOString(), - }); - posts.forEach(this.emitEvent); }, }; From 6e81037a43717ec844cecf9e82a2348ddedf318d Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Thu, 7 Aug 2025 18:47:25 -0300 Subject: [PATCH 2/4] pnpm update --- pnpm-lock.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6496e14c5a618..41c8546817ba7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6518,8 +6518,8 @@ importers: components/hootsuite: dependencies: '@pipedream/platform': - specifier: ^1.5.1 - version: 1.6.6 + specifier: ^3.1.0 + version: 3.1.0 dayjs: specifier: ^1.11.7 version: 1.11.13 @@ -40183,6 +40183,8 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) + transitivePeerDependencies: + - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: From ee44b6720a3a14fdc859972396e14afc91bf79e0 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Mon, 11 Aug 2025 13:06:10 -0300 Subject: [PATCH 3/4] Fix typos in targeting fields and update description formatting in schedule-message component --- .../schedule-message/schedule-message.mjs | 60 +++++++++---------- components/hootsuite/common/constants.mjs | 36 ----------- 2 files changed, 30 insertions(+), 66 deletions(-) diff --git a/components/hootsuite/actions/schedule-message/schedule-message.mjs b/components/hootsuite/actions/schedule-message/schedule-message.mjs index b5b6eb0ed48c2..1b3f1d2647ae6 100644 --- a/components/hootsuite/actions/schedule-message/schedule-message.mjs +++ b/components/hootsuite/actions/schedule-message/schedule-message.mjs @@ -31,7 +31,7 @@ export default { scheduledSendTime: { type: "string", label: "Scheduled Send Time", - description: "The time the message is scheduled to be sent in UTC time, (ISO-8601)[https://en.wikipedia.org/wiki/ISO_8601] format. Missing or different timezones will not be accepted, to ensure there is no ambiguity about scheduled time. Dates must end with 'Z' to be accepted.", + description: "The time the message is scheduled to be sent in UTC time, [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) format. Missing or different timezones will not be accepted, to ensure there is no ambiguity about scheduled time. Dates must end with 'Z' to be accepted.", optional: true, }, webhookUrls: { @@ -46,7 +46,7 @@ export default { description: "The Hootsuite message tags to apply to the message. To set tags the social profile must belong to an organization. Tags are case sensitive. Limited permission members can only use the existing tags for organization and cannot create new ones. See more about message tags at the Hootsuite Help Center. Not supported by Pinterest.", optional: true, }, - targetingFecabookPageAgeMin: { + targetingFacebookPageAgeMin: { type: "integer", label: "Targeting Facebook Page - Age Min", description: "Minimum age to target the message at.", @@ -59,7 +59,7 @@ export default { ], optional: true, }, - targetingFecabookPageEducation: { + targetingFacebookPageEducation: { type: "string", label: "Targeting Facebook Page - Education", description: "The education level of the Facebook page to target.", @@ -70,7 +70,7 @@ export default { ], optional: true, }, - targetingFecabookPageInterestIn: { + targetingFacebookPageInterestIn: { type: "string[]", label: "Targeting Facebook Page - Interests", description: "Interested in preferences to target the message at.", @@ -80,7 +80,7 @@ export default { ], optional: true, }, - targetingFecabookPageRelationshipStatus: { + targetingFacebookPageRelationshipStatus: { type: "string", label: "Targeting Facebook Page - Relationship Status", description: "Relationship status to target the message at.", @@ -92,25 +92,25 @@ export default { ], optional: true, }, - targetingFecabookPageCountry: { + targetingFacebookPageCountry: { type: "string[]", label: "Targeting Facebook Page - Country", description: "Country to target the message at. 2-digit ISO 3166 format code as provided by Facebook.", optional: true, }, - targetingFecabookPageRegions: { + targetingFacebookPageRegions: { type: "string[]", label: "Targeting Facebook Page - Regions", description: "Region to target the message at. Note that regions can only be specified when there is exactly one country targeted. Limit 200.", optional: true, }, - targetingFecabookPageCities: { + targetingFacebookPageCities: { type: "string[]", label: "Targeting Facebook Page - Cities", description: "City to target the message at. Note that cities can only be specified when there is exactly one country targeted. Limit 250.", optional: true, }, - targetingFecabookPageZips: { + targetingFacebookPageZips: { type: "string[]", label: "Targeting Facebook Page - Zip", description: "Zip/Postal Code to target the message at. Limit 50,000.", @@ -154,32 +154,32 @@ export default { targetingLinkedInV2CompanyLocations: { type: "string[]", label: "Targeting LinkedIn V2 Company - Locations", - description: "Locations to target the message at, expected format of urn:li:geo:{CODE}. (Geo Locations reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo], (Geo Typeahead Locations reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo-typeahead?tabs=http]", + description: "Locations to target the message at, expected format of `urn:li:geo:{CODE}`. [Geo Locations reference](https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo), [Geo Typeahead Locations reference](https://learn.microsoft.com/en-us/linkedin/shared/references/v2/standardized-data/locations/geo-typeahead?tabs=http)", optional: true, }, targetingLinkedInV2CompanyStaffCountRange: { type: "string[]", label: "Targeting LinkedIn V2 Company - Staff Count Range", - description: "Staff count to target the message at, expected format of SIZE_{VALUES}. (Staff count codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/company-size-codes]", + description: "Staff count to target the message at, expected format of `SIZE_{VALUES}`. [Staff count codes reference](https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/company-size-codes)", options: STAFF_COUNT_RANGE_OPTIONS, optional: true, }, targetingLinkedInV2CompanySeniorities: { type: "string[]", label: "Targeting LinkedIn V2 Company - Seniorities", - description: "Seniorities to target the message at, expected format of urn:li:seniority:{CODE}. (Seniorities codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/seniority-codes]", + description: "Seniorities to target the message at, expected format of `urn:li:seniority:{CODE}`. [Seniorities codes reference](https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/seniority-codes)", optional: true, }, targetingLinkedInV2CompanyIndustries: { type: "string[]", label: "Targeting LinkedIn V2 Company - Industries", - description: "Industries to target the message at, expected format of urn:li:industry:{CODE}. (Industries codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/industry-codes-v2]", + description: "Industries to target the message at, expected format of `urn:li:industry:{CODE}`. [Industries codes reference](https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/industry-codes-v2)", optional: true, }, targetingLinkedInV2CompanyInterfaceLocations: { type: "string[]", label: "Targeting LinkedIn V2 Company - Interface Locations", - description: "Languages to target the message at, expected format of {\"country\":\"COUNTRY\",\"language\":\"language\"}. (Language codes reference)[https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/language-codes] Languages can be interpreted as this format: language_COUNTRY, replace in request as necessary.", + description: "Languages to target the message at, expected format of `{\"country\":\"COUNTRY\",\"language\":\"language\"}`. [Language codes reference](https://learn.microsoft.com/en-us/linkedin/shared/references/reference-tables/language-codes) Languages can be interpreted as this format: language_COUNTRY, replace in request as necessary.", optional: true, }, privacyFacebookVisibility: { @@ -237,35 +237,35 @@ export default { async run({ $ }) { const facebookPage = {}; - if (this.targetingFecabookPageAgeMin) { - facebookPage.ageMin = this.targetingFecabookPageAgeMin; + if (this.targetingFacebookPageAgeMin) { + facebookPage.ageMin = this.targetingFacebookPageAgeMin; } - if (this.targetingFecabookPageEducation) { - facebookPage.education = parseObject(this.targetingFecabookPageEducation); + if (this.targetingFacebookPageEducation) { + facebookPage.education = parseObject(this.targetingFacebookPageEducation); } - if (this.targetingFecabookPageInterestIn) { - facebookPage.interestIn = parseObject(this.targetingFecabookPageInterestIn); + if (this.targetingFacebookPageInterestIn) { + facebookPage.interestIn = parseObject(this.targetingFacebookPageInterestIn); } - if (this.targetingFecabookPageRelationshipStatus) { - facebookPage.relationshipStatus = parseObject(this.targetingFecabookPageRelationshipStatus); + if (this.targetingFacebookPageRelationshipStatus) { + facebookPage.relationshipStatus = parseObject(this.targetingFacebookPageRelationshipStatus); } - if (this.targetingFecabookPageCountry) { - facebookPage.countries = parseObject(this.targetingFecabookPageCountry)?.map((country) => ({ + if (this.targetingFacebookPageCountry) { + facebookPage.countries = parseObject(this.targetingFacebookPageCountry)?.map((country) => ({ v: country, })); } - if (this.targetingFecabookPageRegions) { - facebookPage.regions = parseObject(this.targetingFecabookPageRegions)?.map((region) => ({ + if (this.targetingFacebookPageRegions) { + facebookPage.regions = parseObject(this.targetingFacebookPageRegions)?.map((region) => ({ v: region, })); } - if (this.targetingFecabookPageCities) { - facebookPage.cities = parseObject(this.targetingFecabookPageCities)?.map((city) => ({ + if (this.targetingFacebookPageCities) { + facebookPage.cities = parseObject(this.targetingFacebookPageCities)?.map((city) => ({ v: city, })); } - if (this.targetingFecabookPageZips) { - facebookPage.zips = parseObject(this.targetingFecabookPageZips)?.map((zip) => ({ + if (this.targetingFacebookPageZips) { + facebookPage.zips = parseObject(this.targetingFacebookPageZips)?.map((zip) => ({ v: zip, })); } diff --git a/components/hootsuite/common/constants.mjs b/components/hootsuite/common/constants.mjs index 120103c44b485..56f5100fe4916 100644 --- a/components/hootsuite/common/constants.mjs +++ b/components/hootsuite/common/constants.mjs @@ -206,46 +206,10 @@ export const GEOGRAPHY_OPTIONS = [ label: "Haryana", value: "as.in.hr", }, - { - label: "Daman & Diu", - value: "as.in.dd", - }, - { - label: "Delhi", - value: "as.in.dl", - }, - { - label: "New Delhi Area, India", - value: "as.in.dl.7151", - }, - { - label: "Dadra & Nagar Haveli", - value: "as.in.dn", - }, - { - label: "Goa", - value: "as.in.ga", - }, { label: "Gujarat", value: "as.in.gj", }, - { - label: "Vadodara Area, India", - value: "as.in.gj.6552", - }, - { - label: "Ahmedabad Area, India", - value: "as.in.gj.7065", - }, - { - label: "Himachal Pradesh", - value: "as.in.hp", - }, - { - label: "Haryana", - value: "as.in.hr", - }, { label: "Gurgaon, India", value: "as.in.hr.7391", From 195fe3481127f8030d4ea8a7c0506bf8ca7236a6 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 12 Aug 2025 17:57:43 -0300 Subject: [PATCH 4/4] Update targeting field types and descriptions in schedule-message component; refactor LinkedIn targeting logic for improved clarity --- .../schedule-message/schedule-message.mjs | 106 +++++++++++------- components/hootsuite/common/constants.mjs | 32 +++--- 2 files changed, 81 insertions(+), 57 deletions(-) diff --git a/components/hootsuite/actions/schedule-message/schedule-message.mjs b/components/hootsuite/actions/schedule-message/schedule-message.mjs index 1b3f1d2647ae6..11d2eb5da8c09 100644 --- a/components/hootsuite/actions/schedule-message/schedule-message.mjs +++ b/components/hootsuite/actions/schedule-message/schedule-message.mjs @@ -47,20 +47,20 @@ export default { optional: true, }, targetingFacebookPageAgeMin: { - type: "integer", + type: "string", label: "Targeting Facebook Page - Age Min", description: "Minimum age to target the message at.", options: [ - 13, - 17, - 18, - 19, - 21, + "13", + "17", + "18", + "19", + "21", ], optional: true, }, targetingFacebookPageEducation: { - type: "string", + type: "string[]", label: "Targeting Facebook Page - Education", description: "The education level of the Facebook page to target.", options: [ @@ -81,7 +81,7 @@ export default { optional: true, }, targetingFacebookPageRelationshipStatus: { - type: "string", + type: "string[]", label: "Targeting Facebook Page - Relationship Status", description: "Relationship status to target the message at.", options: [ @@ -95,25 +95,25 @@ export default { targetingFacebookPageCountry: { type: "string[]", label: "Targeting Facebook Page - Country", - description: "Country to target the message at. 2-digit ISO 3166 format code as provided by Facebook.", + description: "Country to target the message at. 2-digit ISO 3166 format code as provided by Facebook. **Format: [{\"k\": \"Canada\", \"v\": \"CA\"}]** [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/scheduleMessage) for more information.", optional: true, }, targetingFacebookPageRegions: { type: "string[]", label: "Targeting Facebook Page - Regions", - description: "Region to target the message at. Note that regions can only be specified when there is exactly one country targeted. Limit 200.", + description: "Region to target the message at. Note that regions can only be specified when there is exactly one country targeted. Limit 200. **Format: [{\"k\": \"British Columbia\", \"v\": \"2\"}]** [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/scheduleMessage) for more information.", optional: true, }, targetingFacebookPageCities: { type: "string[]", label: "Targeting Facebook Page - Cities", - description: "City to target the message at. Note that cities can only be specified when there is exactly one country targeted. Limit 250.", + description: "City to target the message at. Note that cities can only be specified when there is exactly one country targeted. Limit 250. **Format: [{\"k\": \"Burnaby, BC\", \"v\": \"292466\"}]** [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/scheduleMessage) for more information.", optional: true, }, targetingFacebookPageZips: { type: "string[]", label: "Targeting Facebook Page - Zip", - description: "Zip/Postal Code to target the message at. Limit 50,000.", + description: "Zip/Postal Code to target the message at. Limit 50,000. **Format: [{\"k\": \"K1S\", \"v\": \"CA:K1S\"}]** [See the documentation](https://apidocs.hootsuite.com/docs/api/index.html#operation/scheduleMessage) for more information.", optional: true, }, targetingLinkedInCompanySize: { @@ -238,7 +238,7 @@ export default { const facebookPage = {}; if (this.targetingFacebookPageAgeMin) { - facebookPage.ageMin = this.targetingFacebookPageAgeMin; + facebookPage.ageMin = parseInt(this.targetingFacebookPageAgeMin); } if (this.targetingFacebookPageEducation) { facebookPage.education = parseObject(this.targetingFacebookPageEducation); @@ -250,24 +250,52 @@ export default { facebookPage.relationshipStatus = parseObject(this.targetingFacebookPageRelationshipStatus); } if (this.targetingFacebookPageCountry) { - facebookPage.countries = parseObject(this.targetingFacebookPageCountry)?.map((country) => ({ - v: country, - })); + facebookPage.countries = parseObject(this.targetingFacebookPageCountry); } if (this.targetingFacebookPageRegions) { - facebookPage.regions = parseObject(this.targetingFacebookPageRegions)?.map((region) => ({ - v: region, - })); + facebookPage.regions = parseObject(this.targetingFacebookPageRegions); } if (this.targetingFacebookPageCities) { - facebookPage.cities = parseObject(this.targetingFacebookPageCities)?.map((city) => ({ - v: city, - })); + facebookPage.cities = parseObject(this.targetingFacebookPageCities); } if (this.targetingFacebookPageZips) { - facebookPage.zips = parseObject(this.targetingFacebookPageZips)?.map((zip) => ({ - v: zip, - })); + facebookPage.zips = parseObject(this.targetingFacebookPageZips); + } + const linkedInCompany = {}; + if (this.targetingLinkedInCompanySize) { + linkedInCompany.companySize = parseObject(this.targetingLinkedInCompanySize); + } + if (this.targetingLinkedInCompanyGeography) { + linkedInCompany.geography = parseObject(this.targetingLinkedInCompanyGeography); + } + if (this.targetingLinkedInCompanyIndustry) { + linkedInCompany.industry = + parseObject(this.targetingLinkedInCompanyIndustry)?.map((item) => String(item)); + } + if (this.targetingLinkedInCompanyJobFunction) { + linkedInCompany.jobFunction = parseObject(this.targetingLinkedInCompanyJobFunction); + } + if (this.targetingLinkedInCompanySeniority) { + linkedInCompany.seniority = parseObject(this.targetingLinkedInCompanySeniority); + } + + const linkedInV2Company = {}; + if (this.targetingLinkedInV2CompanyLocations) { + linkedInV2Company.locations = parseObject(this.targetingLinkedInV2CompanyLocations); + } + if (this.targetingLinkedInV2CompanyStaffCountRange) { + linkedInV2Company.staffCountRange = + parseObject(this.targetingLinkedInV2CompanyStaffCountRange); + } + if (this.targetingLinkedInV2CompanySeniorities) { + linkedInV2Company.seniorities = parseObject(this.targetingLinkedInV2CompanySeniorities); + } + if (this.targetingLinkedInV2CompanyIndustries) { + linkedInV2Company.industries = parseObject(this.targetingLinkedInV2CompanyIndustries); + } + if (this.targetingLinkedInV2CompanyInterfaceLocations) { + linkedInV2Company.interfaceLocations = + parseObject(this.targetingLinkedInV2CompanyInterfaceLocations); } const response = await this.hootsuite.scheduleMessage({ @@ -284,20 +312,16 @@ export default { facebookPage, } : {}), - linkedInCompany: { - companySize: parseObject(this.targetingLinkedInCompanySize), - geography: parseObject(this.targetingLinkedInCompanyGeography), - industry: parseObject(this.targetingLinkedInCompanyIndustry), - jobFunction: parseObject(this.targetingLinkedInCompanyJobFunction), - seniority: parseObject(this.targetingLinkedInCompanySeniority), - }, - linkedInV2Company: { - locations: parseObject(this.targetingLinkedInV2CompanyLocations), - staffCountRange: parseObject(this.targetingLinkedInV2CompanyStaffCountRange), - seniorities: parseObject(this.targetingLinkedInV2CompanySeniorities), - industries: parseObject(this.targetingLinkedInV2CompanyIndustries), - interfaceLocations: parseObject(this.targetingLinkedInV2CompanyInterfaceLocations), - }, + ...(Object.keys(linkedInCompany).length > 0 + ? { + linkedInCompany, + } + : {}), + ...(Object.keys(linkedInV2Company).length > 0 + ? { + linkedInV2Company, + } + : {}), }, privacy: (this.privacyFacebookVisibility || this.privacyLinkedInVisibility) && { ...(this.privacyFacebookVisibility @@ -320,8 +344,8 @@ export default { : {}), }, location: { - latitude: this.latitude, - longitude: this.longitude, + latitude: parseFloat(this.latitude), + longitude: parseFloat(this.longitude), }, emailNotification: this.emailNotification, mediaUrls: parseObject(this.mediaUrls)?.map((mediaUrl) => ({ diff --git a/components/hootsuite/common/constants.mjs b/components/hootsuite/common/constants.mjs index 56f5100fe4916..19a2dbb104e5f 100644 --- a/components/hootsuite/common/constants.mjs +++ b/components/hootsuite/common/constants.mjs @@ -4,36 +4,36 @@ export const COMPANY_SIZE_OPTIONS = [ value: "self", }, { - label: "1-10", - value: "1 to 10 employees", + label: "1 to 10 employees", + value: "1-10", }, { - label: "11-50", - value: "11 to 50 employees", + label: "11 to 50 employees", + value: "11-50", }, { - label: "51-200", - value: "51 to 200 employees", + label: "51 to 200 employees", + value: "51-200", }, { - label: "201-500", - value: "201 to 500 employees", + label: "201 to 500 employees", + value: "201-500", }, { - label: "501-1000", - value: "501 to 1000 employees", + label: "501 to 1000 employees", + value: "501-1000", }, { - label: "1001-5000", - value: "1001 to 5000 employees", + label: "1001 to 5000 employees", + value: "1001-5000", }, { - label: "5001-10000", - value: "5001 to 10000 employees", + label: "5001 to 10000 employees", + value: "5001-10000", }, { - label: "10001", - value: "10001+ employees", + label: "10001+ employees", + value: "10001", }, ];