feat: providers
This commit is contained in:
parent
fe10030a68
commit
818d172d88
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -0,0 +1,107 @@
|
|||
import { FC } from 'react';
|
||||
import { withProvider } from '@gitroom/frontend/components/launches/providers/high.order.provider';
|
||||
import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration';
|
||||
import { useFormatting } from '@gitroom/frontend/components/launches/helpers/use.formatting';
|
||||
import { useMediaDirectory } from '@gitroom/react/helpers/use.media.directory';
|
||||
import {afterLinkedinCompanyPreventRemove, linkedinCompanyPreventRemove} from "@gitroom/helpers/utils/linkedin.company.prevent.remove";
|
||||
|
||||
const LinkedinPreview: FC = (props) => {
|
||||
const { value: topValue, integration } = useIntegration();
|
||||
const mediaDir = useMediaDirectory();
|
||||
const newValues = useFormatting(topValue, {
|
||||
removeMarkdown: true,
|
||||
saveBreaklines: true,
|
||||
beforeSpecialFunc: (text: string) => {
|
||||
return linkedinCompanyPreventRemove(text);
|
||||
},
|
||||
specialFunc: (text: string) => {
|
||||
return afterLinkedinCompanyPreventRemove(text.slice(0, 280));
|
||||
},
|
||||
});
|
||||
|
||||
const [firstPost, ...morePosts] = newValues;
|
||||
if (!firstPost) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-[8px] flex flex-col gap-[8px] border border-black/90 w-[555px] pt-[12px] pl-[16px] pb-[12px] pr-[40px] bg-white text-black font-['helvetica']">
|
||||
<div className="flex gap-[8px]">
|
||||
<div className="w-[48px] h-[48px]">
|
||||
<img
|
||||
src={integration?.picture}
|
||||
alt="x"
|
||||
className="rounded-full w-full h-full relative z-[2]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col leading-[16px]">
|
||||
<div className="text-[14px] font-[600]">{integration?.name}</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">
|
||||
CEO @ Gitroom
|
||||
</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">1m</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<pre className="font-['helvetica'] text-[14px] font-[400] text-wrap" dangerouslySetInnerHTML={{__html: firstPost?.text}} />
|
||||
|
||||
{!!firstPost?.images?.length && (
|
||||
<div className="-ml-[16px] -mr-[40px] flex-1 h-[555px] flex overflow-hidden mt-[12px] gap-[2px]">
|
||||
{firstPost.images.map((image, index) => (
|
||||
<a
|
||||
key={`image_${index}`}
|
||||
href={mediaDir.set(image.path)}
|
||||
className="flex-1"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src={mediaDir.set(image.path)}
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{morePosts.map((p, index) => (
|
||||
<div className="flex gap-[8px]" key={index}>
|
||||
<div className="w-[40px] h-[40px]">
|
||||
<img
|
||||
src={integration?.picture}
|
||||
alt="x"
|
||||
className="rounded-full w-full h-full relative z-[2]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col leading-[16px] bg-[#F2F2F2] w-full pt-[8px] pr-[64px] pl-[12px] pb-[8px] rounded-[8px]">
|
||||
<div className="text-[14px] font-[600]">{integration?.name}</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">
|
||||
CEO @ Gitroom
|
||||
</div>
|
||||
<div className="text-[14px] mt-[8px] font-[400] text-black/90">
|
||||
{p.text}
|
||||
</div>
|
||||
|
||||
{!!p?.images?.length && (
|
||||
<div className="w-full h-[120px] flex overflow-hidden mt-[12px] gap-[2px]">
|
||||
{p.images.map((image, index) => (
|
||||
<a
|
||||
key={`image_${index}`}
|
||||
href={mediaDir.set(image.path)}
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
className="w-[120px] h-full object-cover"
|
||||
src={mediaDir.set(image.path)}
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, LinkedinPreview);
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
import { FC } from 'react';
|
||||
import { withProvider } from '@gitroom/frontend/components/launches/providers/high.order.provider';
|
||||
import { useIntegration } from '@gitroom/frontend/components/launches/helpers/use.integration';
|
||||
import { useFormatting } from '@gitroom/frontend/components/launches/helpers/use.formatting';
|
||||
import { useMediaDirectory } from '@gitroom/react/helpers/use.media.directory';
|
||||
import {afterLinkedinCompanyPreventRemove, linkedinCompanyPreventRemove} from "@gitroom/helpers/utils/linkedin.company.prevent.remove";
|
||||
|
||||
const FacebookPreview: FC = (props) => {
|
||||
const { value: topValue, integration } = useIntegration();
|
||||
const mediaDir = useMediaDirectory();
|
||||
const newValues = useFormatting(topValue, {
|
||||
removeMarkdown: true,
|
||||
saveBreaklines: true,
|
||||
beforeSpecialFunc: (text: string) => {
|
||||
return linkedinCompanyPreventRemove(text);
|
||||
},
|
||||
specialFunc: (text: string) => {
|
||||
return afterLinkedinCompanyPreventRemove(text.slice(0, 280));
|
||||
},
|
||||
});
|
||||
|
||||
const [firstPost, ...morePosts] = newValues;
|
||||
if (!firstPost) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-[8px] flex flex-col gap-[8px] border border-black/90 w-[555px] pt-[12px] pl-[16px] pb-[12px] pr-[40px] bg-white text-black font-['helvetica']">
|
||||
<div className="flex gap-[8px]">
|
||||
<div className="w-[48px] h-[48px]">
|
||||
<img
|
||||
src={integration?.picture}
|
||||
alt="x"
|
||||
className="rounded-full w-full h-full relative z-[2]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col leading-[16px]">
|
||||
<div className="text-[14px] font-[600]">{integration?.name}</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">
|
||||
CEO @ Gitroom
|
||||
</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">1m</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<pre className="font-['helvetica'] text-[14px] font-[400] text-wrap" dangerouslySetInnerHTML={{__html: firstPost?.text}} />
|
||||
|
||||
{!!firstPost?.images?.length && (
|
||||
<div className="-ml-[16px] -mr-[40px] flex-1 h-[555px] flex overflow-hidden mt-[12px] gap-[2px]">
|
||||
{firstPost.images.map((image, index) => (
|
||||
<a
|
||||
key={`image_${index}`}
|
||||
href={mediaDir.set(image.path)}
|
||||
className="flex-1"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src={mediaDir.set(image.path)}
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{morePosts.map((p, index) => (
|
||||
<div className="flex gap-[8px]" key={index}>
|
||||
<div className="w-[40px] h-[40px]">
|
||||
<img
|
||||
src={integration?.picture}
|
||||
alt="x"
|
||||
className="rounded-full w-full h-full relative z-[2]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col leading-[16px] bg-[#F2F2F2] w-full pt-[8px] pr-[64px] pl-[12px] pb-[8px] rounded-[8px]">
|
||||
<div className="text-[14px] font-[600]">{integration?.name}</div>
|
||||
<div className="text-[12px] font-[400] text-black/60">
|
||||
CEO @ Gitroom
|
||||
</div>
|
||||
<div className="text-[14px] mt-[8px] font-[400] text-black/90">
|
||||
{p.text}
|
||||
</div>
|
||||
|
||||
{!!p?.images?.length && (
|
||||
<div className="w-full h-[120px] flex overflow-hidden mt-[12px] gap-[2px]">
|
||||
{p.images.map((image, index) => (
|
||||
<a
|
||||
key={`image_${index}`}
|
||||
href={mediaDir.set(image.path)}
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
className="w-[120px] h-full object-cover"
|
||||
src={mediaDir.set(image.path)}
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, FacebookPreview);
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
import {
|
||||
AuthTokenDetails,
|
||||
PostDetails,
|
||||
PostResponse,
|
||||
SocialProvider,
|
||||
} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
|
||||
|
||||
export class FacebookProvider implements SocialProvider {
|
||||
identifier = 'facebook';
|
||||
name = 'Facebook';
|
||||
async refreshToken(refresh_token: string): Promise<AuthTokenDetails> {
|
||||
const { access_token, expires_in, ...all } = await (
|
||||
await fetch(
|
||||
'https://graph.facebook.com/v19.0/oauth/access_token' +
|
||||
'?grant_type=fb_exchange_token' +
|
||||
`&client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&client_secret=${process.env.FACEBOOK_APP_SECRET}` +
|
||||
`&fb_exchange_token=${refresh_token}`
|
||||
)
|
||||
).json();
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
picture: {
|
||||
data: { url },
|
||||
},
|
||||
} = await (
|
||||
await fetch(
|
||||
`https://graph.facebook.com/v19.0/me?fields=id,name,picture&access_token=${access_token}`
|
||||
)
|
||||
).json();
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
accessToken: access_token,
|
||||
refreshToken: access_token,
|
||||
expiresIn: expires_in,
|
||||
picture: url,
|
||||
username: '',
|
||||
};
|
||||
}
|
||||
|
||||
async generateAuthUrl() {
|
||||
const state = makeId(6);
|
||||
return {
|
||||
url:
|
||||
'https://www.facebook.com/v19.0/dialog/oauth' +
|
||||
`?client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/facebook`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
'&scope=email,public_profile',
|
||||
// '&scope=email,public_profile,pages_manage_posts,pages_read_engagement,publish_to_groups,groups_access_member_info',
|
||||
codeVerifier: makeId(10),
|
||||
state,
|
||||
};
|
||||
}
|
||||
|
||||
async authenticate(params: { code: string; codeVerifier: string }) {
|
||||
const getAccessToken = await (
|
||||
await fetch(
|
||||
'https://graph.facebook.com/v19.0/oauth/access_token' +
|
||||
`?client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&redirect_uri=${encodeURIComponent(
|
||||
`${process.env.FRONTEND_URL}/integrations/social/facebook`
|
||||
)}` +
|
||||
`&client_secret=${process.env.FACEBOOK_APP_SECRET}` +
|
||||
`&code=${params.code}`
|
||||
)
|
||||
).json();
|
||||
|
||||
const { access_token, expires_in, ...all } = await (
|
||||
await fetch(
|
||||
'https://graph.facebook.com/v19.0/oauth/access_token' +
|
||||
'?grant_type=fb_exchange_token' +
|
||||
`&client_id=${process.env.FACEBOOK_APP_ID}` +
|
||||
`&client_secret=${process.env.FACEBOOK_APP_SECRET}` +
|
||||
`&fb_exchange_token=${getAccessToken.access_token}`
|
||||
)
|
||||
).json();
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
picture: {
|
||||
data: { url },
|
||||
},
|
||||
} = await (
|
||||
await fetch(
|
||||
`https://graph.facebook.com/v19.0/me?fields=id,name,picture&access_token=${access_token}`
|
||||
)
|
||||
).json();
|
||||
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
accessToken: access_token,
|
||||
refreshToken: access_token,
|
||||
expiresIn: expires_in,
|
||||
picture: url,
|
||||
username: '',
|
||||
};
|
||||
}
|
||||
|
||||
async post(
|
||||
id: string,
|
||||
accessToken: string,
|
||||
postDetails: PostDetails[]
|
||||
): Promise<PostResponse[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue