Skip to content

Commit

Permalink
Merge pull request #98 from premieroctet/fix/order-template
Browse files Browse the repository at this point in the history
refacto and fix template api
  • Loading branch information
quentingrchr authored Dec 4, 2023
2 parents cd431e3 + 3c340ee commit 5f9244a
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 157 deletions.
36 changes: 22 additions & 14 deletions src/components/digests/templates/CreateTemplateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,33 @@ import useCustomToast from '@/hooks/useCustomToast';
import { useMutation } from 'react-query';
import api from '@/lib/api';
import { Input } from '../../Input';
import { DigestBlock, Team } from '@prisma/client';
import { DigestBlock, DigestBlockType, Team } from '@prisma/client';
import { AxiosError } from 'axios';
import { CreateBlockData } from '@/pages/api/teams/[teamId]/digests/[digestId]/block';

const CreateTemplateModal = ({
team,
digestBlocks,
templateBlocks,
}: {
team: Team;
digestBlocks: DigestBlock[];
templateBlocks: CreateBlockData[]; // only template blocks
}) => {
const [isDialogOpen, setIsDialogOpen] = useState(false);

const router = useRouter();
const { errorToast, successToast } = useCustomToast();

const { mutate: saveTemplate, isLoading } = useMutation(
// find type for useMutation
const { mutate: saveTemplate, isLoading } = useMutation<
any,
AxiosError,
{
title: string;
digestBlocks: CreateBlockData[];
}
>(
'save-digest-template',
(title: string) =>
api.post(`/teams/${team.id}/digests`, {
title: `${team?.slug}-template-${title}`,
digestBlocks,
isTemplate: 'true',
}),
(data) => api.post(`/teams/${team.id}/template`, data),
{
onSuccess: () => {
successToast('Your template has been saved');
Expand All @@ -48,12 +53,15 @@ const CreateTemplateModal = ({

const onSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const template = e.currentTarget.template.value;
if (!template) return;
saveTemplate(template);
const templateTitle = e.currentTarget.template.value as string;
if (!templateTitle) return;
saveTemplate({
title: `${team?.slug}-template-${templateTitle}`,
digestBlocks: templateBlocks,
});
};

if (!digestBlocks?.length) return null;
if (!templateBlocks?.length) return null;
return (
<div className="py-4">
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
Expand Down
5 changes: 3 additions & 2 deletions src/components/pages/DigestEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import DigestEditTypefully from './DigestEditTypefully';
import DigestEditSendNewsletter from './DigestEditSendNewsletter';
import { EyeIcon } from '@heroicons/react/24/solid';
import CreateTemplateModal from '../digests/templates/CreateTemplateModal';
import { digestBlockToTemplateBlocks } from '@/utils/template';

type Props = {
teamLinksData: TeamLinksData;
Expand Down Expand Up @@ -325,8 +326,8 @@ export const DigestEditPage = ({
</div>
<CreateTemplateModal
team={team}
digestBlocks={digest?.digestBlocks.filter(
(block) => block?.type === 'TEXT'
templateBlocks={digestBlockToTemplateBlocks(
digest.digestBlocks
)}
/>
<div
Expand Down
168 changes: 167 additions & 1 deletion src/lib/queries.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
'use server';

import { DigestBlockType, Prisma } from '@prisma/client';
import {
BookmarkDigestStyle,
Digest,
DigestBlock,
DigestBlockType,
Prisma,
} from '@prisma/client';
import { unstable_cache } from 'next/cache';
import db from './db';
import { reorderList } from '@/utils/actionOnList';
import urlSlug from 'url-slug';

export const getUserById = (userId: string) =>
db.user.findUnique({
Expand Down Expand Up @@ -639,3 +647,161 @@ export type DigestDataForTypefullyResult = Awaited<
export type DiscoveryDigest = Awaited<
ReturnType<typeof getDiscoverDigests>
>['digests'][number];

export type CreateBlockData = {
bookmarkId?: string;
text?: string;
position?: number;
type: DigestBlockType;
style?: BookmarkDigestStyle;
isTemplate?: boolean;
};
/**
* Create a new digest with the blocks from a template
*/
export async function createDigest({
title,
teamId,
}: {
title: string;
teamId: string;
}) {
const newDigest = (await db.digest.create({
data: {
teamId,
title: title,
slug: urlSlug(title),
isTemplate: false,
},
include: {
digestBlocks: true,
},
})) as Digest & {
digestBlocks: DigestBlock[];
};

return newDigest;
}

/**
* Create a new digest with the blocks from a template
*/
export async function createDigestWithTemplate({
title,
templateId,
teamId,
}: {
title: string;
templateId: string;
teamId: string;
}) {
// Get template
const template = await db.digest.findUnique({
where: {
id: templateId,
},
include: {
digestBlocks: true,
},
});

// Create new digest
const newDigest = await createDigest({ title, teamId });

// Create all blocks from template
const templateBlocks = template?.digestBlocks;
if (!templateBlocks) {
throw new Error('Template blocks not found');
}

await Promise.all(
templateBlocks.map(async (block) => {
const { bookmarkId, text, style, type, order } = block;
return createDigestBlock(
{
type: type,
...(text && { text: text }),
...(style && { style: style }),
...(bookmarkId && { bookmarkId: bookmarkId }),
isTemplate: false,
},
newDigest,
order // we want to keep the same order as the template
);
})
);

return newDigest;
}

export const orderBlock = async (
digestId: string,
blockId: string,
position: number
) => {
const digestBlocks = await db.digestBlock.findMany({
where: {
digestId: digestId,
},
orderBy: {
order: 'asc',
},
});

if (digestBlocks) {
const bookmarkDigestMoved = digestBlocks.find(
(bookmarkDigest) => bookmarkDigest.id === blockId
);

if (bookmarkDigestMoved) {
await db.$transaction(
reorderList(digestBlocks, bookmarkDigestMoved.order, position).map(
(currentBookmarkDigest: any, index: number) => {
return db.digestBlock.updateMany({
where: {
id: currentBookmarkDigest.id,
digestId: digestId,
},
data: { order: index },
});
}
)
);
}
}
};

/**
* Create a digest block in a digest. If position is provided, the block will be ordered to that position depending on the other blocks in the digest.
* If order is provided, the block will be ordered to that position regardless of the other blocks in the digest.
* @param blockInfo The data to create the block with
* @param digest The digest to create the block in
* @param order Optional | The order to place the block in
* @returns The created block
*/
export const createDigestBlock = async (
blockInfo: CreateBlockData,
digest: Digest & {
digestBlocks: DigestBlock[];
},
order?: number | undefined
) => {
const { bookmarkId, text, style, type, position, isTemplate } = blockInfo;
const hasOrderParam = order !== undefined;
const block = await db.digestBlock.create({
data: {
digestId: digest.id,
...(bookmarkId && { bookmarkId }),
...(text && { text }),
...(style && { style }),
order: hasOrderParam ? order : digest.digestBlocks.length,
type,
isTemplate,
},
});

if (position !== undefined && !hasOrderParam) {
await orderBlock(digest.id, block.id, position);
}
return block;
};
27 changes: 1 addition & 26 deletions src/pages/api/teams/[teamId]/digests/[digestId]/block/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@prisma/client';
import type { NextApiResponse } from 'next';
import { createRouter } from 'next-connect';
import { orderBlock } from '../order';
import { createDigestBlock } from '@/lib/queries';

export type ApiBookmarkDigestResponseSuccess = DigestBlock;
export const router = createRouter<AuthApiRequest, NextApiResponse>();
Expand All @@ -23,31 +23,6 @@ export type CreateBlockData = {
isTemplate?: boolean;
};

export const createDigestBlock = async (
blockInfo: CreateBlockData,
digest: Digest & {
digestBlocks: DigestBlock[];
}
) => {
const { bookmarkId, text, style, type, position, isTemplate } = blockInfo;
const block = await client.digestBlock.create({
data: {
digestId: digest.id,
...(bookmarkId && { bookmarkId }),
...(text && { text }),
...(style && { style }),
order: digest.digestBlocks.length,
type,
isTemplate,
},
});

if (position !== undefined) {
await orderBlock(digest.id, block.id, position);
}
return block;
};

router
.use(checkTeam)
.use(checkDigest)
Expand Down
Loading

1 comment on commit 5f9244a

@vercel
Copy link

@vercel vercel bot commented on 5f9244a Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

digestclub – ./

digestclub-premieroctet.vercel.app
digestclub.vercel.app
digestclub-git-main-premieroctet.vercel.app

Please sign in to comment.