From 7d3302e3b84d9623cfd18328296b2031bf8bb2f1 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Wed, 29 May 2024 21:40:10 +0700 Subject: [PATCH] feat: pinterest --- .../src/api/routes/posts.controller.ts | 1 + .../public/icons/platforms/pinterest.png | Bin 0 -> 1745 bytes apps/frontend/public/postiz-text.svg | 6 + apps/frontend/public/postiz.svg | 6 + .../components/launches/add.edit.model.tsx | 4 +- .../providers/pinterest/pinterest.board.tsx | 47 ++++ .../pinterest/pinterest.provider.tsx | 135 +++++++++++ .../launches/providers/show.all.providers.tsx | 2 + .../src/components/layout/layout.settings.tsx | 7 +- .../src/dtos/posts/create.post.dto.ts | 2 + .../all.providers.settings.ts | 6 +- .../providers-settings/dev.to.settings.dto.ts | 4 +- ...ettings.ts => dev.to.tags.settings.dto.ts} | 2 +- .../posts/providers-settings/pinterest.dto.ts | 32 +++ .../youtube.settings.dto.ts | 1 - .../src/integrations/integration.manager.ts | 2 + .../integrations/social/instagram.provider.ts | 4 +- .../integrations/social/pinterest.provider.ts | 222 ++++++++++++++++++ .../src/form/color.picker.tsx | 68 ++++++ package-lock.json | 10 + package.json | 1 + 21 files changed, 549 insertions(+), 13 deletions(-) create mode 100644 apps/frontend/public/icons/platforms/pinterest.png create mode 100644 apps/frontend/public/postiz-text.svg create mode 100644 apps/frontend/public/postiz.svg create mode 100644 apps/frontend/src/components/launches/providers/pinterest/pinterest.board.tsx create mode 100644 apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx rename libraries/nestjs-libraries/src/dtos/posts/providers-settings/{dev.to.tags.settings.ts => dev.to.tags.settings.dto.ts} (77%) create mode 100644 libraries/nestjs-libraries/src/dtos/posts/providers-settings/pinterest.dto.ts create mode 100644 libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts create mode 100644 libraries/react-shared-libraries/src/form/color.picker.tsx diff --git a/apps/backend/src/api/routes/posts.controller.ts b/apps/backend/src/api/routes/posts.controller.ts index 7ad68fda..8814a6b0 100644 --- a/apps/backend/src/api/routes/posts.controller.ts +++ b/apps/backend/src/api/routes/posts.controller.ts @@ -87,6 +87,7 @@ export class PostsController { @GetOrgFromRequest() org: Organization, @Body() body: CreatePostDto ) { + console.log(JSON.stringify(body, null, 2)); return this._postsService.createPost(org.id, body); } diff --git a/apps/frontend/public/icons/platforms/pinterest.png b/apps/frontend/public/icons/platforms/pinterest.png new file mode 100644 index 0000000000000000000000000000000000000000..eadb872fda2dfee1e0b793204bf284c284dfce9b GIT binary patch literal 1745 zcmV;?1}^!DP)8uIdjE9S+2PXAU|pYN`-4g zt~6XDa;4#_A!5#kQmt$hDKt*rd5I4xED)vJ$I=ne8e7K^fWM-KIiLC@p=C?(*Vkc| zmxI=%$Hz(Z_7QD6L#*pOwjITw3?Yj*qXa|*N+rRNEd0thslESRD!_6wY^v8Ylztl`>WC$tBKons`aW}ihR+E%3Tgi%No}%imJ3x4|Cf?n{+YfFh(s}?x zgb)R~TMP1H7A5plb0 zd`eb_3BZ{7mJD{sWAsK8N)95tpaCppkh=boQ~&hDkZx`qXJ-Qn4+f{4^_ z{GLnHcHbsY4hVr#Hp_NA%-VCOXgYI@FSH$_`p$KE6lsL87}|f3^!RvIy=hRjejP|} zrg{2WD~Dj?QUZ(WGqRD^*Lk<24Jpe2sQ%hImjC7#So5acrEGBnjk_O12K;$-#(Fw& zCSxvH<=Q4!0x3BWhXgen?sm!gn_tEv1ZcFfS+euT2+JK4!KF(OW^T#_P(X6^%idaYIv>RxRG<{UAZOU2a#1o)ZUY!C^$yA<+StSBiWj4du z(Mi;M*+pxIKtn^`b%_fX(P?`|o&Kr?c_zFiQ%^($kcvdIW77n~$jmzNc;0pIo;Zn0 z<=J(>#D{U6yDG3JqG*p7q9-B}!T9kLnXy%I9lq+h00?O?6}gnNMy1lc(|UNu9S+pg zAp<^_EZ%hi)T|OICXVv-gi&Vw{_pSmlSEVN~4uRsWi5lr1tjpG(P@F z&i7|FZpNU@vrR=cR*s4R5-BXwI?nCAeUvS7-z7Sg=G?B`48Hst_Cyr3axRM=+{DtK z?!*YXOZB&ZxPzV-p2v^@yrRffmrPKa6=80T^yZW&?;{l%B0V~WziwepHwiHC;w!Xo z*^0oTkPfl<_ZT5SL-;eF2APe8)X*>^t*>XszUnGMD?Xk>LfbaoPyLQF4?P50QV0ns z(F2`E5&rCISH&9d?&j!ix6<{*uSk!K=B#mIF(NJdId=1xIs3@NNZ~K|;Q>nYt|d*2 z@T!%rOK<$hF*J&f#~-Elncq|O^{*1Tp%JYdCfm<4`j59rTNgQ*+)nVll=Wi zsZex`Xys7$q4Is=WE&24$#(mHLGeUzT&*ua*Au_QD&SHp1|`T^3iAW~M53pU(IZC? za&}$m!zcj}fl5wgMgyOBt13;K&-Qi&ON(5KOB?-B{&g-Wd9%l zC)VGM!2G`k`THpTM5H7+FhKkFw-D<(kCge}uVx#?7mWaD9F-`^4P7Wo^b=2fq$J=f n`m1}5$d!g`M6NVkHAMakpNmkQVe30700000NkvXXu0mjff@n>f literal 0 HcmV?d00001 diff --git a/apps/frontend/public/postiz-text.svg b/apps/frontend/public/postiz-text.svg new file mode 100644 index 00000000..26c46d62 --- /dev/null +++ b/apps/frontend/public/postiz-text.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/frontend/public/postiz.svg b/apps/frontend/public/postiz.svg new file mode 100644 index 00000000..d2495e61 --- /dev/null +++ b/apps/frontend/public/postiz.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/frontend/src/components/launches/add.edit.model.tsx b/apps/frontend/src/components/launches/add.edit.model.tsx index 4e6b7c88..a88f1e88 100644 --- a/apps/frontend/src/components/launches/add.edit.model.tsx +++ b/apps/frontend/src/components/launches/add.edit.model.tsx @@ -259,12 +259,12 @@ export const AddEditModal: FC<{ // @ts-ignore const images = key?.value[0].image; if ( - (images?.length || 0) > (key.maximumMediaRequirements || 0) || + (images?.length || 0) > (key.maximumMediaRequirements || 100000) || (images?.length || 0) < (key.minimumMediaRequirements || 0) ) { toaster.show( `The amount of ${capitalize(key?.integration?.identifier)} media attached supposed to be ${ - key.maximumMediaRequirements === key.minimumMediaRequirements + (key.maximumMediaRequirements === key.minimumMediaRequirements) || !key.maximumMediaRequirements ? key.minimumMediaRequirements : `between ${key.minimumMediaRequirements} to ${key.maximumMediaRequirements}` }`, diff --git a/apps/frontend/src/components/launches/providers/pinterest/pinterest.board.tsx b/apps/frontend/src/components/launches/providers/pinterest/pinterest.board.tsx new file mode 100644 index 00000000..40047435 --- /dev/null +++ b/apps/frontend/src/components/launches/providers/pinterest/pinterest.board.tsx @@ -0,0 +1,47 @@ +import { FC, useEffect, useState } from 'react'; +import { useCustomProviderFunction } from '@gitroom/frontend/components/launches/helpers/use.custom.provider.function'; +import { Select } from '@gitroom/react/form/select'; +import { useSettings } from '@gitroom/frontend/components/launches/helpers/use.values'; + +export const PinterestBoard: FC<{ + name: string; + onChange: (event: { target: { value: string; name: string } }) => void; +}> = (props) => { + const { onChange, name } = props; + const customFunc = useCustomProviderFunction(); + const [orgs, setOrgs] = useState(); + const { getValues } = useSettings(); + const [currentMedia, setCurrentMedia] = useState(); + + const onChangeInner = (event: { target: { value: string, name: string } }) => { + setCurrentMedia(event.target.value); + onChange(event); + }; + + useEffect(() => { + customFunc.get('boards').then((data) => setOrgs(data)); + const settings = getValues()[props.name]; + if (settings) { + setCurrentMedia(settings); + } + }, []); + + if (!orgs) { + return null; + } + + if (!orgs.length) { + return 'No boards found, you have to create a board first'; + } + + return ( + + ); +}; diff --git a/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx b/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx new file mode 100644 index 00000000..b883e18c --- /dev/null +++ b/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx @@ -0,0 +1,135 @@ +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'; +import { VideoOrImage } from '@gitroom/react/helpers/video.or.image'; +import { useSettings } from '@gitroom/frontend/components/launches/helpers/use.values'; +import { PinterestBoard } from '@gitroom/frontend/components/launches/providers/pinterest/pinterest.board'; +import { PinterestSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/pinterest.dto'; +import { Input } from '@gitroom/react/form/input'; +import { ColorPicker } from '@gitroom/react/form/color.picker'; + +const PinterestSettings: FC = () => { + const { register, control } = useSettings(); + return ( +
+ + + + +
+ ); +}; +const PinterestPreview: 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 ( +
+
+
+ x +
+
+
{integration?.name}
+
+ CEO @ Gitroom +
+
1m
+
+
+
+
+
+        {!!firstPost?.images?.length && (
+          
+ {firstPost.images.map((image, index) => ( + + + + ))} +
+ )} +
+ {morePosts.map((p, index) => ( +
+
+ x +
+
+
{integration?.name}
+
+ CEO @ Gitroom +
+
+ {p.text} +
+ + {!!p?.images?.length && ( +
+ {p.images.map((image, index) => ( + +
+ +
+
+ ))} +
+ )} +
+
+ ))} +
+ ); +}; + +export default withProvider( + PinterestSettings, + PinterestPreview, + PinterestSettingsDto, + undefined, + 1 +); diff --git a/apps/frontend/src/components/launches/providers/show.all.providers.tsx b/apps/frontend/src/components/launches/providers/show.all.providers.tsx index 0df12fd5..a4996015 100644 --- a/apps/frontend/src/components/launches/providers/show.all.providers.tsx +++ b/apps/frontend/src/components/launches/providers/show.all.providers.tsx @@ -10,6 +10,7 @@ import FacebookProvider from '@gitroom/frontend/components/launches/providers/fa import InstagramProvider from '@gitroom/frontend/components/launches/providers/instagram/instagram.provider'; import YoutubeProvider from '@gitroom/frontend/components/launches/providers/youtube/youtube.provider'; import TiktokProvider from '@gitroom/frontend/components/launches/providers/tiktok/tiktok.provider'; +import PinterestProvider from '@gitroom/frontend/components/launches/providers/pinterest/pinterest.provider'; export const Providers = [ {identifier: 'devto', component: DevtoProvider}, @@ -22,6 +23,7 @@ export const Providers = [ {identifier: 'instagram', component: InstagramProvider}, {identifier: 'youtube', component: YoutubeProvider}, {identifier: 'tiktok', component: TiktokProvider}, + {identifier: 'pinterest', component: PinterestProvider}, ]; diff --git a/apps/frontend/src/components/layout/layout.settings.tsx b/apps/frontend/src/components/layout/layout.settings.tsx index 3a8751d1..e2ff36a8 100644 --- a/apps/frontend/src/components/layout/layout.settings.tsx +++ b/apps/frontend/src/components/layout/layout.settings.tsx @@ -27,6 +27,7 @@ import { Support } from '@gitroom/frontend/components/layout/support'; import { ContinueProvider } from '@gitroom/frontend/components/layout/continue.provider'; import { isGeneral } from '@gitroom/react/helpers/is.general'; import { Impersonate } from '@gitroom/frontend/components/layout/impersonate'; +import clsx from 'clsx'; dayjs.extend(utc); dayjs.extend(weekOfYear); @@ -62,10 +63,10 @@ export const LayoutSettings = ({ children }: { children: ReactNode }) => { {user?.admin && }
-
- Logo +
+ Logo
-
{isGeneral() ? 'Postiz' : 'Gitroom'}
+
{isGeneral() ? : 'Gitroom'}
{user?.orgId ? :
}
diff --git a/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts index 92777a35..c314c473 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts @@ -9,6 +9,7 @@ import {MediumSettingsDto} from "@gitroom/nestjs-libraries/dtos/posts/providers- import {HashnodeSettingsDto} from "@gitroom/nestjs-libraries/dtos/posts/providers-settings/hashnode.settings.dto"; import {RedditSettingsDto} from "@gitroom/nestjs-libraries/dtos/posts/providers-settings/reddit.dto"; import { YoutubeSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/youtube.settings.dto'; +import { PinterestSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/pinterest.dto'; export class EmptySettings {} export class Integration { @@ -62,6 +63,7 @@ export class Post { { value: HashnodeSettingsDto, name: 'hashnode' }, { value: RedditSettingsDto, name: 'reddit' }, { value: YoutubeSettingsDto, name: 'youtube' }, + { value: PinterestSettingsDto, name: 'pinterest' }, ], }, }) diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/all.providers.settings.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/all.providers.settings.ts index 8801f4d9..042e3ad7 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/all.providers.settings.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/all.providers.settings.ts @@ -2,9 +2,13 @@ import { DevToSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers import { MediumSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/medium.settings.dto'; import { HashnodeSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/hashnode.settings.dto'; import { RedditSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/reddit.dto'; +import { PinterestSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/pinterest.dto'; +import { YoutubeSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/youtube.settings.dto'; export type AllProvidersSettings = | DevToSettingsDto | MediumSettingsDto | HashnodeSettingsDto - | RedditSettingsDto; + | RedditSettingsDto + | YoutubeSettingsDto + | PinterestSettingsDto; diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.settings.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.settings.dto.ts index 9cf51fa1..deb048d9 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.settings.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.settings.dto.ts @@ -11,7 +11,7 @@ import { } from 'class-validator'; import { MediaDto } from '@gitroom/nestjs-libraries/dtos/media/media.dto'; import { Type } from 'class-transformer'; -import { DevToTagsSettings } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/dev.to.tags.settings'; +import { DevToTagsSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/dev.to.tags.settings.dto'; export class DevToSettingsDto { @IsString() @@ -42,5 +42,5 @@ export class DevToSettingsDto { @IsArray() @ArrayMaxSize(4) @IsOptional() - tags: DevToTagsSettings[]; + tags: DevToTagsSettingsDto[]; } diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.dto.ts similarity index 77% rename from libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.ts rename to libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.dto.ts index f71b241e..688fb284 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/dev.to.tags.settings.dto.ts @@ -1,6 +1,6 @@ import {IsNumber, IsString} from "class-validator"; -export class DevToTagsSettings { +export class DevToTagsSettingsDto { @IsNumber() value: number; diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/pinterest.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/pinterest.dto.ts new file mode 100644 index 00000000..7f3ff938 --- /dev/null +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/pinterest.dto.ts @@ -0,0 +1,32 @@ +import { IsDefined, IsOptional, IsString, IsUrl, MinLength, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; + +export class PinterestSettingsDto { + @IsString() + @IsOptional() + title: string; + + @IsString() + @IsOptional() + description: string; + + @IsString() + @IsOptional() + @IsUrl() + link: string; + + @IsString() + @IsOptional() + dominant_color: string; + + @IsDefined({ + message: 'Board is required' + }) + @IsString({ + message: 'Board is required' + }) + @MinLength(1, { + message: 'Board is required' + }) + board: string; +} diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/youtube.settings.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/youtube.settings.dto.ts index 27dbfd42..d4fd7c67 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/youtube.settings.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/youtube.settings.dto.ts @@ -1,5 +1,4 @@ import { - ArrayMaxSize, IsArray, IsDefined, IsOptional, diff --git a/libraries/nestjs-libraries/src/integrations/integration.manager.ts b/libraries/nestjs-libraries/src/integrations/integration.manager.ts index 50b5c138..efa47538 100644 --- a/libraries/nestjs-libraries/src/integrations/integration.manager.ts +++ b/libraries/nestjs-libraries/src/integrations/integration.manager.ts @@ -11,6 +11,7 @@ import { FacebookProvider } from '@gitroom/nestjs-libraries/integrations/social/ import { InstagramProvider } from '@gitroom/nestjs-libraries/integrations/social/instagram.provider'; import { YoutubeProvider } from '@gitroom/nestjs-libraries/integrations/social/youtube.provider'; import { TiktokProvider } from '@gitroom/nestjs-libraries/integrations/social/tiktok.provider'; +import { PinterestProvider } from '@gitroom/nestjs-libraries/integrations/social/pinterest.provider'; const socialIntegrationList = [ new XProvider(), @@ -20,6 +21,7 @@ const socialIntegrationList = [ new InstagramProvider(), new YoutubeProvider(), new TiktokProvider(), + new PinterestProvider() ]; const articleIntegrationList = [ diff --git a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts index 9515792f..8f11cca8 100644 --- a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts @@ -219,7 +219,7 @@ export class InstagramProvider implements SocialProvider { let containerIdGlobal = ''; let linkGlobal = ''; if (medias.length === 1) { - const { id: mediaId, ...all } = await ( + const { id: mediaId } = await ( await fetch( `https://graph.facebook.com/v20.0/${id}/media_publish?creation_id=${medias[0]}&access_token=${accessToken}&field=id`, { @@ -228,8 +228,6 @@ export class InstagramProvider implements SocialProvider { ) ).json(); - console.log(all); - containerIdGlobal = mediaId; const { permalink } = await ( diff --git a/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts new file mode 100644 index 00000000..3708702f --- /dev/null +++ b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts @@ -0,0 +1,222 @@ +import { + AuthTokenDetails, + PostDetails, + PostResponse, + SocialProvider, +} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; +import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; +import { timer } from '@gitroom/helpers/utils/timer'; +import dayjs from 'dayjs'; +import { PinterestSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/pinterest.dto'; +import axios from 'axios'; +import FormData from 'form-data'; +const form = new FormData(); + +export class PinterestProvider implements SocialProvider { + identifier = 'pinterest'; + name = 'Pinterest'; + isBetweenSteps = false; + + async refreshToken(refresh_token: string): Promise { + return { + refreshToken: '', + expiresIn: 0, + accessToken: '', + id: '', + name: '', + picture: '', + username: '', + }; + } + + async generateAuthUrl(refresh?: string) { + const state = makeId(6); + return { + url: `https://www.pinterest.com/oauth/?client_id=${ + process.env.PINTEREST_CLIENT_ID + }&redirect_uri=${encodeURIComponent( + `${process.env.FRONTEND_URL}/integrations/social/pinterest${ + refresh ? `?refresh=${refresh}` : '' + }` + )}&response_type=code&scope=${encodeURIComponent( + 'boards:read,boards:write,pins:read,pins:write,user_accounts:read' + )}&state=${state}`, + codeVerifier: makeId(10), + state, + }; + } + + async authenticate(params: { + code: string; + codeVerifier: string; + refresh: string; + }) { + const { access_token, refresh_token, expires_in } = await ( + await fetch('https://api-sandbox.pinterest.com/v5/oauth/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: `Basic ${Buffer.from( + `${process.env.PINTEREST_CLIENT_ID}:${process.env.PINTEREST_CLIENT_SECRET}` + ).toString('base64')}`, + }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + code: params.code, + redirect_uri: `${process.env.FRONTEND_URL}/integrations/social/pinterest`, + }), + }) + ).json(); + + const { id, profile_image, username } = await ( + await fetch('https://api-sandbox.pinterest.com/v5/user_account', { + method: 'GET', + headers: { + Authorization: `Bearer ${access_token}`, + }, + }) + ).json(); + + return { + id: id, + name: username, + accessToken: access_token, + refreshToken: refresh_token, + expiresIn: expires_in, + picture: profile_image, + username, + }; + } + + async boards(accessToken: string) { + const { items } = await ( + await fetch('https://api-sandbox.pinterest.com/v5/boards', { + method: 'GET', + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }) + ).json(); + + return ( + items?.map((item: any) => ({ + name: item.name, + id: item.id, + })) || [] + ); + } + + async post( + id: string, + accessToken: string, + postDetails: PostDetails[] + ): Promise { + let mediaId = ''; + if ((postDetails?.[0]?.media?.[0]?.path?.indexOf('mp4') || -1) > -1) { + const { upload_url, media_id, upload_parameters } = await ( + await fetch('https://api-sandbox.pinterest.com/v5/media', { + method: 'POST', + body: JSON.stringify({ + media_type: 'video', + }), + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken}`, + }, + }) + ).json(); + + console.log(media_id, upload_url); + + try { + const { data } = await axios({ + url: postDetails?.[0]?.media?.[0]?.url, + method: 'GET', + responseType: 'stream', + }); + + const p = await ( + await fetch(upload_url, { + method: 'PUT', + body: data.buffer, + headers: { + Authorization: `Bearer ${accessToken}`, + ...upload_parameters, + }, + }) + ).json(); + + console.log(p); + } catch (err) { + console.log(err); + } + + mediaId = media_id; + } + + const mapImages = postDetails?.[0]?.media?.map((m) => ({ + url: m.url, + })); + + console.log('1'); + + try { + const { + id: pId, + link, + ...all + } = await ( + await fetch('https://api-sandbox.pinterest.com/v5/pins', { + method: 'POST', + headers: { + Authorization: `Bearer ${accessToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ...(postDetails?.[0]?.settings.link + ? { link: postDetails?.[0]?.settings.link } + : {}), + ...(postDetails?.[0]?.settings.title + ? { title: postDetails?.[0]?.settings.title } + : {}), + ...(postDetails?.[0]?.settings.description + ? { title: postDetails?.[0]?.settings.description } + : {}), + ...(postDetails?.[0]?.settings.dominant_color + ? { title: postDetails?.[0]?.settings.dominant_color } + : {}), + board_id: postDetails?.[0]?.settings.board, + media_source: mediaId + ? { + source_type: 'video', + media_id: mediaId, + } + : mapImages?.length === 1 + ? { + source_type: 'image_url', + url: mapImages?.[0]?.url, + } + : { + source_type: 'multiple_image_urls', + items: mapImages, + }, + }), + }) + ).json(); + + console.log(all); + + return [ + { + id, + postId: pId, + releaseURL: link, + status: 'success', + }, + ]; + } catch (err) { + console.log(err); + return []; + } + } +} diff --git a/libraries/react-shared-libraries/src/form/color.picker.tsx b/libraries/react-shared-libraries/src/form/color.picker.tsx new file mode 100644 index 00000000..da05c09f --- /dev/null +++ b/libraries/react-shared-libraries/src/form/color.picker.tsx @@ -0,0 +1,68 @@ +import { FC, useCallback, useState } from 'react'; +import { Button } from './button'; +import { HexColorPicker } from 'react-colorful'; +import { useFormContext } from 'react-hook-form'; +import interClass from '../helpers/inter.font'; + +export const ColorPicker: FC<{ + name: string; + label: string; + enabled: boolean; + canBeCancelled: boolean; +}> = (props) => { + const { name, label, enabled, canBeCancelled } = props; + const form = useFormContext(); + const [enabledState, setEnabledState] = useState(enabled); + const color = form.register(name); + const watch = form.watch(name); + + const enable = useCallback(async () => { + await color.onChange({ target: { name, value: '#FFFFFF' } }); + setEnabledState(true); + }, []); + + const cancel = useCallback(async () => { + await color.onChange({ target: { name, value: '' } }); + setEnabledState(false); + }, []); + + if (!enabledState) { + return ( +
+ +
+ ); + } + + return ( +
+
+ {!!label &&
{label}
} +
+ {canBeCancelled && ( +
+ +
+ )} +
+
+ color.onChange({ target: { name, value } })} + /> +
+
+
+
+
+
{watch}
+
+
+
+ ); +}; diff --git a/package-lock.json b/package-lock.json index 5d4cad91..7020d979 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,6 +70,7 @@ "openai": "^4.47.1", "prisma-paginate": "^5.2.1", "react": "18.2.0", + "react-colorful": "^5.6.1", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "18.2.0", @@ -33283,6 +33284,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-dnd": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", diff --git a/package.json b/package.json index fd5e051a..b59a51dc 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "openai": "^4.47.1", "prisma-paginate": "^5.2.1", "react": "18.2.0", + "react-colorful": "^5.6.1", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "18.2.0",