Files
twenty_crm/packages/twenty-website/src/app/components/PlaygroundTokenForm.tsx
Charles Bochet c15e138d72 Fix nx lint setup (#3234)
* Fix nx lint setup

* Fixes

* Fixes

* Add missing metadata

Fixes

Fix

Fixes

* Fix
2024-01-04 16:39:57 +01:00

191 lines
4.2 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { TbLoader2 } from 'react-icons/tb';
import styled from '@emotion/styled';
import { parseJson } from 'nx/src/utils/json';
export type TokenFormProps = {
setOpenApiJson?: (json: object) => void;
setToken?: (token: string) => void;
isTokenValid: boolean;
setIsTokenValid: (boolean: boolean) => void;
};
const Container = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 90vh;
`;
const Form = styled.form`
text-align: center;
padding: 50px;
`;
const StyledLink = styled.a`
color: #16233f;
text-decoration: none;
position: relative;
font-weight: bold;
transition: color 0.3s ease;
[data-theme='dark'] & {
color: #a3c0f8;
}
`;
const Input = styled.input`
padding: 6px;
margin: 20px 0 5px 0;
max-width: 460px;
width: 100%;
box-sizing: border-box;
background-color: #f3f3f3;
border: 1px solid #ddd;
border-radius: 4px;
[data-theme='dark'] & {
background-color: #16233f;
}
&.invalid {
border: 1px solid #f83e3e;
}
`;
const TokenInvalid = styled.span`
color: #f83e3e;
font-size: 12px;
`;
const Loader = styled(TbLoader2)`
color: #16233f;
font-size: 2rem;
animation: animate 2s infinite;
[data-theme='dark'] & {
color: #a3c0f8;
}
&.not-visible {
visibility: hidden;
}
@keyframes animate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(720deg);
}
}
`;
const LoaderContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 50px;
`;
const TokenForm = ({
setOpenApiJson,
setToken,
isTokenValid,
setIsTokenValid,
}: TokenFormProps) => {
const [isLoading, setIsLoading] = useState(false);
const token =
parseJson(localStorage.getItem('TryIt_securitySchemeValues') || '')
?.bearerAuth ?? '';
const updateToken = async (event: React.ChangeEvent<HTMLInputElement>) => {
localStorage.setItem(
'TryIt_securitySchemeValues',
JSON.stringify({ bearerAuth: event.target.value }),
);
await submitToken(event.target.value);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const validateToken = (openApiJson: any) =>
setIsTokenValid(!!openApiJson.tags);
const getJson = async (token: string) => {
setIsLoading(true);
return await fetch('https://api.twenty.com/open-api', {
headers: { Authorization: `Bearer ${token}` },
})
.then((res) => res.json())
.then((result) => {
validateToken(result);
setIsLoading(false);
return result;
})
.catch(() => setIsLoading(false));
};
const submitToken = async (token: string) => {
if (isLoading) return;
const json = await getJson(token);
setToken && setToken(token);
setOpenApiJson && setOpenApiJson(json);
};
useEffect(() => {
(async () => {
await submitToken(token);
})();
});
// We load playground style using useEffect as it breaks remaining docs style
useEffect(() => {
const styleElement = document.createElement('style');
styleElement.innerHTML = TokenForm.toString();
document.head.append(styleElement);
return () => styleElement.remove();
}, []);
return (
!isTokenValid && (
<Container>
<Form>
<label>
To load your playground schema,{' '}
<StyledLink href="https://app.twenty.com/settings/developers/api-keys">
generate an API key
</StyledLink>{' '}
and paste it here:
</label>
<p>
<Input
className={token && !isLoading ? 'input invalid' : 'input'}
type="text"
readOnly={isLoading}
placeholder="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMD..."
defaultValue={token}
onChange={updateToken}
/>
<TokenInvalid
className={`${(!token || isLoading) && 'not-visible'}`}
>
Token invalid
</TokenInvalid>
<LoaderContainer>
<Loader className={`${!isLoading && 'not-visible'}`} />
</LoaderContainer>
</p>
</Form>
</Container>
)
);
};
export default TokenForm;