Skip to content

Commit

Permalink
Merge pull request #87 from JimTheCat/CU-869760jjk_Support-CRUD-for-P…
Browse files Browse the repository at this point in the history
…osts_Patryk-Kosiski

feature: Create post menu
  • Loading branch information
JimTheCat authored Dec 21, 2024
2 parents eb9995b + ce66387 commit e29e69b
Show file tree
Hide file tree
Showing 16 changed files with 215 additions and 61 deletions.
13 changes: 13 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@mantine/dates": "^7.15.1",
"@mantine/form": "^7.15.1",
"@mantine/hooks": "^7.15.1",
"@mantine/modals": "^7.15.1",
"@mantine/notifications": "^7.15.1",
"@mantine/tiptap": "^7.15.1",
"@tabler/icons-react": "^3.23.0",
Expand Down
58 changes: 28 additions & 30 deletions frontend/src/Features/CreatePost/CreatePost.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,55 @@
import {RichEditor} from "../shared/components/RichEditor";
import {Button, Divider, Group, Modal} from "@mantine/core";
import {useDisclosure} from "@mantine/hooks";
import {IconPencil} from "@tabler/icons-react";
import {useState} from "react";
import {useRef, useState} from "react";
import api from "../shared/services/api.ts";
import {useAlert} from "../../Providers/AlertProvider.tsx";
import {ModificationModal} from "../shared/components/ModificationModal";
import {Button} from "@mantine/core";
import {ModalRichContent} from "../shared/consts";

export const CreatePost = () => {
const [opened, {open, close}] = useDisclosure(false);
const [content, setContent] = useState('');
const contentRef = useRef(content);
const alert = useAlert();

const handleContentChange = (html: string) => {
setContent(html);
contentRef.current = html;
}

const handleCreatePost = () => {
console.log('Create post: ', content)
if (!content) {
const contentToSave = contentRef.current;
console.log('Create post: ', contentToSave);
if (!contentToSave) {
alert.showError('Post is empty!');
return;
}

api.post('/api/posts/create', null, {params: {content}}).then((response) => {
api.post('/api/posts/create', null, {params: {content: contentToSave}}).then((response) => {
if (response.status === 200) {
close();
}
});
}

return (
<>
<Modal opened={opened} onClose={close} title="Create post" size={"auto"} centered closeOnClickOutside={false}>
<RichEditor onContentChange={handleContentChange}/>
<Divider my={"md"}/>
<Group justify={"space-between"}>
<Button color="red" variant="light" onClick={close}>Cancel</Button>
<Button color="blue" variant="light" onClick={handleCreatePost}>Create</Button>
</Group>
</Modal>
<Button
variant={"subtle"}
size={"md"}
leftSection={<IconPencil/>}
autoContrast
fullWidth
justify={"flex-start"}
color={"gray"}
onClick={() => ModificationModal({
handleAction: handleCreatePost,
title: 'Create post',
buttonConfirmText: 'Create',
buttonConfirmColor: 'blue',
childrenContent: <ModalRichContent handleContentChange={handleContentChange}/>
})}
>
Create post
</Button>

<Button
variant={"subtle"}
size={"md"}
leftSection={<IconPencil/>}
autoContrast
fullWidth
justify={"flex-start"}
color={"gray"}
onClick={open}
>
Napisz post
</Button>
</>
);
}
22 changes: 4 additions & 18 deletions frontend/src/Features/shared/components/Cards/Post/Post.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import {
ActionIcon,
Avatar,
BackgroundImage,
Box,
Button,
Card,
Divider,
Group,
SimpleGrid,
Stack,
Text
} from "@mantine/core";
import {Avatar, BackgroundImage, Box, Button, Card, Divider, Group, SimpleGrid, Stack, Text} from "@mantine/core";
import {User} from "../../../types/User.tsx";
import {InnerHtmlHandler} from "../../InnerHtmlHandler";
import {DateFormatter} from "../../../utils/DateFormatter.tsx";
import {IconDots, IconMessage, IconPaw, IconShare3} from "@tabler/icons-react";
import {IconMessage, IconPaw, IconShare3} from "@tabler/icons-react";
import {useAuthStore} from "../../../services/authStore.ts";
import {useNavigate} from "react-router-dom";
import {ImageWithSkeleton} from "../../ImageWithSkeleton";
import {MenuPost} from "./components/MenuPost";

type PostProps = {
ownerLogin: string;
Expand Down Expand Up @@ -147,10 +136,7 @@ export const Post = (props: PostProps) => {
</Stack>
</Group>
{isOwner &&
<ActionIcon size="lg" color="gray" radius={"xl"} variant={"subtle"} onClick={() => {
}}>
<IconDots stroke={1.5}/>
</ActionIcon>
<MenuPost content={props.contentHtml}/>
}
</Group>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {ModificationModal} from "../../../../ModificationModal";
import {IconPencil} from "@tabler/icons-react";
import {Menu, rem} from "@mantine/core";
import {useRef, useState} from "react";
import {ModalRichContent} from "../../../../../consts";

type EditPostProps = {
content?: string;
postId?: string;
}

export const EditPost = (props: EditPostProps) => {
const [content, setContent] = useState(props.content ?? '');
const contentRef = useRef(content);

const handleContentChange = (html: string) => {
console.log('Content changed: ', html);
setContent(html);
contentRef.current = html;
}

const handleEditPost = () => {
// TODO: Replace with actual edit logic
console.log('Edit post: ', contentRef.current);
};

return (
<Menu.Item
leftSection={<IconPencil style={{width: rem(14), height: rem(14)}}/>}
onClick={() => ModificationModal({
handleAction: handleEditPost,
title: 'Edit post',
buttonConfirmText: 'Save',
buttonConfirmColor: 'blue',
content: content,
childrenContent: <ModalRichContent content={content} handleContentChange={handleContentChange}/>
})}
>
Edit post
</Menu.Item>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {EditPost} from './EditPost';
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {ActionIcon, Menu} from "@mantine/core";
import {IconDots} from "@tabler/icons-react";
import {EditPost} from "../EditPost";
import {RemovePost} from "../RemovePost";

type MenuPostProps = {
content?: string;
}

export const MenuPost = (props: MenuPostProps) => {
return (
<Menu radius={'sm'} shadow="xl" width={"auto"} closeOnItemClick>
<Menu.Target>
<ActionIcon size="lg" color="gray" radius={"xl"} variant={"subtle"}>
<IconDots stroke={1.5}/>
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Manage</Menu.Label>
<EditPost content={props.content}/>
<RemovePost/>
</Menu.Dropdown>
</Menu>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {MenuPost} from './MenuPost';
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {Menu, rem, Text} from "@mantine/core";
import {IconTrash} from "@tabler/icons-react";
import {ModificationModal} from "../../../../ModificationModal";

type RemovePostProps = {
postId?: string;
}

export const RemovePost = (props: RemovePostProps) => {
const handleRemoval = () => {
// TODO: Replace with actual removal logic
console.log('Remove post: ', props.postId);
};

return (
<Menu.Item
color="red"
leftSection={<IconTrash style={{width: rem(14), height: rem(14)}}/>}
onClick={() => ModificationModal({
handleAction: handleRemoval,
title: 'Remove post',
buttonConfirmText: 'Remove',
buttonConfirmColor: 'red',
childrenContent: <Text>Are you sure that you want to remove your post?</Text>
})}
>
Remove post
</Menu.Item>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {RemovePost} from './RemovePost';
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {MantineColor} from "@mantine/core";
import {modals} from "@mantine/modals";
import React from "react";

type ModificationModalProps = {
handleAction: () => void;
buttonConfirmText: string;
buttonConfirmColor: MantineColor;
title: string;
content?: string;
childrenContent: React.ReactNode;
}

export const ModificationModal = (props: ModificationModalProps) => modals.openConfirmModal({
title: props.title,
children: (
props.childrenContent
),
labels: {confirm: props.buttonConfirmText, cancel: "Cancel"},
confirmProps: {color: props.buttonConfirmColor},
size: "auto",
centered: true,
closeOnClickOutside: false,
onConfirm: props.handleAction
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {ModificationModal} from './ModificationModal.tsx';
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import Superscript from '@tiptap/extension-superscript';
import SubScript from '@tiptap/extension-subscript';
import Placeholder from "@tiptap/extension-placeholder";

export const RichEditor = ({onContentChange}: { onContentChange?: (html: string) => void }) => {
type RichEditorProps = {
onContentChange?: (html: string) => void;
content?: string;
}

export const RichEditor = (props: RichEditorProps) => {
const editor = useEditor({
extensions: [
StarterKit,
Expand All @@ -20,8 +25,10 @@ export const RichEditor = ({onContentChange}: { onContentChange?: (html: string)
TextAlign.configure({types: ['heading', 'paragraph']}),
Placeholder.configure({placeholder: 'What\'s on your mind?'}),
],
content: props.content,
onUpdate({editor}) {
onContentChange && onContentChange(editor.getHTML());
const html = editor.getHTML();
props.onContentChange && props.onContentChange(html);
},
});

Expand Down
19 changes: 19 additions & 0 deletions frontend/src/Features/shared/consts/ModalRichContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {RichEditor} from "../components/RichEditor";
import {Divider} from "@mantine/core";

type ModalContentProps = {
content?: string;
handleContentChange: (html: string) => void;
}

export const ModalRichContent = (props: ModalContentProps) => {
return (
<>
<RichEditor
content={props.content}
onContentChange={props.handleContentChange}
/>
<Divider my={"md"}/>
</>
);
};
3 changes: 2 additions & 1 deletion frontend/src/Features/shared/consts/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export {Languages} from './Languages';
export {Languages} from './Languages';
export {ModalRichContent} from './ModalRichContent';
23 changes: 13 additions & 10 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {i18nInitializer} from "./Utils";
import {ThemeProvider} from "./Providers/ThemeProvider.tsx";
import {CookiesPopup} from "./Features/shared/components/CookiesPopup";
import {AlertProvider} from "./Providers/AlertProvider.tsx";
import {ModalsProvider} from "@mantine/modals";

i18nInitializer();

Expand All @@ -27,16 +28,18 @@ const theme = createTheme({
createRoot(document.getElementById('root')!).render(
<StrictMode>
<MantineProvider theme={theme} defaultColorScheme={'dark'}>
<AlertProvider>
<ThemeProvider>
<BrowserRouter>
<I18nextProvider i18n={i18next}>
<CookiesPopup/>
<App/>
</I18nextProvider>
</BrowserRouter>
</ThemeProvider>
</AlertProvider>
<ModalsProvider>
<AlertProvider>
<ThemeProvider>
<BrowserRouter>
<I18nextProvider i18n={i18next}>
<CookiesPopup/>
<App/>
</I18nextProvider>
</BrowserRouter>
</ThemeProvider>
</AlertProvider>
</ModalsProvider>
</MantineProvider>
</StrictMode>,
)

0 comments on commit e29e69b

Please sign in to comment.