Files
twenty/packages/twenty-chrome-extension/src/contentScript/extractPersonProfile.ts

141 lines
4.7 KiB
TypeScript

import { createDefaultButton } from '~/contentScript/createButton';
import changeSidePanelUrl from '~/contentScript/utils/changeSidepanelUrl';
import extractFirstAndLastName from '~/contentScript/utils/extractFirstAndLastName';
import { createPerson, fetchPerson } from '~/db/person.db';
import { PersonInput } from '~/db/types/person.types';
import { isDefined } from '~/utils/isDefined';
export const checkIfPersonExists = async () => {
const { tab: activeTab } = await chrome.runtime.sendMessage({
action: 'getActiveTab',
});
let activeTabUrl = '';
if (isDefined(activeTab.url.endsWith('/'))) {
activeTabUrl = activeTab.url.slice(0, -1);
}
const personNameElement = document.querySelector('.text-heading-xlarge');
const personName = personNameElement ? personNameElement.textContent : '';
const { firstName, lastName } = extractFirstAndLastName(String(personName));
const person = await fetchPerson({
name: {
firstName: { eq: firstName },
lastName: { eq: lastName },
},
linkedinLink: { url: { eq: activeTabUrl }, label: { eq: activeTabUrl } },
});
return person;
};
export const addPerson = async () => {
const personNameElement = document.querySelector('.text-heading-xlarge');
const separatorElement = document.querySelector(
'.pv-text-details__separator',
);
const personCityElement = separatorElement?.previousElementSibling;
const profilePictureElement = document.querySelector(
'.pv-top-card-profile-picture__image',
);
const firstListItem = document.querySelector(
'div[data-view-name="profile-component-entity"]',
);
const secondDivElement = firstListItem?.querySelector('div:nth-child(2)');
const ariaHiddenSpan = secondDivElement?.querySelector(
'span[aria-hidden="true"]',
);
// Get the text content or other necessary data from the DOM elements.
const personName = personNameElement ? personNameElement.textContent : '';
const personCity = personCityElement
? personCityElement.textContent?.trim().replace(/\s+/g, ' ').split(',')[0]
: '';
const profilePicture = profilePictureElement
? profilePictureElement?.getAttribute('src')
: '';
const jobTitle = ariaHiddenSpan ? ariaHiddenSpan.textContent?.trim() : '';
const { firstName, lastName } = extractFirstAndLastName(String(personName));
// Prepare person data to send to the backend.
const personData: PersonInput = {
name: { firstName, lastName },
city: personCity ?? '',
avatarUrl: profilePicture ?? '',
jobTitle: jobTitle ?? '',
linkedinLink: { url: '', label: '' },
};
// Extract active tab url using chrome API - an event is triggered here and is caught by background script.
const { tab: activeTab } = await chrome.runtime.sendMessage({
action: 'getActiveTab',
});
let activeTabUrl = '';
// Remove last slash from the URL for consistency when saving usernames.
if (isDefined(activeTab.url.endsWith('/'))) {
activeTabUrl = activeTab.url.slice(0, -1);
}
personData.linkedinLink = { url: activeTabUrl, label: activeTabUrl };
const personId = await createPerson(personData);
if (isDefined(personId)) {
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/person/${personId}`,
);
}
return personId;
};
export const insertButtonForPerson = async () => {
const personButtonDiv = createDefaultButton('twenty-person-btn');
if (isDefined(personButtonDiv)) {
const addedProfileDiv: HTMLDivElement | null = document.querySelector(
'.pv-top-card-v2-ctas__custom',
);
if (isDefined(addedProfileDiv)) {
Object.assign(personButtonDiv.style, {
marginRight: '.8rem',
});
addedProfileDiv.prepend(personButtonDiv);
}
const personButtonSpan = personButtonDiv.getElementsByTagName('span')[0];
const person = await checkIfPersonExists();
const openPersonOnSidePanel = (personId: string) => {
personButtonSpan.textContent = 'View in Twenty';
personButtonDiv.onClickHandler(async () => {
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/person/${personId}`,
);
chrome.runtime.sendMessage({ action: 'openSidepanel' });
});
};
if (isDefined(person)) {
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/person/${person.id}`,
);
if (isDefined(person.id)) openPersonOnSidePanel(person.id);
} else {
personButtonSpan.textContent = 'Add to Twenty';
personButtonDiv.onClickHandler(async () => {
personButtonSpan.textContent = 'Saving...';
const personId = await addPerson();
if (isDefined(personId)) openPersonOnSidePanel(personId);
else personButtonSpan.textContent = 'Try again';
});
}
}
};