Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geeks for geeks of 100x devs introducing 100x blogs #663

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
reactStrictMode: false,
experimental: {
serverActions: {
bodySizeLimit: '10mb',
allowedOrigins: ['localhost:3000', 'app.100xdevs.com', 'app2.100xdevs.com']
}
},
Expand Down
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
"nextjs-toploader": "^1.6.11",
"@discordjs/core": "^1.1.1",
"@discordjs/next": "^0.1.1-dev.1673526225-a580768.0",
"@editorjs/editorjs": "^2.29.1",
"@editorjs/header": "^2.8.1",
"@editorjs/inline-code": "^1.5.0",
"@editorjs/list": "^1.9.0",
"@editorjs/simple-image": "^1.6.0",
"@editorjs/table": "^2.3.0",
"@icons-pack/react-simple-icons": "^9.4.0",
"@prisma/client": "^5.6.0",
"@radix-ui/react-accordion": "^1.1.2",
Expand All @@ -46,6 +52,8 @@
"@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.5",
"@uiw/react-md-editor": "^4.0.4",
"ace-builds": "^1.33.2",
"ace-code-editorjs": "^1.0.2",
"axios": "^1.6.2",
"bcrypt": "^5.1.1",
"canvas": "^2.11.2",
Expand Down Expand Up @@ -85,6 +93,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@types/editorjs__header": "^2.6.3",
"@chromatic-com/storybook": "^1.3.3",
"@storybook/addon-controls": "^8.0.8",
"@storybook/addon-essentials": "^8.0.8",
Expand All @@ -101,14 +110,14 @@
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"autoprefixer": "^10.0.1",

"eslint": "^8.56.0",
"eslint-plugin-storybook": "^0.8.0",
"husky": "^9.0.7",
"postcss": "^8",
"prettier": "^3.2.4",
"prisma": "^5.6.0",
"simple-image-editorjs": "^1.4.0",
"tailwindcss": "^3.3.0",
"ts-node": "^10.9.2",
"ts-node": "^10.9.2"
}
}
17 changes: 17 additions & 0 deletions prisma/migrations/20240517144042_added_blog/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "Blog" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"imageUrl" TEXT NOT NULL,
"subtitle" TEXT NOT NULL,
"content" JSONB NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"authorId" TEXT NOT NULL,
"tags" TEXT[],
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Blog_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Blog" ADD CONSTRAINT "Blog_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
13 changes: 13 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ model User {
questions Question[]
answers Answer[]
certificate Certificate[]
Post Blog[]
}

model DiscordConnect {
Expand Down Expand Up @@ -247,6 +248,18 @@ model Answer {
@@index([parentId])
}

model Blog {
id Int @id @default(autoincrement())
title String
imageUrl String
subtitle String
content Json
createdAt DateTime @default(now())
authorId String
author User @relation(fields: [authorId], references: [id])
tags String[]
updatedAt DateTime @updatedAt
}

model Vote {
id Int @id @default(autoincrement())
Expand Down
70 changes: 70 additions & 0 deletions src/actions/blog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use server';
import { getServerSession } from 'next-auth';
import { InputTypeCreateBlog, ReturnTypeCreateBlog } from './types';
import { authOptions } from '@/lib/auth';
import { createSafeAction } from '@/lib/create-safe-action';
import { blogInsertSchema } from './scema';
import prisma from '@/db';

const createBlogHandler = async (
data: InputTypeCreateBlog,
): Promise<ReturnTypeCreateBlog> => {
try {
const session = await getServerSession(authOptions);

if (!session || !session.user) {
return { error: 'Unauthorized or insufficient permissions' };
}
const { title, subTitle, imageUrl, blocks } = data;
const post = await prisma.blog.create({
data: {
title,
subtitle: subTitle,
imageUrl,
content: blocks,
authorId: session.user.id,
},
});
return { data: post };
} catch (error: any) {
return { error };
}
};

export const getAllBlogs = async () => {
try {
const posts = await prisma.blog.findMany({
select: {
id: true,
title: true,
subtitle: true,
imageUrl: true,
createdAt: true,
updatedAt: true,
author: {
select: {
name: true,
},
},
},
});
return { data: posts };
} catch (error: any) {
return { error };
}
};

export const getBlog = async (id: number) => {
try {
const post = await prisma.blog.findUnique({
where: {
id,
},
});
return { data: post };
} catch (error: any) {
return { error };
}
};

export const createBlog = createSafeAction(blogInsertSchema, createBlogHandler);
27 changes: 27 additions & 0 deletions src/actions/blog/scema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { z } from 'zod';

export const blogInsertSchema = z.object({
title: z.string().min(1),
subTitle: z.string().min(1),
imageUrl: z.string().min(1),
blocks: z.object({
blocks: z.array(
z.object({
id: z.string().optional(),
type: z.string().optional(),
data: z.object({
text: z.string().optional(),
url: z.string().optional(),
items: z.array(z.string()).optional(),
code: z.string().optional(),
language: z.string().optional(),
withBorder: z.boolean().optional(),
withBackground: z.boolean().optional(),
stretched: z.boolean().optional(),
caption: z.string().optional(),
}),
}),
),
}),
tags: z.array(z.string()),
});
7 changes: 7 additions & 0 deletions src/actions/blog/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from 'zod';
import { ActionState } from '@/lib/create-safe-action';
import { blogInsertSchema } from './scema';
import { Post } from '@prisma/client';

export type InputTypeCreateBlog = z.infer<typeof blogInsertSchema>;
export type ReturnTypeCreateBlog = ActionState<InputTypeCreateBlog, Post>;
1 change: 1 addition & 0 deletions src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface QueryParams {
timestamp?: number;
editCommentId?: number;
newPost?: 'open' | 'close';
newBlog?: 'open' | 'close';
}
export enum TabType {
md = 'Most downvotes',
Expand Down
18 changes: 18 additions & 0 deletions src/app/blog/[...blogId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';
import { getBlog } from '@/actions/blog';
import { useParams } from 'next/navigation';
import { useEffect } from 'react';
import { JsonObject } from '@prisma/client/runtime/library';
import { DefaultEditor } from '@/components/DefaultEditor';

export default () => {
const { blogId } = useParams();
useEffect(() => {
getBlog(Number(blogId)).then((res) => {
const content = res.data?.content as JsonObject;
DefaultEditor({ blocks: content.blocks as any[] }, true);
});
}, []);

return <div id="editorjs"></div>;
};
6 changes: 6 additions & 0 deletions src/app/blog/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Loading from '@/components/Loading';
import React from 'react';

export default () => {
return <Loading />;
};
6 changes: 6 additions & 0 deletions src/app/blog/new/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Loading from '@/components/Loading';
import React from 'react';

export default () => {
return <Loading />;
};
64 changes: 64 additions & 0 deletions src/app/blog/new/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
'use client';
import { useEffect, useState } from 'react';
import EditorJS from '@editorjs/editorjs';
import { useRecoilState } from 'recoil';
import { contentAtom } from '@/store/atoms';
import { toast } from 'sonner';
import NewBlogDialog from '@/components/NewBlogDialog';
import { useRouter } from 'next/navigation';
import { DefaultEditor } from '@/components/DefaultEditor';

export default () => {
const [editor, setEditor] = useState<EditorJS | null>(null);
const [content, setContent] = useRecoilState(contentAtom);
const router = useRouter();
useEffect(() => {
const edit = DefaultEditor(
!content
? {
blocks: [
{
type: 'header',
data: {
text: '',
},
},
{
type: 'paragraph',
data: {
text: 'use "/" command to get started',
},
},
],
}
: content,
false,
);
setEditor(edit);
}, [content]);

return (
<div className="p-10">
<div className="flex justify-end">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold rounded p-2"
onClick={() => {
editor?.save().then((outputData) => {
if (outputData.blocks.length < 2) {
toast.error('Title and Subtitle are required');
return;
}
setContent(outputData);
editor.destroy();
router.push('/blog/new?newBlog=open');
});
}}
>
Publish
</button>
</div>
<NewBlogDialog />
<div id="editorjs"></div>
</div>
);
};
24 changes: 24 additions & 0 deletions src/app/blog/new/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
declare module 'simple-image-editorjs' {
const SimpleImage: any;
export default SimpleImage;
}

declare module '@editorjs/list' {
const list: any;
export default list;
}

declare module '@editorjs/table' {
const table: any;
export default table;
}

declare module '@editorjs/inline-code' {
const inlinecode: any;
export default inlinecode;
}

declare module '@editorjs/simple-image' {
const cssWorker: any;
export default cssWorker;
}
Loading
Loading