From 989be4cbf299e78a4b2c296f5bbfd1b5548a7b3c Mon Sep 17 00:00:00 2001 From: warmachine028 <75939390+warmachine028@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:13:41 +0530 Subject: [PATCH] feat: server controllers for posts --- .prettierrc | 5 +- client/bun.lockb | Bin 147815 -> 150059 bytes client/package.json | 9 +- client/src/api/posts.ts | 10 +-- client/src/components/ui/index.ts | 1 + client/src/components/ui/mode-toggle.tsx | 16 ++-- client/src/components/ui/search.tsx | 1 + client/src/components/ui/separator.tsx | 29 ++++++ client/src/index.css | 2 + client/src/pages/Posts.tsx | 16 ++-- client/src/pages/Todos.tsx | 30 +++---- client/src/pages/Vite.tsx | 109 ++++++++++++++++------- server/src/controllers/index.ts | 67 +++++++------- server/src/lib/index.ts | 1 + server/src/routes/index.ts | 23 ++++- server/src/types.d.ts | 15 ++++ 16 files changed, 226 insertions(+), 108 deletions(-) create mode 100644 client/src/components/ui/separator.tsx create mode 100644 server/src/lib/index.ts create mode 100644 server/src/types.d.ts diff --git a/.prettierrc b/.prettierrc index eff7b7c..ab10840 100644 --- a/.prettierrc +++ b/.prettierrc @@ -7,5 +7,8 @@ "trailingComma": "none", "bracketSpacing": true, "arrowParens": "always", - "endOfLine": "lf" + "endOfLine": "lf", + "plugins": [ + "prettier-plugin-tailwindcss" + ] } diff --git a/client/bun.lockb b/client/bun.lockb index 6e70273bd61923e326aff3fb230ee7c6474eb0ad..6ed77dd815f4f46185859e351cd0728f338f77c8 100644 GIT binary patch delta 27354 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 V!XB{?BgCn;hWc9)O@@Ee`+uJUyDI => { } } -// Search posts export const searchPosts = async (query: string): Promise => { try { const { data } = await api.get(`/posts/search?q=${query}`) - const postsWithImages = data.posts.map((post) => ({ - ...post, - imageUrl: `https://picsum.photos/seed/${post.id}/800/600` - })) - - return { ...data, posts: postsWithImages } + return data } catch (error) { throw handleApiError(error) } @@ -78,7 +71,6 @@ export const getPostsByUser = async (userId: number): Promise => export const updateReaction = async (postId: number, type: 'like' | 'dislike') => { try { - await sleep(3000) const { data } = await api.put(`/posts/${postId}`, { reactions: { [type]: +1 } }) return data diff --git a/client/src/components/ui/index.ts b/client/src/components/ui/index.ts index 08ed825..79bd353 100644 --- a/client/src/components/ui/index.ts +++ b/client/src/components/ui/index.ts @@ -7,3 +7,4 @@ export { ScrollArea } from './scroll-area' export { Badge } from './badge' export { Textarea } from './textarea' export { Search } from './search' +export { Separator } from './separator' diff --git a/client/src/components/ui/mode-toggle.tsx b/client/src/components/ui/mode-toggle.tsx index 191832b..878a5f3 100644 --- a/client/src/components/ui/mode-toggle.tsx +++ b/client/src/components/ui/mode-toggle.tsx @@ -1,17 +1,23 @@ -import { Moon, Sun } from 'lucide-react' +import { Computer, Moon, Sun } from 'lucide-react' import { Button } from './button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from './dropdown-menu' import { useTheme } from '@/hooks' export const ModeToggle = ({ variant, className }: { variant?: 'default' | 'outline'; className?: string }) => { - const { setTheme } = useTheme() - + const { setTheme, theme } = useTheme() + console.log(theme) return ( diff --git a/client/src/components/ui/search.tsx b/client/src/components/ui/search.tsx index 945cc09..8f9fc1d 100644 --- a/client/src/components/ui/search.tsx +++ b/client/src/components/ui/search.tsx @@ -18,5 +18,6 @@ const Search = ({ className, iconClassName, ...props }: { iconClassName?: string ) } +Search.displayName = 'Search' export { Search } diff --git a/client/src/components/ui/separator.tsx b/client/src/components/ui/separator.tsx new file mode 100644 index 0000000..6d7f122 --- /dev/null +++ b/client/src/components/ui/separator.tsx @@ -0,0 +1,29 @@ +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/client/src/index.css b/client/src/index.css index 35de7f0..b1ff4bc 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -29,6 +29,8 @@ a:hover { body { margin: 0; display: flex; + align-items: center; + justify-content: center; place-items: center; min-width: 320px; min-height: 100vh; diff --git a/client/src/pages/Posts.tsx b/client/src/pages/Posts.tsx index ddc4c4f..b3aa799 100644 --- a/client/src/pages/Posts.tsx +++ b/client/src/pages/Posts.tsx @@ -29,7 +29,7 @@ const PostsCard = () => {
Posts -
+
{status === 'pending' ? ( -
- +
+
) : status === 'error' ? ( -

Error fetching posts

+

Error fetching posts

) : ( {results.map((post) => ( @@ -83,8 +83,8 @@ const PostsCard = () => { )} {isFetchingNextPage && ( -
- +
+
)}
@@ -97,7 +97,7 @@ const PostsCard = () => { const Posts = () => { return (
-
+
diff --git a/client/src/pages/Todos.tsx b/client/src/pages/Todos.tsx index d226032..dc54daa 100644 --- a/client/src/pages/Todos.tsx +++ b/client/src/pages/Todos.tsx @@ -91,11 +91,11 @@ export default function Todos() { {status === 'pending' ? ( -
- +
+
) : status === 'error' ? ( -

Error fetching todos

+

Error fetching todos

) : (
    {data.pages.map((page, i) => ( @@ -103,9 +103,9 @@ export default function Todos() { {page.todos.map((todo) => (
  • -
    +
    {todo.title} @@ -127,7 +127,7 @@ export default function Todos() { onClick={() => handleDeleteTodo(todo.id)} className="text-destructive hover:text-destructive hover:bg-destructive/10" > - +
  • ))} @@ -136,8 +136,8 @@ export default function Todos() {
)} {isFetchingNextPage && ( -
- +
+
)}
@@ -155,15 +155,11 @@ export default function Todos() { diff --git a/client/src/pages/Vite.tsx b/client/src/pages/Vite.tsx index 5eb3b7b..4c32ead 100644 --- a/client/src/pages/Vite.tsx +++ b/client/src/pages/Vite.tsx @@ -1,42 +1,85 @@ import { useState } from 'react' -import { reactLogo } from '@/assets' +import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card' +import { Button, Separator, ModeToggle } from '@/components/ui' import { Link } from 'react-router-dom' -import { Button, Card, ModeToggle } from '@/components/ui' -import '@/App.css' +import { House } from 'lucide-react' +import { create } from 'zustand' -const Vite = () => { - const [count, setCount] = useState(0) +const logos = [ + { name: 'Vite', url: 'https://vite.dev', src: '/vite.svg' }, + { name: 'React Query', url: 'https://tanstack.com/query', src: 'https://query.gg/favicon.png' }, + { name: 'Zustand', url: 'https://zustand-demo.pmnd.rs', src: 'https://zustand-demo.pmnd.rs/favicon.ico' }, + { name: 'shadcn/ui', url: 'https://ui.shadcn.com', src: 'https://ui.shadcn.com/favicon.ico' }, + { name: 'React', url: 'https://react.dev', src: 'https://react.dev/favicon.ico' }, + { name: 'Axios', url: 'https://axios-http.com', src: 'https://axios-http.com/assets/favicon.ico' }, + { name: 'Tailwind CSS', url: 'https://tailwindcss.com', src: 'https://tailwindcss.com/favicons/favicon.ico' }, + { name: 'Lucide Icons', url: 'https://lucide.dev', src: 'https://lucide.dev/favicon.ico' }, + { name: 'TypeScript', url: 'https://www.typescriptlang.org', src: 'https://www.typescriptlang.org/favicon.ico' } +] - return ( - -
- - Vite logo - - - React logo - - - React Query logo - -
-

Vite + React

-
{count}
- - - +type Store = { + count: number + inc: () => void + dec: () => void +} -

- Edit src/App.tsx and save to test HMR -

+const useStore = create()((set) => ({ + count: 1, + inc: () => set((state) => ({ count: state.count + 1 })), + dec: () => set((state) => ({ count: state.count - 1 })) +})) -

Click on the Vite and React logos to learn more

-
+const TechStack = () => { + const { count, inc, dec } = useStore() + + return ( +
+ + + Tech Stack + + +
+ {logos.map((logo) => ( + + {`${logo.name} + {logo.name} + + ))} +
+ +
+
{count}
+
+ + + + +
+
+
+ +

+ Edit src/TechStack.tsx and save to test HMR +

+
+
+
) } -export default Vite +export default TechStack diff --git a/server/src/controllers/index.ts b/server/src/controllers/index.ts index cec05c4..8c9b8eb 100644 --- a/server/src/controllers/index.ts +++ b/server/src/controllers/index.ts @@ -1,29 +1,23 @@ -interface Post { - id: number - title: string - reactions: { likes: number; dislikes: number } - tags: string[] - userId: number - imageUrl: string -} +import type { Post, Request } from '@/types' -type GetPostsParams = { - query: { skip?: string; limit?: string } -} +const baseUrl = 'https://dummyjson.com' +const delay = 5000 -type UpdatePostParams = { - params: { id: number } - body: Post -} +export const getPosts = async ({ query: { skip, limit } }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts?skip=${skip || 0}&limit=${limit || 10}`) + const data = await response.json() -type CreatePostParams = { - body: Omit + return { + ...data, + posts: data.posts.map((post: Post) => ({ + ...post, + imageUrl: `https://picsum.photos/seed/${post.id}/800/600` + })) + } } -const baseUrl = 'https://dummyjson.com' - -export const getPosts = async ({ query: { skip, limit } }: GetPostsParams): Promise => { - const response = await fetch(`${baseUrl}/posts?skip=${skip || 0}&limit=${limit || 10}`) +export const searchPosts = async ({ query: { q } }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts/search?q=${q}&delay=${delay}`) const data = await response.json() return { @@ -34,14 +28,21 @@ export const getPosts = async ({ query: { skip, limit } }: GetPostsParams): Prom })) } } -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) -export const createPost = async ({ body: post }: CreatePostParams): Promise => { - await sleep(5000) - const response = await fetch(`${baseUrl}/posts/add`, { +export const getPost = async ({ params: { id } }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts/${id}`) + const data = await response.json() + return { + ...data, + imageUrl: `https://picsum.photos/seed/${data.id}/800/600` + } +} + +export const createPost = async ({ body }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts/add?delay=${delay}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(post) + body: JSON.stringify(body) }) const data = await response.json() return { @@ -50,12 +51,11 @@ export const createPost = async ({ body: post }: CreatePostParams): Promise => { - await sleep(5000) - const response = await fetch(`${baseUrl}/posts/${id}`, { +export const updatePost = async ({ body, params: { id } }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts/${id}?delay=${delay}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(post) + body: JSON.stringify(body) }) const data = await response.json() return { @@ -63,3 +63,10 @@ export const updatePost = async ({ body: post, params: { id } }: UpdatePostParam imageUrl: `https://picsum.photos/seed/${data.id}/800/600` } } + +export const deletePost = async ({ params: { id } }: Request): Promise => { + const response = await fetch(`${baseUrl}/posts/${id}?delay=${delay}`, { method: 'DELETE' }) + return response.json() +} + + diff --git a/server/src/lib/index.ts b/server/src/lib/index.ts new file mode 100644 index 0000000..ae79457 --- /dev/null +++ b/server/src/lib/index.ts @@ -0,0 +1 @@ +export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/server/src/routes/index.ts b/server/src/routes/index.ts index 96c7e0f..b8219a0 100644 --- a/server/src/routes/index.ts +++ b/server/src/routes/index.ts @@ -1,20 +1,29 @@ import { Elysia, t } from 'elysia' -import { createPost, getPosts, updatePost } from '@/controllers' +import { createPost, deletePost, getPost, getPosts, searchPosts, updatePost } from '@/controllers' export const postRoutes = new Elysia({ prefix: '/posts' }) - // .get('/', getPosts, { query: t.Object({ skip: t.Optional(t.String()), limit: t.Optional(t.String()) }) }) + .get('/search', searchPosts, { + query: t.Object({ + q: t.String() + }) + }) + .get('/:id', getPost, { + params: t.Object({ + id: t.Number() + }) + }) .post('/', createPost, { body: t.Object({ title: t.String(), body: t.String(), + tags: t.Array(t.String()), userId: t.Number(), - tags: t.Array(t.String()) }) }) .put('/:id', updatePost, { @@ -23,5 +32,13 @@ export const postRoutes = new Elysia({ prefix: '/posts' }) body: t.String(), tags: t.Array(t.String()), userId: t.Number() + }), + params: t.Object({ + id: t.Number() + }) + }) + .delete('/:id', deletePost, { + params: t.Object({ + id: t.Number() }) }) diff --git a/server/src/types.d.ts b/server/src/types.d.ts new file mode 100644 index 0000000..0478107 --- /dev/null +++ b/server/src/types.d.ts @@ -0,0 +1,15 @@ +export interface Post { + id: number + title: string + reactions: { likes: number; dislikes: number } + tags: string[] + userId: number + imageUrl: string +} + + +export type Request = { + params: { id: number } + query: { skip?: string; limit?: string; q?: string } + body: Post +} \ No newline at end of file