diff --git a/package-lock.json b/package-lock.json
index 3b12f0b..4f23825 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,6 +32,7 @@
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/preset-typescript": "^7.18.6",
+ "@types/react-toastify": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.49.0",
"eslint": "^8.32.0",
@@ -4213,6 +4214,27 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-toastify": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/react-toastify/-/react-toastify-4.0.2.tgz",
+ "integrity": "sha512-pHjCstnN0ZgopIWQ9UiWsD9n+HsXs1PnMQC4hIZuSzpDO0lRjigpTuqsUtnBkMbLIg+mGFSAsBjL49SspzoLKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*",
+ "@types/react-transition-group": "*"
+ }
+ },
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.12",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+ "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -21723,6 +21745,23 @@
"@types/react": "*"
}
},
+ "@types/react-toastify": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/react-toastify/-/react-toastify-4.0.2.tgz",
+ "integrity": "sha512-pHjCstnN0ZgopIWQ9UiWsD9n+HsXs1PnMQC4hIZuSzpDO0lRjigpTuqsUtnBkMbLIg+mGFSAsBjL49SspzoLKA==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*",
+ "@types/react-transition-group": "*"
+ }
+ },
+ "@types/react-transition-group": {
+ "version": "4.4.12",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+ "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+ "dev": true,
+ "requires": {}
+ },
"@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
diff --git a/package.json b/package.json
index bbe6f1b..d664795 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/preset-typescript": "^7.18.6",
+ "@types/react-toastify": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.49.0",
"@typescript-eslint/parser": "^5.49.0",
"eslint": "^8.32.0",
diff --git a/src/App.tsx b/src/App.tsx
index f9fb05b..c13f921 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,11 +1,13 @@
import React from 'react';
import Router from './Router';
import UserContextProvider from '@/contexts/UserContextProvider';
-
+import "react-toastify/dist/ReactToastify.css";
+import { ToastContainer } from "react-toastify";
function App() {
return (
+
diff --git a/src/components/article/Revisions.tsx b/src/components/article/Revisions.tsx
new file mode 100644
index 0000000..a393b98
--- /dev/null
+++ b/src/components/article/Revisions.tsx
@@ -0,0 +1,54 @@
+
+import { useRevisions,useRevertRevision } from "@/lib/hooks/useRevisions";
+import React from "react";
+
+import { toast } from "react-toastify";
+interface RevisionsProps {
+ articleId: number;
+ isAdmin: boolean;
+}
+
+const Revisions: React.FC = ({ articleId, isAdmin }) => {
+ const { data: revisions, isLoading, error } = useRevisions(articleId);
+ const revertMutation = useRevertRevision();
+
+ const handleRevert = async (revisionId: number) => {
+ try {
+ await revertMutation.mutateAsync({ articleId, revisionId });
+ toast.success("Article reverted successfully!");
+ } catch (err) {
+ toast.error("Failed to revert article");
+ }
+ };
+
+ if (isLoading) return Loading revisions...
;
+ if (error) return Error loading revisions
;
+
+ return (
+
+
Revision History
+
+ {revisions?.map((revision) => (
+ -
+
+ Timestamp: {new Date(revision.created_at).toLocaleString()}
+
+
+ Content: {revision.content.slice(0, 50)}...
+
+ {isAdmin && (
+
+ )}
+
+ ))}
+
+
+ );
+};
+
+export default Revisions;
diff --git a/src/lib/hooks/useRevisions.ts b/src/lib/hooks/useRevisions.ts
new file mode 100644
index 0000000..849e34d
--- /dev/null
+++ b/src/lib/hooks/useRevisions.ts
@@ -0,0 +1,35 @@
+import apiClient from '@/repositories/apiClient';
+import { useMutation, useQuery } from '@tanstack/react-query';
+
+// Revision Type
+export interface Revision {
+ id: number;
+ article_id: number;
+ content: string;
+ created_at: string;
+}
+
+// Fetch Revisions
+export const useRevisions = (articleId: number) =>
+ useQuery(["revisions", articleId], async () => {
+ const { data } = await apiClient.get(`/articles/${articleId}/revisions`);
+ return data;
+ });
+
+// Fetch Single Revision
+export const useRevision = (articleId: number, revisionId: number) =>
+ useQuery(["revision", articleId, revisionId], async () => {
+ const { data } = await apiClient.get(
+ `/articles/${articleId}/revisions/${revisionId}`
+ );
+ return data;
+ });
+
+// Revert to a Revision
+export const useRevertRevision = () =>
+ useMutation(async ({ articleId, revisionId }: { articleId: number; revisionId: number }) => {
+ const { data } = await apiClient.post(
+ `/articles/${articleId}/revisions/${revisionId}/revert`
+ );
+ return data;
+ });
diff --git a/src/pages/ArticlePage.tsx b/src/pages/ArticlePage.tsx
index a71c90f..11a3e5e 100644
--- a/src/pages/ArticlePage.tsx
+++ b/src/pages/ArticlePage.tsx
@@ -8,11 +8,17 @@ import { UserContext } from '@/contexts/UserContextProvider';
import Comment from '@/components/article/Comment';
import routerMeta from '@/lib/routerMeta';
import convertToDate from '@/lib/utils/convertToDate';
+//import Revisions from '@/components/Revisions'; // ✅ Import Revisions
+import { useGetUserQuery } from '@/queries/user.query';
+import Revisions from '@/components/article/Revisions';
const ArticlePage = () => {
const { state } = useLocation();
const [articleInfo, commentsInfo] = useGetArticleQueries(state);
- const { isLogin } = useContext(UserContext);
+ const { isLogin } = useContext(UserContext); // ✅ Get user info for admin check
+ const { data } = useGetUserQuery();
+ const articleId = articleInfo.data.id;
+ const isAdmin = data?.is_admin || data?.id === articleInfo.data.author.id; // ✅ Check if user is admin or author
return (
@@ -55,6 +61,11 @@ const ArticlePage = () => {
+ {/* ✅ Add Revisions Section */}
+
+
+
+