]> PHS Git Server - phs-admin.git/commitdiff
#PA-1 Modifying posts to work better with attachments.
authorcharleswrayjr <charleswrayjr@gmail.com>
Fri, 26 Sep 2025 06:01:51 +0000 (01:01 -0500)
committercharleswrayjr <charleswrayjr@gmail.com>
Fri, 26 Sep 2025 06:01:51 +0000 (01:01 -0500)
src/app/components/PostForm.js
src/app/components/PostsTable.js
src/app/views/Posts/PostFormView.js [deleted file]
src/app/views/Posts/PostsView.js

index 297612668997daf0a24a813b11489f2ed43e5373..36be28235cca6124c467052f61a1c09a05f8efeb 100644 (file)
  * @file Component for creating a new post
  */
 
-import React from 'react';
-import { useForm, Controller } from 'react-hook-form';
+import React, { useEffect } from 'react';
+import { Controller, useForm } from 'react-hook-form';
 import { yupResolver } from '@hookform/resolvers/yup';
 import * as yup from 'yup';
-import { TextField, MenuItem, Button } from '@mui/material';
+import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Grid, MenuItem, TextField } from '@mui/material';
 import { useSnackbar } from 'notistack';
-import { useNavigate } from 'react-router-dom';
 import { PostService } from '../services';
 
-const schema = yup.object({
-  user_id: yup.number().required('User ID is required'),
-  title: yup.string().required('Title is required'),
-  content: yup.string().required('Content is required'),
-  post_type: yup.string().oneOf(['blog', 'vlog']).required('Post type is required'),
-  visibility: yup.string().oneOf(['private', 'family', 'public']).required('Visibility is required'),
-}).required();
+const schema = yup.object( {
+  user_id: yup.number().required( 'User ID is required' ),
+  title: yup.string().required( 'Title is required' ),
+  content: yup.string().required( 'Content is required' ),
+  post_type: yup.string().oneOf( [ 'blog', 'vlog' ] ).required( 'Post type is required' ),
+  visibility: yup.string().oneOf( [ 'private', 'family', 'public' ] ).required( 'Visibility is required' ),
+} ).required();
 
-const PostForm = () => {
+const PostForm = ( { isOpen, setOpen, refresh, user } ) => {
   const { enqueueSnackbar } = useSnackbar();
-  const navigate = useNavigate();
-  const { control, handleSubmit, formState: { errors } } = useForm({
-    resolver: yupResolver(schema),
-  });
+  const { control, handleSubmit, setValue, reset, formState: { errors } } = useForm( {
+    resolver: yupResolver( schema ),
+  } );
 
-  const onSubmit = async (data) => {
+  useEffect( () => {
+    setValue( 'user_id', user?.id );
+  }, [ user, setValue ] );
+
+  const onSubmit = async ( data ) => {
     try {
-      await PostService.createPost(data);
-      enqueueSnackbar('Post created successfully', { variant: 'success' });
-      navigate('/posts');
-    } catch (error) {
-      enqueueSnackbar(`Error creating post: ${error.message}`, { variant: 'error' });
+      await PostService.createPost( data );
+      await reset();
+      await refresh();
+      enqueueSnackbar( 'Post created successfully', { variant: 'success' } );
+      setOpen( false );
+    } catch ( error ) {
+      enqueueSnackbar( `Error creating post: ${ error.message }`, { variant: 'error' } );
     }
   };
 
+  const onCancel = () => {
+    reset();
+    setOpen( false );
+  };
+
   return (
-    <div className="container">
-      <h2 className="text-2xl font-bold mb-4">Create Post</h2>
-      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
-        <Controller
-          name="user_id"
-          control={control}
-          defaultValue=""
-          render={({ field }) => (
-            <TextField
-              {...field}
-              label="User ID"
-              type="number"
-              fullWidth
-              error={!!errors.user_id}
-              helperText={errors.user_id?.message}
-              className="mb-4"
-            />
-          )}
-        />
-        <Controller
-          name="title"
-          control={control}
-          defaultValue=""
-          render={({ field }) => (
-            <TextField
-              {...field}
-              label="Title"
-              fullWidth
-              error={!!errors.title}
-              helperText={errors.title?.message}
-              className="mb-4"
-            />
-          )}
-        />
-        <Controller
-          name="content"
-          control={control}
-          defaultValue=""
-          render={({ field }) => (
-            <TextField
-              {...field}
-              label="Content"
-              multiline
-              rows={6}
-              fullWidth
-              error={!!errors.content}
-              helperText={errors.content?.message}
-              className="mb-4"
-            />
-          )}
-        />
-        <Controller
-          name="post_type"
-          control={control}
-          defaultValue=""
-          render={({ field }) => (
-            <TextField
-              {...field}
-              label="Post Type"
-              select
-              fullWidth
-              error={!!errors.post_type}
-              helperText={errors.post_type?.message}
-              className="mb-4"
-            >
-              <MenuItem value="blog">Blog</MenuItem>
-              <MenuItem value="vlog">Vlog</MenuItem>
-            </TextField>
-          )}
-        />
-        <Controller
-          name="visibility"
-          control={control}
-          defaultValue=""
-          render={({ field }) => (
-            <TextField
-              {...field}
-              label="Visibility"
-              select
-              fullWidth
-              error={!!errors.visibility}
-              helperText={errors.visibility?.message}
-              className="mb-4"
-            >
-              <MenuItem value="private">Private</MenuItem>
-              <MenuItem value="family">Family</MenuItem>
-              <MenuItem value="public">Public</MenuItem>
-            </TextField>
-          )}
-        />
-        <Button type="submit" variant="contained" color="primary" fullWidth>
-          Create Post
-        </Button>
+    <Dialog open={ isOpen } onClose={ onCancel } fullWidth maxWidth="md">
+      <DialogTitle component="h2">Create Post From { ''.concat( user?.first_name, ' ', user.last_name ) }</DialogTitle>
+      <form onSubmit={ handleSubmit( onSubmit ) }>
+        <DialogContent>
+          <Grid container spacing={ 1 }>
+            <Grid size={ { xs: 12 } }>
+              <Controller
+                name="title"
+                control={ control }
+                defaultValue=""
+                render={ ( { field } ) => (
+                  <TextField
+                    { ...field }
+                    label="Title"
+                    fullWidth
+                    error={ !!errors.title }
+                    helperText={ errors.title?.message }
+                    className="mb-4"
+                  />
+                ) }
+              />
+            </Grid>
+            <Grid size={ { xs: 12 } }>
+              <Controller
+                name="content"
+                control={ control }
+                defaultValue=""
+                render={ ( { field } ) => (
+                  <TextField
+                    { ...field }
+                    label="Content"
+                    multiline
+                    rows={ 6 }
+                    fullWidth
+                    error={ !!errors.content }
+                    helperText={ errors.content?.message }
+                    className="mb-4"
+                  />
+                ) }
+              />
+            </Grid>
+            <Grid size={ { xs: 12 } }>
+              <Controller
+                name="post_type"
+                control={ control }
+                defaultValue=""
+                render={ ( { field } ) => (
+                  <TextField
+                    { ...field }
+                    label="Post Type"
+                    select
+                    fullWidth
+                    error={ !!errors.post_type }
+                    helperText={ errors.post_type?.message }
+                    className="mb-4"
+                  >
+                    <MenuItem value="blog">Blog</MenuItem>
+                    <MenuItem value="vlog">Vlog</MenuItem>
+                  </TextField>
+                ) }
+              />
+            </Grid>
+            <Grid size={ { xs: 12 } }>
+              <Controller
+                name="visibility"
+                control={ control }
+                defaultValue=""
+                render={ ( { field } ) => (
+                  <TextField
+                    { ...field }
+                    label="Visibility"
+                    select
+                    fullWidth
+                    error={ !!errors.visibility }
+                    helperText={ errors.visibility?.message }
+                    className="mb-4"
+                  >
+                    <MenuItem value="private">Private</MenuItem>
+                    <MenuItem value="family">Family</MenuItem>
+                    <MenuItem value="public">Public</MenuItem>
+                  </TextField>
+                ) }
+              />
+            </Grid>
+          </Grid>
+        </DialogContent>
+        <DialogActions className="mr-16 mb-12">
+          <Button onClick={ onCancel } variant="contained" color="info" size="small">
+            Cancel
+          </Button>
+          <Button type="submit" variant="contained" color="warning" size="small">
+            Create Post
+          </Button>
+        </DialogActions>
       </form>
-    </div>
+    </Dialog>
   );
 };
 
index 1217385ed3707f1600e66f6d555a2ca731b3482e..2567cc1450f98855366e6b6ec28f2a25615be9f6 100644 (file)
@@ -2,43 +2,46 @@
  * @file Component for displaying posts in a table
  */
 
-import React, { useMemo, useState } from 'react';
+import React, { useContext, useMemo, useState } from 'react';
 import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
-import { Button, Container } from '@mui/material';
+import { Button, Container, Grid } from '@mui/material';
+import { AuthContext } from '../components/AuthContext';
 import { useSnackbar } from 'notistack';
-import { useNavigate } from 'react-router-dom';
 import { PostService } from '../services';
 import { getFormattedDate } from '../utils';
+import PostForm from './PostForm';
 
 const PostsTable = () => {
   const { enqueueSnackbar } = useSnackbar();
-  const navigate = useNavigate();
-  const [posts, setPosts] = useState([]);
+  const [ posts, setPosts ] = useState( [] );
+  const [ showForm, setShowForm ] = useState( false );
+  const { user } = useContext( AuthContext );
 
   const fetchPosts = useMemo( () => async () => {
     try {
-      console.log('Fetching posts...');
-      const response = await PostService.getPosts();
-      setPosts(response.data);
-    } catch (error) {
-      enqueueSnackbar(`Error fetching posts: ${error.message}`, { variant: 'error' });
+      console.log( 'Fetching posts...' );
+      const response = await PostService.getPosts( { is_deleted: false } );
+      setPosts( response.data );
+    } catch ( error ) {
+      enqueueSnackbar( `Error fetching posts: ${ error.message }`, { variant: 'error' } );
     }
-  }, [enqueueSnackbar] );
+  }, [ enqueueSnackbar ] );
 
   // Fetch posts on mount
-  React.useEffect(() => {
+  React.useEffect( () => {
     fetchPosts().catch();
-  }, [fetchPosts, enqueueSnackbar]);
+  }, [ fetchPosts, enqueueSnackbar ] );
 
-  const columns = useMemo(() => [
+  const columns = useMemo( () => [
     {
       accessorKey: 'id',
       header: 'ID',
       size: 80,
+      visibleInShowHideMenu: false,
     },
     {
-      accessorKey: 'user_id',
-      header: 'User ID',
+      accessorKey: 'user_name',
+      header: 'Creator',
       size: 100,
     },
     {
@@ -65,11 +68,11 @@ const PostsTable = () => {
       accessorKey: 'created_at',
       header: 'Created At',
       size: 150,
-      Cell: ({ cell }) => getFormattedDate(cell.getValue()),
+      Cell: ( { cell } ) => getFormattedDate( cell.getValue() ),
     },
-  ], []);
+  ], [] );
 
-  const table = useMaterialReactTable({
+  const table = useMaterialReactTable( {
     columns,
     data: posts,
     enableColumnActions: false,
@@ -84,20 +87,34 @@ const PostsTable = () => {
     },
     muiTableBodyCellProps: {
       className: 'table-row',
-  }});
+    },
+    initialState: {
+      columnVisibility: {
+        id: false
+      }
+    },
+    renderTopToolbarCustomActions: () => (
+      <Grid container spacing={ 2 } alignItems="center">
+        <Grid item>
+          <h2 className="text-2xl font-bold mb-4">Posts</h2>
+        </Grid>
+        <Grid item>
+          <Button
+            variant="contained"
+            color="primary"
+            onClick={ () => setShowForm( true ) }
+          >
+            Create Post
+          </Button>
+        </Grid>
+      </Grid>
+    )
+  } );
 
   return (
-    <Container maxWidth='xxl'>
-      <h2 className="text-2xl font-bold mb-4">Posts</h2>
-      <Button
-        variant="contained"
-        color="primary"
-        onClick={() => navigate('/posts/new')}
-        className="mb-4"
-      >
-        Create Post
-      </Button>
-      <MaterialReactTable table={table} />
+    <Container maxWidth="xxl" className="mt-4">
+      { showForm && <PostForm isOpen={ showForm } setOpen={ setShowForm } refresh={ fetchPosts } user={ user }/> }
+      <MaterialReactTable table={ table }/>
     </Container>
   );
 };
diff --git a/src/app/views/Posts/PostFormView.js b/src/app/views/Posts/PostFormView.js
deleted file mode 100644 (file)
index e6fbdab..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * @file View for creating a new post
- */
-
-import React from 'react';
-import PostForm from '../../components/PostForm';
-
-const PostFormView = () => {
-  return (
-    <div className="container">
-      <PostForm />
-    </div>
-  );
-};
-
-export default PostFormView;
\ No newline at end of file
index 14a4d993b13e867c532d90b5f99763837dacba60..da02a6873634b34a8437b139a1c0898909e1d2b2 100644 (file)
@@ -4,12 +4,13 @@
 
 import React from 'react';
 import PostsTable from '../../components/PostsTable';
+import { Container } from '@mui/material';
 
 const PostsView = () => {
   return (
-    <div className="container">
-      <PostsTable />
-    </div>
+    <Container maxWidth="xxl">
+      <PostsTable/>
+    </Container>
   );
 };