Files
twenty/packages/twenty-chrome-extension/src/options/modules/api-key/components/ApiKeyForm.tsx
Abdullah 1265dc74d0 Closes #2413 - Building a chrome extension for twenty to store person/company data into a workspace. (#3430)
* build: create a new vite project for chrome extension

* feat: configure theme per the frontend codebase for chrome extension

* feat: inject the add to twenty button into linkedin profile page

* feat: create the api key form ui and render it on the options page

* feat: inject the add to twenty button into linkedin company page

* feat: scrape required data from both the user profile and the company profile

* refactor: move modules into options because it is the only page using react for now

* fix: show add to twenty button without having to reload the single page application

* fix: extract domain of the business website instead of scrapping the industry type

* feat: store api key to local storage and open options page when trying to store data without setting a key

* feat: send data to the backend upon click and store it to the database

* fix: open options page upon clicking the extension icon

* fix: update terminology from user to person to match the codebase convention

* fix: adopt chrome extension to monorepo approach using nx and get the development server working

* fix: update vite config for build command to work per the requirement

* feat: add instructions in the readme file to install the extension for local testing

* fix: move server base url to a dotenv file and replace the hard-coded url

* feat: permit user to configure a custom route for the server from the options page

* fix: fetch api key and route from local storage and display on options page to inform users of their choices

* fix: move front base url to dotenv and replace the hard-coded url

* fix: remove the trailing slash from person and company linkedin username

* fix: improve code commenting to explain implementation somewhat better

* ci: introduce a workflow to build chrome extension to ensure it can be published

* fix: format files to display code in a consistent manner per the prettier configuration in codebase

* fix: improve the commenting significantly to explain important and hard-to-understand parts of the code

* fix: remove unused permissions from the manifest file for publishing to the chrome web store

* Add nx

* Fix vale

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-02-12 12:30:23 +01:00

147 lines
3.7 KiB
TypeScript

import styled from '@emotion/styled';
import { H2Title } from '../../ui/display/typography/components/H2Title';
import { useEffect, useState } from 'react';
import { TextInput } from '../../ui/input/components/TextInput';
import { Button } from '../../ui/input/button/Button';
import { Toggle } from '../../ui/input/components/Toggle';
const StyledContainer = styled.div<{ isToggleOn: boolean }>`
width: 400px;
margin: 0 auto;
background-color: ${({ theme }) => theme.background.primary};
padding: ${({ theme }) => theme.spacing(10)};
overflow: hidden;
transition: height 0.3s ease;
height: ${({ isToggleOn }) => (isToggleOn ? '450px' : '390px')};
max-height: ${({ isToggleOn }) => (isToggleOn ? '450px' : '390px')};
`;
const StyledHeader = styled.header`
text-align: center;
margin-bottom: ${({ theme }) => theme.spacing(8)};
`;
const StyledImg = styled.img``;
const StyledMain = styled.main`
margin-bottom: ${({ theme }) => theme.spacing(8)};
`;
const StyledFooter = styled.footer`
display: flex;
`;
const StyledTitleContainer = styled.div`
flex: 0 0 80%;
`;
const StyledToggleContainer = styled.div`
flex: 0 0 20%;
display: flex;
justify-content: flex-end;
`;
const StyledSection = styled.div<{ showSection: boolean }>`
transition:
max-height 0.3s ease,
opacity 0.3s ease;
overflow: hidden;
max-height: ${({ showSection }) => (showSection ? '200px' : '0')};
`;
export const ApiKeyForm = () => {
const [apiKey, setApiKey] = useState('');
const [route, setRoute] = useState('');
const [showSection, setShowSection] = useState(false);
useEffect(() => {
const getState = async () => {
const localStorage = await chrome.storage.local.get();
if (localStorage.apiKey) {
setApiKey(localStorage.apiKey);
}
if (localStorage.serverBaseUrl) {
setRoute(localStorage.serverBaseUrl);
}
};
void getState();
}, []);
useEffect(() => {
chrome.storage.local.set({ apiKey });
}, [apiKey]);
useEffect(() => {
chrome.storage.local.set({ serverBaseUrl: route });
}, [route]);
const handleGenerateClick = () => {
window.open(
`${import.meta.env.VITE_FRONT_BASE_URL}/settings/developers/api-keys`,
);
};
const handleToggle = () => {
setShowSection(!showSection);
};
return (
<StyledContainer isToggleOn={showSection}>
<StyledHeader>
<StyledImg src="/logo/32-32.png" alt="Twenty Logo" />
</StyledHeader>
<StyledMain>
<H2Title
title="Connect your account"
description="Input your key to link the extension to your workspace."
/>
<TextInput
label="Api key"
value={apiKey}
onChange={setApiKey}
placeholder="My API key"
/>
<Button
title="Generate a key"
fullWidth={false}
variant="primary"
accent="default"
size="small"
position="standalone"
soon={false}
disabled={false}
onClick={handleGenerateClick}
/>
</StyledMain>
<StyledFooter>
<StyledTitleContainer>
<H2Title
title="Custom route"
description="For developers interested in self-hosting or local testing of the extension."
/>
</StyledTitleContainer>
<StyledToggleContainer>
<Toggle value={showSection} onChange={handleToggle} />
</StyledToggleContainer>
</StyledFooter>
<StyledSection showSection={showSection}>
{showSection && (
<TextInput
label="Route"
value={route}
onChange={setRoute}
placeholder="My Route"
/>
)}
</StyledSection>
</StyledContainer>
);
};