diff --git a/apps/api/src/app/shared/services/lead.service.ts b/apps/api/src/app/shared/services/lead.service.ts index f044ec533..2d9ee2d5b 100644 --- a/apps/api/src/app/shared/services/lead.service.ts +++ b/apps/api/src/app/shared/services/lead.service.ts @@ -16,123 +16,24 @@ interface ILeadInformation { @Injectable() export class LeadService { private log = process.env.NODE_ENV === 'local'; - private maAccessTokenDate: Date; - private maAccessToken: string; - private crmAccessTokenDate: Date; - private crmAccessToken: string; - - private async getMaAccessToken(): Promise { - if ( - this.maAccessToken && - this.maAccessTokenDate && - new Date().getTime() - this.maAccessTokenDate.getTime() < 3500000 - ) { - if (this.log) console.log('Using cached ma access token'); - - // 3500000 = 58 minutes - return this.maAccessToken; - } - if (process.env.LEAD_REFRESH_TOKEN && process.env.LEAD_CLIENT_ID && process.env.LEAD_CLIENT_SECRET) { - // eslint-disable-next-line max-len - const url = `https://accounts.zoho.com/oauth/v2/token?client_id=${process.env.LEAD_CLIENT_ID}&grant_type=refresh_token&client_secret=${process.env.LEAD_CLIENT_SECRET}&refresh_token=${process.env.LEAD_REFRESH_TOKEN}`; - if (this.log) console.log('Lead URL', url); - - const response = await axios.post(url); - this.maAccessTokenDate = new Date(); - this.maAccessToken = response.data.access_token; - if (this.log) console.log('New access token generated', this.maAccessToken); - - return response.data.access_token; - } - - return undefined; - } - private async getCRMAccessToken(): Promise { - if ( - this.crmAccessToken && - this.crmAccessTokenDate && - new Date().getTime() - this.crmAccessTokenDate.getTime() < 3500000 - ) { - if (this.log) console.log('Using cached crm access token'); - - // 3500000 = 58 minutes - return this.maAccessToken; - } - if (process.env.CRM_REFRESH_TOKEN && process.env.CRM_CLIENT_ID && process.env.CRM_CLIENT_SECRET) { - // eslint-disable-next-line max-len - const url = `https://accounts.zoho.com/oauth/v2/token?client_id=${process.env.CRM_CLIENT_ID}&grant_type=refresh_token&client_secret=${process.env.CRM_CLIENT_SECRET}&refresh_token=${process.env.CRM_REFRESH_TOKEN}`; - if (this.log) console.log('CRM URL', url); - - const response = await axios.post(url); - this.crmAccessTokenDate = new Date(); - this.crmAccessToken = response.data.access_token; - if (this.log) console.log('New crm token generated', this.crmAccessToken); - - return response.data.access_token; - } - - return undefined; - } - - public async createLead(data: ILeadInformation): Promise { - const maAccessToken = await this.getMaAccessToken(); - if (maAccessToken) { - const leadData = JSON.stringify({ - 'First Name': data['First Name'], - 'Last Name': data['Last Name'], - 'Lead Email': data['Lead Email'], - }); - // Add Lead to marketing automation - // eslint-disable-next-line max-len - const maUrl = `https://marketingautomation.zoho.com/api/v1/json/listsubscribe?listkey=${process.env.LEAD_LIST_KEY}&leadinfo=${leadData}&topic_id=${process.env.LEAD_TOPIC_ID}`; - if (this.log) console.log(maUrl); - - try { - const maResponse = await axios.post( - maUrl, - {}, - { - headers: { - Authorization: `Zoho-oauthtoken ${maAccessToken}`, - }, - } - ); - if (this.log) console.log('Lead created', maResponse.data); - } catch (error) { - captureException(error); - } - } - const crmAccessToken = await this.getCRMAccessToken(); - if (crmAccessToken) { - // Add Lead to Zoho CRM - const crmUrl = `https://www.zohoapis.com/crm/v6/Leads`; - if (this.log) console.log(crmUrl); + public async createLead(data: ILeadInformation): Promise { + if (process.env.LEAD_MAKE_WEBHOOK_URL) { try { - const crmResponse = await axios.post( - crmUrl, - { - data: [ - { - Last_Name: data['Last Name'], - First_Name: data['First Name'], - Email: data['Lead Email'], - Lead_Source: data['Lead Source'], - Signup_Method: data['Signup Method'], - Mentioned_Role: data['Mentioned Role'], - Company_Size: [data['Company Size']], - }, - ], - }, - { - headers: { - Authorization: `Zoho-oauthtoken ${crmAccessToken}`, - }, - } - ); - if (this.log) console.log('CRM LEad created', crmResponse.data); + await axios.post(process.env.LEAD_MAKE_WEBHOOK_URL, { + firstName: data['First Name'], + lastName: data['Last Name'], + email: data['Lead Email'], + signupMethod: data['Signup Method'], + mentionedRole: data['Mentioned Role'], + leadSource: data['Lead Source'], + companySize: data['Company Size'], + createdAt: new Date(), + }); + if (this.log) console.log('Lead data sent to Make.com webhook'); } catch (error) { captureException(error); + console.error('Error sending data to Make.com webhook:', error); } } } diff --git a/apps/web/config/constants.config.ts b/apps/web/config/constants.config.ts index 4b509e954..979a6d817 100644 --- a/apps/web/config/constants.config.ts +++ b/apps/web/config/constants.config.ts @@ -436,6 +436,7 @@ export const HOW_HEARD_ABOUT_US = [ { value: 'Colleague', label: 'Colleague' }, { value: 'Linkdin', label: 'Linkdin' }, { value: 'Invitation', label: 'Invitation' }, + { value: 'AI (ChatGPT, Perplexity, Claude ...)', label: 'AI (ChatGPT, Perplexity, Claude ...)' }, ]; export const PLACEHOLDERS = { @@ -445,7 +446,7 @@ export const PLACEHOLDERS = { fullName: 'John Doe', companySize: 'Only me', role: 'Engineer, Manager, Founder...', - source: 'Google Search, Recommendation...', + source: 'Google Search, AI (ChatGPT, Perplexity, Claude ...), Recommendation...', about: 'Google Search', importName: 'Products, Employees, Assets...', }; diff --git a/apps/web/pages/imports/[id].tsx b/apps/web/pages/imports/[id].tsx index 3a38d6d52..31bf04407 100644 --- a/apps/web/pages/imports/[id].tsx +++ b/apps/web/pages/imports/[id].tsx @@ -48,11 +48,36 @@ function ImportDetails() { templateId: router.query.id as string, }); const { showWidget, isImplerInitiated } = useImpler({ - primaryColor: colors.blue, + primaryColor: colors.faintYellow, templateId: templateData?._id, projectId: templateData?._projectId, accessToken: profileInfo?.accessToken, onUploadComplete: onSpreadsheetImported, + appearance: { + widget: { + backgroundColor: '#1c1917', + }, + fontFamily: 'Inter, sans-serif', + borderRadius: '12px', + primaryButtonConfig: { + backgroundColor: '#f59e0b', + textColor: '#1c1917', + hoverBackground: '#fbbf24', + hoverTextColor: '#1c1917', + borderColor: 'transparent', + hoverBorderColor: 'transparent', + buttonShadow: '0 4px 16px rgba(245, 158, 11, 0.4)', + }, + secondaryButtonConfig: { + backgroundColor: '#292524', + textColor: '#fcd34d', + hoverBackground: '#3c2d2a', + hoverTextColor: '#fed7aa', + borderColor: '#44403c', + hoverBorderColor: '#f59e0b', + buttonShadow: 'none', + }, + }, }); const onImportClick = () => { track({ diff --git a/apps/widget/src/components/Common/Container/Container.tsx b/apps/widget/src/components/Common/Container/Container.tsx index 378bd97c5..142c1c844 100644 --- a/apps/widget/src/components/Common/Container/Container.tsx +++ b/apps/widget/src/components/Common/Container/Container.tsx @@ -586,7 +586,7 @@ export function Container({ children }: PropsWithChildren<{}>) { SegmentedControl: { styles: (theme) => ({ root: { - backgroundColor: theme.fn.rgba(theme.colors[theme.primaryColor][5], 0.06), + backgroundColor: 'var(--stepper-background)', borderRadius: 'var(--border-radius)', padding: '4px', border: `1px solid var(--border-color)`, @@ -596,11 +596,10 @@ export function Container({ children }: PropsWithChildren<{}>) { borderRadius: 'calc(var(--border-radius) - 2px)', border: 'none !important', transition: 'all 0.2s ease', - color: 'var(--text-color) !important', + backgroundColor: 'transparent', '&:not([data-active])': { backgroundColor: 'transparent', - color: 'var(--text-color) !important', '&:hover': { backgroundColor: isColorDark(backgroundColor) @@ -611,7 +610,6 @@ export function Container({ children }: PropsWithChildren<{}>) { '&[data-active]': { backgroundColor: 'var(--button-primary-background) !important', - color: 'var(--button-primary-color) !important', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)', '&:hover': { @@ -622,7 +620,6 @@ export function Container({ children }: PropsWithChildren<{}>) { controlActive: { backgroundColor: 'var(--button-primary-background) !important', - color: 'var(--button-primary-color) !important', boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)', }, @@ -631,16 +628,36 @@ export function Container({ children }: PropsWithChildren<{}>) { fontSize: theme.fontSizes.sm, padding: '8px 16px', transition: 'color 0.2s ease', - color: 'var(--text-color) !important', + // Use secondary text color for inactive labels (more subdued but still visible) + color: 'var(--secondary-text-color) !important', + + // Ensure inactive state uses secondary text color + '[data-active="false"] &': { + color: 'var(--secondary-text-color) !important', + }, + + // Ensure active state uses primary button text color + '[data-active="true"] &': { + color: 'var(--button-primary-color) !important', + }, }, labelActive: { color: 'var(--button-primary-color) !important', fontWeight: 600, }, + + // Additional selector to ensure proper color inheritance + input: { + '&:not(:checked) + label': { + color: 'var(--secondary-text-color) !important', + }, + '&:checked + label': { + color: 'var(--button-primary-color) !important', + }, + }, }), }, - FindReplaceModal: { styles: (theme) => ({ root: { diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 0d0f2f4c4..f17260eb2 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -50,6 +50,7 @@ services: EMAIL_FROM: ${EMAIL_FROM} EMAIL_FROM_NAME: ${EMAIL_FROM_NAME} ALERT_EMAIL_FROM: ${ALERT_EMAIL_FROM} + LEAD_MAKE_WEBHOOK_URL: ${LEAD_MAKE_WEBHOOK_URL} ports: - "3000:3000" networks: