Skip to content

Commit a61dd71

Browse files
committed
feat: update the snippetDetail page with the backend data
1 parent 397a8e4 commit a61dd71

File tree

4 files changed

+83
-21
lines changed

4 files changed

+83
-21
lines changed

src/pages/snippets/SnippetDetailPage.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { Separator } from "@/components/ui/separator";
1313
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
1414
import { useToast } from "@/hooks/use-toast";
15-
import { MOCK_SNIPPETS } from "@/mockdata";
15+
import { AppDispatch } from "@/store";
1616
import { formatDistanceToNow } from "date-fns";
1717
import { useEffect, useState } from "react";
1818
import {
@@ -26,9 +26,15 @@ import {
2626
import { FiArrowLeft, FiShare2 } from "react-icons/fi";
2727
import { MdContentCopy } from "react-icons/md";
2828
import { SlCalender } from "react-icons/sl";
29+
import { useDispatch, useSelector } from "react-redux";
2930
import { useNavigate, useParams } from "react-router-dom";
31+
import { toggleLikeSnippet } from "@/store/slices/snippetSlice";
3032

3133
const SnippetDetailPage = () => {
34+
const { snippets, currentSnippet } = useSelector(
35+
(state: any) => state.snippet
36+
);
37+
const dispatch = useDispatch<AppDispatch>();
3238
const [activeTab, setActiveTab] = useState("code");
3339
const [snippet, setSnippet] = useState<any>({});
3440
const [isLiked, setIsLiked] = useState<Boolean>(false);
@@ -39,8 +45,8 @@ const SnippetDetailPage = () => {
3945
const showToast = useToast();
4046

4147
useEffect(() => {
42-
const foundSnippet = MOCK_SNIPPETS.find(
43-
(snippet) => snippet.id === snippetID
48+
const foundSnippet = snippets.find(
49+
(snippet: any) => snippet?._id === snippetID
4450
);
4551

4652
if (foundSnippet) {
@@ -55,6 +61,8 @@ const SnippetDetailPage = () => {
5561
const updatedIsLiked = !isLiked;
5662
setIsLiked(updatedIsLiked);
5763

64+
dispatch(toggleLikeSnippet(snippet?._id));
65+
5866
showToast(
5967
updatedIsLiked
6068
? "You've liked this snippet"
@@ -178,18 +186,18 @@ const SnippetDetailPage = () => {
178186
</Button>
179187
</div>
180188
<pre className="bg-muted p-4 rounded-md overflow-x-auto ">
181-
<code>{snippet?.content}</code>
189+
<code>{snippet?.code}</code>
182190
</pre>
183191
</TabsContent>
184192

185193
<TabsContent value="comments" className="pt-4">
186194
<div className="space-y-4 last:mb-4">
187-
{comments.length === 0 ? (
195+
{snippet?.comments?.length === 0 ? (
188196
<p className="text-center text-muted-foreground py-6">
189197
No comments yet. Be the first to comment!
190198
</p>
191199
) : (
192-
comments.map((comment) => (
200+
snippet?.comments?.map((comment: any) => (
193201
<div key={comment.id} className="border rounded-md p-4">
194202
<div className="flex items-start gap-3">
195203
<Avatar className="size-8">
@@ -223,7 +231,7 @@ const SnippetDetailPage = () => {
223231
<div className="flex items-center space-x-4 text-muted-foreground">
224232
<div className="flex items-center">
225233
<FaRegHeart className="size-4 mr-1" />
226-
<span>{isLiked ? snippet.likes + 1 : snippet.likes}</span>
234+
<span>{snippet?.likeCount}</span>
227235
</div>
228236
<div className="flex items-center">
229237
<FaRegCommentAlt className="size-4 mr-1" />
@@ -246,11 +254,11 @@ const SnippetDetailPage = () => {
246254
alt={snippet?.author?.name}
247255
/>
248256
<AvatarFallback>
249-
{snippet?.author?.name.charAt(0)}
257+
{snippet?.owner?.name.charAt(0)}
250258
</AvatarFallback>
251259
</Avatar>
252260
<div>
253-
<p className="font-medium">{snippet?.author?.name}</p>
261+
<p className="font-medium">{snippet?.owner?.name}</p>
254262
<p className="text-sm text-muted-foreground">Author</p>
255263
</div>
256264
</div>

src/pages/snippets/SnippetsPage.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import LoadingSnipper from "@/components/LoadingSnipper";
2+
import Pagination from "@/components/Pagination";
23
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
34
import { Badge } from "@/components/ui/badge";
45
import { Button } from "@/components/ui/button";
@@ -19,21 +20,19 @@ import {
1920
SelectTrigger,
2021
SelectValue,
2122
} from "@/components/ui/select";
22-
import { MOCK_SNIPPETS } from "@/mockdata";
23+
import { supportedLanguages } from "@/constants";
2324
import { AppDispatch, RootState } from "@/store";
2425
import { getSnippets } from "@/store/slices/snippetSlice";
26+
import { setCurrentPage } from "@/store/slices/templateSlice";
2527
import { useEffect, useState } from "react";
2628
import { CiHeart, CiSearch } from "react-icons/ci";
2729
import { FaCode, FaFileCode } from "react-icons/fa";
2830
import { FiMessageSquare } from "react-icons/fi";
2931
import { useDispatch, useSelector } from "react-redux";
3032
import { useNavigate } from "react-router-dom";
31-
import { supportedLanguages } from "@/constants";
32-
import Pagination from "@/components/Pagination";
33-
import { setCurrentPage } from "@/store/slices/templateSlice";
3433

3534
const SnippetsPage = () => {
36-
const { snippets, isLoading, error, totalPages, currentPage } = useSelector(
35+
const { snippets, isLoading, totalPages, currentPage } = useSelector(
3736
(state: RootState) => state.snippet
3837
);
3938
const dispatch = useDispatch<AppDispatch>();
@@ -54,7 +53,7 @@ const SnippetsPage = () => {
5453
);
5554
}, [dispatch, languageFilter, searchQuery, currentPage]);
5655

57-
const handleViewSnippet = (snippetId: number) => {
56+
const handleViewSnippet = (snippetId: string) => {
5857
navigate(`/snippets/${snippetId}`);
5958
};
6059

@@ -143,7 +142,7 @@ const SnippetsPage = () => {
143142
<CardTitle
144143
className="text-xl hover:text-primary cursor-pointer"
145144
onClick={() => {
146-
handleViewSnippet(Number(snippet._id));
145+
handleViewSnippet(snippet?._id as string);
147146
}}
148147
>
149148
{snippet.title}
@@ -205,7 +204,7 @@ const SnippetsPage = () => {
205204
variant="outline"
206205
size="sm"
207206
onClick={() => {
208-
handleViewSnippet(Number(snippet._id));
207+
handleViewSnippet(snippet._id as string);
209208
}}
210209
>
211210
View Details

src/store/slices/snippetSlice.ts

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import type { SnippetState } from "@/types";
2-
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
2+
import {
3+
createAsyncThunk,
4+
createSlice,
5+
isRejectedWithValue,
6+
PayloadAction,
7+
} from "@reduxjs/toolkit";
38
import axios from "axios";
49

510
const API = import.meta.env.VITE_API_URL;
@@ -106,7 +111,32 @@ export const getSnippet = createAsyncThunk(
106111
// Toggle like snippet
107112
export const toggleLikeSnippet = createAsyncThunk(
108113
"snippet/toggleLikeSnippet",
109-
async () => {}
114+
async (snippetId: string, { rejectWithValue }) => {
115+
const token = localStorage.getItem("token");
116+
117+
if (!token) {
118+
return rejectWithValue("No authentication token");
119+
}
120+
121+
try {
122+
const response = await axios.post(
123+
`${API}/snippets/${snippetId}/like`,
124+
{},
125+
{
126+
headers: {
127+
Authorization: `Bearer ${token}`,
128+
"Content-Type": "application/json",
129+
},
130+
}
131+
);
132+
133+
return response.data.data;
134+
} catch (error: any) {
135+
return rejectWithValue(
136+
error.response?.data?.message || "Failed to like snippet"
137+
);
138+
}
139+
}
110140
);
111141

112142
// Update snippet
@@ -170,7 +200,31 @@ const snippetSlice = createSlice({
170200
.addCase(getSnippets.rejected, (state, action: PayloadAction<any>) => {
171201
state.isLoading = false;
172202
state.error = action.payload;
173-
});
203+
})
204+
// toggle like snippet
205+
.addCase(toggleLikeSnippet.pending, (state) => {
206+
state.isLoading = true;
207+
state.error = null;
208+
})
209+
.addCase(
210+
toggleLikeSnippet.fulfilled,
211+
(state, action: PayloadAction<any>) => {
212+
state.isLoading = false;
213+
const { snippetId, isLiked, likeCount } = action.payload;
214+
215+
if (state.currentSnippet && state.currentSnippet?._id === snippetId) {
216+
state.currentSnippet.likeCount = likeCount;
217+
state.currentSnippet.isLiked = isLiked;
218+
}
219+
}
220+
)
221+
.addCase(
222+
toggleLikeSnippet.rejected,
223+
(state, action: PayloadAction<any>) => {
224+
state.isLoading = false;
225+
state.error = action.payload;
226+
}
227+
);
174228
},
175229
});
176230

src/types/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export interface SnippetOwner {
143143
}
144144

145145
export interface Snippet {
146-
_id?: string;
146+
_id: string;
147147
title: string;
148148
description?: string;
149149
code: string;
@@ -165,6 +165,7 @@ export interface Snippet {
165165
owner: SnippetOwner;
166166
viewCount: number;
167167
likeCount: number;
168+
isLiked: Boolean;
168169
comments: any[];
169170
commentcount: number;
170171
createdAt: string;

0 commit comments

Comments
 (0)