Skip to content

feat: Added the Make.com Lead Webhook URL and Added a Yellowish theme to Widget #1041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 14 additions & 113 deletions apps/api/src/app/shared/services/lead.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> {
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<string> {
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<any> {
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<void> {
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);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion apps/web/config/constants.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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...',
};
Expand Down
27 changes: 26 additions & 1 deletion apps/web/pages/imports/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
31 changes: 24 additions & 7 deletions apps/widget/src/components/Common/Container/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)`,
Expand All @@ -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)
Expand All @@ -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': {
Expand All @@ -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)',
},

Expand All @@ -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: {
Expand Down
1 change: 1 addition & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading