From ae0bc7dd1236f101a13aac0400aa4f571b9c707b Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Sat, 15 Nov 2025 05:44:18 +0530 Subject: [PATCH] update and create article provider functions --- src/blog/components/Article/ArticleEditor.tsx | 21 ++++++- src/blog/providers/Article.tsx | 61 ++++++++++++++++++- src/blog/types/contexts.ts | 2 + 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/blog/components/Article/ArticleEditor.tsx b/src/blog/components/Article/ArticleEditor.tsx index 934070f..c66ae1d 100644 --- a/src/blog/components/Article/ArticleEditor.tsx +++ b/src/blog/components/Article/ArticleEditor.tsx @@ -1,12 +1,14 @@ import * as React from 'react'; -import { Box, Typography, Divider, IconButton, Chip, TextField, Button } from '@mui/material'; +import { Box, Typography, Divider, IconButton, TextField, Button } from '@mui/material'; import { styled } from '@mui/material/styles'; import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded'; import { ArticleEditorProps } from '../../types/props'; +import { ArticleModel } from "../../types/models"; +import { useUpload } from "../../providers/Upload"; +import { useArticles } from "../../providers/Article"; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import ImageUploadField from "../ImageUploadField"; -import { useUpload } from "../../providers/Upload"; const ArticleContainer = styled(Box)(({ theme }) => ({ maxWidth: '800px', @@ -31,6 +33,7 @@ export default function ArticleView({ }: ArticleEditorProps) { const { uploadFile } = useUpload(); + const { updateArticle, createArticle } = useArticles(); const [title, setTitle] = React.useState(article?.title ?? ""); const [description, setDescription] = React.useState(article?.description ?? ""); @@ -54,6 +57,18 @@ export default function ArticleView({ } }; + const handleSaveArticle = async (articleData: Partial) => { + // If _id exists → UPDATE + if (articleData._id) { + console.log("Updating article with ID:", articleData._id); + return await updateArticle(articleData as ArticleModel); + } + + // No _id → CREATE + console.log("Creating new article:", articleData); + return await createArticle(articleData as ArticleModel); + }; + return ( {/* BACK BUTTON */} @@ -159,7 +174,7 @@ export default function ArticleView({ variant="contained" color="primary" onClick={() => - console.log({ + handleSaveArticle({ ...article, title, tag, diff --git a/src/blog/providers/Article.tsx b/src/blog/providers/Article.tsx index 381f82b..9a676a5 100644 --- a/src/blog/providers/Article.tsx +++ b/src/blog/providers/Article.tsx @@ -12,6 +12,14 @@ export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ child const [error, setError] = useState(null); const { token } = useAuth(); + /** 🔹 Author IDs must be strings for API, so we normalize here */ + const normalizeArticleForApi = (article: Partial) => ({ + ...article, + authors: (article.authors ?? []).map(a => + a._id + ), + }); + /** 🔹 Fetch articles (JWT automatically attached by api.ts interceptor) */ const fetchArticles = async () => { try { @@ -29,6 +37,50 @@ export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ child } }; + /** 🔹 Update article */ + const updateArticle = async (articleData: ArticleModel) => { + if (!articleData._id) { + console.error('updateArticle called without _id'); + return; + } + + const normalizedArticleData = normalizeArticleForApi(articleData); + try { + setLoading(true); + setError(null); + + const res = await api.put(`/articles/${articleData._id}`, normalizedArticleData); + return res.data; + } catch (err: any) { + console.error('Article update failed:', err); + setError(err.response?.data?.detail || 'Failed to update article'); + } finally { + setLoading(false); + } + }; + + /** 🔹 Create article */ + const createArticle = async (articleData: ArticleModel) => { + if (articleData._id) { + console.error('createArticle called with _id'); + return; + } + + const normalizedArticleData = normalizeArticleForApi(articleData); + try { + setLoading(true); + setError(null); + + const res = await api.post(`/articles`, normalizedArticleData); + return res.data; + } catch (err: any) { + console.error('Article create failed:', err); + setError(err.response?.data?.detail || 'Failed to create article'); + } finally { + setLoading(false); + } + }; + /** 🔹 Auto-fetch articles whenever user logs in/out */ useEffect(() => { // Always load once on mount @@ -41,7 +93,14 @@ export const ArticleProvider: React.FC<{ children: React.ReactNode }> = ({ child }, [token]); return ( - + {children} ); diff --git a/src/blog/types/contexts.ts b/src/blog/types/contexts.ts index 9a46603..9b46f44 100644 --- a/src/blog/types/contexts.ts +++ b/src/blog/types/contexts.ts @@ -5,6 +5,8 @@ export interface ArticleContextModel { loading: boolean; error: string | null; refreshArticles: () => Promise; + updateArticle: (user: ArticleModel) => Promise; + createArticle: (user: ArticleModel) => Promise; } export interface AuthContextModel {