Merge branch 'main' into main
This commit is contained in:
commit
6433115977
|
|
@ -1,12 +1,5 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
Post,
|
||||
Query,
|
||||
UploadedFile,
|
||||
UseInterceptors,
|
||||
Body, Controller, Delete, Get, HttpException, Param, Post, Query, UploadedFile, UseInterceptors
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
|
||||
|
|
@ -76,6 +69,15 @@ export class PublicIntegrationsController {
|
|||
return this._postsService.createPost(org.id, body);
|
||||
}
|
||||
|
||||
@Delete('/posts/:id')
|
||||
async deletePost(
|
||||
@GetOrgFromRequest() org: Organization,
|
||||
@Param() body: { id: string }
|
||||
) {
|
||||
const getPostById = await this._postsService.getPost(org.id, body.id);
|
||||
return this._postsService.deletePost(org.id, getPostById.group);
|
||||
}
|
||||
|
||||
@Get('/integrations')
|
||||
async listIntegration(@GetOrgFromRequest() org: Organization) {
|
||||
return (await this._integrationService.getIntegrationsList(org.id)).map(
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ html {
|
|||
width: auto !important;
|
||||
}
|
||||
|
||||
.editor * {
|
||||
.editor :not(.removeEditor *) {
|
||||
@apply text-textColor;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ export const CalendarColumn: FC<{
|
|||
))}
|
||||
{!showAll && postList.length > 3 && (
|
||||
<div
|
||||
className="text-center hover:underline py-[5px]"
|
||||
className="text-center hover:underline py-[5px] text-textColor"
|
||||
onClick={showAllFunc}
|
||||
>
|
||||
+ Show more ({postList.length - 3})
|
||||
|
|
@ -683,7 +683,7 @@ const CalendarItem: FC<{
|
|||
className={clsx('w-full flex h-full flex-1 flex-col group', 'relative')}
|
||||
style={{ opacity }}
|
||||
>
|
||||
<div className="bg-forth text-[11px] h-[15px] w-full rounded-tr-[10px] rounded-tl-[10px] flex justify-center gap-[10px] px-[5px]">
|
||||
<div className="text-primary bg-forth text-[11px] h-[15px] w-full rounded-tr-[10px] rounded-tl-[10px] flex justify-center gap-[10px] px-[5px]">
|
||||
<div
|
||||
className="hidden group-hover:block hover:underline cursor-pointer"
|
||||
onClick={duplicatePost}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export const Filters = () => {
|
|||
return (
|
||||
<div className="text-textColor flex flex-col md:flex-row gap-[8px] items-center select-none">
|
||||
<div className="flex flex-grow flex-row">
|
||||
<div onClick={previous} className="cursor-pointer">
|
||||
<div onClick={previous} className="cursor-pointer text-textColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
|
|
@ -178,7 +178,7 @@ export const Filters = () => {
|
|||
>
|
||||
<path
|
||||
d="M13.1644 15.5866C13.3405 15.7628 13.4395 16.0016 13.4395 16.2507C13.4395 16.4998 13.3405 16.7387 13.1644 16.9148C12.9883 17.0909 12.7494 17.1898 12.5003 17.1898C12.2513 17.1898 12.0124 17.0909 11.8363 16.9148L5.58629 10.6648C5.49889 10.5777 5.42954 10.4742 5.38222 10.3602C5.3349 10.2463 5.31055 10.1241 5.31055 10.0007C5.31055 9.87732 5.3349 9.75515 5.38222 9.64119C5.42954 9.52724 5.49889 9.42375 5.58629 9.33665L11.8363 3.08665C12.0124 2.91053 12.2513 2.81158 12.5003 2.81158C12.7494 2.81158 12.9883 2.91053 13.1644 3.08665C13.3405 3.26277 13.4395 3.50164 13.4395 3.75071C13.4395 3.99978 13.3405 4.23865 13.1644 4.41477L7.57925 9.99993L13.1644 15.5866Z"
|
||||
fill="#E9E9F1"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
|
@ -193,7 +193,7 @@ export const Filters = () => {
|
|||
? `Week ${week.currentWeek}`
|
||||
: `${dayjs().month(week.currentMonth).format('MMMM')}`}
|
||||
</div>
|
||||
<div onClick={next} className="cursor-pointer">
|
||||
<div onClick={next} className="cursor-pointer text-textColor">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
|
|
@ -203,7 +203,7 @@ export const Filters = () => {
|
|||
>
|
||||
<path
|
||||
d="M14.4137 10.6633L8.16374 16.9133C7.98761 17.0894 7.74874 17.1884 7.49967 17.1884C7.2506 17.1884 7.01173 17.0894 6.83561 16.9133C6.65949 16.7372 6.56055 16.4983 6.56055 16.2492C6.56055 16.0002 6.65949 15.7613 6.83561 15.5852L12.4223 10L6.83717 4.41331C6.74997 4.3261 6.68079 4.22257 6.6336 4.10863C6.5864 3.99469 6.56211 3.87257 6.56211 3.74925C6.56211 3.62592 6.5864 3.5038 6.6336 3.38986C6.68079 3.27592 6.74997 3.17239 6.83717 3.08518C6.92438 2.99798 7.02791 2.9288 7.14185 2.88161C7.25579 2.83441 7.37791 2.81012 7.50124 2.81012C7.62456 2.81012 7.74668 2.83441 7.86062 2.88161C7.97456 2.9288 8.07809 2.99798 8.1653 3.08518L14.4153 9.33518C14.5026 9.42238 14.5718 9.52596 14.619 9.63997C14.6662 9.75398 14.6904 9.87618 14.6903 9.99957C14.6901 10.123 14.6656 10.2451 14.6182 10.359C14.5707 10.4729 14.5012 10.5763 14.4137 10.6633Z"
|
||||
fill="#E9E9F1"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ export const PickPlatforms: FC<{
|
|||
height={15}
|
||||
/>
|
||||
</div>
|
||||
<div>{integration.name}</div>
|
||||
<div>{integration.name.slice(0, 10)}{integration.name.length > 10 ? '...' : ''}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -409,7 +409,9 @@ export const withProvider = function <T extends object>(
|
|||
>
|
||||
{editInPlace
|
||||
? 'Edit globally'
|
||||
: `Edit only ${integration?.name} (${capitalize(
|
||||
: `Edit only ${integration?.name.slice(0, 10)}${
|
||||
(integration?.name?.length || 0) > 10 ? '...' : ''
|
||||
} (${capitalize(
|
||||
integration?.identifier.replace('-', ' ')
|
||||
)})`}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ export const Pagination: FC<{
|
|||
aria-current="page"
|
||||
onClick={() => setPage(page)}
|
||||
className={clsx(
|
||||
'cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border hover:bg-forth h-10 w-10 hover:text-white border-[#1F1F1F] text-white',
|
||||
current === page && 'bg-forth'
|
||||
'cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border hover:bg-forth h-10 w-10 hover:text-white border-[#1F1F1F]',
|
||||
current === page ? 'bg-forth !text-white' : 'text-textColor hover:text-white'
|
||||
)}
|
||||
>
|
||||
{page + 1}
|
||||
|
|
@ -89,7 +89,7 @@ export const Pagination: FC<{
|
|||
)}
|
||||
>
|
||||
<a
|
||||
className="cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 pr-2.5 text-gray-400 hover:text-white border-[#1F1F1F] hover:bg-forth"
|
||||
className="text-textColor hover:text-white group cursor-pointer inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-10 px-4 py-2 gap-1 pr-2.5 text-gray-400 border-[#1F1F1F] hover:bg-forth"
|
||||
aria-label="Go to next page"
|
||||
onClick={() => setPage(current + 1)}
|
||||
>
|
||||
|
|
@ -292,7 +292,7 @@ export const MediaBox: FC<{
|
|||
}, [data]);
|
||||
|
||||
return (
|
||||
<div className="fixed left-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="removeEditor fixed left-0 top-0 bg-primary/80 z-[300] w-full min-h-full p-4 md:p-[60px] animate-fade">
|
||||
<div className="max-w-[1000px] w-full h-full bg-sixth border-tableBorder border-2 rounded-xl relative mx-auto">
|
||||
<DropFiles onDrop={dragAndDrop}>
|
||||
<div className="pb-[20px] px-[20px] w-full h-full">
|
||||
|
|
@ -375,8 +375,10 @@ export const MediaBox: FC<{
|
|||
) : (
|
||||
<>
|
||||
{selectedMedia.length > 0 && (
|
||||
<div className="flex justify-center absolute top-[7px]">
|
||||
<Button onClick={addMedia}>Add selected media</Button>
|
||||
<div className="flex justify-center absolute top-[7px] text-white">
|
||||
<Button onClick={addMedia} className="!text-white">
|
||||
<span className="!text-white">Add selected media</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -403,7 +405,7 @@ export const MediaBox: FC<{
|
|||
>
|
||||
<div
|
||||
onClick={removeItem(media)}
|
||||
className="border border-red-400 text-white flex justify-center items-center absolute w-[20px] h-[20px] rounded-full bg-red-700 -top-[5px] -right-[5px]"
|
||||
className="border border-red-400 !text-white flex justify-center items-center absolute w-[20px] h-[20px] rounded-full bg-red-700 -top-[5px] -right-[5px]"
|
||||
>
|
||||
X
|
||||
</div>
|
||||
|
|
@ -445,15 +447,7 @@ export const MultiMediaComponent: FC<{
|
|||
target: { name: string; value?: Array<{ id: string; path: string }> };
|
||||
}) => void;
|
||||
}> = (props) => {
|
||||
const {
|
||||
onOpen,
|
||||
onClose,
|
||||
name,
|
||||
error,
|
||||
text,
|
||||
onChange,
|
||||
value,
|
||||
} = props;
|
||||
const { onOpen, onClose, name, error, text, onChange, value } = props;
|
||||
const user = useUser();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -577,14 +571,14 @@ export const MultiMediaComponent: FC<{
|
|||
<div className="cursor-pointer w-[40px] h-[40px] border-2 border-tableBorder relative flex">
|
||||
<div
|
||||
className="w-full h-full"
|
||||
onClick={() => window.open(mediaDirectory.set(media.path))}
|
||||
onClick={() => window.open(mediaDirectory.set(media?.path))}
|
||||
>
|
||||
{media.path.indexOf('mp4') > -1 ? (
|
||||
<VideoFrame url={mediaDirectory.set(media.path)} />
|
||||
{media?.path?.indexOf('mp4') > -1 ? (
|
||||
<VideoFrame url={mediaDirectory.set(media?.path)} />
|
||||
) : (
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src={mediaDirectory.set(media.path)}
|
||||
src={mediaDirectory.set(media?.path)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@ export class MediaRepository {
|
|||
});
|
||||
}
|
||||
|
||||
getMediaById(id: string) {
|
||||
return this._media.model.media.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
deleteMedia(org: string, id: string) {
|
||||
return this._media.model.media.update({
|
||||
where: {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ export class MediaService {
|
|||
return this._mediaRepository.deleteMedia(org, id);
|
||||
}
|
||||
|
||||
getMediaById(id: string) {
|
||||
return this._mediaRepository.getMediaById(id);
|
||||
}
|
||||
|
||||
async generateImage(
|
||||
prompt: string,
|
||||
org: Organization,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,17 @@ export class PostsRepository {
|
|||
});
|
||||
}
|
||||
|
||||
updateImages(id: string, images: string) {
|
||||
return this._post.model.post.update({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
data: {
|
||||
image: images,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getPostUrls(orgId: string, ids: string[]) {
|
||||
return this._post.model.post.findMany({
|
||||
where: {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { BullMqClient } from '@gitroom/nestjs-libraries/bull-mq-transport-new/cl
|
|||
import { timer } from '@gitroom/helpers/utils/timer';
|
||||
import { AuthTokenDetails } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import { MediaService } from '@gitroom/nestjs-libraries/database/prisma/media/media.service';
|
||||
dayjs.extend(utc);
|
||||
|
||||
type PostWithConditionals = Post & {
|
||||
|
|
@ -36,7 +37,8 @@ export class PostsService {
|
|||
private _notificationService: NotificationService,
|
||||
private _messagesService: MessagesService,
|
||||
private _stripeService: StripeService,
|
||||
private _integrationService: IntegrationService
|
||||
private _integrationService: IntegrationService,
|
||||
private _mediaService: MediaService
|
||||
) {}
|
||||
|
||||
async getPostsRecursively(
|
||||
|
|
@ -73,18 +75,63 @@ export class PostsService {
|
|||
return this._postRepository.getPosts(orgId, query);
|
||||
}
|
||||
|
||||
async updateMedia(id: string, imagesList: any[]) {
|
||||
let imageUpdateNeeded = false;
|
||||
const getImageList = (
|
||||
await Promise.all(
|
||||
imagesList.map(async (p: any) => {
|
||||
if (!p.path && p.id) {
|
||||
imageUpdateNeeded = true;
|
||||
return this._mediaService.getMediaById(p.id);
|
||||
}
|
||||
|
||||
return p;
|
||||
})
|
||||
)
|
||||
).map((m) => {
|
||||
return {
|
||||
...m,
|
||||
url:
|
||||
m.path.indexOf('http') === -1
|
||||
? process.env.FRONTEND_URL +
|
||||
'/' +
|
||||
process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY +
|
||||
m.path
|
||||
: m.path,
|
||||
type: 'image',
|
||||
path:
|
||||
m.path.indexOf('http') === -1
|
||||
? process.env.UPLOAD_DIRECTORY + m.path
|
||||
: m.path,
|
||||
};
|
||||
});
|
||||
|
||||
if (imageUpdateNeeded) {
|
||||
await this._postRepository.updateImages(id, JSON.stringify(getImageList));
|
||||
}
|
||||
|
||||
return getImageList;
|
||||
}
|
||||
|
||||
async getPost(orgId: string, id: string) {
|
||||
const posts = await this.getPostsRecursively(id, true, orgId, true);
|
||||
return {
|
||||
const list = {
|
||||
group: posts?.[0]?.group,
|
||||
posts: posts.map((post) => ({
|
||||
...post,
|
||||
image: JSON.parse(post.image || '[]'),
|
||||
})),
|
||||
posts: await Promise.all(
|
||||
posts.map(async (post) => ({
|
||||
...post,
|
||||
image: await this.updateMedia(
|
||||
post.id,
|
||||
JSON.parse(post.image || '[]')
|
||||
),
|
||||
}))
|
||||
),
|
||||
integrationPicture: posts[0]?.integration?.picture,
|
||||
integration: posts[0].integrationId,
|
||||
settings: JSON.parse(posts[0].settings || '{}'),
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
async getOldPosts(orgId: string, date: string) {
|
||||
|
|
@ -280,25 +327,14 @@ export class PostsService {
|
|||
const publishedPosts = await getIntegration.post(
|
||||
integration.internalId,
|
||||
integration.token,
|
||||
newPosts.map((p) => ({
|
||||
id: p.id,
|
||||
message: p.content,
|
||||
settings: JSON.parse(p.settings || '{}'),
|
||||
media: (JSON.parse(p.image || '[]') as Media[]).map((m) => ({
|
||||
url:
|
||||
m.path.indexOf('http') === -1
|
||||
? process.env.FRONTEND_URL +
|
||||
'/' +
|
||||
process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY +
|
||||
m.path
|
||||
: m.path,
|
||||
type: 'image',
|
||||
path:
|
||||
m.path.indexOf('http') === -1
|
||||
? process.env.UPLOAD_DIRECTORY + m.path
|
||||
: m.path,
|
||||
})),
|
||||
})),
|
||||
await Promise.all(
|
||||
newPosts.map(async (p) => ({
|
||||
id: p.id,
|
||||
message: p.content,
|
||||
settings: JSON.parse(p.settings || '{}'),
|
||||
media: await this.updateMedia(p.id, JSON.parse(p.image || '[]')),
|
||||
}))
|
||||
),
|
||||
integration
|
||||
);
|
||||
|
||||
|
|
@ -469,7 +505,10 @@ export class PostsService {
|
|||
const post = await this._postRepository.deletePost(orgId, group);
|
||||
if (post?.id) {
|
||||
await this._workerServiceProducer.delete('post', post.id);
|
||||
return {id: post.id};
|
||||
}
|
||||
|
||||
return {error: true};
|
||||
}
|
||||
|
||||
async countPostsFromDay(orgId: string, date: Date) {
|
||||
|
|
@ -513,6 +552,7 @@ export class PostsService {
|
|||
}
|
||||
|
||||
async createPost(orgId: string, body: CreatePostDto) {
|
||||
const postList = [];
|
||||
for (const post of body.posts) {
|
||||
const { previousPost, posts } =
|
||||
await this._postRepository.createOrUpdatePost(
|
||||
|
|
@ -560,7 +600,14 @@ export class PostsService {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
postList.push({
|
||||
postId: posts[0].id,
|
||||
integration: post.integration.id,
|
||||
})
|
||||
}
|
||||
|
||||
return postList;
|
||||
}
|
||||
|
||||
async changeDate(orgId: string, id: string, date: string) {
|
||||
|
|
@ -802,7 +849,12 @@ export class PostsService {
|
|||
return this._postRepository.getComments(postId);
|
||||
}
|
||||
|
||||
createComment(orgId: string, userId: string, postId: string, comment: string) {
|
||||
createComment(
|
||||
orgId: string,
|
||||
userId: string,
|
||||
postId: string,
|
||||
comment: string
|
||||
) {
|
||||
return this._postRepository.createComment(orgId, userId, postId, comment);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const VideoOrImage: FC<{
|
|||
isContain?: boolean;
|
||||
}> = (props) => {
|
||||
const { src, autoplay, isContain } = props;
|
||||
if (src.indexOf('mp4') > -1) {
|
||||
if (src?.indexOf('mp4') > -1) {
|
||||
return (
|
||||
<video
|
||||
src={src}
|
||||
|
|
|
|||
Loading…
Reference in New Issue