feat: repeated posts
This commit is contained in:
parent
d51e5607cb
commit
83c7f75621
|
|
@ -58,6 +58,7 @@ import { LoadingComponent } from '@gitroom/frontend/components/layout/loading';
|
|||
import { DropFiles } from '@gitroom/frontend/components/layout/drop.files';
|
||||
import { SelectCustomer } from '@gitroom/frontend/components/launches/select.customer';
|
||||
import { TagsComponent } from './tags.component';
|
||||
import { RepeatComponent } from '@gitroom/frontend/components/launches/repeat.component';
|
||||
|
||||
function countCharacters(text: string, type: string): number {
|
||||
if (type !== 'x') {
|
||||
|
|
@ -140,6 +141,8 @@ export const AddEditModal: FC<{
|
|||
// are we in edit mode?
|
||||
const existingData = useExistingData();
|
||||
|
||||
const [inter, setInter] = useState(existingData?.posts?.[0]?.intervalInDays);
|
||||
|
||||
const [tags, setTags] = useState<any[]>(
|
||||
// @ts-ignore
|
||||
existingData?.posts?.[0]?.tags?.map((p: any) => ({
|
||||
|
|
@ -394,6 +397,7 @@ export const AddEditModal: FC<{
|
|||
body: JSON.stringify({
|
||||
...(postFor ? { order: postFor.id } : {}),
|
||||
type,
|
||||
inter,
|
||||
tags,
|
||||
shortLink,
|
||||
date: dateState.utc().format('YYYY-MM-DDTHH:mm:ss'),
|
||||
|
|
@ -418,6 +422,7 @@ export const AddEditModal: FC<{
|
|||
modal.closeAll();
|
||||
},
|
||||
[
|
||||
inter,
|
||||
postFor,
|
||||
dateState,
|
||||
value,
|
||||
|
|
@ -566,6 +571,7 @@ export const AddEditModal: FC<{
|
|||
setSelectedIntegrations([]);
|
||||
}}
|
||||
/>
|
||||
<RepeatComponent repeat={inter} onChange={setInter} />
|
||||
<DatePicker onChange={setDateState} date={dateState} />
|
||||
{!selectedIntegrations.length && (
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -420,8 +420,13 @@ export const CalendarColumn: FC<{
|
|||
);
|
||||
|
||||
const editPost = useCallback(
|
||||
(post: Post & { integration: Integration }, isDuplicate?: boolean) =>
|
||||
(loadPost: Post & { integration: Integration }, isDuplicate?: boolean) =>
|
||||
async () => {
|
||||
const post = {
|
||||
...loadPost,
|
||||
// @ts-ignore
|
||||
publishDate: loadPost.actualDate || loadPost.publishDate,
|
||||
};
|
||||
if (user?.orgId === post.submittedForOrganizationId) {
|
||||
return previewPublication(post);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
import { FC } from 'react';
|
||||
import { Select } from '@gitroom/react/form/select';
|
||||
|
||||
const list = [
|
||||
{ value: 1, label: 'Every Day' },
|
||||
{ value: 2, label: 'Every Two Days' },
|
||||
{ value: 3, label: 'Every Three Days' },
|
||||
{ value: 4, label: 'Every Four Days' },
|
||||
{ value: 5, label: 'Every Five Days' },
|
||||
{ value: 6, label: 'Every Six Days' },
|
||||
{ value: 7, label: 'Every Week' },
|
||||
{ value: 14, label: 'Every Two Weeks' },
|
||||
{ value: 30, label: 'Every Month' },
|
||||
];
|
||||
|
||||
export const RepeatComponent: FC<{ repeat: number|null, onChange: (newVal: number) => void }> = (props) => {
|
||||
const { repeat } = props;
|
||||
return (
|
||||
<Select
|
||||
disableForm={true}
|
||||
label=""
|
||||
hideErrors={true}
|
||||
name="repeat"
|
||||
value={repeat ? repeat : undefined}
|
||||
onChange={(e) => props.onChange(Number(e.target.value))}
|
||||
>
|
||||
<option>Repeat Post Every...</option>
|
||||
{list.map((item) => (
|
||||
<option key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
|
@ -6,11 +6,15 @@ import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto'
|
|||
import dayjs from 'dayjs';
|
||||
import isoWeek from 'dayjs/plugin/isoWeek';
|
||||
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
||||
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { CreateTagDto } from '@gitroom/nestjs-libraries/dtos/posts/create.tag.dto';
|
||||
|
||||
dayjs.extend(isoWeek);
|
||||
dayjs.extend(weekOfYear);
|
||||
dayjs.extend(isSameOrAfter);
|
||||
dayjs.extend(utc);
|
||||
|
||||
@Injectable()
|
||||
export class PostsRepository {
|
||||
|
|
@ -80,7 +84,7 @@ export class PostsRepository {
|
|||
});
|
||||
}
|
||||
|
||||
getPosts(orgId: string, query: GetPostsDto) {
|
||||
async getPosts(orgId: string, query: GetPostsDto) {
|
||||
const dateYear = dayjs().year(query.year);
|
||||
const date =
|
||||
query.display === 'day'
|
||||
|
|
@ -108,20 +112,35 @@ export class PostsRepository {
|
|||
.add(2, 'hours')
|
||||
.toDate();
|
||||
|
||||
return this._post.model.post.findMany({
|
||||
const list = await this._post.model.post.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
AND: [
|
||||
{
|
||||
organizationId: orgId,
|
||||
OR: [
|
||||
{
|
||||
organizationId: orgId,
|
||||
},
|
||||
{
|
||||
submittedForOrganizationId: orgId,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
submittedForOrganizationId: orgId,
|
||||
OR: [
|
||||
{
|
||||
publishDate: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
},
|
||||
{
|
||||
intervalInDays: {
|
||||
not: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
publishDate: {
|
||||
gte: startDate,
|
||||
lte: endDate,
|
||||
},
|
||||
deletedAt: null,
|
||||
parentPostId: null,
|
||||
...(query.customer
|
||||
|
|
@ -140,6 +159,7 @@ export class PostsRepository {
|
|||
submittedForOrganizationId: true,
|
||||
submittedForOrderId: true,
|
||||
state: true,
|
||||
intervalInDays: true,
|
||||
tags: {
|
||||
select: {
|
||||
tag: true,
|
||||
|
|
@ -155,6 +175,28 @@ export class PostsRepository {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
return list.reduce((all, post) => {
|
||||
if (!post.intervalInDays) {
|
||||
return [...all, post];
|
||||
}
|
||||
|
||||
const addMorePosts = [];
|
||||
let startingDate = dayjs.utc(post.publishDate);
|
||||
while (dayjs.utc(endDate).isSameOrAfter(startingDate)) {
|
||||
if (dayjs(startingDate).isSameOrAfter(dayjs.utc(post.publishDate))) {
|
||||
addMorePosts.push({
|
||||
...post,
|
||||
publishDate: startingDate.toDate(),
|
||||
actualDate: post.publishDate,
|
||||
});
|
||||
}
|
||||
|
||||
startingDate = startingDate.add(post.intervalInDays, 'days');
|
||||
}
|
||||
|
||||
return [...all, ...addMorePosts];
|
||||
}, [] as any[]);
|
||||
}
|
||||
|
||||
async deletePost(orgId: string, group: string) {
|
||||
|
|
@ -272,7 +314,8 @@ export class PostsRepository {
|
|||
orgId: string,
|
||||
date: string,
|
||||
body: PostBody,
|
||||
tags: { value: string; label: string }[]
|
||||
tags: { value: string; label: string }[],
|
||||
inter?: number,
|
||||
) {
|
||||
const posts: Post[] = [];
|
||||
const uuid = uuidv4();
|
||||
|
|
@ -303,6 +346,7 @@ export class PostsRepository {
|
|||
: {}),
|
||||
content: value.content,
|
||||
group: uuid,
|
||||
intervalInDays: inter ? +inter : null,
|
||||
approvedSubmitForOrder: APPROVED_SUBMIT_FOR_ORDER.NO,
|
||||
state: state === 'draft' ? ('DRAFT' as const) : ('QUEUE' as const),
|
||||
image: JSON.stringify(value.image),
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export class PostsService {
|
|||
];
|
||||
}
|
||||
|
||||
getPosts(orgId: string, query: GetPostsDto) {
|
||||
async getPosts(orgId: string, query: GetPostsDto) {
|
||||
return this._postRepository.getPosts(orgId, query);
|
||||
}
|
||||
|
||||
|
|
@ -205,6 +205,18 @@ export class PostsService {
|
|||
return;
|
||||
}
|
||||
|
||||
if (firstPost?.intervalInDays) {
|
||||
this._workerServiceProducer.emit('post', {
|
||||
id,
|
||||
options: {
|
||||
delay: firstPost.intervalInDays * 86400000,
|
||||
},
|
||||
payload: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (firstPost.submittedForOrderId) {
|
||||
this._workerServiceProducer.emit('submit', {
|
||||
payload: {
|
||||
|
|
@ -597,7 +609,8 @@ export class PostsService {
|
|||
? dayjs().format('YYYY-MM-DDTHH:mm:00')
|
||||
: body.date,
|
||||
post,
|
||||
body.tags
|
||||
body.tags,
|
||||
body.inter,
|
||||
);
|
||||
|
||||
if (!posts?.length) {
|
||||
|
|
@ -633,6 +646,10 @@ export class PostsService {
|
|||
},
|
||||
payload: {
|
||||
id: posts[0].id,
|
||||
delay:
|
||||
body.type === 'now'
|
||||
? 0
|
||||
: dayjs(posts[0].publishDate).diff(dayjs(), 'millisecond'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -666,6 +683,7 @@ export class PostsService {
|
|||
},
|
||||
payload: {
|
||||
id: id,
|
||||
delay: dayjs(date).diff(dayjs(), 'millisecond'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ model Post {
|
|||
approvedSubmitForOrder APPROVED_SUBMIT_FOR_ORDER @default(NO)
|
||||
lastMessageId String?
|
||||
lastMessage Messages? @relation(fields: [lastMessageId], references: [id])
|
||||
intervalInDays Int?
|
||||
payoutProblems PayoutProblems[]
|
||||
comments Comments[]
|
||||
tags TagsPosts[]
|
||||
|
|
@ -389,6 +390,7 @@ model Post {
|
|||
@@index([organizationId])
|
||||
@@index([parentPostId])
|
||||
@@index([submittedForOrderId])
|
||||
@@index([intervalInDays])
|
||||
@@index([approvedSubmitForOrder])
|
||||
@@index([lastMessageId])
|
||||
@@index([createdAt])
|
||||
|
|
|
|||
|
|
@ -1,15 +1,5 @@
|
|||
import {
|
||||
ArrayMinSize,
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsDateString,
|
||||
IsDefined,
|
||||
IsIn,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MinLength,
|
||||
ValidateIf,
|
||||
ValidateNested,
|
||||
ArrayMinSize, IsArray, IsBoolean, IsDateString, IsDefined, IsIn, IsNumber, IsOptional, IsString, MinLength, ValidateIf, ValidateNested
|
||||
} from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { DevToSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/dev.to.settings.dto';
|
||||
|
|
@ -113,6 +103,10 @@ export class CreatePostDto {
|
|||
@IsBoolean()
|
||||
shortLink: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
inter?: number;
|
||||
|
||||
@IsDefined()
|
||||
@IsDateString()
|
||||
date: string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue