feat: social media
This commit is contained in:
parent
7d3302e3b8
commit
4e9c181719
|
|
@ -250,44 +250,16 @@ export const AddEditModal: FC<{
|
|||
group: existingData?.group,
|
||||
trigger: values[v].trigger,
|
||||
settings: values[v].settings(),
|
||||
firstCommentRequirements: values[v].firstCommentRequirements,
|
||||
maximumMediaRequirements: values[v].maximumMediaRequirements,
|
||||
minimumMediaRequirements: values[v].minimumMediaRequirements,
|
||||
checkValidity: values[v].checkValidity
|
||||
}));
|
||||
|
||||
for (const key of allKeys) {
|
||||
// @ts-ignore
|
||||
const images = key?.value[0].image;
|
||||
if (
|
||||
(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
|
||||
: `between ${key.minimumMediaRequirements} to ${key.maximumMediaRequirements}`
|
||||
}`,
|
||||
'warning'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
key.firstCommentRequirements &&
|
||||
!images?.every((p: any) =>
|
||||
key.firstCommentRequirements === 'video'
|
||||
? p.name.includes('mp4')
|
||||
: !p.name.includes('mp4')
|
||||
)
|
||||
) {
|
||||
toaster.show(
|
||||
`${capitalize(key?.integration?.identifier?.toUpperCase())} media should be a ${
|
||||
key.firstCommentRequirements === 'video' ? 'video' : 'image'
|
||||
}`,
|
||||
'warning'
|
||||
);
|
||||
return;
|
||||
if (key.checkValidity) {
|
||||
const check = await key.checkValidity(key?.value.map((p: any) => p.image || {path: ''}));
|
||||
if (typeof check === 'string') {
|
||||
toaster.show(check, 'warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (key.value.some((p) => !p.content || p.content.length < 6)) {
|
||||
|
|
@ -322,7 +294,7 @@ export const AddEditModal: FC<{
|
|||
);
|
||||
modal.closeAll();
|
||||
},
|
||||
[postFor, dateState, value, integrations, existingData]
|
||||
[postFor, dateState, value, integrations, existingData, selectedIntegrations]
|
||||
);
|
||||
|
||||
const getPostsMarketplace = useCallback(async () => {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ const finalInformation = {} as {
|
|||
settings: () => object;
|
||||
trigger: () => Promise<boolean>;
|
||||
isValid: boolean;
|
||||
firstCommentRequirements?: 'video' | 'image';
|
||||
minimumMediaRequirements?: number;
|
||||
maximumMediaRequirements?: number;
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>;
|
||||
};
|
||||
};
|
||||
export const useValues = (
|
||||
|
|
@ -19,9 +17,7 @@ export const useValues = (
|
|||
identifier: string,
|
||||
value: Array<{ id?: string; content: string; media?: Array<string> }>,
|
||||
dto: any,
|
||||
firstCommentRequirements?: 'video' | 'image',
|
||||
minimumMediaRequirements?: number,
|
||||
maximumMediaRequirements?: number
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>,
|
||||
) => {
|
||||
const resolver = useMemo(() => {
|
||||
return classValidatorResolver(dto);
|
||||
|
|
@ -44,17 +40,9 @@ export const useValues = (
|
|||
finalInformation[integration].settings = getValues;
|
||||
finalInformation[integration].trigger = form.trigger;
|
||||
|
||||
if (firstCommentRequirements) {
|
||||
finalInformation[integration].firstCommentRequirements =
|
||||
firstCommentRequirements;
|
||||
}
|
||||
if (minimumMediaRequirements) {
|
||||
finalInformation[integration].minimumMediaRequirements =
|
||||
minimumMediaRequirements;
|
||||
}
|
||||
if (maximumMediaRequirements) {
|
||||
finalInformation[integration].maximumMediaRequirements =
|
||||
maximumMediaRequirements;
|
||||
if (checkValidity) {
|
||||
finalInformation[integration].checkValidity =
|
||||
checkValidity;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -67,9 +67,7 @@ export const withProvider = (
|
|||
SettingsComponent: FC | null,
|
||||
PreviewComponent: FC,
|
||||
dto?: any,
|
||||
firstCommentRequirements?: 'video' | 'image',
|
||||
minimumMediaRequirements?: number,
|
||||
maximumMediaRequirements?: number,
|
||||
checkValidity?: (value: Array<Array<{path: string}>>) => Promise<string|true>
|
||||
) => {
|
||||
return (props: {
|
||||
identifier: string;
|
||||
|
|
@ -121,9 +119,7 @@ export const withProvider = (
|
|||
props.identifier,
|
||||
editInPlace ? InPlaceValue : props.value,
|
||||
dto,
|
||||
firstCommentRequirements,
|
||||
minimumMediaRequirements,
|
||||
maximumMediaRequirements
|
||||
checkValidity
|
||||
);
|
||||
|
||||
// change editor value
|
||||
|
|
|
|||
|
|
@ -109,4 +109,10 @@ const InstagramPreview: FC = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default withProvider(null, InstagramPreview, undefined, undefined, 1, 10);
|
||||
export default withProvider(null, InstagramPreview, undefined, async ([firstPost, ...otherPosts]) => {
|
||||
if (!firstPost.length) {
|
||||
return 'Instagram should have at least one media';
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -130,6 +130,47 @@ export default withProvider(
|
|||
PinterestSettings,
|
||||
PinterestPreview,
|
||||
PinterestSettingsDto,
|
||||
undefined,
|
||||
1
|
||||
async ([firstItem, ...otherItems]) => {
|
||||
const isMp4 = firstItem.find((item) => item.path.indexOf('mp4') > -1);
|
||||
const isPicture = firstItem.find((item) => item.path.indexOf('mp4') === -1);
|
||||
|
||||
if (firstItem.length === 0) {
|
||||
return 'Pinterest requires at least one media';
|
||||
}
|
||||
|
||||
if (isMp4 && firstItem.length !== 2 && !isPicture) {
|
||||
return 'If posting a video to Pinterest you have to also include a cover image as second media';
|
||||
}
|
||||
|
||||
if (isMp4 && firstItem.length > 2) {
|
||||
return 'If posting a video to Pinterest you can only have two media items';
|
||||
}
|
||||
|
||||
if (otherItems.length) {
|
||||
return 'Pinterest can only have one post';
|
||||
}
|
||||
|
||||
if (firstItem.length > 1 && firstItem.every(p => p.path.indexOf('mp4') == -1)) {
|
||||
const loadAll: Array<{width: number, height: number}> = await Promise.all(firstItem.map(p => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = new Image();
|
||||
url.onload = function() {
|
||||
// @ts-ignore
|
||||
resolve({width: this.width, height: this.height});
|
||||
}
|
||||
url.src = p.path;
|
||||
});
|
||||
})) as any;
|
||||
|
||||
const checkAllTheSameWidthHeight = loadAll.every((p, i, arr) => {
|
||||
return p.width === arr[0].width && p.height === arr[0].height;
|
||||
});
|
||||
|
||||
if (!checkAllTheSameWidthHeight) {
|
||||
return 'Pinterest requires all images to have the same width and height';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { TopTitle } from '@gitroom/frontend/components/launches/helpers/top.titl
|
|||
import clsx from 'clsx';
|
||||
import interClass from '@gitroom/react/helpers/inter.font';
|
||||
import { VideoFrame } from '@gitroom/react/helpers/video.frame';
|
||||
import { useToaster } from '@gitroom/react/toaster/toaster';
|
||||
const showModalEmitter = new EventEmitter();
|
||||
|
||||
export const ShowMediaBoxModal: FC = () => {
|
||||
|
|
@ -58,6 +59,7 @@ export const MediaBox: FC<{
|
|||
const [mediaList, setListMedia] = useState<Media[]>([]);
|
||||
const fetch = useFetch();
|
||||
const mediaDirectory = useMediaDirectory();
|
||||
const toaster = useToaster();
|
||||
|
||||
const loadMedia = useCallback(async () => {
|
||||
return (await fetch('/media')).json();
|
||||
|
|
@ -69,8 +71,10 @@ export const MediaBox: FC<{
|
|||
if (
|
||||
!file?.target?.files?.length ||
|
||||
file?.target?.files?.[0]?.size > maxFileSize
|
||||
)
|
||||
) {
|
||||
toaster.show('Maximum file size 10mb', 'warning');
|
||||
return;
|
||||
}
|
||||
const formData = new FormData();
|
||||
formData.append('file', file?.target?.files?.[0]);
|
||||
const data = await (
|
||||
|
|
@ -226,7 +230,7 @@ export const MediaBox: FC<{
|
|||
.map((media) => (
|
||||
<div
|
||||
key={media.id}
|
||||
className="w-[200px] h-[200px] border-tableBorder border-2 cursor-pointer"
|
||||
className="w-[200px] h-[200px] flex border-tableBorder border-2 cursor-pointer"
|
||||
onClick={setNewMedia(media)}
|
||||
>
|
||||
{media.path.indexOf('mp4') > -1 ? (
|
||||
|
|
@ -319,7 +323,7 @@ export const MultiMediaComponent: FC<{
|
|||
{!!currentMedia &&
|
||||
currentMedia.map((media, index) => (
|
||||
<>
|
||||
<div className="cursor-pointer w-[40px] h-[40px] border-2 border-tableBorder relative">
|
||||
<div className="cursor-pointer w-[40px] h-[40px] border-2 border-tableBorder relative flex">
|
||||
<div
|
||||
onClick={() => window.open(mediaDirectory.set(media.path))}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { IsDefined, IsOptional, IsString, IsUrl, MinLength, ValidateNested } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsDefined, IsOptional, IsString, IsUrl, MinLength } from 'class-validator';
|
||||
|
||||
export class PinterestSettingsDto {
|
||||
@IsString()
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export class FacebookProvider implements SocialProvider {
|
|||
`${process.env.FRONTEND_URL}/integrations/social/facebook${refresh ? `?refresh=${refresh}` : ''}`
|
||||
)}` +
|
||||
`&state=${state}` +
|
||||
'&scope=pages_show_list,business_management,pages_manage_posts,publish_video,pages_manage_engagement,pages_read_engagement',
|
||||
'&scope=pages_show_list,business_management,pages_manage_posts,pages_manage_engagement,pages_read_engagement',
|
||||
codeVerifier: makeId(10),
|
||||
state,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import {
|
|||
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();
|
||||
import { timer } from '@gitroom/helpers/utils/timer';
|
||||
|
||||
export class PinterestProvider implements SocialProvider {
|
||||
identifier = 'pinterest';
|
||||
|
|
@ -126,29 +124,40 @@ export class PinterestProvider implements SocialProvider {
|
|||
})
|
||||
).json();
|
||||
|
||||
console.log(media_id, upload_url);
|
||||
|
||||
try {
|
||||
const { data } = await axios({
|
||||
url: postDetails?.[0]?.media?.[0]?.url,
|
||||
method: 'GET',
|
||||
const { data, status } = await axios.get(
|
||||
postDetails?.[0]?.media?.[0]?.url!,
|
||||
{
|
||||
responseType: 'stream',
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const p = await (
|
||||
await fetch(upload_url, {
|
||||
method: 'PUT',
|
||||
body: data.buffer,
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
...upload_parameters,
|
||||
},
|
||||
})
|
||||
const formData = Object.keys(upload_parameters)
|
||||
.filter((f) => f)
|
||||
.reduce((acc, key) => {
|
||||
acc.append(key, upload_parameters[key]);
|
||||
return acc;
|
||||
}, new FormData());
|
||||
|
||||
formData.append('file', data);
|
||||
await axios.post(upload_url, formData);
|
||||
|
||||
let statusCode = '';
|
||||
while (statusCode !== 'succeeded') {
|
||||
console.log('trying');
|
||||
const mediafile = await (
|
||||
await fetch(
|
||||
'https://api-sandbox.pinterest.com/v5/media/' + media_id,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
}
|
||||
)
|
||||
).json();
|
||||
|
||||
console.log(p);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
await timer(3000);
|
||||
statusCode = mediafile.status;
|
||||
}
|
||||
|
||||
mediaId = media_id;
|
||||
|
|
@ -158,8 +167,6 @@ export class PinterestProvider implements SocialProvider {
|
|||
url: m.url,
|
||||
}));
|
||||
|
||||
console.log('1');
|
||||
|
||||
try {
|
||||
const {
|
||||
id: pId,
|
||||
|
|
@ -188,7 +195,7 @@ export class PinterestProvider implements SocialProvider {
|
|||
board_id: postDetails?.[0]?.settings.board,
|
||||
media_source: mediaId
|
||||
? {
|
||||
source_type: 'video',
|
||||
source_type: 'video_id',
|
||||
media_id: mediaId,
|
||||
}
|
||||
: mapImages?.length === 1
|
||||
|
|
@ -204,8 +211,6 @@ export class PinterestProvider implements SocialProvider {
|
|||
})
|
||||
).json();
|
||||
|
||||
console.log(all);
|
||||
|
||||
return [
|
||||
{
|
||||
id,
|
||||
|
|
|
|||
Loading…
Reference in New Issue